<entry>True if table has (or once had) any inheritance children</entry>
</row>
+ <row>
+ <entry><structfield>relispopulated</structfield></entry>
+ <entry><type>bool</type></entry>
+ <entry></entry>
+ <entry>True if relation is populated (this is true for all
+ relations other than some materialized views)</entry>
+ </row>
+
<row>
<entry><structfield>relfrozenxid</structfield></entry>
<entry><type>xid</type></entry>
<row>
<entry><structfield>hasindexes</structfield></entry>
<entry><type>boolean</type></entry>
- <entry><literal><link linkend="catalog-pg-class"><structname>pg_class</structname></link>.relhasindex</literal></entry>
+ <entry></entry>
<entry>True if materialized view has (or recently had) any indexes</entry>
</row>
<row>
- <entry><structfield>isscannable</structfield></entry>
+ <entry><structfield>ispopulated</structfield></entry>
<entry><type>boolean</type></entry>
<entry></entry>
- <entry>True if materialized view can currently be scanned</entry>
+ <entry>True if materialized view is currently populated</entry>
</row>
<row>
<entry><structfield>definition</structfield></entry>
<primary>pg_tablespace_location</primary>
</indexterm>
- <indexterm>
- <primary>pg_relation_is_scannable</primary>
- </indexterm>
-
<indexterm>
<primary>pg_typeof</primary>
</indexterm>
<entry><type>text</type></entry>
<entry>get the path in the file system that this tablespace is located in</entry>
</row>
- <row>
- <entry><literal><function>pg_relation_is_scannable(<parameter>relation_oid</parameter>)</function></literal></entry>
- <entry><type>boolean</type></entry>
- <entry>is the relation scannable; a materialized view which has not been loaded will not be scannable</entry>
- </row>
<row>
<entry><literal><function>pg_typeof(<parameter>any</parameter>)</function></literal></entry>
<entry><type>regtype</type></entry>
values[Anum_pg_class_relhasrules - 1] = BoolGetDatum(rd_rel->relhasrules);
values[Anum_pg_class_relhastriggers - 1] = BoolGetDatum(rd_rel->relhastriggers);
values[Anum_pg_class_relhassubclass - 1] = BoolGetDatum(rd_rel->relhassubclass);
+ values[Anum_pg_class_relispopulated - 1] = BoolGetDatum(rd_rel->relispopulated);
values[Anum_pg_class_relfrozenxid - 1] = TransactionIdGetDatum(rd_rel->relfrozenxid);
values[Anum_pg_class_relminmxid - 1] = MultiXactIdGetDatum(rd_rel->relminmxid);
if (relacl != (Datum) 0)
smgrimmedsync(rel->rd_smgr, INIT_FORKNUM);
}
-/*
- * Check whether a materialized view is in an initial, unloaded state.
- *
- * The check here must match what is set up in heap_create_init_fork().
- * Currently the init fork is an empty file. A missing heap is also
- * considered to be unloaded.
- */
-bool
-heap_is_matview_init_state(Relation rel)
-{
- Assert(rel->rd_rel->relkind == RELKIND_MATVIEW);
-
- RelationOpenSmgr(rel);
-
- if (!smgrexists(rel->rd_smgr, MAIN_FORKNUM))
- return true;
-
- return (smgrnblocks(rel->rd_smgr, MAIN_FORKNUM) < 1);
-}
-
/*
* RelationRemoveInheritance
*
pg_get_userbyid(C.relowner) AS matviewowner,
T.spcname AS tablespace,
C.relhasindex AS hasindexes,
- pg_relation_is_scannable(C.oid) AS isscannable,
+ C.relispopulated AS ispopulated,
pg_get_viewdef(C.oid) AS definition
FROM pg_class C LEFT JOIN pg_namespace N ON (N.oid = C.relnamespace)
LEFT JOIN pg_tablespace T ON (T.oid = C.reltablespace)
#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"
* database.
*/
if (OldHeap->rd_rel->relkind == RELKIND_MATVIEW &&
- !OldHeap->rd_ispopulated)
+ !RelationIsPopulated(OldHeap))
{
relation_close(OldHeap, AccessExclusiveLock);
return;
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
*/
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.
*
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
*/
*/
#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"
#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
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();
}
/*
* 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,
*/
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);
OIDNewHeap = make_new_heap(matviewOid, tableSpace);
dest = CreateTransientRelDestReceiver(OIDNewHeap);
+ /* Generate the data, if wanted. */
if (!stmt->skipData)
refresh_matview_datafill(dest, dataQuery, queryString);
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);
}
*
* 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 ||
PG_RETURN_TEXT_P(cstring_to_text(path));
}
-
-
-/*
- * Indicate whether a relation is scannable.
- *
- * Currently, this is always true except for a materialized view which has not
- * been populated. It is expected that other conditions for allowing a
- * materialized view to be scanned will be added in later releases.
- */
-Datum
-pg_relation_is_scannable(PG_FUNCTION_ARGS)
-{
- Oid relid;
- Relation relation;
- bool result;
-
- relid = PG_GETARG_OID(0);
- relation = try_relation_open(relid, AccessShareLock);
-
- if (relation == NULL)
- PG_RETURN_BOOL(false);
-
- result = RelationIsScannable(relation);
-
- relation_close(relation, AccessShareLock);
- PG_RETURN_BOOL(result);
-}
#include "access/transam.h"
#include "access/xact.h"
#include "catalog/catalog.h"
-#include "catalog/heap.h"
#include "catalog/index.h"
#include "catalog/indexing.h"
#include "catalog/namespace.h"
/* make sure relation is marked as having no open file yet */
relation->rd_smgr = NULL;
- if (relation->rd_rel->relkind == RELKIND_MATVIEW &&
- heap_is_matview_init_state(relation))
- relation->rd_ispopulated = false;
- else
- relation->rd_ispopulated = true;
-
/*
* now we can free the memory allocated for pg_class_tuple
*/
/* formrdesc is used only for permanent relations */
relation->rd_rel->relpersistence = RELPERSISTENCE_PERMANENT;
+ /* ... and they're always populated, too */
+ relation->rd_rel->relispopulated = true;
+
relation->rd_rel->relpages = 0;
relation->rd_rel->reltuples = 0;
relation->rd_rel->relallvisible = 0;
* initialize physical addressing information for the relation
*/
RelationInitPhysicalAddr(relation);
- relation->rd_ispopulated = true;
/*
* initialize the rel-has-index flag, using hardwired knowledge
heap_freetuple(pg_class_tuple);
/* We must recalculate physical address in case it changed */
RelationInitPhysicalAddr(relation);
- relation->rd_ispopulated = true;
/*
* For a non-system index, there are fields of the pg_index row that are
if (relation->rd_isnailed)
{
RelationInitPhysicalAddr(relation);
- if (relation->rd_rel->relkind == RELKIND_MATVIEW &&
- heap_is_matview_init_state(relation))
- relation->rd_ispopulated = false;
- else
- relation->rd_ispopulated = true;
if (relation->rd_rel->relkind == RELKIND_INDEX)
{
break;
}
+ /* if it's a materialized view, it's not populated initially */
+ if (relkind == RELKIND_MATVIEW)
+ rel->rd_rel->relispopulated = false;
+ else
+ rel->rd_rel->relispopulated = true;
+
/*
* Insert relation physical and logical identifiers (OIDs) into the right
* places. For a mapped relation, we set relfilenode to zero and rely on
RelationInitPhysicalAddr(rel);
- /* materialized view not initially scannable */
- if (relkind == RELKIND_MATVIEW)
- rel->rd_ispopulated = false;
- else
- rel->rd_ispopulated = true;
-
/*
* Okay to insert into the relcache hash tables.
*/
*/
RelationInitLockInfo(rel);
RelationInitPhysicalAddr(rel);
- if (rel->rd_rel->relkind == RELKIND_MATVIEW &&
- heap_is_matview_init_state(rel))
- rel->rd_ispopulated = false;
- else
- rel->rd_ispopulated = true;
}
/*
TableInfo *tbinfo = tdinfo->tdtable;
PQExpBuffer q;
- /* If the materialized view is not flagged as scannable, skip this. */
- if (!tbinfo->isscannable)
+ /* If the materialized view is not flagged as populated, skip this. */
+ if (!tbinfo->relispopulated)
return;
q = createPQExpBuffer();
addObjectDependency(dobj, refdobj->dumpId);
- if (!reftbinfo->isscannable)
- tbinfo->isscannable = false;
+ if (!reftbinfo->relispopulated)
+ tbinfo->relispopulated = false;
}
PQclear(res);
int i_toastoid;
int i_toastfrozenxid;
int i_relpersistence;
- int i_isscannable;
+ int i_relispopulated;
int i_owning_tab;
int i_owning_col;
int i_reltablespace;
"c.relhasindex, c.relhasrules, c.relhasoids, "
"c.relfrozenxid, tc.oid AS toid, "
"tc.relfrozenxid AS tfrozenxid, "
- "c.relpersistence, "
- "CASE WHEN c.relkind = '%c' THEN pg_relation_is_scannable(c.oid) ELSE 't'::bool END as isscannable, "
+ "c.relpersistence, c.relispopulated, "
"c.relpages, "
"CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
"d.refobjid AS owning_tab, "
"WHERE c.relkind in ('%c', '%c', '%c', '%c', '%c', '%c') "
"ORDER BY c.oid",
username_subquery,
- RELKIND_MATVIEW,
RELKIND_SEQUENCE,
RELKIND_RELATION, RELKIND_SEQUENCE,
RELKIND_VIEW, RELKIND_COMPOSITE_TYPE,
"c.relhasindex, c.relhasrules, c.relhasoids, "
"c.relfrozenxid, tc.oid AS toid, "
"tc.relfrozenxid AS tfrozenxid, "
- "c.relpersistence, 't'::bool as isscannable, "
+ "c.relpersistence, 't' as relispopulated, "
"c.relpages, "
"CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
"d.refobjid AS owning_tab, "
"c.relhasindex, c.relhasrules, c.relhasoids, "
"c.relfrozenxid, tc.oid AS toid, "
"tc.relfrozenxid AS tfrozenxid, "
- "'p' AS relpersistence, 't'::bool as isscannable, "
+ "'p' AS relpersistence, 't' as relispopulated, "
"c.relpages, "
"CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
"d.refobjid AS owning_tab, "
"c.relhasindex, c.relhasrules, c.relhasoids, "
"c.relfrozenxid, tc.oid AS toid, "
"tc.relfrozenxid AS tfrozenxid, "
- "'p' AS relpersistence, 't'::bool as isscannable, "
+ "'p' AS relpersistence, 't' as relispopulated, "
"c.relpages, "
"NULL AS reloftype, "
"d.refobjid AS owning_tab, "
"c.relhasindex, c.relhasrules, c.relhasoids, "
"c.relfrozenxid, tc.oid AS toid, "
"tc.relfrozenxid AS tfrozenxid, "
- "'p' AS relpersistence, 't'::bool as isscannable, "
+ "'p' AS relpersistence, 't' as relispopulated, "
"c.relpages, "
"NULL AS reloftype, "
"d.refobjid AS owning_tab, "
"0 AS relfrozenxid, "
"0 AS toid, "
"0 AS tfrozenxid, "
- "'p' AS relpersistence, 't'::bool as isscannable, "
+ "'p' AS relpersistence, 't' as relispopulated, "
"relpages, "
"NULL AS reloftype, "
"d.refobjid AS owning_tab, "
"0 AS relfrozenxid, "
"0 AS toid, "
"0 AS tfrozenxid, "
- "'p' AS relpersistence, 't'::bool as isscannable, "
+ "'p' AS relpersistence, 't' as relispopulated, "
"relpages, "
"NULL AS reloftype, "
"d.refobjid AS owning_tab, "
"0 AS relfrozenxid, "
"0 AS toid, "
"0 AS tfrozenxid, "
- "'p' AS relpersistence, 't'::bool as isscannable, "
+ "'p' AS relpersistence, 't' as relispopulated, "
"relpages, "
"NULL AS reloftype, "
"NULL::oid AS owning_tab, "
"0 AS relfrozenxid, "
"0 AS toid, "
"0 AS tfrozenxid, "
- "'p' AS relpersistence, 't'::bool as isscannable, "
+ "'p' AS relpersistence, 't' as relispopulated, "
"relpages, "
"NULL AS reloftype, "
"NULL::oid AS owning_tab, "
"0 as relfrozenxid, "
"0 AS toid, "
"0 AS tfrozenxid, "
- "'p' AS relpersistence, 't'::bool as isscannable, "
+ "'p' AS relpersistence, 't' as relispopulated, "
"0 AS relpages, "
"NULL AS reloftype, "
"NULL::oid AS owning_tab, "
i_toastoid = PQfnumber(res, "toid");
i_toastfrozenxid = PQfnumber(res, "tfrozenxid");
i_relpersistence = PQfnumber(res, "relpersistence");
- i_isscannable = PQfnumber(res, "isscannable");
+ i_relispopulated = PQfnumber(res, "relispopulated");
i_relpages = PQfnumber(res, "relpages");
i_owning_tab = PQfnumber(res, "owning_tab");
i_owning_col = PQfnumber(res, "owning_col");
tblinfo[i].hasrules = (strcmp(PQgetvalue(res, i, i_relhasrules), "t") == 0);
tblinfo[i].hastriggers = (strcmp(PQgetvalue(res, i, i_relhastriggers), "t") == 0);
tblinfo[i].hasoids = (strcmp(PQgetvalue(res, i, i_relhasoids), "t") == 0);
- tblinfo[i].isscannable = (strcmp(PQgetvalue(res, i, i_isscannable), "t") == 0);
+ tblinfo[i].relispopulated = (strcmp(PQgetvalue(res, i, i_relispopulated), "t") == 0);
tblinfo[i].relpages = atoi(PQgetvalue(res, i, i_relpages));
tblinfo[i].frozenxid = atooid(PQgetvalue(res, i, i_relfrozenxid));
tblinfo[i].toast_oid = atooid(PQgetvalue(res, i, i_toastoid));
/*
* For materialized views, create the AS clause just like a view.
+ * At this point, we always mark the view as not populated.
*/
if (tbinfo->relkind == RELKIND_MATVIEW)
{
}
}
+ /*
+ * In binary_upgrade mode, restore matviews' populated status by
+ * poking pg_class directly. This is pretty ugly, but we can't use
+ * REFRESH MATERIALIZED VIEW since it's possible that some underlying
+ * matview is not populated even though this matview is.
+ */
+ if (binary_upgrade && tbinfo->relkind == RELKIND_MATVIEW &&
+ tbinfo->relispopulated)
+ {
+ appendPQExpBuffer(q, "\n-- For binary upgrade, mark materialized view as populated\n");
+ appendPQExpBuffer(q, "UPDATE pg_catalog.pg_class\n"
+ "SET relispopulated = 't'\n"
+ "WHERE oid = ");
+ appendStringLiteralAH(q, fmtId(tbinfo->dobj.name), fout);
+ appendPQExpBuffer(q, "::pg_catalog.regclass;\n");
+ }
+
/*
* Dump additional per-column properties that we can't handle in the
* main CREATE TABLE command.
char *relacl;
char relkind;
char relpersistence; /* relation persistence */
+ bool relispopulated; /* relation is populated */
char *reltablespace; /* relation tablespace */
char *reloptions; /* options specified by WITH (...) */
char *toast_reloptions; /* ditto, for the TOAST table */
bool hasrules; /* does it have any rules? */
bool hastriggers; /* does it have any triggers? */
bool hasoids; /* does it have OIDs? */
- bool isscannable; /* is valid for use in queries */
uint32 frozenxid; /* for restore frozen xid */
Oid toast_oid; /* for restore toast frozen xid */
uint32 toast_frozenxid; /* for restore toast frozen xid */
*/
/* yyyymmddN */
-#define CATALOG_VERSION_NO 201304271
+#define CATALOG_VERSION_NO 201305061
#endif
bool is_internal);
extern void heap_create_init_fork(Relation rel);
-extern bool heap_is_matview_init_state(Relation rel);
extern void heap_drop_with_catalog(Oid relid);
bool relhasrules; /* has (or has had) any rules */
bool relhastriggers; /* has (or has had) any TRIGGERs */
bool relhassubclass; /* has (or has had) derived classes */
+ bool relispopulated; /* matview currently holds query results */
TransactionId relfrozenxid; /* all Xids < this are frozen in this rel */
TransactionId relminmxid; /* all multixacts in this rel are >= this.
* this is really a MultiXactId */
* ----------------
*/
-#define Natts_pg_class 28
+#define Natts_pg_class 29
#define Anum_pg_class_relname 1
#define Anum_pg_class_relnamespace 2
#define Anum_pg_class_reltype 3
#define Anum_pg_class_relhasrules 22
#define Anum_pg_class_relhastriggers 23
#define Anum_pg_class_relhassubclass 24
-#define Anum_pg_class_relfrozenxid 25
-#define Anum_pg_class_relminmxid 26
-#define Anum_pg_class_relacl 27
-#define Anum_pg_class_reloptions 28
+#define Anum_pg_class_relispopulated 25
+#define Anum_pg_class_relfrozenxid 26
+#define Anum_pg_class_relminmxid 27
+#define Anum_pg_class_relacl 28
+#define Anum_pg_class_reloptions 29
/* ----------------
* initial contents of pg_class
* Note: "3" in the relfrozenxid column stands for FirstNormalTransactionId;
* similarly, "1" in relminmxid stands for FirstMultiXactId
*/
-DATA(insert OID = 1247 ( pg_type PGNSP 71 0 PGUID 0 0 0 0 0 0 0 0 f f p r 30 0 t f f f f 3 1 _null_ _null_ ));
+DATA(insert OID = 1247 ( pg_type PGNSP 71 0 PGUID 0 0 0 0 0 0 0 0 f f p r 30 0 t f f f f t 3 1 _null_ _null_ ));
DESCR("");
-DATA(insert OID = 1249 ( pg_attribute PGNSP 75 0 PGUID 0 0 0 0 0 0 0 0 f f p r 21 0 f f f f f 3 1 _null_ _null_ ));
+DATA(insert OID = 1249 ( pg_attribute PGNSP 75 0 PGUID 0 0 0 0 0 0 0 0 f f p r 21 0 f f f f f t 3 1 _null_ _null_ ));
DESCR("");
-DATA(insert OID = 1255 ( pg_proc PGNSP 81 0 PGUID 0 0 0 0 0 0 0 0 f f p r 27 0 t f f f f 3 1 _null_ _null_ ));
+DATA(insert OID = 1255 ( pg_proc PGNSP 81 0 PGUID 0 0 0 0 0 0 0 0 f f p r 27 0 t f f f f t 3 1 _null_ _null_ ));
DESCR("");
-DATA(insert OID = 1259 ( pg_class PGNSP 83 0 PGUID 0 0 0 0 0 0 0 0 f f p r 28 0 t f f f f 3 1 _null_ _null_ ));
+DATA(insert OID = 1259 ( pg_class PGNSP 83 0 PGUID 0 0 0 0 0 0 0 0 f f p r 29 0 t f f f f t 3 1 _null_ _null_ ));
DESCR("");
DESCR("is a view insertable-into");
DATA(insert OID = 3843 ( pg_view_is_updatable PGNSP PGUID 12 10 0 0 0 f f f f t f s 1 0 16 "26" _null_ _null_ _null_ _null_ pg_view_is_updatable _null_ _null_ _null_ ));
DESCR("is a view updatable");
-DATA(insert OID = 3846 ( pg_relation_is_scannable PGNSP PGUID 12 10 0 0 0 f f f f t f s 1 0 16 "26" _null_ _null_ _null_ _null_ pg_relation_is_scannable _null_ _null_ _null_ ));
-DESCR("is a relation scannable");
/* Deferrable unique constraint trigger */
DATA(insert OID = 1250 ( unique_key_recheck PGNSP PGUID 12 1 0 0 0 f f f f t f v 0 0 2279 "" _null_ _null_ _null_ _null_ unique_key_recheck _null_ _null_ _null_ ));
#include "utils/relcache.h"
-extern void SetMatViewToPopulated(Relation relation);
+extern void SetMatViewPopulatedState(Relation relation, bool newstate);
extern void ExecRefreshMatView(RefreshMatViewStmt *stmt, const char *queryString,
ParamListInfo params, char *completionTag);
extern Datum pg_indexes_size(PG_FUNCTION_ARGS);
extern Datum pg_relation_filenode(PG_FUNCTION_ARGS);
extern Datum pg_relation_filepath(PG_FUNCTION_ARGS);
-extern Datum pg_relation_is_scannable(PG_FUNCTION_ARGS);
/* genfile.c */
extern bytea *read_binary_file(const char *filename,
BackendId rd_backend; /* owning backend id, if temporary relation */
bool rd_islocaltemp; /* rel is a temp rel of this session */
bool rd_isnailed; /* rel is nailed in cache */
- bool rd_ispopulated; /* matview has query results */
bool rd_isvalid; /* relcache entry is valid */
char rd_indexvalid; /* state of rd_indexlist: 0 = not valid, 1 =
* valid, 2 = temporarily forced */
* populated by its query. This is likely to get more complicated later,
* so use a macro which looks like a function.
*/
-#define RelationIsScannable(relation) ((relation)->rd_ispopulated)
+#define RelationIsScannable(relation) ((relation)->rd_rel->relispopulated)
+
+/*
+ * RelationIsPopulated
+ * Currently, we don't physically distinguish the "populated" and
+ * "scannable" properties of matviews, but that may change later.
+ * Hence, use the appropriate one of these macros in code tests.
+ */
+#define RelationIsPopulated(relation) ((relation)->rd_rel->relispopulated)
/* routines in utils/cache/relcache.c */
(2 rows)
CREATE MATERIALIZED VIEW tm AS SELECT type, sum(amt) AS totamt FROM t GROUP BY type WITH NO DATA;
-SELECT pg_relation_is_scannable('tm'::regclass);
- pg_relation_is_scannable
---------------------------
+SELECT relispopulated FROM pg_class WHERE oid = 'tm'::regclass;
+ relispopulated
+----------------
f
(1 row)
ERROR: materialized view "tm" has not been populated
HINT: Use the REFRESH MATERIALIZED VIEW command.
REFRESH MATERIALIZED VIEW tm;
-SELECT pg_relation_is_scannable('tm'::regclass);
- pg_relation_is_scannable
---------------------------
+SELECT relispopulated FROM pg_class WHERE oid = 'tm'::regclass;
+ relispopulated
+----------------
t
(1 row)
FROM v_test2;
CREATE MATERIALIZED VIEW mv_test3 AS SELECT * FROM mv_test2 WHERE moo = 12345;
-SELECT pg_relation_is_scannable('mv_test3'::regclass);
- pg_relation_is_scannable
---------------------------
+SELECT relispopulated FROM pg_class WHERE oid = 'mv_test3'::regclass;
+ relispopulated
+----------------
t
(1 row)
| pg_get_userbyid(c.relowner) AS matviewowner, +
| t.spcname AS tablespace, +
| c.relhasindex AS hasindexes, +
- | pg_relation_is_scannable(c.oid) AS isscannable, +
+ | c.relispopulated AS ispopulated, +
| pg_get_viewdef(c.oid) AS definition +
| FROM ((pg_class c +
| LEFT JOIN pg_namespace n ON ((n.oid = c.relnamespace))) +
EXPLAIN (costs off)
CREATE MATERIALIZED VIEW tm AS SELECT type, sum(amt) AS totamt FROM t GROUP BY type WITH NO DATA;
CREATE MATERIALIZED VIEW tm AS SELECT type, sum(amt) AS totamt FROM t GROUP BY type WITH NO DATA;
-SELECT pg_relation_is_scannable('tm'::regclass);
+SELECT relispopulated FROM pg_class WHERE oid = 'tm'::regclass;
SELECT * FROM tm;
REFRESH MATERIALIZED VIEW tm;
-SELECT pg_relation_is_scannable('tm'::regclass);
+SELECT relispopulated FROM pg_class WHERE oid = 'tm'::regclass;
CREATE UNIQUE INDEX tm_type ON tm (type);
SELECT * FROM tm;
CREATE MATERIALIZED VIEW mv_test2 AS SELECT moo, 2*moo FROM v_test2 UNION ALL SELECT moo, 3*moo FROM v_test2;
\d+ mv_test2
CREATE MATERIALIZED VIEW mv_test3 AS SELECT * FROM mv_test2 WHERE moo = 12345;
-SELECT pg_relation_is_scannable('mv_test3'::regclass);
+SELECT relispopulated FROM pg_class WHERE oid = 'mv_test3'::regclass;
DROP VIEW v_test1 CASCADE;