Skip to content

Commit 5194024

Browse files
committed
Incidental cleanup of matviews code.
Move checking for unscannable matviews into ExecOpenScanRelation, which is a better place for it first because the open relation is already available (saving a relcache lookup cycle), and second because this eliminates the problem of telling the difference between rangetable entries that will or will not be scanned by the query. In particular we can get rid of the not-terribly-well-thought-out-or-implemented isResultRel field that the initial matviews patch added to RangeTblEntry. Also get rid of entirely unnecessary scannability check in the rewriter, and a bogus decision about whether RefreshMatViewStmt requires a parse-time snapshot. catversion bump due to removal of a RangeTblEntry field, which changes stored rules.
1 parent f5d576c commit 5194024

19 files changed

+49
-141
lines changed

src/backend/commands/createas.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -373,7 +373,6 @@ intorel_startup(DestReceiver *self, int operation, TupleDesc typeinfo)
373373
rte->rtekind = RTE_RELATION;
374374
rte->relid = intoRelationId;
375375
rte->relkind = relkind;
376-
rte->isResultRel = true;
377376
rte->requiredPerms = ACL_INSERT;
378377

379378
for (attnum = 1; attnum <= intoRelationDesc->rd_att->natts; attnum++)

src/backend/commands/matview.c

Lines changed: 1 addition & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -215,10 +215,8 @@ refresh_matview_datafill(DestReceiver *dest, Query *query,
215215
List *rewritten;
216216
PlannedStmt *plan;
217217
QueryDesc *queryDesc;
218-
List *rtable;
219-
RangeTblEntry *initial_rte;
220-
RangeTblEntry *second_rte;
221218

219+
/* Rewrite, copying the given Query to make sure it's not changed */
222220
rewritten = QueryRewrite((Query *) copyObject(query));
223221

224222
/* SELECT should never rewrite to more or less than one SELECT query */
@@ -229,26 +227,6 @@ refresh_matview_datafill(DestReceiver *dest, Query *query,
229227
/* Check for user-requested abort. */
230228
CHECK_FOR_INTERRUPTS();
231229

232-
/*
233-
* Kludge here to allow refresh of a materialized view which is invalid
234-
* (that is, it was created or refreshed WITH NO DATA. We flag the first
235-
* two RangeTblEntry list elements, which were added to the front of the
236-
* rewritten Query to keep the rules system happy, with the isResultRel
237-
* flag to indicate that it is OK if they are flagged as invalid. See
238-
* UpdateRangeTableOfViewParse() for details.
239-
*
240-
* NOTE: The rewrite has switched the frist two RTEs, but they are still
241-
* in the first two positions. If that behavior changes, the asserts here
242-
* will fail.
243-
*/
244-
rtable = query->rtable;
245-
initial_rte = ((RangeTblEntry *) linitial(rtable));
246-
Assert(strcmp(initial_rte->alias->aliasname, "new"));
247-
initial_rte->isResultRel = true;
248-
second_rte = ((RangeTblEntry *) lsecond(rtable));
249-
Assert(strcmp(second_rte->alias->aliasname, "old"));
250-
second_rte->isResultRel = true;
251-
252230
/* Plan the query which will generate data for the refresh. */
253231
plan = pg_plan_query(query, 0, NULL);
254232

src/backend/executor/execMain.c

Lines changed: 0 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,6 @@ static char *ExecBuildSlotValueDescription(TupleTableSlot *slot,
8585
int maxfieldlen);
8686
static void EvalPlanQualStart(EPQState *epqstate, EState *parentestate,
8787
Plan *planTree);
88-
static bool RelationIdIsScannable(Oid relid);
8988

9089
/* end of local decls */
9190

@@ -494,63 +493,6 @@ ExecutorRewind(QueryDesc *queryDesc)
494493
}
495494

496495

497-
/*
498-
* ExecCheckRelationsScannable
499-
* Check that relations which are to be accessed are in a scannable
500-
* state.
501-
*
502-
* Currently the only relations which are not are materialized views which
503-
* have not been populated by their queries.
504-
*/
505-
static void
506-
ExecCheckRelationsScannable(List *rangeTable)
507-
{
508-
ListCell *l;
509-
510-
foreach(l, rangeTable)
511-
{
512-
RangeTblEntry *rte = (RangeTblEntry *) lfirst(l);
513-
514-
if (rte->rtekind != RTE_RELATION)
515-
continue;
516-
517-
if (rte->relkind != RELKIND_MATVIEW)
518-
continue;
519-
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.")));
530-
}
531-
}
532-
533-
/*
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.
538-
*
539-
* This should only be called while a lock is held on the relation.
540-
*/
541-
static bool
542-
RelationIdIsScannable(Oid relid)
543-
{
544-
Relation relation;
545-
bool result;
546-
547-
relation = heap_open(relid, NoLock);
548-
result = RelationIsScannable(relation);
549-
heap_close(relation, NoLock);
550-
551-
return result;
552-
}
553-
554496
/*
555497
* ExecCheckRTPerms
556498
* Check access permissions for all relations listed in a range table.
@@ -941,20 +883,6 @@ InitPlan(QueryDesc *queryDesc, int eflags)
941883
*/
942884
planstate = ExecInitNode(plan, estate, eflags);
943885

944-
/*
945-
* Unless we are creating a view or are creating a materialized view WITH
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.
954-
*/
955-
if ((eflags & EXEC_FLAG_WITH_NO_DATA) == 0)
956-
ExecCheckRelationsScannable(rangeTable);
957-
958886
/*
959887
* Get the tuple descriptor describing the type of tuples to return.
960888
*/

src/backend/executor/execUtils.c

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -798,8 +798,9 @@ ExecRelationIsTargetRelation(EState *estate, Index scanrelid)
798798
* ----------------------------------------------------------------
799799
*/
800800
Relation
801-
ExecOpenScanRelation(EState *estate, Index scanrelid)
801+
ExecOpenScanRelation(EState *estate, Index scanrelid, int eflags)
802802
{
803+
Relation rel;
803804
Oid reloid;
804805
LOCKMODE lockmode;
805806

@@ -827,9 +828,24 @@ ExecOpenScanRelation(EState *estate, Index scanrelid)
827828
}
828829
}
829830

830-
/* OK, open the relation and acquire lock as needed */
831+
/* Open the relation and acquire lock as needed */
831832
reloid = getrelid(scanrelid, estate->es_range_table);
832-
return heap_open(reloid, lockmode);
833+
rel = heap_open(reloid, lockmode);
834+
835+
/*
836+
* Complain if we're attempting a scan of an unscannable relation, except
837+
* when the query won't actually be run. This is a slightly klugy place
838+
* to do this, perhaps, but there is no better place.
839+
*/
840+
if ((eflags & (EXEC_FLAG_EXPLAIN_ONLY | EXEC_FLAG_WITH_NO_DATA)) == 0 &&
841+
!RelationIsScannable(rel))
842+
ereport(ERROR,
843+
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
844+
errmsg("materialized view \"%s\" has not been populated",
845+
RelationGetRelationName(rel)),
846+
errhint("Use the REFRESH MATERIALIZED VIEW command.")));
847+
848+
return rel;
833849
}
834850

835851
/* ----------------------------------------------------------------

src/backend/executor/nodeBitmapHeapscan.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -587,7 +587,7 @@ ExecInitBitmapHeapScan(BitmapHeapScan *node, EState *estate, int eflags)
587587
/*
588588
* open the base relation and acquire appropriate lock on it.
589589
*/
590-
currentRelation = ExecOpenScanRelation(estate, node->scan.scanrelid);
590+
currentRelation = ExecOpenScanRelation(estate, node->scan.scanrelid, eflags);
591591

592592
scanstate->ss.ss_currentRelation = currentRelation;
593593

src/backend/executor/nodeForeignscan.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ ExecInitForeignScan(ForeignScan *node, EState *estate, int eflags)
143143
/*
144144
* open the base relation and acquire appropriate lock on it.
145145
*/
146-
currentRelation = ExecOpenScanRelation(estate, node->scan.scanrelid);
146+
currentRelation = ExecOpenScanRelation(estate, node->scan.scanrelid, eflags);
147147
scanstate->ss.ss_currentRelation = currentRelation;
148148

149149
/*

src/backend/executor/nodeIndexonlyscan.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -410,7 +410,7 @@ ExecInitIndexOnlyScan(IndexOnlyScan *node, EState *estate, int eflags)
410410
/*
411411
* open the base relation and acquire appropriate lock on it.
412412
*/
413-
currentRelation = ExecOpenScanRelation(estate, node->scan.scanrelid);
413+
currentRelation = ExecOpenScanRelation(estate, node->scan.scanrelid, eflags);
414414

415415
indexstate->ss.ss_currentRelation = currentRelation;
416416
indexstate->ss.ss_currentScanDesc = NULL; /* no heap scan here */

src/backend/executor/nodeIndexscan.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -511,7 +511,7 @@ ExecInitIndexScan(IndexScan *node, EState *estate, int eflags)
511511
/*
512512
* open the base relation and acquire appropriate lock on it.
513513
*/
514-
currentRelation = ExecOpenScanRelation(estate, node->scan.scanrelid);
514+
currentRelation = ExecOpenScanRelation(estate, node->scan.scanrelid, eflags);
515515

516516
indexstate->ss.ss_currentRelation = currentRelation;
517517
indexstate->ss.ss_currentScanDesc = NULL; /* no heap scan here */

src/backend/executor/nodeSeqscan.c

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
#include "executor/nodeSeqscan.h"
3030
#include "utils/rel.h"
3131

32-
static void InitScanRelation(SeqScanState *node, EState *estate);
32+
static void InitScanRelation(SeqScanState *node, EState *estate, int eflags);
3333
static TupleTableSlot *SeqNext(SeqScanState *node);
3434

3535
/* ----------------------------------------------------------------
@@ -118,12 +118,11 @@ ExecSeqScan(SeqScanState *node)
118118
/* ----------------------------------------------------------------
119119
* InitScanRelation
120120
*
121-
* This does the initialization for scan relations and
122-
* subplans of scans.
121+
* Set up to access the scan relation.
123122
* ----------------------------------------------------------------
124123
*/
125124
static void
126-
InitScanRelation(SeqScanState *node, EState *estate)
125+
InitScanRelation(SeqScanState *node, EState *estate, int eflags)
127126
{
128127
Relation currentRelation;
129128
HeapScanDesc currentScanDesc;
@@ -133,8 +132,10 @@ InitScanRelation(SeqScanState *node, EState *estate)
133132
* open that relation and acquire appropriate lock on it.
134133
*/
135134
currentRelation = ExecOpenScanRelation(estate,
136-
((SeqScan *) node->ps.plan)->scanrelid);
135+
((SeqScan *) node->ps.plan)->scanrelid,
136+
eflags);
137137

138+
/* initialize a heapscan */
138139
currentScanDesc = heap_beginscan(currentRelation,
139140
estate->es_snapshot,
140141
0,
@@ -143,6 +144,7 @@ InitScanRelation(SeqScanState *node, EState *estate)
143144
node->ss_currentRelation = currentRelation;
144145
node->ss_currentScanDesc = currentScanDesc;
145146

147+
/* and report the scan tuple slot's rowtype */
146148
ExecAssignScanType(node, RelationGetDescr(currentRelation));
147149
}
148150

@@ -196,7 +198,7 @@ ExecInitSeqScan(SeqScan *node, EState *estate, int eflags)
196198
/*
197199
* initialize scan relation
198200
*/
199-
InitScanRelation(scanstate, estate);
201+
InitScanRelation(scanstate, estate, eflags);
200202

201203
scanstate->ps.ps_TupFromTlist = false;
202204

src/backend/executor/nodeTidscan.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -531,7 +531,7 @@ ExecInitTidScan(TidScan *node, EState *estate, int eflags)
531531
/*
532532
* open the base relation and acquire appropriate lock on it.
533533
*/
534-
currentRelation = ExecOpenScanRelation(estate, node->scan.scanrelid);
534+
currentRelation = ExecOpenScanRelation(estate, node->scan.scanrelid, eflags);
535535

536536
tidstate->ss.ss_currentRelation = currentRelation;
537537
tidstate->ss.ss_currentScanDesc = NULL; /* no heap scan here */

src/backend/nodes/copyfuncs.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1972,7 +1972,6 @@ _copyRangeTblEntry(const RangeTblEntry *from)
19721972
COPY_SCALAR_FIELD(rtekind);
19731973
COPY_SCALAR_FIELD(relid);
19741974
COPY_SCALAR_FIELD(relkind);
1975-
COPY_SCALAR_FIELD(isResultRel);
19761975
COPY_NODE_FIELD(subquery);
19771976
COPY_SCALAR_FIELD(security_barrier);
19781977
COPY_SCALAR_FIELD(jointype);

src/backend/nodes/equalfuncs.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2234,7 +2234,6 @@ _equalRangeTblEntry(const RangeTblEntry *a, const RangeTblEntry *b)
22342234
COMPARE_SCALAR_FIELD(rtekind);
22352235
COMPARE_SCALAR_FIELD(relid);
22362236
COMPARE_SCALAR_FIELD(relkind);
2237-
COMPARE_SCALAR_FIELD(isResultRel);
22382237
COMPARE_NODE_FIELD(subquery);
22392238
COMPARE_SCALAR_FIELD(security_barrier);
22402239
COMPARE_SCALAR_FIELD(jointype);

src/backend/nodes/outfuncs.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2353,7 +2353,6 @@ _outRangeTblEntry(StringInfo str, const RangeTblEntry *node)
23532353
case RTE_RELATION:
23542354
WRITE_OID_FIELD(relid);
23552355
WRITE_CHAR_FIELD(relkind);
2356-
WRITE_BOOL_FIELD(isResultRel);
23572356
break;
23582357
case RTE_SUBQUERY:
23592358
WRITE_NODE_FIELD(subquery);

src/backend/nodes/readfuncs.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1191,7 +1191,6 @@ _readRangeTblEntry(void)
11911191
case RTE_RELATION:
11921192
READ_OID_FIELD(relid);
11931193
READ_CHAR_FIELD(relkind);
1194-
READ_BOOL_FIELD(isResultRel);
11951194
break;
11961195
case RTE_SUBQUERY:
11971196
READ_NODE_FIELD(subquery);

src/backend/parser/analyze.c

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -325,11 +325,6 @@ analyze_requires_snapshot(Node *parseTree)
325325
result = true;
326326
break;
327327

328-
case T_RefreshMatViewStmt:
329-
/* yes, because the SELECT from pg_rewrite must be analyzed */
330-
result = true;
331-
break;
332-
333328
default:
334329
/* other utility statements don't have any real parse analysis */
335330
result = false;

src/backend/rewrite/rewriteHandler.c

Lines changed: 13 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1579,6 +1579,19 @@ fireRIRrules(Query *parsetree, List *activeRIRs, bool forUpdatePushedDown)
15791579
if (rte->rtekind != RTE_RELATION)
15801580
continue;
15811581

1582+
/*
1583+
* Always ignore RIR rules for materialized views referenced in
1584+
* queries. (This does not prevent refreshing MVs, since they aren't
1585+
* referenced in their own query definitions.)
1586+
*
1587+
* Note: in the future we might want to allow MVs to be conditionally
1588+
* expanded as if they were regular views, if they are not scannable.
1589+
* In that case this test would need to be postponed till after we've
1590+
* opened the rel, so that we could check its state.
1591+
*/
1592+
if (rte->relkind == RELKIND_MATVIEW)
1593+
continue;
1594+
15821595
/*
15831596
* If the table is not referenced in the query, then we ignore it.
15841597
* This prevents infinite expansion loop due to new rtable entries
@@ -1604,24 +1617,6 @@ fireRIRrules(Query *parsetree, List *activeRIRs, bool forUpdatePushedDown)
16041617
*/
16051618
rel = heap_open(rte->relid, NoLock);
16061619

1607-
/*
1608-
* Ignore RIR rules for a materialized view, if it is scannable.
1609-
*
1610-
* NOTE: This is assuming that if an MV is scannable then we always
1611-
* want to use the existing contents, and if it is not scannable we
1612-
* cannot have gotten to this point unless it is being populated
1613-
* (otherwise an error should be thrown). It would be nice to have
1614-
* some way to confirm that we're doing the right thing here, but rule
1615-
* expansion doesn't give us a lot to work with, so we are trusting
1616-
* earlier validations to throw error if needed.
1617-
*/
1618-
if (rel->rd_rel->relkind == RELKIND_MATVIEW &&
1619-
RelationIsScannable(rel))
1620-
{
1621-
heap_close(rel, NoLock);
1622-
continue;
1623-
}
1624-
16251620
/*
16261621
* Collect the RIR rules that we must apply
16271622
*/

src/include/catalog/catversion.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,6 @@
5353
*/
5454

5555
/* yyyymmddN */
56-
#define CATALOG_VERSION_NO 201304151
56+
#define CATALOG_VERSION_NO 201304271
5757

5858
#endif

src/include/executor/executor.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -341,7 +341,7 @@ extern void ExecAssignScanTypeFromOuterPlan(ScanState *scanstate);
341341

342342
extern bool ExecRelationIsTargetRelation(EState *estate, Index scanrelid);
343343

344-
extern Relation ExecOpenScanRelation(EState *estate, Index scanrelid);
344+
extern Relation ExecOpenScanRelation(EState *estate, Index scanrelid, int eflags);
345345
extern void ExecCloseScanRelation(Relation scanrel);
346346

347347
extern void ExecOpenIndices(ResultRelInfo *resultRelInfo);

src/include/nodes/parsenodes.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -713,7 +713,6 @@ typedef struct RangeTblEntry
713713
*/
714714
Oid relid; /* OID of the relation */
715715
char relkind; /* relation kind (see pg_class.relkind) */
716-
bool isResultRel; /* used in target of SELECT INTO or similar */
717716

718717
/*
719718
* Fields valid for a subquery RTE (else NULL):
@@ -2461,7 +2460,7 @@ typedef struct CreateTableAsStmt
24612460
NodeTag type;
24622461
Node *query; /* the query (see comments above) */
24632462
IntoClause *into; /* destination table */
2464-
ObjectType relkind; /* type of object */
2463+
ObjectType relkind; /* OBJECT_TABLE or OBJECT_MATVIEW */
24652464
bool is_select_into; /* it was written as SELECT INTO */
24662465
} CreateTableAsStmt;
24672466

0 commit comments

Comments
 (0)