Add UUID column to pg_ivm_immv.
This commit is contained in:
parent
38777f260a
commit
5a31d7a9ad
5 changed files with 169 additions and 54 deletions
89
createas.c
89
createas.c
|
|
@ -62,8 +62,8 @@ typedef struct
|
||||||
} DR_intorel;
|
} DR_intorel;
|
||||||
|
|
||||||
/* utility functions for IMMV definition creation */
|
/* utility functions for IMMV definition creation */
|
||||||
static ObjectAddress create_immv_internal(List *attrList, IntoClause *into);
|
static ImmvAddress create_immv_internal(List *attrList, IntoClause *into);
|
||||||
static ObjectAddress create_immv_nodata(List *tlist, IntoClause *into);
|
static ImmvAddress create_immv_nodata(List *tlist, IntoClause *into);
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
|
|
@ -74,15 +74,15 @@ typedef struct
|
||||||
int sublevels_up; /* (current) nesting depth */
|
int sublevels_up; /* (current) nesting depth */
|
||||||
} check_ivm_restriction_context;
|
} check_ivm_restriction_context;
|
||||||
|
|
||||||
static void CreateIvmTriggersOnBaseTablesRecurse(Query *qry, Node *node, Oid matviewOid,
|
static void CreateIvmTriggersOnBaseTablesRecurse(Query *qry, Node *node, ImmvAddress immv_addr,
|
||||||
Relids *relids, bool ex_lock);
|
Relids *relids, bool ex_lock);
|
||||||
static void CreateIvmTrigger(Oid relOid, Oid viewOid, int16 type, int16 timing, bool ex_lock);
|
static void CreateIvmTrigger(Oid relOid, ImmvAddress immv_addr, 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);
|
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, Query *viewQuery);
|
static void StoreImmvQuery(ImmvAddress immv_addr, Query *viewQuery);
|
||||||
|
|
||||||
#if defined(PG_VERSION_NUM) && (PG_VERSION_NUM < 140000)
|
#if defined(PG_VERSION_NUM) && (PG_VERSION_NUM < 140000)
|
||||||
static bool CreateTableAsRelExists(CreateTableAsStmt *ctas);
|
static bool CreateTableAsRelExists(CreateTableAsStmt *ctas);
|
||||||
|
|
@ -96,14 +96,15 @@ static bool CreateTableAsRelExists(CreateTableAsStmt *ctas);
|
||||||
*
|
*
|
||||||
* This imitates PostgreSQL's create_ctas_internal().
|
* This imitates PostgreSQL's create_ctas_internal().
|
||||||
*/
|
*/
|
||||||
static ObjectAddress
|
static ImmvAddress
|
||||||
create_immv_internal(List *attrList, IntoClause *into)
|
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;
|
||||||
static char *validnsps[] = HEAP_RELOPT_NAMESPACES;
|
static char *validnsps[] = HEAP_RELOPT_NAMESPACES;
|
||||||
ObjectAddress intoRelationAddr;
|
ImmvAddress immv_addr;
|
||||||
|
pg_uuid_t *immv_uuid;
|
||||||
|
|
||||||
/* This code supports both CREATE TABLE AS and CREATE MATERIALIZED VIEW */
|
/* This code supports both CREATE TABLE AS and CREATE MATERIALIZED VIEW */
|
||||||
/* relkind of IMMV must be RELKIND_RELATION */
|
/* relkind of IMMV must be RELKIND_RELATION */
|
||||||
|
|
@ -128,7 +129,12 @@ create_immv_internal(List *attrList, IntoClause *into)
|
||||||
* Create the relation. (This will error out if there's an existing view,
|
* Create the relation. (This will error out if there's an existing view,
|
||||||
* so we don't need more code to complain if "replace" is false.)
|
* so we don't need more code to complain if "replace" is false.)
|
||||||
*/
|
*/
|
||||||
intoRelationAddr = DefineRelation(create, relkind, InvalidOid, NULL, NULL);
|
immv_addr.address = DefineRelation(create, relkind, InvalidOid, NULL, NULL);
|
||||||
|
/* Generate the IMMV UUID. */
|
||||||
|
// TODO: check for hash collision
|
||||||
|
immv_uuid = DatumGetUUIDP(DirectFunctionCall1(gen_random_uuid, (Datum) NULL));
|
||||||
|
memcpy(&immv_addr.immv_uuid, immv_uuid, sizeof(*immv_uuid));
|
||||||
|
pfree(immv_uuid);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If necessary, create a TOAST table for the target table. Note that
|
* If necessary, create a TOAST table for the target table. Note that
|
||||||
|
|
@ -146,13 +152,13 @@ create_immv_internal(List *attrList, IntoClause *into)
|
||||||
|
|
||||||
(void) heap_reloptions(RELKIND_TOASTVALUE, toast_options, true);
|
(void) heap_reloptions(RELKIND_TOASTVALUE, toast_options, true);
|
||||||
|
|
||||||
NewRelationCreateToastTable(intoRelationAddr.objectId, toast_options);
|
NewRelationCreateToastTable(immv_addr.address.objectId, toast_options);
|
||||||
|
|
||||||
/* Create the "view" part of an IMMV. */
|
/* Create the "view" part of an IMMV. */
|
||||||
StoreImmvQuery(intoRelationAddr.objectId, (Query *) into->viewQuery);
|
StoreImmvQuery(immv_addr, (Query *) into->viewQuery);
|
||||||
CommandCounterIncrement();
|
CommandCounterIncrement();
|
||||||
|
|
||||||
return intoRelationAddr;
|
return immv_addr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -163,7 +169,7 @@ create_immv_internal(List *attrList, IntoClause *into)
|
||||||
*
|
*
|
||||||
* This imitates PostgreSQL's create_ctas_nodata().
|
* This imitates PostgreSQL's create_ctas_nodata().
|
||||||
*/
|
*/
|
||||||
static ObjectAddress
|
static ImmvAddress
|
||||||
create_immv_nodata(List *tlist, IntoClause *into)
|
create_immv_nodata(List *tlist, IntoClause *into)
|
||||||
{
|
{
|
||||||
List *attrList;
|
List *attrList;
|
||||||
|
|
@ -240,7 +246,7 @@ ExecCreateImmv(ParseState *pstate, CreateTableAsStmt *stmt,
|
||||||
Query *query = castNode(Query, stmt->query);
|
Query *query = castNode(Query, stmt->query);
|
||||||
IntoClause *into = stmt->into;
|
IntoClause *into = stmt->into;
|
||||||
bool do_refresh = false;
|
bool do_refresh = false;
|
||||||
ObjectAddress address;
|
ImmvAddress immv_addr;
|
||||||
|
|
||||||
/* Check if the relation exists or not */
|
/* Check if the relation exists or not */
|
||||||
if (CreateTableAsRelExists(stmt))
|
if (CreateTableAsRelExists(stmt))
|
||||||
|
|
@ -275,7 +281,7 @@ ExecCreateImmv(ParseState *pstate, CreateTableAsStmt *stmt,
|
||||||
* similar to CREATE VIEW. This avoids dump/restore problems stemming
|
* similar to CREATE VIEW. This avoids dump/restore problems stemming
|
||||||
* from running the planner before all dependencies are set up.
|
* from running the planner before all dependencies are set up.
|
||||||
*/
|
*/
|
||||||
address = create_immv_nodata(query->targetList, into);
|
immv_addr = create_immv_nodata(query->targetList, into);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* For materialized views, reuse the REFRESH logic, which locks down
|
* For materialized views, reuse the REFRESH logic, which locks down
|
||||||
|
|
@ -286,18 +292,18 @@ ExecCreateImmv(ParseState *pstate, CreateTableAsStmt *stmt,
|
||||||
{
|
{
|
||||||
Relation matviewRel;
|
Relation matviewRel;
|
||||||
|
|
||||||
RefreshImmvByOid(address.objectId, true, false, pstate->p_sourcetext, qc);
|
RefreshImmvByOid(immv_addr, true, false, pstate->p_sourcetext, qc);
|
||||||
|
|
||||||
if (qc)
|
if (qc)
|
||||||
qc->commandTag = CMDTAG_SELECT;
|
qc->commandTag = CMDTAG_SELECT;
|
||||||
|
|
||||||
matviewRel = table_open(address.objectId, NoLock);
|
matviewRel = table_open(immv_addr.address.objectId, NoLock);
|
||||||
|
|
||||||
/* 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 being changed */
|
||||||
CreateChangePreventTrigger(address.objectId);
|
CreateChangePreventTrigger(immv_addr.address.objectId);
|
||||||
|
|
||||||
table_close(matviewRel, NoLock);
|
table_close(matviewRel, NoLock);
|
||||||
|
|
||||||
|
|
@ -309,7 +315,7 @@ ExecCreateImmv(ParseState *pstate, CreateTableAsStmt *stmt,
|
||||||
"or execute refresh_immv to make sure the view is consistent.")));
|
"or execute refresh_immv to make sure the view is consistent.")));
|
||||||
}
|
}
|
||||||
|
|
||||||
return address;
|
return immv_addr.address;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -548,7 +554,7 @@ 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)
|
CreateIvmTriggersOnBaseTables(Query *qry, ImmvAddress immv_addr)
|
||||||
{
|
{
|
||||||
Relids relids = NULL;
|
Relids relids = NULL;
|
||||||
bool ex_lock = false;
|
bool ex_lock = false;
|
||||||
|
|
@ -582,13 +588,13 @@ CreateIvmTriggersOnBaseTables(Query *qry, Oid matviewOid)
|
||||||
qry->distinctClause || (qry->hasAggs && qry->groupClause))
|
qry->distinctClause || (qry->hasAggs && qry->groupClause))
|
||||||
ex_lock = true;
|
ex_lock = true;
|
||||||
|
|
||||||
CreateIvmTriggersOnBaseTablesRecurse(qry, (Node *)qry, matviewOid, &relids, ex_lock);
|
CreateIvmTriggersOnBaseTablesRecurse(qry, (Node *)qry, immv_addr, &relids, ex_lock);
|
||||||
|
|
||||||
bms_free(relids);
|
bms_free(relids);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
CreateIvmTriggersOnBaseTablesRecurse(Query *qry, Node *node, Oid matviewOid,
|
CreateIvmTriggersOnBaseTablesRecurse(Query *qry, Node *node, ImmvAddress immv_addr,
|
||||||
Relids *relids, bool ex_lock)
|
Relids *relids, bool ex_lock)
|
||||||
{
|
{
|
||||||
if (node == NULL)
|
if (node == NULL)
|
||||||
|
|
@ -604,12 +610,12 @@ CreateIvmTriggersOnBaseTablesRecurse(Query *qry, Node *node, Oid matviewOid,
|
||||||
Query *query = (Query *) node;
|
Query *query = (Query *) node;
|
||||||
ListCell *lc;
|
ListCell *lc;
|
||||||
|
|
||||||
CreateIvmTriggersOnBaseTablesRecurse(qry, (Node *) query->jointree, matviewOid, relids, ex_lock);
|
CreateIvmTriggersOnBaseTablesRecurse(qry, (Node *) query->jointree, immv_addr, relids, ex_lock);
|
||||||
foreach(lc, query->cteList)
|
foreach(lc, query->cteList)
|
||||||
{
|
{
|
||||||
CommonTableExpr *cte = (CommonTableExpr *) lfirst(lc);
|
CommonTableExpr *cte = (CommonTableExpr *) lfirst(lc);
|
||||||
Assert(IsA(cte->ctequery, Query));
|
Assert(IsA(cte->ctequery, Query));
|
||||||
CreateIvmTriggersOnBaseTablesRecurse((Query *) cte->ctequery, cte->ctequery, matviewOid, relids, ex_lock);
|
CreateIvmTriggersOnBaseTablesRecurse((Query *) cte->ctequery, cte->ctequery, immv_addr, relids, ex_lock);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
@ -621,14 +627,14 @@ CreateIvmTriggersOnBaseTablesRecurse(Query *qry, Node *node, Oid matviewOid,
|
||||||
|
|
||||||
if (rte->rtekind == RTE_RELATION && !bms_is_member(rte->relid, *relids))
|
if (rte->rtekind == RTE_RELATION && !bms_is_member(rte->relid, *relids))
|
||||||
{
|
{
|
||||||
CreateIvmTrigger(rte->relid, matviewOid, TRIGGER_TYPE_INSERT, TRIGGER_TYPE_BEFORE, ex_lock);
|
CreateIvmTrigger(rte->relid, immv_addr, TRIGGER_TYPE_INSERT, TRIGGER_TYPE_BEFORE, ex_lock);
|
||||||
CreateIvmTrigger(rte->relid, matviewOid, TRIGGER_TYPE_DELETE, TRIGGER_TYPE_BEFORE, ex_lock);
|
CreateIvmTrigger(rte->relid, immv_addr, TRIGGER_TYPE_DELETE, TRIGGER_TYPE_BEFORE, ex_lock);
|
||||||
CreateIvmTrigger(rte->relid, matviewOid, TRIGGER_TYPE_UPDATE, TRIGGER_TYPE_BEFORE, ex_lock);
|
CreateIvmTrigger(rte->relid, immv_addr, TRIGGER_TYPE_UPDATE, TRIGGER_TYPE_BEFORE, ex_lock);
|
||||||
CreateIvmTrigger(rte->relid, matviewOid, TRIGGER_TYPE_TRUNCATE, TRIGGER_TYPE_BEFORE, true);
|
CreateIvmTrigger(rte->relid, immv_addr, TRIGGER_TYPE_TRUNCATE, TRIGGER_TYPE_BEFORE, true);
|
||||||
CreateIvmTrigger(rte->relid, matviewOid, TRIGGER_TYPE_INSERT, TRIGGER_TYPE_AFTER, ex_lock);
|
CreateIvmTrigger(rte->relid, immv_addr, TRIGGER_TYPE_INSERT, TRIGGER_TYPE_AFTER, ex_lock);
|
||||||
CreateIvmTrigger(rte->relid, matviewOid, TRIGGER_TYPE_DELETE, TRIGGER_TYPE_AFTER, ex_lock);
|
CreateIvmTrigger(rte->relid, immv_addr, TRIGGER_TYPE_DELETE, TRIGGER_TYPE_AFTER, ex_lock);
|
||||||
CreateIvmTrigger(rte->relid, matviewOid, TRIGGER_TYPE_UPDATE, TRIGGER_TYPE_AFTER, ex_lock);
|
CreateIvmTrigger(rte->relid, immv_addr, TRIGGER_TYPE_UPDATE, TRIGGER_TYPE_AFTER, ex_lock);
|
||||||
CreateIvmTrigger(rte->relid, matviewOid, TRIGGER_TYPE_TRUNCATE, TRIGGER_TYPE_AFTER, true);
|
CreateIvmTrigger(rte->relid, immv_addr, TRIGGER_TYPE_TRUNCATE, TRIGGER_TYPE_AFTER, true);
|
||||||
|
|
||||||
*relids = bms_add_member(*relids, rte->relid);
|
*relids = bms_add_member(*relids, rte->relid);
|
||||||
}
|
}
|
||||||
|
|
@ -636,7 +642,7 @@ CreateIvmTriggersOnBaseTablesRecurse(Query *qry, Node *node, Oid matviewOid,
|
||||||
{
|
{
|
||||||
Query *subquery = rte->subquery;
|
Query *subquery = rte->subquery;
|
||||||
Assert(rte->subquery != NULL);
|
Assert(rte->subquery != NULL);
|
||||||
CreateIvmTriggersOnBaseTablesRecurse(subquery, (Node *) subquery, matviewOid, relids, ex_lock);
|
CreateIvmTriggersOnBaseTablesRecurse(subquery, (Node *) subquery, immv_addr, relids, ex_lock);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
@ -647,7 +653,7 @@ CreateIvmTriggersOnBaseTablesRecurse(Query *qry, Node *node, Oid matviewOid,
|
||||||
ListCell *l;
|
ListCell *l;
|
||||||
|
|
||||||
foreach(l, f->fromlist)
|
foreach(l, f->fromlist)
|
||||||
CreateIvmTriggersOnBaseTablesRecurse(qry, lfirst(l), matviewOid, relids, ex_lock);
|
CreateIvmTriggersOnBaseTablesRecurse(qry, lfirst(l), immv_addr, relids, ex_lock);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
@ -655,8 +661,8 @@ CreateIvmTriggersOnBaseTablesRecurse(Query *qry, Node *node, Oid matviewOid,
|
||||||
{
|
{
|
||||||
JoinExpr *j = (JoinExpr *) node;
|
JoinExpr *j = (JoinExpr *) node;
|
||||||
|
|
||||||
CreateIvmTriggersOnBaseTablesRecurse(qry, j->larg, matviewOid, relids, ex_lock);
|
CreateIvmTriggersOnBaseTablesRecurse(qry, j->larg, immv_addr, relids, ex_lock);
|
||||||
CreateIvmTriggersOnBaseTablesRecurse(qry, j->rarg, matviewOid, relids, ex_lock);
|
CreateIvmTriggersOnBaseTablesRecurse(qry, j->rarg, immv_addr, relids, ex_lock);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
@ -669,7 +675,7 @@ CreateIvmTriggersOnBaseTablesRecurse(Query *qry, Node *node, Oid matviewOid,
|
||||||
* CreateIvmTrigger -- create IVM trigger on a base table
|
* CreateIvmTrigger -- create IVM trigger on a base table
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
CreateIvmTrigger(Oid relOid, Oid viewOid, int16 type, int16 timing, bool ex_lock)
|
CreateIvmTrigger(Oid relOid, ImmvAddress immv_addr, int16 type, int16 timing, bool ex_lock)
|
||||||
{
|
{
|
||||||
ObjectAddress refaddr;
|
ObjectAddress refaddr;
|
||||||
ObjectAddress address;
|
ObjectAddress address;
|
||||||
|
|
@ -679,7 +685,7 @@ CreateIvmTrigger(Oid relOid, Oid viewOid, int16 type, int16 timing, bool ex_lock
|
||||||
Assert(timing == TRIGGER_TYPE_BEFORE || timing == TRIGGER_TYPE_AFTER);
|
Assert(timing == TRIGGER_TYPE_BEFORE || timing == TRIGGER_TYPE_AFTER);
|
||||||
|
|
||||||
refaddr.classId = RelationRelationId;
|
refaddr.classId = RelationRelationId;
|
||||||
refaddr.objectId = viewOid;
|
refaddr.objectId = immv_addr.address.objectId;
|
||||||
refaddr.objectSubId = 0;
|
refaddr.objectSubId = 0;
|
||||||
|
|
||||||
ivm_trigger = makeNode(CreateTrigStmt);
|
ivm_trigger = makeNode(CreateTrigStmt);
|
||||||
|
|
@ -753,7 +759,7 @@ CreateIvmTrigger(Oid relOid, Oid viewOid, int16 type, int16 timing, bool ex_lock
|
||||||
ivm_trigger->initdeferred = false;
|
ivm_trigger->initdeferred = false;
|
||||||
ivm_trigger->constrrel = NULL;
|
ivm_trigger->constrrel = NULL;
|
||||||
ivm_trigger->args = list_make2(
|
ivm_trigger->args = list_make2(
|
||||||
makeString(DatumGetPointer(DirectFunctionCall1(oidout, ObjectIdGetDatum(viewOid)))),
|
makeString(DatumGetPointer(UUIDPGetDatum(&immv_addr.immv_uuid))),
|
||||||
makeString(DatumGetPointer(DirectFunctionCall1(boolout, BoolGetDatum(ex_lock))))
|
makeString(DatumGetPointer(DirectFunctionCall1(boolout, BoolGetDatum(ex_lock))))
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -1708,7 +1714,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_ivm_immv
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
StoreImmvQuery(Oid viewOid, Query *viewQuery)
|
StoreImmvQuery(ImmvAddress immv_addr, Query *viewQuery)
|
||||||
{
|
{
|
||||||
char *querytree = nodeToString((Node *) viewQuery);
|
char *querytree = nodeToString((Node *) viewQuery);
|
||||||
char *querystring;
|
char *querystring;
|
||||||
|
|
@ -1736,10 +1742,11 @@ StoreImmvQuery(Oid viewOid, Query *viewQuery)
|
||||||
memset(values, 0, sizeof(values));
|
memset(values, 0, sizeof(values));
|
||||||
memset(isNulls, false, sizeof(isNulls));
|
memset(isNulls, false, sizeof(isNulls));
|
||||||
|
|
||||||
values[Anum_pg_ivm_immv_immvrelid -1 ] = ObjectIdGetDatum(viewOid);
|
values[Anum_pg_ivm_immv_immvrelid -1 ] = ObjectIdGetDatum(immv_addr.address.objectId);
|
||||||
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);
|
||||||
values[Anum_pg_ivm_immv_querystring - 1] = CStringGetTextDatum(querystring);
|
values[Anum_pg_ivm_immv_querystring - 1] = CStringGetTextDatum(querystring);
|
||||||
|
values[Anum_pg_ivm_immv_immvuuid -1 ] = UUIDPGetDatum(&immv_addr.immv_uuid);
|
||||||
|
|
||||||
pgIvmImmv = table_open(PgIvmImmvRelationId(), RowExclusiveLock);
|
pgIvmImmv = table_open(PgIvmImmvRelationId(), RowExclusiveLock);
|
||||||
|
|
||||||
|
|
@ -1749,7 +1756,7 @@ StoreImmvQuery(Oid viewOid, Query *viewQuery)
|
||||||
CatalogTupleInsert(pgIvmImmv, heapTuple);
|
CatalogTupleInsert(pgIvmImmv, heapTuple);
|
||||||
|
|
||||||
address.classId = RelationRelationId;
|
address.classId = RelationRelationId;
|
||||||
address.objectId = viewOid;
|
address.objectId = immv_addr.address.objectId;
|
||||||
address.objectSubId = 0;
|
address.objectSubId = 0;
|
||||||
|
|
||||||
recordDependencyOnExpr(&address, (Node *) viewQuery, NIL,
|
recordDependencyOnExpr(&address, (Node *) viewQuery, NIL,
|
||||||
|
|
|
||||||
29
matview.c
29
matview.c
|
|
@ -50,6 +50,7 @@
|
||||||
#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/uuid.h"
|
||||||
#include "utils/xid8.h"
|
#include "utils/xid8.h"
|
||||||
|
|
||||||
#include "pg_ivm.h"
|
#include "pg_ivm.h"
|
||||||
|
|
@ -251,6 +252,7 @@ ExecRefreshImmv(const RangeVar *relation, bool skipData,
|
||||||
{
|
{
|
||||||
Oid matviewOid;
|
Oid matviewOid;
|
||||||
LOCKMODE lockmode;
|
LOCKMODE lockmode;
|
||||||
|
ImmvAddress immv_addr;
|
||||||
|
|
||||||
/* Determine strength of lock needed. */
|
/* Determine strength of lock needed. */
|
||||||
//concurrent = stmt->concurrent;
|
//concurrent = stmt->concurrent;
|
||||||
|
|
@ -272,7 +274,12 @@ ExecRefreshImmv(const RangeVar *relation, bool skipData,
|
||||||
NULL);
|
NULL);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return RefreshImmvByOid(matviewOid, false, skipData, queryString, qc);
|
immv_addr.address.classId = RelationRelationId;
|
||||||
|
immv_addr.address.objectId = matviewOid;
|
||||||
|
immv_addr.address.objectSubId = 0;
|
||||||
|
|
||||||
|
// TODO: get uuid
|
||||||
|
return RefreshImmvByOid(immv_addr, false, skipData, queryString, qc);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -283,7 +290,7 @@ ExecRefreshImmv(const RangeVar *relation, bool skipData,
|
||||||
* This imitates PostgreSQL's RefreshMatViewByOid().
|
* This imitates PostgreSQL's RefreshMatViewByOid().
|
||||||
*/
|
*/
|
||||||
ObjectAddress
|
ObjectAddress
|
||||||
RefreshImmvByOid(Oid matviewOid, bool is_create, bool skipData,
|
RefreshImmvByOid(ImmvAddress immv_addr, bool is_create, bool skipData,
|
||||||
const char *queryString, QueryCompletion *qc)
|
const char *queryString, QueryCompletion *qc)
|
||||||
{
|
{
|
||||||
Relation matviewRel;
|
Relation matviewRel;
|
||||||
|
|
@ -300,6 +307,7 @@ RefreshImmvByOid(Oid matviewOid, bool is_create, bool skipData,
|
||||||
int save_nestlevel;
|
int save_nestlevel;
|
||||||
ObjectAddress address;
|
ObjectAddress address;
|
||||||
bool oldPopulated;
|
bool oldPopulated;
|
||||||
|
Oid matviewOid = immv_addr.address.objectId;
|
||||||
|
|
||||||
Relation pgIvmImmv;
|
Relation pgIvmImmv;
|
||||||
TupleDesc tupdesc;
|
TupleDesc tupdesc;
|
||||||
|
|
@ -486,10 +494,7 @@ RefreshImmvByOid(Oid matviewOid, bool is_create, bool skipData,
|
||||||
* is created.
|
* is created.
|
||||||
*/
|
*/
|
||||||
if (!skipData && !oldPopulated)
|
if (!skipData && !oldPopulated)
|
||||||
{
|
CreateIvmTriggersOnBaseTables(dataQuery, immv_addr);
|
||||||
CreateIvmTriggersOnBaseTables(dataQuery, matviewOid);
|
|
||||||
CreateChangePreventTrigger(matviewOid);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Create the transient table that will receive the regenerated data. Lock
|
* Create the transient table that will receive the regenerated data. Lock
|
||||||
|
|
@ -844,15 +849,17 @@ Datum
|
||||||
IVM_immediate_before(PG_FUNCTION_ARGS)
|
IVM_immediate_before(PG_FUNCTION_ARGS)
|
||||||
{
|
{
|
||||||
TriggerData *trigdata = (TriggerData *) fcinfo->context;
|
TriggerData *trigdata = (TriggerData *) fcinfo->context;
|
||||||
char *matviewOid_text = trigdata->tg_trigger->tgargs[0];
|
char *immv_uuid_text = trigdata->tg_trigger->tgargs[0];
|
||||||
char *ex_lock_text = trigdata->tg_trigger->tgargs[1];
|
char *ex_lock_text = trigdata->tg_trigger->tgargs[1];
|
||||||
|
pg_uuid_t *immv_uuid;
|
||||||
Oid matviewOid;
|
Oid matviewOid;
|
||||||
MV_TriggerHashEntry *entry;
|
MV_TriggerHashEntry *entry;
|
||||||
bool found;
|
bool found;
|
||||||
bool ex_lock;
|
bool ex_lock;
|
||||||
|
|
||||||
matviewOid = DatumGetObjectId(DirectFunctionCall1(oidin, CStringGetDatum(matviewOid_text)));
|
immv_uuid = DatumGetUUIDP(CStringGetDatum(immv_uuid_text));
|
||||||
ex_lock = DatumGetBool(DirectFunctionCall1(boolin, CStringGetDatum(ex_lock_text)));
|
ex_lock = DatumGetBool(DirectFunctionCall1(boolin, CStringGetDatum(ex_lock_text)));
|
||||||
|
matviewOid = GetImmvRelid(immv_uuid);
|
||||||
|
|
||||||
/* 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)
|
||||||
|
|
@ -967,10 +974,11 @@ IVM_immediate_maintenance(PG_FUNCTION_ARGS)
|
||||||
Oid matviewOid;
|
Oid matviewOid;
|
||||||
Query *query;
|
Query *query;
|
||||||
Query *rewritten = NULL;
|
Query *rewritten = NULL;
|
||||||
char *matviewOid_text = trigdata->tg_trigger->tgargs[0];
|
char *immv_uuid_text = trigdata->tg_trigger->tgargs[0];
|
||||||
Relation matviewRel;
|
Relation matviewRel;
|
||||||
int old_depth = immv_maintenance_depth;
|
int old_depth = immv_maintenance_depth;
|
||||||
SubTransactionId subxid;
|
SubTransactionId subxid;
|
||||||
|
pg_uuid_t *immv_uuid;
|
||||||
|
|
||||||
Oid relowner;
|
Oid relowner;
|
||||||
Tuplestorestate *old_tuplestore = NULL;
|
Tuplestorestate *old_tuplestore = NULL;
|
||||||
|
|
@ -998,7 +1006,8 @@ IVM_immediate_maintenance(PG_FUNCTION_ARGS)
|
||||||
rel = trigdata->tg_relation;
|
rel = trigdata->tg_relation;
|
||||||
relid = rel->rd_id;
|
relid = rel->rd_id;
|
||||||
|
|
||||||
matviewOid = DatumGetObjectId(DirectFunctionCall1(oidin, CStringGetDatum(matviewOid_text)));
|
immv_uuid = DatumGetUUIDP(CStringGetDatum(immv_uuid_text));
|
||||||
|
matviewOid = GetImmvRelid(immv_uuid);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* On the first call initialize the hashtable
|
* On the first call initialize the hashtable
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,6 @@
|
||||||
ALTER TABLE pgivm.pg_ivm_immv ADD COLUMN querystring text NOT NULL;
|
ALTER TABLE pgivm.pg_ivm_immv ADD COLUMN querystring text NOT NULL;
|
||||||
|
ALTER TABLE pgivm.pg_ivm_immv ADD COLUMN immvuuid uuid NOT NULL;
|
||||||
|
ALTER TABLE pgivm.pg_ivm_immv ADD CONSTRAINT pg_ivm_immv_uuid UNIQUE (immvuuid);
|
||||||
|
|
||||||
CREATE FUNCTION pgivm.recreate_all_immvs() RETURNS VOID LANGUAGE PLPGSQL AS
|
CREATE FUNCTION pgivm.recreate_all_immvs() RETURNS VOID LANGUAGE PLPGSQL AS
|
||||||
$$
|
$$
|
||||||
|
|
|
||||||
86
pg_ivm.c
86
pg_ivm.c
|
|
@ -32,6 +32,7 @@
|
||||||
#include "utils/lsyscache.h"
|
#include "utils/lsyscache.h"
|
||||||
#include "utils/regproc.h"
|
#include "utils/regproc.h"
|
||||||
#include "utils/rel.h"
|
#include "utils/rel.h"
|
||||||
|
#include "utils/uuid.h"
|
||||||
#include "utils/varlena.h"
|
#include "utils/varlena.h"
|
||||||
|
|
||||||
#include "pg_ivm.h"
|
#include "pg_ivm.h"
|
||||||
|
|
@ -365,6 +366,17 @@ PgIvmImmvPrimaryKeyIndexId(void)
|
||||||
AccessShareLock, true);
|
AccessShareLock, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Get relid of pg_ivm_immv's UUID unique key.
|
||||||
|
*/
|
||||||
|
Oid
|
||||||
|
PgIvmImmvUuidIndexId(void)
|
||||||
|
{
|
||||||
|
return RangeVarGetRelid(
|
||||||
|
makeRangeVar("pgivm", "pg_ivm_immv_uuid", -1),
|
||||||
|
AccessShareLock, true);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Return the SELECT part of an IMMV
|
* Return the SELECT part of an IMMV
|
||||||
*/
|
*/
|
||||||
|
|
@ -488,3 +500,77 @@ RestrictSearchPath(void)
|
||||||
PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false);
|
PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* GetImmvOid
|
||||||
|
*
|
||||||
|
* Look up the immvrelid of an IMMV from its immv_uuid.
|
||||||
|
*/
|
||||||
|
Oid
|
||||||
|
GetImmvRelid(pg_uuid_t *immv_uuid)
|
||||||
|
{
|
||||||
|
Datum datum;
|
||||||
|
HeapTuple tup;
|
||||||
|
Relation pgIvmImmv = table_open(PgIvmImmvRelationId(), AccessShareLock);
|
||||||
|
ScanKeyData key;
|
||||||
|
SysScanDesc scan;
|
||||||
|
TupleDesc tupdesc = RelationGetDescr(pgIvmImmv);
|
||||||
|
bool isnull;
|
||||||
|
|
||||||
|
ScanKeyInit(&key, Anum_pg_ivm_immv_immvuuid, BTEqualStrategyNumber,
|
||||||
|
F_UUID_EQ, UUIDPGetDatum(immv_uuid));
|
||||||
|
scan = systable_beginscan(pgIvmImmv, PgIvmImmvUuidIndexId(), true, NULL, 1,
|
||||||
|
&key);
|
||||||
|
tup = systable_getnext(scan);
|
||||||
|
|
||||||
|
if (!HeapTupleIsValid(tup))
|
||||||
|
{
|
||||||
|
systable_endscan(scan);
|
||||||
|
table_close(pgIvmImmv, NoLock);
|
||||||
|
return InvalidOid;
|
||||||
|
}
|
||||||
|
|
||||||
|
datum = heap_getattr(tup, Anum_pg_ivm_immv_immvrelid, tupdesc, &isnull);
|
||||||
|
Assert(!isnull);
|
||||||
|
|
||||||
|
systable_endscan(scan);
|
||||||
|
table_close(pgIvmImmv, NoLock);
|
||||||
|
return DatumGetObjectId(datum);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* GetImmvUuid
|
||||||
|
*
|
||||||
|
* Look up the immv_uuid of an IMMV from its immvrelid.
|
||||||
|
*/
|
||||||
|
pg_uuid_t *
|
||||||
|
GetImmvUuid(Oid immvrelid)
|
||||||
|
{
|
||||||
|
Datum datum;
|
||||||
|
HeapTuple tup;
|
||||||
|
Relation pgIvmImmv = table_open(PgIvmImmvRelationId(), AccessShareLock);
|
||||||
|
ScanKeyData key;
|
||||||
|
SysScanDesc scan;
|
||||||
|
TupleDesc tupdesc = RelationGetDescr(pgIvmImmv);
|
||||||
|
bool isnull;
|
||||||
|
|
||||||
|
ScanKeyInit(&key, Anum_pg_ivm_immv_immvrelid, BTEqualStrategyNumber, F_OIDEQ,
|
||||||
|
ObjectIdGetDatum(immvrelid));
|
||||||
|
scan = systable_beginscan(pgIvmImmv, PgIvmImmvPrimaryKeyIndexId(),
|
||||||
|
true, NULL, 1, &key);
|
||||||
|
tup = systable_getnext(scan);
|
||||||
|
|
||||||
|
if (!HeapTupleIsValid(tup))
|
||||||
|
{
|
||||||
|
systable_endscan(scan);
|
||||||
|
table_close(pgIvmImmv, NoLock);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
datum = heap_getattr(tup, Anum_pg_ivm_immv_immvuuid, tupdesc, &isnull);
|
||||||
|
Assert(!isnull);
|
||||||
|
|
||||||
|
systable_endscan(scan);
|
||||||
|
table_close(pgIvmImmv, NoLock);
|
||||||
|
return DatumGetUUIDP(datum);
|
||||||
|
}
|
||||||
|
|
|
||||||
17
pg_ivm.h
17
pg_ivm.h
|
|
@ -19,30 +19,41 @@
|
||||||
#include "parser/parse_node.h"
|
#include "parser/parse_node.h"
|
||||||
#include "tcop/dest.h"
|
#include "tcop/dest.h"
|
||||||
#include "utils/queryenvironment.h"
|
#include "utils/queryenvironment.h"
|
||||||
|
#include "utils/uuid.h"
|
||||||
|
|
||||||
#define Natts_pg_ivm_immv 5
|
#define Natts_pg_ivm_immv 6
|
||||||
|
|
||||||
#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
|
#define Anum_pg_ivm_immv_lastivmupdate 4
|
||||||
#define Anum_pg_ivm_immv_querystring 5
|
#define Anum_pg_ivm_immv_querystring 5
|
||||||
|
#define Anum_pg_ivm_immv_immvuuid 6
|
||||||
|
|
||||||
|
typedef struct ImmvAddress
|
||||||
|
{
|
||||||
|
ObjectAddress address;
|
||||||
|
pg_uuid_t immv_uuid;
|
||||||
|
} ImmvAddress;
|
||||||
|
|
||||||
/* pg_ivm.c */
|
/* pg_ivm.c */
|
||||||
|
|
||||||
extern void CreateChangePreventTrigger(Oid matviewOid);
|
extern void CreateChangePreventTrigger(Oid matviewOid);
|
||||||
extern Oid PgIvmImmvRelationId(void);
|
extern Oid PgIvmImmvRelationId(void);
|
||||||
extern Oid PgIvmImmvPrimaryKeyIndexId(void);
|
extern Oid PgIvmImmvPrimaryKeyIndexId(void);
|
||||||
|
extern Oid PgIvmImmvUuidIndexId(void);
|
||||||
extern bool isImmv(Oid immv_oid);
|
extern bool isImmv(Oid immv_oid);
|
||||||
extern List *PgIvmFuncName(char *name);
|
extern List *PgIvmFuncName(char *name);
|
||||||
extern void parse_immv_query(const char *relname, const char *sql,
|
extern void parse_immv_query(const char *relname, const char *sql,
|
||||||
Query **query_ret, ParseState **pstate_ret);
|
Query **query_ret, ParseState **pstate_ret);
|
||||||
|
extern Oid GetImmvRelid(pg_uuid_t *immv_uuid);
|
||||||
|
extern pg_uuid_t *GetImmvUuid(Oid immvrelid);
|
||||||
|
|
||||||
/* createas.c */
|
/* createas.c */
|
||||||
|
|
||||||
extern ObjectAddress ExecCreateImmv(ParseState *pstate, CreateTableAsStmt *stmt,
|
extern ObjectAddress ExecCreateImmv(ParseState *pstate, CreateTableAsStmt *stmt,
|
||||||
QueryCompletion *qc);
|
QueryCompletion *qc);
|
||||||
extern void CreateIvmTriggersOnBaseTables(Query *qry, Oid matviewOid);
|
extern void CreateIvmTriggersOnBaseTables(Query *qry, ImmvAddress immv_addr);
|
||||||
extern void CreateIndexOnIMMV(Query *query, Relation matviewRel);
|
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);
|
||||||
|
|
@ -52,7 +63,7 @@ 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(ImmvAddress immv_addr, bool is_create, bool skipData,
|
||||||
const char *queryString, QueryCompletion *qc);
|
const char *queryString, QueryCompletion *qc);
|
||||||
extern bool ImmvIncrementalMaintenanceIsEnabled(void);
|
extern bool ImmvIncrementalMaintenanceIsEnabled(void);
|
||||||
extern Datum IVM_immediate_before(PG_FUNCTION_ARGS);
|
extern Datum IVM_immediate_before(PG_FUNCTION_ARGS);
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue