168{
177 char relpersistence;
179 int save_sec_context;
180 int save_nestlevel;
182
184 relowner = matviewRel->
rd_rel->relowner;
185
186 /*
187 * Switch to the owner's userid, so that any functions are run as that
188 * user. Also lock down security-restricted operations and arrange to
189 * make GUC variable changes local to this command.
190 */
196
197 /* Make sure it is a materialized view. */
198 if (matviewRel->
rd_rel->relkind != RELKIND_MATVIEW)
200 (
errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
201 errmsg(
"\"%s\" is not a materialized view",
203
204 /* Check that CONCURRENTLY is not specified if not populated. */
207 (
errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
208 errmsg(
"CONCURRENTLY cannot be used when the materialized view is not populated")));
209
210 /* Check that conflicting options have not been specified. */
211 if (concurrent && skipData)
213 (
errcode(ERRCODE_SYNTAX_ERROR),
214 errmsg(
"%s and %s options cannot be used together",
215 "CONCURRENTLY", "WITH NO DATA")));
216
217 /*
218 * Check that everything is correct for a refresh. Problems at this point
219 * are internal errors, so elog is sufficient.
220 */
221 if (matviewRel->
rd_rel->relhasrules ==
false ||
224 "materialized view \"%s\" is missing rewrite information",
226
229 "materialized view \"%s\" has too many rules",
231
235 "the rule for materialized view \"%s\" is not a SELECT INSTEAD OF rule",
237
238 actions =
rule->actions;
241 "the rule for materialized view \"%s\" is not a single action",
243
244 /*
245 * Check that there is a unique index with no WHERE clause on one or more
246 * columns of the materialized view if CONCURRENTLY is specified.
247 */
248 if (concurrent)
249 {
252 bool hasUniqueIndex = false;
253
255
256 foreach(indexoidscan, indexoidlist)
257 {
260
264 if (hasUniqueIndex)
265 break;
266 }
267
269
270 if (!hasUniqueIndex)
272 (
errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
273 errmsg(
"cannot refresh materialized view \"%s\" concurrently",
276 errhint(
"Create a unique index with no WHERE clause on one or more columns of the materialized view.")));
277 }
278
279 /*
280 * The stored query was rewritten at the time of the MV definition, but
281 * has not been scribbled on by the planner.
282 */
284
285 /*
286 * Check for active uses of the relation in the current transaction, such
287 * as open scans.
288 *
289 * NB: We count on this to protect us against problems with refreshing the
290 * data using TABLE_INSERT_FROZEN.
291 */
293 is_create ? "CREATE MATERIALIZED VIEW" :
294 "REFRESH MATERIALIZED VIEW");
295
296 /*
297 * Tentatively mark the matview as populated or not (this will roll back
298 * if we fail later).
299 */
301
302 /* Concurrent refresh builds new data in temp tablespace, and does diff. */
303 if (concurrent)
304 {
306 relpersistence = RELPERSISTENCE_TEMP;
307 }
308 else
309 {
310 tableSpace = matviewRel->
rd_rel->reltablespace;
311 relpersistence = matviewRel->
rd_rel->relpersistence;
312 }
313
314 /*
315 * Create the transient table that will receive the regenerated data. Lock
316 * it against access by any other process until commit (by which time it
317 * will be gone).
318 */
320 matviewRel->
rd_rel->relam,
323
324 /* Generate the data, if wanted. */
325 if (!skipData)
326 {
328
331 is_create);
332 }
333
334 /* Make the matview match the newly generated data. */
335 if (concurrent)
336 {
338
340 {
342 save_sec_context);
343 }
345 {
348 }
351 }
352 else
353 {
355
356 /*
357 * Inform cumulative stats system about our activity: basically, we
358 * truncated the matview and inserted some new data. (The concurrent
359 * code path above doesn't need to worry about this because the
360 * inserts and deletes it issues get counted by lower-level code.)
361 */
363 if (!skipData)
365 }
366
368
369 /* Roll back any GUC changes */
371
372 /* Restore userid and security context */
374
376
377 /*
378 * Save the rowcount so that pg_stat_statements can track the total number
379 * of rows processed by REFRESH MATERIALIZED VIEW command. Note that we
380 * still don't display the rowcount in the command completion tag output,
381 * i.e., the display_rowcount flag of CMDTAG_REFRESH_MATERIALIZED_VIEW
382 * command tag is left false in cmdtaglist.h. Otherwise, the change of
383 * completion tag output might break applications using it.
384 *
385 * When called from CREATE MATERIALIZED VIEW command, the rowcount is
386 * displayed with the command tag CMDTAG_SELECT.
387 */
388 if (qc)
390 is_create ? CMDTAG_SELECT : CMDTAG_REFRESH_MATERIALIZED_VIEW,
391 processed);
392
393 return address;
394}
Oid GetDefaultTablespace(char relpersistence, bool partitioned)
Oid make_new_heap(Oid OIDOldHeap, Oid NewTableSpace, Oid NewAccessMethod, char relpersistence, LOCKMODE lockmode)
static void SetQueryCompletion(QueryCompletion *qc, CommandTag commandTag, uint64 nprocessed)
int errhint(const char *fmt,...)
int errcode(int sqlerrcode)
int errmsg(const char *fmt,...)
#define ereport(elevel,...)
int NewGUCNestLevel(void)
void RestrictSearchPath(void)
void AtEOXact_GUC(bool isCommit, int nestLevel)
Assert(PointerIsAligned(start, uint64))
void index_close(Relation relation, LOCKMODE lockmode)
Relation index_open(Oid relationId, LOCKMODE lockmode)
void list_free(List *list)
bool CheckRelationOidLockedByMe(Oid relid, LOCKMODE lockmode, bool orstronger)
char * get_namespace_name(Oid nspid)
DestReceiver * CreateTransientRelDestReceiver(Oid transientoid)
static void refresh_by_match_merge(Oid matviewOid, Oid tempOid, Oid relowner, int save_sec_context)
static bool is_usable_unique_index(Relation indexRel)
static uint64 refresh_matview_datafill(DestReceiver *dest, Query *query, const char *queryString, bool is_create)
void SetMatViewPopulatedState(Relation relation, bool newstate)
static void refresh_by_heap_swap(Oid matviewOid, Oid OIDNewHeap, char relpersistence)
#define SECURITY_RESTRICTED_OPERATION
void GetUserIdAndSecContext(Oid *userid, int *sec_context)
void SetUserIdAndSecContext(Oid userid, int sec_context)
#define ObjectAddressSet(addr, class_id, object_id)
static int list_length(const List *l)
#define linitial_node(type, l)
void pgstat_count_heap_insert(Relation rel, PgStat_Counter n)
void pgstat_count_truncate(Relation rel)
#define RelationGetRelationName(relation)
#define RelationIsPopulated(relation)
#define RelationGetNamespace(relation)
List * RelationGetIndexList(Relation relation)
char * quote_qualified_identifier(const char *qualifier, const char *ident)
void table_close(Relation relation, LOCKMODE lockmode)
Relation table_open(Oid relationId, LOCKMODE lockmode)
void CheckTableNotInUse(Relation rel, const char *stmt)