14
14
*/
15
15
#include "postgres.h"
16
16
17
- #include "access/heapam_xlog .h"
17
+ #include "access/htup_details .h"
18
18
#include "access/multixact.h"
19
- #include "access/relscan.h"
20
19
#include "access/xact.h"
21
20
#include "catalog/catalog.h"
22
- #include "catalog/heap .h"
21
+ #include "catalog/indexing .h"
23
22
#include "catalog/namespace.h"
24
23
#include "commands/cluster.h"
25
24
#include "commands/matview.h"
26
25
#include "commands/tablecmds.h"
27
26
#include "executor/executor.h"
28
27
#include "miscadmin.h"
29
28
#include "rewrite/rewriteHandler.h"
30
- #include "storage/lmgr.h"
31
29
#include "storage/smgr.h"
32
30
#include "tcop/tcopprot.h"
31
+ #include "utils/rel.h"
33
32
#include "utils/snapmgr.h"
33
+ #include "utils/syscache.h"
34
34
35
35
36
36
typedef struct
@@ -52,38 +52,45 @@ static void refresh_matview_datafill(DestReceiver *dest, Query *query,
52
52
const char * queryString );
53
53
54
54
/*
55
- * SetMatViewToPopulated
56
- * Indicate that the materialized view has been populated by its query.
57
- *
58
- * NOTE: The heap starts out in a state that doesn't look scannable, and can
59
- * only transition from there to scannable at the time a new heap is created.
55
+ * SetMatViewPopulatedState
56
+ * Mark a materialized view as populated, or not.
60
57
*
61
58
* NOTE: caller must be holding an appropriate lock on the relation.
62
59
*/
63
60
void
64
- SetMatViewToPopulated (Relation relation )
61
+ SetMatViewPopulatedState (Relation relation , bool newstate )
65
62
{
66
- Page page ;
63
+ Relation pgrel ;
64
+ HeapTuple tuple ;
67
65
68
66
Assert (relation -> rd_rel -> relkind == RELKIND_MATVIEW );
69
- Assert (relation -> rd_ispopulated == false);
70
-
71
- page = (Page ) palloc (BLCKSZ );
72
- PageInit (page , BLCKSZ , 0 );
73
67
74
- if (RelationNeedsWAL (relation ))
75
- log_newpage (& (relation -> rd_node ), MAIN_FORKNUM , 0 , page );
68
+ /*
69
+ * Update relation's pg_class entry. Crucial side-effect: other backends
70
+ * (and this one too!) are sent SI message to make them rebuild relcache
71
+ * entries.
72
+ */
73
+ pgrel = heap_open (RelationRelationId , RowExclusiveLock );
74
+ tuple = SearchSysCacheCopy1 (RELOID ,
75
+ ObjectIdGetDatum (RelationGetRelid (relation )));
76
+ if (!HeapTupleIsValid (tuple ))
77
+ elog (ERROR , "cache lookup failed for relation %u" ,
78
+ RelationGetRelid (relation ));
76
79
77
- RelationOpenSmgr ( relation ) ;
80
+ (( Form_pg_class ) GETSTRUCT ( tuple )) -> relispopulated = newstate ;
78
81
79
- PageSetChecksumInplace (page , 0 );
80
- smgrextend (relation -> rd_smgr , MAIN_FORKNUM , 0 , (char * ) page , true);
82
+ simple_heap_update (pgrel , & tuple -> t_self , tuple );
81
83
82
- pfree ( page );
84
+ CatalogUpdateIndexes ( pgrel , tuple );
83
85
84
- smgrimmedsync (relation -> rd_smgr , MAIN_FORKNUM );
86
+ heap_freetuple (tuple );
87
+ heap_close (pgrel , RowExclusiveLock );
85
88
86
- RelationCacheInvalidateEntry (relation -> rd_id );
89
+ /*
90
+ * Advance command counter to make the updated pg_class row locally
91
+ * visible.
92
+ */
93
+ CommandCounterIncrement ();
87
94
}
88
95
89
96
/*
@@ -97,14 +104,14 @@ SetMatViewToPopulated(Relation relation)
97
104
* If WITH NO DATA was specified, this is effectively like a TRUNCATE;
98
105
* otherwise it is like a TRUNCATE followed by an INSERT using the SELECT
99
106
* statement associated with the materialized view. The statement node's
100
- * skipData field is used to indicate that the clause was used.
107
+ * skipData field shows whether the clause was used.
101
108
*
102
109
* Indexes are rebuilt too, via REINDEX. Since we are effectively bulk-loading
103
110
* the new heap, it's better to create the indexes afterwards than to fill them
104
111
* incrementally while we load.
105
112
*
106
- * The scannable state is changed based on whether the contents reflect the
107
- * result set of the materialized view's query.
113
+ * The matview's "populated" state is changed based on whether the contents
114
+ * reflect the result set of the materialized view's query.
108
115
*/
109
116
void
110
117
ExecRefreshMatView (RefreshMatViewStmt * stmt , const char * queryString ,
@@ -184,6 +191,12 @@ ExecRefreshMatView(RefreshMatViewStmt *stmt, const char *queryString,
184
191
*/
185
192
CheckTableNotInUse (matviewRel , "REFRESH MATERIALIZED VIEW" );
186
193
194
+ /*
195
+ * Tentatively mark the matview as populated or not (this will roll back
196
+ * if we fail later).
197
+ */
198
+ SetMatViewPopulatedState (matviewRel , !stmt -> skipData );
199
+
187
200
tableSpace = matviewRel -> rd_rel -> reltablespace ;
188
201
189
202
heap_close (matviewRel , NoLock );
@@ -192,6 +205,7 @@ ExecRefreshMatView(RefreshMatViewStmt *stmt, const char *queryString,
192
205
OIDNewHeap = make_new_heap (matviewOid , tableSpace );
193
206
dest = CreateTransientRelDestReceiver (OIDNewHeap );
194
207
208
+ /* Generate the data, if wanted. */
195
209
if (!stmt -> skipData )
196
210
refresh_matview_datafill (dest , dataQuery , queryString );
197
211
@@ -300,8 +314,6 @@ transientrel_startup(DestReceiver *self, int operation, TupleDesc typeinfo)
300
314
myState -> hi_options |= HEAP_INSERT_SKIP_WAL ;
301
315
myState -> bistate = GetBulkInsertState ();
302
316
303
- SetMatViewToPopulated (transientrel );
304
-
305
317
/* Not using WAL requires smgr_targblock be initially invalid */
306
318
Assert (RelationGetTargetBlock (transientrel ) == InvalidBlockNumber );
307
319
}
0 commit comments