Consider tuple duplicity in maintenance of EXISTS views

When a tuple is inserted into a table in an EXISTS subquery,
the duplicity of row is computed by count(*), but it was not
considered and only one tuple was inserted with ignoring
the duplicity.

This is fixed by duplicating rows as much as the duplicity
by using generate_series at inserting.

(Issue #82)
This commit is contained in:
Yugo Nagata 2024-02-27 17:09:34 +09:00 committed by thoshiai
parent aab9db3605
commit 8c3b4ba9d7
3 changed files with 36 additions and 2 deletions

View file

@ -828,6 +828,19 @@ SELECT * FROM mv_ivm_exists_subquery2 ORDER BY i, j;
4 | 40 | 1
(4 rows)
DELETE FROM mv_base_b WHERE i = 1 or i = 3;
INSERT INTO mv_base_b VALUES (1,100), (3,300);
SELECT * FROM mv_ivm_exists_subquery ORDER BY i, j;
i | j | __ivm_exists_count_0__
---+-----+------------------------
1 | 10 | 1
1 | 10 | 1
3 | 30 | 1
3 | 30 | 1
3 | 300 | 1
4 | 40 | 1
(6 rows)
ROLLBACK;
-- support simple subquery in FROM clause
BEGIN;

View file

@ -2523,6 +2523,7 @@ apply_new_delta_with_count(const char *matviewname, const char* deltaname_new,
StringInfoData returning_keys;
ListCell *lc;
char *match_cond = "";
StringInfoData deltaname_new_for_insert;
/* build WHERE condition for searching tuples to be updated */
match_cond = get_matching_condition_string(keys);
@ -2543,6 +2544,24 @@ apply_new_delta_with_count(const char *matviewname, const char* deltaname_new,
else
appendStringInfo(&returning_keys, "NULL");
/*
* If count_colname is not "__ivm_count__", the view contains EXISTS
* subquery and the count column to be updated here is "__ivm_exists_count_*"
* that stores the number of columns generated by corresponding EXISTS
* subquery for each row in the view. In this case, __ivm_count__ in
* deltaname_new stores duplicity of rows, and each row need to be
* duplicated as much as __ivm_count__ by using generate_series at
* inserting.
*/
initStringInfo(&deltaname_new_for_insert);
if (!strcmp(count_colname, "__ivm_count__"))
appendStringInfo(&deltaname_new_for_insert, "%s", deltaname_new);
else
appendStringInfo(&deltaname_new_for_insert,
"(SELECT diff.* FROM %s diff,"
"pg_catalog.generate_series(1, diff.\"__ivm_count__\"))",
deltaname_new);
/* Search for matching tuples from the view and update if found or insert if not. */
initStringInfo(&querybuf);
appendStringInfo(&querybuf,
@ -2561,9 +2580,8 @@ apply_new_delta_with_count(const char *matviewname, const char* deltaname_new,
match_cond,
returning_keys.data,
matviewname, target_list->data,
target_list->data, deltaname_new,
target_list->data, deltaname_new_for_insert.data,
match_cond);
if (SPI_exec(querybuf.data, 0) != SPI_OK_INSERT)
elog(ERROR, "SPI_exec failed: %s", querybuf.data);
}

View file

@ -269,6 +269,9 @@ DELETE FROM mv_base_a WHERE (i,j) = (1,60);
DELETE FROM mv_base_b WHERE i = 2;
SELECT * FROM mv_ivm_exists_subquery ORDER BY i, j;
SELECT * FROM mv_ivm_exists_subquery2 ORDER BY i, j;
DELETE FROM mv_base_b WHERE i = 1 or i = 3;
INSERT INTO mv_base_b VALUES (1,100), (3,300);
SELECT * FROM mv_ivm_exists_subquery ORDER BY i, j;
ROLLBACK;
-- support simple subquery in FROM clause