agora inbox for [email protected]  
help / color / mirror / Atom feed
[PATCH 2/2] doc review
84+ messages / 3 participants
[nested] [flat]

* [PATCH 2/2] doc review
@ 2021-03-03 22:36  Justin Pryzby <[email protected]>
  0 siblings, 0 replies; 84+ messages in thread

From: Justin Pryzby @ 2021-03-03 22:36 UTC (permalink / raw)

---
 doc/src/sgml/libpq.sgml                | 67 +++++++++++++-------------
 src/interfaces/libpq/fe-exec.c         |  2 +-
 src/test/modules/test_libpq/pipeline.c |  6 +--
 3 files changed, 38 insertions(+), 37 deletions(-)

diff --git a/doc/src/sgml/libpq.sgml b/doc/src/sgml/libpq.sgml
index a34ecbb144..e2865a218b 100644
--- a/doc/src/sgml/libpq.sgml
+++ b/doc/src/sgml/libpq.sgml
@@ -3130,8 +3130,9 @@ ExecStatusType PQresultStatus(const PGresult *res);
           <term><literal>PGRES_PIPELINE_SYNC</literal></term>
           <listitem>
            <para>
-            The <structname>PGresult</structname> represents a point in a
-            pipeline where a synchronization point has been established.
+            The <structname>PGresult</structname> represents a
+            synchronization point in pipeline mode, requested by 
+            <xref linkend="libpq-PQsendPipeline"/>.
             This status occurs only when pipeline mode has been selected.
            </para>
           </listitem>
@@ -3141,9 +3142,9 @@ ExecStatusType PQresultStatus(const PGresult *res);
           <term><literal>PGRES_PIPELINE_ABORTED</literal></term>
           <listitem>
            <para>
-            The <structname>PGresult</structname> represents a pipeline that's
+            The <structname>PGresult</structname> represents a pipeline that has
             received an error from the server.  <function>PQgetResult</function>
-            must be called repeatedly, and it will return this status code,
+            must be called repeatedly, and each time it will return this status code
             until the end of the current pipeline, at which point it will return
             <literal>PGRES_PIPELINE_SYNC</literal> and normal processing can
             resume.
@@ -4953,7 +4954,7 @@ int PQflush(PGconn *conn);
    <title>Using Pipeline Mode</title>
 
    <para>
-    To issue pipelines the application must switch a connection into pipeline mode.
+    To issue pipelines, the application must switch a connection into pipeline mode.
     Enter pipeline mode with <xref linkend="libpq-PQenterPipelineMode"/>
     or test whether pipeline mode is active with
     <xref linkend="libpq-PQpipelineStatus"/>.
@@ -4975,7 +4976,7 @@ int PQflush(PGconn *conn);
         server will block trying to send results to the client from queries
         it has already processed. This only occurs when the client sends
         enough queries to fill both its output buffer and the server's receive
-        buffer before switching to processing input from the server,
+        buffer before it switches to processing input from the server,
         but it's hard to predict exactly when that will happen.
        </para>
       </footnote>
@@ -5025,7 +5026,7 @@ int PQflush(PGconn *conn);
     <title>Processing Results</title>
 
     <para>
-     To process the result of one pipeline query, the application calls
+     To process the result of one query in a pipeline, the application calls
      <function>PQgetResult</function> repeatedly and handles each result
      until <function>PQgetResult</function> returns null.
      The result from the next query in the pipeline may then be retrieved using
@@ -5057,10 +5058,10 @@ int PQflush(PGconn *conn);
      <type>PGresult</type> types <literal>PGRES_PIPELINE_SYNC</literal>
      and <literal>PGRES_PIPELINE_ABORTED</literal>.
      <literal>PGRES_PIPELINE_SYNC</literal> is reported exactly once for each
-     <function>PQsendPipeline</function> call at the corresponding point in
-     the result stream.
+     <function>PQsendPipeline</function> after retrieving results for all
+     queries in the pipeline.
      <literal>PGRES_PIPELINE_ABORTED</literal> is emitted in place of a normal
-     result stream result for the first error and all subsequent results
+     stream result for the first error and all subsequent results
      except <literal>PGRES_PIPELINE_SYNC</literal> and null;
      see <xref linkend="libpq-pipeline-errors"/>.
     </para>
@@ -5075,7 +5076,8 @@ int PQflush(PGconn *conn);
      application about the query currently being processed (except that
      <function>PQgetResult</function> returns null to indicate that we start
      returning the results of next query). The application must keep track
-     of the order in which it sent queries and the expected results.
+     of the order in which it sent queries, to associate them with their
+     corresponding results.
      Applications will typically use a state machine or a FIFO queue for this.
     </para>
 
@@ -5091,10 +5093,10 @@ int PQflush(PGconn *conn);
     </para>
 
     <para>
-     From the client perspective, after the client gets a
-     <literal>PGRES_FATAL_ERROR</literal> return from
-     <function>PQresultStatus</function> the pipeline is flagged as aborted.
-     <application>libpq</application> will report
+     From the client perspective, after <function>PQresultStatus</function>
+     returns <literal>PGRES_FATAL_ERROR</literal>,
+     the pipeline is flagged as aborted.
+     <function>PQresultStatus</function>, will report a
      <literal>PGRES_PIPELINE_ABORTED</literal> result for each remaining queued
      operation in an aborted pipeline. The result for
      <function>PQsendPipeline</function> is reported as
@@ -5108,8 +5110,8 @@ int PQflush(PGconn *conn);
     </para>
 
     <para>
-     If the pipeline used an implicit transaction then operations that have
-     already executed are rolled back and operations that were queued for after
+     If the pipeline used an implicit transaction, then operations that have
+     already executed are rolled back and operations that were queued to follow
      the failed operation are skipped entirely. The same behaviour holds if the
      pipeline starts and commits a single explicit transaction (i.e. the first
      statement is <literal>BEGIN</literal> and the last is
@@ -5145,11 +5147,11 @@ int PQflush(PGconn *conn);
 
     <para>
      The client application should generally maintain a queue of work
-     still to be dispatched and a queue of work that has been dispatched
+     remaining to be dispatched and a queue of work that has been dispatched
      but not yet had its results processed. When the socket is writable
      it should dispatch more work. When the socket is readable it should
      read results and process them, matching them up to the next entry in
-     its expected results queue.  Based on available memory, results from
+     its expected results queue.  Based on available memory, results from the
      socket should be read frequently: there's no need to wait until the
      pipeline end to read the results.  Pipelines should be scoped to logical
      units of work, usually (but not necessarily) one transaction per pipeline.
@@ -5191,8 +5193,8 @@ int PQflush(PGconn *conn);
 
      <listitem>
       <para>
-      Returns current pipeline mode status of the <application>libpq</application>
-      connection.
+      Returns the current pipeline mode status of the
+      <application>libpq</application> connection.
 <synopsis>
 PGpipelineStatus PQpipelineStatus(const PGconn *conn);
 </synopsis>
@@ -5233,11 +5235,10 @@ PGpipelineStatus PQpipelineStatus(const PGconn *conn);
          <listitem>
           <para>
            The <application>libpq</application> connection is in pipeline
-           mode and an error has occurred while processing the current
-           pipeline.
-           The aborted flag is cleared as soon as the result
-           of the <function>PQsendPipeline</function> at the end of the aborted
-           pipeline is processed. Clients don't usually need this function to
+           mode and an error occurred while processing the current pipeline.
+           The aborted flag is cleared when <function>PQresultStatus</function>
+           returns PGRES_PIPELINE_SYNC at the end of the pipeline.
+           Clients don't usually need this function to
            verify aborted status, as they can tell that the pipeline is aborted
            from the <literal>PGRES_PIPELINE_ABORTED</literal> result code.
           </para>
@@ -5328,7 +5329,7 @@ int PQsendPipeline(PGconn *conn);
        Returns 1 for success. Returns 0 if the connection is not in
        pipeline mode or sending a
        <link linkend="protocol-flow-ext-query">sync message</link>
-       is failed.
+       failed.
       </para>
      </listitem>
     </varlistentry>
@@ -5349,7 +5350,7 @@ int PQsendPipeline(PGconn *conn);
    <para>
     Pipeline mode is most useful when the server is distant, i.e., network latency
     (<quote>ping time</quote>) is high, and also when many small operations
-    are being performed in rapid sequence.  There is usually less benefit
+    are being performed in rapid succession.  There is usually less benefit
     in using pipelined commands when each query takes many multiples of the client/server
     round-trip time to execute.  A 100-statement operation run on a server
     300ms round-trip-time away would take 30 seconds in network latency alone
@@ -5367,7 +5368,7 @@ int PQsendPipeline(PGconn *conn);
    <para>
     Pipeline mode is not useful when information from one operation is required by
     the client to produce the next operation. In such cases, the client
-    must introduce a synchronization point and wait for a full client/server
+    would have to introduce a synchronization point and wait for a full client/server
     round-trip to get the results it needs. However, it's often possible to
     adjust the client design to exchange the required information server-side.
     Read-modify-write cycles are especially good candidates; for example:
@@ -5392,10 +5393,10 @@ UPDATE mytable SET x = x + 1 WHERE id = 42;
 
    <note>
     <para>
-     The pipeline API was introduced in PostgreSQL 14, but clients using
-     the PostgreSQL 14 version of <application>libpq</application> can use
-     pipelines on server versions 7.4 and newer. Pipeline mode works on any server
-     that supports the v3 extended query protocol.
+     The pipeline API was introduced in <productname>PostgreSQL</productname> 14.
+     Pipeline mode is a client-side feature which doesn't require server
+     support, and works on any server that supports the v3 extended query
+     protocol.
     </para>
    </note>
   </sect2>
diff --git a/src/interfaces/libpq/fe-exec.c b/src/interfaces/libpq/fe-exec.c
index 7ae7c14948..d7b036a35c 100644
--- a/src/interfaces/libpq/fe-exec.c
+++ b/src/interfaces/libpq/fe-exec.c
@@ -3803,7 +3803,7 @@ pqPipelineFlush(PGconn *conn)
 {
 	if ((conn->pipelineStatus == PQ_PIPELINE_OFF) ||
 		(conn->outCount >= OUTBUFFER_THRESHOLD))
-		return (pqFlush(conn));
+		return pqFlush(conn);
 	return 0;
 }
 
diff --git a/src/test/modules/test_libpq/pipeline.c b/src/test/modules/test_libpq/pipeline.c
index f4a2bdec57..01d5a9a8ff 100644
--- a/src/test/modules/test_libpq/pipeline.c
+++ b/src/test/modules/test_libpq/pipeline.c
@@ -126,7 +126,7 @@ test_simple_pipeline(PGconn *conn)
 	 * process the results of as they come in.
 	 *
 	 * For a simple case we should be able to do this without interim
-	 * processing of results since our out buffer will give us enough slush to
+	 * processing of results since our output buffer will give us enough slush to
 	 * work with and we won't block on sending. So blocking mode is fine.
 	 */
 	if (PQisnonblocking(conn))
@@ -603,7 +603,7 @@ test_pipelined_insert(PGconn *conn, int n_rows)
 
 	/*
 	 * Now we start inserting. We'll be sending enough data that we could fill
-	 * our out buffer, so to avoid deadlocking we need to enter nonblocking
+	 * our output buffer, so to avoid deadlocking we need to enter nonblocking
 	 * mode and consume input while we send more output. As results of each
 	 * query are processed we should pop them to allow processing of the next
 	 * query. There's no need to finish the pipeline before processing
@@ -635,7 +635,7 @@ test_pipelined_insert(PGconn *conn, int n_rows)
 		}
 
 		/*
-		 * Process any results, so we keep the server's out buffer free
+		 * Process any results, so we keep the server's output buffer free
 		 * flowing and it can continue to process input
 		 */
 		if (FD_ISSET(sock, &input_mask))
-- 
2.17.0


--oC1+HKm2/end4ao3--





^ permalink  raw  reply  [nested|flat] 84+ 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; 84+ 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] 84+ 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; 84+ 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] 84+ 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; 84+ 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] 84+ 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; 84+ 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] 84+ 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; 84+ 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] 84+ 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; 84+ 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] 84+ 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; 84+ 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] 84+ 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; 84+ 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] 84+ 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; 84+ 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] 84+ messages in thread

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


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

Thread overview: 84+ messages (download: mbox mbox.gz follow: Atom feed)
-- links below jump to the message on this page --
2021-03-03 22:36 [PATCH 2/2] doc review Justin Pryzby <[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 v33 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 v27 8/9] 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 v26 09/10] 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 v24 09/15] 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 v34 10/11] 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 v28 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 v30 10/11] Add regression tests for Incremental View Maintenance Takuma Hoshiai <[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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 v37 10/11] 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