diff options
author | Kevin Grittner <kgrittn@postgresql.org> | 2013-03-03 18:23:31 -0600 |
---|---|---|
committer | Kevin Grittner <kgrittn@postgresql.org> | 2013-03-03 18:23:31 -0600 |
commit | 3bf3ab8c563699138be02f9dc305b7b77a724307 (patch) | |
tree | a36ddfded0bea88ee863595f58f62661cc61948b /src/backend/executor/execMain.c | |
parent | b15a6da29217b14f02895af1d9271e84415a91ae (diff) | |
download | postgresql-3bf3ab8c563699138be02f9dc305b7b77a724307.tar.gz postgresql-3bf3ab8c563699138be02f9dc305b7b77a724307.zip |
Add a materialized view relations.
A materialized view has a rule just like a view and a heap and
other physical properties like a table. The rule is only used to
populate the table, references in queries refer to the
materialized data.
This is a minimal implementation, but should still be useful in
many cases. Currently data is only populated "on demand" by the
CREATE MATERIALIZED VIEW and REFRESH MATERIALIZED VIEW statements.
It is expected that future releases will add incremental updates
with various timings, and that a more refined concept of defining
what is "fresh" data will be developed. At some point it may even
be possible to have queries use a materialized in place of
references to underlying tables, but that requires the other
above-mentioned features to be working first.
Much of the documentation work by Robert Haas.
Review by Noah Misch, Thom Brown, Robert Haas, Marko Tiikkaja
Security review by KaiGai Kohei, with a decision on how best to
implement sepgsql still pending.
Diffstat (limited to 'src/backend/executor/execMain.c')
-rw-r--r-- | src/backend/executor/execMain.c | 80 |
1 files changed, 80 insertions, 0 deletions
diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c index 632644f1d8f..288b29e44a9 100644 --- a/src/backend/executor/execMain.c +++ b/src/backend/executor/execMain.c @@ -84,6 +84,7 @@ static char *ExecBuildSlotValueDescription(TupleTableSlot *slot, int maxfieldlen); static void EvalPlanQualStart(EPQState *epqstate, EState *parentestate, Plan *planTree); +static bool RelationIdIsScannable(Oid relid); /* end of local decls */ @@ -493,6 +494,65 @@ ExecutorRewind(QueryDesc *queryDesc) /* + * ExecCheckRelationsScannable + * Check that relations which are to be accessed are in a scannable + * state. + * + * If not, throw error. For a materialized view, suggest refresh. + */ +static void +ExecCheckRelationsScannable(List *rangeTable) +{ + ListCell *l; + + foreach(l, rangeTable) + { + RangeTblEntry *rte = (RangeTblEntry *) lfirst(l); + + if (rte->rtekind != RTE_RELATION) + continue; + + if (!RelationIdIsScannable(rte->relid)) + { + if (rte->relkind == RELKIND_MATVIEW) + { + /* It is OK to replace the contents of an invalid matview. */ + if (rte->isResultRel) + continue; + + ereport(ERROR, + (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), + errmsg("materialized view \"%s\" has not been populated", + get_rel_name(rte->relid)), + errhint("Use the REFRESH MATERIALIZED VIEW command."))); + } + else + /* This should never happen, so elog will do. */ + elog(ERROR, "relation \"%s\" is not flagged as scannable", + get_rel_name(rte->relid)); + } + } +} + +/* + * Tells whether a relation is scannable. + * + * Currently only non-populated materialzed views are not. + */ +static bool +RelationIdIsScannable(Oid relid) +{ + Relation relation; + bool result; + + relation = RelationIdGetRelation(relid); + result = relation->rd_isscannable; + RelationClose(relation); + + return result; +} + +/* * ExecCheckRTPerms * Check access permissions for all relations listed in a range table. * @@ -883,6 +943,13 @@ InitPlan(QueryDesc *queryDesc, int eflags) planstate = ExecInitNode(plan, estate, eflags); /* + * Unless we are creating a view or are creating a materialized view WITH + * NO DATA, ensure that all referenced relations are scannable. + */ + if ((eflags & EXEC_FLAG_WITH_NO_DATA) == 0) + ExecCheckRelationsScannable(rangeTable); + + /* * Get the tuple descriptor describing the type of tuples to return. */ tupType = ExecGetResultType(planstate); @@ -995,6 +1062,12 @@ CheckValidResultRel(Relation resultRel, CmdType operation) break; } break; + case RELKIND_MATVIEW: + ereport(ERROR, + (errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("cannot change materialized view \"%s\"", + RelationGetRelationName(resultRel)))); + break; case RELKIND_FOREIGN_TABLE: ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), @@ -1045,6 +1118,13 @@ CheckValidRowMarkRel(Relation rel, RowMarkType markType) errmsg("cannot lock rows in view \"%s\"", RelationGetRelationName(rel)))); break; + case RELKIND_MATVIEW: + /* Should not get here */ + ereport(ERROR, + (errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("cannot lock rows in materialized view \"%s\"", + RelationGetRelationName(rel)))); + break; case RELKIND_FOREIGN_TABLE: /* Perhaps we can support this someday, but not today */ ereport(ERROR, |