Build errors/warnings against PostgreSQL 16 are fixed. Also, adapted to the change of codes, including: - Get rid of the "new" and "old" entries in a view's rangetable. (Although, removed codes were dead codes because pg_ivm doesn't have any rules in pg_rewrite.) - Rework query relation permission checking - Require empty Bitmapsets to be represented as NULL - Fix some compiler warnings
This commit is contained in:
parent
6f99049848
commit
71f9d268b0
5 changed files with 83 additions and 72 deletions
|
|
@ -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, and 15.
|
The extension is compatible with PostgreSQL 13, 14, 15, and 16.
|
||||||
|
|
||||||
## Description
|
## Description
|
||||||
|
|
||||||
|
|
|
||||||
82
createas.c
82
createas.c
|
|
@ -78,7 +78,7 @@ static void CreateIvmTriggersOnBaseTablesRecurse(Query *qry, Node *node, Oid mat
|
||||||
static void CreateIvmTrigger(Oid relOid, Oid viewOid, int16 type, int16 timing, bool ex_lock);
|
static void CreateIvmTrigger(Oid relOid, Oid viewOid, int16 type, int16 timing, bool ex_lock);
|
||||||
static void check_ivm_restriction(Node *node);
|
static void check_ivm_restriction(Node *node);
|
||||||
static bool check_ivm_restriction_walker(Node *node, check_ivm_restriction_context *context);
|
static bool check_ivm_restriction_walker(Node *node, check_ivm_restriction_context *context);
|
||||||
static Bitmapset *get_primary_key_attnos_from_query(Query *query, List **constraintList, bool is_create);
|
static Bitmapset *get_primary_key_attnos_from_query(Query *query, List **constraintList);
|
||||||
static bool check_aggregate_supports_ivm(Oid aggfnoid);
|
static bool check_aggregate_supports_ivm(Oid aggfnoid);
|
||||||
|
|
||||||
static void StoreImmvQuery(Oid viewOid, bool ispopulated, Query *viewQuery);
|
static void StoreImmvQuery(Oid viewOid, bool ispopulated, Query *viewQuery);
|
||||||
|
|
@ -262,14 +262,14 @@ ExecCreateImmv(ParseState *pstate, CreateTableAsStmt *stmt,
|
||||||
if (!into->skipData)
|
if (!into->skipData)
|
||||||
{
|
{
|
||||||
/* Create an index on incremental maintainable materialized view, if possible */
|
/* Create an index on incremental maintainable materialized view, if possible */
|
||||||
CreateIndexOnIMMV(viewQuery, matviewRel, true);
|
CreateIndexOnIMMV(viewQuery, matviewRel);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Create triggers on incremental maintainable materialized view
|
* Create triggers on incremental maintainable materialized view
|
||||||
* This argument should use 'query'. This needs to use a rewritten query,
|
* This argument should use 'query'. This needs to use a rewritten query,
|
||||||
* because a sublink in jointree is not supported by this function.
|
* because a sublink in jointree is not supported by this function.
|
||||||
*/
|
*/
|
||||||
CreateIvmTriggersOnBaseTables(query, matviewOid, true);
|
CreateIvmTriggersOnBaseTables(query, matviewOid);
|
||||||
|
|
||||||
/* Create triggers to prevent IMMV from beeing changed */
|
/* Create triggers to prevent IMMV from beeing changed */
|
||||||
CreateChangePreventTrigger(matviewOid);
|
CreateChangePreventTrigger(matviewOid);
|
||||||
|
|
@ -297,7 +297,6 @@ rewriteQueryForIMMV(Query *query, List *colNames)
|
||||||
{
|
{
|
||||||
Query *rewritten;
|
Query *rewritten;
|
||||||
|
|
||||||
TargetEntry *tle;
|
|
||||||
Node *node;
|
Node *node;
|
||||||
ParseState *pstate = make_parsestate(NULL);
|
ParseState *pstate = make_parsestate(NULL);
|
||||||
FuncCall *fn;
|
FuncCall *fn;
|
||||||
|
|
@ -348,7 +347,7 @@ rewriteQueryForIMMV(Query *query, List *colNames)
|
||||||
|
|
||||||
if (countCol != NULL)
|
if (countCol != NULL)
|
||||||
{
|
{
|
||||||
tle = makeTargetEntry((Expr *) countCol,
|
TargetEntry *tle = makeTargetEntry((Expr *) countCol,
|
||||||
list_length(rewritten->targetList) + 1,
|
list_length(rewritten->targetList) + 1,
|
||||||
pstrdup(columnName),
|
pstrdup(columnName),
|
||||||
false);
|
false);
|
||||||
|
|
@ -399,6 +398,8 @@ rewriteQueryForIMMV(Query *query, List *colNames)
|
||||||
/* Add count(*) for counting distinct tuples in views */
|
/* Add count(*) for counting distinct tuples in views */
|
||||||
if (rewritten->distinctClause || rewritten->hasAggs)
|
if (rewritten->distinctClause || rewritten->hasAggs)
|
||||||
{
|
{
|
||||||
|
TargetEntry *tle;
|
||||||
|
|
||||||
#if defined(PG_VERSION_NUM) && (PG_VERSION_NUM >= 140000)
|
#if defined(PG_VERSION_NUM) && (PG_VERSION_NUM >= 140000)
|
||||||
fn = makeFuncCall(SystemFuncName("count"), NIL, COERCE_EXPLICIT_CALL, -1);
|
fn = makeFuncCall(SystemFuncName("count"), NIL, COERCE_EXPLICIT_CALL, -1);
|
||||||
#else
|
#else
|
||||||
|
|
@ -516,22 +517,14 @@ makeIvmAggColumn(ParseState *pstate, Aggref *aggref, char *resname, AttrNumber *
|
||||||
* CreateIvmTriggersOnBaseTables -- create IVM triggers on all base tables
|
* CreateIvmTriggersOnBaseTables -- create IVM triggers on all base tables
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
CreateIvmTriggersOnBaseTables(Query *qry, Oid matviewOid, bool is_create)
|
CreateIvmTriggersOnBaseTables(Query *qry, Oid matviewOid)
|
||||||
{
|
{
|
||||||
Relids relids = NULL;
|
Relids relids = NULL;
|
||||||
bool ex_lock = false;
|
bool ex_lock = false;
|
||||||
Index first_rtindex = is_create ? 1 : PRS2_NEW_VARNO + 1;
|
|
||||||
RangeTblEntry *rte;
|
RangeTblEntry *rte;
|
||||||
|
|
||||||
/*
|
|
||||||
* is_create must be true in pg_ivm because the view definition doesn't
|
|
||||||
* contain NEW/OLD RTE.
|
|
||||||
* XXX: This argument should be removed?
|
|
||||||
*/
|
|
||||||
Assert(is_create);
|
|
||||||
|
|
||||||
/* Immediately return if we don't have any base tables. */
|
/* Immediately return if we don't have any base tables. */
|
||||||
if (list_length(qry->rtable) < first_rtindex)
|
if (list_length(qry->rtable) < 1)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -553,10 +546,9 @@ CreateIvmTriggersOnBaseTables(Query *qry, Oid matviewOid, bool is_create)
|
||||||
* target list are not nullable.
|
* target list are not nullable.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
rte = list_nth(qry->rtable, first_rtindex - 1);
|
rte = list_nth(qry->rtable, 0);
|
||||||
if (list_length(qry->rtable) > first_rtindex ||
|
if (list_length(qry->rtable) > 1 || rte->rtekind != RTE_RELATION ||
|
||||||
rte->rtekind != RTE_RELATION || qry->distinctClause ||
|
qry->distinctClause || (qry->hasAggs && qry->groupClause))
|
||||||
(qry->hasAggs && qry->groupClause))
|
|
||||||
ex_lock = true;
|
ex_lock = true;
|
||||||
|
|
||||||
CreateIvmTriggersOnBaseTablesRecurse(qry, (Node *)qry, matviewOid, &relids, ex_lock);
|
CreateIvmTriggersOnBaseTablesRecurse(qry, (Node *)qry, matviewOid, &relids, ex_lock);
|
||||||
|
|
@ -927,8 +919,6 @@ check_ivm_restriction_walker(Node *node, check_ivm_restriction_context *context)
|
||||||
*/
|
*/
|
||||||
if (context->exists_qual_vars != NIL && context->sublevels_up == 0)
|
if (context->exists_qual_vars != NIL && context->sublevels_up == 0)
|
||||||
{
|
{
|
||||||
ListCell *lc;
|
|
||||||
|
|
||||||
foreach (lc, context->exists_qual_vars)
|
foreach (lc, context->exists_qual_vars)
|
||||||
{
|
{
|
||||||
Var *var = (Var *) lfirst(lc);
|
Var *var = (Var *) lfirst(lc);
|
||||||
|
|
@ -1284,7 +1274,7 @@ check_aggregate_supports_ivm(Oid aggfnoid)
|
||||||
* is created on these attritubes. 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, bool is_create)
|
CreateIndexOnIMMV(Query *query, Relation matviewRel)
|
||||||
{
|
{
|
||||||
ListCell *lc;
|
ListCell *lc;
|
||||||
IndexStmt *index;
|
IndexStmt *index;
|
||||||
|
|
@ -1294,14 +1284,6 @@ CreateIndexOnIMMV(Query *query, Relation matviewRel, bool is_create)
|
||||||
List *indexoidlist = RelationGetIndexList(matviewRel);
|
List *indexoidlist = RelationGetIndexList(matviewRel);
|
||||||
ListCell *indexoidscan;
|
ListCell *indexoidscan;
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* is_create must be true in pg_ivm because the view definition doesn't
|
|
||||||
* contain NEW/OLD RTE.
|
|
||||||
* XXX: This argument should be removed?
|
|
||||||
*/
|
|
||||||
Assert(is_create);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* For aggregate without GROUP BY, we do not need to create an index
|
* For aggregate without GROUP BY, we do not need to create an index
|
||||||
* because the view has only one row.
|
* because the view has only one row.
|
||||||
|
|
@ -1341,9 +1323,14 @@ CreateIndexOnIMMV(Query *query, Relation matviewRel, bool is_create)
|
||||||
index->excludeOpNames = NIL;
|
index->excludeOpNames = NIL;
|
||||||
index->idxcomment = NULL;
|
index->idxcomment = NULL;
|
||||||
index->indexOid = InvalidOid;
|
index->indexOid = InvalidOid;
|
||||||
|
#if defined(PG_VERSION_NUM) && (PG_VERSION_NUM >= 160000)
|
||||||
|
index->oldNumber = InvalidRelFileNumber;
|
||||||
|
index->oldFirstRelfilelocatorSubid = InvalidSubTransactionId;
|
||||||
|
#else
|
||||||
index->oldNode = InvalidOid;
|
index->oldNode = InvalidOid;
|
||||||
index->oldCreateSubid = InvalidSubTransactionId;
|
|
||||||
index->oldFirstRelfilenodeSubid = InvalidSubTransactionId;
|
index->oldFirstRelfilenodeSubid = InvalidSubTransactionId;
|
||||||
|
#endif
|
||||||
|
index->oldCreateSubid = InvalidSubTransactionId;
|
||||||
index->transformed = true;
|
index->transformed = true;
|
||||||
index->concurrent = false;
|
index->concurrent = false;
|
||||||
index->if_not_exists = false;
|
index->if_not_exists = false;
|
||||||
|
|
@ -1396,7 +1383,7 @@ CreateIndexOnIMMV(Query *query, Relation matviewRel, bool is_create)
|
||||||
Bitmapset *key_attnos;
|
Bitmapset *key_attnos;
|
||||||
|
|
||||||
/* create index on the base tables' primary key columns */
|
/* create index on the base tables' primary key columns */
|
||||||
key_attnos = get_primary_key_attnos_from_query(query, &constraintList, is_create);
|
key_attnos = get_primary_key_attnos_from_query(query, &constraintList);
|
||||||
if (key_attnos)
|
if (key_attnos)
|
||||||
{
|
{
|
||||||
foreach(lc, query->targetList)
|
foreach(lc, query->targetList)
|
||||||
|
|
@ -1460,6 +1447,9 @@ CreateIndexOnIMMV(Query *query, Relation matviewRel, bool is_create)
|
||||||
InvalidOid,
|
InvalidOid,
|
||||||
InvalidOid,
|
InvalidOid,
|
||||||
InvalidOid,
|
InvalidOid,
|
||||||
|
#if defined(PG_VERSION_NUM) && (PG_VERSION_NUM >= 160000)
|
||||||
|
-1,
|
||||||
|
#endif
|
||||||
false, true, false, false, true);
|
false, true, false, false, true);
|
||||||
|
|
||||||
ereport(NOTICE,
|
ereport(NOTICE,
|
||||||
|
|
@ -1500,7 +1490,7 @@ CreateIndexOnIMMV(Query *query, Relation matviewRel, bool is_create)
|
||||||
* constraintList is set to a list of the OIDs of the pkey constraints.
|
* constraintList is set to a list of the OIDs of the pkey constraints.
|
||||||
*/
|
*/
|
||||||
static Bitmapset *
|
static Bitmapset *
|
||||||
get_primary_key_attnos_from_query(Query *query, List **constraintList, bool is_create)
|
get_primary_key_attnos_from_query(Query *query, List **constraintList)
|
||||||
{
|
{
|
||||||
List *key_attnos_list = NIL;
|
List *key_attnos_list = NIL;
|
||||||
ListCell *lc;
|
ListCell *lc;
|
||||||
|
|
@ -1527,21 +1517,16 @@ get_primary_key_attnos_from_query(Query *query, List **constraintList, bool is_c
|
||||||
* Collect primary key attributes from all tables used in query. The key attributes
|
* Collect primary key attributes from all tables used in query. The key attributes
|
||||||
* sets for each table are stored in key_attnos_list in order by RTE index.
|
* sets for each table are stored in key_attnos_list in order by RTE index.
|
||||||
*/
|
*/
|
||||||
i = 1;
|
|
||||||
foreach(lc, query->rtable)
|
foreach(lc, query->rtable)
|
||||||
{
|
{
|
||||||
RangeTblEntry *r = (RangeTblEntry*) lfirst(lc);
|
RangeTblEntry *r = (RangeTblEntry*) lfirst(lc);
|
||||||
Bitmapset *key_attnos;
|
Bitmapset *key_attnos;
|
||||||
bool has_pkey = true;
|
bool has_pkey = true;
|
||||||
Index first_rtindex = is_create ? 1 : PRS2_NEW_VARNO + 1;
|
|
||||||
|
|
||||||
/* skip NEW/OLD entries */
|
|
||||||
if (i >= first_rtindex)
|
|
||||||
{
|
|
||||||
/* for subqueries, scan recursively */
|
/* for subqueries, scan recursively */
|
||||||
if (r->rtekind == RTE_SUBQUERY)
|
if (r->rtekind == RTE_SUBQUERY)
|
||||||
{
|
{
|
||||||
key_attnos = get_primary_key_attnos_from_query(r->subquery, constraintList, true);
|
key_attnos = get_primary_key_attnos_from_query(r->subquery, constraintList);
|
||||||
has_pkey = (key_attnos != NULL);
|
has_pkey = (key_attnos != NULL);
|
||||||
}
|
}
|
||||||
/* for tables, call get_primary_key_attnos */
|
/* for tables, call get_primary_key_attnos */
|
||||||
|
|
@ -1555,9 +1540,6 @@ get_primary_key_attnos_from_query(Query *query, List **constraintList, bool is_c
|
||||||
/* for other RTEs, store NULL into key_attnos_list */
|
/* for other RTEs, store NULL into key_attnos_list */
|
||||||
else
|
else
|
||||||
key_attnos = NULL;
|
key_attnos = NULL;
|
||||||
}
|
|
||||||
else
|
|
||||||
key_attnos = NULL;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If any table or subquery has no primary key or its pkey constraint is deferrable,
|
* If any table or subquery has no primary key or its pkey constraint is deferrable,
|
||||||
|
|
@ -1567,14 +1549,17 @@ get_primary_key_attnos_from_query(Query *query, List **constraintList, bool is_c
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
key_attnos_list = lappend(key_attnos_list, key_attnos);
|
key_attnos_list = lappend(key_attnos_list, key_attnos);
|
||||||
i++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Collect key attributes appearing in the target list */
|
/* Collect key attributes appearing in the target list */
|
||||||
i = 1;
|
i = 1;
|
||||||
foreach(lc, query->targetList)
|
foreach(lc, query->targetList)
|
||||||
{
|
{
|
||||||
|
#if defined(PG_VERSION_NUM) && (PG_VERSION_NUM >= 160000)
|
||||||
|
TargetEntry *tle = (TargetEntry *) flatten_join_alias_vars(NULL, query, lfirst(lc));
|
||||||
|
#else
|
||||||
TargetEntry *tle = (TargetEntry *) flatten_join_alias_vars(query, lfirst(lc));
|
TargetEntry *tle = (TargetEntry *) flatten_join_alias_vars(query, lfirst(lc));
|
||||||
|
#endif
|
||||||
|
|
||||||
if (IsA(tle->expr, Var))
|
if (IsA(tle->expr, Var))
|
||||||
{
|
{
|
||||||
|
|
@ -1588,7 +1573,12 @@ get_primary_key_attnos_from_query(Query *query, List **constraintList, bool is_c
|
||||||
* Remove found key attributes from key_attnos_list, and add this
|
* Remove found key attributes from key_attnos_list, and add this
|
||||||
* to the result list.
|
* to the result list.
|
||||||
*/
|
*/
|
||||||
bms_del_member(key_attnos, var->varattno - FirstLowInvalidHeapAttributeNumber);
|
key_attnos = bms_del_member(key_attnos, var->varattno - FirstLowInvalidHeapAttributeNumber);
|
||||||
|
if (bms_is_empty(key_attnos))
|
||||||
|
{
|
||||||
|
key_attnos_list = list_delete_nth_cell(key_attnos_list, var->varno - 1);
|
||||||
|
key_attnos_list = list_insert_nth(key_attnos_list, var->varno - 1, NULL);
|
||||||
|
}
|
||||||
keys = bms_add_member(keys, i - FirstLowInvalidHeapAttributeNumber);
|
keys = bms_add_member(keys, i - FirstLowInvalidHeapAttributeNumber);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1596,7 +1586,11 @@ get_primary_key_attnos_from_query(Query *query, List **constraintList, bool is_c
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Collect RTE indexes of relations appearing in the FROM clause */
|
/* Collect RTE indexes of relations appearing in the FROM clause */
|
||||||
|
#if defined(PG_VERSION_NUM) && (PG_VERSION_NUM >= 160000)
|
||||||
|
rels_in_from = get_relids_in_jointree((Node *) query->jointree, false, false);
|
||||||
|
#else
|
||||||
rels_in_from = get_relids_in_jointree((Node *) query->jointree, false);
|
rels_in_from = get_relids_in_jointree((Node *) query->jointree, false);
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check if all key attributes of relations in FROM are appearing in the target
|
* Check if all key attributes of relations in FROM are appearing in the target
|
||||||
|
|
|
||||||
33
matview.c
33
matview.c
|
|
@ -354,9 +354,6 @@ ExecRefreshImmv(const RangeVar *relation, bool skipData,
|
||||||
{
|
{
|
||||||
Relation tgRel;
|
Relation tgRel;
|
||||||
Relation depRel;
|
Relation depRel;
|
||||||
ScanKeyData key;
|
|
||||||
SysScanDesc scan;
|
|
||||||
HeapTuple tup;
|
|
||||||
ObjectAddresses *immv_triggers;
|
ObjectAddresses *immv_triggers;
|
||||||
|
|
||||||
immv_triggers = new_object_addresses();
|
immv_triggers = new_object_addresses();
|
||||||
|
|
@ -450,7 +447,7 @@ ExecRefreshImmv(const RangeVar *relation, bool skipData,
|
||||||
pgstat_count_heap_insert(matviewRel, processed);
|
pgstat_count_heap_insert(matviewRel, processed);
|
||||||
|
|
||||||
if (!skipData && !oldPopulated)
|
if (!skipData && !oldPopulated)
|
||||||
CreateIvmTriggersOnBaseTables(viewQuery, matviewOid, true);
|
CreateIvmTriggersOnBaseTables(viewQuery, matviewOid);
|
||||||
|
|
||||||
table_close(matviewRel, NoLock);
|
table_close(matviewRel, NoLock);
|
||||||
|
|
||||||
|
|
@ -905,8 +902,13 @@ IVM_immediate_maintenance(PG_FUNCTION_ARGS)
|
||||||
if (!(query->hasAggs && query->groupClause == NIL))
|
if (!(query->hasAggs && query->groupClause == NIL))
|
||||||
{
|
{
|
||||||
OpenImmvIncrementalMaintenance();
|
OpenImmvIncrementalMaintenance();
|
||||||
|
#if defined(PG_VERSION_NUM) && (PG_VERSION_NUM >= 160000)
|
||||||
|
ExecuteTruncateGuts(list_make1(matviewRel), list_make1_oid(matviewOid),
|
||||||
|
NIL, DROP_RESTRICT, false, false);
|
||||||
|
#else
|
||||||
ExecuteTruncateGuts(list_make1(matviewRel), list_make1_oid(matviewOid),
|
ExecuteTruncateGuts(list_make1(matviewRel), list_make1_oid(matviewOid),
|
||||||
NIL, DROP_RESTRICT, false);
|
NIL, DROP_RESTRICT, false);
|
||||||
|
#endif
|
||||||
CloseImmvIncrementalMaintenance();
|
CloseImmvIncrementalMaintenance();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
@ -1041,7 +1043,6 @@ IVM_immediate_maintenance(PG_FUNCTION_ARGS)
|
||||||
foreach(lc2, table->rte_paths)
|
foreach(lc2, table->rte_paths)
|
||||||
{
|
{
|
||||||
List *rte_path = lfirst(lc2);
|
List *rte_path = lfirst(lc2);
|
||||||
int i;
|
|
||||||
Query *querytree = rewritten;
|
Query *querytree = rewritten;
|
||||||
RangeTblEntry *rte;
|
RangeTblEntry *rte;
|
||||||
TupleDesc tupdesc_old;
|
TupleDesc tupdesc_old;
|
||||||
|
|
@ -1359,7 +1360,7 @@ get_prestate_rte(RangeTblEntry *rte, MV_TriggerTable *table,
|
||||||
{
|
{
|
||||||
StringInfoData str;
|
StringInfoData str;
|
||||||
RawStmt *raw;
|
RawStmt *raw;
|
||||||
Query *sub;
|
Query *subquery;
|
||||||
Relation rel;
|
Relation rel;
|
||||||
ParseState *pstate;
|
ParseState *pstate;
|
||||||
char *relname;
|
char *relname;
|
||||||
|
|
@ -1371,7 +1372,7 @@ get_prestate_rte(RangeTblEntry *rte, MV_TriggerTable *table,
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We can use NoLock here since AcquireRewriteLocks should
|
* We can use NoLock here since AcquireRewriteLocks should
|
||||||
* have locked the rel already.
|
* have locked the relation already.
|
||||||
*/
|
*/
|
||||||
rel = table_open(table->table_id, NoLock);
|
rel = table_open(table->table_id, NoLock);
|
||||||
relname = quote_qualified_identifier(
|
relname = quote_qualified_identifier(
|
||||||
|
|
@ -1379,12 +1380,19 @@ get_prestate_rte(RangeTblEntry *rte, MV_TriggerTable *table,
|
||||||
RelationGetRelationName(rel));
|
RelationGetRelationName(rel));
|
||||||
table_close(rel, NoLock);
|
table_close(rel, NoLock);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Filtering inserted row using the snapshot taken before the table
|
||||||
|
* is modified. ctid is required for maintaining outer join views.
|
||||||
|
*/
|
||||||
initStringInfo(&str);
|
initStringInfo(&str);
|
||||||
appendStringInfo(&str,
|
appendStringInfo(&str,
|
||||||
"SELECT t.* FROM %s t"
|
"SELECT t.* FROM %s t"
|
||||||
" WHERE pg_catalog.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)",
|
||||||
relname, matviewid);
|
relname, matviewid);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Append deleted rows contained in old transition tables.
|
||||||
|
*/
|
||||||
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 ");
|
||||||
|
|
@ -1392,20 +1400,21 @@ get_prestate_rte(RangeTblEntry *rte, MV_TriggerTable *table,
|
||||||
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 */
|
||||||
#if defined(PG_VERSION_NUM) && (PG_VERSION_NUM >= 140000)
|
#if defined(PG_VERSION_NUM) && (PG_VERSION_NUM >= 140000)
|
||||||
raw = (RawStmt*)linitial(raw_parser(str.data, RAW_PARSE_DEFAULT));
|
raw = (RawStmt*)linitial(raw_parser(str.data, RAW_PARSE_DEFAULT));
|
||||||
#else
|
#else
|
||||||
raw = (RawStmt*)linitial(raw_parser(str.data));
|
raw = (RawStmt*)linitial(raw_parser(str.data));
|
||||||
#endif
|
#endif
|
||||||
sub = transformStmt(pstate, raw->stmt);
|
subquery = transformStmt(pstate, raw->stmt);
|
||||||
|
|
||||||
/* save the original RTE */
|
/* save the original RTE */
|
||||||
table->original_rte = copyObject(rte);
|
table->original_rte = copyObject(rte);
|
||||||
|
|
||||||
rte->rtekind = RTE_SUBQUERY;
|
rte->rtekind = RTE_SUBQUERY;
|
||||||
rte->subquery = sub;
|
rte->subquery = subquery;
|
||||||
rte->security_barrier = false;
|
rte->security_barrier = false;
|
||||||
|
|
||||||
/* Clear fields that should not be set in a subquery RTE */
|
/* Clear fields that should not be set in a subquery RTE */
|
||||||
rte->relid = InvalidOid;
|
rte->relid = InvalidOid;
|
||||||
rte->relkind = 0;
|
rte->relkind = 0;
|
||||||
|
|
@ -1413,12 +1422,16 @@ get_prestate_rte(RangeTblEntry *rte, MV_TriggerTable *table,
|
||||||
rte->tablesample = NULL;
|
rte->tablesample = NULL;
|
||||||
rte->inh = false; /* must not be set for a subquery */
|
rte->inh = false; /* must not be set for a subquery */
|
||||||
|
|
||||||
|
#if defined(PG_VERSION_NUM) && (PG_VERSION_NUM >= 160000)
|
||||||
|
rte->perminfoindex = 0; /* no permission checking for this RTE */
|
||||||
|
#else
|
||||||
rte->requiredPerms = 0; /* no permission check on subquery itself */
|
rte->requiredPerms = 0; /* no permission check on subquery itself */
|
||||||
rte->checkAsUser = InvalidOid;
|
rte->checkAsUser = InvalidOid;
|
||||||
rte->selectedCols = NULL;
|
rte->selectedCols = NULL;
|
||||||
rte->insertedCols = NULL;
|
rte->insertedCols = NULL;
|
||||||
rte->updatedCols = NULL;
|
rte->updatedCols = NULL;
|
||||||
rte->extraUpdatedCols = NULL;
|
rte->extraUpdatedCols = NULL;
|
||||||
|
#endif
|
||||||
|
|
||||||
return rte;
|
return rte;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
4
pg_ivm.c
4
pg_ivm.c
|
|
@ -122,7 +122,11 @@ parseNameAndColumns(const char *string, List **names, List **colNames)
|
||||||
|
|
||||||
/* Separate the name and parse it into a list */
|
/* Separate the name and parse it into a list */
|
||||||
*ptr++ = '\0';
|
*ptr++ = '\0';
|
||||||
|
#if defined(PG_VERSION_NUM) && (PG_VERSION_NUM >= 160000)
|
||||||
|
*names = stringToQualifiedNameList(rawname, NULL);
|
||||||
|
#else
|
||||||
*names = stringToQualifiedNameList(rawname);
|
*names = stringToQualifiedNameList(rawname);
|
||||||
|
#endif
|
||||||
|
|
||||||
if (!has_colnames)
|
if (!has_colnames)
|
||||||
goto end;
|
goto end;
|
||||||
|
|
|
||||||
4
pg_ivm.h
4
pg_ivm.h
|
|
@ -38,8 +38,8 @@ extern bool isImmv(Oid immv_oid);
|
||||||
extern ObjectAddress ExecCreateImmv(ParseState *pstate, CreateTableAsStmt *stmt,
|
extern ObjectAddress ExecCreateImmv(ParseState *pstate, CreateTableAsStmt *stmt,
|
||||||
ParamListInfo params, QueryEnvironment *queryEnv,
|
ParamListInfo params, QueryEnvironment *queryEnv,
|
||||||
QueryCompletion *qc);
|
QueryCompletion *qc);
|
||||||
extern void CreateIvmTriggersOnBaseTables(Query *qry, Oid matviewOid, bool is_create);
|
extern void CreateIvmTriggersOnBaseTables(Query *qry, Oid matviewOid);
|
||||||
extern void CreateIndexOnIMMV(Query *query, Relation matviewRel, bool is_create);
|
extern void CreateIndexOnIMMV(Query *query, Relation matviewRel);
|
||||||
extern Query *rewriteQueryForIMMV(Query *query, List *colNames);
|
extern Query *rewriteQueryForIMMV(Query *query, List *colNames);
|
||||||
extern void makeIvmAggColumn(ParseState *pstate, Aggref *aggref, char *resname, AttrNumber *next_resno, List **aggs);
|
extern void makeIvmAggColumn(ParseState *pstate, Aggref *aggref, char *resname, AttrNumber *next_resno, List **aggs);
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue