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;
|
||||
|
||||
/* utility functions for IMMV definition creation */
|
||||
static ObjectAddress create_immv_internal(List *attrList, IntoClause *into);
|
||||
static ObjectAddress create_immv_nodata(List *tlist, IntoClause *into);
|
||||
static ImmvAddress create_immv_internal(List *attrList, IntoClause *into);
|
||||
static ImmvAddress create_immv_nodata(List *tlist, IntoClause *into);
|
||||
|
||||
typedef struct
|
||||
{
|
||||
|
|
@ -74,15 +74,15 @@ typedef struct
|
|||
int sublevels_up; /* (current) nesting depth */
|
||||
} 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);
|
||||
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 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 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)
|
||||
static bool CreateTableAsRelExists(CreateTableAsStmt *ctas);
|
||||
|
|
@ -96,14 +96,15 @@ static bool CreateTableAsRelExists(CreateTableAsStmt *ctas);
|
|||
*
|
||||
* This imitates PostgreSQL's create_ctas_internal().
|
||||
*/
|
||||
static ObjectAddress
|
||||
static ImmvAddress
|
||||
create_immv_internal(List *attrList, IntoClause *into)
|
||||
{
|
||||
CreateStmt *create = makeNode(CreateStmt);
|
||||
char relkind;
|
||||
Datum toast_options;
|
||||
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 */
|
||||
/* 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,
|
||||
* 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
|
||||
|
|
@ -146,13 +152,13 @@ create_immv_internal(List *attrList, IntoClause *into)
|
|||
|
||||
(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. */
|
||||
StoreImmvQuery(intoRelationAddr.objectId, (Query *) into->viewQuery);
|
||||
StoreImmvQuery(immv_addr, (Query *) into->viewQuery);
|
||||
CommandCounterIncrement();
|
||||
|
||||
return intoRelationAddr;
|
||||
return immv_addr;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -163,7 +169,7 @@ create_immv_internal(List *attrList, IntoClause *into)
|
|||
*
|
||||
* This imitates PostgreSQL's create_ctas_nodata().
|
||||
*/
|
||||
static ObjectAddress
|
||||
static ImmvAddress
|
||||
create_immv_nodata(List *tlist, IntoClause *into)
|
||||
{
|
||||
List *attrList;
|
||||
|
|
@ -240,7 +246,7 @@ ExecCreateImmv(ParseState *pstate, CreateTableAsStmt *stmt,
|
|||
Query *query = castNode(Query, stmt->query);
|
||||
IntoClause *into = stmt->into;
|
||||
bool do_refresh = false;
|
||||
ObjectAddress address;
|
||||
ImmvAddress immv_addr;
|
||||
|
||||
/* Check if the relation exists or not */
|
||||
if (CreateTableAsRelExists(stmt))
|
||||
|
|
@ -275,7 +281,7 @@ ExecCreateImmv(ParseState *pstate, CreateTableAsStmt *stmt,
|
|||
* similar to CREATE VIEW. This avoids dump/restore problems stemming
|
||||
* 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
|
||||
|
|
@ -286,18 +292,18 @@ ExecCreateImmv(ParseState *pstate, CreateTableAsStmt *stmt,
|
|||
{
|
||||
Relation matviewRel;
|
||||
|
||||
RefreshImmvByOid(address.objectId, true, false, pstate->p_sourcetext, qc);
|
||||
RefreshImmvByOid(immv_addr, true, false, pstate->p_sourcetext, qc);
|
||||
|
||||
if (qc)
|
||||
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 */
|
||||
CreateIndexOnIMMV(query, matviewRel);
|
||||
|
||||
/* Create triggers to prevent IMMV from being changed */
|
||||
CreateChangePreventTrigger(address.objectId);
|
||||
CreateChangePreventTrigger(immv_addr.address.objectId);
|
||||
|
||||
table_close(matviewRel, NoLock);
|
||||
|
||||
|
|
@ -309,7 +315,7 @@ ExecCreateImmv(ParseState *pstate, CreateTableAsStmt *stmt,
|
|||
"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
|
||||
*/
|
||||
void
|
||||
CreateIvmTriggersOnBaseTables(Query *qry, Oid matviewOid)
|
||||
CreateIvmTriggersOnBaseTables(Query *qry, ImmvAddress immv_addr)
|
||||
{
|
||||
Relids relids = NULL;
|
||||
bool ex_lock = false;
|
||||
|
|
@ -582,13 +588,13 @@ CreateIvmTriggersOnBaseTables(Query *qry, Oid matviewOid)
|
|||
qry->distinctClause || (qry->hasAggs && qry->groupClause))
|
||||
ex_lock = true;
|
||||
|
||||
CreateIvmTriggersOnBaseTablesRecurse(qry, (Node *)qry, matviewOid, &relids, ex_lock);
|
||||
CreateIvmTriggersOnBaseTablesRecurse(qry, (Node *)qry, immv_addr, &relids, ex_lock);
|
||||
|
||||
bms_free(relids);
|
||||
}
|
||||
|
||||
static void
|
||||
CreateIvmTriggersOnBaseTablesRecurse(Query *qry, Node *node, Oid matviewOid,
|
||||
CreateIvmTriggersOnBaseTablesRecurse(Query *qry, Node *node, ImmvAddress immv_addr,
|
||||
Relids *relids, bool ex_lock)
|
||||
{
|
||||
if (node == NULL)
|
||||
|
|
@ -604,12 +610,12 @@ CreateIvmTriggersOnBaseTablesRecurse(Query *qry, Node *node, Oid matviewOid,
|
|||
Query *query = (Query *) node;
|
||||
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)
|
||||
{
|
||||
CommonTableExpr *cte = (CommonTableExpr *) lfirst(lc);
|
||||
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;
|
||||
|
|
@ -621,14 +627,14 @@ CreateIvmTriggersOnBaseTablesRecurse(Query *qry, Node *node, Oid matviewOid,
|
|||
|
||||
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, matviewOid, TRIGGER_TYPE_DELETE, TRIGGER_TYPE_BEFORE, ex_lock);
|
||||
CreateIvmTrigger(rte->relid, matviewOid, TRIGGER_TYPE_UPDATE, TRIGGER_TYPE_BEFORE, ex_lock);
|
||||
CreateIvmTrigger(rte->relid, matviewOid, TRIGGER_TYPE_TRUNCATE, TRIGGER_TYPE_BEFORE, true);
|
||||
CreateIvmTrigger(rte->relid, matviewOid, TRIGGER_TYPE_INSERT, TRIGGER_TYPE_AFTER, ex_lock);
|
||||
CreateIvmTrigger(rte->relid, matviewOid, TRIGGER_TYPE_DELETE, TRIGGER_TYPE_AFTER, ex_lock);
|
||||
CreateIvmTrigger(rte->relid, matviewOid, 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_INSERT, TRIGGER_TYPE_BEFORE, ex_lock);
|
||||
CreateIvmTrigger(rte->relid, immv_addr, TRIGGER_TYPE_DELETE, TRIGGER_TYPE_BEFORE, ex_lock);
|
||||
CreateIvmTrigger(rte->relid, immv_addr, TRIGGER_TYPE_UPDATE, TRIGGER_TYPE_BEFORE, ex_lock);
|
||||
CreateIvmTrigger(rte->relid, immv_addr, TRIGGER_TYPE_TRUNCATE, TRIGGER_TYPE_BEFORE, true);
|
||||
CreateIvmTrigger(rte->relid, immv_addr, TRIGGER_TYPE_INSERT, TRIGGER_TYPE_AFTER, ex_lock);
|
||||
CreateIvmTrigger(rte->relid, immv_addr, TRIGGER_TYPE_DELETE, TRIGGER_TYPE_AFTER, ex_lock);
|
||||
CreateIvmTrigger(rte->relid, immv_addr, TRIGGER_TYPE_UPDATE, TRIGGER_TYPE_AFTER, ex_lock);
|
||||
CreateIvmTrigger(rte->relid, immv_addr, TRIGGER_TYPE_TRUNCATE, TRIGGER_TYPE_AFTER, true);
|
||||
|
||||
*relids = bms_add_member(*relids, rte->relid);
|
||||
}
|
||||
|
|
@ -636,7 +642,7 @@ CreateIvmTriggersOnBaseTablesRecurse(Query *qry, Node *node, Oid matviewOid,
|
|||
{
|
||||
Query *subquery = rte->subquery;
|
||||
Assert(rte->subquery != NULL);
|
||||
CreateIvmTriggersOnBaseTablesRecurse(subquery, (Node *) subquery, matviewOid, relids, ex_lock);
|
||||
CreateIvmTriggersOnBaseTablesRecurse(subquery, (Node *) subquery, immv_addr, relids, ex_lock);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
|
@ -647,7 +653,7 @@ CreateIvmTriggersOnBaseTablesRecurse(Query *qry, Node *node, Oid matviewOid,
|
|||
ListCell *l;
|
||||
|
||||
foreach(l, f->fromlist)
|
||||
CreateIvmTriggersOnBaseTablesRecurse(qry, lfirst(l), matviewOid, relids, ex_lock);
|
||||
CreateIvmTriggersOnBaseTablesRecurse(qry, lfirst(l), immv_addr, relids, ex_lock);
|
||||
}
|
||||
break;
|
||||
|
||||
|
|
@ -655,8 +661,8 @@ CreateIvmTriggersOnBaseTablesRecurse(Query *qry, Node *node, Oid matviewOid,
|
|||
{
|
||||
JoinExpr *j = (JoinExpr *) node;
|
||||
|
||||
CreateIvmTriggersOnBaseTablesRecurse(qry, j->larg, matviewOid, relids, ex_lock);
|
||||
CreateIvmTriggersOnBaseTablesRecurse(qry, j->rarg, matviewOid, relids, ex_lock);
|
||||
CreateIvmTriggersOnBaseTablesRecurse(qry, j->larg, immv_addr, relids, ex_lock);
|
||||
CreateIvmTriggersOnBaseTablesRecurse(qry, j->rarg, immv_addr, relids, ex_lock);
|
||||
}
|
||||
break;
|
||||
|
||||
|
|
@ -669,7 +675,7 @@ CreateIvmTriggersOnBaseTablesRecurse(Query *qry, Node *node, Oid matviewOid,
|
|||
* CreateIvmTrigger -- create IVM trigger on a base table
|
||||
*/
|
||||
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 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);
|
||||
|
||||
refaddr.classId = RelationRelationId;
|
||||
refaddr.objectId = viewOid;
|
||||
refaddr.objectId = immv_addr.address.objectId;
|
||||
refaddr.objectSubId = 0;
|
||||
|
||||
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->constrrel = NULL;
|
||||
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))))
|
||||
);
|
||||
|
||||
|
|
@ -1708,7 +1714,7 @@ get_primary_key_attnos_from_query(Query *query, List **constraintList)
|
|||
* Store the query for the IMMV to pg_ivm_immv
|
||||
*/
|
||||
static void
|
||||
StoreImmvQuery(Oid viewOid, Query *viewQuery)
|
||||
StoreImmvQuery(ImmvAddress immv_addr, Query *viewQuery)
|
||||
{
|
||||
char *querytree = nodeToString((Node *) viewQuery);
|
||||
char *querystring;
|
||||
|
|
@ -1736,10 +1742,11 @@ StoreImmvQuery(Oid viewOid, Query *viewQuery)
|
|||
memset(values, 0, sizeof(values));
|
||||
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_viewdef -1 ] = CStringGetTextDatum(querytree);
|
||||
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);
|
||||
|
||||
|
|
@ -1749,7 +1756,7 @@ StoreImmvQuery(Oid viewOid, Query *viewQuery)
|
|||
CatalogTupleInsert(pgIvmImmv, heapTuple);
|
||||
|
||||
address.classId = RelationRelationId;
|
||||
address.objectId = viewOid;
|
||||
address.objectId = immv_addr.address.objectId;
|
||||
address.objectSubId = 0;
|
||||
|
||||
recordDependencyOnExpr(&address, (Node *) viewQuery, NIL,
|
||||
|
|
|
|||
29
matview.c
29
matview.c
|
|
@ -50,6 +50,7 @@
|
|||
#include "utils/rel.h"
|
||||
#include "utils/snapmgr.h"
|
||||
#include "utils/typcache.h"
|
||||
#include "utils/uuid.h"
|
||||
#include "utils/xid8.h"
|
||||
|
||||
#include "pg_ivm.h"
|
||||
|
|
@ -251,6 +252,7 @@ ExecRefreshImmv(const RangeVar *relation, bool skipData,
|
|||
{
|
||||
Oid matviewOid;
|
||||
LOCKMODE lockmode;
|
||||
ImmvAddress immv_addr;
|
||||
|
||||
/* Determine strength of lock needed. */
|
||||
//concurrent = stmt->concurrent;
|
||||
|
|
@ -272,7 +274,12 @@ ExecRefreshImmv(const RangeVar *relation, bool skipData,
|
|||
NULL);
|
||||
#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().
|
||||
*/
|
||||
ObjectAddress
|
||||
RefreshImmvByOid(Oid matviewOid, bool is_create, bool skipData,
|
||||
RefreshImmvByOid(ImmvAddress immv_addr, bool is_create, bool skipData,
|
||||
const char *queryString, QueryCompletion *qc)
|
||||
{
|
||||
Relation matviewRel;
|
||||
|
|
@ -300,6 +307,7 @@ RefreshImmvByOid(Oid matviewOid, bool is_create, bool skipData,
|
|||
int save_nestlevel;
|
||||
ObjectAddress address;
|
||||
bool oldPopulated;
|
||||
Oid matviewOid = immv_addr.address.objectId;
|
||||
|
||||
Relation pgIvmImmv;
|
||||
TupleDesc tupdesc;
|
||||
|
|
@ -486,10 +494,7 @@ RefreshImmvByOid(Oid matviewOid, bool is_create, bool skipData,
|
|||
* is created.
|
||||
*/
|
||||
if (!skipData && !oldPopulated)
|
||||
{
|
||||
CreateIvmTriggersOnBaseTables(dataQuery, matviewOid);
|
||||
CreateChangePreventTrigger(matviewOid);
|
||||
}
|
||||
CreateIvmTriggersOnBaseTables(dataQuery, immv_addr);
|
||||
|
||||
/*
|
||||
* Create the transient table that will receive the regenerated data. Lock
|
||||
|
|
@ -844,15 +849,17 @@ Datum
|
|||
IVM_immediate_before(PG_FUNCTION_ARGS)
|
||||
{
|
||||
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];
|
||||
pg_uuid_t *immv_uuid;
|
||||
Oid matviewOid;
|
||||
MV_TriggerHashEntry *entry;
|
||||
bool found;
|
||||
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)));
|
||||
matviewOid = GetImmvRelid(immv_uuid);
|
||||
|
||||
/* If the view has more than one tables, we have to use an exclusive lock. */
|
||||
if (ex_lock)
|
||||
|
|
@ -967,10 +974,11 @@ IVM_immediate_maintenance(PG_FUNCTION_ARGS)
|
|||
Oid matviewOid;
|
||||
Query *query;
|
||||
Query *rewritten = NULL;
|
||||
char *matviewOid_text = trigdata->tg_trigger->tgargs[0];
|
||||
char *immv_uuid_text = trigdata->tg_trigger->tgargs[0];
|
||||
Relation matviewRel;
|
||||
int old_depth = immv_maintenance_depth;
|
||||
SubTransactionId subxid;
|
||||
pg_uuid_t *immv_uuid;
|
||||
|
||||
Oid relowner;
|
||||
Tuplestorestate *old_tuplestore = NULL;
|
||||
|
|
@ -998,7 +1006,8 @@ IVM_immediate_maintenance(PG_FUNCTION_ARGS)
|
|||
rel = trigdata->tg_relation;
|
||||
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
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
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
|
||||
$$
|
||||
|
|
|
|||
86
pg_ivm.c
86
pg_ivm.c
|
|
@ -32,6 +32,7 @@
|
|||
#include "utils/lsyscache.h"
|
||||
#include "utils/regproc.h"
|
||||
#include "utils/rel.h"
|
||||
#include "utils/uuid.h"
|
||||
#include "utils/varlena.h"
|
||||
|
||||
#include "pg_ivm.h"
|
||||
|
|
@ -365,6 +366,17 @@ PgIvmImmvPrimaryKeyIndexId(void)
|
|||
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
|
||||
*/
|
||||
|
|
@ -488,3 +500,77 @@ RestrictSearchPath(void)
|
|||
PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false);
|
||||
}
|
||||
#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 "tcop/dest.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_viewdef 2
|
||||
#define Anum_pg_ivm_immv_ispopulated 3
|
||||
#define Anum_pg_ivm_immv_lastivmupdate 4
|
||||
#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 */
|
||||
|
||||
extern void CreateChangePreventTrigger(Oid matviewOid);
|
||||
extern Oid PgIvmImmvRelationId(void);
|
||||
extern Oid PgIvmImmvPrimaryKeyIndexId(void);
|
||||
extern Oid PgIvmImmvUuidIndexId(void);
|
||||
extern bool isImmv(Oid immv_oid);
|
||||
extern List *PgIvmFuncName(char *name);
|
||||
extern void parse_immv_query(const char *relname, const char *sql,
|
||||
Query **query_ret, ParseState **pstate_ret);
|
||||
extern Oid GetImmvRelid(pg_uuid_t *immv_uuid);
|
||||
extern pg_uuid_t *GetImmvUuid(Oid immvrelid);
|
||||
|
||||
/* createas.c */
|
||||
|
||||
extern ObjectAddress ExecCreateImmv(ParseState *pstate, CreateTableAsStmt *stmt,
|
||||
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 Query *rewriteQueryForIMMV(Query *query, List *colNames);
|
||||
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 ObjectAddress ExecRefreshImmv(const RangeVar *relation, bool skipData,
|
||||
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);
|
||||
extern bool ImmvIncrementalMaintenanceIsEnabled(void);
|
||||
extern Datum IVM_immediate_before(PG_FUNCTION_ARGS);
|
||||
|
|
|
|||
Loading…
Reference in a new issue