PostgreSQL Source Code  git master
matview.h File Reference
#include "catalog/objectaddress.h"
#include "nodes/params.h"
#include "nodes/parsenodes.h"
#include "tcop/dest.h"
#include "utils/relcache.h"
Include dependency graph for matview.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Functions

void SetMatViewPopulatedState (Relation relation, bool newstate)
 
ObjectAddress ExecRefreshMatView (RefreshMatViewStmt *stmt, const char *queryString, ParamListInfo params, QueryCompletion *qc)
 
DestReceiverCreateTransientRelDestReceiver (Oid transientoid)
 
bool MatViewIncrementalMaintenanceIsEnabled (void)
 

Function Documentation

◆ CreateTransientRelDestReceiver()

DestReceiver* CreateTransientRelDestReceiver ( Oid  transientoid)

Definition at line 430 of file matview.c.

431 {
433 
434  self->pub.receiveSlot = transientrel_receive;
435  self->pub.rStartup = transientrel_startup;
436  self->pub.rShutdown = transientrel_shutdown;
437  self->pub.rDestroy = transientrel_destroy;
438  self->pub.mydest = DestTransientRel;
439  self->transientoid = transientoid;
440 
441  return (DestReceiver *) self;
442 }
@ DestTransientRel
Definition: dest.h:97
static void transientrel_destroy(DestReceiver *self)
Definition: matview.c:519
static void transientrel_startup(DestReceiver *self, int operation, TupleDesc typeinfo)
Definition: matview.c:448
static bool transientrel_receive(TupleTableSlot *slot, DestReceiver *self)
Definition: matview.c:474
static void transientrel_shutdown(DestReceiver *self)
Definition: matview.c:502
void * palloc0(Size size)
Definition: mcxt.c:1227

References DestTransientRel, palloc0(), transientrel_destroy(), transientrel_receive(), transientrel_shutdown(), and transientrel_startup().

Referenced by CreateDestReceiver(), and ExecRefreshMatView().

◆ ExecRefreshMatView()

ObjectAddress ExecRefreshMatView ( RefreshMatViewStmt stmt,
const char *  queryString,
ParamListInfo  params,
QueryCompletion qc 
)

Definition at line 133 of file matview.c.

135 {
136  Oid matviewOid;
137  Relation matviewRel;
138  RewriteRule *rule;
139  List *actions;
140  Query *dataQuery;
141  Oid tableSpace;
142  Oid relowner;
143  Oid OIDNewHeap;
145  uint64 processed = 0;
146  bool concurrent;
147  LOCKMODE lockmode;
148  char relpersistence;
149  Oid save_userid;
150  int save_sec_context;
151  int save_nestlevel;
152  ObjectAddress address;
153 
154  /* Determine strength of lock needed. */
155  concurrent = stmt->concurrent;
156  lockmode = concurrent ? ExclusiveLock : AccessExclusiveLock;
157 
158  /*
159  * Get a lock until end of transaction.
160  */
161  matviewOid = RangeVarGetRelidExtended(stmt->relation,
162  lockmode, 0,
164  matviewRel = table_open(matviewOid, NoLock);
165  relowner = matviewRel->rd_rel->relowner;
166 
167  /*
168  * Switch to the owner's userid, so that any functions are run as that
169  * user. Also lock down security-restricted operations and arrange to
170  * make GUC variable changes local to this command.
171  */
172  GetUserIdAndSecContext(&save_userid, &save_sec_context);
173  SetUserIdAndSecContext(relowner,
174  save_sec_context | SECURITY_RESTRICTED_OPERATION);
175  save_nestlevel = NewGUCNestLevel();
176 
177  /* Make sure it is a materialized view. */
178  if (matviewRel->rd_rel->relkind != RELKIND_MATVIEW)
179  ereport(ERROR,
180  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
181  errmsg("\"%s\" is not a materialized view",
182  RelationGetRelationName(matviewRel))));
183 
184  /* Check that CONCURRENTLY is not specified if not populated. */
185  if (concurrent && !RelationIsPopulated(matviewRel))
186  ereport(ERROR,
187  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
188  errmsg("CONCURRENTLY cannot be used when the materialized view is not populated")));
189 
190  /* Check that conflicting options have not been specified. */
191  if (concurrent && stmt->skipData)
192  ereport(ERROR,
193  (errcode(ERRCODE_SYNTAX_ERROR),
194  errmsg("%s and %s options cannot be used together",
195  "CONCURRENTLY", "WITH NO DATA")));
196 
197  /*
198  * Check that everything is correct for a refresh. Problems at this point
199  * are internal errors, so elog is sufficient.
200  */
201  if (matviewRel->rd_rel->relhasrules == false ||
202  matviewRel->rd_rules->numLocks < 1)
203  elog(ERROR,
204  "materialized view \"%s\" is missing rewrite information",
205  RelationGetRelationName(matviewRel));
206 
207  if (matviewRel->rd_rules->numLocks > 1)
208  elog(ERROR,
209  "materialized view \"%s\" has too many rules",
210  RelationGetRelationName(matviewRel));
211 
212  rule = matviewRel->rd_rules->rules[0];
213  if (rule->event != CMD_SELECT || !(rule->isInstead))
214  elog(ERROR,
215  "the rule for materialized view \"%s\" is not a SELECT INSTEAD OF rule",
216  RelationGetRelationName(matviewRel));
217 
218  actions = rule->actions;
219  if (list_length(actions) != 1)
220  elog(ERROR,
221  "the rule for materialized view \"%s\" is not a single action",
222  RelationGetRelationName(matviewRel));
223 
224  /*
225  * Check that there is a unique index with no WHERE clause on one or more
226  * columns of the materialized view if CONCURRENTLY is specified.
227  */
228  if (concurrent)
229  {
230  List *indexoidlist = RelationGetIndexList(matviewRel);
231  ListCell *indexoidscan;
232  bool hasUniqueIndex = false;
233 
234  foreach(indexoidscan, indexoidlist)
235  {
236  Oid indexoid = lfirst_oid(indexoidscan);
237  Relation indexRel;
238 
239  indexRel = index_open(indexoid, AccessShareLock);
240  hasUniqueIndex = is_usable_unique_index(indexRel);
241  index_close(indexRel, AccessShareLock);
242  if (hasUniqueIndex)
243  break;
244  }
245 
246  list_free(indexoidlist);
247 
248  if (!hasUniqueIndex)
249  ereport(ERROR,
250  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
251  errmsg("cannot refresh materialized view \"%s\" concurrently",
253  RelationGetRelationName(matviewRel))),
254  errhint("Create a unique index with no WHERE clause on one or more columns of the materialized view.")));
255  }
256 
257  /*
258  * The stored query was rewritten at the time of the MV definition, but
259  * has not been scribbled on by the planner.
260  */
261  dataQuery = linitial_node(Query, actions);
262 
263  /*
264  * Check for active uses of the relation in the current transaction, such
265  * as open scans.
266  *
267  * NB: We count on this to protect us against problems with refreshing the
268  * data using TABLE_INSERT_FROZEN.
269  */
270  CheckTableNotInUse(matviewRel, "REFRESH MATERIALIZED VIEW");
271 
272  /*
273  * Tentatively mark the matview as populated or not (this will roll back
274  * if we fail later).
275  */
276  SetMatViewPopulatedState(matviewRel, !stmt->skipData);
277 
278  /* Concurrent refresh builds new data in temp tablespace, and does diff. */
279  if (concurrent)
280  {
281  tableSpace = GetDefaultTablespace(RELPERSISTENCE_TEMP, false);
282  relpersistence = RELPERSISTENCE_TEMP;
283  }
284  else
285  {
286  tableSpace = matviewRel->rd_rel->reltablespace;
287  relpersistence = matviewRel->rd_rel->relpersistence;
288  }
289 
290  /*
291  * Create the transient table that will receive the regenerated data. Lock
292  * it against access by any other process until commit (by which time it
293  * will be gone).
294  */
295  OIDNewHeap = make_new_heap(matviewOid, tableSpace,
296  matviewRel->rd_rel->relam,
297  relpersistence, ExclusiveLock);
299  dest = CreateTransientRelDestReceiver(OIDNewHeap);
300 
301  /* Generate the data, if wanted. */
302  if (!stmt->skipData)
303  processed = refresh_matview_datafill(dest, dataQuery, queryString);
304 
305  /* Make the matview match the newly generated data. */
306  if (concurrent)
307  {
308  int old_depth = matview_maintenance_depth;
309 
310  PG_TRY();
311  {
312  refresh_by_match_merge(matviewOid, OIDNewHeap, relowner,
313  save_sec_context);
314  }
315  PG_CATCH();
316  {
317  matview_maintenance_depth = old_depth;
318  PG_RE_THROW();
319  }
320  PG_END_TRY();
321  Assert(matview_maintenance_depth == old_depth);
322  }
323  else
324  {
325  refresh_by_heap_swap(matviewOid, OIDNewHeap, relpersistence);
326 
327  /*
328  * Inform cumulative stats system about our activity: basically, we
329  * truncated the matview and inserted some new data. (The concurrent
330  * code path above doesn't need to worry about this because the
331  * inserts and deletes it issues get counted by lower-level code.)
332  */
333  pgstat_count_truncate(matviewRel);
334  if (!stmt->skipData)
335  pgstat_count_heap_insert(matviewRel, processed);
336  }
337 
338  table_close(matviewRel, NoLock);
339 
340  /* Roll back any GUC changes */
341  AtEOXact_GUC(false, save_nestlevel);
342 
343  /* Restore userid and security context */
344  SetUserIdAndSecContext(save_userid, save_sec_context);
345 
346  ObjectAddressSet(address, RelationRelationId, matviewOid);
347 
348  /*
349  * Save the rowcount so that pg_stat_statements can track the total number
350  * of rows processed by REFRESH MATERIALIZED VIEW command. Note that we
351  * still don't display the rowcount in the command completion tag output,
352  * i.e., the display_rowcount flag of CMDTAG_REFRESH_MATERIALIZED_VIEW
353  * command tag is left false in cmdtaglist.h. Otherwise, the change of
354  * completion tag output might break applications using it.
355  */
356  if (qc)
357  SetQueryCompletion(qc, CMDTAG_REFRESH_MATERIALIZED_VIEW, processed);
358 
359  return address;
360 }
Oid GetDefaultTablespace(char relpersistence, bool partitioned)
Definition: tablespace.c:1143
Oid make_new_heap(Oid OIDOldHeap, Oid NewTableSpace, Oid NewAccessMethod, char relpersistence, LOCKMODE lockmode)
Definition: cluster.c:685
static void SetQueryCompletion(QueryCompletion *qc, CommandTag commandTag, uint64 nprocessed)
Definition: cmdtag.h:38
int errhint(const char *fmt,...)
Definition: elog.c:1319
int errcode(int sqlerrcode)
Definition: elog.c:859
int errmsg(const char *fmt,...)
Definition: elog.c:1072
#define PG_RE_THROW()
Definition: elog.h:411
#define PG_TRY(...)
Definition: elog.h:370
#define PG_END_TRY(...)
Definition: elog.h:395
#define ERROR
Definition: elog.h:39
#define PG_CATCH(...)
Definition: elog.h:380
#define elog(elevel,...)
Definition: elog.h:224
#define ereport(elevel,...)
Definition: elog.h:149
int NewGUCNestLevel(void)
Definition: guc.c:2232
void AtEOXact_GUC(bool isCommit, int nestLevel)
Definition: guc.c:2246
#define stmt
Definition: indent_codes.h:59
void index_close(Relation relation, LOCKMODE lockmode)
Definition: indexam.c:177
Relation index_open(Oid relationId, LOCKMODE lockmode)
Definition: indexam.c:133
Assert(fmt[strlen(fmt) - 1] !='\n')
void list_free(List *list)
Definition: list.c:1546
void LockRelationOid(Oid relid, LOCKMODE lockmode)
Definition: lmgr.c:108
int LOCKMODE
Definition: lockdefs.h:26
#define NoLock
Definition: lockdefs.h:34
#define AccessExclusiveLock
Definition: lockdefs.h:43
#define AccessShareLock
Definition: lockdefs.h:36
#define ExclusiveLock
Definition: lockdefs.h:42
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3322
static uint64 refresh_matview_datafill(DestReceiver *dest, Query *query, const char *queryString)
Definition: matview.c:371
static void refresh_by_match_merge(Oid matviewOid, Oid tempOid, Oid relowner, int save_sec_context)
Definition: matview.c:579
DestReceiver * CreateTransientRelDestReceiver(Oid transientoid)
Definition: matview.c:430
static bool is_usable_unique_index(Relation indexRel)
Definition: matview.c:880
void SetMatViewPopulatedState(Relation relation, bool newstate)
Definition: matview.c:79
static int matview_maintenance_depth
Definition: matview.c:56
static void refresh_by_heap_swap(Oid matviewOid, Oid OIDNewHeap, char relpersistence)
Definition: matview.c:870
#define SECURITY_RESTRICTED_OPERATION
Definition: miscadmin.h:315
void GetUserIdAndSecContext(Oid *userid, int *sec_context)
Definition: miscinit.c:635
void SetUserIdAndSecContext(Oid userid, int sec_context)
Definition: miscinit.c:642
Oid RangeVarGetRelidExtended(const RangeVar *relation, LOCKMODE lockmode, uint32 flags, RangeVarGetRelidCallback callback, void *callback_arg)
Definition: namespace.c:426
@ CMD_SELECT
Definition: nodes.h:255
#define ObjectAddressSet(addr, class_id, object_id)
Definition: objectaddress.h:40
static int list_length(const List *l)
Definition: pg_list.h:152
#define linitial_node(type, l)
Definition: pg_list.h:181
#define lfirst_oid(lc)
Definition: pg_list.h:174
void pgstat_count_heap_insert(Relation rel, PgStat_Counter n)
void pgstat_count_truncate(Relation rel)
unsigned int Oid
Definition: postgres_ext.h:31
#define RelationGetRelationName(relation)
Definition: rel.h:538
#define RelationIsPopulated(relation)
Definition: rel.h:676
#define RelationGetNamespace(relation)
Definition: rel.h:545
List * RelationGetIndexList(Relation relation)
Definition: relcache.c:4753
char * quote_qualified_identifier(const char *qualifier, const char *ident)
Definition: ruleutils.c:12058
Definition: pg_list.h:54
RuleLock * rd_rules
Definition: rel.h:115
Form_pg_class rd_rel
Definition: rel.h:111
RewriteRule ** rules
Definition: prs2lock.h:43
int numLocks
Definition: prs2lock.h:42
Definition: localtime.c:73
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:126
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:40
void RangeVarCallbackOwnsTable(const RangeVar *relation, Oid relId, Oid oldRelId, void *arg)
Definition: tablecmds.c:18102
void CheckTableNotInUse(Relation rel, const char *stmt)
Definition: tablecmds.c:4332

References AccessExclusiveLock, AccessShareLock, Assert(), AtEOXact_GUC(), CheckTableNotInUse(), CMD_SELECT, CreateTransientRelDestReceiver(), generate_unaccent_rules::dest, elog, ereport, errcode(), errhint(), errmsg(), ERROR, ExclusiveLock, get_namespace_name(), GetDefaultTablespace(), GetUserIdAndSecContext(), index_close(), index_open(), is_usable_unique_index(), lfirst_oid, linitial_node, list_free(), list_length(), LockRelationOid(), make_new_heap(), matview_maintenance_depth, NewGUCNestLevel(), NoLock, RuleLock::numLocks, ObjectAddressSet, PG_CATCH, PG_END_TRY, PG_RE_THROW, PG_TRY, pgstat_count_heap_insert(), pgstat_count_truncate(), quote_qualified_identifier(), RangeVarCallbackOwnsTable(), RangeVarGetRelidExtended(), RelationData::rd_rel, RelationData::rd_rules, refresh_by_heap_swap(), refresh_by_match_merge(), refresh_matview_datafill(), RelationGetIndexList(), RelationGetNamespace, RelationGetRelationName, RelationIsPopulated, RuleLock::rules, SECURITY_RESTRICTED_OPERATION, SetMatViewPopulatedState(), SetQueryCompletion(), SetUserIdAndSecContext(), stmt, table_close(), and table_open().

Referenced by ProcessUtilitySlow().

◆ MatViewIncrementalMaintenanceIsEnabled()

bool MatViewIncrementalMaintenanceIsEnabled ( void  )

Definition at line 934 of file matview.c.

935 {
936  return matview_maintenance_depth > 0;
937 }

References matview_maintenance_depth.

Referenced by CheckValidResultRel().

◆ SetMatViewPopulatedState()

void SetMatViewPopulatedState ( Relation  relation,
bool  newstate 
)

Definition at line 79 of file matview.c.

80 {
81  Relation pgrel;
82  HeapTuple tuple;
83 
84  Assert(relation->rd_rel->relkind == RELKIND_MATVIEW);
85 
86  /*
87  * Update relation's pg_class entry. Crucial side-effect: other backends
88  * (and this one too!) are sent SI message to make them rebuild relcache
89  * entries.
90  */
91  pgrel = table_open(RelationRelationId, RowExclusiveLock);
92  tuple = SearchSysCacheCopy1(RELOID,
94  if (!HeapTupleIsValid(tuple))
95  elog(ERROR, "cache lookup failed for relation %u",
96  RelationGetRelid(relation));
97 
98  ((Form_pg_class) GETSTRUCT(tuple))->relispopulated = newstate;
99 
100  CatalogTupleUpdate(pgrel, &tuple->t_self, tuple);
101 
102  heap_freetuple(tuple);
104 
105  /*
106  * Advance command counter to make the updated pg_class row locally
107  * visible.
108  */
110 }
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1434
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define GETSTRUCT(TUP)
Definition: htup_details.h:653
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:313
#define RowExclusiveLock
Definition: lockdefs.h:38
FormData_pg_class * Form_pg_class
Definition: pg_class.h:153
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:252
static struct state * newstate(struct nfa *nfa)
Definition: regc_nfa.c:137
#define RelationGetRelid(relation)
Definition: rel.h:504
ItemPointerData t_self
Definition: htup.h:65
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:86
void CommandCounterIncrement(void)
Definition: xact.c:1076

References Assert(), CatalogTupleUpdate(), CommandCounterIncrement(), elog, ERROR, GETSTRUCT, heap_freetuple(), HeapTupleIsValid, newstate(), ObjectIdGetDatum(), RelationData::rd_rel, RelationGetRelid, RowExclusiveLock, SearchSysCacheCopy1, HeapTupleData::t_self, table_close(), and table_open().

Referenced by ExecRefreshMatView(), and intorel_startup().