diff options
Diffstat (limited to 'src/backend/commands')
-rw-r--r-- | src/backend/commands/cluster.c | 7 | ||||
-rw-r--r-- | src/backend/commands/createas.c | 11 | ||||
-rw-r--r-- | src/backend/commands/matview.c | 68 | ||||
-rw-r--r-- | src/backend/commands/vacuumlazy.c | 6 |
4 files changed, 48 insertions, 44 deletions
diff --git a/src/backend/commands/cluster.c b/src/backend/commands/cluster.c index ed62246cc52..878b6254f54 100644 --- a/src/backend/commands/cluster.c +++ b/src/backend/commands/cluster.c @@ -30,7 +30,6 @@ #include "catalog/objectaccess.h" #include "catalog/toasting.h" #include "commands/cluster.h" -#include "commands/matview.h" #include "commands/tablecmds.h" #include "commands/vacuum.h" #include "miscadmin.h" @@ -388,7 +387,7 @@ cluster_rel(Oid tableOid, Oid indexOid, bool recheck, bool verbose, * database. */ if (OldHeap->rd_rel->relkind == RELKIND_MATVIEW && - !OldHeap->rd_ispopulated) + !RelationIsPopulated(OldHeap)) { relation_close(OldHeap, AccessExclusiveLock); return; @@ -922,10 +921,6 @@ copy_heap_data(Oid OIDNewHeap, Oid OIDOldHeap, Oid OIDOldIndex, get_namespace_name(RelationGetNamespace(OldHeap)), RelationGetRelationName(OldHeap)))); - if (OldHeap->rd_rel->relkind == RELKIND_MATVIEW) - /* Make sure the heap looks good even if no rows are written. */ - SetMatViewToPopulated(NewHeap); - /* * Scan through the OldHeap, either in OldIndex order or sequentially; * copy each tuple into the NewHeap, or transiently to the tuplesort diff --git a/src/backend/commands/createas.c b/src/backend/commands/createas.c index de65c4c7817..14973f8e7c4 100644 --- a/src/backend/commands/createas.c +++ b/src/backend/commands/createas.c @@ -359,10 +359,6 @@ intorel_startup(DestReceiver *self, int operation, TupleDesc typeinfo) */ intoRelationDesc = heap_open(intoRelationId, AccessExclusiveLock); - if (is_matview && !into->skipData) - /* Make sure the heap looks good even if no rows are written. */ - SetMatViewToPopulated(intoRelationDesc); - /* * Check INSERT permission on the constructed table. * @@ -382,6 +378,13 @@ intorel_startup(DestReceiver *self, int operation, TupleDesc typeinfo) ExecCheckRTPerms(list_make1(rte), true); /* + * Tentatively mark the target as populated, if it's a matview and we're + * going to fill it; otherwise, no change needed. + */ + if (is_matview && !into->skipData) + SetMatViewPopulatedState(intoRelationDesc, true); + + /* * Fill private fields of myState for use by later routines */ myState->rel = intoRelationDesc; diff --git a/src/backend/commands/matview.c b/src/backend/commands/matview.c index da373045cc0..5491c84c766 100644 --- a/src/backend/commands/matview.c +++ b/src/backend/commands/matview.c @@ -14,12 +14,11 @@ */ #include "postgres.h" -#include "access/heapam_xlog.h" +#include "access/htup_details.h" #include "access/multixact.h" -#include "access/relscan.h" #include "access/xact.h" #include "catalog/catalog.h" -#include "catalog/heap.h" +#include "catalog/indexing.h" #include "catalog/namespace.h" #include "commands/cluster.h" #include "commands/matview.h" @@ -27,10 +26,11 @@ #include "executor/executor.h" #include "miscadmin.h" #include "rewrite/rewriteHandler.h" -#include "storage/lmgr.h" #include "storage/smgr.h" #include "tcop/tcopprot.h" +#include "utils/rel.h" #include "utils/snapmgr.h" +#include "utils/syscache.h" typedef struct @@ -52,38 +52,45 @@ static void refresh_matview_datafill(DestReceiver *dest, Query *query, const char *queryString); /* - * SetMatViewToPopulated - * Indicate that the materialized view has been populated by its query. - * - * NOTE: The heap starts out in a state that doesn't look scannable, and can - * only transition from there to scannable at the time a new heap is created. + * SetMatViewPopulatedState + * Mark a materialized view as populated, or not. * * NOTE: caller must be holding an appropriate lock on the relation. */ void -SetMatViewToPopulated(Relation relation) +SetMatViewPopulatedState(Relation relation, bool newstate) { - Page page; + Relation pgrel; + HeapTuple tuple; Assert(relation->rd_rel->relkind == RELKIND_MATVIEW); - Assert(relation->rd_ispopulated == false); - - page = (Page) palloc(BLCKSZ); - PageInit(page, BLCKSZ, 0); - if (RelationNeedsWAL(relation)) - log_newpage(&(relation->rd_node), MAIN_FORKNUM, 0, page); + /* + * Update relation's pg_class entry. Crucial side-effect: other backends + * (and this one too!) are sent SI message to make them rebuild relcache + * entries. + */ + pgrel = heap_open(RelationRelationId, RowExclusiveLock); + tuple = SearchSysCacheCopy1(RELOID, + ObjectIdGetDatum(RelationGetRelid(relation))); + if (!HeapTupleIsValid(tuple)) + elog(ERROR, "cache lookup failed for relation %u", + RelationGetRelid(relation)); - RelationOpenSmgr(relation); + ((Form_pg_class) GETSTRUCT(tuple))->relispopulated = newstate; - PageSetChecksumInplace(page, 0); - smgrextend(relation->rd_smgr, MAIN_FORKNUM, 0, (char *) page, true); + simple_heap_update(pgrel, &tuple->t_self, tuple); - pfree(page); + CatalogUpdateIndexes(pgrel, tuple); - smgrimmedsync(relation->rd_smgr, MAIN_FORKNUM); + heap_freetuple(tuple); + heap_close(pgrel, RowExclusiveLock); - RelationCacheInvalidateEntry(relation->rd_id); + /* + * Advance command counter to make the updated pg_class row locally + * visible. + */ + CommandCounterIncrement(); } /* @@ -97,14 +104,14 @@ SetMatViewToPopulated(Relation relation) * If WITH NO DATA was specified, this is effectively like a TRUNCATE; * otherwise it is like a TRUNCATE followed by an INSERT using the SELECT * statement associated with the materialized view. The statement node's - * skipData field is used to indicate that the clause was used. + * skipData field shows whether the clause was used. * * Indexes are rebuilt too, via REINDEX. Since we are effectively bulk-loading * the new heap, it's better to create the indexes afterwards than to fill them * incrementally while we load. * - * The scannable state is changed based on whether the contents reflect the - * result set of the materialized view's query. + * The matview's "populated" state is changed based on whether the contents + * reflect the result set of the materialized view's query. */ void ExecRefreshMatView(RefreshMatViewStmt *stmt, const char *queryString, @@ -184,6 +191,12 @@ ExecRefreshMatView(RefreshMatViewStmt *stmt, const char *queryString, */ CheckTableNotInUse(matviewRel, "REFRESH MATERIALIZED VIEW"); + /* + * Tentatively mark the matview as populated or not (this will roll back + * if we fail later). + */ + SetMatViewPopulatedState(matviewRel, !stmt->skipData); + tableSpace = matviewRel->rd_rel->reltablespace; heap_close(matviewRel, NoLock); @@ -192,6 +205,7 @@ ExecRefreshMatView(RefreshMatViewStmt *stmt, const char *queryString, OIDNewHeap = make_new_heap(matviewOid, tableSpace); dest = CreateTransientRelDestReceiver(OIDNewHeap); + /* Generate the data, if wanted. */ if (!stmt->skipData) refresh_matview_datafill(dest, dataQuery, queryString); @@ -300,8 +314,6 @@ transientrel_startup(DestReceiver *self, int operation, TupleDesc typeinfo) myState->hi_options |= HEAP_INSERT_SKIP_WAL; myState->bistate = GetBulkInsertState(); - SetMatViewToPopulated(transientrel); - /* Not using WAL requires smgr_targblock be initially invalid */ Assert(RelationGetTargetBlock(transientrel) == InvalidBlockNumber); } diff --git a/src/backend/commands/vacuumlazy.c b/src/backend/commands/vacuumlazy.c index 02f3cf3c205..9d304153b8b 100644 --- a/src/backend/commands/vacuumlazy.c +++ b/src/backend/commands/vacuumlazy.c @@ -230,13 +230,7 @@ lazy_vacuum_rel(Relation onerel, VacuumStmt *vacstmt, * * Don't even think about it unless we have a shot at releasing a goodly * number of pages. Otherwise, the time taken isn't worth it. - * - * Leave a populated materialized view with at least one page. */ - if (onerel->rd_rel->relkind == RELKIND_MATVIEW && - vacrelstats->nonempty_pages == 0) - vacrelstats->nonempty_pages = 1; - possibly_freeable = vacrelstats->rel_pages - vacrelstats->nonempty_pages; if (possibly_freeable > 0 && (possibly_freeable >= REL_TRUNCATE_MINIMUM || |