Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit52e6e33

Browse files
committed
Create a distinction between a populated matview and a scannable one.
The intent was that being populated would, long term, be just oneof the conditions which could affect whether a matview wasscannable; being populated should be necessary but not alwayssufficient to scan the relation. Since only CREATE and REFRESHcurrently determine the scannability, names and commentsaccidentally conflated these concepts, leading to confusion.Also add missing locking for the SQL function which allows atest for scannability, and fix a modularity violatiion.Per complaints from Tom Lane, although its not clear that thesewill satisfy his concerns. Hopefully this will at least betterframe the discussion.
1 parent0bf42a5 commit52e6e33

File tree

10 files changed

+81
-58
lines changed

10 files changed

+81
-58
lines changed

‎src/backend/commands/cluster.c

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -381,13 +381,14 @@ cluster_rel(Oid tableOid, Oid indexOid, bool recheck, bool verbose,
381381
check_index_is_clusterable(OldHeap,indexOid,recheck,AccessExclusiveLock);
382382

383383
/*
384-
* Quietly ignore the request if the a materialized view is not scannable.
385-
* No harm is done because there is nothing no data to deal with, and we
386-
* don't want to throw an error if this is part of a multi-relation
387-
* request -- for example, CLUSTER was run on the entire database.
384+
* Quietly ignore the request if this is a materialized view which has not
385+
* been populated from its query. No harm is done because there is no data
386+
* to deal with, and we don't want to throw an error if this is part of a
387+
* multi-relation request -- for example, CLUSTER was run on the entire
388+
* database.
388389
*/
389390
if (OldHeap->rd_rel->relkind==RELKIND_MATVIEW&&
390-
!OldHeap->rd_isscannable)
391+
!OldHeap->rd_ispopulated)
391392
{
392393
relation_close(OldHeap,AccessExclusiveLock);
393394
return;
@@ -923,7 +924,7 @@ copy_heap_data(Oid OIDNewHeap, Oid OIDOldHeap, Oid OIDOldIndex,
923924

924925
if (OldHeap->rd_rel->relkind==RELKIND_MATVIEW)
925926
/* Make sure the heap looks good even if no rows are written. */
926-
SetRelationIsScannable(NewHeap);
927+
SetMatViewToPopulated(NewHeap);
927928

928929
/*
929930
* Scan through the OldHeap, either in OldIndex order or sequentially;

‎src/backend/commands/createas.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -417,7 +417,7 @@ intorel_startup(DestReceiver *self, int operation, TupleDesc typeinfo)
417417

418418
if (into->relkind==RELKIND_MATVIEW&& !into->skipData)
419419
/* Make sure the heap looks good even if no rows are written. */
420-
SetRelationIsScannable(intoRelationDesc);
420+
SetMatViewToPopulated(intoRelationDesc);
421421

422422
/*
423423
* Check INSERT permission on the constructed table.

‎src/backend/commands/matview.c

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -52,22 +52,21 @@ static void refresh_matview_datafill(DestReceiver *dest, Query *query,
5252
constchar*queryString);
5353

5454
/*
55-
*SetRelationIsScannable
56-
*Maketherelation appear scannable.
55+
*SetMatViewToPopulated
56+
*Indicate thatthematerialized view has been populated by its query.
5757
*
58-
* NOTE: This is only implemented for materialized views. The heap starts out
59-
* in a state that doesn't look scannable, and can only transition from there
60-
* to scannable, unless a new heap is created.
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.
6160
*
6261
* NOTE: caller must be holding an appropriate lock on the relation.
6362
*/
6463
void
65-
SetRelationIsScannable(Relationrelation)
64+
SetMatViewToPopulated(Relationrelation)
6665
{
6766
Pagepage;
6867

6968
Assert(relation->rd_rel->relkind==RELKIND_MATVIEW);
70-
Assert(relation->rd_isscannable== false);
69+
Assert(relation->rd_ispopulated== false);
7170

7271
page= (Page)palloc(BLCKSZ);
7372
PageInit(page,BLCKSZ,0);
@@ -323,7 +322,7 @@ transientrel_startup(DestReceiver *self, int operation, TupleDesc typeinfo)
323322
myState->hi_options |=HEAP_INSERT_SKIP_WAL;
324323
myState->bistate=GetBulkInsertState();
325324

326-
SetRelationIsScannable(transientrel);
325+
SetMatViewToPopulated(transientrel);
327326

328327
/* Not using WAL requires smgr_targblock be initially invalid */
329328
Assert(RelationGetTargetBlock(transientrel)==InvalidBlockNumber);

‎src/backend/executor/execMain.c

Lines changed: 30 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -499,7 +499,8 @@ ExecutorRewind(QueryDesc *queryDesc)
499499
*Check that relations which are to be accessed are in a scannable
500500
*state.
501501
*
502-
* If not, throw error. For a materialized view, suggest refresh.
502+
* Currently the only relations which are not are materialized views which
503+
* have not been populated by their queries.
503504
*/
504505
staticvoid
505506
ExecCheckRelationsScannable(List*rangeTable)
@@ -513,42 +514,39 @@ ExecCheckRelationsScannable(List *rangeTable)
513514
if (rte->rtekind!=RTE_RELATION)
514515
continue;
515516

516-
if (!RelationIdIsScannable(rte->relid))
517-
{
518-
if (rte->relkind==RELKIND_MATVIEW)
519-
{
520-
/* It is OK to replace the contents of an invalid matview. */
521-
if (rte->isResultRel)
522-
continue;
517+
if (rte->relkind!=RELKIND_MATVIEW)
518+
continue;
523519

524-
ereport(ERROR,
525-
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
526-
errmsg("materialized view \"%s\" has not been populated",
527-
get_rel_name(rte->relid)),
528-
errhint("Use the REFRESH MATERIALIZED VIEW command.")));
529-
}
530-
else
531-
/* This should never happen, so elog will do. */
532-
elog(ERROR,"relation \"%s\" is not flagged as scannable",
533-
get_rel_name(rte->relid));
534-
}
520+
/* It is OK to target an unpopulated materialized for results. */
521+
if (rte->isResultRel)
522+
continue;
523+
524+
if (!RelationIdIsScannable(rte->relid))
525+
ereport(ERROR,
526+
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
527+
errmsg("materialized view \"%s\" has not been populated",
528+
get_rel_name(rte->relid)),
529+
errhint("Use the REFRESH MATERIALIZED VIEW command.")));
535530
}
536531
}
537532

538533
/*
539-
* Tells whether a relation is scannable.
534+
* Tells whether a relation is scannable based on its OID.
535+
*
536+
* Currently only non-populated materialized views are not. This is likely to
537+
* change to include other conditions.
540538
*
541-
*Currentlyonlynon-populated materialzed views are not.
539+
*This shouldonlybe called while a lock is held on the relation.
542540
*/
543541
staticbool
544542
RelationIdIsScannable(Oidrelid)
545543
{
546544
Relationrelation;
547545
boolresult;
548546

549-
relation=RelationIdGetRelation(relid);
550-
result=relation->rd_isscannable;
551-
RelationClose(relation);
547+
relation=heap_open(relid,NoLock);
548+
result=RelationIsScannable(relation);
549+
heap_close(relation,NoLock);
552550

553551
returnresult;
554552
}
@@ -945,7 +943,14 @@ InitPlan(QueryDesc *queryDesc, int eflags)
945943

946944
/*
947945
* Unless we are creating a view or are creating a materialized view WITH
948-
* NO DATA, ensure that all referenced relations are scannable.
946+
* NO DATA, ensure that all referenced relations are scannable. The
947+
* omitted cases will be checked as SELECT statements in a different
948+
* phase, so checking again here would be wasteful and it would generate
949+
* errors on a materialized view referenced as a target.
950+
*
951+
* NB: This is being done after all relations are locked, files have been
952+
* opened, etc., to avoid duplicating that effort or creating deadlock
953+
* possibilities.
949954
*/
950955
if ((eflags&EXEC_FLAG_WITH_NO_DATA)==0)
951956
ExecCheckRelationsScannable(rangeTable);

‎src/backend/rewrite/rewriteHandler.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1615,7 +1615,8 @@ fireRIRrules(Query *parsetree, List *activeRIRs, bool forUpdatePushedDown)
16151615
* expansion doesn't give us a lot to work with, so we are trusting
16161616
* earlier validations to throw error if needed.
16171617
*/
1618-
if (rel->rd_rel->relkind==RELKIND_MATVIEW&&rel->rd_isscannable)
1618+
if (rel->rd_rel->relkind==RELKIND_MATVIEW&&
1619+
RelationIsScannable(rel))
16191620
{
16201621
heap_close(rel,NoLock);
16211622
continue;

‎src/backend/utils/adt/dbsize.c

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -840,7 +840,8 @@ pg_relation_filepath(PG_FUNCTION_ARGS)
840840
* Indicate whether a relation is scannable.
841841
*
842842
* Currently, this is always true except for a materialized view which has not
843-
* been populated.
843+
* been populated. It is expected that other conditions for allowing a
844+
* materialized view to be scanned will be added in later releases.
844845
*/
845846
Datum
846847
pg_relation_is_scannable(PG_FUNCTION_ARGS)
@@ -850,9 +851,13 @@ pg_relation_is_scannable(PG_FUNCTION_ARGS)
850851
boolresult;
851852

852853
relid=PG_GETARG_OID(0);
853-
relation=RelationIdGetRelation(relid);
854-
result=relation->rd_isscannable;
855-
RelationClose(relation);
854+
relation=try_relation_open(relid,AccessShareLock);
856855

856+
if (relation==NULL)
857+
PG_RETURN_BOOL(false);
858+
859+
result=RelationIsScannable(relation);
860+
861+
relation_close(relation,AccessShareLock);
857862
PG_RETURN_BOOL(result);
858863
}

‎src/backend/utils/cache/relcache.c

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -958,9 +958,9 @@ RelationBuildDesc(Oid targetRelId, bool insertIt)
958958

959959
if (relation->rd_rel->relkind==RELKIND_MATVIEW&&
960960
heap_is_matview_init_state(relation))
961-
relation->rd_isscannable= false;
961+
relation->rd_ispopulated= false;
962962
else
963-
relation->rd_isscannable= true;
963+
relation->rd_ispopulated= true;
964964

965965
/*
966966
* now we can free the memory allocated for pg_class_tuple
@@ -1531,7 +1531,7 @@ formrdesc(const char *relationName, Oid relationReltype,
15311531
* initialize physical addressing information for the relation
15321532
*/
15331533
RelationInitPhysicalAddr(relation);
1534-
relation->rd_isscannable= true;
1534+
relation->rd_ispopulated= true;
15351535

15361536
/*
15371537
* initialize the rel-has-index flag, using hardwired knowledge
@@ -1756,7 +1756,7 @@ RelationReloadIndexInfo(Relation relation)
17561756
heap_freetuple(pg_class_tuple);
17571757
/* We must recalculate physical address in case it changed */
17581758
RelationInitPhysicalAddr(relation);
1759-
relation->rd_isscannable= true;
1759+
relation->rd_ispopulated= true;
17601760

17611761
/*
17621762
* For a non-system index, there are fields of the pg_index row that are
@@ -1907,9 +1907,9 @@ RelationClearRelation(Relation relation, bool rebuild)
19071907
RelationInitPhysicalAddr(relation);
19081908
if (relation->rd_rel->relkind==RELKIND_MATVIEW&&
19091909
heap_is_matview_init_state(relation))
1910-
relation->rd_isscannable= false;
1910+
relation->rd_ispopulated= false;
19111911
else
1912-
relation->rd_isscannable= true;
1912+
relation->rd_ispopulated= true;
19131913

19141914
if (relation->rd_rel->relkind==RELKIND_INDEX)
19151915
{
@@ -2700,9 +2700,9 @@ RelationBuildLocalRelation(const char *relname,
27002700

27012701
/* materialized view not initially scannable */
27022702
if (relkind==RELKIND_MATVIEW)
2703-
rel->rd_isscannable= false;
2703+
rel->rd_ispopulated= false;
27042704
else
2705-
rel->rd_isscannable= true;
2705+
rel->rd_ispopulated= true;
27062706

27072707
/*
27082708
* Okay to insert into the relcache hash tables.
@@ -4450,9 +4450,9 @@ load_relcache_init_file(bool shared)
44504450
RelationInitPhysicalAddr(rel);
44514451
if (rel->rd_rel->relkind==RELKIND_MATVIEW&&
44524452
heap_is_matview_init_state(rel))
4453-
rel->rd_isscannable= false;
4453+
rel->rd_ispopulated= false;
44544454
else
4455-
rel->rd_isscannable= true;
4455+
rel->rd_ispopulated= true;
44564456
}
44574457

44584458
/*

‎src/bin/pg_dump/pg_dump.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4264,7 +4264,8 @@ getTables(Archive *fout, int *numTables)
42644264
"c.relhasindex, c.relhasrules, c.relhasoids, "
42654265
"c.relfrozenxid, tc.oid AS toid, "
42664266
"tc.relfrozenxid AS tfrozenxid, "
4267-
"c.relpersistence, pg_relation_is_scannable(c.oid) as isscannable, "
4267+
"c.relpersistence, "
4268+
"CASE WHEN c.relkind = '%c' THEN pg_relation_is_scannable(c.oid) ELSE 't'::bool END as isscannable, "
42684269
"c.relpages, "
42694270
"CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
42704271
"d.refobjid AS owning_tab, "
@@ -4282,6 +4283,7 @@ getTables(Archive *fout, int *numTables)
42824283
"WHERE c.relkind in ('%c', '%c', '%c', '%c', '%c', '%c') "
42834284
"ORDER BY c.oid",
42844285
username_subquery,
4286+
RELKIND_MATVIEW,
42854287
RELKIND_SEQUENCE,
42864288
RELKIND_RELATION,RELKIND_SEQUENCE,
42874289
RELKIND_VIEW,RELKIND_COMPOSITE_TYPE,

‎src/include/commands/matview.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
#include"utils/relcache.h"
2121

2222

23-
externvoidSetRelationIsScannable(Relationrelation);
23+
externvoidSetMatViewToPopulated(Relationrelation);
2424

2525
externvoidExecRefreshMatView(RefreshMatViewStmt*stmt,constchar*queryString,
2626
ParamListInfoparams,char*completionTag);

‎src/include/utils/rel.h

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ typedef struct RelationData
8383
BackendIdrd_backend;/* owning backend id, if temporary relation */
8484
boolrd_islocaltemp;/* rel is a temp rel of this session */
8585
boolrd_isnailed;/* rel is nailed in cache */
86-
boolrd_isscannable;/*rel can be scanned */
86+
boolrd_ispopulated;/*matview has query results */
8787
boolrd_isvalid;/* relcache entry is valid */
8888
charrd_indexvalid;/* state of rd_indexlist: 0 = not valid, 1 =
8989
* valid, 2 = temporarily forced */
@@ -407,6 +407,16 @@ typedef struct StdRdOptions
407407
((relation)->rd_rel->relpersistence == RELPERSISTENCE_TEMP && \
408408
!(relation)->rd_islocaltemp)
409409

410+
411+
/*
412+
* RelationIsScannable
413+
* Currently can only be false for a materialized view which has not been
414+
* populated by its query. This is likely to get more complicated later,
415+
* so use a macro which looks like a function.
416+
*/
417+
#defineRelationIsScannable(relation) ((relation)->rd_ispopulated)
418+
419+
410420
/* routines in utils/cache/relcache.c */
411421
externvoidRelationIncrementReferenceCount(Relationrel);
412422
externvoidRelationDecrementReferenceCount(Relationrel);

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp