Skip to content

Commit

Permalink
Consider tuple duplicity in maintenance of EXISTS views
Browse files Browse the repository at this point in the history
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)
  • Loading branch information
yugo-n authored and thoshiai committed Feb 29, 2024
1 parent aab9db3 commit 8c3b4ba
Show file tree
Hide file tree
Showing 3 changed files with 36 additions and 2 deletions.
13 changes: 13 additions & 0 deletions expected/pg_ivm.out
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
22 changes: 20 additions & 2 deletions matview.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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,
Expand All @@ -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);
}
Expand Down
3 changes: 3 additions & 0 deletions sql/pg_ivm.sql
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit 8c3b4ba

Please sign in to comment.