Compare commits
1 commit
main
...
fix_autoin
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d954439b17 |
40 changed files with 428 additions and 6338 deletions
28
.gitignore
vendored
28
.gitignore
vendored
|
|
@ -1,30 +1,8 @@
|
||||||
# Object files
|
# Global excludes across all subdirectories
|
||||||
*.o
|
|
||||||
|
|
||||||
# Coverage files
|
|
||||||
*.gcno
|
|
||||||
*.gcda
|
|
||||||
|
|
||||||
# Libraries
|
|
||||||
*.lib
|
|
||||||
*.a
|
|
||||||
|
|
||||||
# LLVM bitcode
|
|
||||||
*.bc
|
*.bc
|
||||||
|
*.o
|
||||||
# Shared objects (inc. Windows DLLs)
|
|
||||||
*.dll
|
|
||||||
*.so
|
*.so
|
||||||
*.so.*
|
regression.*
|
||||||
*.dylib
|
|
||||||
|
|
||||||
# Executables
|
|
||||||
*.exe
|
|
||||||
*.app
|
|
||||||
|
|
||||||
# Dependencies
|
|
||||||
.deps
|
|
||||||
|
|
||||||
# Generated subdirectories
|
# Generated subdirectories
|
||||||
/results/
|
/results/
|
||||||
/output_iso/
|
|
||||||
|
|
|
||||||
20
Makefile
20
Makefile
|
|
@ -1,7 +1,5 @@
|
||||||
# contrib/pg_ivm/Makefile
|
# contrib/pg_ivm/Makefile
|
||||||
|
|
||||||
PG_CONFIG ?= pg_config
|
|
||||||
|
|
||||||
MODULE_big = pg_ivm
|
MODULE_big = pg_ivm
|
||||||
OBJS = \
|
OBJS = \
|
||||||
$(WIN32RES) \
|
$(WIN32RES) \
|
||||||
|
|
@ -16,24 +14,10 @@ EXTENSION = pg_ivm
|
||||||
DATA = pg_ivm--1.0.sql \
|
DATA = pg_ivm--1.0.sql \
|
||||||
pg_ivm--1.0--1.1.sql pg_ivm--1.1--1.2.sql pg_ivm--1.2--1.3.sql \
|
pg_ivm--1.0--1.1.sql pg_ivm--1.1--1.2.sql pg_ivm--1.2--1.3.sql \
|
||||||
pg_ivm--1.3--1.4.sql pg_ivm--1.4--1.5.sql pg_ivm--1.5--1.6.sql \
|
pg_ivm--1.3--1.4.sql pg_ivm--1.4--1.5.sql pg_ivm--1.5--1.6.sql \
|
||||||
pg_ivm--1.6--1.7.sql pg_ivm--1.7--1.8.sql pg_ivm--1.8--1.9.sql \
|
pg_ivm--1.6--1.7.sql pg_ivm--1.7--1.8.sql pg_ivm--1.8--1.9.sql
|
||||||
pg_ivm--1.9--1.10.sql \
|
|
||||||
pg_ivm--1.10.sql \
|
|
||||||
pg_ivm--1.10--1.11.sql pg_ivm--1.11--1.12.sql
|
|
||||||
|
|
||||||
REGRESS = pg_ivm create_immv refresh_immv
|
REGRESS = pg_ivm create_immv refresh_immv
|
||||||
|
|
||||||
PGVER = $(shell $(PG_CONFIG) --version | sed "s/^[^ ]* \([0-9]*\).*$$/\1/" 2>/dev/null)
|
PG_CONFIG ?= pg_config
|
||||||
|
|
||||||
# We assume PG13 is the only version that is supported by pg_ivm but
|
|
||||||
# missing pg_isolation_regress.
|
|
||||||
|
|
||||||
ifneq ($(PGVER),13)
|
|
||||||
ISOLATION = create_insert refresh_insert insert_insert \
|
|
||||||
create_insert2 refresh_insert2 insert_insert2 \
|
|
||||||
create_insert3 refresh_insert3 insert_insert3
|
|
||||||
ISOLATION_OPTS = --load-extension=pg_ivm
|
|
||||||
endif
|
|
||||||
|
|
||||||
PGXS := $(shell $(PG_CONFIG) --pgxs)
|
PGXS := $(shell $(PG_CONFIG) --pgxs)
|
||||||
include $(PGXS)
|
include $(PGXS)
|
||||||
|
|
|
||||||
202
README.md
202
README.md
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
The `pg_ivm` module provides Incremental View Maintenance (IVM) feature for PostgreSQL.
|
The `pg_ivm` module provides Incremental View Maintenance (IVM) feature for PostgreSQL.
|
||||||
|
|
||||||
The extension is compatible with PostgreSQL 13, 14, 15, 16, 17, and 18.
|
The extension is compatible with PostgreSQL 13, 14, 15, 16, and 17.
|
||||||
|
|
||||||
## Description
|
## Description
|
||||||
|
|
||||||
|
|
@ -13,7 +13,7 @@ There are two approaches with regard to timing of view maintenance: immediate an
|
||||||
We call a materialized view supporting IVM an **Incrementally Maintainable Materialized View (IMMV)**. To create IMMV, you have to call `create_immv` function with a relation name and a view definition query. For example:
|
We call a materialized view supporting IVM an **Incrementally Maintainable Materialized View (IMMV)**. To create IMMV, you have to call `create_immv` function with a relation name and a view definition query. For example:
|
||||||
|
|
||||||
```sql
|
```sql
|
||||||
SELECT pgivm.create_immv('myview', 'SELECT * FROM mytab');
|
SELECT create_immv('myview', 'SELECT * FROM mytab');
|
||||||
```
|
```
|
||||||
|
|
||||||
creates an IMMV with name 'myview' defined as `SELECT * FROM mytab`. This is corresponding to the following command to create a normal materialized view;
|
creates an IMMV with name 'myview' defined as `SELECT * FROM mytab`. This is corresponding to the following command to create a normal materialized view;
|
||||||
|
|
@ -25,7 +25,7 @@ CREATE MATERIALIZED VIEW myview AS SELECT * FROM mytab;
|
||||||
When an IMMV is created, some triggers are automatically created so that the view's contents are immediately updated when its base tables are modified.
|
When an IMMV is created, some triggers are automatically created so that the view's contents are immediately updated when its base tables are modified.
|
||||||
|
|
||||||
```sql
|
```sql
|
||||||
postgres=# SELECT pgivm.create_immv('m', 'SELECT * FROM t0');
|
postgres=# SELECT create_immv('m', 'SELECT * FROM t0');
|
||||||
NOTICE: could not create an index on immv "m" automatically
|
NOTICE: could not create an index on immv "m" automatically
|
||||||
DETAIL: This target list does not have all the primary key columns, or this view does not contain DISTINCT clause.
|
DETAIL: This target list does not have all the primary key columns, or this view does not contain DISTINCT clause.
|
||||||
HINT: Create an index on the immv for efficient incremental maintenance.
|
HINT: Create an index on the immv for efficient incremental maintenance.
|
||||||
|
|
@ -57,7 +57,6 @@ postgres=# SELECT * FROM m; -- automatically updated
|
||||||
Note that if you use PostgreSQL 17 or later, during automatic maintenance of an IMMV, the `search_path` is temporarily changed to `pg_catalog, pg_temp`.
|
Note that if you use PostgreSQL 17 or later, during automatic maintenance of an IMMV, the `search_path` is temporarily changed to `pg_catalog, pg_temp`.
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
To install `pg_ivm`, execute this in the module's directory:
|
To install `pg_ivm`, execute this in the module's directory:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
|
|
@ -68,32 +67,18 @@ If you installed PostgreSQL from rpm or deb, you will need the devel package (fo
|
||||||
|
|
||||||
> **Important:** Don't forget to set the `PG_CONFIG` variable (`make PG_CONFIG=...`) or the `PATH` to the `pg_config` command in case you want to use `pg_ivm` on a non-default or custom build of PostgreSQL. Read more [here](https://wiki.postgresql.org/wiki/Building_and_Installing_PostgreSQL_Extension_Modules).
|
> **Important:** Don't forget to set the `PG_CONFIG` variable (`make PG_CONFIG=...`) or the `PATH` to the `pg_config` command in case you want to use `pg_ivm` on a non-default or custom build of PostgreSQL. Read more [here](https://wiki.postgresql.org/wiki/Building_and_Installing_PostgreSQL_Extension_Modules).
|
||||||
|
|
||||||
Once installed, execute `CREATE EXTENSION` comand.
|
And, execute CREATE EXTENSION comand.
|
||||||
|
|
||||||
```sql
|
```
|
||||||
CREATE EXTENSION pg_ivm;
|
CREATE EXTENSION pg_ivm;
|
||||||
```
|
```
|
||||||
|
|
||||||
### Configuration
|
|
||||||
|
|
||||||
To ensure `pg_ivm` maintains IMMVs correctly, add it to either shared_preload_libraries or session_preload_libraries in postgresql.conf:
|
|
||||||
|
|
||||||
```
|
|
||||||
# Add pg_ivm to preload libraries
|
|
||||||
shared_preload_libraries = 'pg_ivm'
|
|
||||||
# OR
|
|
||||||
session_preload_libraries = 'pg_ivm'
|
|
||||||
```
|
|
||||||
|
|
||||||
After making this change, restart PostgreSQL for the configuration to take effect.
|
|
||||||
|
|
||||||
### RPM packages and yum repository
|
### RPM packages and yum repository
|
||||||
|
|
||||||
RPM packages of pg_ivm are available from the [PostgreSQL yum repository](https://yum.postgresql.org/). See the [instruction](https://yum.postgresql.org/howto/) for details. Note that we are not the maintainer of this yum repository and RPMs for pg_ivm in it may be not always latest.
|
RPM packages of pg_ivm are available from the [PostgreSQL yum repository](https://yum.postgresql.org/). See the [instruction](https://yum.postgresql.org/howto/) for details. Note that we are not the maintainer of this yum repository and RPMs for pg_ivm in it may be not always latest.
|
||||||
|
|
||||||
## Objects
|
## Objects
|
||||||
|
|
||||||
When `pg_ivm` is installed, the 'pgivm' schema is created, along with the following objects within this schema.
|
When `pg_ivm` is installed, the following objects are created.
|
||||||
|
|
||||||
### Functions
|
### Functions
|
||||||
|
|
||||||
|
|
@ -101,28 +86,24 @@ When `pg_ivm` is installed, the 'pgivm' schema is created, along with the follow
|
||||||
|
|
||||||
Use `create_immv` function to create IMMV.
|
Use `create_immv` function to create IMMV.
|
||||||
```
|
```
|
||||||
pgivm.create_immv(immv_name text, view_definition text) RETURNS bigint
|
create_immv(immv_name text, view_definition text) RETURNS bigint
|
||||||
```
|
```
|
||||||
`create_immv` defines a new IMMV of a query. A table of the name `immv_name` is created and a query specified by `view_definition` is executed and used to populate the IMMV. The query is stored in `pg_ivm_immv`, so that it can be refreshed later upon incremental view maintenance. `create_immv` returns the number of rows in the created IMMV.
|
`create_immv` defines a new IMMV of a query. A table of the name `immv_name` is created and a query specified by `view_definition` is executed and used to populate the IMMV. The query is stored in `pg_ivm_immv`, so that it can be refreshed later upon incremental view maintenance. `create_immv` returns the number of rows in the created IMMV.
|
||||||
|
|
||||||
When an IMMV is created, some triggers are automatically created so that the view's contents are immediately updated when its base tables are modified. In addition, a unique index is created on the IMMV automatically if possible. If the view definition query has a GROUP BY clause, a unique index is created on the columns of GROUP BY expressions. Also, if the view has DISTINCT clause, a unique index is created on all columns in the target list. Otherwise, if the IMMV contains all primary key attributes of its base tables in the target list, a unique index is created on these attributes. In other cases, no index is created.
|
When an IMMV is created, some triggers are automatically created so that the view's contents are immediately updated when its base tables are modified. In addition, a unique index is created on the IMMV automatically if possible. If the view definition query has a GROUP BY clause, a unique index is created on the columns of GROUP BY expressions. Also, if the view has DISTINCT clause, a unique index is created on all columns in the target list. Otherwise, if the IMMV contains all primary key attributes of its base tables in the target list, a unique index is created on these attributes. In other cases, no index is created.
|
||||||
|
|
||||||
`create_immv` acquires an `AccessExclusiveLock` on the view. However, even if we are able to acquire the lock, a concurrent transaction may have already incrementally updated and committed the view before we can acquire it. In the `REPEATABLE READ` or `SERIALIZABLE` isolation levels, this could lead to an inconsistent state of the view. Unfortunately, this situation cannot be detected during the creation of the view. As a result, `create_immv` raises a warning in these isolation levels, suggesting that the command be used in `READ COMMITTED` or that `refresh_immv` be executed afterward to make the view's contents remain consistent.
|
|
||||||
|
|
||||||
Note that if you use PostgreSQL 17 or later, while `create_immv` is running, the `search_path` is temporarily changed to `pg_catalog, pg_temp`.
|
Note that if you use PostgreSQL 17 or later, while `create_immv` is running, the `search_path` is temporarily changed to `pg_catalog, pg_temp`.
|
||||||
|
|
||||||
#### refresh_immv
|
#### refresh_imm
|
||||||
|
|
||||||
Use `refresh_immv` function to refresh IMMV.
|
Use `refresh_immv` function to refresh IMMV.
|
||||||
```
|
```
|
||||||
pgivm.refresh_immv(immv_name text, with_data bool) RETURNS bigint
|
refresh_immv(immv_name text, with_data bool) RETURNS bigint
|
||||||
```
|
```
|
||||||
|
|
||||||
`refresh_immv` completely replaces the contents of an IMMV as `REFRESH MATERIALIZED VIEW` command does for a materialized view. To execute this function you must be the owner of the IMMV (with PostgreSQL 16 or earlier) or have the `MAINTAIN` privilege on the IMMV (with PostgreSQL 17 or later). The old contents are discarded.
|
`refresh_immv` completely replaces the contents of an IMMV as `REFRESH MATERIALIZED VIEW` command does for a materialized view. To execute this function you must be the owner of the IMMV (with PostgreSQL 16 or earlier) or have the `MAINTAIN` privilege on the IMMV (with PostgreSQL 17 or later). The old contents are discarded.
|
||||||
|
|
||||||
The with_data flag is corresponding to `WITH [NO] DATA` option of `REFRESH MATERIALIZED VIEW` command. If with_data is true, the backing query is executed to provide the new data, and if the IMMV is unpopulated, triggers for maintaining the view are created. Also, a unique index is created for IMMV if it is possible and the view doesn't have that yet. If with_data is false, no new data is generated and the IMMV become unpopulated, and the triggers are dropped from the IMMV. Note that unpopulated IMMV is still scannable although the result is empty. This behaviour may be changed in future to raise an error when an unpopulated IMMV is scanned.
|
The with_data flag is corresponding to `WITH [NO] DATA` option of REFRESH MATERIALIZED VIEW` command. If with_data is true, the backing query is executed to provide the new data, and if the IMMV is unpopulated, triggers for maintaining the view are created. Also, a unique index is created for IMMV if it is possible and the view doesn't have that yet. If with_data is false, no new data is generated and the IMMV become unpopulated, and the triggers are dropped from the IMMV. Note that unpopulated IMMV is still scannable although the result is empty. This behaviour may be changed in future to raise an error when an unpopulated IMMV is scanned.
|
||||||
|
|
||||||
`refresh_immv` acquires `AccessExclusiveLock` on the view. However, even if we are able to acquire the lock, a concurrent transaction may have already incrementally updated and committed the view before we can acquire the lock. In `REPEATABLE READ` or `SERIALIZABLE` isolation level, this could lead to an inconsistent state of the view. Therefore, an error is raised to prevent anomalies when this situation is detected.
|
|
||||||
|
|
||||||
Note that if you use PostgreSQL 17 or later, while `refresh_immv` is running, the `search_path` is temporarily changed to `pg_catalog, pg_temp`.
|
Note that if you use PostgreSQL 17 or later, while `refresh_immv` is running, the `search_path` is temporarily changed to `pg_catalog, pg_temp`.
|
||||||
|
|
||||||
|
|
@ -130,25 +111,22 @@ Note that if you use PostgreSQL 17 or later, while `refresh_immv` is running, th
|
||||||
|
|
||||||
`get_immv_def` reconstructs the underlying SELECT command for an IMMV. (This is a decompiled reconstruction, not the original text of the command.)
|
`get_immv_def` reconstructs the underlying SELECT command for an IMMV. (This is a decompiled reconstruction, not the original text of the command.)
|
||||||
```
|
```
|
||||||
pgivm.get_immv_def(immv regclass) RETURNS text
|
get_immv_def(immv regclass) RETURNS text
|
||||||
```
|
```
|
||||||
|
|
||||||
### IMMV metadata catalog
|
### IMMV metadata catalog
|
||||||
|
|
||||||
The catalog `pgivm.pg_ivm_immv` stores IMMV information.
|
The catalog `pg_ivm_immv` stores IMMV information.
|
||||||
|
|
||||||
|Name|Type|Description|
|
|Name|Type|Description|
|
||||||
|:---|:---|:---|
|
|:---|:---|:---|
|
||||||
|immvrelid|regclass|The OID of the IMMV|
|
|immvrelid|regclass|The OID of the IMMV|
|
||||||
|viewdef|text|Query tree (in the form of a nodeToString() representation) for the view definition|
|
|viewdef|text|Query tree (in the form of a nodeToString() representation) for the view definition|
|
||||||
|ispopulated|bool|True if IMMV is currently populated|
|
|ispopulated|bool|True if IMMV is currently populated|
|
||||||
|lastivmupdate|xid8|The transaction ID of the most recent incremental update to the view|
|
|
||||||
|
|
||||||
|
|
||||||
## Example
|
## Example
|
||||||
|
|
||||||
### `CREATE MATERIALIZED VIEW` and `REFRESH MATERIALIZED VIEW`
|
|
||||||
|
|
||||||
In general, IMMVs allow faster updates than `REFRESH MATERIALIZED VIEW` at the price of slower updates to their base tables. Update of base tables is slower because triggers will be invoked and the IMMV is updated in triggers per modification statement.
|
In general, IMMVs allow faster updates than `REFRESH MATERIALIZED VIEW` at the price of slower updates to their base tables. Update of base tables is slower because triggers will be invoked and the IMMV is updated in triggers per modification statement.
|
||||||
|
|
||||||
For example, suppose a normal materialized view defined as below:
|
For example, suppose a normal materialized view defined as below:
|
||||||
|
|
@ -172,12 +150,10 @@ REFRESH MATERIALIZED VIEW
|
||||||
Time: 20575.721 ms (00:20.576)
|
Time: 20575.721 ms (00:20.576)
|
||||||
```
|
```
|
||||||
|
|
||||||
### Creating an IMMV
|
|
||||||
|
|
||||||
On the other hand, after creating IMMV with the same view definition as below:
|
On the other hand, after creating IMMV with the same view definition as below:
|
||||||
|
|
||||||
```
|
```
|
||||||
test=# SELECT pgivm.create_immv('immv',
|
test=# SELECT create_immv('immv',
|
||||||
'SELECT a.aid, b.bid, a.abalance, b.bbalance
|
'SELECT a.aid, b.bid, a.abalance, b.bbalance
|
||||||
FROM pgbench_accounts a JOIN pgbench_branches b USING(bid)');
|
FROM pgbench_accounts a JOIN pgbench_branches b USING(bid)');
|
||||||
NOTICE: created index "immv_index" on immv "immv"
|
NOTICE: created index "immv_index" on immv "immv"
|
||||||
|
|
@ -187,7 +163,7 @@ NOTICE: created index "immv_index" on immv "immv"
|
||||||
(1 row)
|
(1 row)
|
||||||
```
|
```
|
||||||
|
|
||||||
Updating a tuple in a base table takes more than the normal view, but its content is updated automatically and this is faster than the `REFRESH MATERIALIZED VIEW` command.
|
updating a tuple in a base table takes more than the normal view, but its content is updated automatically and this is faster than the `REFRESH MATERIALIZED VIEW` command.
|
||||||
|
|
||||||
```sql
|
```sql
|
||||||
test=# UPDATE pgbench_accounts SET abalance = 1234 WHERE aid = 1;
|
test=# UPDATE pgbench_accounts SET abalance = 1234 WHERE aid = 1;
|
||||||
|
|
@ -201,7 +177,7 @@ test=# SELECT * FROM immv WHERE aid = 1;
|
||||||
(1 row)
|
(1 row)
|
||||||
```
|
```
|
||||||
|
|
||||||
An appropriate index on IMMV is necessary for efficient IVM because we need to look for tuples to be updated in IMMV. If there are no indexes, it will take a long time.
|
An appropriate index on IMMV is necessary for efficient IVM because we need to looks for tuples to be updated in IMMV. If there are no indexes, it will take a long time.
|
||||||
|
|
||||||
Therefore, when an IMMV is created by the `create_immv` function, a unique index is created on it automatically if possible. If the view definition query has a GROUP BY clause, a unique index is created on the columns of GROUP BY expressions. Also, if the view has DISTINCT clause, a unique index is created on all columns in the target list. Otherwise, if the IMMV contains all primary key attributes of its base tables in the target list, a unique index is created on these attributes. In other cases, no index is created.
|
Therefore, when an IMMV is created by the `create_immv` function, a unique index is created on it automatically if possible. If the view definition query has a GROUP BY clause, a unique index is created on the columns of GROUP BY expressions. Also, if the view has DISTINCT clause, a unique index is created on all columns in the target list. Otherwise, if the IMMV contains all primary key attributes of its base tables in the target list, a unique index is created on these attributes. In other cases, no index is created.
|
||||||
|
|
||||||
|
|
@ -216,131 +192,6 @@ UPDATE 1
|
||||||
Time: 3224.741 ms (00:03.225)
|
Time: 3224.741 ms (00:03.225)
|
||||||
```
|
```
|
||||||
|
|
||||||
### IMMV with Aggregate Functions
|
|
||||||
|
|
||||||
You can create an IMMV that includes aggregate functions.
|
|
||||||
|
|
||||||
```sql
|
|
||||||
test=# SELECT pgivm.create_immv('immv_agg',
|
|
||||||
'SELECT bid, count(*), sum(abalance), avg(abalance)
|
|
||||||
FROM pgbench_accounts JOIN pgbench_branches USING(bid) GROUP BY bid');
|
|
||||||
NOTICE: created index "immv_agg_index" on immv "immv_agg"
|
|
||||||
create_immv
|
|
||||||
-------------
|
|
||||||
100
|
|
||||||
(1 row)
|
|
||||||
|
|
||||||
Time: 5772.625 ms (00:05.773)
|
|
||||||
```
|
|
||||||
|
|
||||||
Creating this view takes about five seconds, and the normal refresh operation requires a similar amount of time. The following example demonstrates refreshing the IMMV using `refresh_immv`. The execution time would be approximately the same if you used `REFRESH MATERIALIZED VIEW` on a regular materialized view with the same definition.
|
|
||||||
|
|
||||||
```sql
|
|
||||||
test=# SELECT pgivm.refresh_immv('immv_agg',true);
|
|
||||||
refresh_immv
|
|
||||||
--------------
|
|
||||||
100
|
|
||||||
(1 row)
|
|
||||||
|
|
||||||
Time: 5766.292 ms (00:05.766)
|
|
||||||
```
|
|
||||||
|
|
||||||
When a base table is updated, the IMMV is also automatically updated incrementally, as expected.
|
|
||||||
|
|
||||||
```sql
|
|
||||||
test=# SELECT bid, count, sum, avg FROM immv_agg WHERE bid = 42;
|
|
||||||
bid | count | sum | avg
|
|
||||||
-----+--------+-------+------------------------
|
|
||||||
42 | 100000 | 38774 | 0.38774000000000000000
|
|
||||||
(1 row)
|
|
||||||
|
|
||||||
Time: 3.123 ms
|
|
||||||
|
|
||||||
test=# UPDATE pgbench_accounts SET abalance = abalance + 1000 WHERE aid = 4112345 AND bid = 42;
|
|
||||||
UPDATE 1
|
|
||||||
Time: 16.616 ms
|
|
||||||
|
|
||||||
test=# SELECT bid, count, sum, avg FROM immv_agg WHERE bid = 42;
|
|
||||||
bid | count | sum | avg
|
|
||||||
-----+--------+-------+------------------------
|
|
||||||
42 | 100000 | 39774 | 0.39774000000000000000
|
|
||||||
(1 row)
|
|
||||||
|
|
||||||
Time: 1.987 ms
|
|
||||||
```
|
|
||||||
|
|
||||||
After updating a row in the `pgbench_accounts` table, you can see that the aggregated values in `immv_agg` are updated automatically.
|
|
||||||
|
|
||||||
### Listing IMMVs and Viewing Their Definitions
|
|
||||||
|
|
||||||
You can find all IMMVs in the `pg_ivm_immv` catalog and view their definition queries by executing the `get_immv_def` function."
|
|
||||||
|
|
||||||
```sql
|
|
||||||
test=# SELECT immvrelid AS immv, pgivm.get_immv_def(immvrelid) AS immv_def FROM pgivm.pg_ivm_immv;
|
|
||||||
immv | immv_def
|
|
||||||
----------+--------------------------------------------
|
|
||||||
immv_agg | SELECT pgbench_accounts.bid, +
|
|
||||||
| count(*) AS count, +
|
|
||||||
| sum(pgbench_accounts.abalance) AS sum,+
|
|
||||||
| avg(pgbench_accounts.abalance) AS avg +
|
|
||||||
| FROM (pgbench_accounts +
|
|
||||||
| JOIN pgbench_branches USING (bid)) +
|
|
||||||
| GROUP BY pgbench_accounts.bid
|
|
||||||
immv | SELECT a.aid, +
|
|
||||||
| b.bid, +
|
|
||||||
| a.abalance, +
|
|
||||||
| b.bbalance +
|
|
||||||
| FROM (pgbench_accounts a +
|
|
||||||
| JOIN pgbench_branches b USING (bid))
|
|
||||||
(2 rows)
|
|
||||||
```
|
|
||||||
|
|
||||||
### Dropping an IMMV
|
|
||||||
|
|
||||||
An IMMV can be dropped using the `DROP TABLE` command. Once an IMMV is dropped, its entry is automatically removed from the `pg_ivm_immv` catalog.
|
|
||||||
|
|
||||||
```sql
|
|
||||||
test=# DROP TABLE immv
|
|
||||||
DROP TABLE
|
|
||||||
|
|
||||||
test=# SELECT immvrelid AS immv, pgivm.get_immv_def(immvrelid) AS immv_def FROM pgivm.pg_ivm_immv;
|
|
||||||
immv | immv_def
|
|
||||||
----------+--------------------------------------------
|
|
||||||
immv_agg | SELECT pgbench_accounts.bid, +
|
|
||||||
| count(*) AS count, +
|
|
||||||
| sum(pgbench_accounts.abalance) AS sum,+
|
|
||||||
| avg(pgbench_accounts.abalance) AS avg +
|
|
||||||
| FROM (pgbench_accounts +
|
|
||||||
| JOIN pgbench_branches USING (bid)) +
|
|
||||||
| GROUP BY pgbench_accounts.bid
|
|
||||||
(1 row)
|
|
||||||
```
|
|
||||||
|
|
||||||
### Renaming an IMMV
|
|
||||||
|
|
||||||
An IMMV can be renamed using the `ALTER TABLE` command.
|
|
||||||
|
|
||||||
```sql
|
|
||||||
test=# ALTER TABLE immv_agg RENAME TO immv_agg2;
|
|
||||||
ALTER TABLE
|
|
||||||
|
|
||||||
test=# SELECT immvrelid AS immv, pgivm.get_immv_def(immvrelid) AS immv_def FROM pgivm.pg_ivm_immv;
|
|
||||||
immv | immv_def
|
|
||||||
-----------+--------------------------------------------
|
|
||||||
immv_agg2 | SELECT pgbench_accounts.bid, +
|
|
||||||
| count(*) AS count, +
|
|
||||||
| sum(pgbench_accounts.abalance) AS sum,+
|
|
||||||
| avg(pgbench_accounts.abalance) AS avg +
|
|
||||||
| FROM (pgbench_accounts +
|
|
||||||
| JOIN pgbench_branches USING (bid)) +
|
|
||||||
| GROUP BY pgbench_accounts.bid
|
|
||||||
(1 row)
|
|
||||||
```
|
|
||||||
|
|
||||||
## `pg_dump` and `pg_upgrade`
|
|
||||||
|
|
||||||
After restoring data from a `pg_dump` backup or upgrading `PostgreSQL` using `pg_upgrade`, all IMMVs must be manually dropped and recreated.
|
|
||||||
|
|
||||||
## Supported View Definitions and Restriction
|
## Supported View Definitions and Restriction
|
||||||
|
|
||||||
Currently, IMMV's view definition can contain inner joins, DISTINCT clause, some built-in aggregate functions, simple sub-queries in `FROM` clause, EXISTS sub-queries, and simple CTE (`WITH` query). Inner joins including self-join are supported, but outer joins are not supported. Supported aggregate functions are count, sum, avg, min and max. Other aggregates, sub-queries which contain an aggregate or `DISTINCT` clause, sub-queries in other than `FROM` clause, window functions, `HAVING`, `ORDER BY`, `LIMIT`/`OFFSET`, `UNION`/`INTERSECT`/`EXCEPT`, `DISTINCT ON`, `TABLESAMPLE`, `VALUES`, and `FOR UPDATE`/`SHARE` can not be used in view definition.
|
Currently, IMMV's view definition can contain inner joins, DISTINCT clause, some built-in aggregate functions, simple sub-queries in `FROM` clause, EXISTS sub-queries, and simple CTE (`WITH` query). Inner joins including self-join are supported, but outer joins are not supported. Supported aggregate functions are count, sum, avg, min and max. Other aggregates, sub-queries which contain an aggregate or `DISTINCT` clause, sub-queries in other than `FROM` clause, window functions, `HAVING`, `ORDER BY`, `LIMIT`/`OFFSET`, `UNION`/`INTERSECT`/`EXCEPT`, `DISTINCT ON`, `TABLESAMPLE`, `VALUES`, and `FOR UPDATE`/`SHARE` can not be used in view definition.
|
||||||
|
|
@ -397,7 +248,7 @@ Recursive queries (`WITH RECURSIVE`) are not allowed. Unreferenced CTEs are not
|
||||||
|
|
||||||
`DISTINCT` is allowed in IMMV's definition queries. Suppose an IMMV defined with DISTINCT on a base table containing duplicate tuples. When tuples are deleted from the base table, a tuple in the view is deleted if and only if the multiplicity of the tuple becomes zero. Moreover, when tuples are inserted into the base table, a tuple is inserted into the view only if the same tuple doesn't already exist in it.
|
`DISTINCT` is allowed in IMMV's definition queries. Suppose an IMMV defined with DISTINCT on a base table containing duplicate tuples. When tuples are deleted from the base table, a tuple in the view is deleted if and only if the multiplicity of the tuple becomes zero. Moreover, when tuples are inserted into the base table, a tuple is inserted into the view only if the same tuple doesn't already exist in it.
|
||||||
|
|
||||||
Physically, an IMMV defined with `DISTINCT` contains tuples after eliminating duplicates, and the multiplicity of each tuple is stored in an extra column named `__ivm_count__` that is added when such IMMV is created.
|
Physically, an IMMV defined with `DISTINCT` contains tuples after eliminating duplicates, and the multiplicity of each tuple is stored in a extra column named `__ivm_count__` that is added when such IMMV is created.
|
||||||
|
|
||||||
### TRUNCATE
|
### TRUNCATE
|
||||||
|
|
||||||
|
|
@ -406,31 +257,22 @@ When a base table is truncated, the IMMV is also truncated and the contents beco
|
||||||
|
|
||||||
### Concurrent Transactions
|
### Concurrent Transactions
|
||||||
|
|
||||||
Incremental updates of a view are basically performed in sequentially even with concurrent transactions running.
|
Suppose an IMMV is defined on two base tables and each table was modified in different a concurrent transaction simultaneously. In the transaction which was committed first, the IMMV can be updated considering only the change which happened in this transaction. On the other hand, in order to update the IMMV correctly in the transaction which was committed later, we need to know the changes occurred in both transactions. For this reason, `ExclusiveLock` is held on an IMMV immediately after a base table is modified in `READ COMMITTED` mode to make sure that the IMMV is updated in the latter transaction after the former transaction is committed. In `REPEATABLE READ` or `SERIALIZABLE` mode, an error is raised immediately if lock acquisition fails because any changes which occurred in other transactions are not be visible in these modes and IMMV cannot be updated correctly in such situations. However, as an exception if the IMMV has only one base table and doesn't use DISTINCT or GROUP BY, and the table is modified by `INSERT`, then the lock held on the IMMV is `RowExclusiveLock`.
|
||||||
|
|
||||||
Suppose an IMMV is defined on two base tables and each table is modified in different concurrent transactions simultaneously. In the transaction which was committed first, the IMMV can be updated considering only the change made in that transaction. However, to update the IMMV correctly in the transaction that commits later, we need to account for the changes made in both transactions.
|
|
||||||
|
|
||||||
For this reason, `ExclusiveLock` is held on an IMMV immediately after a base table is modified in `READ COMMITTED` isolation level. This ensures that the IMMV is updated in the latter transaction only after the former transaction has committed. In `REPEATABLE READ` or `SERIALIZABLE` isolation level, an error is raised immediately if lock acquisition fails, as changes made by other transactions are not visible in these levels, and the IMMV cannot be updated correctly in such situations.
|
|
||||||
|
|
||||||
However, as an exception if the IMMV has only one base table, does not use DISTINCT or GROUP BY, and is modified by `INSERT`, then the lock held on the IMMV is `RowExclusiveLock`.
|
|
||||||
|
|
||||||
Even if we are able to acquire a lock, a concurrent transaction may have already incrementally updated and committed the view before we can acquire the lock. In `REPEATABLE READ` or `SERIALIZABLE` isolation level, this could lead to an inconsistent state of the view. Therefore, an error is raised to prevent anomalies when this situation is detected.
|
|
||||||
|
|
||||||
### Row Level Security
|
### Row Level Security
|
||||||
|
|
||||||
If some base tables have row level security policy, rows that are not visible to the materialized view's owner are excluded from the result. In addition, such rows are excluded as well when views are incrementally maintained. However, if a new policy is defined or policies are changed after the materialized view was created, the new policy will not be applied to the view contents. To apply the new policy, you need to refresh or recreate the IMMV.
|
If some base tables have row level security policy, rows that are not visible to the materialized view's owner are excluded from the result. In addition, such rows are excluded as well when views are incrementally maintained. However, if a new policy is defined or policies are changed after the materialized view was created, the new policy will not be applied to the view contents. To apply the new policy, you need to recreate IMMV.
|
||||||
|
|
||||||
### How to Disable or Enable Immediate Maintenance
|
### How to Disable or Enable Immediate Maintenance
|
||||||
|
|
||||||
IVM is effective when we want to keep an IMMV up-to-date and small fraction of a base table is modified infrequently. Due to the overhead of immediate maintenance, IVM is not effective when a base table is modified frequently. Also, when a large part of a base table is modified or large data is inserted into a base table, IVM is not effective and the cost of maintenance can be larger than refresh from scratch.
|
IVM is effective when we want to keep an IMMV up-to-date and small fraction of a base table is modified infrequently. Due to the overhead of immediate maintenance, IVM is not effective when a base table is modified frequently. Also, when a large part of a base table is modified or large data is inserted into a base table, IVM is not effective and the cost of maintenance can be larger than refresh from scratch.
|
||||||
|
|
||||||
In such situation, we can use `refresh_immv` function with `with_data = false` to disable immediate maintenance before modifying a base table. After a base table modification, call `refresh_immv`with `with_data = true` to refresh the view data and enable immediate maintenance.
|
In such situation, we can use `refesh_immv` function with `with_data = false` to disable immediate maintenance before modifying a base table. After a base table modification, call `refresh_immv`with `with_data = true` to refresh the view data and enable immediate maintenance.
|
||||||
|
|
||||||
## Developer
|
## Authors
|
||||||
IVM Development Group
|
IVM Development Group
|
||||||
- Original Authors
|
- https://github.com/yugo-n
|
||||||
- https://github.com/yugo-n
|
- https://github.com/thoshiai
|
||||||
- https://github.com/thoshiai
|
|
||||||
|
|
||||||
## License
|
## License
|
||||||
[PostgreSQL License](https://github.com/sraoss/pg_ivm/blob/main/LICENSE)
|
[PostgreSQL License](https://github.com/sraoss/pg_ivm/blob/main/LICENSE)
|
||||||
|
|
|
||||||
48
createas.c
48
createas.c
|
|
@ -101,11 +101,7 @@ create_immv_internal(List *attrList, IntoClause *into)
|
||||||
CreateStmt *create = makeNode(CreateStmt);
|
CreateStmt *create = makeNode(CreateStmt);
|
||||||
char relkind;
|
char relkind;
|
||||||
Datum toast_options;
|
Datum toast_options;
|
||||||
#if defined(PG_VERSION_NUM) && (PG_VERSION_NUM >= 180000)
|
|
||||||
const char *const validnsps[] = HEAP_RELOPT_NAMESPACES;
|
|
||||||
#else
|
|
||||||
static char *validnsps[] = HEAP_RELOPT_NAMESPACES;
|
static char *validnsps[] = HEAP_RELOPT_NAMESPACES;
|
||||||
#endif
|
|
||||||
ObjectAddress intoRelationAddr;
|
ObjectAddress intoRelationAddr;
|
||||||
|
|
||||||
/* This code supports both CREATE TABLE AS and CREATE MATERIALIZED VIEW */
|
/* This code supports both CREATE TABLE AS and CREATE MATERIALIZED VIEW */
|
||||||
|
|
@ -152,12 +148,7 @@ create_immv_internal(List *attrList, IntoClause *into)
|
||||||
NewRelationCreateToastTable(intoRelationAddr.objectId, toast_options);
|
NewRelationCreateToastTable(intoRelationAddr.objectId, toast_options);
|
||||||
|
|
||||||
/* Create the "view" part of an IMMV. */
|
/* Create the "view" part of an IMMV. */
|
||||||
#if defined(PG_VERSION_NUM) && (PG_VERSION_NUM >= 180000)
|
|
||||||
StoreImmvQuery(intoRelationAddr.objectId, into->viewQuery);
|
|
||||||
#else
|
|
||||||
StoreImmvQuery(intoRelationAddr.objectId, (Query *) into->viewQuery);
|
StoreImmvQuery(intoRelationAddr.objectId, (Query *) into->viewQuery);
|
||||||
#endif
|
|
||||||
|
|
||||||
CommandCounterIncrement();
|
CommandCounterIncrement();
|
||||||
|
|
||||||
return intoRelationAddr;
|
return intoRelationAddr;
|
||||||
|
|
@ -294,7 +285,7 @@ ExecCreateImmv(ParseState *pstate, CreateTableAsStmt *stmt,
|
||||||
{
|
{
|
||||||
Relation matviewRel;
|
Relation matviewRel;
|
||||||
|
|
||||||
RefreshImmvByOid(address.objectId, true, false, pstate->p_sourcetext, qc);
|
RefreshImmvByOid(address.objectId, false, pstate->p_sourcetext, qc);
|
||||||
|
|
||||||
if (qc)
|
if (qc)
|
||||||
qc->commandTag = CMDTAG_SELECT;
|
qc->commandTag = CMDTAG_SELECT;
|
||||||
|
|
@ -304,17 +295,10 @@ ExecCreateImmv(ParseState *pstate, CreateTableAsStmt *stmt,
|
||||||
/* Create an index on incremental maintainable materialized view, if possible */
|
/* Create an index on incremental maintainable materialized view, if possible */
|
||||||
CreateIndexOnIMMV(query, matviewRel);
|
CreateIndexOnIMMV(query, matviewRel);
|
||||||
|
|
||||||
/* Create triggers to prevent IMMV from being changed */
|
/* Create triggers to prevent IMMV from beeing changed */
|
||||||
CreateChangePreventTrigger(address.objectId);
|
CreateChangePreventTrigger(address.objectId);
|
||||||
|
|
||||||
table_close(matviewRel, NoLock);
|
table_close(matviewRel, NoLock);
|
||||||
|
|
||||||
if (IsolationUsesXactSnapshot())
|
|
||||||
ereport(WARNING,
|
|
||||||
(errmsg("inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ"),
|
|
||||||
errdetail("The view may not include effects of a concurrent transaction."),
|
|
||||||
errhint("create_immv should be used in isolation level READ COMMITTED, "
|
|
||||||
"or execute refresh_immv to make sure the view is consistent.")));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return address;
|
return address;
|
||||||
|
|
@ -341,7 +325,7 @@ rewriteQueryForIMMV(Query *query, List *colNames)
|
||||||
FuncCall *fn;
|
FuncCall *fn;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check the length of column name list not to override names of
|
* Check the length of colunm name list not to override names of
|
||||||
* additional columns
|
* additional columns
|
||||||
*/
|
*/
|
||||||
if (list_length(colNames) > list_length(query->targetList))
|
if (list_length(colNames) > list_length(query->targetList))
|
||||||
|
|
@ -750,8 +734,7 @@ CreateIvmTrigger(Oid relOid, Oid viewOid, int16 type, int16 timing, bool ex_lock
|
||||||
ex_lock = true;
|
ex_lock = true;
|
||||||
|
|
||||||
ivm_trigger->funcname =
|
ivm_trigger->funcname =
|
||||||
(timing == TRIGGER_TYPE_BEFORE ?
|
(timing == TRIGGER_TYPE_BEFORE ? SystemFuncName("IVM_immediate_before") : SystemFuncName("IVM_immediate_maintenance"));
|
||||||
PgIvmFuncName("IVM_immediate_before") : PgIvmFuncName("IVM_immediate_maintenance"));
|
|
||||||
|
|
||||||
ivm_trigger->columns = NIL;
|
ivm_trigger->columns = NIL;
|
||||||
ivm_trigger->transitionRels = transitionRels;
|
ivm_trigger->transitionRels = transitionRels;
|
||||||
|
|
@ -1010,7 +993,7 @@ check_ivm_restriction_walker(Node *node, check_ivm_restriction_context *context)
|
||||||
errmsg("WITH query name %s is not supported on incrementally maintainable materialized view", cte->ctename)));
|
errmsg("WITH query name %s is not supported on incrementally maintainable materialized view", cte->ctename)));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* When a table in an unreferenced CTE is TRUNCATEd, the contents of the
|
* When a table in a unreferenced CTE is TRUNCATEd, the contents of the
|
||||||
* IMMV is not affected so it must not be truncated. For confirming it
|
* IMMV is not affected so it must not be truncated. For confirming it
|
||||||
* at the maintenance time, we have to check if the modified table used
|
* at the maintenance time, we have to check if the modified table used
|
||||||
* in a CTE is actually referenced. Although it would be possible, we
|
* in a CTE is actually referenced. Although it would be possible, we
|
||||||
|
|
@ -1052,7 +1035,7 @@ check_ivm_restriction_walker(Node *node, check_ivm_restriction_context *context)
|
||||||
check_ivm_restriction_walker((Node *) from->fromlist, context);
|
check_ivm_restriction_walker((Node *) from->fromlist, context);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* EXIST is allowed directly under FROM clause
|
* EXIEST is allowed directly under FROM clause
|
||||||
*/
|
*/
|
||||||
context->allow_exists = true;
|
context->allow_exists = true;
|
||||||
check_ivm_restriction_walker(from->quals, context);
|
check_ivm_restriction_walker(from->quals, context);
|
||||||
|
|
@ -1124,7 +1107,7 @@ check_ivm_restriction_walker(Node *node, check_ivm_restriction_context *context)
|
||||||
Node *opnode = (Node *) lfirst(lc);
|
Node *opnode = (Node *) lfirst(lc);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* EXIST is allowed under AND expression only if it is
|
* EXIEST is allowed under AND expression only if it is
|
||||||
* directly under WHERE.
|
* directly under WHERE.
|
||||||
*/
|
*/
|
||||||
if (allow_exists)
|
if (allow_exists)
|
||||||
|
|
@ -1363,8 +1346,8 @@ check_aggregate_supports_ivm(Oid aggfnoid)
|
||||||
* Create a unique index on incremental maintainable materialized view.
|
* Create a unique index on incremental maintainable materialized view.
|
||||||
* If the view definition query has a GROUP BY clause, the index is created
|
* If the view definition query has a GROUP BY clause, the index is created
|
||||||
* on the columns of GROUP BY expressions. Otherwise, if the view contains
|
* on the columns of GROUP BY expressions. Otherwise, if the view contains
|
||||||
* all primary key attributes of its base tables in the target list, the index
|
* all primary key attritubes of its base tables in the target list, the index
|
||||||
* is created on these attributes. In other cases, no index is created.
|
* is created on these attritubes. In other cases, no index is created.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
CreateIndexOnIMMV(Query *query, Relation matviewRel)
|
CreateIndexOnIMMV(Query *query, Relation matviewRel)
|
||||||
|
|
@ -1523,18 +1506,10 @@ CreateIndexOnIMMV(Query *query, Relation matviewRel)
|
||||||
|
|
||||||
indexRel = index_open(indexoid, AccessShareLock);
|
indexRel = index_open(indexoid, AccessShareLock);
|
||||||
|
|
||||||
#if defined(PG_VERSION_NUM) && (PG_VERSION_NUM >= 180000)
|
|
||||||
if (CheckIndexCompatible(indexRel->rd_id,
|
|
||||||
index->accessMethod,
|
|
||||||
index->indexParams,
|
|
||||||
index->excludeOpNames,
|
|
||||||
false))
|
|
||||||
#else
|
|
||||||
if (CheckIndexCompatible(indexRel->rd_id,
|
if (CheckIndexCompatible(indexRel->rd_id,
|
||||||
index->accessMethod,
|
index->accessMethod,
|
||||||
index->indexParams,
|
index->indexParams,
|
||||||
index->excludeOpNames))
|
index->excludeOpNames))
|
||||||
#endif
|
|
||||||
hasCompatibleIndex = true;
|
hasCompatibleIndex = true;
|
||||||
|
|
||||||
index_close(indexRel, AccessShareLock);
|
index_close(indexRel, AccessShareLock);
|
||||||
|
|
@ -1558,7 +1533,7 @@ CreateIndexOnIMMV(Query *query, Relation matviewRel)
|
||||||
idxname, RelationGetRelationName(matviewRel))));
|
idxname, RelationGetRelationName(matviewRel))));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Make dependencies so that the index is dropped if any base tables'
|
* Make dependencies so that the index is dropped if any base tables's
|
||||||
* primary key is dropped.
|
* primary key is dropped.
|
||||||
*/
|
*/
|
||||||
foreach(lc, constraintList)
|
foreach(lc, constraintList)
|
||||||
|
|
@ -1721,7 +1696,7 @@ get_primary_key_attnos_from_query(Query *query, List **constraintList)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Store the query for the IMMV to pg_ivm_immv
|
* Store the query for the IMMV to pg_ivwm_immv
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
StoreImmvQuery(Oid viewOid, Query *viewQuery)
|
StoreImmvQuery(Oid viewOid, Query *viewQuery)
|
||||||
|
|
@ -1740,7 +1715,6 @@ StoreImmvQuery(Oid viewOid, Query *viewQuery)
|
||||||
values[Anum_pg_ivm_immv_immvrelid -1 ] = ObjectIdGetDatum(viewOid);
|
values[Anum_pg_ivm_immv_immvrelid -1 ] = ObjectIdGetDatum(viewOid);
|
||||||
values[Anum_pg_ivm_immv_ispopulated -1 ] = BoolGetDatum(false);
|
values[Anum_pg_ivm_immv_ispopulated -1 ] = BoolGetDatum(false);
|
||||||
values[Anum_pg_ivm_immv_viewdef -1 ] = CStringGetTextDatum(querytree);
|
values[Anum_pg_ivm_immv_viewdef -1 ] = CStringGetTextDatum(querytree);
|
||||||
isNulls[Anum_pg_ivm_immv_lastivmupdate -1 ] = true;
|
|
||||||
|
|
||||||
pgIvmImmv = table_open(PgIvmImmvRelationId(), RowExclusiveLock);
|
pgIvmImmv = table_open(PgIvmImmvRelationId(), RowExclusiveLock);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,22 +1,22 @@
|
||||||
CREATE TABLE t (i int PRIMARY KEY);
|
CREATE TABLE t (i int PRIMARY KEY);
|
||||||
INSERT INTO t SELECT generate_series(1, 100);
|
INSERT INTO t SELECT generate_series(1, 100);
|
||||||
SELECT pgivm.create_immv('mv', 'SELECT * FROM t');
|
SELECT create_immv('mv', 'SELECT * FROM t');
|
||||||
NOTICE: created index "mv_index" on immv "mv"
|
NOTICE: created index "mv_index" on immv "mv"
|
||||||
create_immv
|
create_immv
|
||||||
-------------
|
-------------
|
||||||
100
|
100
|
||||||
(1 row)
|
(1 row)
|
||||||
|
|
||||||
SELECT pgivm.create_immv(' mv2 ( x ) ', 'SELECT * FROM t WHERE i%2 = 0');
|
SELECT create_immv(' mv2 ( x ) ', 'SELECT * FROM t WHERE i%2 = 0');
|
||||||
NOTICE: created index "mv2_index" on immv "mv2"
|
NOTICE: created index "mv2_index" on immv "mv2"
|
||||||
create_immv
|
create_immv
|
||||||
-------------
|
-------------
|
||||||
50
|
50
|
||||||
(1 row)
|
(1 row)
|
||||||
|
|
||||||
SELECT pgivm.create_immv('mv3', 'WITH d AS (DELETE FROM t RETURNING NULL) SELECT * FROM t');
|
SELECT create_immv('mv3', 'WITH d AS (DELETE FROM t RETURNING NULL) SELECT * FROM t');
|
||||||
ERROR: materialized views must not use data-modifying statements in WITH
|
ERROR: materialized views must not use data-modifying statements in WITH
|
||||||
SELECT immvrelid, pgivm.get_immv_def(immvrelid) FROM pgivm.pg_ivm_immv ORDER BY 1;
|
SELECT immvrelid, get_immv_def(immvrelid) FROM pg_ivm_immv ORDER BY 1;
|
||||||
immvrelid | get_immv_def
|
immvrelid | get_immv_def
|
||||||
-----------+-----------------------
|
-----------+-----------------------
|
||||||
mv | SELECT i +
|
mv | SELECT i +
|
||||||
|
|
@ -27,20 +27,20 @@ SELECT immvrelid, pgivm.get_immv_def(immvrelid) FROM pgivm.pg_ivm_immv ORDER BY
|
||||||
(2 rows)
|
(2 rows)
|
||||||
|
|
||||||
-- contain immv
|
-- contain immv
|
||||||
SELECT pgivm.create_immv('mv_in_immv01', 'SELECT i FROM mv');
|
SELECT create_immv('mv_in_immv01', 'SELECT i FROM mv');
|
||||||
ERROR: including IMMV in definition is not supported on incrementally maintainable materialized view
|
ERROR: including IMMV in definition is not supported on incrementally maintainable materialized view
|
||||||
SELECT pgivm.create_immv('mv_in_immv02', 'SELECT t.i FROM t INNER JOIN mv2 ON t.i = mv2.x');
|
SELECT create_immv('mv_in_immv02', 'SELECT t.i FROM t INNER JOIN mv2 ON t.i = mv2.x');
|
||||||
ERROR: including IMMV in definition is not supported on incrementally maintainable materialized view
|
ERROR: including IMMV in definition is not supported on incrementally maintainable materialized view
|
||||||
-- SQL other than SELECT
|
-- SQL other than SELECT
|
||||||
SELECT pgivm.create_immv('mv_in_create', 'CREATE TABLE in_create(i int)');
|
SELECT create_immv('mv_in_create', 'CREATE TABLE in_create(i int)');
|
||||||
ERROR: view definition must specify SELECT statement
|
ERROR: view definition must specify SELECT statement
|
||||||
SELECT pgivm.create_immv('mv_in_insert', 'INSERT INTO t VALUES(10)');
|
SELECT create_immv('mv_in_insert', 'INSERT INTO t VALUES(10)');
|
||||||
ERROR: view definition must specify SELECT statement
|
ERROR: view definition must specify SELECT statement
|
||||||
SELECT pgivm.create_immv('mv_in_update', 'UPDATE t SET i = 10');
|
SELECT create_immv('mv_in_update', 'UPDATE t SET i = 10');
|
||||||
ERROR: view definition must specify SELECT statement
|
ERROR: view definition must specify SELECT statement
|
||||||
SELECT pgivm.create_immv('mv_in_delete', 'DELETE FROM t');
|
SELECT create_immv('mv_in_delete', 'DELETE FROM t');
|
||||||
ERROR: view definition must specify SELECT statement
|
ERROR: view definition must specify SELECT statement
|
||||||
SELECT pgivm.create_immv('mv_in_drop', 'DROP TABLE t');
|
SELECT create_immv('mv_in_drop', 'DROP TABLE t');
|
||||||
ERROR: view definition must specify SELECT statement
|
ERROR: view definition must specify SELECT statement
|
||||||
DROP TABLE t;
|
DROP TABLE t;
|
||||||
ERROR: cannot drop table t because other objects depend on it
|
ERROR: cannot drop table t because other objects depend on it
|
||||||
|
|
@ -48,7 +48,7 @@ DETAIL: table mv depends on table t
|
||||||
table mv2 depends on table t
|
table mv2 depends on table t
|
||||||
HINT: Use DROP ... CASCADE to drop the dependent objects too.
|
HINT: Use DROP ... CASCADE to drop the dependent objects too.
|
||||||
DROP TABLE mv;
|
DROP TABLE mv;
|
||||||
SELECT immvrelid, pgivm.get_immv_def(immvrelid) FROM pgivm.pg_ivm_immv ORDER BY 1;
|
SELECT immvrelid, get_immv_def(immvrelid) FROM pg_ivm_immv ORDER BY 1;
|
||||||
immvrelid | get_immv_def
|
immvrelid | get_immv_def
|
||||||
-----------+-----------------------
|
-----------+-----------------------
|
||||||
mv2 | SELECT i AS x +
|
mv2 | SELECT i AS x +
|
||||||
|
|
@ -57,7 +57,7 @@ SELECT immvrelid, pgivm.get_immv_def(immvrelid) FROM pgivm.pg_ivm_immv ORDER BY
|
||||||
(1 row)
|
(1 row)
|
||||||
|
|
||||||
DROP TABLE mv2;
|
DROP TABLE mv2;
|
||||||
SELECT immvrelid, pgivm.get_immv_def(immvrelid) FROM pgivm.pg_ivm_immv ORDER BY 1;
|
SELECT immvrelid, get_immv_def(immvrelid) FROM pg_ivm_immv ORDER BY 1;
|
||||||
immvrelid | get_immv_def
|
immvrelid | get_immv_def
|
||||||
-----------+--------------
|
-----------+--------------
|
||||||
(0 rows)
|
(0 rows)
|
||||||
|
|
|
||||||
|
|
@ -1,325 +0,0 @@
|
||||||
Parsed test spec with 2 sessions
|
|
||||||
|
|
||||||
starting permutation: s1 create s2 insert c1 check2 c2 mv
|
|
||||||
step s1: SELECT;
|
|
||||||
tx1: NOTICE: could not create an index on immv "mv" automatically
|
|
||||||
DETAIL: This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
|
|
||||||
HINT: Create an index on the immv for efficient incremental maintenance.
|
|
||||||
step create:
|
|
||||||
SELECT pgivm.create_immv('mv(x,y)', 'SELECT * FROM a a1, a a2 WHERE a1.i = a2.i');
|
|
||||||
CREATE FUNCTION check_mv() RETURNS text AS
|
|
||||||
$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
|
|
||||||
FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
|
|
||||||
(SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
|
|
||||||
|
|
||||||
create_immv
|
|
||||||
-----------
|
|
||||||
1
|
|
||||||
(1 row)
|
|
||||||
|
|
||||||
step s2: SELECT;
|
|
||||||
step insert: INSERT INTO a VALUES (2); <waiting ...>
|
|
||||||
step c1: COMMIT;
|
|
||||||
step insert: <... completed>
|
|
||||||
step check2: SELECT check_mv();
|
|
||||||
check_mv
|
|
||||||
--------
|
|
||||||
ok
|
|
||||||
(1 row)
|
|
||||||
|
|
||||||
step c2: COMMIT;
|
|
||||||
step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
|
|
||||||
x|y
|
|
||||||
-+-
|
|
||||||
1|1
|
|
||||||
2|2
|
|
||||||
(2 rows)
|
|
||||||
|
|
||||||
check_mv
|
|
||||||
--------
|
|
||||||
ok
|
|
||||||
(1 row)
|
|
||||||
|
|
||||||
|
|
||||||
starting permutation: s1 create s2 c1 insert check2 c2 mv
|
|
||||||
step s1: SELECT;
|
|
||||||
tx1: NOTICE: could not create an index on immv "mv" automatically
|
|
||||||
DETAIL: This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
|
|
||||||
HINT: Create an index on the immv for efficient incremental maintenance.
|
|
||||||
step create:
|
|
||||||
SELECT pgivm.create_immv('mv(x,y)', 'SELECT * FROM a a1, a a2 WHERE a1.i = a2.i');
|
|
||||||
CREATE FUNCTION check_mv() RETURNS text AS
|
|
||||||
$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
|
|
||||||
FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
|
|
||||||
(SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
|
|
||||||
|
|
||||||
create_immv
|
|
||||||
-----------
|
|
||||||
1
|
|
||||||
(1 row)
|
|
||||||
|
|
||||||
step s2: SELECT;
|
|
||||||
step c1: COMMIT;
|
|
||||||
step insert: INSERT INTO a VALUES (2);
|
|
||||||
step check2: SELECT check_mv();
|
|
||||||
check_mv
|
|
||||||
--------
|
|
||||||
ok
|
|
||||||
(1 row)
|
|
||||||
|
|
||||||
step c2: COMMIT;
|
|
||||||
step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
|
|
||||||
x|y
|
|
||||||
-+-
|
|
||||||
1|1
|
|
||||||
2|2
|
|
||||||
(2 rows)
|
|
||||||
|
|
||||||
check_mv
|
|
||||||
--------
|
|
||||||
ok
|
|
||||||
(1 row)
|
|
||||||
|
|
||||||
|
|
||||||
starting permutation: s1 s2 create insert c1 check2 c2 mv
|
|
||||||
step s1: SELECT;
|
|
||||||
step s2: SELECT;
|
|
||||||
tx1: NOTICE: could not create an index on immv "mv" automatically
|
|
||||||
DETAIL: This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
|
|
||||||
HINT: Create an index on the immv for efficient incremental maintenance.
|
|
||||||
step create:
|
|
||||||
SELECT pgivm.create_immv('mv(x,y)', 'SELECT * FROM a a1, a a2 WHERE a1.i = a2.i');
|
|
||||||
CREATE FUNCTION check_mv() RETURNS text AS
|
|
||||||
$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
|
|
||||||
FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
|
|
||||||
(SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
|
|
||||||
|
|
||||||
create_immv
|
|
||||||
-----------
|
|
||||||
1
|
|
||||||
(1 row)
|
|
||||||
|
|
||||||
step insert: INSERT INTO a VALUES (2); <waiting ...>
|
|
||||||
step c1: COMMIT;
|
|
||||||
step insert: <... completed>
|
|
||||||
step check2: SELECT check_mv();
|
|
||||||
check_mv
|
|
||||||
--------
|
|
||||||
ok
|
|
||||||
(1 row)
|
|
||||||
|
|
||||||
step c2: COMMIT;
|
|
||||||
step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
|
|
||||||
x|y
|
|
||||||
-+-
|
|
||||||
1|1
|
|
||||||
2|2
|
|
||||||
(2 rows)
|
|
||||||
|
|
||||||
check_mv
|
|
||||||
--------
|
|
||||||
ok
|
|
||||||
(1 row)
|
|
||||||
|
|
||||||
|
|
||||||
starting permutation: s1 s2 insert create c2 check1 c1 mv
|
|
||||||
step s1: SELECT;
|
|
||||||
step s2: SELECT;
|
|
||||||
step insert: INSERT INTO a VALUES (2);
|
|
||||||
step create:
|
|
||||||
SELECT pgivm.create_immv('mv(x,y)', 'SELECT * FROM a a1, a a2 WHERE a1.i = a2.i');
|
|
||||||
CREATE FUNCTION check_mv() RETURNS text AS
|
|
||||||
$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
|
|
||||||
FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
|
|
||||||
(SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
|
|
||||||
<waiting ...>
|
|
||||||
step c2: COMMIT;
|
|
||||||
tx1: NOTICE: could not create an index on immv "mv" automatically
|
|
||||||
DETAIL: This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
|
|
||||||
HINT: Create an index on the immv for efficient incremental maintenance.
|
|
||||||
step create: <... completed>
|
|
||||||
create_immv
|
|
||||||
-----------
|
|
||||||
2
|
|
||||||
(1 row)
|
|
||||||
|
|
||||||
step check1: SELECT check_mv();
|
|
||||||
check_mv
|
|
||||||
--------
|
|
||||||
ok
|
|
||||||
(1 row)
|
|
||||||
|
|
||||||
step c1: COMMIT;
|
|
||||||
step mv: SELECT * FROM mv ORDER 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 immv "mv" automatically
|
|
||||||
DETAIL: This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
|
|
||||||
HINT: Create an index on the immv for efficient incremental maintenance.
|
|
||||||
step create:
|
|
||||||
SELECT pgivm.create_immv('mv(x,y)', 'SELECT * FROM a a1, a a2 WHERE a1.i = a2.i');
|
|
||||||
CREATE FUNCTION check_mv() RETURNS text AS
|
|
||||||
$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
|
|
||||||
FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
|
|
||||||
(SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
|
|
||||||
|
|
||||||
create_immv
|
|
||||||
-----------
|
|
||||||
1
|
|
||||||
(1 row)
|
|
||||||
|
|
||||||
step c1: COMMIT;
|
|
||||||
step insert: INSERT INTO a VALUES (2);
|
|
||||||
step check2: SELECT check_mv();
|
|
||||||
check_mv
|
|
||||||
--------
|
|
||||||
ok
|
|
||||||
(1 row)
|
|
||||||
|
|
||||||
step c2: COMMIT;
|
|
||||||
step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
|
|
||||||
x|y
|
|
||||||
-+-
|
|
||||||
1|1
|
|
||||||
2|2
|
|
||||||
(2 rows)
|
|
||||||
|
|
||||||
check_mv
|
|
||||||
--------
|
|
||||||
ok
|
|
||||||
(1 row)
|
|
||||||
|
|
||||||
|
|
||||||
starting permutation: s2 insert s1 create c2 check1 c1 mv
|
|
||||||
step s2: SELECT;
|
|
||||||
step insert: INSERT INTO a VALUES (2);
|
|
||||||
step s1: SELECT;
|
|
||||||
step create:
|
|
||||||
SELECT pgivm.create_immv('mv(x,y)', 'SELECT * FROM a a1, a a2 WHERE a1.i = a2.i');
|
|
||||||
CREATE FUNCTION check_mv() RETURNS text AS
|
|
||||||
$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
|
|
||||||
FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
|
|
||||||
(SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
|
|
||||||
<waiting ...>
|
|
||||||
step c2: COMMIT;
|
|
||||||
tx1: NOTICE: could not create an index on immv "mv" automatically
|
|
||||||
DETAIL: This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
|
|
||||||
HINT: Create an index on the immv for efficient incremental maintenance.
|
|
||||||
step create: <... completed>
|
|
||||||
create_immv
|
|
||||||
-----------
|
|
||||||
2
|
|
||||||
(1 row)
|
|
||||||
|
|
||||||
step check1: SELECT check_mv();
|
|
||||||
check_mv
|
|
||||||
--------
|
|
||||||
ok
|
|
||||||
(1 row)
|
|
||||||
|
|
||||||
step c1: COMMIT;
|
|
||||||
step mv: SELECT * FROM mv ORDER BY 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 immv "mv" automatically
|
|
||||||
DETAIL: This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
|
|
||||||
HINT: Create an index on the immv for efficient incremental maintenance.
|
|
||||||
step create:
|
|
||||||
SELECT pgivm.create_immv('mv(x,y)', 'SELECT * FROM a a1, a a2 WHERE a1.i = a2.i');
|
|
||||||
CREATE FUNCTION check_mv() RETURNS text AS
|
|
||||||
$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
|
|
||||||
FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
|
|
||||||
(SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
|
|
||||||
|
|
||||||
create_immv
|
|
||||||
-----------
|
|
||||||
2
|
|
||||||
(1 row)
|
|
||||||
|
|
||||||
step check1: SELECT check_mv();
|
|
||||||
check_mv
|
|
||||||
--------
|
|
||||||
ok
|
|
||||||
(1 row)
|
|
||||||
|
|
||||||
step c1: COMMIT;
|
|
||||||
step mv: SELECT * FROM mv ORDER BY 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 immv "mv" automatically
|
|
||||||
DETAIL: This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
|
|
||||||
HINT: Create an index on the immv for efficient incremental maintenance.
|
|
||||||
step create:
|
|
||||||
SELECT pgivm.create_immv('mv(x,y)', 'SELECT * FROM a a1, a a2 WHERE a1.i = a2.i');
|
|
||||||
CREATE FUNCTION check_mv() RETURNS text AS
|
|
||||||
$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
|
|
||||||
FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
|
|
||||||
(SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
|
|
||||||
|
|
||||||
create_immv
|
|
||||||
-----------
|
|
||||||
2
|
|
||||||
(1 row)
|
|
||||||
|
|
||||||
step check1: SELECT check_mv();
|
|
||||||
check_mv
|
|
||||||
--------
|
|
||||||
ok
|
|
||||||
(1 row)
|
|
||||||
|
|
||||||
step c1: COMMIT;
|
|
||||||
step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
|
|
||||||
x|y
|
|
||||||
-+-
|
|
||||||
1|1
|
|
||||||
2|2
|
|
||||||
(2 rows)
|
|
||||||
|
|
||||||
check_mv
|
|
||||||
--------
|
|
||||||
ok
|
|
||||||
(1 row)
|
|
||||||
|
|
||||||
|
|
@ -1,345 +0,0 @@
|
||||||
Parsed test spec with 2 sessions
|
|
||||||
|
|
||||||
starting permutation: s1 create s2 insert c1 check2 c2 mv
|
|
||||||
step s1: SELECT;
|
|
||||||
tx1: NOTICE: could not create an index on immv "mv" automatically
|
|
||||||
DETAIL: This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
|
|
||||||
HINT: Create an index on the immv for efficient incremental maintenance.
|
|
||||||
tx1: WARNING: inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
|
|
||||||
DETAIL: The view may not include effects of a concurrent transaction.
|
|
||||||
HINT: create_immv should be used in isolation level READ COMMITTED, or execute refresh_immv to make sure the view is consistent.
|
|
||||||
step create:
|
|
||||||
SELECT pgivm.create_immv('mv(x,y)', 'SELECT * FROM a a1, a a2 WHERE a1.i = a2.i');
|
|
||||||
CREATE FUNCTION check_mv() RETURNS text AS
|
|
||||||
$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
|
|
||||||
FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
|
|
||||||
(SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
|
|
||||||
|
|
||||||
create_immv
|
|
||||||
-----------
|
|
||||||
1
|
|
||||||
(1 row)
|
|
||||||
|
|
||||||
step s2: SELECT;
|
|
||||||
step insert: INSERT INTO a VALUES (2); <waiting ...>
|
|
||||||
step c1: COMMIT;
|
|
||||||
step insert: <... completed>
|
|
||||||
step check2: SELECT check_mv();
|
|
||||||
check_mv
|
|
||||||
--------
|
|
||||||
ok
|
|
||||||
(1 row)
|
|
||||||
|
|
||||||
step c2: COMMIT;
|
|
||||||
step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
|
|
||||||
x|y
|
|
||||||
-+-
|
|
||||||
1|1
|
|
||||||
2|2
|
|
||||||
(2 rows)
|
|
||||||
|
|
||||||
check_mv
|
|
||||||
--------
|
|
||||||
ok
|
|
||||||
(1 row)
|
|
||||||
|
|
||||||
|
|
||||||
starting permutation: s1 create s2 c1 insert check2 c2 mv
|
|
||||||
step s1: SELECT;
|
|
||||||
tx1: NOTICE: could not create an index on immv "mv" automatically
|
|
||||||
DETAIL: This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
|
|
||||||
HINT: Create an index on the immv for efficient incremental maintenance.
|
|
||||||
tx1: WARNING: inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
|
|
||||||
DETAIL: The view may not include effects of a concurrent transaction.
|
|
||||||
HINT: create_immv should be used in isolation level READ COMMITTED, or execute refresh_immv to make sure the view is consistent.
|
|
||||||
step create:
|
|
||||||
SELECT pgivm.create_immv('mv(x,y)', 'SELECT * FROM a a1, a a2 WHERE a1.i = a2.i');
|
|
||||||
CREATE FUNCTION check_mv() RETURNS text AS
|
|
||||||
$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
|
|
||||||
FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
|
|
||||||
(SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
|
|
||||||
|
|
||||||
create_immv
|
|
||||||
-----------
|
|
||||||
1
|
|
||||||
(1 row)
|
|
||||||
|
|
||||||
step s2: SELECT;
|
|
||||||
step c1: COMMIT;
|
|
||||||
step insert: INSERT INTO a VALUES (2);
|
|
||||||
step check2: SELECT check_mv();
|
|
||||||
check_mv
|
|
||||||
--------
|
|
||||||
ok
|
|
||||||
(1 row)
|
|
||||||
|
|
||||||
step c2: COMMIT;
|
|
||||||
step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
|
|
||||||
x|y
|
|
||||||
-+-
|
|
||||||
1|1
|
|
||||||
2|2
|
|
||||||
(2 rows)
|
|
||||||
|
|
||||||
check_mv
|
|
||||||
--------
|
|
||||||
ok
|
|
||||||
(1 row)
|
|
||||||
|
|
||||||
|
|
||||||
starting permutation: s1 s2 create insert c1 check2 c2 mv
|
|
||||||
step s1: SELECT;
|
|
||||||
step s2: SELECT;
|
|
||||||
tx1: NOTICE: could not create an index on immv "mv" automatically
|
|
||||||
DETAIL: This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
|
|
||||||
HINT: Create an index on the immv for efficient incremental maintenance.
|
|
||||||
tx1: WARNING: inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
|
|
||||||
DETAIL: The view may not include effects of a concurrent transaction.
|
|
||||||
HINT: create_immv should be used in isolation level READ COMMITTED, or execute refresh_immv to make sure the view is consistent.
|
|
||||||
step create:
|
|
||||||
SELECT pgivm.create_immv('mv(x,y)', 'SELECT * FROM a a1, a a2 WHERE a1.i = a2.i');
|
|
||||||
CREATE FUNCTION check_mv() RETURNS text AS
|
|
||||||
$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
|
|
||||||
FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
|
|
||||||
(SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
|
|
||||||
|
|
||||||
create_immv
|
|
||||||
-----------
|
|
||||||
1
|
|
||||||
(1 row)
|
|
||||||
|
|
||||||
step insert: INSERT INTO a VALUES (2); <waiting ...>
|
|
||||||
step c1: COMMIT;
|
|
||||||
step insert: <... completed>
|
|
||||||
step check2: SELECT check_mv();
|
|
||||||
check_mv
|
|
||||||
--------
|
|
||||||
ok
|
|
||||||
(1 row)
|
|
||||||
|
|
||||||
step c2: COMMIT;
|
|
||||||
step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
|
|
||||||
x|y
|
|
||||||
-+-
|
|
||||||
1|1
|
|
||||||
2|2
|
|
||||||
(2 rows)
|
|
||||||
|
|
||||||
check_mv
|
|
||||||
--------
|
|
||||||
ok
|
|
||||||
(1 row)
|
|
||||||
|
|
||||||
|
|
||||||
starting permutation: s1 s2 insert create c2 check1 c1 mv
|
|
||||||
step s1: SELECT;
|
|
||||||
step s2: SELECT;
|
|
||||||
step insert: INSERT INTO a VALUES (2);
|
|
||||||
step create:
|
|
||||||
SELECT pgivm.create_immv('mv(x,y)', 'SELECT * FROM a a1, a a2 WHERE a1.i = a2.i');
|
|
||||||
CREATE FUNCTION check_mv() RETURNS text AS
|
|
||||||
$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
|
|
||||||
FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
|
|
||||||
(SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
|
|
||||||
<waiting ...>
|
|
||||||
step c2: COMMIT;
|
|
||||||
tx1: NOTICE: could not create an index on immv "mv" automatically
|
|
||||||
DETAIL: This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
|
|
||||||
HINT: Create an index on the immv for efficient incremental maintenance.
|
|
||||||
tx1: WARNING: inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
|
|
||||||
DETAIL: The view may not include effects of a concurrent transaction.
|
|
||||||
HINT: create_immv should be used in isolation level READ COMMITTED, or execute refresh_immv to make sure the view is consistent.
|
|
||||||
step create: <... completed>
|
|
||||||
create_immv
|
|
||||||
-----------
|
|
||||||
1
|
|
||||||
(1 row)
|
|
||||||
|
|
||||||
step check1: SELECT check_mv();
|
|
||||||
check_mv
|
|
||||||
--------
|
|
||||||
ok
|
|
||||||
(1 row)
|
|
||||||
|
|
||||||
step c1: COMMIT;
|
|
||||||
step 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 immv "mv" automatically
|
|
||||||
DETAIL: This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
|
|
||||||
HINT: Create an index on the immv for efficient incremental maintenance.
|
|
||||||
tx1: WARNING: inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
|
|
||||||
DETAIL: The view may not include effects of a concurrent transaction.
|
|
||||||
HINT: create_immv should be used in isolation level READ COMMITTED, or execute refresh_immv to make sure the view is consistent.
|
|
||||||
step create:
|
|
||||||
SELECT pgivm.create_immv('mv(x,y)', 'SELECT * FROM a a1, a a2 WHERE a1.i = a2.i');
|
|
||||||
CREATE FUNCTION check_mv() RETURNS text AS
|
|
||||||
$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
|
|
||||||
FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
|
|
||||||
(SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
|
|
||||||
|
|
||||||
create_immv
|
|
||||||
-----------
|
|
||||||
1
|
|
||||||
(1 row)
|
|
||||||
|
|
||||||
step c1: COMMIT;
|
|
||||||
step insert: INSERT INTO a VALUES (2);
|
|
||||||
step check2: SELECT check_mv();
|
|
||||||
check_mv
|
|
||||||
--------
|
|
||||||
ok
|
|
||||||
(1 row)
|
|
||||||
|
|
||||||
step c2: COMMIT;
|
|
||||||
step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
|
|
||||||
x|y
|
|
||||||
-+-
|
|
||||||
1|1
|
|
||||||
2|2
|
|
||||||
(2 rows)
|
|
||||||
|
|
||||||
check_mv
|
|
||||||
--------
|
|
||||||
ok
|
|
||||||
(1 row)
|
|
||||||
|
|
||||||
|
|
||||||
starting permutation: s2 insert s1 create c2 check1 c1 mv
|
|
||||||
step s2: SELECT;
|
|
||||||
step insert: INSERT INTO a VALUES (2);
|
|
||||||
step s1: SELECT;
|
|
||||||
step create:
|
|
||||||
SELECT pgivm.create_immv('mv(x,y)', 'SELECT * FROM a a1, a a2 WHERE a1.i = a2.i');
|
|
||||||
CREATE FUNCTION check_mv() RETURNS text AS
|
|
||||||
$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
|
|
||||||
FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
|
|
||||||
(SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
|
|
||||||
<waiting ...>
|
|
||||||
step c2: COMMIT;
|
|
||||||
tx1: NOTICE: could not create an index on immv "mv" automatically
|
|
||||||
DETAIL: This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
|
|
||||||
HINT: Create an index on the immv for efficient incremental maintenance.
|
|
||||||
tx1: WARNING: inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
|
|
||||||
DETAIL: The view may not include effects of a concurrent transaction.
|
|
||||||
HINT: create_immv should be used in isolation level READ COMMITTED, or execute refresh_immv to make sure the view is consistent.
|
|
||||||
step create: <... completed>
|
|
||||||
create_immv
|
|
||||||
-----------
|
|
||||||
1
|
|
||||||
(1 row)
|
|
||||||
|
|
||||||
step check1: SELECT check_mv();
|
|
||||||
check_mv
|
|
||||||
--------
|
|
||||||
ok
|
|
||||||
(1 row)
|
|
||||||
|
|
||||||
step c1: COMMIT;
|
|
||||||
step mv: 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 immv "mv" automatically
|
|
||||||
DETAIL: This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
|
|
||||||
HINT: Create an index on the immv for efficient incremental maintenance.
|
|
||||||
tx1: WARNING: inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
|
|
||||||
DETAIL: The view may not include effects of a concurrent transaction.
|
|
||||||
HINT: create_immv should be used in isolation level READ COMMITTED, or execute refresh_immv to make sure the view is consistent.
|
|
||||||
step create:
|
|
||||||
SELECT pgivm.create_immv('mv(x,y)', 'SELECT * FROM a a1, a a2 WHERE a1.i = a2.i');
|
|
||||||
CREATE FUNCTION check_mv() RETURNS text AS
|
|
||||||
$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
|
|
||||||
FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
|
|
||||||
(SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
|
|
||||||
|
|
||||||
create_immv
|
|
||||||
-----------
|
|
||||||
1
|
|
||||||
(1 row)
|
|
||||||
|
|
||||||
step check1: SELECT check_mv();
|
|
||||||
check_mv
|
|
||||||
--------
|
|
||||||
ok
|
|
||||||
(1 row)
|
|
||||||
|
|
||||||
step c1: COMMIT;
|
|
||||||
step mv: 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 immv "mv" automatically
|
|
||||||
DETAIL: This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
|
|
||||||
HINT: Create an index on the immv for efficient incremental maintenance.
|
|
||||||
tx1: WARNING: inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
|
|
||||||
DETAIL: The view may not include effects of a concurrent transaction.
|
|
||||||
HINT: create_immv should be used in isolation level READ COMMITTED, or execute refresh_immv to make sure the view is consistent.
|
|
||||||
step create:
|
|
||||||
SELECT pgivm.create_immv('mv(x,y)', 'SELECT * FROM a a1, a a2 WHERE a1.i = a2.i');
|
|
||||||
CREATE FUNCTION check_mv() RETURNS text AS
|
|
||||||
$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
|
|
||||||
FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
|
|
||||||
(SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
|
|
||||||
|
|
||||||
create_immv
|
|
||||||
-----------
|
|
||||||
1
|
|
||||||
(1 row)
|
|
||||||
|
|
||||||
step check1: SELECT check_mv();
|
|
||||||
check_mv
|
|
||||||
--------
|
|
||||||
ok
|
|
||||||
(1 row)
|
|
||||||
|
|
||||||
step c1: COMMIT;
|
|
||||||
step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
|
|
||||||
x|y
|
|
||||||
-+-
|
|
||||||
1|1
|
|
||||||
(1 row)
|
|
||||||
|
|
||||||
check_mv
|
|
||||||
--------
|
|
||||||
ng
|
|
||||||
(1 row)
|
|
||||||
|
|
||||||
|
|
@ -1,329 +0,0 @@
|
||||||
Parsed test spec with 2 sessions
|
|
||||||
|
|
||||||
starting permutation: s1 create s2 insert c1 check2 c2 mv
|
|
||||||
step s1: SELECT;
|
|
||||||
tx1: NOTICE: could not create an index on immv "mv" automatically
|
|
||||||
DETAIL: This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
|
|
||||||
HINT: Create an index on the immv for efficient incremental maintenance.
|
|
||||||
tx1: WARNING: inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
|
|
||||||
DETAIL: The view may not include effects of a concurrent transaction.
|
|
||||||
HINT: create_immv should be used in isolation level READ COMMITTED, or execute refresh_immv to make sure the view is consistent.
|
|
||||||
step create:
|
|
||||||
SELECT pgivm.create_immv('mv(x,y)', 'SELECT * FROM a a1, a a2 WHERE a1.i = a2.i');
|
|
||||||
CREATE FUNCTION check_mv() RETURNS text AS
|
|
||||||
$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
|
|
||||||
FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
|
|
||||||
(SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
|
|
||||||
|
|
||||||
create_immv
|
|
||||||
-----------
|
|
||||||
1
|
|
||||||
(1 row)
|
|
||||||
|
|
||||||
step s2: SELECT;
|
|
||||||
step insert: INSERT INTO a VALUES (2); <waiting ...>
|
|
||||||
step c1: COMMIT;
|
|
||||||
step insert: <... completed>
|
|
||||||
ERROR: could not serialize access due to read/write dependencies among transactions
|
|
||||||
step check2: SELECT check_mv();
|
|
||||||
ERROR: current transaction is aborted, commands ignored until end of transaction block
|
|
||||||
step c2: COMMIT;
|
|
||||||
step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
|
|
||||||
x|y
|
|
||||||
-+-
|
|
||||||
1|1
|
|
||||||
(1 row)
|
|
||||||
|
|
||||||
check_mv
|
|
||||||
--------
|
|
||||||
ok
|
|
||||||
(1 row)
|
|
||||||
|
|
||||||
|
|
||||||
starting permutation: s1 create s2 c1 insert check2 c2 mv
|
|
||||||
step s1: SELECT;
|
|
||||||
tx1: NOTICE: could not create an index on immv "mv" automatically
|
|
||||||
DETAIL: This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
|
|
||||||
HINT: Create an index on the immv for efficient incremental maintenance.
|
|
||||||
tx1: WARNING: inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
|
|
||||||
DETAIL: The view may not include effects of a concurrent transaction.
|
|
||||||
HINT: create_immv should be used in isolation level READ COMMITTED, or execute refresh_immv to make sure the view is consistent.
|
|
||||||
step create:
|
|
||||||
SELECT pgivm.create_immv('mv(x,y)', 'SELECT * FROM a a1, a a2 WHERE a1.i = a2.i');
|
|
||||||
CREATE FUNCTION check_mv() RETURNS text AS
|
|
||||||
$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
|
|
||||||
FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
|
|
||||||
(SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
|
|
||||||
|
|
||||||
create_immv
|
|
||||||
-----------
|
|
||||||
1
|
|
||||||
(1 row)
|
|
||||||
|
|
||||||
step s2: SELECT;
|
|
||||||
step c1: COMMIT;
|
|
||||||
step insert: INSERT INTO a VALUES (2);
|
|
||||||
ERROR: could not serialize access due to read/write dependencies among transactions
|
|
||||||
step check2: SELECT check_mv();
|
|
||||||
ERROR: current transaction is aborted, commands ignored until end of transaction block
|
|
||||||
step c2: COMMIT;
|
|
||||||
step mv: 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 create insert c1 check2 c2 mv
|
|
||||||
step s1: SELECT;
|
|
||||||
step s2: SELECT;
|
|
||||||
tx1: NOTICE: could not create an index on immv "mv" automatically
|
|
||||||
DETAIL: This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
|
|
||||||
HINT: Create an index on the immv for efficient incremental maintenance.
|
|
||||||
tx1: WARNING: inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
|
|
||||||
DETAIL: The view may not include effects of a concurrent transaction.
|
|
||||||
HINT: create_immv should be used in isolation level READ COMMITTED, or execute refresh_immv to make sure the view is consistent.
|
|
||||||
step create:
|
|
||||||
SELECT pgivm.create_immv('mv(x,y)', 'SELECT * FROM a a1, a a2 WHERE a1.i = a2.i');
|
|
||||||
CREATE FUNCTION check_mv() RETURNS text AS
|
|
||||||
$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
|
|
||||||
FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
|
|
||||||
(SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
|
|
||||||
|
|
||||||
create_immv
|
|
||||||
-----------
|
|
||||||
1
|
|
||||||
(1 row)
|
|
||||||
|
|
||||||
step insert: INSERT INTO a VALUES (2); <waiting ...>
|
|
||||||
step c1: COMMIT;
|
|
||||||
step insert: <... completed>
|
|
||||||
ERROR: could not serialize access due to read/write dependencies among transactions
|
|
||||||
step check2: SELECT check_mv();
|
|
||||||
ERROR: current transaction is aborted, commands ignored until end of transaction block
|
|
||||||
step c2: COMMIT;
|
|
||||||
step mv: 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 create c2 check1 c1 mv
|
|
||||||
step s1: SELECT;
|
|
||||||
step s2: SELECT;
|
|
||||||
step insert: INSERT INTO a VALUES (2);
|
|
||||||
step create:
|
|
||||||
SELECT pgivm.create_immv('mv(x,y)', 'SELECT * FROM a a1, a a2 WHERE a1.i = a2.i');
|
|
||||||
CREATE FUNCTION check_mv() RETURNS text AS
|
|
||||||
$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
|
|
||||||
FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
|
|
||||||
(SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
|
|
||||||
<waiting ...>
|
|
||||||
step c2: COMMIT;
|
|
||||||
tx1: NOTICE: could not create an index on immv "mv" automatically
|
|
||||||
DETAIL: This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
|
|
||||||
HINT: Create an index on the immv for efficient incremental maintenance.
|
|
||||||
tx1: WARNING: inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
|
|
||||||
DETAIL: The view may not include effects of a concurrent transaction.
|
|
||||||
HINT: create_immv should be used in isolation level READ COMMITTED, or execute refresh_immv to make sure the view is consistent.
|
|
||||||
step create: <... completed>
|
|
||||||
create_immv
|
|
||||||
-----------
|
|
||||||
1
|
|
||||||
(1 row)
|
|
||||||
|
|
||||||
step check1: SELECT check_mv();
|
|
||||||
check_mv
|
|
||||||
--------
|
|
||||||
ok
|
|
||||||
(1 row)
|
|
||||||
|
|
||||||
step c1: COMMIT;
|
|
||||||
step 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 immv "mv" automatically
|
|
||||||
DETAIL: This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
|
|
||||||
HINT: Create an index on the immv for efficient incremental maintenance.
|
|
||||||
tx1: WARNING: inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
|
|
||||||
DETAIL: The view may not include effects of a concurrent transaction.
|
|
||||||
HINT: create_immv should be used in isolation level READ COMMITTED, or execute refresh_immv to make sure the view is consistent.
|
|
||||||
step create:
|
|
||||||
SELECT pgivm.create_immv('mv(x,y)', 'SELECT * FROM a a1, a a2 WHERE a1.i = a2.i');
|
|
||||||
CREATE FUNCTION check_mv() RETURNS text AS
|
|
||||||
$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
|
|
||||||
FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
|
|
||||||
(SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
|
|
||||||
|
|
||||||
create_immv
|
|
||||||
-----------
|
|
||||||
1
|
|
||||||
(1 row)
|
|
||||||
|
|
||||||
step c1: COMMIT;
|
|
||||||
step insert: INSERT INTO a VALUES (2);
|
|
||||||
ERROR: could not serialize access due to read/write dependencies among transactions
|
|
||||||
step check2: SELECT check_mv();
|
|
||||||
ERROR: current transaction is aborted, commands ignored until end of transaction block
|
|
||||||
step c2: COMMIT;
|
|
||||||
step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
|
|
||||||
x|y
|
|
||||||
-+-
|
|
||||||
1|1
|
|
||||||
(1 row)
|
|
||||||
|
|
||||||
check_mv
|
|
||||||
--------
|
|
||||||
ok
|
|
||||||
(1 row)
|
|
||||||
|
|
||||||
|
|
||||||
starting permutation: s2 insert s1 create c2 check1 c1 mv
|
|
||||||
step s2: SELECT;
|
|
||||||
step insert: INSERT INTO a VALUES (2);
|
|
||||||
step s1: SELECT;
|
|
||||||
step create:
|
|
||||||
SELECT pgivm.create_immv('mv(x,y)', 'SELECT * FROM a a1, a a2 WHERE a1.i = a2.i');
|
|
||||||
CREATE FUNCTION check_mv() RETURNS text AS
|
|
||||||
$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
|
|
||||||
FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
|
|
||||||
(SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
|
|
||||||
<waiting ...>
|
|
||||||
step c2: COMMIT;
|
|
||||||
tx1: NOTICE: could not create an index on immv "mv" automatically
|
|
||||||
DETAIL: This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
|
|
||||||
HINT: Create an index on the immv for efficient incremental maintenance.
|
|
||||||
tx1: WARNING: inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
|
|
||||||
DETAIL: The view may not include effects of a concurrent transaction.
|
|
||||||
HINT: create_immv should be used in isolation level READ COMMITTED, or execute refresh_immv to make sure the view is consistent.
|
|
||||||
step create: <... completed>
|
|
||||||
create_immv
|
|
||||||
-----------
|
|
||||||
1
|
|
||||||
(1 row)
|
|
||||||
|
|
||||||
step check1: SELECT check_mv();
|
|
||||||
check_mv
|
|
||||||
--------
|
|
||||||
ok
|
|
||||||
(1 row)
|
|
||||||
|
|
||||||
step c1: COMMIT;
|
|
||||||
step mv: 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 immv "mv" automatically
|
|
||||||
DETAIL: This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
|
|
||||||
HINT: Create an index on the immv for efficient incremental maintenance.
|
|
||||||
tx1: WARNING: inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
|
|
||||||
DETAIL: The view may not include effects of a concurrent transaction.
|
|
||||||
HINT: create_immv should be used in isolation level READ COMMITTED, or execute refresh_immv to make sure the view is consistent.
|
|
||||||
step create:
|
|
||||||
SELECT pgivm.create_immv('mv(x,y)', 'SELECT * FROM a a1, a a2 WHERE a1.i = a2.i');
|
|
||||||
CREATE FUNCTION check_mv() RETURNS text AS
|
|
||||||
$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
|
|
||||||
FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
|
|
||||||
(SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
|
|
||||||
|
|
||||||
create_immv
|
|
||||||
-----------
|
|
||||||
1
|
|
||||||
(1 row)
|
|
||||||
|
|
||||||
step check1: SELECT check_mv();
|
|
||||||
check_mv
|
|
||||||
--------
|
|
||||||
ok
|
|
||||||
(1 row)
|
|
||||||
|
|
||||||
step c1: COMMIT;
|
|
||||||
step mv: 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 immv "mv" automatically
|
|
||||||
DETAIL: This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
|
|
||||||
HINT: Create an index on the immv for efficient incremental maintenance.
|
|
||||||
tx1: WARNING: inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
|
|
||||||
DETAIL: The view may not include effects of a concurrent transaction.
|
|
||||||
HINT: create_immv should be used in isolation level READ COMMITTED, or execute refresh_immv to make sure the view is consistent.
|
|
||||||
step create:
|
|
||||||
SELECT pgivm.create_immv('mv(x,y)', 'SELECT * FROM a a1, a a2 WHERE a1.i = a2.i');
|
|
||||||
CREATE FUNCTION check_mv() RETURNS text AS
|
|
||||||
$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
|
|
||||||
FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
|
|
||||||
(SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
|
|
||||||
|
|
||||||
create_immv
|
|
||||||
-----------
|
|
||||||
1
|
|
||||||
(1 row)
|
|
||||||
|
|
||||||
step check1: SELECT check_mv();
|
|
||||||
check_mv
|
|
||||||
--------
|
|
||||||
ok
|
|
||||||
(1 row)
|
|
||||||
|
|
||||||
step c1: COMMIT;
|
|
||||||
step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
|
|
||||||
x|y
|
|
||||||
-+-
|
|
||||||
1|1
|
|
||||||
(1 row)
|
|
||||||
|
|
||||||
check_mv
|
|
||||||
--------
|
|
||||||
ng
|
|
||||||
(1 row)
|
|
||||||
|
|
||||||
|
|
@ -1,497 +0,0 @@
|
||||||
Parsed test spec with 2 sessions
|
|
||||||
|
|
||||||
starting permutation: s1 update1 s2 update2 c1 check2 c2 mv
|
|
||||||
step s1: 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)
|
|
||||||
|
|
||||||
|
|
@ -1,373 +0,0 @@
|
||||||
Parsed test spec with 2 sessions
|
|
||||||
|
|
||||||
starting permutation: s1 update1 s2 update2 c1 check2 c2 mv
|
|
||||||
step s1: 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)
|
|
||||||
|
|
||||||
|
|
@ -1,373 +0,0 @@
|
||||||
Parsed test spec with 2 sessions
|
|
||||||
|
|
||||||
starting permutation: s1 update1 s2 update2 c1 check2 c2 mv
|
|
||||||
step s1: 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)
|
|
||||||
|
|
||||||
|
|
@ -1,25 +1,20 @@
|
||||||
CREATE EXTENSION pg_ivm;
|
CREATE EXTENSION pg_ivm;
|
||||||
GRANT ALL ON SCHEMA public TO public;
|
GRANT ALL ON SCHEMA public TO public;
|
||||||
-- create a table to use as a basis for views and materialized views in various combinations
|
-- create a table to use as a basis for views and materialized views in various combinations
|
||||||
CREATE TABLE mv_base_a (x int, i int, y int, j int);
|
CREATE TABLE mv_base_a (i int, j int);
|
||||||
CREATE TABLE mv_base_b (x int, i int, y int, k int);
|
|
||||||
-- test for base tables with dropped columns
|
|
||||||
ALTER TABLE mv_base_a DROP COLUMN x;
|
|
||||||
ALTER TABLE mv_base_a DROP COLUMN y;
|
|
||||||
ALTER TABLE mv_base_b DROP COLUMN x;
|
|
||||||
ALTER TABLE mv_base_b DROP COLUMN y;
|
|
||||||
INSERT INTO mv_base_a VALUES
|
INSERT INTO mv_base_a VALUES
|
||||||
(1,10),
|
(1,10),
|
||||||
(2,20),
|
(2,20),
|
||||||
(3,30),
|
(3,30),
|
||||||
(4,40),
|
(4,40),
|
||||||
(5,50);
|
(5,50);
|
||||||
|
CREATE TABLE mv_base_b (i int, k int);
|
||||||
INSERT INTO mv_base_b VALUES
|
INSERT INTO mv_base_b VALUES
|
||||||
(1,101),
|
(1,101),
|
||||||
(2,102),
|
(2,102),
|
||||||
(3,103),
|
(3,103),
|
||||||
(4,104);
|
(4,104);
|
||||||
SELECT pgivm.create_immv('mv_ivm_1', 'SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i)');
|
SELECT create_immv('mv_ivm_1', 'SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i)');
|
||||||
NOTICE: could not create an index on immv "mv_ivm_1" automatically
|
NOTICE: could not create an index on immv "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.
|
DETAIL: This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
|
||||||
HINT: Create an index on the immv for efficient incremental maintenance.
|
HINT: Create an index on the immv for efficient incremental maintenance.
|
||||||
|
|
@ -81,21 +76,6 @@ SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
|
||||||
4 | 40 | 104
|
4 | 40 | 104
|
||||||
(4 rows)
|
(4 rows)
|
||||||
|
|
||||||
-- test for renaming column name to camel style
|
|
||||||
BEGIN;
|
|
||||||
ALTER TABLE mv_base_a RENAME i TO "I";
|
|
||||||
ALTER TABLE mv_base_a 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
|
-- TRUNCATE a base table in join views
|
||||||
BEGIN;
|
BEGIN;
|
||||||
TRUNCATE mv_base_a;
|
TRUNCATE mv_base_a;
|
||||||
|
|
@ -117,7 +97,7 @@ ROLLBACK;
|
||||||
BEGIN;
|
BEGIN;
|
||||||
CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
|
CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
|
||||||
AS 'SELECT 1' IMMUTABLE;
|
AS 'SELECT 1' IMMUTABLE;
|
||||||
SELECT pgivm.create_immv('mv_ivm_func', 'SELECT * FROM ivm_func()');
|
SELECT create_immv('mv_ivm_func', 'SELECT * FROM ivm_func()');
|
||||||
NOTICE: could not create an index on immv "mv_ivm_func" automatically
|
NOTICE: could not create an index on immv "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.
|
DETAIL: This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
|
||||||
HINT: Create an index on the immv for efficient incremental maintenance.
|
HINT: Create an index on the immv for efficient incremental maintenance.
|
||||||
|
|
@ -126,7 +106,7 @@ HINT: Create an index on the immv for efficient incremental maintenance.
|
||||||
1
|
1
|
||||||
(1 row)
|
(1 row)
|
||||||
|
|
||||||
SELECT pgivm.create_immv('mv_ivm_no_tbl', 'SELECT 1');
|
SELECT create_immv('mv_ivm_no_tbl', 'SELECT 1');
|
||||||
NOTICE: could not create an index on immv "mv_ivm_no_tbl" automatically
|
NOTICE: could not create an index on immv "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.
|
DETAIL: This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
|
||||||
HINT: Create an index on the immv for efficient incremental maintenance.
|
HINT: Create an index on the immv for efficient incremental maintenance.
|
||||||
|
|
@ -138,7 +118,7 @@ HINT: Create an index on the immv for efficient incremental maintenance.
|
||||||
ROLLBACK;
|
ROLLBACK;
|
||||||
-- result of materialized view have DISTINCT clause or the duplicate result.
|
-- result of materialized view have DISTINCT clause or the duplicate result.
|
||||||
BEGIN;
|
BEGIN;
|
||||||
SELECT pgivm.create_immv('mv_ivm_duplicate', 'SELECT j FROM mv_base_a');
|
SELECT create_immv('mv_ivm_duplicate', 'SELECT j FROM mv_base_a');
|
||||||
NOTICE: could not create an index on immv "mv_ivm_duplicate" automatically
|
NOTICE: could not create an index on immv "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.
|
DETAIL: This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
|
||||||
HINT: Create an index on the immv for efficient incremental maintenance.
|
HINT: Create an index on the immv for efficient incremental maintenance.
|
||||||
|
|
@ -147,7 +127,7 @@ HINT: Create an index on the immv for efficient incremental maintenance.
|
||||||
5
|
5
|
||||||
(1 row)
|
(1 row)
|
||||||
|
|
||||||
SELECT pgivm.create_immv('mv_ivm_distinct', 'SELECT DISTINCT j FROM mv_base_a');
|
SELECT create_immv('mv_ivm_distinct', 'SELECT DISTINCT j FROM mv_base_a');
|
||||||
NOTICE: created index "mv_ivm_distinct_index" on immv "mv_ivm_distinct"
|
NOTICE: created index "mv_ivm_distinct_index" on immv "mv_ivm_distinct"
|
||||||
create_immv
|
create_immv
|
||||||
-------------
|
-------------
|
||||||
|
|
@ -200,7 +180,7 @@ SELECT * FROM mv_ivm_distinct ORDER BY 1;
|
||||||
ROLLBACK;
|
ROLLBACK;
|
||||||
-- support SUM(), COUNT() and AVG() aggregate functions
|
-- support SUM(), COUNT() and AVG() aggregate functions
|
||||||
BEGIN;
|
BEGIN;
|
||||||
SELECT pgivm.create_immv('mv_ivm_agg', 'SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i');
|
SELECT create_immv('mv_ivm_agg', 'SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i');
|
||||||
NOTICE: created index "mv_ivm_agg_index" on immv "mv_ivm_agg"
|
NOTICE: created index "mv_ivm_agg_index" on immv "mv_ivm_agg"
|
||||||
create_immv
|
create_immv
|
||||||
-------------
|
-------------
|
||||||
|
|
@ -253,7 +233,7 @@ SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
|
||||||
ROLLBACK;
|
ROLLBACK;
|
||||||
-- support COUNT(*) aggregate function
|
-- support COUNT(*) aggregate function
|
||||||
BEGIN;
|
BEGIN;
|
||||||
SELECT pgivm.create_immv('mv_ivm_agg', 'SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i');
|
SELECT create_immv('mv_ivm_agg', 'SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i');
|
||||||
NOTICE: created index "mv_ivm_agg_index" on immv "mv_ivm_agg"
|
NOTICE: created index "mv_ivm_agg_index" on immv "mv_ivm_agg"
|
||||||
create_immv
|
create_immv
|
||||||
-------------
|
-------------
|
||||||
|
|
@ -284,7 +264,7 @@ SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
|
||||||
ROLLBACK;
|
ROLLBACK;
|
||||||
-- TRUNCATE a base table in aggregate views
|
-- TRUNCATE a base table in aggregate views
|
||||||
BEGIN;
|
BEGIN;
|
||||||
SELECT pgivm.create_immv('mv_ivm_agg', 'SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i');
|
SELECT create_immv('mv_ivm_agg', 'SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i');
|
||||||
NOTICE: created index "mv_ivm_agg_index" on immv "mv_ivm_agg"
|
NOTICE: created index "mv_ivm_agg_index" on immv "mv_ivm_agg"
|
||||||
create_immv
|
create_immv
|
||||||
-------------
|
-------------
|
||||||
|
|
@ -305,7 +285,7 @@ SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
|
||||||
ROLLBACK;
|
ROLLBACK;
|
||||||
-- support aggregate functions without GROUP clause
|
-- support aggregate functions without GROUP clause
|
||||||
BEGIN;
|
BEGIN;
|
||||||
SELECT pgivm.create_immv('mv_ivm_group', 'SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a');
|
SELECT create_immv('mv_ivm_group', 'SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a');
|
||||||
create_immv
|
create_immv
|
||||||
-------------
|
-------------
|
||||||
1
|
1
|
||||||
|
|
@ -334,7 +314,7 @@ SELECT * FROM mv_ivm_group ORDER BY 1;
|
||||||
ROLLBACK;
|
ROLLBACK;
|
||||||
-- TRUNCATE a base table in aggregate views without GROUP clause
|
-- TRUNCATE a base table in aggregate views without GROUP clause
|
||||||
BEGIN;
|
BEGIN;
|
||||||
SELECT pgivm.create_immv('mv_ivm_group', 'SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a');
|
SELECT create_immv('mv_ivm_group', 'SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a');
|
||||||
create_immv
|
create_immv
|
||||||
-------------
|
-------------
|
||||||
1
|
1
|
||||||
|
|
@ -356,7 +336,7 @@ SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
|
||||||
ROLLBACK;
|
ROLLBACK;
|
||||||
-- resolved issue: When use AVG() function and values is indivisible, result of AVG() is incorrect.
|
-- resolved issue: When use AVG() function and values is indivisible, result of AVG() is incorrect.
|
||||||
BEGIN;
|
BEGIN;
|
||||||
SELECT pgivm.create_immv('mv_ivm_avg_bug', 'SELECT i, SUM(j), COUNT(j), AVG(j) FROM mv_base_A GROUP BY i');
|
SELECT create_immv('mv_ivm_avg_bug', 'SELECT i, SUM(j), COUNT(j), AVG(j) FROM mv_base_A GROUP BY i');
|
||||||
NOTICE: created index "mv_ivm_avg_bug_index" on immv "mv_ivm_avg_bug"
|
NOTICE: created index "mv_ivm_avg_bug_index" on immv "mv_ivm_avg_bug"
|
||||||
create_immv
|
create_immv
|
||||||
-------------
|
-------------
|
||||||
|
|
@ -403,7 +383,7 @@ SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
|
||||||
ROLLBACK;
|
ROLLBACK;
|
||||||
-- support MIN(), MAX() aggregate functions
|
-- support MIN(), MAX() aggregate functions
|
||||||
BEGIN;
|
BEGIN;
|
||||||
SELECT pgivm.create_immv('mv_ivm_min_max(i, min_j, max_j)', 'SELECT i, MIN(j), MAX(j) FROM mv_base_a GROUP BY i');
|
SELECT create_immv('mv_ivm_min_max(i, min_j, max_j)', 'SELECT i, MIN(j), MAX(j) FROM mv_base_a GROUP BY i');
|
||||||
NOTICE: created index "mv_ivm_min_max_index" on immv "mv_ivm_min_max"
|
NOTICE: created index "mv_ivm_min_max_index" on immv "mv_ivm_min_max"
|
||||||
create_immv
|
create_immv
|
||||||
-------------
|
-------------
|
||||||
|
|
@ -450,7 +430,7 @@ SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
|
||||||
ROLLBACK;
|
ROLLBACK;
|
||||||
-- support MIN(), MAX() aggregate functions without GROUP clause
|
-- support MIN(), MAX() aggregate functions without GROUP clause
|
||||||
BEGIN;
|
BEGIN;
|
||||||
SELECT pgivm.create_immv('mv_ivm_min_max(min_j, max_j)', 'SELECT MIN(j), MAX(j) FROM mv_base_a');
|
SELECT create_immv('mv_ivm_min_max(min_j, max_j)', 'SELECT MIN(j), MAX(j) FROM mv_base_a');
|
||||||
create_immv
|
create_immv
|
||||||
-------------
|
-------------
|
||||||
1
|
1
|
||||||
|
|
@ -487,7 +467,7 @@ SELECT * FROM mv_ivm_min_max;
|
||||||
ROLLBACK;
|
ROLLBACK;
|
||||||
-- Test MIN/MAX after search_path change
|
-- Test MIN/MAX after search_path change
|
||||||
BEGIN;
|
BEGIN;
|
||||||
SELECT pgivm.create_immv('mv_ivm_min', 'SELECT MIN(j) FROM mv_base_a');
|
SELECT create_immv('mv_ivm_min', 'SELECT MIN(j) FROM mv_base_a');
|
||||||
create_immv
|
create_immv
|
||||||
-------------
|
-------------
|
||||||
1
|
1
|
||||||
|
|
@ -521,7 +501,7 @@ SELECT * FROM mv_ivm_min ORDER BY 1,2,3;
|
||||||
ROLLBACK;
|
ROLLBACK;
|
||||||
-- aggregate views with column names specified
|
-- aggregate views with column names specified
|
||||||
BEGIN;
|
BEGIN;
|
||||||
SELECT pgivm.create_immv('mv_ivm_agg(a)', 'SELECT i, SUM(j) FROM mv_base_a GROUP BY i');
|
SELECT create_immv('mv_ivm_agg(a)', 'SELECT i, SUM(j) FROM mv_base_a GROUP BY i');
|
||||||
NOTICE: created index "mv_ivm_agg_index" on immv "mv_ivm_agg"
|
NOTICE: created index "mv_ivm_agg_index" on immv "mv_ivm_agg"
|
||||||
create_immv
|
create_immv
|
||||||
-------------
|
-------------
|
||||||
|
|
@ -543,7 +523,7 @@ SELECT * FROM mv_ivm_agg ORDER BY 1,2;
|
||||||
|
|
||||||
ROLLBACK;
|
ROLLBACK;
|
||||||
BEGIN;
|
BEGIN;
|
||||||
SELECT pgivm.create_immv('mv_ivm_agg(a,b)', 'SELECT i, SUM(j) FROM mv_base_a GROUP BY i');
|
SELECT create_immv('mv_ivm_agg(a,b)', 'SELECT i, SUM(j) FROM mv_base_a GROUP BY i');
|
||||||
NOTICE: created index "mv_ivm_agg_index" on immv "mv_ivm_agg"
|
NOTICE: created index "mv_ivm_agg_index" on immv "mv_ivm_agg"
|
||||||
create_immv
|
create_immv
|
||||||
-------------
|
-------------
|
||||||
|
|
@ -565,14 +545,14 @@ SELECT * FROM mv_ivm_agg ORDER BY 1,2;
|
||||||
|
|
||||||
ROLLBACK;
|
ROLLBACK;
|
||||||
BEGIN;
|
BEGIN;
|
||||||
SELECT pgivm.create_immv('mv_ivm_agg(a,b,c)', 'SELECT i, SUM(j) FROM mv_base_a GROUP BY i');
|
SELECT create_immv('mv_ivm_agg(a,b,c)', 'SELECT i, SUM(j) FROM mv_base_a GROUP BY i');
|
||||||
ERROR: too many column names were specified
|
ERROR: too many column names were specified
|
||||||
ROLLBACK;
|
ROLLBACK;
|
||||||
-- support self join view and multiple change on the same table
|
-- support self join view and multiple change on the same table
|
||||||
BEGIN;
|
BEGIN;
|
||||||
CREATE TABLE base_t (i int, v int);
|
CREATE TABLE base_t (i int, v int);
|
||||||
INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
|
INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
|
||||||
SELECT pgivm.create_immv('mv_self(v1, v2)',
|
SELECT create_immv('mv_self(v1, v2)',
|
||||||
'SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i');
|
'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 immv "mv_self" automatically
|
NOTICE: could not create an index on immv "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.
|
DETAIL: This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
|
||||||
|
|
@ -646,7 +626,7 @@ CREATE TABLE base_r (i int, v int);
|
||||||
CREATE TABLE base_s (i int, v int);
|
CREATE TABLE base_s (i int, v int);
|
||||||
INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
|
INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
|
||||||
INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
|
INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
|
||||||
SELECT pgivm.create_immv('mv(v1, v2)', 'SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i)');;
|
SELECT create_immv('mv(v1, v2)', 'SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i)');;
|
||||||
NOTICE: could not create an index on immv "mv" automatically
|
NOTICE: could not create an index on immv "mv" automatically
|
||||||
DETAIL: This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
|
DETAIL: This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
|
||||||
HINT: Create an index on the immv for efficient incremental maintenance.
|
HINT: Create an index on the immv for efficient incremental maintenance.
|
||||||
|
|
@ -691,7 +671,7 @@ CREATE TABLE ri1 (i int PRIMARY KEY);
|
||||||
CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
|
CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
|
||||||
INSERT INTO ri1 VALUES (1),(2),(3);
|
INSERT INTO ri1 VALUES (1),(2),(3);
|
||||||
INSERT INTO ri2 VALUES (1),(2),(3);
|
INSERT INTO ri2 VALUES (1),(2),(3);
|
||||||
SELECT pgivm.create_immv('mv_ri(i1, i2)', 'SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i)');
|
SELECT create_immv('mv_ri(i1, i2)', 'SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i)');
|
||||||
NOTICE: created index "mv_ri_index" on immv "mv_ri"
|
NOTICE: created index "mv_ri_index" on immv "mv_ri"
|
||||||
create_immv
|
create_immv
|
||||||
-------------
|
-------------
|
||||||
|
|
@ -718,7 +698,7 @@ SELECT * FROM mv_ri ORDER BY i2;
|
||||||
ROLLBACK;
|
ROLLBACK;
|
||||||
-- support subquery for using EXISTS()
|
-- support subquery for using EXISTS()
|
||||||
BEGIN;
|
BEGIN;
|
||||||
SELECT pgivm.create_immv('mv_ivm_exists_subquery', 'SELECT a.i, a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i)');
|
SELECT create_immv('mv_ivm_exists_subquery', 'SELECT a.i, a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i)');
|
||||||
NOTICE: could not create an index on immv "mv_ivm_exists_subquery" automatically
|
NOTICE: could not create an index on immv "mv_ivm_exists_subquery" automatically
|
||||||
DETAIL: This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
|
DETAIL: This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
|
||||||
HINT: Create an index on the immv for efficient incremental maintenance.
|
HINT: Create an index on the immv for efficient incremental maintenance.
|
||||||
|
|
@ -727,7 +707,7 @@ HINT: Create an index on the immv for efficient incremental maintenance.
|
||||||
4
|
4
|
||||||
(1 row)
|
(1 row)
|
||||||
|
|
||||||
SELECT pgivm.create_immv('mv_ivm_exists_subquery2', 'SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) AND a.i > 2');
|
SELECT create_immv('mv_ivm_exists_subquery2', 'SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) AND a.i > 2');
|
||||||
NOTICE: could not create an index on immv "mv_ivm_exists_subquery2" automatically
|
NOTICE: could not create an index on immv "mv_ivm_exists_subquery2" automatically
|
||||||
DETAIL: This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
|
DETAIL: This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
|
||||||
HINT: Create an index on the immv for efficient incremental maintenance.
|
HINT: Create an index on the immv for efficient incremental maintenance.
|
||||||
|
|
@ -849,7 +829,7 @@ SELECT * FROM mv_ivm_exists_subquery2 ORDER BY i, j;
|
||||||
(4 rows)
|
(4 rows)
|
||||||
|
|
||||||
--- EXISTS subquery with tuple duplication and DISTINCT
|
--- EXISTS subquery with tuple duplication and DISTINCT
|
||||||
SELECT pgivm.create_immv('mv_ivm_exists_subquery_distinct', 'SELECT DISTINCT a.i, a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i)');
|
SELECT create_immv('mv_ivm_exists_subquery_distinct', 'SELECT DISTINCT a.i, a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i)');
|
||||||
NOTICE: created index "mv_ivm_exists_subquery_distinct_index" on immv "mv_ivm_exists_subquery_distinct"
|
NOTICE: created index "mv_ivm_exists_subquery_distinct_index" on immv "mv_ivm_exists_subquery_distinct"
|
||||||
create_immv
|
create_immv
|
||||||
-------------
|
-------------
|
||||||
|
|
@ -881,7 +861,7 @@ SELECT * FROM mv_ivm_exists_subquery_distinct ORDER BY i, j;
|
||||||
ROLLBACK;
|
ROLLBACK;
|
||||||
-- support simple subquery in FROM clause
|
-- support simple subquery in FROM clause
|
||||||
BEGIN;
|
BEGIN;
|
||||||
SELECT pgivm.create_immv('mv_ivm_subquery', 'SELECT a.i,a.j FROM mv_base_a a,( SELECT * FROM mv_base_b) b WHERE a.i = b.i');
|
SELECT create_immv('mv_ivm_subquery', 'SELECT a.i,a.j FROM mv_base_a a,( SELECT * FROM mv_base_b) b WHERE a.i = b.i');
|
||||||
NOTICE: could not create an index on immv "mv_ivm_subquery" automatically
|
NOTICE: could not create an index on immv "mv_ivm_subquery" automatically
|
||||||
DETAIL: This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
|
DETAIL: This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
|
||||||
HINT: Create an index on the immv for efficient incremental maintenance.
|
HINT: Create an index on the immv for efficient incremental maintenance.
|
||||||
|
|
@ -905,48 +885,48 @@ SELECT * FROM mv_ivm_subquery ORDER BY i,j;
|
||||||
|
|
||||||
ROLLBACK;
|
ROLLBACK;
|
||||||
-- disallow non-simple subqueries
|
-- disallow non-simple subqueries
|
||||||
SELECT pgivm.create_immv('mv_ivm_subquery', 'SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i');
|
SELECT create_immv('mv_ivm_subquery', 'SELECT a.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: aggregate functions in nested query are not supported on incrementally maintainable materialized view
|
ERROR: aggregate functions in nested query are not supported on incrementally maintainable materialized view
|
||||||
SELECT pgivm.create_immv('mv_ivm_subquery', 'SELECT a.i,a.j FROM mv_base_a a, (SELECT DISTINCT i FROM mv_base_b) b WHERE a.i = b.i');
|
SELECT create_immv('mv_ivm_subquery', 'SELECT a.i,a.j FROM mv_base_a a, (SELECT DISTINCT i FROM mv_base_b) b WHERE a.i = b.i');
|
||||||
ERROR: DISTINCT clause in nested query are not supported on incrementally maintainable materialized view
|
ERROR: DISTINCT clause in nested query are not supported on incrementally maintainable materialized view
|
||||||
SELECT pgivm.create_immv('mv_ivm_subquery', 'SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 )');
|
SELECT create_immv('mv_ivm_subquery', 'SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 )');
|
||||||
ERROR: this query is not allowed on incrementally maintainable materialized view
|
ERROR: this query is not allowed on incrementally maintainable materialized view
|
||||||
HINT: sublink only supports subquery with EXISTS clause in WHERE clause
|
HINT: sublink only supports subquery with EXISTS clause in WHERE clause
|
||||||
SELECT pgivm.create_immv('mv_ivm_subquery', 'SELECT i,j, (SELECT k FROM mv_base_b LIMIT 1) FROM mv_base_a a');
|
SELECT create_immv('mv_ivm_subquery', 'SELECT i,j, (SELECT k FROM mv_base_b LIMIT 1) FROM mv_base_a a');
|
||||||
ERROR: this query is not allowed on incrementally maintainable materialized view
|
ERROR: this query is not allowed on incrementally maintainable materialized view
|
||||||
HINT: sublink only supports subquery with EXISTS clause in WHERE clause
|
HINT: sublink only supports subquery with EXISTS clause in WHERE clause
|
||||||
SELECT pgivm.create_immv('mv_ivm_subquery', 'SELECT i,j, (SELECT k FROM mv_base_b LIMIT 1) + 1 FROM mv_base_a a');
|
SELECT create_immv('mv_ivm_subquery', 'SELECT i,j, (SELECT k FROM mv_base_b LIMIT 1) + 1 FROM mv_base_a a');
|
||||||
ERROR: this query is not allowed on incrementally maintainable materialized view
|
ERROR: this query is not allowed on incrementally maintainable materialized view
|
||||||
HINT: sublink only supports subquery with EXISTS clause in WHERE clause
|
HINT: sublink only supports subquery with EXISTS clause in WHERE clause
|
||||||
SELECT pgivm.create_immv('mv_ivm_subquery', 'SELECT * FROM generate_series(1, (SELECT k FROM mv_base_b LIMIT 1)) AS v');
|
SELECT create_immv('mv_ivm_subquery', 'SELECT * FROM generate_series(1, (SELECT k FROM mv_base_b LIMIT 1)) AS v');
|
||||||
ERROR: this query is not allowed on incrementally maintainable materialized view
|
ERROR: this query is not allowed on incrementally maintainable materialized view
|
||||||
HINT: sublink only supports subquery with EXISTS clause in WHERE clause
|
HINT: sublink only supports subquery with EXISTS clause in WHERE clause
|
||||||
SELECT pgivm.create_immv('mv_ivm_subquery', 'SELECT a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i)');
|
SELECT create_immv('mv_ivm_subquery', 'SELECT a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i)');
|
||||||
ERROR: this query is not allowed on incrementally maintainable materialized view
|
ERROR: this query is not allowed on incrementally maintainable materialized view
|
||||||
HINT: targetlist must contain vars that are referred to in EXISTS subquery
|
HINT: targetlist must contain vars that are referred to in EXISTS subquery
|
||||||
SELECT pgivm.create_immv('mv_ivm_subquery', 'SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 2');
|
SELECT create_immv('mv_ivm_subquery', 'SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 2');
|
||||||
ERROR: this query is not allowed on incrementally maintainable materialized view
|
ERROR: this query is not allowed on incrementally maintainable materialized view
|
||||||
HINT: OR or NOT conditions and EXISTS condition can not be used together
|
HINT: OR or NOT conditions and EXISTS condition can not be used together
|
||||||
SELECT pgivm.create_immv('mv_ivm_subquery', 'SELECT a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_a a2 WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a2.i = b.i))');
|
SELECT create_immv('mv_ivm_subquery', 'SELECT a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_a a2 WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a2.i = b.i))');
|
||||||
ERROR: nested sublink is not supported on incrementally maintainable materialized view
|
ERROR: nested sublink is not supported on incrementally maintainable materialized view
|
||||||
SELECT pgivm.create_immv('mv_ivm_subquery', 'SELECT EXISTS(SELECT 1 from mv_base_b) FROM mv_base_a a');
|
SELECT create_immv('mv_ivm_subquery', 'SELECT EXISTS(SELECT 1 from mv_base_b) FROM mv_base_a a');
|
||||||
ERROR: this query is not allowed on incrementally maintainable materialized view
|
ERROR: this query is not allowed on incrementally maintainable materialized view
|
||||||
HINT: sublink only supports subquery with EXISTS clause in WHERE clause
|
HINT: sublink only supports subquery with EXISTS clause in WHERE clause
|
||||||
SELECT pgivm.create_immv('mv_ivm_subquery', 'SELECT false OR EXISTS(SELECT 1 FROM mv_base_a) FROM mv_base_b');
|
SELECT create_immv('mv_ivm_subquery', 'SELECT false OR EXISTS(SELECT 1 FROM mv_base_a) FROM mv_base_b');
|
||||||
ERROR: this query is not allowed on incrementally maintainable materialized view
|
ERROR: this query is not allowed on incrementally maintainable materialized view
|
||||||
HINT: OR or NOT conditions and EXISTS condition can not be used together
|
HINT: OR or NOT conditions and EXISTS condition can not be used together
|
||||||
SELECT pgivm.create_immv('mv_ivm_subquery', 'SELECT * FROM generate_series(1, CASE EXISTS(SELECT 1 FROM mv_base_a) WHEN true THEN 100 ELSE 10 END), mv_base_b');
|
SELECT create_immv('mv_ivm_subquery', 'SELECT * FROM generate_series(1, CASE EXISTS(SELECT 1 FROM mv_base_a) WHEN true THEN 100 ELSE 10 END), mv_base_b');
|
||||||
ERROR: this query is not allowed on incrementally maintainable materialized view
|
ERROR: this query is not allowed on incrementally maintainable materialized view
|
||||||
HINT: sublink only supports subquery with EXISTS clause in WHERE clause
|
HINT: sublink only supports subquery with EXISTS clause in WHERE clause
|
||||||
SELECT pgivm.create_immv('mv_ivm_subquery', 'SELECT * FROM mv_base_a a WHERE CASE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) WHEN true THEN false ELSE true END');
|
SELECT create_immv('mv_ivm_subquery', 'SELECT * FROM mv_base_a a WHERE CASE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) WHEN true THEN false ELSE true END');
|
||||||
ERROR: this query is not allowed on incrementally maintainable materialized view
|
ERROR: this query is not allowed on incrementally maintainable materialized view
|
||||||
HINT: sublink only supports subquery with EXISTS clause in WHERE clause
|
HINT: sublink only supports subquery with EXISTS clause in WHERE clause
|
||||||
SELECT pgivm.create_immv('mv_ivm_subquery', 'SELECT * FROM mv_base_a a WHERE true and CASE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) WHEN true THEN false ELSE true END');
|
SELECT create_immv('mv_ivm_subquery', 'SELECT * FROM mv_base_a a WHERE true and CASE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) WHEN true THEN false ELSE true END');
|
||||||
ERROR: this query is not allowed on incrementally maintainable materialized view
|
ERROR: this query is not allowed on incrementally maintainable materialized view
|
||||||
HINT: sublink only supports subquery with EXISTS clause in WHERE clause
|
HINT: sublink only supports subquery with EXISTS clause in WHERE clause
|
||||||
-- support join subquery in FROM clause
|
-- support join subquery in FROM clause
|
||||||
BEGIN;
|
BEGIN;
|
||||||
SELECT pgivm.create_immv('mv_ivm_join_subquery', 'SELECT i, j, k FROM ( SELECT i, a.j, b.k FROM mv_base_b b INNER JOIN mv_base_a a USING(i)) tmp');
|
SELECT create_immv('mv_ivm_join_subquery', 'SELECT i, j, k FROM ( SELECT i, a.j, b.k FROM mv_base_b b INNER JOIN mv_base_a a USING(i)) tmp');
|
||||||
NOTICE: could not create an index on immv "mv_ivm_join_subquery" automatically
|
NOTICE: could not create an index on immv "mv_ivm_join_subquery" automatically
|
||||||
DETAIL: This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
|
DETAIL: This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
|
||||||
HINT: Create an index on the immv for efficient incremental maintenance.
|
HINT: Create an index on the immv for efficient incremental maintenance.
|
||||||
|
|
@ -979,7 +959,7 @@ SELECT * FROM mv_ivm_join_subquery ORDER BY i,j,k;
|
||||||
ROLLBACK;
|
ROLLBACK;
|
||||||
BEGIN;
|
BEGIN;
|
||||||
-- nested subquery
|
-- nested subquery
|
||||||
SELECT pgivm.create_immv('mv_ivm_join_subquery', 'SELECT i, j, k FROM ( SELECT i, a.j, b.k FROM mv_base_b b INNER JOIN (SELECT * FROM mv_base_a) a USING(i)) tmp');
|
SELECT create_immv('mv_ivm_join_subquery', 'SELECT i, j, k FROM ( SELECT i, a.j, b.k FROM mv_base_b b INNER JOIN (SELECT * FROM mv_base_a) a USING(i)) tmp');
|
||||||
NOTICE: could not create an index on immv "mv_ivm_join_subquery" automatically
|
NOTICE: could not create an index on immv "mv_ivm_join_subquery" automatically
|
||||||
DETAIL: This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
|
DETAIL: This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
|
||||||
HINT: Create an index on the immv for efficient incremental maintenance.
|
HINT: Create an index on the immv for efficient incremental maintenance.
|
||||||
|
|
@ -1012,7 +992,7 @@ SELECT * FROM mv_ivm_join_subquery ORDER BY i,j,k;
|
||||||
ROLLBACK;
|
ROLLBACK;
|
||||||
-- support simple CTE
|
-- support simple CTE
|
||||||
BEGIN;
|
BEGIN;
|
||||||
SELECT pgivm.create_immv('mv_cte',
|
SELECT create_immv('mv_cte',
|
||||||
'WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i');
|
'WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i');
|
||||||
NOTICE: could not create an index on immv "mv_cte" automatically
|
NOTICE: could not create an index on immv "mv_cte" automatically
|
||||||
DETAIL: This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
|
DETAIL: This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
|
||||||
|
|
@ -1037,7 +1017,7 @@ SELECT * FROM mv_cte ORDER BY i,j;
|
||||||
|
|
||||||
ROLLBACK;
|
ROLLBACK;
|
||||||
BEGIN;
|
BEGIN;
|
||||||
SELECT pgivm.create_immv('mv_cte',
|
SELECT create_immv('mv_cte',
|
||||||
'WITH a AS (SELECT * FROM mv_base_a), b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM a, b WHERE a.i = b.i');
|
'WITH a AS (SELECT * FROM mv_base_a), b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM a, b WHERE a.i = b.i');
|
||||||
NOTICE: could not create an index on immv "mv_cte" automatically
|
NOTICE: could not create an index on immv "mv_cte" automatically
|
||||||
DETAIL: This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
|
DETAIL: This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
|
||||||
|
|
@ -1062,7 +1042,7 @@ SELECT * FROM mv_cte ORDER BY i,j;
|
||||||
|
|
||||||
ROLLBACK;
|
ROLLBACK;
|
||||||
BEGIN;
|
BEGIN;
|
||||||
SELECT pgivm.create_immv('mv_cte',
|
SELECT create_immv('mv_cte',
|
||||||
'WITH b AS ( SELECT * FROM mv_base_b) SELECT v.i,v.j FROM (WITH a AS (SELECT * FROM mv_base_a) SELECT a.i,a.j FROM a, b WHERE a.i = b.i) v');
|
'WITH b AS ( SELECT * FROM mv_base_b) SELECT v.i,v.j FROM (WITH a AS (SELECT * FROM mv_base_a) SELECT a.i,a.j FROM a, b WHERE a.i = b.i) v');
|
||||||
NOTICE: could not create an index on immv "mv_cte" automatically
|
NOTICE: could not create an index on immv "mv_cte" automatically
|
||||||
DETAIL: This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
|
DETAIL: This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
|
||||||
|
|
@ -1087,7 +1067,7 @@ SELECT * FROM mv_cte ORDER BY i,j;
|
||||||
|
|
||||||
ROLLBACK;
|
ROLLBACK;
|
||||||
BEGIN;
|
BEGIN;
|
||||||
SELECT pgivm.create_immv('mv_cte',
|
SELECT create_immv('mv_cte',
|
||||||
'SELECT * FROM (WITH a AS (SELECT * FROM mv_base_a), b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM a, b WHERE a.i = b.i) v');
|
'SELECT * FROM (WITH a AS (SELECT * FROM mv_base_a), b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM a, b WHERE a.i = b.i) v');
|
||||||
NOTICE: could not create an index on immv "mv_cte" automatically
|
NOTICE: could not create an index on immv "mv_cte" automatically
|
||||||
DETAIL: This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
|
DETAIL: This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
|
||||||
|
|
@ -1112,7 +1092,7 @@ SELECT * FROM mv_cte ORDER BY i,j;
|
||||||
|
|
||||||
ROLLBACK;
|
ROLLBACK;
|
||||||
BEGIN;
|
BEGIN;
|
||||||
SELECT pgivm.create_immv('mv_cte',
|
SELECT create_immv('mv_cte',
|
||||||
'WITH b AS ( SELECT * FROM (SELECT * FROM mv_base_b) b2) SELECT v.i,v.j FROM (WITH a AS (SELECT * FROM mv_base_a) SELECT a.i,a.j FROM a, b WHERE a.i = b.i) v');
|
'WITH b AS ( SELECT * FROM (SELECT * FROM mv_base_b) b2) SELECT v.i,v.j FROM (WITH a AS (SELECT * FROM mv_base_a) SELECT a.i,a.j FROM a, b WHERE a.i = b.i) v');
|
||||||
NOTICE: could not create an index on immv "mv_cte" automatically
|
NOTICE: could not create an index on immv "mv_cte" automatically
|
||||||
DETAIL: This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
|
DETAIL: This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
|
||||||
|
|
@ -1137,7 +1117,7 @@ SELECT * FROM mv_cte ORDER BY i,j;
|
||||||
|
|
||||||
ROLLBACK;
|
ROLLBACK;
|
||||||
BEGIN;
|
BEGIN;
|
||||||
SELECT pgivm.create_immv('mv_cte',
|
SELECT create_immv('mv_cte',
|
||||||
'WITH x AS ( SELECT i, a.j, b.k FROM mv_base_b b INNER JOIN mv_base_a a USING(i)) SELECT * FROM x');
|
'WITH x AS ( SELECT i, a.j, b.k FROM mv_base_b b INNER JOIN mv_base_a a USING(i)) SELECT * FROM x');
|
||||||
NOTICE: could not create an index on immv "mv_cte" automatically
|
NOTICE: could not create an index on immv "mv_cte" automatically
|
||||||
DETAIL: This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
|
DETAIL: This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
|
||||||
|
|
@ -1171,7 +1151,7 @@ SELECT * FROM mv_cte ORDER BY i,j,k;
|
||||||
ROLLBACK;
|
ROLLBACK;
|
||||||
-- nested CTE
|
-- nested CTE
|
||||||
BEGIN;
|
BEGIN;
|
||||||
SELECT pgivm.create_immv('mv_ivm_nested_cte', 'WITH v AS ( WITH a AS (SELECT * FROM mv_base_a) SELECT i, a.j, b.k FROM mv_base_b b INNER JOIN a USING(i)) SELECT * FROM v');
|
SELECT create_immv('mv_ivm_nested_cte', 'WITH v AS ( WITH a AS (SELECT * FROM mv_base_a) SELECT i, a.j, b.k FROM mv_base_b b INNER JOIN a USING(i)) SELECT * FROM v');
|
||||||
NOTICE: could not create an index on immv "mv_ivm_nested_cte" automatically
|
NOTICE: could not create an index on immv "mv_ivm_nested_cte" automatically
|
||||||
DETAIL: This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
|
DETAIL: This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
|
||||||
HINT: Create an index on the immv for efficient incremental maintenance.
|
HINT: Create an index on the immv for efficient incremental maintenance.
|
||||||
|
|
@ -1206,7 +1186,7 @@ ROLLBACK;
|
||||||
BEGIN;
|
BEGIN;
|
||||||
CREATE TABLE base_t (i int, v int);
|
CREATE TABLE base_t (i int, v int);
|
||||||
INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
|
INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
|
||||||
SELECT pgivm.create_immv('mv_cte_multi(v1, v2)',
|
SELECT create_immv('mv_cte_multi(v1, v2)',
|
||||||
'WITH t AS (SELECT * FROM base_t) SELECT t1.v, t2.v FROM t AS t1 JOIN t AS t2 ON t1.i = t2.i');
|
'WITH t AS (SELECT * FROM base_t) SELECT t1.v, t2.v FROM t AS t1 JOIN t AS t2 ON t1.i = t2.i');
|
||||||
NOTICE: could not create an index on immv "mv_cte_multi" automatically
|
NOTICE: could not create an index on immv "mv_cte_multi" automatically
|
||||||
DETAIL: This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
|
DETAIL: This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
|
||||||
|
|
@ -1257,20 +1237,20 @@ SELECT * FROM mv_cte_multi ORDER BY v1;
|
||||||
|
|
||||||
ROLLBACK;
|
ROLLBACK;
|
||||||
--- disallow not-simple CTE
|
--- disallow not-simple CTE
|
||||||
SELECT pgivm.create_immv('mv_cte_fail', 'WITH b AS (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i');
|
SELECT create_immv('mv_cte_fail', 'WITH b AS (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i');
|
||||||
ERROR: aggregate functions in nested query are not supported on incrementally maintainable materialized view
|
ERROR: aggregate functions in nested query are not supported on incrementally maintainable materialized view
|
||||||
SELECT pgivm.create_immv('mv_cte_fail', 'WITH b AS (SELECT DISTINCT i FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i');
|
SELECT create_immv('mv_cte_fail', 'WITH b AS (SELECT DISTINCT i FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i');
|
||||||
ERROR: DISTINCT clause in nested query are not supported on incrementally maintainable materialized view
|
ERROR: DISTINCT clause in nested query are not supported on incrementally maintainable materialized view
|
||||||
SELECT pgivm.create_immv('mv_cte_fail', 'WITH a AS (SELECT i, j FROM mv_base_a) SELECT a.i,a.j FROM a WHERE EXISTS(WITH b AS (SELECT i FROM mv_base_b) SELECT 1 FROM b WHERE a.i = b.i)');
|
SELECT create_immv('mv_cte_fail', 'WITH a AS (SELECT i, j FROM mv_base_a) SELECT a.i,a.j FROM a WHERE EXISTS(WITH b AS (SELECT i FROM mv_base_b) SELECT 1 FROM b WHERE a.i = b.i)');
|
||||||
ERROR: CTE in EXIST clause is not supported on incrementally maintainable materialized view
|
ERROR: CTE in EXIST clause is not supported on incrementally maintainable materialized view
|
||||||
-- unreferenced CTE
|
-- unreferenced CTE
|
||||||
SELECT pgivm.create_immv('mv_cte_fail', 'WITH b AS (SELECT * FROM mv_base_b) SELECT * FROM mv_base_a a');
|
SELECT create_immv('mv_cte_fail', 'WITH b AS (SELECT * FROM mv_base_b) SELECT * FROM mv_base_a a');
|
||||||
ERROR: Ureferenced WITH query is not supported on incrementally maintainable materialized view
|
ERROR: Ureferenced WITH query is not supported on incrementally maintainable materialized view
|
||||||
-- views including NULL
|
-- views including NULL
|
||||||
BEGIN;
|
BEGIN;
|
||||||
CREATE TABLE base_t (i int, v int);
|
CREATE TABLE base_t (i int, v int);
|
||||||
INSERT INTO base_t VALUES (1,10),(2, NULL);
|
INSERT INTO base_t VALUES (1,10),(2, NULL);
|
||||||
SELECT pgivm.create_immv('mv', 'SELECT * FROM base_t');
|
SELECT create_immv('mv', 'SELECT * FROM base_t');
|
||||||
NOTICE: could not create an index on immv "mv" automatically
|
NOTICE: could not create an index on immv "mv" automatically
|
||||||
DETAIL: This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
|
DETAIL: This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
|
||||||
HINT: Create an index on the immv for efficient incremental maintenance.
|
HINT: Create an index on the immv for efficient incremental maintenance.
|
||||||
|
|
@ -1297,7 +1277,7 @@ SELECT * FROM mv ORDER BY i;
|
||||||
ROLLBACK;
|
ROLLBACK;
|
||||||
BEGIN;
|
BEGIN;
|
||||||
CREATE TABLE base_t (i int);
|
CREATE TABLE base_t (i int);
|
||||||
SELECT pgivm.create_immv('mv', 'SELECT * FROM base_t');
|
SELECT create_immv('mv', 'SELECT * FROM base_t');
|
||||||
NOTICE: could not create an index on immv "mv" automatically
|
NOTICE: could not create an index on immv "mv" automatically
|
||||||
DETAIL: This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
|
DETAIL: This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
|
||||||
HINT: Create an index on the immv for efficient incremental maintenance.
|
HINT: Create an index on the immv for efficient incremental maintenance.
|
||||||
|
|
@ -1323,7 +1303,7 @@ ROLLBACK;
|
||||||
BEGIN;
|
BEGIN;
|
||||||
CREATE TABLE base_t (i int, v int);
|
CREATE TABLE base_t (i int, v int);
|
||||||
INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (1, 10), (1, 20);
|
INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (1, 10), (1, 20);
|
||||||
SELECT pgivm.create_immv('mv', 'SELECT i, sum(v) FROM base_t GROUP BY i');
|
SELECT create_immv('mv', 'SELECT i, sum(v) FROM base_t GROUP BY i');
|
||||||
NOTICE: created index "mv_index" on immv "mv"
|
NOTICE: created index "mv_index" on immv "mv"
|
||||||
create_immv
|
create_immv
|
||||||
-------------
|
-------------
|
||||||
|
|
@ -1349,7 +1329,7 @@ ROLLBACK;
|
||||||
BEGIN;
|
BEGIN;
|
||||||
CREATE TABLE base_t (i int, v int);
|
CREATE TABLE base_t (i int, v int);
|
||||||
INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (NULL, 3), (NULL, 4), (NULL, 5);
|
INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (NULL, 3), (NULL, 4), (NULL, 5);
|
||||||
SELECT pgivm.create_immv('mv', 'SELECT i, min(v), max(v) FROM base_t GROUP BY i');
|
SELECT create_immv('mv', 'SELECT i, min(v), max(v) FROM base_t GROUP BY i');
|
||||||
NOTICE: created index "mv_index" on immv "mv"
|
NOTICE: created index "mv_index" on immv "mv"
|
||||||
create_immv
|
create_immv
|
||||||
-------------
|
-------------
|
||||||
|
|
@ -1395,8 +1375,6 @@ CREATE FUNCTION mytype_out(mytype)
|
||||||
RETURNS cstring AS 'int4out'
|
RETURNS cstring AS 'int4out'
|
||||||
LANGUAGE INTERNAL STRICT IMMUTABLE;
|
LANGUAGE INTERNAL STRICT IMMUTABLE;
|
||||||
NOTICE: argument type mytype is only a shell
|
NOTICE: argument type mytype is only a shell
|
||||||
LINE 1: CREATE FUNCTION mytype_out(mytype)
|
|
||||||
^
|
|
||||||
CREATE TYPE mytype (
|
CREATE TYPE mytype (
|
||||||
LIKE = int4,
|
LIKE = int4,
|
||||||
INPUT = mytype_in,
|
INPUT = mytype_in,
|
||||||
|
|
@ -1423,7 +1401,7 @@ CREATE OPERATOR CLASS mytype_ops
|
||||||
OPERATOR 3 = ,
|
OPERATOR 3 = ,
|
||||||
FUNCTION 1 mytype_cmp(mytype,mytype);
|
FUNCTION 1 mytype_cmp(mytype,mytype);
|
||||||
CREATE TABLE t_mytype (x mytype);
|
CREATE TABLE t_mytype (x mytype);
|
||||||
SELECT pgivm.create_immv('mv_mytype',
|
SELECT create_immv('mv_mytype',
|
||||||
'SELECT * FROM t_mytype');
|
'SELECT * FROM t_mytype');
|
||||||
NOTICE: could not create an index on immv "mv_mytype" automatically
|
NOTICE: could not create an index on immv "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.
|
DETAIL: This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
|
||||||
|
|
@ -1442,108 +1420,108 @@ SELECT * FROM mv_mytype;
|
||||||
|
|
||||||
ROLLBACK;
|
ROLLBACK;
|
||||||
-- outer join is not supported
|
-- outer join is not supported
|
||||||
SELECT pgivm.create_immv('mv(a,b)',
|
SELECT create_immv('mv(a,b)',
|
||||||
'SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i');
|
'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
|
ERROR: OUTER JOIN is not supported on incrementally maintainable materialized view
|
||||||
-- contain system column
|
-- contain system column
|
||||||
SELECT pgivm.create_immv('mv_ivm01', 'SELECT i,j,xmin FROM mv_base_a');
|
SELECT create_immv('mv_ivm01', 'SELECT i,j,xmin FROM mv_base_a');
|
||||||
ERROR: system column is not supported on incrementally maintainable materialized view
|
ERROR: system column is not supported on incrementally maintainable materialized view
|
||||||
SELECT pgivm.create_immv('mv_ivm02', 'SELECT i,j FROM mv_base_a WHERE xmin = ''610''');
|
SELECT create_immv('mv_ivm02', 'SELECT i,j FROM mv_base_a WHERE xmin = ''610''');
|
||||||
ERROR: system column is not supported on incrementally maintainable materialized view
|
ERROR: system column is not supported on incrementally maintainable materialized view
|
||||||
SELECT pgivm.create_immv('mv_ivm03', 'SELECT i,j,xmin::text AS x_min FROM mv_base_a');
|
SELECT create_immv('mv_ivm03', 'SELECT i,j,xmin::text AS x_min FROM mv_base_a');
|
||||||
ERROR: system column is not supported on incrementally maintainable materialized view
|
ERROR: system column is not supported on incrementally maintainable materialized view
|
||||||
SELECT pgivm.create_immv('mv_ivm04', 'SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a');
|
SELECT create_immv('mv_ivm04', 'SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a');
|
||||||
ERROR: system column is not supported on incrementally maintainable materialized view
|
ERROR: system column is not supported on incrementally maintainable materialized view
|
||||||
-- contain ORDER BY
|
-- contain ORDER BY
|
||||||
SELECT pgivm.create_immv('mv_ivm07', 'SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k');
|
SELECT create_immv('mv_ivm07', '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
|
ERROR: ORDER BY clause is not supported on incrementally maintainable materialized view
|
||||||
-- contain HAVING
|
-- contain HAVING
|
||||||
SELECT pgivm.create_immv('mv_ivm08', 'SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5');
|
SELECT create_immv('mv_ivm08', 'SELECT i,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
|
ERROR: HAVING clause is not supported on incrementally maintainable materialized view
|
||||||
-- contain GROUP BY without aggregate
|
-- contain GROUP BY without aggregate
|
||||||
SELECT pgivm.create_immv('mv_ivm08', 'SELECT i,j FROM mv_base_a GROUP BY i,j');
|
SELECT create_immv('mv_ivm08', 'SELECT i,j FROM mv_base_a GROUP BY i,j');
|
||||||
ERROR: GROUP BY clause without aggregate is not supported on incrementally maintainable materialized view
|
ERROR: GROUP BY clause without aggregate is not supported on incrementally maintainable materialized view
|
||||||
-- contain view or materialized view
|
-- contain view or materialized view
|
||||||
CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
|
CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
|
||||||
CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
|
CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
|
||||||
SELECT pgivm.create_immv('mv_ivm07', 'SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i');
|
SELECT create_immv('mv_ivm07', '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
|
ERROR: VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
|
||||||
SELECT pgivm.create_immv('mv_ivm08', 'SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i');
|
SELECT create_immv('mv_ivm08', '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
|
ERROR: VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
|
||||||
-- contain mutable functions
|
-- contain mutable functions
|
||||||
SELECT pgivm.create_immv('mv_ivm12', 'SELECT i,j FROM mv_base_a WHERE i = random()::int');
|
SELECT create_immv('mv_ivm12', 'SELECT i,j FROM mv_base_a WHERE i = random()::int');
|
||||||
ERROR: mutable function is not supported on incrementally maintainable materialized view
|
ERROR: mutable function is not supported on incrementally maintainable materialized view
|
||||||
HINT: functions must be marked IMMUTABLE
|
HINT: functions must be marked IMMUTABLE
|
||||||
-- LIMIT/OFFSET is not supported
|
-- LIMIT/OFFSET is not supported
|
||||||
SELECT pgivm.create_immv('mv_ivm13', 'SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5');
|
SELECT create_immv('mv_ivm13', 'SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5');
|
||||||
ERROR: LIMIT/OFFSET clause is not supported on incrementally maintainable materialized view
|
ERROR: LIMIT/OFFSET clause is not supported on incrementally maintainable materialized view
|
||||||
-- DISTINCT ON is not supported
|
-- DISTINCT ON is not supported
|
||||||
SELECT pgivm.create_immv('mv_ivm14', 'SELECT DISTINCT ON(i) i, j FROM mv_base_a');
|
SELECT create_immv('mv_ivm14', 'SELECT DISTINCT ON(i) i, j FROM mv_base_a');
|
||||||
ERROR: DISTINCT ON is not supported on incrementally maintainable materialized view
|
ERROR: DISTINCT ON is not supported on incrementally maintainable materialized view
|
||||||
-- TABLESAMPLE clause is not supported
|
-- TABLESAMPLE clause is not supported
|
||||||
SELECT pgivm.create_immv('mv_ivm15', 'SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50)');
|
SELECT create_immv('mv_ivm15', 'SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50)');
|
||||||
ERROR: TABLESAMPLE clause is not supported on incrementally maintainable materialized view
|
ERROR: TABLESAMPLE clause is not supported on incrementally maintainable materialized view
|
||||||
-- window functions are not supported
|
-- window functions are not supported
|
||||||
SELECT pgivm.create_immv('mv_ivm16', 'SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a');
|
SELECT create_immv('mv_ivm16', 'SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a');
|
||||||
ERROR: window functions are not supported on incrementally maintainable materialized view
|
ERROR: window functions are not supported on incrementally maintainable materialized view
|
||||||
-- aggregate function with some options is not supported
|
-- aggregate function with some options is not supported
|
||||||
SELECT pgivm.create_immv('mv_ivm17', 'SELECT COUNT(*) FILTER(WHERE i < 3) FROM mv_base_a');
|
SELECT create_immv('mv_ivm17', 'SELECT COUNT(*) FILTER(WHERE i < 3) FROM mv_base_a');
|
||||||
ERROR: aggregate function with FILTER clause is not supported on incrementally maintainable materialized view
|
ERROR: aggregate function with FILTER clause is not supported on incrementally maintainable materialized view
|
||||||
SELECT pgivm.create_immv('mv_ivm18', 'SELECT COUNT(DISTINCT i) FROM mv_base_a');
|
SELECT create_immv('mv_ivm18', 'SELECT COUNT(DISTINCT i) FROM mv_base_a');
|
||||||
ERROR: aggregate function with DISTINCT arguments is not supported on incrementally maintainable materialized view
|
ERROR: aggregate function with DISTINCT arguments is not supported on incrementally maintainable materialized view
|
||||||
SELECT pgivm.create_immv('mv_ivm19', 'SELECT array_agg(j ORDER BY i DESC) FROM mv_base_a');
|
SELECT create_immv('mv_ivm19', '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
|
ERROR: aggregate function with ORDER clause is not supported on incrementally maintainable materialized view
|
||||||
SELECT pgivm.create_immv('mv_ivm20', 'SELECT i,SUM(j) FROM mv_base_a GROUP BY GROUPING SETS((i),())');
|
SELECT create_immv('mv_ivm20', '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
|
ERROR: GROUPING SETS, ROLLUP, or CUBE clauses is not supported on incrementally maintainable materialized view
|
||||||
-- inheritance parent is not supported
|
-- inheritance parent is not supported
|
||||||
BEGIN;
|
BEGIN;
|
||||||
CREATE TABLE parent (i int, v int);
|
CREATE TABLE parent (i int, v int);
|
||||||
CREATE TABLE child_a(options text) INHERITS(parent);
|
CREATE TABLE child_a(options text) INHERITS(parent);
|
||||||
SELECT pgivm.create_immv('mv_ivm21', 'SELECT * FROM parent');
|
SELECT create_immv('mv_ivm21', 'SELECT * FROM parent');
|
||||||
ERROR: inheritance parent is not supported on incrementally maintainable materialized view
|
ERROR: inheritance parent is not supported on incrementally maintainable materialized view
|
||||||
ROLLBACK;
|
ROLLBACK;
|
||||||
-- UNION statement is not supported
|
-- UNION statement is not supported
|
||||||
SELECT pgivm.create_immv('mv_ivm22', 'SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b');
|
SELECT create_immv('mv_ivm22', '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
|
ERROR: UNION/INTERSECT/EXCEPT statements are not supported on incrementally maintainable materialized view
|
||||||
-- DISTINCT clause in nested query are not supported
|
-- DISTINCT clause in nested query are not supported
|
||||||
SELECT pgivm.create_immv('mv_ivm23', 'SELECT * FROM (SELECT DISTINCT i,j FROM mv_base_a) AS tmp');;
|
SELECT create_immv('mv_ivm23', 'SELECT * FROM (SELECT DISTINCT i,j FROM mv_base_a) AS tmp');;
|
||||||
ERROR: DISTINCT clause in nested query are not supported on incrementally maintainable materialized view
|
ERROR: DISTINCT clause in nested query are not supported on incrementally maintainable materialized view
|
||||||
-- empty target list is not allowed with IVM
|
-- empty target list is not allowed with IVM
|
||||||
SELECT pgivm.create_immv('mv_ivm25', 'SELECT FROM mv_base_a');
|
SELECT create_immv('mv_ivm25', 'SELECT FROM mv_base_a');
|
||||||
ERROR: empty target list is not supported on incrementally maintainable materialized view
|
ERROR: empty target list is not supported on incrementally maintainable materialized view
|
||||||
-- FOR UPDATE/SHARE is not supported
|
-- FOR UPDATE/SHARE is not supported
|
||||||
SELECT pgivm.create_immv('mv_ivm26', 'SELECT i,j FROM mv_base_a FOR UPDATE');
|
SELECT create_immv('mv_ivm26', 'SELECT i,j FROM mv_base_a FOR UPDATE');
|
||||||
ERROR: FOR UPDATE/SHARE clause is not supported on incrementally maintainable materialized view
|
ERROR: FOR UPDATE/SHARE clause is not supported on incrementally maintainable materialized view
|
||||||
SELECT pgivm.create_immv('mv_ivm27', 'SELECT * FROM (SELECT i,j FROM mv_base_a FOR UPDATE) AS tmp;');
|
SELECT create_immv('mv_ivm27', 'SELECT * FROM (SELECT i,j FROM mv_base_a FOR UPDATE) AS tmp;');
|
||||||
ERROR: FOR UPDATE/SHARE clause is not supported on incrementally maintainable materialized view
|
ERROR: FOR UPDATE/SHARE clause is not supported on incrementally maintainable materialized view
|
||||||
-- tartget list cannot contain ivm column that start with '__ivm'
|
-- tartget list cannot contain ivm column that start with '__ivm'
|
||||||
SELECT pgivm.create_immv('mv_ivm28', 'SELECT i AS "__ivm_count__" FROM mv_base_a');
|
SELECT create_immv('mv_ivm28', 'SELECT i AS "__ivm_count__" FROM mv_base_a');
|
||||||
ERROR: column name __ivm_count__ is not supported on incrementally maintainable materialized view
|
ERROR: column name __ivm_count__ is not supported on incrementally maintainable materialized view
|
||||||
-- expressions specified in GROUP BY must appear in the target list.
|
-- expressions specified in GROUP BY must appear in the target list.
|
||||||
SELECT pgivm.create_immv('mv_ivm29', 'SELECT COUNT(i) FROM mv_base_a GROUP BY i;');
|
SELECT create_immv('mv_ivm29', '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
|
ERROR: GROUP BY expression not appearing in select list is not supported on incrementally maintainable materialized view
|
||||||
-- experssions containing an aggregate is not supported
|
-- experssions containing an aggregate is not supported
|
||||||
SELECT pgivm.create_immv('mv_ivm30', 'SELECT sum(i)*0.5 FROM mv_base_a');
|
SELECT create_immv('mv_ivm30', 'SELECT sum(i)*0.5 FROM mv_base_a');
|
||||||
ERROR: expression containing an aggregate in it is not supported on incrementally maintainable materialized view
|
ERROR: expression containing an aggregate in it is not supported on incrementally maintainable materialized view
|
||||||
SELECT pgivm.create_immv('mv_ivm31', 'SELECT sum(i)/sum(j) FROM mv_base_a');
|
SELECT create_immv('mv_ivm31', 'SELECT sum(i)/sum(j) FROM mv_base_a');
|
||||||
ERROR: expression containing an aggregate in it is not supported on incrementally maintainable materialized view
|
ERROR: expression containing an aggregate in it is not supported on incrementally maintainable materialized view
|
||||||
-- VALUES is not supported
|
-- VALUES is not supported
|
||||||
SELECT pgivm.create_immv('mv_ivm_only_values1', 'values(1)');
|
SELECT create_immv('mv_ivm_only_values1', 'values(1)');
|
||||||
ERROR: VALUES is not supported on incrementally maintainable materialized view
|
ERROR: VALUES is not supported on incrementally maintainable materialized view
|
||||||
SELECT pgivm.create_immv('mv_ivm_only_values2', 'SELECT * FROM (values(1)) AS tmp');
|
SELECT create_immv('mv_ivm_only_values2', 'SELECT * FROM (values(1)) AS tmp');
|
||||||
ERROR: VALUES is not supported on incrementally maintainable materialized view
|
ERROR: VALUES is not supported on incrementally maintainable materialized view
|
||||||
-- views containing base tables with Row Level Security
|
-- views containing base tables with Row Level Security
|
||||||
DROP USER IF EXISTS regress_ivm_admin;
|
DROP USER IF EXISTS ivm_admin;
|
||||||
NOTICE: role "regress_ivm_admin" does not exist, skipping
|
NOTICE: role "ivm_admin" does not exist, skipping
|
||||||
DROP USER IF EXISTS regress_ivm_user;
|
DROP USER IF EXISTS ivm_user;
|
||||||
NOTICE: role "regress_ivm_user" does not exist, skipping
|
NOTICE: role "ivm_user" does not exist, skipping
|
||||||
CREATE USER regress_ivm_admin;
|
CREATE USER ivm_admin;
|
||||||
CREATE USER regress_ivm_user;
|
CREATE USER ivm_user;
|
||||||
--- create a table with RLS
|
--- create a table with RLS
|
||||||
SET SESSION AUTHORIZATION regress_ivm_admin;
|
SET SESSION AUTHORIZATION ivm_admin;
|
||||||
CREATE TABLE rls_tbl(id int, data text, owner name);
|
CREATE TABLE rls_tbl(id int, data text, owner name);
|
||||||
INSERT INTO rls_tbl VALUES
|
INSERT INTO rls_tbl VALUES
|
||||||
(1,'foo','regress_ivm_user'),
|
(1,'foo','ivm_user'),
|
||||||
(2,'bar','postgres');
|
(2,'bar','postgres');
|
||||||
CREATE TABLE num_tbl(id int, num text);
|
CREATE TABLE num_tbl(id int, num text);
|
||||||
INSERT INTO num_tbl VALUES
|
INSERT INTO num_tbl VALUES
|
||||||
|
|
@ -1558,9 +1536,9 @@ CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = curre
|
||||||
ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
|
ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
|
||||||
GRANT ALL on rls_tbl TO PUBLIC;
|
GRANT ALL on rls_tbl TO PUBLIC;
|
||||||
GRANT ALL on num_tbl TO PUBLIC;
|
GRANT ALL on num_tbl TO PUBLIC;
|
||||||
--- create a view owned by regress_ivm_user
|
--- create a view owned by ivm_user
|
||||||
SET SESSION AUTHORIZATION regress_ivm_user;
|
SET SESSION AUTHORIZATION ivm_user;
|
||||||
SELECT pgivm.create_immv('ivm_rls', 'SELECT * FROM rls_tbl');
|
SELECT create_immv('ivm_rls', 'SELECT * FROM rls_tbl');
|
||||||
NOTICE: could not create an index on immv "ivm_rls" automatically
|
NOTICE: could not create an index on immv "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.
|
DETAIL: This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
|
||||||
HINT: Create an index on the immv for efficient incremental maintenance.
|
HINT: Create an index on the immv for efficient incremental maintenance.
|
||||||
|
|
@ -1571,42 +1549,42 @@ HINT: Create an index on the immv for efficient incremental maintenance.
|
||||||
|
|
||||||
SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
|
SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
|
||||||
id | data | owner
|
id | data | owner
|
||||||
----+------+------------------
|
----+------+----------
|
||||||
1 | foo | regress_ivm_user
|
1 | foo | ivm_user
|
||||||
(1 row)
|
(1 row)
|
||||||
|
|
||||||
RESET SESSION AUTHORIZATION;
|
RESET SESSION AUTHORIZATION;
|
||||||
--- inserts rows owned by different users
|
--- inserts rows owned by different users
|
||||||
INSERT INTO rls_tbl VALUES
|
INSERT INTO rls_tbl VALUES
|
||||||
(3,'baz','regress_ivm_user'),
|
(3,'baz','ivm_user'),
|
||||||
(4,'qux','postgres');
|
(4,'qux','postgres');
|
||||||
SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
|
SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
|
||||||
id | data | owner
|
id | data | owner
|
||||||
----+------+------------------
|
----+------+----------
|
||||||
1 | foo | regress_ivm_user
|
1 | foo | ivm_user
|
||||||
3 | baz | regress_ivm_user
|
3 | baz | ivm_user
|
||||||
(2 rows)
|
(2 rows)
|
||||||
|
|
||||||
--- combination of diffent kinds of commands
|
--- combination of diffent kinds of commands
|
||||||
WITH
|
WITH
|
||||||
i AS (INSERT INTO rls_tbl VALUES(5,'quux','postgres'), (6,'corge','regress_ivm_user')),
|
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),
|
u AS (UPDATE rls_tbl SET owner = 'postgres' WHERE id = 1),
|
||||||
u2 AS (UPDATE rls_tbl SET owner = 'regress_ivm_user' WHERE id = 2)
|
u2 AS (UPDATE rls_tbl SET owner = 'ivm_user' WHERE id = 2)
|
||||||
SELECT;
|
SELECT;
|
||||||
--
|
--
|
||||||
(1 row)
|
(1 row)
|
||||||
|
|
||||||
SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
|
SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
|
||||||
id | data | owner
|
id | data | owner
|
||||||
----+-------+------------------
|
----+-------+----------
|
||||||
2 | bar | regress_ivm_user
|
2 | bar | ivm_user
|
||||||
3 | baz | regress_ivm_user
|
3 | baz | ivm_user
|
||||||
6 | corge | regress_ivm_user
|
6 | corge | ivm_user
|
||||||
(3 rows)
|
(3 rows)
|
||||||
|
|
||||||
---
|
---
|
||||||
SET SESSION AUTHORIZATION regress_ivm_user;
|
SET SESSION AUTHORIZATION ivm_user;
|
||||||
SELECT pgivm.create_immv('ivm_rls2', 'SELECT * FROM rls_tbl JOIN num_tbl USING(id)');
|
SELECT create_immv('ivm_rls2', 'SELECT * FROM rls_tbl JOIN num_tbl USING(id)');
|
||||||
NOTICE: could not create an index on immv "ivm_rls2" automatically
|
NOTICE: could not create an index on immv "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.
|
DETAIL: This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
|
||||||
HINT: Create an index on the immv for efficient incremental maintenance.
|
HINT: Create an index on the immv for efficient incremental maintenance.
|
||||||
|
|
@ -1625,10 +1603,10 @@ SELECT;
|
||||||
|
|
||||||
SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
|
SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
|
||||||
id | data | owner | num
|
id | data | owner | num
|
||||||
----+-------+------------------+---------
|
----+-------+----------+---------
|
||||||
2 | bar | regress_ivm_user | two
|
2 | bar | ivm_user | two
|
||||||
3 | baz_2 | regress_ivm_user | three_2
|
3 | baz_2 | ivm_user | three_2
|
||||||
6 | corge | regress_ivm_user | six
|
6 | corge | ivm_user | six
|
||||||
(3 rows)
|
(3 rows)
|
||||||
|
|
||||||
DROP TABLE rls_tbl CASCADE;
|
DROP TABLE rls_tbl CASCADE;
|
||||||
|
|
@ -1636,14 +1614,14 @@ NOTICE: drop cascades to 2 other objects
|
||||||
DETAIL: drop cascades to table ivm_rls
|
DETAIL: drop cascades to table ivm_rls
|
||||||
drop cascades to table ivm_rls2
|
drop cascades to table ivm_rls2
|
||||||
DROP TABLE num_tbl CASCADE;
|
DROP TABLE num_tbl CASCADE;
|
||||||
DROP USER regress_ivm_user;
|
DROP USER ivm_user;
|
||||||
DROP USER regress_ivm_admin;
|
DROP USER ivm_admin;
|
||||||
-- automatic index creation
|
-- automatic index creation
|
||||||
BEGIN;
|
BEGIN;
|
||||||
CREATE TABLE base_a (i int primary key, j int);
|
CREATE TABLE base_a (i int primary key, j int);
|
||||||
CREATE TABLE base_b (i int primary key, j int);
|
CREATE TABLE base_b (i int primary key, j int);
|
||||||
--- group by: create an index
|
--- group by: create an index
|
||||||
SELECT pgivm.create_immv('mv_idx1', 'SELECT i, sum(j) FROM base_a GROUP BY i');
|
SELECT create_immv('mv_idx1', 'SELECT i, sum(j) FROM base_a GROUP BY i');
|
||||||
NOTICE: created index "mv_idx1_index" on immv "mv_idx1"
|
NOTICE: created index "mv_idx1_index" on immv "mv_idx1"
|
||||||
create_immv
|
create_immv
|
||||||
-------------
|
-------------
|
||||||
|
|
@ -1651,7 +1629,7 @@ NOTICE: created index "mv_idx1_index" on immv "mv_idx1"
|
||||||
(1 row)
|
(1 row)
|
||||||
|
|
||||||
--- distinct: create an index
|
--- distinct: create an index
|
||||||
SELECT pgivm.create_immv('mv_idx2', 'SELECT DISTINCT j FROM base_a');
|
SELECT create_immv('mv_idx2', 'SELECT DISTINCT j FROM base_a');
|
||||||
NOTICE: created index "mv_idx2_index" on immv "mv_idx2"
|
NOTICE: created index "mv_idx2_index" on immv "mv_idx2"
|
||||||
create_immv
|
create_immv
|
||||||
-------------
|
-------------
|
||||||
|
|
@ -1659,7 +1637,7 @@ NOTICE: created index "mv_idx2_index" on immv "mv_idx2"
|
||||||
(1 row)
|
(1 row)
|
||||||
|
|
||||||
--- with all pkey columns: create an index
|
--- with all pkey columns: create an index
|
||||||
SELECT pgivm.create_immv('mv_idx3(i_a, i_b)', 'SELECT a.i, b.i FROM base_a a, base_b b');
|
SELECT create_immv('mv_idx3(i_a, i_b)', 'SELECT a.i, b.i FROM base_a a, base_b b');
|
||||||
NOTICE: created index "mv_idx3_index" on immv "mv_idx3"
|
NOTICE: created index "mv_idx3_index" on immv "mv_idx3"
|
||||||
create_immv
|
create_immv
|
||||||
-------------
|
-------------
|
||||||
|
|
@ -1667,7 +1645,7 @@ NOTICE: created index "mv_idx3_index" on immv "mv_idx3"
|
||||||
(1 row)
|
(1 row)
|
||||||
|
|
||||||
--- missing some pkey columns: no index
|
--- missing some pkey columns: no index
|
||||||
SELECT pgivm.create_immv('mv_idx4', 'SELECT j FROM base_a');
|
SELECT create_immv('mv_idx4', 'SELECT j FROM base_a');
|
||||||
NOTICE: could not create an index on immv "mv_idx4" automatically
|
NOTICE: could not create an index on immv "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.
|
DETAIL: This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
|
||||||
HINT: Create an index on the immv for efficient incremental maintenance.
|
HINT: Create an index on the immv for efficient incremental maintenance.
|
||||||
|
|
@ -1676,7 +1654,7 @@ HINT: Create an index on the immv for efficient incremental maintenance.
|
||||||
0
|
0
|
||||||
(1 row)
|
(1 row)
|
||||||
|
|
||||||
SELECT pgivm.create_immv('mv_idx5', 'SELECT a.i, b.j FROM base_a a, base_b b');
|
SELECT create_immv('mv_idx5', 'SELECT a.i, b.j FROM base_a a, base_b b');
|
||||||
NOTICE: could not create an index on immv "mv_idx5" automatically
|
NOTICE: could not create an index on immv "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.
|
DETAIL: This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
|
||||||
HINT: Create an index on the immv for efficient incremental maintenance.
|
HINT: Create an index on the immv for efficient incremental maintenance.
|
||||||
|
|
@ -1686,7 +1664,7 @@ HINT: Create an index on the immv for efficient incremental maintenance.
|
||||||
(1 row)
|
(1 row)
|
||||||
|
|
||||||
--- subqueries: create an index
|
--- subqueries: create an index
|
||||||
SELECT pgivm.create_immv('mv_idx6(i_a, i_b)', 'SELECT a.i, b.i FROM (SELECT * FROM base_a) a, (SELECT * FROM base_b) b');
|
SELECT create_immv('mv_idx6(i_a, i_b)', 'SELECT a.i, b.i FROM (SELECT * FROM base_a) a, (SELECT * FROM base_b) b');
|
||||||
NOTICE: created index "mv_idx6_index" on immv "mv_idx6"
|
NOTICE: created index "mv_idx6_index" on immv "mv_idx6"
|
||||||
create_immv
|
create_immv
|
||||||
-------------
|
-------------
|
||||||
|
|
@ -1694,7 +1672,7 @@ NOTICE: created index "mv_idx6_index" on immv "mv_idx6"
|
||||||
(1 row)
|
(1 row)
|
||||||
|
|
||||||
--- with set-returning function: no index
|
--- with set-returning function: no index
|
||||||
SELECT pgivm.create_immv('mv_idx7', 'SELECT i FROM base_a, generate_series(1,10)');
|
SELECT create_immv('mv_idx7', 'SELECT i FROM base_a, generate_series(1,10)');
|
||||||
NOTICE: could not create an index on immv "mv_idx7" automatically
|
NOTICE: could not create an index on immv "mv_idx7" automatically
|
||||||
DETAIL: This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
|
DETAIL: This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
|
||||||
HINT: Create an index on the immv for efficient incremental maintenance.
|
HINT: Create an index on the immv for efficient incremental maintenance.
|
||||||
|
|
@ -1707,7 +1685,7 @@ ROLLBACK;
|
||||||
-- type that doesn't have default operator class for access method btree
|
-- type that doesn't have default operator class for access method btree
|
||||||
BEGIN;
|
BEGIN;
|
||||||
CREATE TABLE table_json (j json);
|
CREATE TABLE table_json (j json);
|
||||||
SELECT pgivm.create_immv('mv_json', 'SELECT * from table_json');
|
SELECT create_immv('mv_json', 'SELECT * from table_json');
|
||||||
ERROR: data type json has no default operator class for access method "btree"
|
ERROR: data type json has no default operator class for access method "btree"
|
||||||
ROLLBACK;
|
ROLLBACK;
|
||||||
-- prevent IMMV chanages
|
-- prevent IMMV chanages
|
||||||
|
|
@ -1720,7 +1698,7 @@ ERROR: cannot change materialized view "mv_ivm_1"
|
||||||
TRUNCATE mv_ivm_1;
|
TRUNCATE mv_ivm_1;
|
||||||
ERROR: cannot change materialized view "mv_ivm_1"
|
ERROR: cannot change materialized view "mv_ivm_1"
|
||||||
-- get_immv_def function
|
-- get_immv_def function
|
||||||
SELECT immvrelid, pgivm.get_immv_def(immvrelid) FROM pgivm.pg_ivm_immv ORDER BY 1;
|
SELECT immvrelid, get_immv_def(immvrelid) FROM pg_ivm_immv ORDER BY 1;
|
||||||
immvrelid | get_immv_def
|
immvrelid | get_immv_def
|
||||||
-----------+----------------------------------
|
-----------+----------------------------------
|
||||||
mv_ivm_1 | SELECT a.i, +
|
mv_ivm_1 | SELECT a.i, +
|
||||||
|
|
@ -1731,7 +1709,7 @@ SELECT immvrelid, pgivm.get_immv_def(immvrelid) FROM pgivm.pg_ivm_immv ORDER BY
|
||||||
(1 row)
|
(1 row)
|
||||||
|
|
||||||
-- mv_base_b is not immv
|
-- mv_base_b is not immv
|
||||||
SELECT 'mv_base_b'::regclass, pgivm.get_immv_def('mv_base_b');
|
SELECT 'mv_base_b'::regclass, get_immv_def('mv_base_b');
|
||||||
regclass | get_immv_def
|
regclass | get_immv_def
|
||||||
-----------+--------------
|
-----------+--------------
|
||||||
mv_base_b |
|
mv_base_b |
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,26 +1,26 @@
|
||||||
CREATE TABLE t (i int PRIMARY KEY);
|
CREATE TABLE t (i int PRIMARY KEY);
|
||||||
INSERT INTO t SELECT generate_series(1, 5);
|
INSERT INTO t SELECT generate_series(1, 5);
|
||||||
SELECT pgivm.create_immv('mv', 'SELECT * FROM t');
|
SELECT create_immv('mv', 'SELECT * FROM t');
|
||||||
NOTICE: created index "mv_index" on immv "mv"
|
NOTICE: created index "mv_index" on immv "mv"
|
||||||
create_immv
|
create_immv
|
||||||
-------------
|
-------------
|
||||||
5
|
5
|
||||||
(1 row)
|
(1 row)
|
||||||
|
|
||||||
SELECT immvrelid, ispopulated FROM pgivm.pg_ivm_immv ORDER BY 1;
|
SELECT immvrelid, ispopulated FROM pg_ivm_immv ORDER BY 1;
|
||||||
immvrelid | ispopulated
|
immvrelid | ispopulated
|
||||||
-----------+-------------
|
-----------+-------------
|
||||||
mv | t
|
mv | t
|
||||||
(1 row)
|
(1 row)
|
||||||
|
|
||||||
-- Refresh IMMV with data
|
-- Refresh IMMV with data
|
||||||
SELECT pgivm.refresh_immv('mv', true);
|
SELECT refresh_immv('mv', true);
|
||||||
refresh_immv
|
refresh_immv
|
||||||
--------------
|
--------------
|
||||||
5
|
5
|
||||||
(1 row)
|
(1 row)
|
||||||
|
|
||||||
SELECT immvrelid, ispopulated FROM pgivm.pg_ivm_immv ORDER BY 1;
|
SELECT immvrelid, ispopulated FROM pg_ivm_immv ORDER BY 1;
|
||||||
immvrelid | ispopulated
|
immvrelid | ispopulated
|
||||||
-----------+-------------
|
-----------+-------------
|
||||||
mv | t
|
mv | t
|
||||||
|
|
@ -39,13 +39,13 @@ SELECT i FROM mv ORDER BY 1;
|
||||||
(6 rows)
|
(6 rows)
|
||||||
|
|
||||||
-- Make IMMV unpopulated
|
-- Make IMMV unpopulated
|
||||||
SELECT pgivm.refresh_immv('mv', false);
|
SELECT refresh_immv('mv', false);
|
||||||
refresh_immv
|
refresh_immv
|
||||||
--------------
|
--------------
|
||||||
0
|
0
|
||||||
(1 row)
|
(1 row)
|
||||||
|
|
||||||
SELECT immvrelid, ispopulated FROM pgivm.pg_ivm_immv ORDER BY 1;
|
SELECT immvrelid, ispopulated FROM pg_ivm_immv ORDER BY 1;
|
||||||
immvrelid | ispopulated
|
immvrelid | ispopulated
|
||||||
-----------+-------------
|
-----------+-------------
|
||||||
mv | f
|
mv | f
|
||||||
|
|
@ -64,13 +64,13 @@ SELECT i FROM mv ORDER BY 1;
|
||||||
(0 rows)
|
(0 rows)
|
||||||
|
|
||||||
-- Refresh the IMMV and make it populated.
|
-- Refresh the IMMV and make it populated.
|
||||||
SELECT pgivm.refresh_immv('mv', true);
|
SELECT refresh_immv('mv', true);
|
||||||
refresh_immv
|
refresh_immv
|
||||||
--------------
|
--------------
|
||||||
7
|
7
|
||||||
(1 row)
|
(1 row)
|
||||||
|
|
||||||
SELECT immvrelid, ispopulated FROM pgivm.pg_ivm_immv ORDER BY 1;
|
SELECT immvrelid, ispopulated FROM pg_ivm_immv ORDER BY 1;
|
||||||
immvrelid | ispopulated
|
immvrelid | ispopulated
|
||||||
-----------+-------------
|
-----------+-------------
|
||||||
mv | t
|
mv | t
|
||||||
|
|
@ -104,15 +104,15 @@ SELECT i FROM mv ORDER BY 1;
|
||||||
(8 rows)
|
(8 rows)
|
||||||
|
|
||||||
-- Use qualified name
|
-- Use qualified name
|
||||||
SELECT pgivm.refresh_immv('public.mv', true);
|
SELECT refresh_immv('public.mv', true);
|
||||||
refresh_immv
|
refresh_immv
|
||||||
--------------
|
--------------
|
||||||
8
|
8
|
||||||
(1 row)
|
(1 row)
|
||||||
|
|
||||||
-- Use not existing IMMV
|
-- Use not existing IMMV
|
||||||
SELECT pgivm.refresh_immv('mv_not_existing', true);
|
SELECT refresh_immv('mv_not_existing', true);
|
||||||
ERROR: relation "mv_not_existing" does not exist
|
ERROR: relation "mv_not_existing" does not exist
|
||||||
-- Try to refresh a normal table -- error
|
-- Try to refresh a normal table -- error
|
||||||
SELECT pgivm.refresh_immv('t', true);
|
SELECT refresh_immv('t', true);
|
||||||
ERROR: "t" is not an IMMV
|
ERROR: "t" is not an IMMV
|
||||||
|
|
|
||||||
|
|
@ -1,253 +0,0 @@
|
||||||
Parsed test spec with 2 sessions
|
|
||||||
|
|
||||||
starting permutation: s1 refresh s2 insert c1 check2 c2 mv
|
|
||||||
step s1: SELECT;
|
|
||||||
step refresh: SELECT pgivm.refresh_immv('mv', true);
|
|
||||||
refresh_immv
|
|
||||||
------------
|
|
||||||
1
|
|
||||||
(1 row)
|
|
||||||
|
|
||||||
step s2: SELECT;
|
|
||||||
step insert: INSERT INTO a VALUES (2); <waiting ...>
|
|
||||||
step c1: COMMIT;
|
|
||||||
step insert: <... completed>
|
|
||||||
step check2: SELECT check_mv();
|
|
||||||
check_mv
|
|
||||||
--------
|
|
||||||
ok
|
|
||||||
(1 row)
|
|
||||||
|
|
||||||
step c2: COMMIT;
|
|
||||||
step mv: SELECT * FROM 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: SELECT pgivm.refresh_immv('mv', true);
|
|
||||||
refresh_immv
|
|
||||||
------------
|
|
||||||
1
|
|
||||||
(1 row)
|
|
||||||
|
|
||||||
step s2: SELECT;
|
|
||||||
step c1: COMMIT;
|
|
||||||
step insert: INSERT INTO a VALUES (2);
|
|
||||||
step check2: SELECT check_mv();
|
|
||||||
check_mv
|
|
||||||
--------
|
|
||||||
ok
|
|
||||||
(1 row)
|
|
||||||
|
|
||||||
step c2: COMMIT;
|
|
||||||
step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
|
|
||||||
x|y
|
|
||||||
-+-
|
|
||||||
1|1
|
|
||||||
2|2
|
|
||||||
(2 rows)
|
|
||||||
|
|
||||||
check_mv
|
|
||||||
--------
|
|
||||||
ok
|
|
||||||
(1 row)
|
|
||||||
|
|
||||||
|
|
||||||
starting permutation: s1 s2 refresh insert c1 check2 c2 mv
|
|
||||||
step s1: SELECT;
|
|
||||||
step s2: SELECT;
|
|
||||||
step refresh: SELECT pgivm.refresh_immv('mv', true);
|
|
||||||
refresh_immv
|
|
||||||
------------
|
|
||||||
1
|
|
||||||
(1 row)
|
|
||||||
|
|
||||||
step insert: INSERT INTO a VALUES (2); <waiting ...>
|
|
||||||
step c1: COMMIT;
|
|
||||||
step insert: <... completed>
|
|
||||||
step check2: SELECT check_mv();
|
|
||||||
check_mv
|
|
||||||
--------
|
|
||||||
ok
|
|
||||||
(1 row)
|
|
||||||
|
|
||||||
step c2: COMMIT;
|
|
||||||
step mv: SELECT * FROM mv ORDER 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: SELECT pgivm.refresh_immv('mv', true); <waiting ...>
|
|
||||||
step c2: COMMIT;
|
|
||||||
step refresh: <... completed>
|
|
||||||
refresh_immv
|
|
||||||
------------
|
|
||||||
2
|
|
||||||
(1 row)
|
|
||||||
|
|
||||||
step check1: SELECT check_mv();
|
|
||||||
check_mv
|
|
||||||
--------
|
|
||||||
ok
|
|
||||||
(1 row)
|
|
||||||
|
|
||||||
step c1: COMMIT;
|
|
||||||
step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
|
|
||||||
x|y
|
|
||||||
-+-
|
|
||||||
1|1
|
|
||||||
2|2
|
|
||||||
(2 rows)
|
|
||||||
|
|
||||||
check_mv
|
|
||||||
--------
|
|
||||||
ok
|
|
||||||
(1 row)
|
|
||||||
|
|
||||||
|
|
||||||
starting permutation: s1 s2 refresh c1 insert check2 c2 mv
|
|
||||||
step s1: SELECT;
|
|
||||||
step s2: SELECT;
|
|
||||||
step refresh: SELECT pgivm.refresh_immv('mv', true);
|
|
||||||
refresh_immv
|
|
||||||
------------
|
|
||||||
1
|
|
||||||
(1 row)
|
|
||||||
|
|
||||||
step c1: COMMIT;
|
|
||||||
step insert: INSERT INTO a VALUES (2);
|
|
||||||
step check2: SELECT check_mv();
|
|
||||||
check_mv
|
|
||||||
--------
|
|
||||||
ok
|
|
||||||
(1 row)
|
|
||||||
|
|
||||||
step c2: COMMIT;
|
|
||||||
step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
|
|
||||||
x|y
|
|
||||||
-+-
|
|
||||||
1|1
|
|
||||||
2|2
|
|
||||||
(2 rows)
|
|
||||||
|
|
||||||
check_mv
|
|
||||||
--------
|
|
||||||
ok
|
|
||||||
(1 row)
|
|
||||||
|
|
||||||
|
|
||||||
starting permutation: s2 insert s1 refresh c2 check1 c1 mv
|
|
||||||
step s2: SELECT;
|
|
||||||
step insert: INSERT INTO a VALUES (2);
|
|
||||||
step s1: SELECT;
|
|
||||||
step refresh: SELECT pgivm.refresh_immv('mv', true); <waiting ...>
|
|
||||||
step c2: COMMIT;
|
|
||||||
step refresh: <... completed>
|
|
||||||
refresh_immv
|
|
||||||
------------
|
|
||||||
2
|
|
||||||
(1 row)
|
|
||||||
|
|
||||||
step check1: SELECT check_mv();
|
|
||||||
check_mv
|
|
||||||
--------
|
|
||||||
ok
|
|
||||||
(1 row)
|
|
||||||
|
|
||||||
step c1: COMMIT;
|
|
||||||
step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
|
|
||||||
x|y
|
|
||||||
-+-
|
|
||||||
1|1
|
|
||||||
2|2
|
|
||||||
(2 rows)
|
|
||||||
|
|
||||||
check_mv
|
|
||||||
--------
|
|
||||||
ok
|
|
||||||
(1 row)
|
|
||||||
|
|
||||||
|
|
||||||
starting permutation: s2 insert s1 c2 refresh check1 c1 mv
|
|
||||||
step s2: SELECT;
|
|
||||||
step insert: INSERT INTO a VALUES (2);
|
|
||||||
step s1: SELECT;
|
|
||||||
step c2: COMMIT;
|
|
||||||
step refresh: SELECT pgivm.refresh_immv('mv', true);
|
|
||||||
refresh_immv
|
|
||||||
------------
|
|
||||||
2
|
|
||||||
(1 row)
|
|
||||||
|
|
||||||
step check1: SELECT check_mv();
|
|
||||||
check_mv
|
|
||||||
--------
|
|
||||||
ok
|
|
||||||
(1 row)
|
|
||||||
|
|
||||||
step c1: COMMIT;
|
|
||||||
step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
|
|
||||||
x|y
|
|
||||||
-+-
|
|
||||||
1|1
|
|
||||||
2|2
|
|
||||||
(2 rows)
|
|
||||||
|
|
||||||
check_mv
|
|
||||||
--------
|
|
||||||
ok
|
|
||||||
(1 row)
|
|
||||||
|
|
||||||
|
|
||||||
starting permutation: s2 s1 insert c2 refresh check1 c1 mv
|
|
||||||
step s2: SELECT;
|
|
||||||
step s1: SELECT;
|
|
||||||
step insert: INSERT INTO a VALUES (2);
|
|
||||||
step c2: COMMIT;
|
|
||||||
step refresh: SELECT pgivm.refresh_immv('mv', true);
|
|
||||||
refresh_immv
|
|
||||||
------------
|
|
||||||
2
|
|
||||||
(1 row)
|
|
||||||
|
|
||||||
step check1: SELECT check_mv();
|
|
||||||
check_mv
|
|
||||||
--------
|
|
||||||
ok
|
|
||||||
(1 row)
|
|
||||||
|
|
||||||
step c1: COMMIT;
|
|
||||||
step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
|
|
||||||
x|y
|
|
||||||
-+-
|
|
||||||
1|1
|
|
||||||
2|2
|
|
||||||
(2 rows)
|
|
||||||
|
|
||||||
check_mv
|
|
||||||
--------
|
|
||||||
ok
|
|
||||||
(1 row)
|
|
||||||
|
|
||||||
|
|
@ -1,211 +0,0 @@
|
||||||
Parsed test spec with 2 sessions
|
|
||||||
|
|
||||||
starting permutation: s1 refresh s2 insert c1 check2 c2 mv
|
|
||||||
step s1: SELECT;
|
|
||||||
step refresh: SELECT pgivm.refresh_immv('mv', true);
|
|
||||||
refresh_immv
|
|
||||||
------------
|
|
||||||
1
|
|
||||||
(1 row)
|
|
||||||
|
|
||||||
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: SELECT pgivm.refresh_immv('mv', true);
|
|
||||||
refresh_immv
|
|
||||||
------------
|
|
||||||
1
|
|
||||||
(1 row)
|
|
||||||
|
|
||||||
step s2: SELECT;
|
|
||||||
step c1: COMMIT;
|
|
||||||
step insert: INSERT INTO a VALUES (2);
|
|
||||||
step check2: SELECT check_mv();
|
|
||||||
check_mv
|
|
||||||
--------
|
|
||||||
ok
|
|
||||||
(1 row)
|
|
||||||
|
|
||||||
step c2: COMMIT;
|
|
||||||
step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
|
|
||||||
x|y
|
|
||||||
-+-
|
|
||||||
1|1
|
|
||||||
2|2
|
|
||||||
(2 rows)
|
|
||||||
|
|
||||||
check_mv
|
|
||||||
--------
|
|
||||||
ok
|
|
||||||
(1 row)
|
|
||||||
|
|
||||||
|
|
||||||
starting permutation: s1 s2 refresh insert c1 check2 c2 mv
|
|
||||||
step s1: SELECT;
|
|
||||||
step s2: SELECT;
|
|
||||||
step refresh: SELECT pgivm.refresh_immv('mv', true);
|
|
||||||
refresh_immv
|
|
||||||
------------
|
|
||||||
1
|
|
||||||
(1 row)
|
|
||||||
|
|
||||||
step insert: INSERT INTO a VALUES (2);
|
|
||||||
ERROR: could not obtain lock on materialized view "mv" during incremental maintenance
|
|
||||||
step c1: COMMIT;
|
|
||||||
step check2: SELECT check_mv();
|
|
||||||
ERROR: current transaction is aborted, commands ignored until end of transaction block
|
|
||||||
step c2: COMMIT;
|
|
||||||
step mv: 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: SELECT pgivm.refresh_immv('mv', true); <waiting ...>
|
|
||||||
step c2: COMMIT;
|
|
||||||
step refresh: <... completed>
|
|
||||||
ERROR: the materialized view is incrementally updated in concurrent transaction
|
|
||||||
step check1: SELECT check_mv();
|
|
||||||
ERROR: current transaction is aborted, commands ignored until end of transaction block
|
|
||||||
step c1: COMMIT;
|
|
||||||
step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
|
|
||||||
x|y
|
|
||||||
-+-
|
|
||||||
1|1
|
|
||||||
2|2
|
|
||||||
(2 rows)
|
|
||||||
|
|
||||||
check_mv
|
|
||||||
--------
|
|
||||||
ok
|
|
||||||
(1 row)
|
|
||||||
|
|
||||||
|
|
||||||
starting permutation: s1 s2 refresh c1 insert check2 c2 mv
|
|
||||||
step s1: SELECT;
|
|
||||||
step s2: SELECT;
|
|
||||||
step refresh: SELECT pgivm.refresh_immv('mv', true);
|
|
||||||
refresh_immv
|
|
||||||
------------
|
|
||||||
1
|
|
||||||
(1 row)
|
|
||||||
|
|
||||||
step c1: COMMIT;
|
|
||||||
step insert: INSERT INTO a VALUES (2);
|
|
||||||
step check2: SELECT check_mv();
|
|
||||||
check_mv
|
|
||||||
--------
|
|
||||||
ok
|
|
||||||
(1 row)
|
|
||||||
|
|
||||||
step c2: COMMIT;
|
|
||||||
step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
|
|
||||||
x|y
|
|
||||||
-+-
|
|
||||||
1|1
|
|
||||||
2|2
|
|
||||||
(2 rows)
|
|
||||||
|
|
||||||
check_mv
|
|
||||||
--------
|
|
||||||
ok
|
|
||||||
(1 row)
|
|
||||||
|
|
||||||
|
|
||||||
starting permutation: s2 insert s1 refresh c2 check1 c1 mv
|
|
||||||
step s2: SELECT;
|
|
||||||
step insert: INSERT INTO a VALUES (2);
|
|
||||||
step s1: SELECT;
|
|
||||||
step refresh: SELECT pgivm.refresh_immv('mv', true); <waiting ...>
|
|
||||||
step c2: COMMIT;
|
|
||||||
step refresh: <... completed>
|
|
||||||
ERROR: the materialized view is incrementally updated in concurrent transaction
|
|
||||||
step check1: SELECT check_mv();
|
|
||||||
ERROR: current transaction is aborted, commands ignored until end of transaction block
|
|
||||||
step c1: COMMIT;
|
|
||||||
step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
|
|
||||||
x|y
|
|
||||||
-+-
|
|
||||||
1|1
|
|
||||||
2|2
|
|
||||||
(2 rows)
|
|
||||||
|
|
||||||
check_mv
|
|
||||||
--------
|
|
||||||
ok
|
|
||||||
(1 row)
|
|
||||||
|
|
||||||
|
|
||||||
starting permutation: s2 insert s1 c2 refresh check1 c1 mv
|
|
||||||
step s2: SELECT;
|
|
||||||
step insert: INSERT INTO a VALUES (2);
|
|
||||||
step s1: SELECT;
|
|
||||||
step c2: COMMIT;
|
|
||||||
step refresh: SELECT pgivm.refresh_immv('mv', true);
|
|
||||||
ERROR: the materialized view is incrementally updated in concurrent transaction
|
|
||||||
step check1: SELECT check_mv();
|
|
||||||
ERROR: current transaction is aborted, commands ignored until end of transaction block
|
|
||||||
step c1: COMMIT;
|
|
||||||
step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
|
|
||||||
x|y
|
|
||||||
-+-
|
|
||||||
1|1
|
|
||||||
2|2
|
|
||||||
(2 rows)
|
|
||||||
|
|
||||||
check_mv
|
|
||||||
--------
|
|
||||||
ok
|
|
||||||
(1 row)
|
|
||||||
|
|
||||||
|
|
||||||
starting permutation: s2 s1 insert c2 refresh check1 c1 mv
|
|
||||||
step s2: SELECT;
|
|
||||||
step s1: SELECT;
|
|
||||||
step insert: INSERT INTO a VALUES (2);
|
|
||||||
step c2: COMMIT;
|
|
||||||
step refresh: SELECT pgivm.refresh_immv('mv', true);
|
|
||||||
ERROR: the materialized view is incrementally updated in concurrent transaction
|
|
||||||
step check1: SELECT check_mv();
|
|
||||||
ERROR: current transaction is aborted, commands ignored until end of transaction block
|
|
||||||
step c1: COMMIT;
|
|
||||||
step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
|
|
||||||
x|y
|
|
||||||
-+-
|
|
||||||
1|1
|
|
||||||
2|2
|
|
||||||
(2 rows)
|
|
||||||
|
|
||||||
check_mv
|
|
||||||
--------
|
|
||||||
ok
|
|
||||||
(1 row)
|
|
||||||
|
|
||||||
|
|
@ -1,211 +0,0 @@
|
||||||
Parsed test spec with 2 sessions
|
|
||||||
|
|
||||||
starting permutation: s1 refresh s2 insert c1 check2 c2 mv
|
|
||||||
step s1: SELECT;
|
|
||||||
step refresh: SELECT pgivm.refresh_immv('mv', true);
|
|
||||||
refresh_immv
|
|
||||||
------------
|
|
||||||
1
|
|
||||||
(1 row)
|
|
||||||
|
|
||||||
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: SELECT pgivm.refresh_immv('mv', true);
|
|
||||||
refresh_immv
|
|
||||||
------------
|
|
||||||
1
|
|
||||||
(1 row)
|
|
||||||
|
|
||||||
step s2: SELECT;
|
|
||||||
step c1: COMMIT;
|
|
||||||
step insert: INSERT INTO a VALUES (2);
|
|
||||||
step check2: SELECT check_mv();
|
|
||||||
check_mv
|
|
||||||
--------
|
|
||||||
ok
|
|
||||||
(1 row)
|
|
||||||
|
|
||||||
step c2: COMMIT;
|
|
||||||
step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
|
|
||||||
x|y
|
|
||||||
-+-
|
|
||||||
1|1
|
|
||||||
2|2
|
|
||||||
(2 rows)
|
|
||||||
|
|
||||||
check_mv
|
|
||||||
--------
|
|
||||||
ok
|
|
||||||
(1 row)
|
|
||||||
|
|
||||||
|
|
||||||
starting permutation: s1 s2 refresh insert c1 check2 c2 mv
|
|
||||||
step s1: SELECT;
|
|
||||||
step s2: SELECT;
|
|
||||||
step refresh: SELECT pgivm.refresh_immv('mv', true);
|
|
||||||
refresh_immv
|
|
||||||
------------
|
|
||||||
1
|
|
||||||
(1 row)
|
|
||||||
|
|
||||||
step insert: INSERT INTO a VALUES (2);
|
|
||||||
ERROR: could not obtain lock on materialized view "mv" during incremental maintenance
|
|
||||||
step c1: COMMIT;
|
|
||||||
step check2: SELECT check_mv();
|
|
||||||
ERROR: current transaction is aborted, commands ignored until end of transaction block
|
|
||||||
step c2: COMMIT;
|
|
||||||
step mv: 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: SELECT pgivm.refresh_immv('mv', true); <waiting ...>
|
|
||||||
step c2: COMMIT;
|
|
||||||
step refresh: <... completed>
|
|
||||||
ERROR: the materialized view is incrementally updated in concurrent transaction
|
|
||||||
step check1: SELECT check_mv();
|
|
||||||
ERROR: current transaction is aborted, commands ignored until end of transaction block
|
|
||||||
step c1: COMMIT;
|
|
||||||
step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
|
|
||||||
x|y
|
|
||||||
-+-
|
|
||||||
1|1
|
|
||||||
2|2
|
|
||||||
(2 rows)
|
|
||||||
|
|
||||||
check_mv
|
|
||||||
--------
|
|
||||||
ok
|
|
||||||
(1 row)
|
|
||||||
|
|
||||||
|
|
||||||
starting permutation: s1 s2 refresh c1 insert check2 c2 mv
|
|
||||||
step s1: SELECT;
|
|
||||||
step s2: SELECT;
|
|
||||||
step refresh: SELECT pgivm.refresh_immv('mv', true);
|
|
||||||
refresh_immv
|
|
||||||
------------
|
|
||||||
1
|
|
||||||
(1 row)
|
|
||||||
|
|
||||||
step c1: COMMIT;
|
|
||||||
step insert: INSERT INTO a VALUES (2);
|
|
||||||
step check2: SELECT check_mv();
|
|
||||||
check_mv
|
|
||||||
--------
|
|
||||||
ok
|
|
||||||
(1 row)
|
|
||||||
|
|
||||||
step c2: COMMIT;
|
|
||||||
step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
|
|
||||||
x|y
|
|
||||||
-+-
|
|
||||||
1|1
|
|
||||||
2|2
|
|
||||||
(2 rows)
|
|
||||||
|
|
||||||
check_mv
|
|
||||||
--------
|
|
||||||
ok
|
|
||||||
(1 row)
|
|
||||||
|
|
||||||
|
|
||||||
starting permutation: s2 insert s1 refresh c2 check1 c1 mv
|
|
||||||
step s2: SELECT;
|
|
||||||
step insert: INSERT INTO a VALUES (2);
|
|
||||||
step s1: SELECT;
|
|
||||||
step refresh: SELECT pgivm.refresh_immv('mv', true); <waiting ...>
|
|
||||||
step c2: COMMIT;
|
|
||||||
step refresh: <... completed>
|
|
||||||
ERROR: the materialized view is incrementally updated in concurrent transaction
|
|
||||||
step check1: SELECT check_mv();
|
|
||||||
ERROR: current transaction is aborted, commands ignored until end of transaction block
|
|
||||||
step c1: COMMIT;
|
|
||||||
step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
|
|
||||||
x|y
|
|
||||||
-+-
|
|
||||||
1|1
|
|
||||||
2|2
|
|
||||||
(2 rows)
|
|
||||||
|
|
||||||
check_mv
|
|
||||||
--------
|
|
||||||
ok
|
|
||||||
(1 row)
|
|
||||||
|
|
||||||
|
|
||||||
starting permutation: s2 insert s1 c2 refresh check1 c1 mv
|
|
||||||
step s2: SELECT;
|
|
||||||
step insert: INSERT INTO a VALUES (2);
|
|
||||||
step s1: SELECT;
|
|
||||||
step c2: COMMIT;
|
|
||||||
step refresh: SELECT pgivm.refresh_immv('mv', true);
|
|
||||||
ERROR: the materialized view is incrementally updated in concurrent transaction
|
|
||||||
step check1: SELECT check_mv();
|
|
||||||
ERROR: current transaction is aborted, commands ignored until end of transaction block
|
|
||||||
step c1: COMMIT;
|
|
||||||
step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
|
|
||||||
x|y
|
|
||||||
-+-
|
|
||||||
1|1
|
|
||||||
2|2
|
|
||||||
(2 rows)
|
|
||||||
|
|
||||||
check_mv
|
|
||||||
--------
|
|
||||||
ok
|
|
||||||
(1 row)
|
|
||||||
|
|
||||||
|
|
||||||
starting permutation: s2 s1 insert c2 refresh check1 c1 mv
|
|
||||||
step s2: SELECT;
|
|
||||||
step s1: SELECT;
|
|
||||||
step insert: INSERT INTO a VALUES (2);
|
|
||||||
step c2: COMMIT;
|
|
||||||
step refresh: SELECT pgivm.refresh_immv('mv', true);
|
|
||||||
ERROR: the materialized view is incrementally updated in concurrent transaction
|
|
||||||
step check1: SELECT check_mv();
|
|
||||||
ERROR: current transaction is aborted, commands ignored until end of transaction block
|
|
||||||
step c1: COMMIT;
|
|
||||||
step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
|
|
||||||
x|y
|
|
||||||
-+-
|
|
||||||
1|1
|
|
||||||
2|2
|
|
||||||
(2 rows)
|
|
||||||
|
|
||||||
check_mv
|
|
||||||
--------
|
|
||||||
ok
|
|
||||||
(1 row)
|
|
||||||
|
|
||||||
434
matview.c
434
matview.c
|
|
@ -50,7 +50,6 @@
|
||||||
#include "utils/rel.h"
|
#include "utils/rel.h"
|
||||||
#include "utils/snapmgr.h"
|
#include "utils/snapmgr.h"
|
||||||
#include "utils/typcache.h"
|
#include "utils/typcache.h"
|
||||||
#include "utils/xid8.h"
|
|
||||||
|
|
||||||
#include "pg_ivm.h"
|
#include "pg_ivm.h"
|
||||||
|
|
||||||
|
|
@ -108,15 +107,6 @@ typedef struct MV_TriggerHashEntry
|
||||||
List *tables; /* List of MV_TriggerTable */
|
List *tables; /* List of MV_TriggerTable */
|
||||||
bool has_old; /* tuples are deleted from any table? */
|
bool has_old; /* tuples are deleted from any table? */
|
||||||
bool has_new; /* tuples are inserted into any table? */
|
bool has_new; /* tuples are inserted into any table? */
|
||||||
|
|
||||||
/*
|
|
||||||
* List of sub-transaction IDs that incrementally updated the view.
|
|
||||||
* This list is maintained through a transaction, and an ID is removed
|
|
||||||
* when a sub-transaction is aborted. If any ID is left when the
|
|
||||||
* transaction is committed, this means the view is incrementally
|
|
||||||
* updated in this transaction.
|
|
||||||
*/
|
|
||||||
List *subxids;
|
|
||||||
} MV_TriggerHashEntry;
|
} MV_TriggerHashEntry;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -169,12 +159,11 @@ static void CloseImmvIncrementalMaintenance(void);
|
||||||
static Query *rewrite_query_for_preupdate_state(Query *query, List *tables,
|
static Query *rewrite_query_for_preupdate_state(Query *query, List *tables,
|
||||||
ParseState *pstate, List *rte_path, Oid matviewid);
|
ParseState *pstate, List *rte_path, Oid matviewid);
|
||||||
static void register_delta_ENRs(ParseState *pstate, Query *query, List *tables);
|
static void register_delta_ENRs(ParseState *pstate, Query *query, List *tables);
|
||||||
static char*make_subquery_targetlist_from_table(MV_TriggerTable *table);
|
|
||||||
static char *make_delta_enr_name(const char *prefix, Oid relid, int count);
|
static char *make_delta_enr_name(const char *prefix, Oid relid, int count);
|
||||||
static RangeTblEntry *get_prestate_rte(RangeTblEntry *rte, MV_TriggerTable *table,
|
static RangeTblEntry *get_prestate_rte(RangeTblEntry *rte, MV_TriggerTable *table,
|
||||||
QueryEnvironment *queryEnv, Oid matviewid);
|
QueryEnvironment *queryEnv, Oid matviewid);
|
||||||
static RangeTblEntry *union_ENRs(RangeTblEntry *rte, MV_TriggerTable *table, List *enr_rtes,
|
static RangeTblEntry *union_ENRs(RangeTblEntry *rte, Oid relid, List *enr_rtes, const char *prefix,
|
||||||
const char *prefix, QueryEnvironment *queryEnv);
|
QueryEnvironment *queryEnv);
|
||||||
static Query *rewrite_query_for_distinct_and_aggregates(Query *query, ParseState *pstate);
|
static Query *rewrite_query_for_distinct_and_aggregates(Query *query, ParseState *pstate);
|
||||||
|
|
||||||
static void calc_delta(MV_TriggerTable *table, List *rte_path, Query *query,
|
static void calc_delta(MV_TriggerTable *table, List *rte_path, Query *query,
|
||||||
|
|
@ -228,11 +217,7 @@ static void mv_InitHashTables(void);
|
||||||
static SPIPlanPtr mv_FetchPreparedPlan(MV_QueryKey *key);
|
static SPIPlanPtr mv_FetchPreparedPlan(MV_QueryKey *key);
|
||||||
static void mv_HashPreparedPlan(MV_QueryKey *key, SPIPlanPtr plan);
|
static void mv_HashPreparedPlan(MV_QueryKey *key, SPIPlanPtr plan);
|
||||||
static void mv_BuildQueryKey(MV_QueryKey *key, Oid matview_id, int32 query_type);
|
static void mv_BuildQueryKey(MV_QueryKey *key, Oid matview_id, int32 query_type);
|
||||||
static void clean_up_IVM_hash_entry(MV_TriggerHashEntry *entry, bool is_abort,
|
static void clean_up_IVM_hash_entry(MV_TriggerHashEntry *entry, bool is_abort);
|
||||||
SubTransactionId subxid);
|
|
||||||
static void setLastUpdateXid(Oid immv_oid, FullTransactionId xid);
|
|
||||||
static FullTransactionId getLastUpdateXid(Oid immv_oid);
|
|
||||||
|
|
||||||
|
|
||||||
/* SQL callable functions */
|
/* SQL callable functions */
|
||||||
PG_FUNCTION_INFO_V1(IVM_immediate_before);
|
PG_FUNCTION_INFO_V1(IVM_immediate_before);
|
||||||
|
|
@ -271,18 +256,16 @@ ExecRefreshImmv(const RangeVar *relation, bool skipData,
|
||||||
NULL);
|
NULL);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return RefreshImmvByOid(matviewOid, false, skipData, queryString, qc);
|
return RefreshImmvByOid(matviewOid, skipData, queryString, qc);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* RefreshMatViewByOid -- refresh IMMV view by OID
|
* RefreshMatViewByOid -- refresh IMMV view by OID
|
||||||
*
|
*
|
||||||
* This is also used to populate the IMMV created by create_immv command.
|
|
||||||
*
|
|
||||||
* This imitates PostgreSQL's RefreshMatViewByOid().
|
* This imitates PostgreSQL's RefreshMatViewByOid().
|
||||||
*/
|
*/
|
||||||
ObjectAddress
|
ObjectAddress
|
||||||
RefreshImmvByOid(Oid matviewOid, bool is_create, bool skipData,
|
RefreshImmvByOid(Oid matviewOid, bool skipData,
|
||||||
const char *queryString, QueryCompletion *qc)
|
const char *queryString, QueryCompletion *qc)
|
||||||
{
|
{
|
||||||
Relation matviewRel;
|
Relation matviewRel;
|
||||||
|
|
@ -462,19 +445,6 @@ RefreshImmvByOid(Oid matviewOid, bool is_create, bool skipData,
|
||||||
free_object_addresses(immv_triggers);
|
free_object_addresses(immv_triggers);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Create triggers on incremental maintainable materialized view
|
|
||||||
* This argument should use 'dataQuery'. This needs to use a rewritten query,
|
|
||||||
* because a sublink in jointree is not supported by this function.
|
|
||||||
*
|
|
||||||
* This is performed before generating data because we have to wait
|
|
||||||
* concurrent transactions modifying a base table and then take a snapshot
|
|
||||||
* to see changes by these transactions to make sure a consistent view
|
|
||||||
* is created.
|
|
||||||
*/
|
|
||||||
if (!skipData && !oldPopulated)
|
|
||||||
CreateIvmTriggersOnBaseTables(dataQuery, matviewOid);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Create the transient table that will receive the regenerated data. Lock
|
* Create the transient table that will receive the regenerated data. Lock
|
||||||
* it against access by any other process until commit (by which time it
|
* it against access by any other process until commit (by which time it
|
||||||
|
|
@ -490,41 +460,10 @@ RefreshImmvByOid(Oid matviewOid, bool is_create, bool skipData,
|
||||||
LockRelationOid(OIDNewHeap, AccessExclusiveLock);
|
LockRelationOid(OIDNewHeap, AccessExclusiveLock);
|
||||||
dest = CreateTransientRelDestReceiver(OIDNewHeap);
|
dest = CreateTransientRelDestReceiver(OIDNewHeap);
|
||||||
|
|
||||||
/*
|
|
||||||
* In READ COMMITTED, get and push the latest snapshot again to see the
|
|
||||||
* results of concurrent transactions committed after the current
|
|
||||||
* transaction started.
|
|
||||||
*/
|
|
||||||
if (!IsolationUsesXactSnapshot())
|
|
||||||
PushActiveSnapshot(GetTransactionSnapshot());
|
|
||||||
|
|
||||||
/*
|
|
||||||
* If a concurrent transaction updated the view incrementally and was
|
|
||||||
* committed before we acquired the lock, the results of refresh_immv could
|
|
||||||
* be inconsistent. Therefore, we have to check the transaction ID of the
|
|
||||||
* most recent update of the view, and if this was in progress at the
|
|
||||||
* transaction start, raise an error to prevent anomalies.
|
|
||||||
*/
|
|
||||||
if (!is_create)
|
|
||||||
{
|
|
||||||
FullTransactionId xid;
|
|
||||||
|
|
||||||
xid = getLastUpdateXid(matviewOid);
|
|
||||||
if (XidInMVCCSnapshot(XidFromFullTransactionId(xid), GetActiveSnapshot()))
|
|
||||||
ereport(ERROR,
|
|
||||||
(errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
|
|
||||||
errmsg("the materialized view is incrementally updated in concurrent transaction"),
|
|
||||||
errhint("The transaction might succeed if retried.")));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Generate the data, if wanted. */
|
/* Generate the data, if wanted. */
|
||||||
if (!skipData)
|
if (!skipData)
|
||||||
processed = refresh_immv_datafill(dest, dataQuery, NULL, NULL, queryString);
|
processed = refresh_immv_datafill(dest, dataQuery, NULL, NULL, queryString);
|
||||||
|
|
||||||
/* Pop the original snapshot. */
|
|
||||||
if (!IsolationUsesXactSnapshot())
|
|
||||||
PopActiveSnapshot();
|
|
||||||
|
|
||||||
/* Make the matview match the newly generated data. */
|
/* Make the matview match the newly generated data. */
|
||||||
refresh_by_heap_swap(matviewOid, OIDNewHeap, relpersistence);
|
refresh_by_heap_swap(matviewOid, OIDNewHeap, relpersistence);
|
||||||
|
|
||||||
|
|
@ -538,6 +477,14 @@ RefreshImmvByOid(Oid matviewOid, bool is_create, bool skipData,
|
||||||
if (!skipData)
|
if (!skipData)
|
||||||
pgstat_count_heap_insert(matviewRel, processed);
|
pgstat_count_heap_insert(matviewRel, processed);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Create triggers on incremental maintainable materialized view
|
||||||
|
* This argument should use 'dataQuery'. This needs to use a rewritten query,
|
||||||
|
* because a sublink in jointree is not supported by this function.
|
||||||
|
*/
|
||||||
|
if (!skipData && !oldPopulated)
|
||||||
|
CreateIvmTriggersOnBaseTables(dataQuery, matviewOid);
|
||||||
|
|
||||||
table_close(matviewRel, NoLock);
|
table_close(matviewRel, NoLock);
|
||||||
|
|
||||||
/* Roll back any GUC changes */
|
/* Roll back any GUC changes */
|
||||||
|
|
@ -617,11 +564,7 @@ refresh_immv_datafill(DestReceiver *dest, Query *query,
|
||||||
ExecutorStart(queryDesc, 0);
|
ExecutorStart(queryDesc, 0);
|
||||||
|
|
||||||
/* run the plan */
|
/* run the plan */
|
||||||
#if PG_VERSION_NUM < 180000
|
|
||||||
ExecutorRun(queryDesc, ForwardScanDirection, 0, true);
|
ExecutorRun(queryDesc, ForwardScanDirection, 0, true);
|
||||||
#else
|
|
||||||
ExecutorRun(queryDesc, ForwardScanDirection, 0);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
processed = queryDesc->estate->es_processed;
|
processed = queryDesc->estate->es_processed;
|
||||||
|
|
||||||
|
|
@ -763,8 +706,6 @@ IVM_immediate_before(PG_FUNCTION_ARGS)
|
||||||
/* If the view has more than one tables, we have to use an exclusive lock. */
|
/* If the view has more than one tables, we have to use an exclusive lock. */
|
||||||
if (ex_lock)
|
if (ex_lock)
|
||||||
{
|
{
|
||||||
FullTransactionId xid;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Wait for concurrent transactions which update this materialized view at
|
* Wait for concurrent transactions which update this materialized view at
|
||||||
* READ COMMITED. This is needed to see changes committed in other
|
* READ COMMITED. This is needed to see changes committed in other
|
||||||
|
|
@ -789,21 +730,6 @@ IVM_immediate_before(PG_FUNCTION_ARGS)
|
||||||
errmsg("could not obtain lock on materialized view \"%s\" during incremental maintenance",
|
errmsg("could not obtain lock on materialized view \"%s\" during incremental maintenance",
|
||||||
relname)));
|
relname)));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Even if we can acquire an lock, a concurrent transaction could have
|
|
||||||
* updated the view incrementally and been committed before we acquired
|
|
||||||
* the lock. Therefore, we have to check the transaction ID of the most
|
|
||||||
* recent update of the view, and if this was in progress at the
|
|
||||||
* transaction start, raise an error to prevent anomalies.
|
|
||||||
*/
|
|
||||||
xid = getLastUpdateXid(matviewOid);
|
|
||||||
if (XidInMVCCSnapshot(XidFromFullTransactionId(xid), GetTransactionSnapshot()))
|
|
||||||
ereport(ERROR,
|
|
||||||
(errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
|
|
||||||
errmsg("the materialized view is incrementally updated in concurrent transaction"),
|
|
||||||
errhint("The transaction might succeed if retried.")));
|
|
||||||
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
LockRelationOid(matviewOid, RowExclusiveLock);
|
LockRelationOid(matviewOid, RowExclusiveLock);
|
||||||
|
|
@ -819,22 +745,13 @@ IVM_immediate_before(PG_FUNCTION_ARGS)
|
||||||
HASH_ENTER, &found);
|
HASH_ENTER, &found);
|
||||||
|
|
||||||
/* On the first BEFORE to update the view, initialize trigger data */
|
/* On the first BEFORE to update the view, initialize trigger data */
|
||||||
if (!found || entry->snapshot == InvalidSnapshot)
|
if (!found)
|
||||||
{
|
{
|
||||||
Snapshot snapshot;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Get a snapshot just before the table was modified for checking
|
* Get a snapshot just before the table was modified for checking
|
||||||
* tuple visibility in the pre-update state of the table.
|
* tuple visibility in the pre-update state of the table.
|
||||||
*
|
|
||||||
* In READ COMMITTED, use the latest snapshot again to see the
|
|
||||||
* results of concurrent transactions committed after the current
|
|
||||||
* transaction started.
|
|
||||||
*/
|
*/
|
||||||
if (IsolationUsesXactSnapshot())
|
Snapshot snapshot = GetActiveSnapshot();
|
||||||
snapshot = GetActiveSnapshot();
|
|
||||||
else
|
|
||||||
snapshot = GetTransactionSnapshot();
|
|
||||||
|
|
||||||
entry->matview_id = matviewOid;
|
entry->matview_id = matviewOid;
|
||||||
entry->before_trig_count = 0;
|
entry->before_trig_count = 0;
|
||||||
|
|
@ -843,17 +760,11 @@ IVM_immediate_before(PG_FUNCTION_ARGS)
|
||||||
entry->tables = NIL;
|
entry->tables = NIL;
|
||||||
entry->has_old = false;
|
entry->has_old = false;
|
||||||
entry->has_new = false;
|
entry->has_new = false;
|
||||||
|
|
||||||
/*
|
|
||||||
* If this is the first table modifying query in the transaction,
|
|
||||||
* initialize the list of subxids.
|
|
||||||
*/
|
|
||||||
if (!found)
|
|
||||||
entry->subxids = NIL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
entry->before_trig_count++;
|
entry->before_trig_count++;
|
||||||
|
|
||||||
|
|
||||||
return PointerGetDatum(NULL);
|
return PointerGetDatum(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -876,7 +787,6 @@ IVM_immediate_maintenance(PG_FUNCTION_ARGS)
|
||||||
char *matviewOid_text = trigdata->tg_trigger->tgargs[0];
|
char *matviewOid_text = trigdata->tg_trigger->tgargs[0];
|
||||||
Relation matviewRel;
|
Relation matviewRel;
|
||||||
int old_depth = immv_maintenance_depth;
|
int old_depth = immv_maintenance_depth;
|
||||||
SubTransactionId subxid;
|
|
||||||
|
|
||||||
Oid relowner;
|
Oid relowner;
|
||||||
Tuplestorestate *old_tuplestore = NULL;
|
Tuplestorestate *old_tuplestore = NULL;
|
||||||
|
|
@ -942,7 +852,6 @@ IVM_immediate_maintenance(PG_FUNCTION_ARGS)
|
||||||
table->new_rtes = NIL;
|
table->new_rtes = NIL;
|
||||||
table->rte_paths = NIL;
|
table->rte_paths = NIL;
|
||||||
table->slot = MakeSingleTupleTableSlot(RelationGetDescr(rel), table_slot_callbacks(rel));
|
table->slot = MakeSingleTupleTableSlot(RelationGetDescr(rel), table_slot_callbacks(rel));
|
||||||
/* We assume we have at least RowExclusiveLock on modified tables. */
|
|
||||||
table->rel = table_open(RelationGetRelid(rel), NoLock);
|
table->rel = table_open(RelationGetRelid(rel), NoLock);
|
||||||
entry->tables = lappend(entry->tables, table);
|
entry->tables = lappend(entry->tables, table);
|
||||||
|
|
||||||
|
|
@ -975,23 +884,7 @@ IVM_immediate_maintenance(PG_FUNCTION_ARGS)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* record the subxid that updated the view incrementally
|
* Advance command counter to make the updated base table row locally
|
||||||
*
|
|
||||||
* Note:
|
|
||||||
* PG16 or later has list_member_xid and lappend_xid. It would be better
|
|
||||||
* to use them, but we use integer for supporting older PGs since there
|
|
||||||
* is no problem or now.
|
|
||||||
*/
|
|
||||||
subxid = GetCurrentSubTransactionId();
|
|
||||||
if (!list_member_int(entry->subxids, subxid))
|
|
||||||
{
|
|
||||||
oldcxt = MemoryContextSwitchTo(TopTransactionContext);
|
|
||||||
entry->subxids = lappend_int(entry->subxids, subxid);
|
|
||||||
MemoryContextSwitchTo(oldcxt);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Advance command counter to make the updated base table rows locally
|
|
||||||
* visible.
|
* visible.
|
||||||
*/
|
*/
|
||||||
CommandCounterIncrement();
|
CommandCounterIncrement();
|
||||||
|
|
@ -1002,11 +895,9 @@ IVM_immediate_maintenance(PG_FUNCTION_ARGS)
|
||||||
Assert(matviewRel->rd_rel->relkind == RELKIND_RELATION);
|
Assert(matviewRel->rd_rel->relkind == RELKIND_RELATION);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* In READ COMMITTED, get and push the latest snapshot again to see the
|
* Get and push the latast snapshot to see any changes which is committed
|
||||||
* results of concurrent transactions committed after the current
|
* during waiting in other transactions at READ COMMITTED level.
|
||||||
* transaction started.
|
|
||||||
*/
|
*/
|
||||||
if (!IsolationUsesXactSnapshot())
|
|
||||||
PushActiveSnapshot(GetTransactionSnapshot());
|
PushActiveSnapshot(GetTransactionSnapshot());
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -1092,10 +983,9 @@ IVM_immediate_maintenance(PG_FUNCTION_ARGS)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Clean up hash entry and delete tuplestores */
|
/* Clean up hash entry and delete tuplestores */
|
||||||
clean_up_IVM_hash_entry(entry, false, InvalidSubTransactionId);
|
clean_up_IVM_hash_entry(entry, false);
|
||||||
|
|
||||||
/* Pop the original snapshot. */
|
/* Pop the original snapshot. */
|
||||||
if (!IsolationUsesXactSnapshot())
|
|
||||||
PopActiveSnapshot();
|
PopActiveSnapshot();
|
||||||
|
|
||||||
table_close(matviewRel, NoLock);
|
table_close(matviewRel, NoLock);
|
||||||
|
|
@ -1256,7 +1146,7 @@ IVM_immediate_maintenance(PG_FUNCTION_ARGS)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Clean up hash entry and delete tuplestores */
|
/* Clean up hash entry and delete tuplestores */
|
||||||
clean_up_IVM_hash_entry(entry, false, InvalidSubTransactionId);
|
clean_up_IVM_hash_entry(entry, false);
|
||||||
if (old_tuplestore)
|
if (old_tuplestore)
|
||||||
{
|
{
|
||||||
dest_old->rDestroy(dest_old);
|
dest_old->rDestroy(dest_old);
|
||||||
|
|
@ -1269,7 +1159,6 @@ IVM_immediate_maintenance(PG_FUNCTION_ARGS)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Pop the original snapshot. */
|
/* Pop the original snapshot. */
|
||||||
if (!IsolationUsesXactSnapshot())
|
|
||||||
PopActiveSnapshot();
|
PopActiveSnapshot();
|
||||||
|
|
||||||
table_close(matviewRel, NoLock);
|
table_close(matviewRel, NoLock);
|
||||||
|
|
@ -1368,7 +1257,6 @@ rewrite_query_for_preupdate_state(Query *query, List *tables,
|
||||||
lfirst(lc) = rte_pre;
|
lfirst(lc) = rte_pre;
|
||||||
|
|
||||||
table->rte_paths = lappend(table->rte_paths, lappend_int(list_copy(rte_path), i));
|
table->rte_paths = lappend(table->rte_paths, lappend_int(list_copy(rte_path), i));
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1512,20 +1400,24 @@ get_prestate_rte(RangeTblEntry *rte, MV_TriggerTable *table,
|
||||||
StringInfoData str;
|
StringInfoData str;
|
||||||
RawStmt *raw;
|
RawStmt *raw;
|
||||||
Query *subquery;
|
Query *subquery;
|
||||||
|
Relation rel;
|
||||||
ParseState *pstate;
|
ParseState *pstate;
|
||||||
char *relname;
|
char *relname;
|
||||||
static char *subquery_tl;
|
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
pstate = make_parsestate(NULL);
|
pstate = make_parsestate(NULL);
|
||||||
pstate->p_queryEnv = queryEnv;
|
pstate->p_queryEnv = queryEnv;
|
||||||
pstate->p_expr_kind = EXPR_KIND_SELECT_TARGET;
|
pstate->p_expr_kind = EXPR_KIND_SELECT_TARGET;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We can use NoLock here since AcquireRewriteLocks should
|
||||||
|
* have locked the relation already.
|
||||||
|
*/
|
||||||
|
rel = table_open(table->table_id, NoLock);
|
||||||
relname = quote_qualified_identifier(
|
relname = quote_qualified_identifier(
|
||||||
get_namespace_name(RelationGetNamespace(table->rel)),
|
get_namespace_name(RelationGetNamespace(rel)),
|
||||||
RelationGetRelationName(table->rel));
|
RelationGetRelationName(rel));
|
||||||
|
table_close(rel, NoLock);
|
||||||
subquery_tl = make_subquery_targetlist_from_table(table);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Filtering inserted row using the snapshot taken before the table
|
* Filtering inserted row using the snapshot taken before the table
|
||||||
|
|
@ -1533,9 +1425,9 @@ get_prestate_rte(RangeTblEntry *rte, MV_TriggerTable *table,
|
||||||
*/
|
*/
|
||||||
initStringInfo(&str);
|
initStringInfo(&str);
|
||||||
appendStringInfo(&str,
|
appendStringInfo(&str,
|
||||||
"SELECT %s FROM %s t"
|
"SELECT t.* FROM %s t"
|
||||||
" WHERE pgivm.ivm_visible_in_prestate(t.tableoid, t.ctid, %d::pg_catalog.oid)",
|
" WHERE pg_catalog.ivm_visible_in_prestate(t.tableoid, t.ctid ,%d::pg_catalog.oid)",
|
||||||
subquery_tl, relname, matviewid);
|
relname, matviewid);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Append deleted rows contained in old transition tables.
|
* Append deleted rows contained in old transition tables.
|
||||||
|
|
@ -1543,8 +1435,8 @@ get_prestate_rte(RangeTblEntry *rte, MV_TriggerTable *table,
|
||||||
for (i = 0; i < list_length(table->old_tuplestores); i++)
|
for (i = 0; i < list_length(table->old_tuplestores); i++)
|
||||||
{
|
{
|
||||||
appendStringInfo(&str, " UNION ALL ");
|
appendStringInfo(&str, " UNION ALL ");
|
||||||
appendStringInfo(&str," SELECT %s FROM %s",
|
appendStringInfo(&str," SELECT * FROM %s",
|
||||||
subquery_tl, make_delta_enr_name("old", table->table_id, i));
|
make_delta_enr_name("old", table->table_id, i));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Get a subquery representing pre-state of the table */
|
/* Get a subquery representing pre-state of the table */
|
||||||
|
|
@ -1583,45 +1475,6 @@ get_prestate_rte(RangeTblEntry *rte, MV_TriggerTable *table,
|
||||||
return rte;
|
return rte;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* make_subquery_targetlist_from_table
|
|
||||||
*
|
|
||||||
* Make a targetlist string of a subquery representing a delta table or a
|
|
||||||
* pre-update state table. This subquery substitutes a modified table RTE
|
|
||||||
* in the view definition query during view maintenance. In the targetlist,
|
|
||||||
* column names appear in order of the table definition. However, for
|
|
||||||
* attribute numbers of vars in the query tree to reference columns of the
|
|
||||||
* subquery correctly even though the table has a dropped column, put "null"
|
|
||||||
* as a dummy value at the position of a dropped column.
|
|
||||||
*
|
|
||||||
* We would also able to walk the query tree to rewrite varattnos, but
|
|
||||||
* crafting targetlist is more simple and reasonable.
|
|
||||||
*/
|
|
||||||
static char*
|
|
||||||
make_subquery_targetlist_from_table(MV_TriggerTable *table)
|
|
||||||
{
|
|
||||||
StringInfoData str;
|
|
||||||
TupleDesc tupdesc;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
tupdesc = RelationGetDescr(table->rel);
|
|
||||||
initStringInfo(&str);
|
|
||||||
for (i = 0; i < tupdesc->natts; i++)
|
|
||||||
{
|
|
||||||
Form_pg_attribute attr = TupleDescAttr(tupdesc, i);
|
|
||||||
|
|
||||||
if (i > 0)
|
|
||||||
appendStringInfo(&str, ", ");
|
|
||||||
|
|
||||||
if (attr->attisdropped)
|
|
||||||
appendStringInfo(&str, "null");
|
|
||||||
else
|
|
||||||
appendStringInfo(&str, "%s", quote_identifier(NameStr(attr->attname)));
|
|
||||||
}
|
|
||||||
|
|
||||||
return str.data;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* make_delta_enr_name
|
* make_delta_enr_name
|
||||||
*
|
*
|
||||||
|
|
@ -1647,8 +1500,8 @@ make_delta_enr_name(const char *prefix, Oid relid, int count)
|
||||||
* all transition tables.
|
* all transition tables.
|
||||||
*/
|
*/
|
||||||
static RangeTblEntry*
|
static RangeTblEntry*
|
||||||
union_ENRs(RangeTblEntry *rte, MV_TriggerTable *table, List *enr_rtes,
|
union_ENRs(RangeTblEntry *rte, Oid relid, List *enr_rtes, const char *prefix,
|
||||||
const char *prefix, QueryEnvironment *queryEnv)
|
QueryEnvironment *queryEnv)
|
||||||
{
|
{
|
||||||
StringInfoData str;
|
StringInfoData str;
|
||||||
ParseState *pstate;
|
ParseState *pstate;
|
||||||
|
|
@ -1665,15 +1518,15 @@ union_ENRs(RangeTblEntry *rte, MV_TriggerTable *table, List *enr_rtes,
|
||||||
pstate->p_expr_kind = EXPR_KIND_SELECT_TARGET;
|
pstate->p_expr_kind = EXPR_KIND_SELECT_TARGET;
|
||||||
|
|
||||||
initStringInfo(&str);
|
initStringInfo(&str);
|
||||||
|
|
||||||
for (i = 0; i < list_length(enr_rtes); i++)
|
for (i = 0; i < list_length(enr_rtes); i++)
|
||||||
{
|
{
|
||||||
if (i > 0)
|
if (i > 0)
|
||||||
appendStringInfo(&str, " UNION ALL ");
|
appendStringInfo(&str, " UNION ALL ");
|
||||||
|
|
||||||
appendStringInfo(&str,
|
appendStringInfo(&str,
|
||||||
" SELECT %s FROM %s",
|
" SELECT * FROM %s",
|
||||||
make_subquery_targetlist_from_table(table),
|
make_delta_enr_name(prefix, relid, i));
|
||||||
make_delta_enr_name(prefix, table->table_id, i));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(PG_VERSION_NUM) && (PG_VERSION_NUM >= 140000)
|
#if defined(PG_VERSION_NUM) && (PG_VERSION_NUM >= 140000)
|
||||||
|
|
@ -1948,18 +1801,18 @@ calc_delta(MV_TriggerTable *table, List *rte_path, Query *query,
|
||||||
in_delta_calculation = true;
|
in_delta_calculation = true;
|
||||||
|
|
||||||
/* Generate old delta */
|
/* Generate old delta */
|
||||||
if (dest_old && list_length(table->old_rtes) > 0)
|
if (list_length(table->old_rtes) > 0)
|
||||||
{
|
{
|
||||||
/* Replace the modified table with the old delta table and calculate the old view delta. */
|
/* Replace the modified table with the old delta table and calculate the old view delta. */
|
||||||
lfirst(lc) = union_ENRs(rte, table, table->old_rtes, "old", queryEnv);
|
lfirst(lc) = union_ENRs(rte, table->table_id, table->old_rtes, "old", queryEnv);
|
||||||
refresh_immv_datafill(dest_old, query, queryEnv, tupdesc_old, "");
|
refresh_immv_datafill(dest_old, query, queryEnv, tupdesc_old, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Generate new delta */
|
/* Generate new delta */
|
||||||
if (dest_new && list_length(table->new_rtes) > 0)
|
if (list_length(table->new_rtes) > 0)
|
||||||
{
|
{
|
||||||
/* Replace the modified table with the new delta table and calculate the new view delta*/
|
/* Replace the modified table with the new delta table and calculate the new view delta*/
|
||||||
lfirst(lc) = union_ENRs(rte, table, table->new_rtes, "new", queryEnv);
|
lfirst(lc) = union_ENRs(rte, table->table_id, table->new_rtes, "new", queryEnv);
|
||||||
refresh_immv_datafill(dest_new, query, queryEnv, tupdesc_new, "");
|
refresh_immv_datafill(dest_new, query, queryEnv, tupdesc_new, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2210,7 +2063,7 @@ apply_delta(Oid matviewOid, Tuplestorestate *old_tuplestores, Tuplestorestate *n
|
||||||
/* apply new delta */
|
/* apply new delta */
|
||||||
if (use_count)
|
if (use_count)
|
||||||
apply_new_delta_with_count(matviewname, NEW_DELTA_ENRNAME,
|
apply_new_delta_with_count(matviewname, NEW_DELTA_ENRNAME,
|
||||||
keys, &target_list_buf, aggs_set_new, count_colname,
|
keys, aggs_set_new, &target_list_buf, count_colname,
|
||||||
query->distinctClause != NULL);
|
query->distinctClause != NULL);
|
||||||
else
|
else
|
||||||
apply_new_delta(matviewname, NEW_DELTA_ENRNAME, &target_list_buf);
|
apply_new_delta(matviewname, NEW_DELTA_ENRNAME, &target_list_buf);
|
||||||
|
|
@ -2537,8 +2390,8 @@ get_null_condition_string(IvmOp op, const char *arg1, const char *arg2,
|
||||||
/*
|
/*
|
||||||
* apply_old_delta_with_count
|
* apply_old_delta_with_count
|
||||||
*
|
*
|
||||||
* Execute a query for applying a delta table given by deltaname_old
|
* Execute a query for applying a delta table given by deltname_old
|
||||||
* which contains tuples to be deleted from a materialized view given by
|
* which contains tuples to be deleted from to a materialized view given by
|
||||||
* matviewname. This is used when counting is required, that is, the view
|
* matviewname. This is used when counting is required, that is, the view
|
||||||
* has aggregate or distinct. Also, when a table in EXISTS sub queries
|
* has aggregate or distinct. Also, when a table in EXISTS sub queries
|
||||||
* is modified.
|
* is modified.
|
||||||
|
|
@ -2633,8 +2486,8 @@ apply_old_delta_with_count(const char *matviewname, const char *deltaname_old,
|
||||||
/*
|
/*
|
||||||
* apply_old_delta
|
* apply_old_delta
|
||||||
*
|
*
|
||||||
* Execute a query for applying a delta table given by deltaname_old
|
* Execute a query for applying a delta table given by deltname_old
|
||||||
* which contains tuples to be deleted from a materialized view given by
|
* which contains tuples to be deleted from to a materialized view given by
|
||||||
* matviewname. This is used when counting is not required.
|
* matviewname. This is used when counting is not required.
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
|
|
@ -2682,7 +2535,7 @@ apply_old_delta(const char *matviewname, const char *deltaname_old,
|
||||||
/*
|
/*
|
||||||
* apply_new_delta_with_count
|
* apply_new_delta_with_count
|
||||||
*
|
*
|
||||||
* Execute a query for applying a delta table given by deltaname_new
|
* Execute a query for applying a delta table given by deltname_new
|
||||||
* which contains tuples to be inserted into a materialized view given by
|
* which contains tuples to be inserted into a materialized view given by
|
||||||
* matviewname. This is used when counting is required, that is, the view
|
* matviewname. This is used when counting is required, that is, the view
|
||||||
* has aggregate or distinct. Also, when a table in EXISTS sub queries
|
* has aggregate or distinct. Also, when a table in EXISTS sub queries
|
||||||
|
|
@ -2694,7 +2547,7 @@ apply_old_delta(const char *matviewname, const char *deltaname_old,
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
apply_new_delta_with_count(const char *matviewname, const char* deltaname_new,
|
apply_new_delta_with_count(const char *matviewname, const char* deltaname_new,
|
||||||
List *keys, StringInfo target_list, StringInfo aggs_set,
|
List *keys, StringInfo aggs_set, StringInfo target_list,
|
||||||
const char* count_colname, bool distinct)
|
const char* count_colname, bool distinct)
|
||||||
{
|
{
|
||||||
StringInfoData querybuf;
|
StringInfoData querybuf;
|
||||||
|
|
@ -2750,7 +2603,7 @@ apply_new_delta_with_count(const char *matviewname, const char* deltaname_new,
|
||||||
"FROM %s AS diff "
|
"FROM %s AS diff "
|
||||||
"WHERE %s " /* tuple matching condition */
|
"WHERE %s " /* tuple matching condition */
|
||||||
"RETURNING %s" /* returning keys of updated tuples */
|
"RETURNING %s" /* returning keys of updated tuples */
|
||||||
") INSERT INTO %s (%s)" /* insert a new tuple if this doesn't exist */
|
") INSERT INTO %s (%s)" /* insert a new tuple if this doesn't existw */
|
||||||
"SELECT %s FROM %s AS diff "
|
"SELECT %s FROM %s AS diff "
|
||||||
"WHERE NOT EXISTS (SELECT 1 FROM updt AS mv WHERE %s);",
|
"WHERE NOT EXISTS (SELECT 1 FROM updt AS mv WHERE %s);",
|
||||||
matviewname, count_colname, count_colname, count_colname,
|
matviewname, count_colname, count_colname, count_colname,
|
||||||
|
|
@ -2761,7 +2614,6 @@ apply_new_delta_with_count(const char *matviewname, const char* deltaname_new,
|
||||||
matviewname, target_list->data,
|
matviewname, target_list->data,
|
||||||
target_list->data, deltaname_new_for_insert.data,
|
target_list->data, deltaname_new_for_insert.data,
|
||||||
match_cond);
|
match_cond);
|
||||||
|
|
||||||
if (SPI_exec(querybuf.data, 0) != SPI_OK_INSERT)
|
if (SPI_exec(querybuf.data, 0) != SPI_OK_INSERT)
|
||||||
elog(ERROR, "SPI_exec failed: %s", querybuf.data);
|
elog(ERROR, "SPI_exec failed: %s", querybuf.data);
|
||||||
}
|
}
|
||||||
|
|
@ -2769,7 +2621,7 @@ apply_new_delta_with_count(const char *matviewname, const char* deltaname_new,
|
||||||
/*
|
/*
|
||||||
* apply_new_delta
|
* apply_new_delta
|
||||||
*
|
*
|
||||||
* Execute a query for applying a delta table given by deltaname_new
|
* Execute a query for applying a delta table given by deltname_new
|
||||||
* which contains tuples to be inserted into a materialized view given by
|
* which contains tuples to be inserted into a materialized view given by
|
||||||
* matviewname. This is used when counting is not required.
|
* matviewname. This is used when counting is not required.
|
||||||
*/
|
*/
|
||||||
|
|
@ -3328,11 +3180,10 @@ mv_BuildQueryKey(MV_QueryKey *key, Oid matview_id, int32 query_type)
|
||||||
* AtAbort_IVM
|
* AtAbort_IVM
|
||||||
*
|
*
|
||||||
* Clean up hash entries for all materialized views. This is called at
|
* Clean up hash entries for all materialized views. This is called at
|
||||||
* (sub-)transaction abort. When the top-level transaction is aborted,
|
* transaction abort.
|
||||||
* InvalidSubTransactionId is set to subxid.
|
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
AtAbort_IVM(SubTransactionId subxid)
|
AtAbort_IVM()
|
||||||
{
|
{
|
||||||
HASH_SEQ_STATUS seq;
|
HASH_SEQ_STATUS seq;
|
||||||
MV_TriggerHashEntry *entry;
|
MV_TriggerHashEntry *entry;
|
||||||
|
|
@ -3341,38 +3192,7 @@ AtAbort_IVM(SubTransactionId subxid)
|
||||||
{
|
{
|
||||||
hash_seq_init(&seq, mv_trigger_info);
|
hash_seq_init(&seq, mv_trigger_info);
|
||||||
while ((entry = hash_seq_search(&seq)) != NULL)
|
while ((entry = hash_seq_search(&seq)) != NULL)
|
||||||
clean_up_IVM_hash_entry(entry, true, subxid);
|
clean_up_IVM_hash_entry(entry, true);
|
||||||
}
|
|
||||||
|
|
||||||
in_delta_calculation = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* AtPreCommit_IVM
|
|
||||||
*
|
|
||||||
* Store the transaction ID that updated the view incrementally
|
|
||||||
* into the pg_ivm_immv catalog at transaction commit.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
AtPreCommit_IVM()
|
|
||||||
{
|
|
||||||
HASH_SEQ_STATUS seq;
|
|
||||||
MV_TriggerHashEntry *entry;
|
|
||||||
|
|
||||||
if (mv_trigger_info)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* For each view that was incrementally updated in the transaction,
|
|
||||||
* record the transaction ID into the pg_ivm_immv catalog, and perform
|
|
||||||
* the final clean up of the entry.
|
|
||||||
*/
|
|
||||||
hash_seq_init(&seq, mv_trigger_info);
|
|
||||||
while ((entry = hash_seq_search(&seq)) != NULL)
|
|
||||||
{
|
|
||||||
bool found;
|
|
||||||
setLastUpdateXid(entry->matview_id, GetTopFullTransactionId());
|
|
||||||
hash_search(mv_trigger_info, (void *) &entry->matview_id, HASH_REMOVE, &found);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
in_delta_calculation = false;
|
in_delta_calculation = false;
|
||||||
|
|
@ -3382,18 +3202,14 @@ AtPreCommit_IVM()
|
||||||
* clean_up_IVM_hash_entry
|
* clean_up_IVM_hash_entry
|
||||||
*
|
*
|
||||||
* Clean up tuple stores and hash entries for a materialized view after its
|
* Clean up tuple stores and hash entries for a materialized view after its
|
||||||
* maintenance finished. This is called at the end of table modifying query
|
* maintenance finished.
|
||||||
* or (sub-)transaction abort. When the top-level transaction is aborted,
|
|
||||||
* InvalidSubTransactionId is set to subxid.
|
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
clean_up_IVM_hash_entry(MV_TriggerHashEntry *entry, bool is_abort,
|
clean_up_IVM_hash_entry(MV_TriggerHashEntry *entry, bool is_abort)
|
||||||
SubTransactionId subxid)
|
|
||||||
{
|
{
|
||||||
bool found;
|
bool found;
|
||||||
ListCell *lc;
|
ListCell *lc;
|
||||||
|
|
||||||
/* clean up tuple stores */
|
|
||||||
foreach(lc, entry->tables)
|
foreach(lc, entry->tables)
|
||||||
{
|
{
|
||||||
MV_TriggerTable *table = (MV_TriggerTable *) lfirst(lc);
|
MV_TriggerTable *table = (MV_TriggerTable *) lfirst(lc);
|
||||||
|
|
@ -3419,140 +3235,12 @@ clean_up_IVM_hash_entry(MV_TriggerHashEntry *entry, bool is_abort,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
list_free(entry->tables);
|
list_free(entry->tables);
|
||||||
entry->tables = NIL;
|
|
||||||
|
|
||||||
if (is_abort)
|
if (!is_abort)
|
||||||
{
|
|
||||||
bool remove_entry = false;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* When the top-level transaction is aborted, remove all subxids.
|
|
||||||
* When a sub-transaction is aborted, remove only its subxid.
|
|
||||||
*/
|
|
||||||
if (subxid == InvalidSubTransactionId)
|
|
||||||
remove_entry = true;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
foreach(lc, entry->subxids)
|
|
||||||
{
|
|
||||||
/* Note:
|
|
||||||
* PG16 or later has lfirst_xid, but we use lfirst_int for
|
|
||||||
* supporting older PGs since there is no problem or now.
|
|
||||||
*/
|
|
||||||
if (lfirst_int(lc) == subxid)
|
|
||||||
{
|
|
||||||
entry->subxids = list_delete_cell(entry->subxids, lc);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* If all the subxid are removed, it means that the view was not
|
|
||||||
* updated at all in this transaction.
|
|
||||||
*/
|
|
||||||
if (list_length(entry->subxids) == 0)
|
|
||||||
remove_entry = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Remove entries of not updated views from the hash table.
|
|
||||||
*/
|
|
||||||
if (remove_entry)
|
|
||||||
hash_search(mv_trigger_info, (void *) &entry->matview_id, HASH_REMOVE, &found);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* When the query sucsessully finished, unregister the snapshot */
|
|
||||||
UnregisterSnapshot(entry->snapshot);
|
UnregisterSnapshot(entry->snapshot);
|
||||||
}
|
|
||||||
|
|
||||||
entry->snapshot = InvalidSnapshot;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
hash_search(mv_trigger_info, (void *) &entry->matview_id, HASH_REMOVE, &found);
|
||||||
* setLastUpdateXid
|
|
||||||
*
|
|
||||||
* Store the transaction ID that updated the view incremenally into the
|
|
||||||
* pg_ivm_immv catalog.
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
setLastUpdateXid(Oid immv_oid, FullTransactionId xid)
|
|
||||||
{
|
|
||||||
Relation pgIvmImmv = table_open(PgIvmImmvRelationId(), ShareRowExclusiveLock);
|
|
||||||
TupleDesc tupdesc = RelationGetDescr(pgIvmImmv);
|
|
||||||
SysScanDesc scan;
|
|
||||||
ScanKeyData key;
|
|
||||||
HeapTuple tup;
|
|
||||||
Datum values[Natts_pg_ivm_immv];
|
|
||||||
bool nulls[Natts_pg_ivm_immv];
|
|
||||||
bool replaces[Natts_pg_ivm_immv];
|
|
||||||
HeapTuple newtup = NULL;
|
|
||||||
|
|
||||||
ScanKeyInit(&key,
|
|
||||||
Anum_pg_ivm_immv_immvrelid,
|
|
||||||
BTEqualStrategyNumber, F_OIDEQ,
|
|
||||||
ObjectIdGetDatum(immv_oid));
|
|
||||||
scan = systable_beginscan(pgIvmImmv, PgIvmImmvPrimaryKeyIndexId(),
|
|
||||||
true, NULL, 1, &key);
|
|
||||||
tup = systable_getnext(scan);
|
|
||||||
|
|
||||||
memset(values, 0, sizeof(values));
|
|
||||||
values[Anum_pg_ivm_immv_lastivmupdate -1 ] = FullTransactionIdGetDatum(xid);
|
|
||||||
MemSet(nulls, false, sizeof(nulls));
|
|
||||||
MemSet(replaces, false, sizeof(replaces));
|
|
||||||
replaces[Anum_pg_ivm_immv_lastivmupdate -1 ] = true;
|
|
||||||
|
|
||||||
newtup = heap_modify_tuple(tup, tupdesc, values, nulls, replaces);
|
|
||||||
|
|
||||||
CatalogTupleUpdate(pgIvmImmv, &newtup->t_self, newtup);
|
|
||||||
heap_freetuple(newtup);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Advance command counter to make the updated pg_ivm_immv row locally
|
|
||||||
* visible.
|
|
||||||
*/
|
|
||||||
CommandCounterIncrement();
|
|
||||||
|
|
||||||
systable_endscan(scan);
|
|
||||||
table_close(pgIvmImmv, ShareRowExclusiveLock);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* getLastUpdateXid
|
|
||||||
*
|
|
||||||
* Get the most recent transaction ID that updated the view incrementally
|
|
||||||
* from the pg_ivm_immv catalog.
|
|
||||||
*/
|
|
||||||
static FullTransactionId
|
|
||||||
getLastUpdateXid(Oid immv_oid)
|
|
||||||
{
|
|
||||||
Relation pgIvmImmv = table_open(PgIvmImmvRelationId(), AccessShareLock);
|
|
||||||
TupleDesc tupdesc = RelationGetDescr(pgIvmImmv);
|
|
||||||
SysScanDesc scan;
|
|
||||||
ScanKeyData key;
|
|
||||||
HeapTuple tup;
|
|
||||||
bool isnull;
|
|
||||||
Datum datum;
|
|
||||||
FullTransactionId xid = InvalidFullTransactionId;
|
|
||||||
|
|
||||||
ScanKeyInit(&key,
|
|
||||||
Anum_pg_ivm_immv_immvrelid,
|
|
||||||
BTEqualStrategyNumber, F_OIDEQ,
|
|
||||||
ObjectIdGetDatum(immv_oid));
|
|
||||||
scan = systable_beginscan(pgIvmImmv, PgIvmImmvPrimaryKeyIndexId(),
|
|
||||||
true, NULL, 1, &key);
|
|
||||||
|
|
||||||
tup = systable_getnext(scan);
|
|
||||||
datum = heap_getattr(tup, Anum_pg_ivm_immv_lastivmupdate, tupdesc, &isnull);
|
|
||||||
|
|
||||||
if (!isnull)
|
|
||||||
xid = DatumGetFullTransactionId(datum);
|
|
||||||
|
|
||||||
systable_endscan(scan);
|
|
||||||
table_close(pgIvmImmv, NoLock);
|
|
||||||
|
|
||||||
return xid;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -3584,7 +3272,7 @@ getColumnNameStartWith(RangeTblEntry *rte, char *str, int *attnum)
|
||||||
/*
|
/*
|
||||||
* isIvmName
|
* isIvmName
|
||||||
*
|
*
|
||||||
* Check if this is an IVM hidden column from the name.
|
* Check if this is a IVM hidden column from the name.
|
||||||
*/
|
*/
|
||||||
bool
|
bool
|
||||||
isIvmName(const char *s)
|
isIvmName(const char *s)
|
||||||
|
|
|
||||||
101
meson.build
101
meson.build
|
|
@ -1,101 +0,0 @@
|
||||||
project('pg_ivm', ['c'])
|
|
||||||
|
|
||||||
pg_config = find_program('pg_config')
|
|
||||||
|
|
||||||
bindir = run_command(pg_config, '--bindir', check: true).stdout().strip()
|
|
||||||
includedir_server = run_command(pg_config, '--includedir-server', check: true).stdout().strip()
|
|
||||||
includedir = run_command(pg_config, '--includedir', check: true).stdout().strip()
|
|
||||||
pkglibdir = run_command(pg_config, '--pkglibdir', check: true).stdout().strip()
|
|
||||||
sharedir = run_command(pg_config, '--sharedir', check: true).stdout().strip()
|
|
||||||
libdir = run_command(pg_config, '--libdir', check: true).stdout().strip()
|
|
||||||
|
|
||||||
module_name = meson.project_name()
|
|
||||||
|
|
||||||
# ruleutils.c includes ruleutils_13.c or ruleutils_14.c based on PostgreSQL version
|
|
||||||
# Note: We don't need to explicitly add these files since they're included by ruleutils.c
|
|
||||||
pg_ivm_sources = files(
|
|
||||||
'createas.c',
|
|
||||||
'matview.c',
|
|
||||||
'pg_ivm.c',
|
|
||||||
'ruleutils.c',
|
|
||||||
'subselect.c',
|
|
||||||
)
|
|
||||||
|
|
||||||
if meson.get_compiler('c').get_id() == 'msvc'
|
|
||||||
incdir = [includedir_server / 'port/win32_msvc',
|
|
||||||
includedir_server / 'port/win32',
|
|
||||||
includedir_server,
|
|
||||||
includedir]
|
|
||||||
postgres_lib = meson.get_compiler('c').find_library(
|
|
||||||
'postgres',
|
|
||||||
dirs: libdir,
|
|
||||||
static: true,
|
|
||||||
required: true
|
|
||||||
)
|
|
||||||
else
|
|
||||||
incdir = [ includedir_server ]
|
|
||||||
postgres_lib = []
|
|
||||||
endif
|
|
||||||
|
|
||||||
shared_module(module_name,
|
|
||||||
pg_ivm_sources,
|
|
||||||
include_directories: incdir,
|
|
||||||
install: true,
|
|
||||||
install_dir: pkglibdir,
|
|
||||||
name_prefix: '',
|
|
||||||
dependencies: postgres_lib,
|
|
||||||
)
|
|
||||||
|
|
||||||
install_data(
|
|
||||||
'pg_ivm--1.0.sql',
|
|
||||||
'pg_ivm--1.0--1.1.sql',
|
|
||||||
'pg_ivm--1.1--1.2.sql',
|
|
||||||
'pg_ivm--1.2--1.3.sql',
|
|
||||||
'pg_ivm--1.3--1.4.sql',
|
|
||||||
'pg_ivm--1.4--1.5.sql',
|
|
||||||
'pg_ivm--1.5--1.6.sql',
|
|
||||||
'pg_ivm--1.6--1.7.sql',
|
|
||||||
'pg_ivm--1.7--1.8.sql',
|
|
||||||
'pg_ivm--1.8--1.9.sql',
|
|
||||||
'pg_ivm--1.9--1.10.sql',
|
|
||||||
'pg_ivm--1.10.sql',
|
|
||||||
'pg_ivm--1.10--1.11.sql',
|
|
||||||
'pg_ivm--1.11--1.12.sql',
|
|
||||||
'pg_ivm.control',
|
|
||||||
install_dir: sharedir / 'extension',
|
|
||||||
)
|
|
||||||
|
|
||||||
pg_regress = find_program('pg_regress',
|
|
||||||
dirs: [pkglibdir / 'pgxs/src/test/regress']
|
|
||||||
)
|
|
||||||
|
|
||||||
regress_tests = ['pg_ivm', 'create_immv', 'refresh_immv']
|
|
||||||
|
|
||||||
test('regress',
|
|
||||||
pg_regress,
|
|
||||||
args: ['--bindir', bindir,
|
|
||||||
'--inputdir', meson.current_source_dir(),
|
|
||||||
] + regress_tests,
|
|
||||||
)
|
|
||||||
|
|
||||||
pg_isolation_regress = find_program('pg_isolation_regress',
|
|
||||||
dirs: [pkglibdir / 'pgxs/src/test/isolation']
|
|
||||||
)
|
|
||||||
|
|
||||||
isolation_tests = [
|
|
||||||
'create_insert', 'refresh_insert', 'insert_insert',
|
|
||||||
'create_insert2', 'refresh_insert2', 'insert_insert2',
|
|
||||||
'create_insert3', 'refresh_insert3', 'insert_insert3'
|
|
||||||
]
|
|
||||||
|
|
||||||
isolation_opts = [
|
|
||||||
'--load-extension','pg_ivm',
|
|
||||||
]
|
|
||||||
|
|
||||||
test('isolation',
|
|
||||||
pg_isolation_regress,
|
|
||||||
args: ['--bindir', bindir,
|
|
||||||
'--inputdir', meson.current_source_dir(),
|
|
||||||
'--outputdir', 'output_iso',
|
|
||||||
] + isolation_opts + isolation_tests,
|
|
||||||
)
|
|
||||||
|
|
@ -11,6 +11,8 @@ CREATE TABLE __pg_ivm__.pg_ivm_immv(
|
||||||
|
|
||||||
ALTER TABLE __pg_ivm__.pg_ivm_immv SET SCHEMA pg_catalog;
|
ALTER TABLE __pg_ivm__.pg_ivm_immv SET SCHEMA pg_catalog;
|
||||||
|
|
||||||
|
--CREATE UNIQUE INDEX ON pg_catalog.pg_ivm_immv USING btree (immvrelid);
|
||||||
|
|
||||||
SELECT pg_catalog.pg_extension_config_dump('pg_catalog.pg_ivm_immv', '');
|
SELECT pg_catalog.pg_extension_config_dump('pg_catalog.pg_ivm_immv', '');
|
||||||
|
|
||||||
-- functions
|
-- functions
|
||||||
|
|
@ -42,7 +44,7 @@ LANGUAGE C;
|
||||||
/*
|
/*
|
||||||
* DDL trigger that removes entry from pg_ivm_immv
|
* DDL trigger that removes entry from pg_ivm_immv
|
||||||
*/
|
*/
|
||||||
CREATE FUNCTION pg_catalog.pg_ivm_sql_drop_trigger_func()
|
CREATE FUNCTION pg_ivm_sql_drop_trigger_func()
|
||||||
RETURNS event_trigger AS $$
|
RETURNS event_trigger AS $$
|
||||||
DECLARE
|
DECLARE
|
||||||
pg_class_oid OID;
|
pg_class_oid OID;
|
||||||
|
|
|
||||||
|
|
@ -1,60 +0,0 @@
|
||||||
CREATE SCHEMA pgivm;
|
|
||||||
|
|
||||||
-- catalog
|
|
||||||
|
|
||||||
CREATE TABLE pgivm.pg_ivm_immv(
|
|
||||||
immvrelid regclass NOT NULL,
|
|
||||||
viewdef text NOT NULL,
|
|
||||||
ispopulated bool NOT NULL,
|
|
||||||
lastivmupdate xid8,
|
|
||||||
|
|
||||||
CONSTRAINT pg_ivm_immv_pkey PRIMARY KEY (immvrelid)
|
|
||||||
);
|
|
||||||
|
|
||||||
SELECT pg_catalog.pg_extension_config_dump('pgivm.pg_ivm_immv', '');
|
|
||||||
|
|
||||||
-- functions
|
|
||||||
|
|
||||||
CREATE FUNCTION pgivm.create_immv(text, text)
|
|
||||||
RETURNS bigint
|
|
||||||
STRICT
|
|
||||||
AS 'MODULE_PATHNAME', 'create_immv'
|
|
||||||
LANGUAGE C;
|
|
||||||
|
|
||||||
CREATE FUNCTION pgivm.refresh_immv(text, bool)
|
|
||||||
RETURNS bigint
|
|
||||||
STRICT
|
|
||||||
AS 'MODULE_PATHNAME', 'refresh_immv'
|
|
||||||
LANGUAGE C;
|
|
||||||
|
|
||||||
CREATE FUNCTION pgivm.get_immv_def(IN immvrelid regclass)
|
|
||||||
RETURNS text
|
|
||||||
STRICT
|
|
||||||
AS 'MODULE_PATHNAME', 'get_immv_def'
|
|
||||||
LANGUAGE C;
|
|
||||||
|
|
||||||
CREATE FUNCTION pgivm.ivm_visible_in_prestate(oid, tid, oid)
|
|
||||||
RETURNS bool
|
|
||||||
STABLE
|
|
||||||
AS 'MODULE_PATHNAME', 'ivm_visible_in_prestate'
|
|
||||||
LANGUAGE C;
|
|
||||||
|
|
||||||
-- trigger functions
|
|
||||||
|
|
||||||
CREATE FUNCTION pgivm."IVM_immediate_before"()
|
|
||||||
RETURNS trigger
|
|
||||||
AS 'MODULE_PATHNAME', 'IVM_immediate_before'
|
|
||||||
LANGUAGE C;
|
|
||||||
|
|
||||||
CREATE FUNCTION pgivm."IVM_immediate_maintenance"()
|
|
||||||
RETURNS trigger
|
|
||||||
AS 'MODULE_PATHNAME', 'IVM_immediate_maintenance'
|
|
||||||
LANGUAGE C;
|
|
||||||
|
|
||||||
CREATE FUNCTION pgivm."IVM_prevent_immv_change"()
|
|
||||||
RETURNS trigger
|
|
||||||
AS 'MODULE_PATHNAME', 'IVM_prevent_immv_change'
|
|
||||||
LANGUAGE C;
|
|
||||||
|
|
||||||
GRANT SELECT ON TABLE pgivm.pg_ivm_immv TO PUBLIC;
|
|
||||||
GRANT USAGE ON SCHEMA pgivm TO PUBLIC;
|
|
||||||
|
|
@ -1,18 +0,0 @@
|
||||||
-- create a new schema pgivm and change the objects' schema to it
|
|
||||||
CREATE SCHEMA pgivm;
|
|
||||||
|
|
||||||
ALTER TABLE pg_ivm_immv SET SCHEMA pgivm;
|
|
||||||
ALTER FUNCTION create_immv(text, text) SET SCHEMA pgivm;
|
|
||||||
ALTER FUNCTION refresh_immv(text, bool) SET SCHEMA pgivm;
|
|
||||||
ALTER FUNCTION get_immv_def(regclass) SET SCHEMA pgivm;
|
|
||||||
ALTER FUNCTION ivm_visible_in_prestate(oid, tid, oid) SET SCHEMA pgivm;
|
|
||||||
ALTER FUNCTION "IVM_immediate_before"() SET SCHEMA pgivm;
|
|
||||||
ALTER FUNCTION "IVM_immediate_maintenance"() SET SCHEMA pgivm;
|
|
||||||
ALTER FUNCTION "IVM_prevent_immv_change"() SET SCHEMA pgivm;
|
|
||||||
|
|
||||||
GRANT USAGE ON SCHEMA pgivm TO PUBLIC;
|
|
||||||
|
|
||||||
ALTER TABLE pgivm.pg_ivm_immv ADD COLUMN lastivmupdate xid8;
|
|
||||||
|
|
||||||
-- drop a garbage
|
|
||||||
DROP SCHEMA __pg_ivm__;
|
|
||||||
37
pg_ivm.c
37
pg_ivm.c
|
|
@ -63,10 +63,8 @@ PG_FUNCTION_INFO_V1(get_immv_def);
|
||||||
static void
|
static void
|
||||||
IvmXactCallback(XactEvent event, void *arg)
|
IvmXactCallback(XactEvent event, void *arg)
|
||||||
{
|
{
|
||||||
if (event == XACT_EVENT_PRE_COMMIT)
|
if (event == XACT_EVENT_ABORT)
|
||||||
AtPreCommit_IVM();
|
AtAbort_IVM();
|
||||||
else if (event == XACT_EVENT_ABORT)
|
|
||||||
AtAbort_IVM(InvalidSubTransactionId);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|
@ -74,7 +72,7 @@ IvmSubXactCallback(SubXactEvent event, SubTransactionId mySubid,
|
||||||
SubTransactionId parentSubid, void *arg)
|
SubTransactionId parentSubid, void *arg)
|
||||||
{
|
{
|
||||||
if (event == SUBXACT_EVENT_ABORT_SUB)
|
if (event == SUBXACT_EVENT_ABORT_SUB)
|
||||||
AtAbort_IVM(mySubid);
|
AtAbort_IVM();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -93,7 +91,7 @@ _PG_init(void)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Given a C string, parse it into a qualified relation name
|
* Given a C string, parse it into a qualified relation name
|
||||||
* followed by an optional parenthesized list of column names.
|
* followed by a optional parenthesized list of column names.
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
parseNameAndColumns(const char *string, List **names, List **colNames)
|
parseNameAndColumns(const char *string, List **names, List **colNames)
|
||||||
|
|
@ -203,7 +201,7 @@ create_immv(PG_FUNCTION_ARGS)
|
||||||
|
|
||||||
parsetree = linitial_node(RawStmt, parsetree_list);
|
parsetree = linitial_node(RawStmt, parsetree_list);
|
||||||
|
|
||||||
/* view definition should specify SELECT query */
|
/* view definition should spcify SELECT query */
|
||||||
if (!IsA(parsetree->stmt, SelectStmt))
|
if (!IsA(parsetree->stmt, SelectStmt))
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
||||||
|
|
@ -224,14 +222,10 @@ create_immv(PG_FUNCTION_ARGS)
|
||||||
ctas->into->options = NIL;
|
ctas->into->options = NIL;
|
||||||
ctas->into->onCommit = ONCOMMIT_NOOP;
|
ctas->into->onCommit = ONCOMMIT_NOOP;
|
||||||
ctas->into->tableSpaceName = NULL;
|
ctas->into->tableSpaceName = NULL;
|
||||||
#if defined(PG_VERSION_NUM) && (PG_VERSION_NUM >= 180000)
|
|
||||||
ctas->into->viewQuery = (Query *) parsetree->stmt;
|
|
||||||
#else
|
|
||||||
ctas->into->viewQuery = parsetree->stmt;
|
ctas->into->viewQuery = parsetree->stmt;
|
||||||
#endif
|
|
||||||
ctas->into->skipData = false;
|
ctas->into->skipData = false;
|
||||||
|
|
||||||
query = transformStmt(pstate, (Node *) ctas);
|
query = transformStmt(pstate, (Node *)ctas);
|
||||||
Assert(query->commandType == CMD_UTILITY && IsA(query->utilityStmt, CreateTableAsStmt));
|
Assert(query->commandType == CMD_UTILITY && IsA(query->utilityStmt, CreateTableAsStmt));
|
||||||
|
|
||||||
ExecCreateImmv(pstate, (CreateTableAsStmt *) query->utilityStmt, &qc);
|
ExecCreateImmv(pstate, (CreateTableAsStmt *) query->utilityStmt, &qc);
|
||||||
|
|
@ -303,7 +297,7 @@ CreateChangePreventTrigger(Oid matviewOid)
|
||||||
|
|
||||||
ivm_trigger->timing = TRIGGER_TYPE_BEFORE;
|
ivm_trigger->timing = TRIGGER_TYPE_BEFORE;
|
||||||
ivm_trigger->trigname = "IVM_prevent_immv_change";
|
ivm_trigger->trigname = "IVM_prevent_immv_change";
|
||||||
ivm_trigger->funcname = PgIvmFuncName("IVM_prevent_immv_change");
|
ivm_trigger->funcname = SystemFuncName("IVM_prevent_immv_change");
|
||||||
ivm_trigger->columns = NIL;
|
ivm_trigger->columns = NIL;
|
||||||
ivm_trigger->transitionRels = NIL;
|
ivm_trigger->transitionRels = NIL;
|
||||||
ivm_trigger->whenClause = NULL;
|
ivm_trigger->whenClause = NULL;
|
||||||
|
|
@ -333,7 +327,7 @@ Oid
|
||||||
PgIvmImmvRelationId(void)
|
PgIvmImmvRelationId(void)
|
||||||
{
|
{
|
||||||
return RangeVarGetRelid(
|
return RangeVarGetRelid(
|
||||||
makeRangeVar("pgivm", "pg_ivm_immv", -1),
|
makeRangeVar("pg_catalog", "pg_ivm_immv", -1),
|
||||||
AccessShareLock, true);
|
AccessShareLock, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -344,12 +338,12 @@ Oid
|
||||||
PgIvmImmvPrimaryKeyIndexId(void)
|
PgIvmImmvPrimaryKeyIndexId(void)
|
||||||
{
|
{
|
||||||
return RangeVarGetRelid(
|
return RangeVarGetRelid(
|
||||||
makeRangeVar("pgivm", "pg_ivm_immv_pkey", -1),
|
makeRangeVar("pg_catalog", "pg_ivm_immv_pkey", -1),
|
||||||
AccessShareLock, true);
|
AccessShareLock, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Return the SELECT part of an IMMV
|
* Return the SELECT part of a IMMV
|
||||||
*/
|
*/
|
||||||
Datum
|
Datum
|
||||||
get_immv_def(PG_FUNCTION_ARGS)
|
get_immv_def(PG_FUNCTION_ARGS)
|
||||||
|
|
@ -427,7 +421,7 @@ PgIvmObjectAccessHook(ObjectAccessType access, Oid classId,
|
||||||
/*
|
/*
|
||||||
* isImmv
|
* isImmv
|
||||||
*
|
*
|
||||||
* Check if this is an IMMV from oid.
|
* Check if this is a IMMV from oid.
|
||||||
*/
|
*/
|
||||||
bool
|
bool
|
||||||
isImmv(Oid immv_oid)
|
isImmv(Oid immv_oid)
|
||||||
|
|
@ -453,12 +447,3 @@ isImmv(Oid immv_oid)
|
||||||
else
|
else
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* PgIvmFuncName()
|
|
||||||
* Build a properly-qualified reference to a pg_ivm internal function.
|
|
||||||
*/
|
|
||||||
List *
|
|
||||||
PgIvmFuncName(char *name)
|
|
||||||
{
|
|
||||||
return list_make2(makeString("pgivm"), makeString(name));
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
# incremental view maintenance extension
|
# incremental view maintenance extension_
|
||||||
comment = 'incremental view maintenance on PostgreSQL'
|
comment = 'incremental view maintenance on PostgreSQL'
|
||||||
default_version = '1.12'
|
default_version = '1.9'
|
||||||
module_pathname = '$libdir/pg_ivm'
|
module_pathname = '$libdir/pg_ivm'
|
||||||
relocatable = false
|
relocatable = false
|
||||||
schema = pg_catalog
|
schema = pg_catalog
|
||||||
|
|
|
||||||
16
pg_ivm.h
16
pg_ivm.h
|
|
@ -20,12 +20,11 @@
|
||||||
#include "tcop/dest.h"
|
#include "tcop/dest.h"
|
||||||
#include "utils/queryenvironment.h"
|
#include "utils/queryenvironment.h"
|
||||||
|
|
||||||
#define Natts_pg_ivm_immv 4
|
#define Natts_pg_ivm_immv 3
|
||||||
|
|
||||||
#define Anum_pg_ivm_immv_immvrelid 1
|
#define Anum_pg_ivm_immv_immvrelid 1
|
||||||
#define Anum_pg_ivm_immv_viewdef 2
|
#define Anum_pg_ivm_immv_viewdef 2
|
||||||
#define Anum_pg_ivm_immv_ispopulated 3
|
#define Anum_pg_ivm_immv_ispopulated 3
|
||||||
#define Anum_pg_ivm_immv_lastivmupdate 4
|
|
||||||
|
|
||||||
/* pg_ivm.c */
|
/* pg_ivm.c */
|
||||||
|
|
||||||
|
|
@ -33,7 +32,6 @@ extern void CreateChangePreventTrigger(Oid matviewOid);
|
||||||
extern Oid PgIvmImmvRelationId(void);
|
extern Oid PgIvmImmvRelationId(void);
|
||||||
extern Oid PgIvmImmvPrimaryKeyIndexId(void);
|
extern Oid PgIvmImmvPrimaryKeyIndexId(void);
|
||||||
extern bool isImmv(Oid immv_oid);
|
extern bool isImmv(Oid immv_oid);
|
||||||
extern List *PgIvmFuncName(char *name);
|
|
||||||
|
|
||||||
/* createas.c */
|
/* createas.c */
|
||||||
|
|
||||||
|
|
@ -49,15 +47,15 @@ extern void makeIvmAggColumn(ParseState *pstate, Aggref *aggref, char *resname,
|
||||||
extern Query *get_immv_query(Relation matviewRel);
|
extern Query *get_immv_query(Relation matviewRel);
|
||||||
extern ObjectAddress ExecRefreshImmv(const RangeVar *relation, bool skipData,
|
extern ObjectAddress ExecRefreshImmv(const RangeVar *relation, bool skipData,
|
||||||
const char *queryString, QueryCompletion *qc);
|
const char *queryString, QueryCompletion *qc);
|
||||||
extern ObjectAddress RefreshImmvByOid(Oid matviewOid, bool is_create, bool skipData,
|
extern ObjectAddress RefreshImmvByOid(Oid matviewOid, bool skipData,
|
||||||
const char *queryString, QueryCompletion *qc);
|
const char *queryString, QueryCompletion *qc);
|
||||||
extern bool ImmvIncrementalMaintenanceIsEnabled(void);
|
extern bool ImmvIncrementalMaintenanceIsEnabled(void);
|
||||||
extern PGDLLEXPORT Datum IVM_immediate_before(PG_FUNCTION_ARGS);
|
extern Query *get_immv_query(Relation matviewRel);
|
||||||
extern PGDLLEXPORT Datum IVM_immediate_maintenance(PG_FUNCTION_ARGS);
|
extern Datum IVM_immediate_before(PG_FUNCTION_ARGS);
|
||||||
|
extern Datum IVM_immediate_maintenance(PG_FUNCTION_ARGS);
|
||||||
extern Query* rewrite_query_for_exists_subquery(Query *query);
|
extern Query* rewrite_query_for_exists_subquery(Query *query);
|
||||||
extern PGDLLEXPORT Datum ivm_visible_in_prestate(PG_FUNCTION_ARGS);
|
extern Datum ivm_visible_in_prestate(PG_FUNCTION_ARGS);
|
||||||
extern void AtAbort_IVM(SubTransactionId subtxid);
|
extern void AtAbort_IVM(void);
|
||||||
extern void AtPreCommit_IVM(void);
|
|
||||||
extern char *getColumnNameStartWith(RangeTblEntry *rte, char *str, int *attnum);
|
extern char *getColumnNameStartWith(RangeTblEntry *rte, char *str, int *attnum);
|
||||||
extern bool isIvmName(const char *s);
|
extern bool isIvmName(const char *s);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
# How to build RPM:
|
# How to build RPM:
|
||||||
#
|
#
|
||||||
# rpmbuild -bb pg_ivm.spec --define "pgmajorversion 18" --define "pginstdir /usr/pgsql-18"
|
# rpmbuild -bb pg_ivm.spec --define "pgmajorversion 14" --define "pginstdir /usr/pgsql-14"
|
||||||
|
|
||||||
%global sname pg_ivm
|
%global sname pg_ivm
|
||||||
|
|
||||||
|
|
@ -8,11 +8,11 @@
|
||||||
%global llvm 1
|
%global llvm 1
|
||||||
%endif
|
%endif
|
||||||
|
|
||||||
Summary: Incremental View Maintenance (IVM) feature for PostgreSQL.
|
Summary: PostgreSQL-based distributed RDBMS
|
||||||
Name: %{sname}_%{pgmajorversion}
|
Name: %{sname}_%{pgmajorversion}
|
||||||
Version: 1.12
|
Version: 1.9
|
||||||
Release: 1%{dist}
|
Release: 1%{dist}
|
||||||
License: PostgreSQL
|
License: BSD
|
||||||
Vendor: IVM Development Group
|
Vendor: IVM Development Group
|
||||||
URL: https://github.com/sraoss/%{sname}
|
URL: https://github.com/sraoss/%{sname}
|
||||||
Source0: https://github.com/sraoss/%{sname}/archive/v%{version}.tar.gz
|
Source0: https://github.com/sraoss/%{sname}/archive/v%{version}.tar.gz
|
||||||
|
|
@ -55,12 +55,6 @@ PATH=%{pginstdir}/bin:$PATH %{__make} %{?_smp_mflags} INSTALL_PREFIX=%{buildroot
|
||||||
%endif
|
%endif
|
||||||
|
|
||||||
%changelog
|
%changelog
|
||||||
* Mon Sep 4 2025 - Yugo Nagata <nagata@sraoss.co.jp> 1.12-1
|
|
||||||
- Update to 1.12
|
|
||||||
* Mon May 25 2025 - Yugo Nagata <nagata@sraoss.co.jp> 1.11-1
|
|
||||||
- Update to 1.11
|
|
||||||
* Tue Mar 11 2025 - Yugo Nagata <nagata@sraoss.co.jp> 1.10-1
|
|
||||||
- Update to 1.10
|
|
||||||
* Fri Jul 31 2024 - Yugo Nagata <nagata@sraoss.co.jp> 1.9-1
|
* Fri Jul 31 2024 - Yugo Nagata <nagata@sraoss.co.jp> 1.9-1
|
||||||
- Update to 1.9
|
- Update to 1.9
|
||||||
* Fri Mar 1 2024 - Yugo Nagata <nagata@sraoss.co.jp> 1.8-1
|
* Fri Mar 1 2024 - Yugo Nagata <nagata@sraoss.co.jp> 1.8-1
|
||||||
|
|
|
||||||
|
|
@ -1,47 +0,0 @@
|
||||||
# Test interaction between concurrent transactions performing
|
|
||||||
# create_immv 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 TABLE mv;
|
|
||||||
DROP VIEW v;
|
|
||||||
DROP TABLE a;
|
|
||||||
}
|
|
||||||
|
|
||||||
session tx1
|
|
||||||
setup { BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
|
|
||||||
step s1 { SELECT; }
|
|
||||||
step create {
|
|
||||||
SELECT pgivm.create_immv('mv(x,y)', 'SELECT * FROM a a1, a a2 WHERE a1.i = a2.i');
|
|
||||||
CREATE FUNCTION check_mv() RETURNS text AS
|
|
||||||
$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
|
|
||||||
FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
|
|
||||||
(SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
|
|
||||||
}
|
|
||||||
step check1 {SELECT 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
|
|
||||||
|
|
@ -1,54 +0,0 @@
|
||||||
# Test interaction between concurrent transactions performing
|
|
||||||
# create_immv 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 TABLE mv;
|
|
||||||
DROP VIEW v;
|
|
||||||
DROP TABLE a;
|
|
||||||
}
|
|
||||||
|
|
||||||
session tx1
|
|
||||||
setup { BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
|
|
||||||
step s1 { SELECT; }
|
|
||||||
step create {
|
|
||||||
SELECT pgivm.create_immv('mv(x,y)', 'SELECT * FROM a a1, a a2 WHERE a1.i = a2.i');
|
|
||||||
CREATE FUNCTION check_mv() RETURNS text AS
|
|
||||||
$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
|
|
||||||
FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
|
|
||||||
(SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
|
|
||||||
}
|
|
||||||
step check1 {SELECT 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
|
|
||||||
|
|
@ -1,54 +0,0 @@
|
||||||
# Test interaction between concurrent transactions performing
|
|
||||||
# create_immv 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 TABLE mv;
|
|
||||||
DROP VIEW v;
|
|
||||||
DROP TABLE a;
|
|
||||||
}
|
|
||||||
|
|
||||||
session tx1
|
|
||||||
setup { BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
|
|
||||||
step s1 { SELECT; }
|
|
||||||
step create {
|
|
||||||
SELECT pgivm.create_immv('mv(x,y)', 'SELECT * FROM a a1, a a2 WHERE a1.i = a2.i');
|
|
||||||
CREATE FUNCTION check_mv() RETURNS text AS
|
|
||||||
$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
|
|
||||||
FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
|
|
||||||
(SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
|
|
||||||
}
|
|
||||||
step check1 {SELECT 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
|
|
||||||
|
|
@ -1,62 +0,0 @@
|
||||||
# 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);
|
|
||||||
SELECT pgivm.create_immv('mv(x,y,z)',
|
|
||||||
'SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i');
|
|
||||||
CREATE VIEW v(x,y,z) AS
|
|
||||||
SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
|
|
||||||
CREATE FUNCTION check_mv() RETURNS text AS
|
|
||||||
$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
|
|
||||||
FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
|
|
||||||
(SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
|
|
||||||
}
|
|
||||||
|
|
||||||
teardown
|
|
||||||
{
|
|
||||||
DROP FUNCTION check_mv();
|
|
||||||
DROP TABLE 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
|
|
||||||
|
|
@ -1,62 +0,0 @@
|
||||||
# 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);
|
|
||||||
SELECT pgivm.create_immv('mv(x,y,z)',
|
|
||||||
'SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i');
|
|
||||||
CREATE VIEW v(x,y,z) AS
|
|
||||||
SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
|
|
||||||
CREATE FUNCTION check_mv() RETURNS text AS
|
|
||||||
$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
|
|
||||||
FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
|
|
||||||
(SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
|
|
||||||
}
|
|
||||||
|
|
||||||
teardown
|
|
||||||
{
|
|
||||||
DROP FUNCTION check_mv();
|
|
||||||
DROP TABLE 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
|
|
||||||
|
|
@ -1,62 +0,0 @@
|
||||||
# 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);
|
|
||||||
SELECT pgivm.create_immv('mv(x,y,z)',
|
|
||||||
'SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i');
|
|
||||||
CREATE VIEW v(x,y,z) AS
|
|
||||||
SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
|
|
||||||
CREATE FUNCTION check_mv() RETURNS text AS
|
|
||||||
$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
|
|
||||||
FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
|
|
||||||
(SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
|
|
||||||
}
|
|
||||||
|
|
||||||
teardown
|
|
||||||
{
|
|
||||||
DROP FUNCTION check_mv();
|
|
||||||
DROP TABLE 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
|
|
||||||
|
|
@ -1,46 +0,0 @@
|
||||||
# Test interaction between concurrent transactions performing
|
|
||||||
# refresh_immv and insert in READ COMMITTED isolation level
|
|
||||||
|
|
||||||
setup
|
|
||||||
{
|
|
||||||
CREATE TABLE a (i int);
|
|
||||||
INSERT INTO a VALUES (1);
|
|
||||||
SELECT pgivm.create_immv('mv(x,y)', 'SELECT * FROM a a1, a a2 WHERE a1.i = a2.i');
|
|
||||||
CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
|
|
||||||
CREATE FUNCTION check_mv() RETURNS text AS
|
|
||||||
$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
|
|
||||||
FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
|
|
||||||
(SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
|
|
||||||
}
|
|
||||||
|
|
||||||
teardown
|
|
||||||
{
|
|
||||||
DROP FUNCTION check_mv();
|
|
||||||
DROP TABLE mv;
|
|
||||||
DROP VIEW v;
|
|
||||||
DROP TABLE a;
|
|
||||||
}
|
|
||||||
|
|
||||||
session tx1
|
|
||||||
setup { BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
|
|
||||||
step s1 { SELECT; }
|
|
||||||
step refresh { SELECT pgivm.refresh_immv('mv', true); }
|
|
||||||
step check1 {SELECT 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
|
|
||||||
|
|
@ -1,46 +0,0 @@
|
||||||
# Test interaction between concurrent transactions performing
|
|
||||||
# refresh_immv and insert in REPEATABLE READ isolation level
|
|
||||||
|
|
||||||
setup
|
|
||||||
{
|
|
||||||
CREATE TABLE a (i int);
|
|
||||||
INSERT INTO a VALUES (1);
|
|
||||||
SELECT pgivm.create_immv('mv(x,y)', 'SELECT * FROM a a1, a a2 WHERE a1.i = a2.i');
|
|
||||||
CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
|
|
||||||
CREATE FUNCTION check_mv() RETURNS text AS
|
|
||||||
$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
|
|
||||||
FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
|
|
||||||
(SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
|
|
||||||
}
|
|
||||||
|
|
||||||
teardown
|
|
||||||
{
|
|
||||||
DROP FUNCTION check_mv();
|
|
||||||
DROP TABLE mv;
|
|
||||||
DROP VIEW v;
|
|
||||||
DROP TABLE a;
|
|
||||||
}
|
|
||||||
|
|
||||||
session tx1
|
|
||||||
setup { BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
|
|
||||||
step s1 { SELECT; }
|
|
||||||
step refresh { SELECT pgivm.refresh_immv('mv', true); }
|
|
||||||
step check1 {SELECT 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
|
|
||||||
|
|
@ -1,46 +0,0 @@
|
||||||
# Test interaction between concurrent transactions performing
|
|
||||||
# refresh_immv and insert in SERIALIZABLE isolation level
|
|
||||||
|
|
||||||
setup
|
|
||||||
{
|
|
||||||
CREATE TABLE a (i int);
|
|
||||||
INSERT INTO a VALUES (1);
|
|
||||||
SELECT pgivm.create_immv('mv(x,y)', 'SELECT * FROM a a1, a a2 WHERE a1.i = a2.i');
|
|
||||||
CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
|
|
||||||
CREATE FUNCTION check_mv() RETURNS text AS
|
|
||||||
$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
|
|
||||||
FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
|
|
||||||
(SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
|
|
||||||
}
|
|
||||||
|
|
||||||
teardown
|
|
||||||
{
|
|
||||||
DROP FUNCTION check_mv();
|
|
||||||
DROP TABLE mv;
|
|
||||||
DROP VIEW v;
|
|
||||||
DROP TABLE a;
|
|
||||||
}
|
|
||||||
|
|
||||||
session tx1
|
|
||||||
setup { BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
|
|
||||||
step s1 { SELECT; }
|
|
||||||
step refresh { SELECT pgivm.refresh_immv('mv', true); }
|
|
||||||
step check1 {SELECT 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
|
|
||||||
|
|
@ -1,30 +1,30 @@
|
||||||
CREATE TABLE t (i int PRIMARY KEY);
|
CREATE TABLE t (i int PRIMARY KEY);
|
||||||
INSERT INTO t SELECT generate_series(1, 100);
|
INSERT INTO t SELECT generate_series(1, 100);
|
||||||
|
|
||||||
SELECT pgivm.create_immv('mv', 'SELECT * FROM t');
|
SELECT create_immv('mv', 'SELECT * FROM t');
|
||||||
SELECT pgivm.create_immv(' mv2 ( x ) ', 'SELECT * FROM t WHERE i%2 = 0');
|
SELECT create_immv(' mv2 ( x ) ', 'SELECT * FROM t WHERE i%2 = 0');
|
||||||
|
|
||||||
SELECT pgivm.create_immv('mv3', 'WITH d AS (DELETE FROM t RETURNING NULL) SELECT * FROM t');
|
SELECT create_immv('mv3', 'WITH d AS (DELETE FROM t RETURNING NULL) SELECT * FROM t');
|
||||||
|
|
||||||
SELECT immvrelid, pgivm.get_immv_def(immvrelid) FROM pgivm.pg_ivm_immv ORDER BY 1;
|
SELECT immvrelid, get_immv_def(immvrelid) FROM pg_ivm_immv ORDER BY 1;
|
||||||
|
|
||||||
-- contain immv
|
-- contain immv
|
||||||
SELECT pgivm.create_immv('mv_in_immv01', 'SELECT i FROM mv');
|
SELECT create_immv('mv_in_immv01', 'SELECT i FROM mv');
|
||||||
SELECT pgivm.create_immv('mv_in_immv02', 'SELECT t.i FROM t INNER JOIN mv2 ON t.i = mv2.x');
|
SELECT create_immv('mv_in_immv02', 'SELECT t.i FROM t INNER JOIN mv2 ON t.i = mv2.x');
|
||||||
|
|
||||||
-- SQL other than SELECT
|
-- SQL other than SELECT
|
||||||
SELECT pgivm.create_immv('mv_in_create', 'CREATE TABLE in_create(i int)');
|
SELECT create_immv('mv_in_create', 'CREATE TABLE in_create(i int)');
|
||||||
SELECT pgivm.create_immv('mv_in_insert', 'INSERT INTO t VALUES(10)');
|
SELECT create_immv('mv_in_insert', 'INSERT INTO t VALUES(10)');
|
||||||
SELECT pgivm.create_immv('mv_in_update', 'UPDATE t SET i = 10');
|
SELECT create_immv('mv_in_update', 'UPDATE t SET i = 10');
|
||||||
SELECT pgivm.create_immv('mv_in_delete', 'DELETE FROM t');
|
SELECT create_immv('mv_in_delete', 'DELETE FROM t');
|
||||||
SELECT pgivm.create_immv('mv_in_drop', 'DROP TABLE t');
|
SELECT create_immv('mv_in_drop', 'DROP TABLE t');
|
||||||
|
|
||||||
DROP TABLE t;
|
DROP TABLE t;
|
||||||
|
|
||||||
DROP TABLE mv;
|
DROP TABLE mv;
|
||||||
SELECT immvrelid, pgivm.get_immv_def(immvrelid) FROM pgivm.pg_ivm_immv ORDER BY 1;
|
SELECT immvrelid, get_immv_def(immvrelid) FROM pg_ivm_immv ORDER BY 1;
|
||||||
|
|
||||||
DROP TABLE mv2;
|
DROP TABLE mv2;
|
||||||
SELECT immvrelid, pgivm.get_immv_def(immvrelid) FROM pgivm.pg_ivm_immv ORDER BY 1;
|
SELECT immvrelid, get_immv_def(immvrelid) FROM pg_ivm_immv ORDER BY 1;
|
||||||
|
|
||||||
DROP TABLE t;
|
DROP TABLE t;
|
||||||
|
|
|
||||||
247
sql/pg_ivm.sql
247
sql/pg_ivm.sql
|
|
@ -2,28 +2,21 @@ CREATE EXTENSION pg_ivm;
|
||||||
GRANT ALL ON SCHEMA public TO public;
|
GRANT ALL ON SCHEMA public TO public;
|
||||||
|
|
||||||
-- create a table to use as a basis for views and materialized views in various combinations
|
-- create a table to use as a basis for views and materialized views in various combinations
|
||||||
CREATE TABLE mv_base_a (x int, i int, y int, j int);
|
CREATE TABLE mv_base_a (i int, j int);
|
||||||
CREATE TABLE mv_base_b (x int, i int, y int, k int);
|
|
||||||
|
|
||||||
-- test for base tables with dropped columns
|
|
||||||
ALTER TABLE mv_base_a DROP COLUMN x;
|
|
||||||
ALTER TABLE mv_base_a DROP COLUMN y;
|
|
||||||
ALTER TABLE mv_base_b DROP COLUMN x;
|
|
||||||
ALTER TABLE mv_base_b DROP COLUMN y;
|
|
||||||
|
|
||||||
INSERT INTO mv_base_a VALUES
|
INSERT INTO mv_base_a VALUES
|
||||||
(1,10),
|
(1,10),
|
||||||
(2,20),
|
(2,20),
|
||||||
(3,30),
|
(3,30),
|
||||||
(4,40),
|
(4,40),
|
||||||
(5,50);
|
(5,50);
|
||||||
|
CREATE TABLE mv_base_b (i int, k int);
|
||||||
INSERT INTO mv_base_b VALUES
|
INSERT INTO mv_base_b VALUES
|
||||||
(1,101),
|
(1,101),
|
||||||
(2,102),
|
(2,102),
|
||||||
(3,103),
|
(3,103),
|
||||||
(4,104);
|
(4,104);
|
||||||
|
|
||||||
SELECT pgivm.create_immv('mv_ivm_1', 'SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i)');
|
SELECT create_immv('mv_ivm_1', 'SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i)');
|
||||||
SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
|
SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
|
||||||
|
|
||||||
-- immediate maintenance
|
-- immediate maintenance
|
||||||
|
|
@ -37,14 +30,6 @@ SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
|
||||||
ROLLBACK;
|
ROLLBACK;
|
||||||
SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
|
SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
|
||||||
|
|
||||||
-- test for renaming column name to camel style
|
|
||||||
BEGIN;
|
|
||||||
ALTER TABLE mv_base_a RENAME i TO "I";
|
|
||||||
ALTER TABLE mv_base_a 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
|
-- TRUNCATE a base table in join views
|
||||||
BEGIN;
|
BEGIN;
|
||||||
TRUNCATE mv_base_a;
|
TRUNCATE mv_base_a;
|
||||||
|
|
@ -60,14 +45,14 @@ ROLLBACK;
|
||||||
BEGIN;
|
BEGIN;
|
||||||
CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
|
CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
|
||||||
AS 'SELECT 1' IMMUTABLE;
|
AS 'SELECT 1' IMMUTABLE;
|
||||||
SELECT pgivm.create_immv('mv_ivm_func', 'SELECT * FROM ivm_func()');
|
SELECT create_immv('mv_ivm_func', 'SELECT * FROM ivm_func()');
|
||||||
SELECT pgivm.create_immv('mv_ivm_no_tbl', 'SELECT 1');
|
SELECT create_immv('mv_ivm_no_tbl', 'SELECT 1');
|
||||||
ROLLBACK;
|
ROLLBACK;
|
||||||
|
|
||||||
-- result of materialized view have DISTINCT clause or the duplicate result.
|
-- result of materialized view have DISTINCT clause or the duplicate result.
|
||||||
BEGIN;
|
BEGIN;
|
||||||
SELECT pgivm.create_immv('mv_ivm_duplicate', 'SELECT j FROM mv_base_a');
|
SELECT create_immv('mv_ivm_duplicate', 'SELECT j FROM mv_base_a');
|
||||||
SELECT pgivm.create_immv('mv_ivm_distinct', 'SELECT DISTINCT j FROM mv_base_a');
|
SELECT create_immv('mv_ivm_distinct', 'SELECT DISTINCT j FROM mv_base_a');
|
||||||
INSERT INTO mv_base_a VALUES(6,20);
|
INSERT INTO mv_base_a VALUES(6,20);
|
||||||
SELECT * FROM mv_ivm_duplicate ORDER BY 1;
|
SELECT * FROM mv_ivm_duplicate ORDER BY 1;
|
||||||
SELECT * FROM mv_ivm_distinct ORDER BY 1;
|
SELECT * FROM mv_ivm_distinct ORDER BY 1;
|
||||||
|
|
@ -78,7 +63,7 @@ ROLLBACK;
|
||||||
|
|
||||||
-- support SUM(), COUNT() and AVG() aggregate functions
|
-- support SUM(), COUNT() and AVG() aggregate functions
|
||||||
BEGIN;
|
BEGIN;
|
||||||
SELECT pgivm.create_immv('mv_ivm_agg', 'SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i');
|
SELECT create_immv('mv_ivm_agg', '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;
|
SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
|
||||||
INSERT INTO mv_base_a VALUES(2,100);
|
INSERT INTO mv_base_a VALUES(2,100);
|
||||||
SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
|
SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
|
||||||
|
|
@ -90,7 +75,7 @@ ROLLBACK;
|
||||||
|
|
||||||
-- support COUNT(*) aggregate function
|
-- support COUNT(*) aggregate function
|
||||||
BEGIN;
|
BEGIN;
|
||||||
SELECT pgivm.create_immv('mv_ivm_agg', 'SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i');
|
SELECT create_immv('mv_ivm_agg', 'SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i');
|
||||||
SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
|
SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
|
||||||
INSERT INTO mv_base_a VALUES(2,100);
|
INSERT INTO mv_base_a VALUES(2,100);
|
||||||
SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
|
SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
|
||||||
|
|
@ -98,7 +83,7 @@ ROLLBACK;
|
||||||
|
|
||||||
-- TRUNCATE a base table in aggregate views
|
-- TRUNCATE a base table in aggregate views
|
||||||
BEGIN;
|
BEGIN;
|
||||||
SELECT pgivm.create_immv('mv_ivm_agg', 'SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i');
|
SELECT create_immv('mv_ivm_agg', 'SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i');
|
||||||
TRUNCATE mv_base_a;
|
TRUNCATE mv_base_a;
|
||||||
SELECT sum, count FROM mv_ivm_agg;
|
SELECT sum, count FROM mv_ivm_agg;
|
||||||
SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
|
SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
|
||||||
|
|
@ -106,7 +91,7 @@ ROLLBACK;
|
||||||
|
|
||||||
-- support aggregate functions without GROUP clause
|
-- support aggregate functions without GROUP clause
|
||||||
BEGIN;
|
BEGIN;
|
||||||
SELECT pgivm.create_immv('mv_ivm_group', 'SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a');
|
SELECT create_immv('mv_ivm_group', 'SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a');
|
||||||
SELECT * FROM mv_ivm_group ORDER BY 1;
|
SELECT * FROM mv_ivm_group ORDER BY 1;
|
||||||
INSERT INTO mv_base_a VALUES(6,60);
|
INSERT INTO mv_base_a VALUES(6,60);
|
||||||
SELECT * FROM mv_ivm_group ORDER BY 1;
|
SELECT * FROM mv_ivm_group ORDER BY 1;
|
||||||
|
|
@ -116,7 +101,7 @@ ROLLBACK;
|
||||||
|
|
||||||
-- TRUNCATE a base table in aggregate views without GROUP clause
|
-- TRUNCATE a base table in aggregate views without GROUP clause
|
||||||
BEGIN;
|
BEGIN;
|
||||||
SELECT pgivm.create_immv('mv_ivm_group', 'SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a');
|
SELECT create_immv('mv_ivm_group', 'SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a');
|
||||||
TRUNCATE mv_base_a;
|
TRUNCATE mv_base_a;
|
||||||
SELECT sum, count, avg FROM mv_ivm_group;
|
SELECT sum, count, avg FROM mv_ivm_group;
|
||||||
SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
|
SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
|
||||||
|
|
@ -124,7 +109,7 @@ ROLLBACK;
|
||||||
|
|
||||||
-- resolved issue: When use AVG() function and values is indivisible, result of AVG() is incorrect.
|
-- resolved issue: When use AVG() function and values is indivisible, result of AVG() is incorrect.
|
||||||
BEGIN;
|
BEGIN;
|
||||||
SELECT pgivm.create_immv('mv_ivm_avg_bug', 'SELECT i, SUM(j), COUNT(j), AVG(j) FROM mv_base_A GROUP BY i');
|
SELECT create_immv('mv_ivm_avg_bug', '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;
|
SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
|
||||||
INSERT INTO mv_base_a VALUES
|
INSERT INTO mv_base_a VALUES
|
||||||
(1,0),
|
(1,0),
|
||||||
|
|
@ -139,7 +124,7 @@ ROLLBACK;
|
||||||
|
|
||||||
-- support MIN(), MAX() aggregate functions
|
-- support MIN(), MAX() aggregate functions
|
||||||
BEGIN;
|
BEGIN;
|
||||||
SELECT pgivm.create_immv('mv_ivm_min_max(i, min_j, max_j)', 'SELECT i, MIN(j), MAX(j) FROM mv_base_a GROUP BY i');
|
SELECT create_immv('mv_ivm_min_max(i, min_j, max_j)', 'SELECT i, MIN(j), MAX(j) FROM mv_base_a GROUP BY i');
|
||||||
SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
|
SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
|
||||||
INSERT INTO mv_base_a VALUES
|
INSERT INTO mv_base_a VALUES
|
||||||
(1,11), (1,12),
|
(1,11), (1,12),
|
||||||
|
|
@ -154,7 +139,7 @@ ROLLBACK;
|
||||||
|
|
||||||
-- support MIN(), MAX() aggregate functions without GROUP clause
|
-- support MIN(), MAX() aggregate functions without GROUP clause
|
||||||
BEGIN;
|
BEGIN;
|
||||||
SELECT pgivm.create_immv('mv_ivm_min_max(min_j, max_j)', 'SELECT MIN(j), MAX(j) FROM mv_base_a');
|
SELECT create_immv('mv_ivm_min_max(min_j, max_j)', 'SELECT MIN(j), MAX(j) FROM mv_base_a');
|
||||||
SELECT * FROM mv_ivm_min_max;
|
SELECT * FROM mv_ivm_min_max;
|
||||||
INSERT INTO mv_base_a VALUES
|
INSERT INTO mv_base_a VALUES
|
||||||
(0,0), (6,60), (7,70);
|
(0,0), (6,60), (7,70);
|
||||||
|
|
@ -167,7 +152,7 @@ ROLLBACK;
|
||||||
|
|
||||||
-- Test MIN/MAX after search_path change
|
-- Test MIN/MAX after search_path change
|
||||||
BEGIN;
|
BEGIN;
|
||||||
SELECT pgivm.create_immv('mv_ivm_min', 'SELECT MIN(j) FROM mv_base_a');
|
SELECT create_immv('mv_ivm_min', 'SELECT MIN(j) FROM mv_base_a');
|
||||||
SELECT * FROM mv_ivm_min ORDER BY 1,2,3;
|
SELECT * FROM mv_ivm_min ORDER BY 1,2,3;
|
||||||
|
|
||||||
CREATE SCHEMA myschema;
|
CREATE SCHEMA myschema;
|
||||||
|
|
@ -185,28 +170,28 @@ ROLLBACK;
|
||||||
|
|
||||||
-- aggregate views with column names specified
|
-- aggregate views with column names specified
|
||||||
BEGIN;
|
BEGIN;
|
||||||
SELECT pgivm.create_immv('mv_ivm_agg(a)', 'SELECT i, SUM(j) FROM mv_base_a GROUP BY i');
|
SELECT create_immv('mv_ivm_agg(a)', 'SELECT i, SUM(j) FROM mv_base_a GROUP BY i');
|
||||||
INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
|
INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
|
||||||
UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
|
UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
|
||||||
DELETE FROM mv_base_a WHERE (i,j) = (3,30);
|
DELETE FROM mv_base_a WHERE (i,j) = (3,30);
|
||||||
SELECT * FROM mv_ivm_agg ORDER BY 1,2;
|
SELECT * FROM mv_ivm_agg ORDER BY 1,2;
|
||||||
ROLLBACK;
|
ROLLBACK;
|
||||||
BEGIN;
|
BEGIN;
|
||||||
SELECT pgivm.create_immv('mv_ivm_agg(a,b)', 'SELECT i, SUM(j) FROM mv_base_a GROUP BY i');
|
SELECT create_immv('mv_ivm_agg(a,b)', 'SELECT i, SUM(j) FROM mv_base_a GROUP BY i');
|
||||||
INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
|
INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
|
||||||
UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
|
UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
|
||||||
DELETE FROM mv_base_a WHERE (i,j) = (3,30);
|
DELETE FROM mv_base_a WHERE (i,j) = (3,30);
|
||||||
SELECT * FROM mv_ivm_agg ORDER BY 1,2;
|
SELECT * FROM mv_ivm_agg ORDER BY 1,2;
|
||||||
ROLLBACK;
|
ROLLBACK;
|
||||||
BEGIN;
|
BEGIN;
|
||||||
SELECT pgivm.create_immv('mv_ivm_agg(a,b,c)', 'SELECT i, SUM(j) FROM mv_base_a GROUP BY i');
|
SELECT create_immv('mv_ivm_agg(a,b,c)', 'SELECT i, SUM(j) FROM mv_base_a GROUP BY i');
|
||||||
ROLLBACK;
|
ROLLBACK;
|
||||||
|
|
||||||
-- support self join view and multiple change on the same table
|
-- support self join view and multiple change on the same table
|
||||||
BEGIN;
|
BEGIN;
|
||||||
CREATE TABLE base_t (i int, v int);
|
CREATE TABLE base_t (i int, v int);
|
||||||
INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
|
INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
|
||||||
SELECT pgivm.create_immv('mv_self(v1, v2)',
|
SELECT create_immv('mv_self(v1, v2)',
|
||||||
'SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i');
|
'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;
|
SELECT * FROM mv_self ORDER BY v1;
|
||||||
INSERT INTO base_t VALUES (4,40);
|
INSERT INTO base_t VALUES (4,40);
|
||||||
|
|
@ -236,7 +221,7 @@ CREATE TABLE base_r (i int, v int);
|
||||||
CREATE TABLE base_s (i int, v int);
|
CREATE TABLE base_s (i int, v int);
|
||||||
INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
|
INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
|
||||||
INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
|
INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
|
||||||
SELECT pgivm.create_immv('mv(v1, v2)', 'SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i)');;
|
SELECT create_immv('mv(v1, v2)', 'SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i)');;
|
||||||
SELECT * FROM mv ORDER BY v1;
|
SELECT * FROM mv ORDER BY v1;
|
||||||
WITH
|
WITH
|
||||||
ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
|
ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
|
||||||
|
|
@ -253,7 +238,7 @@ CREATE TABLE ri1 (i int PRIMARY KEY);
|
||||||
CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
|
CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
|
||||||
INSERT INTO ri1 VALUES (1),(2),(3);
|
INSERT INTO ri1 VALUES (1),(2),(3);
|
||||||
INSERT INTO ri2 VALUES (1),(2),(3);
|
INSERT INTO ri2 VALUES (1),(2),(3);
|
||||||
SELECT pgivm.create_immv('mv_ri(i1, i2)', 'SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i)');
|
SELECT create_immv('mv_ri(i1, i2)', 'SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i)');
|
||||||
SELECT * FROM mv_ri ORDER BY i1;
|
SELECT * FROM mv_ri ORDER BY i1;
|
||||||
UPDATE ri1 SET i=10 where i=1;
|
UPDATE ri1 SET i=10 where i=1;
|
||||||
DELETE FROM ri1 WHERE i=2;
|
DELETE FROM ri1 WHERE i=2;
|
||||||
|
|
@ -262,8 +247,8 @@ ROLLBACK;
|
||||||
|
|
||||||
-- support subquery for using EXISTS()
|
-- support subquery for using EXISTS()
|
||||||
BEGIN;
|
BEGIN;
|
||||||
SELECT pgivm.create_immv('mv_ivm_exists_subquery', 'SELECT a.i, a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i)');
|
SELECT create_immv('mv_ivm_exists_subquery', 'SELECT a.i, a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i)');
|
||||||
SELECT pgivm.create_immv('mv_ivm_exists_subquery2', 'SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) AND a.i > 2');
|
SELECT create_immv('mv_ivm_exists_subquery2', 'SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) AND a.i > 2');
|
||||||
SELECT * FROM mv_ivm_exists_subquery ORDER BY i, j;
|
SELECT * FROM mv_ivm_exists_subquery ORDER BY i, j;
|
||||||
SELECT * FROM mv_ivm_exists_subquery2 ORDER BY i, j;
|
SELECT * FROM mv_ivm_exists_subquery2 ORDER BY i, j;
|
||||||
INSERT INTO mv_base_a VALUES(1,10),(6,60),(3,30),(3,300);
|
INSERT INTO mv_base_a VALUES(1,10),(6,60),(3,30),(3,300);
|
||||||
|
|
@ -285,7 +270,7 @@ DELETE FROM mv_base_b WHERE i = 2;
|
||||||
SELECT * FROM mv_ivm_exists_subquery ORDER BY i, j;
|
SELECT * FROM mv_ivm_exists_subquery ORDER BY i, j;
|
||||||
SELECT * FROM mv_ivm_exists_subquery2 ORDER BY i, j;
|
SELECT * FROM mv_ivm_exists_subquery2 ORDER BY i, j;
|
||||||
--- EXISTS subquery with tuple duplication and DISTINCT
|
--- EXISTS subquery with tuple duplication and DISTINCT
|
||||||
SELECT pgivm.create_immv('mv_ivm_exists_subquery_distinct', 'SELECT DISTINCT a.i, a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i)');
|
SELECT create_immv('mv_ivm_exists_subquery_distinct', 'SELECT DISTINCT a.i, a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i)');
|
||||||
DELETE FROM mv_base_b WHERE i = 1 or i = 3;
|
DELETE FROM mv_base_b WHERE i = 1 or i = 3;
|
||||||
INSERT INTO mv_base_b VALUES (1,100), (3,300);
|
INSERT INTO mv_base_b VALUES (1,100), (3,300);
|
||||||
SELECT * FROM mv_ivm_exists_subquery ORDER BY i, j;
|
SELECT * FROM mv_ivm_exists_subquery ORDER BY i, j;
|
||||||
|
|
@ -294,31 +279,31 @@ ROLLBACK;
|
||||||
|
|
||||||
-- support simple subquery in FROM clause
|
-- support simple subquery in FROM clause
|
||||||
BEGIN;
|
BEGIN;
|
||||||
SELECT pgivm.create_immv('mv_ivm_subquery', 'SELECT a.i,a.j FROM mv_base_a a,( SELECT * FROM mv_base_b) b WHERE a.i = b.i');
|
SELECT create_immv('mv_ivm_subquery', 'SELECT a.i,a.j FROM mv_base_a a,( SELECT * FROM mv_base_b) b WHERE a.i = b.i');
|
||||||
INSERT INTO mv_base_a VALUES(2,20);
|
INSERT INTO mv_base_a VALUES(2,20);
|
||||||
INSERT INTO mv_base_b VALUES(3,300);
|
INSERT INTO mv_base_b VALUES(3,300);
|
||||||
SELECT * FROM mv_ivm_subquery ORDER BY i,j;
|
SELECT * FROM mv_ivm_subquery ORDER BY i,j;
|
||||||
ROLLBACK;
|
ROLLBACK;
|
||||||
|
|
||||||
-- disallow non-simple subqueries
|
-- disallow non-simple subqueries
|
||||||
SELECT pgivm.create_immv('mv_ivm_subquery', 'SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i');
|
SELECT create_immv('mv_ivm_subquery', 'SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i');
|
||||||
SELECT pgivm.create_immv('mv_ivm_subquery', 'SELECT a.i,a.j FROM mv_base_a a, (SELECT DISTINCT i FROM mv_base_b) b WHERE a.i = b.i');
|
SELECT create_immv('mv_ivm_subquery', 'SELECT a.i,a.j FROM mv_base_a a, (SELECT DISTINCT i FROM mv_base_b) b WHERE a.i = b.i');
|
||||||
SELECT pgivm.create_immv('mv_ivm_subquery', 'SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 )');
|
SELECT create_immv('mv_ivm_subquery', 'SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 )');
|
||||||
SELECT pgivm.create_immv('mv_ivm_subquery', 'SELECT i,j, (SELECT k FROM mv_base_b LIMIT 1) FROM mv_base_a a');
|
SELECT create_immv('mv_ivm_subquery', 'SELECT i,j, (SELECT k FROM mv_base_b LIMIT 1) FROM mv_base_a a');
|
||||||
SELECT pgivm.create_immv('mv_ivm_subquery', 'SELECT i,j, (SELECT k FROM mv_base_b LIMIT 1) + 1 FROM mv_base_a a');
|
SELECT create_immv('mv_ivm_subquery', 'SELECT i,j, (SELECT k FROM mv_base_b LIMIT 1) + 1 FROM mv_base_a a');
|
||||||
SELECT pgivm.create_immv('mv_ivm_subquery', 'SELECT * FROM generate_series(1, (SELECT k FROM mv_base_b LIMIT 1)) AS v');
|
SELECT create_immv('mv_ivm_subquery', 'SELECT * FROM generate_series(1, (SELECT k FROM mv_base_b LIMIT 1)) AS v');
|
||||||
SELECT pgivm.create_immv('mv_ivm_subquery', 'SELECT a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i)');
|
SELECT create_immv('mv_ivm_subquery', 'SELECT a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i)');
|
||||||
SELECT pgivm.create_immv('mv_ivm_subquery', 'SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 2');
|
SELECT create_immv('mv_ivm_subquery', 'SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 2');
|
||||||
SELECT pgivm.create_immv('mv_ivm_subquery', 'SELECT a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_a a2 WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a2.i = b.i))');
|
SELECT create_immv('mv_ivm_subquery', 'SELECT a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_a a2 WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a2.i = b.i))');
|
||||||
SELECT pgivm.create_immv('mv_ivm_subquery', 'SELECT EXISTS(SELECT 1 from mv_base_b) FROM mv_base_a a');
|
SELECT create_immv('mv_ivm_subquery', 'SELECT EXISTS(SELECT 1 from mv_base_b) FROM mv_base_a a');
|
||||||
SELECT pgivm.create_immv('mv_ivm_subquery', 'SELECT false OR EXISTS(SELECT 1 FROM mv_base_a) FROM mv_base_b');
|
SELECT create_immv('mv_ivm_subquery', 'SELECT false OR EXISTS(SELECT 1 FROM mv_base_a) FROM mv_base_b');
|
||||||
SELECT pgivm.create_immv('mv_ivm_subquery', 'SELECT * FROM generate_series(1, CASE EXISTS(SELECT 1 FROM mv_base_a) WHEN true THEN 100 ELSE 10 END), mv_base_b');
|
SELECT create_immv('mv_ivm_subquery', 'SELECT * FROM generate_series(1, CASE EXISTS(SELECT 1 FROM mv_base_a) WHEN true THEN 100 ELSE 10 END), mv_base_b');
|
||||||
SELECT pgivm.create_immv('mv_ivm_subquery', 'SELECT * FROM mv_base_a a WHERE CASE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) WHEN true THEN false ELSE true END');
|
SELECT create_immv('mv_ivm_subquery', 'SELECT * FROM mv_base_a a WHERE CASE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) WHEN true THEN false ELSE true END');
|
||||||
SELECT pgivm.create_immv('mv_ivm_subquery', 'SELECT * FROM mv_base_a a WHERE true and CASE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) WHEN true THEN false ELSE true END');
|
SELECT create_immv('mv_ivm_subquery', 'SELECT * FROM mv_base_a a WHERE true and CASE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) WHEN true THEN false ELSE true END');
|
||||||
|
|
||||||
-- support join subquery in FROM clause
|
-- support join subquery in FROM clause
|
||||||
BEGIN;
|
BEGIN;
|
||||||
SELECT pgivm.create_immv('mv_ivm_join_subquery', 'SELECT i, j, k FROM ( SELECT i, a.j, b.k FROM mv_base_b b INNER JOIN mv_base_a a USING(i)) tmp');
|
SELECT create_immv('mv_ivm_join_subquery', 'SELECT i, j, k FROM ( SELECT i, a.j, b.k FROM mv_base_b b INNER JOIN mv_base_a a USING(i)) tmp');
|
||||||
WITH
|
WITH
|
||||||
ai AS (INSERT INTO mv_base_a VALUES (1,11),(2,22) RETURNING 0),
|
ai AS (INSERT INTO mv_base_a VALUES (1,11),(2,22) RETURNING 0),
|
||||||
bi AS (INSERT INTO mv_base_b VALUES (1,111),(3,133) RETURNING 0),
|
bi AS (INSERT INTO mv_base_b VALUES (1,111),(3,133) RETURNING 0),
|
||||||
|
|
@ -329,7 +314,7 @@ ROLLBACK;
|
||||||
BEGIN;
|
BEGIN;
|
||||||
|
|
||||||
-- nested subquery
|
-- nested subquery
|
||||||
SELECT pgivm.create_immv('mv_ivm_join_subquery', 'SELECT i, j, k FROM ( SELECT i, a.j, b.k FROM mv_base_b b INNER JOIN (SELECT * FROM mv_base_a) a USING(i)) tmp');
|
SELECT create_immv('mv_ivm_join_subquery', 'SELECT i, j, k FROM ( SELECT i, a.j, b.k FROM mv_base_b b INNER JOIN (SELECT * FROM mv_base_a) a USING(i)) tmp');
|
||||||
WITH
|
WITH
|
||||||
ai AS (INSERT INTO mv_base_a VALUES (1,11),(2,22) RETURNING 0),
|
ai AS (INSERT INTO mv_base_a VALUES (1,11),(2,22) RETURNING 0),
|
||||||
bi AS (INSERT INTO mv_base_b VALUES (1,111),(3,133) RETURNING 0),
|
bi AS (INSERT INTO mv_base_b VALUES (1,111),(3,133) RETURNING 0),
|
||||||
|
|
@ -340,7 +325,7 @@ ROLLBACK;
|
||||||
|
|
||||||
-- support simple CTE
|
-- support simple CTE
|
||||||
BEGIN;
|
BEGIN;
|
||||||
SELECT pgivm.create_immv('mv_cte',
|
SELECT create_immv('mv_cte',
|
||||||
'WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i');
|
'WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i');
|
||||||
INSERT INTO mv_base_a VALUES(2,20);
|
INSERT INTO mv_base_a VALUES(2,20);
|
||||||
INSERT INTO mv_base_b VALUES(3,300);
|
INSERT INTO mv_base_b VALUES(3,300);
|
||||||
|
|
@ -348,7 +333,7 @@ SELECT * FROM mv_cte ORDER BY i,j;
|
||||||
ROLLBACK;
|
ROLLBACK;
|
||||||
|
|
||||||
BEGIN;
|
BEGIN;
|
||||||
SELECT pgivm.create_immv('mv_cte',
|
SELECT create_immv('mv_cte',
|
||||||
'WITH a AS (SELECT * FROM mv_base_a), b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM a, b WHERE a.i = b.i');
|
'WITH a AS (SELECT * FROM mv_base_a), b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM a, b WHERE a.i = b.i');
|
||||||
INSERT INTO mv_base_a VALUES(2,20);
|
INSERT INTO mv_base_a VALUES(2,20);
|
||||||
INSERT INTO mv_base_b VALUES(3,300);
|
INSERT INTO mv_base_b VALUES(3,300);
|
||||||
|
|
@ -356,7 +341,7 @@ SELECT * FROM mv_cte ORDER BY i,j;
|
||||||
ROLLBACK;
|
ROLLBACK;
|
||||||
|
|
||||||
BEGIN;
|
BEGIN;
|
||||||
SELECT pgivm.create_immv('mv_cte',
|
SELECT create_immv('mv_cte',
|
||||||
'WITH b AS ( SELECT * FROM mv_base_b) SELECT v.i,v.j FROM (WITH a AS (SELECT * FROM mv_base_a) SELECT a.i,a.j FROM a, b WHERE a.i = b.i) v');
|
'WITH b AS ( SELECT * FROM mv_base_b) SELECT v.i,v.j FROM (WITH a AS (SELECT * FROM mv_base_a) SELECT a.i,a.j FROM a, b WHERE a.i = b.i) v');
|
||||||
INSERT INTO mv_base_a VALUES(2,20);
|
INSERT INTO mv_base_a VALUES(2,20);
|
||||||
INSERT INTO mv_base_b VALUES(3,300);
|
INSERT INTO mv_base_b VALUES(3,300);
|
||||||
|
|
@ -364,7 +349,7 @@ SELECT * FROM mv_cte ORDER BY i,j;
|
||||||
ROLLBACK;
|
ROLLBACK;
|
||||||
|
|
||||||
BEGIN;
|
BEGIN;
|
||||||
SELECT pgivm.create_immv('mv_cte',
|
SELECT create_immv('mv_cte',
|
||||||
'SELECT * FROM (WITH a AS (SELECT * FROM mv_base_a), b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM a, b WHERE a.i = b.i) v');
|
'SELECT * FROM (WITH a AS (SELECT * FROM mv_base_a), b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM a, b WHERE a.i = b.i) v');
|
||||||
INSERT INTO mv_base_a VALUES(2,20);
|
INSERT INTO mv_base_a VALUES(2,20);
|
||||||
INSERT INTO mv_base_b VALUES(3,300);
|
INSERT INTO mv_base_b VALUES(3,300);
|
||||||
|
|
@ -372,7 +357,7 @@ SELECT * FROM mv_cte ORDER BY i,j;
|
||||||
ROLLBACK;
|
ROLLBACK;
|
||||||
|
|
||||||
BEGIN;
|
BEGIN;
|
||||||
SELECT pgivm.create_immv('mv_cte',
|
SELECT create_immv('mv_cte',
|
||||||
'WITH b AS ( SELECT * FROM (SELECT * FROM mv_base_b) b2) SELECT v.i,v.j FROM (WITH a AS (SELECT * FROM mv_base_a) SELECT a.i,a.j FROM a, b WHERE a.i = b.i) v');
|
'WITH b AS ( SELECT * FROM (SELECT * FROM mv_base_b) b2) SELECT v.i,v.j FROM (WITH a AS (SELECT * FROM mv_base_a) SELECT a.i,a.j FROM a, b WHERE a.i = b.i) v');
|
||||||
INSERT INTO mv_base_a VALUES(2,20);
|
INSERT INTO mv_base_a VALUES(2,20);
|
||||||
INSERT INTO mv_base_b VALUES(3,300);
|
INSERT INTO mv_base_b VALUES(3,300);
|
||||||
|
|
@ -380,7 +365,7 @@ SELECT * FROM mv_cte ORDER BY i,j;
|
||||||
ROLLBACK;
|
ROLLBACK;
|
||||||
|
|
||||||
BEGIN;
|
BEGIN;
|
||||||
SELECT pgivm.create_immv('mv_cte',
|
SELECT create_immv('mv_cte',
|
||||||
'WITH x AS ( SELECT i, a.j, b.k FROM mv_base_b b INNER JOIN mv_base_a a USING(i)) SELECT * FROM x');
|
'WITH x AS ( SELECT i, a.j, b.k FROM mv_base_b b INNER JOIN mv_base_a a USING(i)) SELECT * FROM x');
|
||||||
WITH
|
WITH
|
||||||
ai AS (INSERT INTO mv_base_a VALUES (1,11),(2,22) RETURNING 0),
|
ai AS (INSERT INTO mv_base_a VALUES (1,11),(2,22) RETURNING 0),
|
||||||
|
|
@ -392,7 +377,7 @@ ROLLBACK;
|
||||||
|
|
||||||
-- nested CTE
|
-- nested CTE
|
||||||
BEGIN;
|
BEGIN;
|
||||||
SELECT pgivm.create_immv('mv_ivm_nested_cte', 'WITH v AS ( WITH a AS (SELECT * FROM mv_base_a) SELECT i, a.j, b.k FROM mv_base_b b INNER JOIN a USING(i)) SELECT * FROM v');
|
SELECT create_immv('mv_ivm_nested_cte', 'WITH v AS ( WITH a AS (SELECT * FROM mv_base_a) SELECT i, a.j, b.k FROM mv_base_b b INNER JOIN a USING(i)) SELECT * FROM v');
|
||||||
WITH
|
WITH
|
||||||
ai AS (INSERT INTO mv_base_a VALUES (1,11),(2,22) RETURNING 0),
|
ai AS (INSERT INTO mv_base_a VALUES (1,11),(2,22) RETURNING 0),
|
||||||
bi AS (INSERT INTO mv_base_b VALUES (1,111),(3,133) RETURNING 0),
|
bi AS (INSERT INTO mv_base_b VALUES (1,111),(3,133) RETURNING 0),
|
||||||
|
|
@ -405,7 +390,7 @@ ROLLBACK;
|
||||||
BEGIN;
|
BEGIN;
|
||||||
CREATE TABLE base_t (i int, v int);
|
CREATE TABLE base_t (i int, v int);
|
||||||
INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
|
INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
|
||||||
SELECT pgivm.create_immv('mv_cte_multi(v1, v2)',
|
SELECT create_immv('mv_cte_multi(v1, v2)',
|
||||||
'WITH t AS (SELECT * FROM base_t) SELECT t1.v, t2.v FROM t AS t1 JOIN t AS t2 ON t1.i = t2.i');
|
'WITH t AS (SELECT * FROM base_t) SELECT t1.v, t2.v FROM t AS t1 JOIN t AS t2 ON t1.i = t2.i');
|
||||||
SELECT * FROM mv_cte_multi ORDER BY v1;
|
SELECT * FROM mv_cte_multi ORDER BY v1;
|
||||||
INSERT INTO base_t VALUES (4,40);
|
INSERT INTO base_t VALUES (4,40);
|
||||||
|
|
@ -422,18 +407,18 @@ SELECT * FROM mv_cte_multi ORDER BY v1;
|
||||||
ROLLBACK;
|
ROLLBACK;
|
||||||
|
|
||||||
--- disallow not-simple CTE
|
--- disallow not-simple CTE
|
||||||
SELECT pgivm.create_immv('mv_cte_fail', 'WITH b AS (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i');
|
SELECT create_immv('mv_cte_fail', 'WITH b AS (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i');
|
||||||
SELECT pgivm.create_immv('mv_cte_fail', 'WITH b AS (SELECT DISTINCT i FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i');
|
SELECT create_immv('mv_cte_fail', 'WITH b AS (SELECT DISTINCT i FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i');
|
||||||
SELECT pgivm.create_immv('mv_cte_fail', 'WITH a AS (SELECT i, j FROM mv_base_a) SELECT a.i,a.j FROM a WHERE EXISTS(WITH b AS (SELECT i FROM mv_base_b) SELECT 1 FROM b WHERE a.i = b.i)');
|
SELECT create_immv('mv_cte_fail', 'WITH a AS (SELECT i, j FROM mv_base_a) SELECT a.i,a.j FROM a WHERE EXISTS(WITH b AS (SELECT i FROM mv_base_b) SELECT 1 FROM b WHERE a.i = b.i)');
|
||||||
|
|
||||||
-- unreferenced CTE
|
-- unreferenced CTE
|
||||||
SELECT pgivm.create_immv('mv_cte_fail', 'WITH b AS (SELECT * FROM mv_base_b) SELECT * FROM mv_base_a a');
|
SELECT create_immv('mv_cte_fail', 'WITH b AS (SELECT * FROM mv_base_b) SELECT * FROM mv_base_a a');
|
||||||
|
|
||||||
-- views including NULL
|
-- views including NULL
|
||||||
BEGIN;
|
BEGIN;
|
||||||
CREATE TABLE base_t (i int, v int);
|
CREATE TABLE base_t (i int, v int);
|
||||||
INSERT INTO base_t VALUES (1,10),(2, NULL);
|
INSERT INTO base_t VALUES (1,10),(2, NULL);
|
||||||
SELECT pgivm.create_immv('mv', 'SELECT * FROM base_t');
|
SELECT create_immv('mv', 'SELECT * FROM base_t');
|
||||||
SELECT * FROM mv ORDER BY i;
|
SELECT * FROM mv ORDER BY i;
|
||||||
UPDATE base_t SET v = 20 WHERE i = 2;
|
UPDATE base_t SET v = 20 WHERE i = 2;
|
||||||
SELECT * FROM mv ORDER BY i;
|
SELECT * FROM mv ORDER BY i;
|
||||||
|
|
@ -441,7 +426,7 @@ ROLLBACK;
|
||||||
|
|
||||||
BEGIN;
|
BEGIN;
|
||||||
CREATE TABLE base_t (i int);
|
CREATE TABLE base_t (i int);
|
||||||
SELECT pgivm.create_immv('mv', 'SELECT * FROM base_t');
|
SELECT create_immv('mv', 'SELECT * FROM base_t');
|
||||||
SELECT * FROM mv ORDER BY i;
|
SELECT * FROM mv ORDER BY i;
|
||||||
INSERT INTO base_t VALUES (1),(NULL);
|
INSERT INTO base_t VALUES (1),(NULL);
|
||||||
SELECT * FROM mv ORDER BY i;
|
SELECT * FROM mv ORDER BY i;
|
||||||
|
|
@ -450,7 +435,7 @@ ROLLBACK;
|
||||||
BEGIN;
|
BEGIN;
|
||||||
CREATE TABLE base_t (i int, v int);
|
CREATE TABLE base_t (i int, v int);
|
||||||
INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (1, 10), (1, 20);
|
INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (1, 10), (1, 20);
|
||||||
SELECT pgivm.create_immv('mv', 'SELECT i, sum(v) FROM base_t GROUP BY i');
|
SELECT create_immv('mv', 'SELECT i, sum(v) FROM base_t GROUP BY i');
|
||||||
SELECT * FROM mv ORDER BY i;
|
SELECT * FROM mv ORDER BY i;
|
||||||
UPDATE base_t SET v = v * 10;
|
UPDATE base_t SET v = v * 10;
|
||||||
SELECT * FROM mv ORDER BY i;
|
SELECT * FROM mv ORDER BY i;
|
||||||
|
|
@ -459,7 +444,7 @@ ROLLBACK;
|
||||||
BEGIN;
|
BEGIN;
|
||||||
CREATE TABLE base_t (i int, v int);
|
CREATE TABLE base_t (i int, v int);
|
||||||
INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (NULL, 3), (NULL, 4), (NULL, 5);
|
INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (NULL, 3), (NULL, 4), (NULL, 5);
|
||||||
SELECT pgivm.create_immv('mv', 'SELECT i, min(v), max(v) FROM base_t GROUP BY i');
|
SELECT create_immv('mv', 'SELECT i, min(v), max(v) FROM base_t GROUP BY i');
|
||||||
SELECT * FROM mv ORDER BY i;
|
SELECT * FROM mv ORDER BY i;
|
||||||
DELETE FROM base_t WHERE v = 1;
|
DELETE FROM base_t WHERE v = 1;
|
||||||
SELECT * FROM mv ORDER BY i;
|
SELECT * FROM mv ORDER BY i;
|
||||||
|
|
@ -509,7 +494,7 @@ CREATE OPERATOR CLASS mytype_ops
|
||||||
FUNCTION 1 mytype_cmp(mytype,mytype);
|
FUNCTION 1 mytype_cmp(mytype,mytype);
|
||||||
|
|
||||||
CREATE TABLE t_mytype (x mytype);
|
CREATE TABLE t_mytype (x mytype);
|
||||||
SELECT pgivm.create_immv('mv_mytype',
|
SELECT create_immv('mv_mytype',
|
||||||
'SELECT * FROM t_mytype');
|
'SELECT * FROM t_mytype');
|
||||||
INSERT INTO t_mytype VALUES ('1'::mytype);
|
INSERT INTO t_mytype VALUES ('1'::mytype);
|
||||||
SELECT * FROM mv_mytype;
|
SELECT * FROM mv_mytype;
|
||||||
|
|
@ -517,95 +502,95 @@ SELECT * FROM mv_mytype;
|
||||||
ROLLBACK;
|
ROLLBACK;
|
||||||
|
|
||||||
-- outer join is not supported
|
-- outer join is not supported
|
||||||
SELECT pgivm.create_immv('mv(a,b)',
|
SELECT create_immv('mv(a,b)',
|
||||||
'SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i');
|
'SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i');
|
||||||
|
|
||||||
-- contain system column
|
-- contain system column
|
||||||
SELECT pgivm.create_immv('mv_ivm01', 'SELECT i,j,xmin FROM mv_base_a');
|
SELECT create_immv('mv_ivm01', 'SELECT i,j,xmin FROM mv_base_a');
|
||||||
SELECT pgivm.create_immv('mv_ivm02', 'SELECT i,j FROM mv_base_a WHERE xmin = ''610''');
|
SELECT create_immv('mv_ivm02', 'SELECT i,j FROM mv_base_a WHERE xmin = ''610''');
|
||||||
SELECT pgivm.create_immv('mv_ivm03', 'SELECT i,j,xmin::text AS x_min FROM mv_base_a');
|
SELECT create_immv('mv_ivm03', 'SELECT i,j,xmin::text AS x_min FROM mv_base_a');
|
||||||
SELECT pgivm.create_immv('mv_ivm04', 'SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a');
|
SELECT create_immv('mv_ivm04', 'SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a');
|
||||||
|
|
||||||
-- contain ORDER BY
|
-- contain ORDER BY
|
||||||
SELECT pgivm.create_immv('mv_ivm07', 'SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k');
|
SELECT create_immv('mv_ivm07', 'SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k');
|
||||||
-- contain HAVING
|
-- contain HAVING
|
||||||
SELECT pgivm.create_immv('mv_ivm08', 'SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5');
|
SELECT create_immv('mv_ivm08', 'SELECT i,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 GROUP BY without aggregate
|
-- contain GROUP BY without aggregate
|
||||||
SELECT pgivm.create_immv('mv_ivm08', 'SELECT i,j FROM mv_base_a GROUP BY i,j');
|
SELECT create_immv('mv_ivm08', 'SELECT i,j FROM mv_base_a GROUP BY i,j');
|
||||||
|
|
||||||
-- contain view or materialized view
|
-- contain view or materialized view
|
||||||
CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
|
CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
|
||||||
CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
|
CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
|
||||||
SELECT pgivm.create_immv('mv_ivm07', 'SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i');
|
SELECT create_immv('mv_ivm07', 'SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i');
|
||||||
SELECT pgivm.create_immv('mv_ivm08', 'SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i');
|
SELECT create_immv('mv_ivm08', 'SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i');
|
||||||
|
|
||||||
-- contain mutable functions
|
-- contain mutable functions
|
||||||
SELECT pgivm.create_immv('mv_ivm12', 'SELECT i,j FROM mv_base_a WHERE i = random()::int');
|
SELECT create_immv('mv_ivm12', 'SELECT i,j FROM mv_base_a WHERE i = random()::int');
|
||||||
|
|
||||||
-- LIMIT/OFFSET is not supported
|
-- LIMIT/OFFSET is not supported
|
||||||
SELECT pgivm.create_immv('mv_ivm13', 'SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5');
|
SELECT create_immv('mv_ivm13', 'SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5');
|
||||||
|
|
||||||
-- DISTINCT ON is not supported
|
-- DISTINCT ON is not supported
|
||||||
SELECT pgivm.create_immv('mv_ivm14', 'SELECT DISTINCT ON(i) i, j FROM mv_base_a');
|
SELECT create_immv('mv_ivm14', 'SELECT DISTINCT ON(i) i, j FROM mv_base_a');
|
||||||
|
|
||||||
-- TABLESAMPLE clause is not supported
|
-- TABLESAMPLE clause is not supported
|
||||||
SELECT pgivm.create_immv('mv_ivm15', 'SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50)');
|
SELECT create_immv('mv_ivm15', 'SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50)');
|
||||||
|
|
||||||
-- window functions are not supported
|
-- window functions are not supported
|
||||||
SELECT pgivm.create_immv('mv_ivm16', 'SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a');
|
SELECT create_immv('mv_ivm16', 'SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a');
|
||||||
|
|
||||||
-- aggregate function with some options is not supported
|
-- aggregate function with some options is not supported
|
||||||
SELECT pgivm.create_immv('mv_ivm17', 'SELECT COUNT(*) FILTER(WHERE i < 3) FROM mv_base_a');
|
SELECT create_immv('mv_ivm17', 'SELECT COUNT(*) FILTER(WHERE i < 3) FROM mv_base_a');
|
||||||
SELECT pgivm.create_immv('mv_ivm18', 'SELECT COUNT(DISTINCT i) FROM mv_base_a');
|
SELECT create_immv('mv_ivm18', 'SELECT COUNT(DISTINCT i) FROM mv_base_a');
|
||||||
SELECT pgivm.create_immv('mv_ivm19', 'SELECT array_agg(j ORDER BY i DESC) FROM mv_base_a');
|
SELECT create_immv('mv_ivm19', 'SELECT array_agg(j ORDER BY i DESC) FROM mv_base_a');
|
||||||
SELECT pgivm.create_immv('mv_ivm20', 'SELECT i,SUM(j) FROM mv_base_a GROUP BY GROUPING SETS((i),())');
|
SELECT create_immv('mv_ivm20', 'SELECT i,SUM(j) FROM mv_base_a GROUP BY GROUPING SETS((i),())');
|
||||||
|
|
||||||
-- inheritance parent is not supported
|
-- inheritance parent is not supported
|
||||||
BEGIN;
|
BEGIN;
|
||||||
CREATE TABLE parent (i int, v int);
|
CREATE TABLE parent (i int, v int);
|
||||||
CREATE TABLE child_a(options text) INHERITS(parent);
|
CREATE TABLE child_a(options text) INHERITS(parent);
|
||||||
SELECT pgivm.create_immv('mv_ivm21', 'SELECT * FROM parent');
|
SELECT create_immv('mv_ivm21', 'SELECT * FROM parent');
|
||||||
ROLLBACK;
|
ROLLBACK;
|
||||||
|
|
||||||
-- UNION statement is not supported
|
-- UNION statement is not supported
|
||||||
SELECT pgivm.create_immv('mv_ivm22', 'SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b');
|
SELECT create_immv('mv_ivm22', 'SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b');
|
||||||
|
|
||||||
-- DISTINCT clause in nested query are not supported
|
-- DISTINCT clause in nested query are not supported
|
||||||
SELECT pgivm.create_immv('mv_ivm23', 'SELECT * FROM (SELECT DISTINCT i,j FROM mv_base_a) AS tmp');;
|
SELECT create_immv('mv_ivm23', 'SELECT * FROM (SELECT DISTINCT i,j FROM mv_base_a) AS tmp');;
|
||||||
|
|
||||||
-- empty target list is not allowed with IVM
|
-- empty target list is not allowed with IVM
|
||||||
SELECT pgivm.create_immv('mv_ivm25', 'SELECT FROM mv_base_a');
|
SELECT create_immv('mv_ivm25', 'SELECT FROM mv_base_a');
|
||||||
|
|
||||||
-- FOR UPDATE/SHARE is not supported
|
-- FOR UPDATE/SHARE is not supported
|
||||||
SELECT pgivm.create_immv('mv_ivm26', 'SELECT i,j FROM mv_base_a FOR UPDATE');
|
SELECT create_immv('mv_ivm26', 'SELECT i,j FROM mv_base_a FOR UPDATE');
|
||||||
SELECT pgivm.create_immv('mv_ivm27', 'SELECT * FROM (SELECT i,j FROM mv_base_a FOR UPDATE) AS tmp;');
|
SELECT create_immv('mv_ivm27', 'SELECT * FROM (SELECT i,j FROM mv_base_a FOR UPDATE) AS tmp;');
|
||||||
|
|
||||||
-- tartget list cannot contain ivm column that start with '__ivm'
|
-- tartget list cannot contain ivm column that start with '__ivm'
|
||||||
SELECT pgivm.create_immv('mv_ivm28', 'SELECT i AS "__ivm_count__" FROM mv_base_a');
|
SELECT create_immv('mv_ivm28', 'SELECT i AS "__ivm_count__" FROM mv_base_a');
|
||||||
|
|
||||||
-- expressions specified in GROUP BY must appear in the target list.
|
-- expressions specified in GROUP BY must appear in the target list.
|
||||||
SELECT pgivm.create_immv('mv_ivm29', 'SELECT COUNT(i) FROM mv_base_a GROUP BY i;');
|
SELECT create_immv('mv_ivm29', 'SELECT COUNT(i) FROM mv_base_a GROUP BY i;');
|
||||||
|
|
||||||
-- experssions containing an aggregate is not supported
|
-- experssions containing an aggregate is not supported
|
||||||
SELECT pgivm.create_immv('mv_ivm30', 'SELECT sum(i)*0.5 FROM mv_base_a');
|
SELECT create_immv('mv_ivm30', 'SELECT sum(i)*0.5 FROM mv_base_a');
|
||||||
SELECT pgivm.create_immv('mv_ivm31', 'SELECT sum(i)/sum(j) FROM mv_base_a');
|
SELECT create_immv('mv_ivm31', 'SELECT sum(i)/sum(j) FROM mv_base_a');
|
||||||
|
|
||||||
-- VALUES is not supported
|
-- VALUES is not supported
|
||||||
SELECT pgivm.create_immv('mv_ivm_only_values1', 'values(1)');
|
SELECT create_immv('mv_ivm_only_values1', 'values(1)');
|
||||||
SELECT pgivm.create_immv('mv_ivm_only_values2', 'SELECT * FROM (values(1)) AS tmp');
|
SELECT create_immv('mv_ivm_only_values2', 'SELECT * FROM (values(1)) AS tmp');
|
||||||
|
|
||||||
|
|
||||||
-- views containing base tables with Row Level Security
|
-- views containing base tables with Row Level Security
|
||||||
DROP USER IF EXISTS regress_ivm_admin;
|
DROP USER IF EXISTS ivm_admin;
|
||||||
DROP USER IF EXISTS regress_ivm_user;
|
DROP USER IF EXISTS ivm_user;
|
||||||
CREATE USER regress_ivm_admin;
|
CREATE USER ivm_admin;
|
||||||
CREATE USER regress_ivm_user;
|
CREATE USER ivm_user;
|
||||||
|
|
||||||
--- create a table with RLS
|
--- create a table with RLS
|
||||||
SET SESSION AUTHORIZATION regress_ivm_admin;
|
SET SESSION AUTHORIZATION ivm_admin;
|
||||||
CREATE TABLE rls_tbl(id int, data text, owner name);
|
CREATE TABLE rls_tbl(id int, data text, owner name);
|
||||||
INSERT INTO rls_tbl VALUES
|
INSERT INTO rls_tbl VALUES
|
||||||
(1,'foo','regress_ivm_user'),
|
(1,'foo','ivm_user'),
|
||||||
(2,'bar','postgres');
|
(2,'bar','postgres');
|
||||||
CREATE TABLE num_tbl(id int, num text);
|
CREATE TABLE num_tbl(id int, num text);
|
||||||
INSERT INTO num_tbl VALUES
|
INSERT INTO num_tbl VALUES
|
||||||
|
|
@ -622,29 +607,29 @@ ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
|
||||||
GRANT ALL on rls_tbl TO PUBLIC;
|
GRANT ALL on rls_tbl TO PUBLIC;
|
||||||
GRANT ALL on num_tbl TO PUBLIC;
|
GRANT ALL on num_tbl TO PUBLIC;
|
||||||
|
|
||||||
--- create a view owned by regress_ivm_user
|
--- create a view owned by ivm_user
|
||||||
SET SESSION AUTHORIZATION regress_ivm_user;
|
SET SESSION AUTHORIZATION ivm_user;
|
||||||
SELECT pgivm.create_immv('ivm_rls', 'SELECT * FROM rls_tbl');
|
SELECT create_immv('ivm_rls', 'SELECT * FROM rls_tbl');
|
||||||
SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
|
SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
|
||||||
RESET SESSION AUTHORIZATION;
|
RESET SESSION AUTHORIZATION;
|
||||||
|
|
||||||
--- inserts rows owned by different users
|
--- inserts rows owned by different users
|
||||||
INSERT INTO rls_tbl VALUES
|
INSERT INTO rls_tbl VALUES
|
||||||
(3,'baz','regress_ivm_user'),
|
(3,'baz','ivm_user'),
|
||||||
(4,'qux','postgres');
|
(4,'qux','postgres');
|
||||||
SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
|
SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
|
||||||
|
|
||||||
--- combination of diffent kinds of commands
|
--- combination of diffent kinds of commands
|
||||||
WITH
|
WITH
|
||||||
i AS (INSERT INTO rls_tbl VALUES(5,'quux','postgres'), (6,'corge','regress_ivm_user')),
|
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),
|
u AS (UPDATE rls_tbl SET owner = 'postgres' WHERE id = 1),
|
||||||
u2 AS (UPDATE rls_tbl SET owner = 'regress_ivm_user' WHERE id = 2)
|
u2 AS (UPDATE rls_tbl SET owner = 'ivm_user' WHERE id = 2)
|
||||||
SELECT;
|
SELECT;
|
||||||
SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
|
SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
|
||||||
|
|
||||||
---
|
---
|
||||||
SET SESSION AUTHORIZATION regress_ivm_user;
|
SET SESSION AUTHORIZATION ivm_user;
|
||||||
SELECT pgivm.create_immv('ivm_rls2', 'SELECT * FROM rls_tbl JOIN num_tbl USING(id)');
|
SELECT create_immv('ivm_rls2', 'SELECT * FROM rls_tbl JOIN num_tbl USING(id)');
|
||||||
RESET SESSION AUTHORIZATION;
|
RESET SESSION AUTHORIZATION;
|
||||||
|
|
||||||
WITH
|
WITH
|
||||||
|
|
@ -656,8 +641,8 @@ SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
|
||||||
DROP TABLE rls_tbl CASCADE;
|
DROP TABLE rls_tbl CASCADE;
|
||||||
DROP TABLE num_tbl CASCADE;
|
DROP TABLE num_tbl CASCADE;
|
||||||
|
|
||||||
DROP USER regress_ivm_user;
|
DROP USER ivm_user;
|
||||||
DROP USER regress_ivm_admin;
|
DROP USER ivm_admin;
|
||||||
|
|
||||||
-- automatic index creation
|
-- automatic index creation
|
||||||
BEGIN;
|
BEGIN;
|
||||||
|
|
@ -665,30 +650,30 @@ CREATE TABLE base_a (i int primary key, j int);
|
||||||
CREATE TABLE base_b (i int primary key, j int);
|
CREATE TABLE base_b (i int primary key, j int);
|
||||||
|
|
||||||
--- group by: create an index
|
--- group by: create an index
|
||||||
SELECT pgivm.create_immv('mv_idx1', 'SELECT i, sum(j) FROM base_a GROUP BY i');
|
SELECT create_immv('mv_idx1', 'SELECT i, sum(j) FROM base_a GROUP BY i');
|
||||||
|
|
||||||
--- distinct: create an index
|
--- distinct: create an index
|
||||||
SELECT pgivm.create_immv('mv_idx2', 'SELECT DISTINCT j FROM base_a');
|
SELECT create_immv('mv_idx2', 'SELECT DISTINCT j FROM base_a');
|
||||||
|
|
||||||
--- with all pkey columns: create an index
|
--- with all pkey columns: create an index
|
||||||
SELECT pgivm.create_immv('mv_idx3(i_a, i_b)', 'SELECT a.i, b.i FROM base_a a, base_b b');
|
SELECT create_immv('mv_idx3(i_a, i_b)', 'SELECT a.i, b.i FROM base_a a, base_b b');
|
||||||
|
|
||||||
--- missing some pkey columns: no index
|
--- missing some pkey columns: no index
|
||||||
SELECT pgivm.create_immv('mv_idx4', 'SELECT j FROM base_a');
|
SELECT create_immv('mv_idx4', 'SELECT j FROM base_a');
|
||||||
SELECT pgivm.create_immv('mv_idx5', 'SELECT a.i, b.j FROM base_a a, base_b b');
|
SELECT create_immv('mv_idx5', 'SELECT a.i, b.j FROM base_a a, base_b b');
|
||||||
|
|
||||||
--- subqueries: create an index
|
--- subqueries: create an index
|
||||||
SELECT pgivm.create_immv('mv_idx6(i_a, i_b)', 'SELECT a.i, b.i FROM (SELECT * FROM base_a) a, (SELECT * FROM base_b) b');
|
SELECT create_immv('mv_idx6(i_a, i_b)', 'SELECT a.i, b.i FROM (SELECT * FROM base_a) a, (SELECT * FROM base_b) b');
|
||||||
|
|
||||||
--- with set-returning function: no index
|
--- with set-returning function: no index
|
||||||
SELECT pgivm.create_immv('mv_idx7', 'SELECT i FROM base_a, generate_series(1,10)');
|
SELECT create_immv('mv_idx7', 'SELECT i FROM base_a, generate_series(1,10)');
|
||||||
|
|
||||||
ROLLBACK;
|
ROLLBACK;
|
||||||
|
|
||||||
-- type that doesn't have default operator class for access method btree
|
-- type that doesn't have default operator class for access method btree
|
||||||
BEGIN;
|
BEGIN;
|
||||||
CREATE TABLE table_json (j json);
|
CREATE TABLE table_json (j json);
|
||||||
SELECT pgivm.create_immv('mv_json', 'SELECT * from table_json');
|
SELECT create_immv('mv_json', 'SELECT * from table_json');
|
||||||
ROLLBACK;
|
ROLLBACK;
|
||||||
|
|
||||||
-- prevent IMMV chanages
|
-- prevent IMMV chanages
|
||||||
|
|
@ -698,9 +683,9 @@ DELETE FROM mv_ivm_1;
|
||||||
TRUNCATE mv_ivm_1;
|
TRUNCATE mv_ivm_1;
|
||||||
|
|
||||||
-- get_immv_def function
|
-- get_immv_def function
|
||||||
SELECT immvrelid, pgivm.get_immv_def(immvrelid) FROM pgivm.pg_ivm_immv ORDER BY 1;
|
SELECT immvrelid, get_immv_def(immvrelid) FROM pg_ivm_immv ORDER BY 1;
|
||||||
-- mv_base_b is not immv
|
-- mv_base_b is not immv
|
||||||
SELECT 'mv_base_b'::regclass, pgivm.get_immv_def('mv_base_b');
|
SELECT 'mv_base_b'::regclass, get_immv_def('mv_base_b');
|
||||||
|
|
||||||
DROP TABLE mv_base_b CASCADE;
|
DROP TABLE mv_base_b CASCADE;
|
||||||
DROP TABLE mv_base_a CASCADE;
|
DROP TABLE mv_base_a CASCADE;
|
||||||
|
|
|
||||||
|
|
@ -1,19 +1,19 @@
|
||||||
CREATE TABLE t (i int PRIMARY KEY);
|
CREATE TABLE t (i int PRIMARY KEY);
|
||||||
INSERT INTO t SELECT generate_series(1, 5);
|
INSERT INTO t SELECT generate_series(1, 5);
|
||||||
|
|
||||||
SELECT pgivm.create_immv('mv', 'SELECT * FROM t');
|
SELECT create_immv('mv', 'SELECT * FROM t');
|
||||||
SELECT immvrelid, ispopulated FROM pgivm.pg_ivm_immv ORDER BY 1;
|
SELECT immvrelid, ispopulated FROM pg_ivm_immv ORDER BY 1;
|
||||||
|
|
||||||
-- Refresh IMMV with data
|
-- Refresh IMMV with data
|
||||||
SELECT pgivm.refresh_immv('mv', true);
|
SELECT refresh_immv('mv', true);
|
||||||
SELECT immvrelid, ispopulated FROM pgivm.pg_ivm_immv ORDER BY 1;
|
SELECT immvrelid, ispopulated FROM pg_ivm_immv ORDER BY 1;
|
||||||
|
|
||||||
INSERT INTO t VALUES(6);
|
INSERT INTO t VALUES(6);
|
||||||
SELECT i FROM mv ORDER BY 1;
|
SELECT i FROM mv ORDER BY 1;
|
||||||
|
|
||||||
-- Make IMMV unpopulated
|
-- Make IMMV unpopulated
|
||||||
SELECT pgivm.refresh_immv('mv', false);
|
SELECT refresh_immv('mv', false);
|
||||||
SELECT immvrelid, ispopulated FROM pgivm.pg_ivm_immv ORDER BY 1;
|
SELECT immvrelid, ispopulated FROM pg_ivm_immv ORDER BY 1;
|
||||||
SELECT i FROM mv ORDER BY 1;
|
SELECT i FROM mv ORDER BY 1;
|
||||||
|
|
||||||
-- Immediate maintenance is disabled. IMMV can be scannable and is empty.
|
-- Immediate maintenance is disabled. IMMV can be scannable and is empty.
|
||||||
|
|
@ -21,8 +21,8 @@ INSERT INTO t VALUES(7);
|
||||||
SELECT i FROM mv ORDER BY 1;
|
SELECT i FROM mv ORDER BY 1;
|
||||||
|
|
||||||
-- Refresh the IMMV and make it populated.
|
-- Refresh the IMMV and make it populated.
|
||||||
SELECT pgivm.refresh_immv('mv', true);
|
SELECT refresh_immv('mv', true);
|
||||||
SELECT immvrelid, ispopulated FROM pgivm.pg_ivm_immv ORDER BY 1;
|
SELECT immvrelid, ispopulated FROM pg_ivm_immv ORDER BY 1;
|
||||||
SELECT i FROM mv ORDER BY 1;
|
SELECT i FROM mv ORDER BY 1;
|
||||||
|
|
||||||
-- Immediate maintenance is enabled.
|
-- Immediate maintenance is enabled.
|
||||||
|
|
@ -30,10 +30,10 @@ INSERT INTO t VALUES(8);
|
||||||
SELECT i FROM mv ORDER BY 1;
|
SELECT i FROM mv ORDER BY 1;
|
||||||
|
|
||||||
-- Use qualified name
|
-- Use qualified name
|
||||||
SELECT pgivm.refresh_immv('public.mv', true);
|
SELECT refresh_immv('public.mv', true);
|
||||||
|
|
||||||
-- Use not existing IMMV
|
-- Use not existing IMMV
|
||||||
SELECT pgivm.refresh_immv('mv_not_existing', true);
|
SELECT refresh_immv('mv_not_existing', true);
|
||||||
|
|
||||||
-- Try to refresh a normal table -- error
|
-- Try to refresh a normal table -- error
|
||||||
SELECT pgivm.refresh_immv('t', true);
|
SELECT refresh_immv('t', true);
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue