2022-04-27 05:45:47 +00:00
|
|
|
/*-------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* pg_ivm.h
|
|
|
|
|
* incremental view maintenance extension
|
|
|
|
|
*
|
|
|
|
|
* Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group
|
|
|
|
|
* Portions Copyright (c) 2022, IVM Development Group
|
|
|
|
|
*
|
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
|
*/
|
2022-03-31 12:48:53 +00:00
|
|
|
|
|
|
|
|
#ifndef _PG_IVM_H_
|
2022-05-02 18:19:58 +00:00
|
|
|
#define _PG_IVM_H_
|
2022-03-31 12:48:53 +00:00
|
|
|
|
2022-04-27 05:45:47 +00:00
|
|
|
#include "catalog/objectaddress.h"
|
|
|
|
|
#include "fmgr.h"
|
|
|
|
|
#include "nodes/params.h"
|
2023-01-30 02:28:27 +00:00
|
|
|
#include "nodes/pathnodes.h"
|
2022-04-27 05:45:47 +00:00
|
|
|
#include "parser/parse_node.h"
|
|
|
|
|
#include "tcop/dest.h"
|
|
|
|
|
#include "utils/queryenvironment.h"
|
|
|
|
|
|
Fix potential view inconsistency issues (#121)
Previously, the view contents could become inconsistent with the base tables
in the following scenarios:
1) A concurrent transaction modifies a base table and commits before the
incremental view maintenance starts in the current transaction.
2) A concurrent transaction modifies a base table and commits before the
create_immv or refresh_immv command generates data.
3) Concurrent transactions incrementally update a view with a self-join
or modify multiple base tables simultaneously.
Incremental updates of a view are generally performed sequentially using an
exclusive lock. However, even if we are able to acquire the lock, a concurrent
transaction may have already incrementally updated the view and been committed
before we can acquire it. In REPEATABLE READ or SERIALIZABLE isolation levels,
this could lead to an inconsistent view state, which is the cause of the first
issue.
To fix this, a new field, lastivmupdate, has been added to the pg_ivm_immv
catalog to record the transaction ID of the most recent update to the view.
Before performing view maintenance, the transaction ID is checked. If the
transaction was still in progress at the start of the current transaction,
an error is raised to prevent anomalies.
To fix the second issue, the timing of CreateTrigger() has been moved to
before data generation. This ensures that locks conflicting with table
modifications have been acquired on all base tables. In addition, the latest
snapshot is used in READ COMMITTED level during the data generation to reflect
committed changes from concurrent transactions. Additionally, inconsistencies
that cannot be avoided through locking are prevented by checking the transaction
ID of the last view update, as done for the first issue.
However, concurrent table modifications and create_immv execution still cannot
be detected at the time of view creation. Therefore, create_immv raises a warning
in REPEATABLE READ or SERIALIZABLE isolation levels, suggesting that the command
be used in READ COMMITTED mode or that refresh_immv be executed afterward to
ensure the view remains consistent.
The third issue was caused by the snapshot used for checking tuple visibility in
the table's pre-update state not being the latest one. To fix this, the latest
snapshot is now used in READ COMMITTED mode.
Isolation tests are also added.
Issue #104
2025-03-10 09:26:54 +00:00
|
|
|
#define Natts_pg_ivm_immv 4
|
2022-03-31 12:48:53 +00:00
|
|
|
|
|
|
|
|
#define Anum_pg_ivm_immv_immvrelid 1
|
2022-06-21 11:50:45 +00:00
|
|
|
#define Anum_pg_ivm_immv_viewdef 2
|
|
|
|
|
#define Anum_pg_ivm_immv_ispopulated 3
|
Fix potential view inconsistency issues (#121)
Previously, the view contents could become inconsistent with the base tables
in the following scenarios:
1) A concurrent transaction modifies a base table and commits before the
incremental view maintenance starts in the current transaction.
2) A concurrent transaction modifies a base table and commits before the
create_immv or refresh_immv command generates data.
3) Concurrent transactions incrementally update a view with a self-join
or modify multiple base tables simultaneously.
Incremental updates of a view are generally performed sequentially using an
exclusive lock. However, even if we are able to acquire the lock, a concurrent
transaction may have already incrementally updated the view and been committed
before we can acquire it. In REPEATABLE READ or SERIALIZABLE isolation levels,
this could lead to an inconsistent view state, which is the cause of the first
issue.
To fix this, a new field, lastivmupdate, has been added to the pg_ivm_immv
catalog to record the transaction ID of the most recent update to the view.
Before performing view maintenance, the transaction ID is checked. If the
transaction was still in progress at the start of the current transaction,
an error is raised to prevent anomalies.
To fix the second issue, the timing of CreateTrigger() has been moved to
before data generation. This ensures that locks conflicting with table
modifications have been acquired on all base tables. In addition, the latest
snapshot is used in READ COMMITTED level during the data generation to reflect
committed changes from concurrent transactions. Additionally, inconsistencies
that cannot be avoided through locking are prevented by checking the transaction
ID of the last view update, as done for the first issue.
However, concurrent table modifications and create_immv execution still cannot
be detected at the time of view creation. Therefore, create_immv raises a warning
in REPEATABLE READ or SERIALIZABLE isolation levels, suggesting that the command
be used in READ COMMITTED mode or that refresh_immv be executed afterward to
ensure the view remains consistent.
The third issue was caused by the snapshot used for checking tuple visibility in
the table's pre-update state not being the latest one. To fix this, the latest
snapshot is now used in READ COMMITTED mode.
Isolation tests are also added.
Issue #104
2025-03-10 09:26:54 +00:00
|
|
|
#define Anum_pg_ivm_immv_lastivmupdate 4
|
2022-03-31 12:48:53 +00:00
|
|
|
|
2022-04-27 05:45:47 +00:00
|
|
|
/* pg_ivm.c */
|
|
|
|
|
|
|
|
|
|
extern void CreateChangePreventTrigger(Oid matviewOid);
|
|
|
|
|
extern Oid PgIvmImmvRelationId(void);
|
|
|
|
|
extern Oid PgIvmImmvPrimaryKeyIndexId(void);
|
2022-10-18 06:51:41 +00:00
|
|
|
extern bool isImmv(Oid immv_oid);
|
2025-02-17 03:07:21 +00:00
|
|
|
extern List *PgIvmFuncName(char *name);
|
2022-04-27 05:45:47 +00:00
|
|
|
|
|
|
|
|
/* createas.c */
|
|
|
|
|
|
|
|
|
|
extern ObjectAddress ExecCreateImmv(ParseState *pstate, CreateTableAsStmt *stmt,
|
|
|
|
|
QueryCompletion *qc);
|
2023-09-11 06:23:51 +00:00
|
|
|
extern void CreateIvmTriggersOnBaseTables(Query *qry, Oid matviewOid);
|
|
|
|
|
extern void CreateIndexOnIMMV(Query *query, Relation matviewRel);
|
2022-04-27 05:45:47 +00:00
|
|
|
extern Query *rewriteQueryForIMMV(Query *query, List *colNames);
|
2022-06-21 11:50:45 +00:00
|
|
|
extern void makeIvmAggColumn(ParseState *pstate, Aggref *aggref, char *resname, AttrNumber *next_resno, List **aggs);
|
2022-04-27 05:45:47 +00:00
|
|
|
|
|
|
|
|
/* matview.c */
|
|
|
|
|
|
2022-09-30 09:59:51 +00:00
|
|
|
extern Query *get_immv_query(Relation matviewRel);
|
2022-06-23 02:33:06 +00:00
|
|
|
extern ObjectAddress ExecRefreshImmv(const RangeVar *relation, bool skipData,
|
|
|
|
|
const char *queryString, QueryCompletion *qc);
|
Fix potential view inconsistency issues (#121)
Previously, the view contents could become inconsistent with the base tables
in the following scenarios:
1) A concurrent transaction modifies a base table and commits before the
incremental view maintenance starts in the current transaction.
2) A concurrent transaction modifies a base table and commits before the
create_immv or refresh_immv command generates data.
3) Concurrent transactions incrementally update a view with a self-join
or modify multiple base tables simultaneously.
Incremental updates of a view are generally performed sequentially using an
exclusive lock. However, even if we are able to acquire the lock, a concurrent
transaction may have already incrementally updated the view and been committed
before we can acquire it. In REPEATABLE READ or SERIALIZABLE isolation levels,
this could lead to an inconsistent view state, which is the cause of the first
issue.
To fix this, a new field, lastivmupdate, has been added to the pg_ivm_immv
catalog to record the transaction ID of the most recent update to the view.
Before performing view maintenance, the transaction ID is checked. If the
transaction was still in progress at the start of the current transaction,
an error is raised to prevent anomalies.
To fix the second issue, the timing of CreateTrigger() has been moved to
before data generation. This ensures that locks conflicting with table
modifications have been acquired on all base tables. In addition, the latest
snapshot is used in READ COMMITTED level during the data generation to reflect
committed changes from concurrent transactions. Additionally, inconsistencies
that cannot be avoided through locking are prevented by checking the transaction
ID of the last view update, as done for the first issue.
However, concurrent table modifications and create_immv execution still cannot
be detected at the time of view creation. Therefore, create_immv raises a warning
in REPEATABLE READ or SERIALIZABLE isolation levels, suggesting that the command
be used in READ COMMITTED mode or that refresh_immv be executed afterward to
ensure the view remains consistent.
The third issue was caused by the snapshot used for checking tuple visibility in
the table's pre-update state not being the latest one. To fix this, the latest
snapshot is now used in READ COMMITTED mode.
Isolation tests are also added.
Issue #104
2025-03-10 09:26:54 +00:00
|
|
|
extern ObjectAddress RefreshImmvByOid(Oid matviewOid, bool is_create, bool skipData,
|
2024-07-31 03:37:43 +00:00
|
|
|
const char *queryString, QueryCompletion *qc);
|
2022-04-27 05:45:47 +00:00
|
|
|
extern bool ImmvIncrementalMaintenanceIsEnabled(void);
|
|
|
|
|
extern Datum IVM_immediate_before(PG_FUNCTION_ARGS);
|
|
|
|
|
extern Datum IVM_immediate_maintenance(PG_FUNCTION_ARGS);
|
2023-08-31 02:51:36 +00:00
|
|
|
extern Query* rewrite_query_for_exists_subquery(Query *query);
|
Use snapshot to check tuple visibility in pre-update state (#28)
When multiple tables are updated or the view contains a self-join,
we need to calculate table states that was before it is modified
during incremental view maintenance. For get the pre-update state,
tuples inserted in a command must be removed when the table is scanned.
Previously, we used xmin and cmin system columns for this purpose,
but this way is problematic because after a tuple is frozen, its xmin
no longer has any meaning. Actually, we will get inconsistent view
results after XID wraparound.
Also, we can see similar similar inconsistency when using sub-transaction
because xmin values do not always monotonically increasing by command
executions.
To fix this, we use a snapshot that taken just before the table is
modified for checking tuple visibility in pre-state table instead of
using xmin and cmin system columns. A new function returning boolean,
ivm_visible_in_prestate, is added, and this is called in WHERE clause
of sub-queries to calculate pre-state table. This function check if a
specified tuple in the post-update table is visible or not using the
snapshot and return true if the tuple is visible.
2022-09-30 02:53:12 +00:00
|
|
|
extern Datum ivm_visible_in_prestate(PG_FUNCTION_ARGS);
|
Fix potential view inconsistency issues (#121)
Previously, the view contents could become inconsistent with the base tables
in the following scenarios:
1) A concurrent transaction modifies a base table and commits before the
incremental view maintenance starts in the current transaction.
2) A concurrent transaction modifies a base table and commits before the
create_immv or refresh_immv command generates data.
3) Concurrent transactions incrementally update a view with a self-join
or modify multiple base tables simultaneously.
Incremental updates of a view are generally performed sequentially using an
exclusive lock. However, even if we are able to acquire the lock, a concurrent
transaction may have already incrementally updated the view and been committed
before we can acquire it. In REPEATABLE READ or SERIALIZABLE isolation levels,
this could lead to an inconsistent view state, which is the cause of the first
issue.
To fix this, a new field, lastivmupdate, has been added to the pg_ivm_immv
catalog to record the transaction ID of the most recent update to the view.
Before performing view maintenance, the transaction ID is checked. If the
transaction was still in progress at the start of the current transaction,
an error is raised to prevent anomalies.
To fix the second issue, the timing of CreateTrigger() has been moved to
before data generation. This ensures that locks conflicting with table
modifications have been acquired on all base tables. In addition, the latest
snapshot is used in READ COMMITTED level during the data generation to reflect
committed changes from concurrent transactions. Additionally, inconsistencies
that cannot be avoided through locking are prevented by checking the transaction
ID of the last view update, as done for the first issue.
However, concurrent table modifications and create_immv execution still cannot
be detected at the time of view creation. Therefore, create_immv raises a warning
in REPEATABLE READ or SERIALIZABLE isolation levels, suggesting that the command
be used in READ COMMITTED mode or that refresh_immv be executed afterward to
ensure the view remains consistent.
The third issue was caused by the snapshot used for checking tuple visibility in
the table's pre-update state not being the latest one. To fix this, the latest
snapshot is now used in READ COMMITTED mode.
Isolation tests are also added.
Issue #104
2025-03-10 09:26:54 +00:00
|
|
|
extern void AtAbort_IVM(SubTransactionId subtxid);
|
|
|
|
|
extern void AtPreCommit_IVM(void);
|
2023-08-31 02:51:36 +00:00
|
|
|
extern char *getColumnNameStartWith(RangeTblEntry *rte, char *str, int *attnum);
|
2022-04-27 05:45:47 +00:00
|
|
|
extern bool isIvmName(const char *s);
|
|
|
|
|
|
2022-07-25 04:11:33 +00:00
|
|
|
/* ruleutils.c */
|
|
|
|
|
|
2022-09-29 13:24:28 +00:00
|
|
|
extern char *pg_ivm_get_viewdef(Relation immvrel, bool pretty);
|
2022-07-25 04:11:33 +00:00
|
|
|
|
2023-01-30 02:28:27 +00:00
|
|
|
/* subselect.c */
|
|
|
|
|
extern void inline_cte(PlannerInfo *root, CommonTableExpr *cte);
|
|
|
|
|
|
2022-03-31 12:48:53 +00:00
|
|
|
#endif
|