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

Commit0b33790

Browse files
committed
Clean up the mess around EXPLAIN and materialized views.
Revert the matview-related changes in explain.c's API, as per recentcomplaint from Robert Haas. The reason for these appears to have beenprincipally some ill-considered choices around having intorel_startup dowhat ought to be parse-time checking, plus a poor arrangement for passingit the view parsetree it needs to store into pg_rewrite when creating amaterialized view. Do the latter by having parse analysis stick a copyinto the IntoClause, instead of doing it at runtime. (On the whole,I seriously question the choice to represent CREATE MATERIALIZED VIEW as avariant of SELECT INTO/CREATE TABLE AS, because that means injecting evenmore complexity into what was already a horrid legacy kluge. However,I didn't go so far as to rethink that choice ... yet.)I also moved several error checks into matview parse analysis, andmade the check for external Params in a matview more accurate.In passing, clean things up a bit more around interpretOidsOption(),and fix things so that we can use that to force no-oids for views,sequences, etc, thereby eliminating the need to cons up "oids = false"options when creating them.catversion bump due to change in IntoClause. (I wonder though if wereally need readfuncs/outfuncs support for IntoClause anymore.)
1 parent5003f94 commit0b33790

26 files changed

+230
-226
lines changed

‎src/backend/commands/createas.c

Lines changed: 43 additions & 99 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
/*-------------------------------------------------------------------------
22
*
33
* createas.c
4-
* Execution of CREATE TABLE ... AS, a/k/a SELECT INTO
4+
* Execution of CREATE TABLE ... AS, a/k/a SELECT INTO.
55
* Since CREATE MATERIALIZED VIEW shares syntax and most behaviors,
6-
* implement that here, too.
6+
*weimplement that here, too.
77
*
88
* We implement this by diverting the query's normal output to a
99
* specialized DestReceiver type.
1010
*
11-
* Formerly,this command was implemented as a variant of SELECT, which led
11+
* Formerly,CTAS was implemented as a variant of SELECT, which led
1212
* to assorted legacy behaviors that we still try to preserve, notably that
1313
* we must return a tuples-processed count in the completionTag.
1414
*
@@ -33,7 +33,6 @@
3333
#include"commands/prepare.h"
3434
#include"commands/tablecmds.h"
3535
#include"commands/view.h"
36-
#include"parser/analyze.h"
3736
#include"parser/parse_clause.h"
3837
#include"rewrite/rewriteHandler.h"
3938
#include"storage/smgr.h"
@@ -48,7 +47,6 @@ typedef struct
4847
{
4948
DestReceiverpub;/* publicly-known function pointers */
5049
IntoClause*into;/* target relation specification */
51-
Query*viewParse;/* the query which defines/populates data */
5250
/* These fields are filled by intorel_startup: */
5351
Relationrel;/* relation to write to */
5452
CommandIdoutput_cid;/* cmin to insert in output tuples */
@@ -62,62 +60,6 @@ static void intorel_shutdown(DestReceiver *self);
6260
staticvoidintorel_destroy(DestReceiver*self);
6361

6462

65-
/*
66-
* Common setup needed by both normal execution and EXPLAIN ANALYZE.
67-
*/
68-
Query*
69-
SetupForCreateTableAs(Query*query,IntoClause*into,constchar*queryString,
70-
ParamListInfoparams,DestReceiver*dest)
71-
{
72-
List*rewritten;
73-
Query*viewParse=NULL;
74-
75-
Assert(query->commandType==CMD_SELECT);
76-
77-
if (into->relkind==RELKIND_MATVIEW)
78-
viewParse= (Query*)parse_analyze((Node*)copyObject(query),
79-
queryString,NULL,0)->utilityStmt;
80-
81-
/*
82-
* Parse analysis was done already, but we still have to run the rule
83-
* rewriter. We do not do AcquireRewriteLocks: we assume the query either
84-
* came straight from the parser, or suitable locks were acquired by
85-
* plancache.c.
86-
*
87-
* Because the rewriter and planner tend to scribble on the input, we make
88-
* a preliminary copy of the source querytree.This prevents problems in
89-
* the case that CTAS is in a portal or plpgsql function and is executed
90-
* repeatedly.(See also the same hack in EXPLAIN and PREPARE.)
91-
*/
92-
rewritten=QueryRewrite((Query*)copyObject(query));
93-
94-
/* SELECT should never rewrite to more or less than one SELECT query */
95-
if (list_length(rewritten)!=1)
96-
elog(ERROR,"unexpected rewrite result for CREATE TABLE AS SELECT");
97-
query= (Query*)linitial(rewritten);
98-
99-
Assert(query->commandType==CMD_SELECT);
100-
101-
/* Save the query after rewrite but before planning. */
102-
((DR_intorel*)dest)->viewParse=viewParse;
103-
((DR_intorel*)dest)->into=into;
104-
105-
if (into->relkind==RELKIND_MATVIEW)
106-
{
107-
/*
108-
* A materialized view would either need to save parameters for use in
109-
* maintaining or loading the data or prohibit them entirely. The
110-
* latter seems safer and more sane.
111-
*/
112-
if (params!=NULL&&params->numParams>0)
113-
ereport(ERROR,
114-
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
115-
errmsg("materialized views may not be defined using bound parameters")));
116-
}
117-
118-
returnquery;
119-
}
120-
12163
/*
12264
* ExecCreateTableAs -- execute a CREATE TABLE AS command
12365
*/
@@ -128,6 +70,7 @@ ExecCreateTableAs(CreateTableAsStmt *stmt, const char *queryString,
12870
Query*query= (Query*)stmt->query;
12971
IntoClause*into=stmt->into;
13072
DestReceiver*dest;
73+
List*rewritten;
13174
PlannedStmt*plan;
13275
QueryDesc*queryDesc;
13376
ScanDirectiondir;
@@ -151,8 +94,26 @@ ExecCreateTableAs(CreateTableAsStmt *stmt, const char *queryString,
15194

15295
return;
15396
}
97+
Assert(query->commandType==CMD_SELECT);
15498

155-
query=SetupForCreateTableAs(query,into,queryString,params,dest);
99+
/*
100+
* Parse analysis was done already, but we still have to run the rule
101+
* rewriter. We do not do AcquireRewriteLocks: we assume the query either
102+
* came straight from the parser, or suitable locks were acquired by
103+
* plancache.c.
104+
*
105+
* Because the rewriter and planner tend to scribble on the input, we make
106+
* a preliminary copy of the source querytree.This prevents problems in
107+
* the case that CTAS is in a portal or plpgsql function and is executed
108+
* repeatedly.(See also the same hack in EXPLAIN and PREPARE.)
109+
*/
110+
rewritten=QueryRewrite((Query*)copyObject(query));
111+
112+
/* SELECT should never rewrite to more or less than one SELECT query */
113+
if (list_length(rewritten)!=1)
114+
elog(ERROR,"unexpected rewrite result for CREATE TABLE AS SELECT");
115+
query= (Query*)linitial(rewritten);
116+
Assert(query->commandType==CMD_SELECT);
156117

157118
/* plan the query */
158119
plan=pg_plan_query(query,0,params);
@@ -213,20 +174,20 @@ int
213174
GetIntoRelEFlags(IntoClause*intoClause)
214175
{
215176
intflags;
177+
216178
/*
217179
* We need to tell the executor whether it has to produce OIDs or not,
218180
* because it doesn't have enough information to do so itself (since we
219181
* can't build the target relation until after ExecutorStart).
182+
*
183+
* Disallow the OIDS option for materialized views.
220184
*/
221-
if (interpretOidsOption(intoClause->options,intoClause->relkind))
185+
if (interpretOidsOption(intoClause->options,
186+
(intoClause->viewQuery==NULL)))
222187
flags=EXEC_FLAG_WITH_OIDS;
223188
else
224189
flags=EXEC_FLAG_WITHOUT_OIDS;
225190

226-
Assert(intoClause->relkind!=RELKIND_MATVIEW||
227-
(flags& (EXEC_FLAG_WITH_OIDS |EXEC_FLAG_WITHOUT_OIDS))==
228-
EXEC_FLAG_WITHOUT_OIDS);
229-
230191
if (intoClause->skipData)
231192
flags |=EXEC_FLAG_WITH_NO_DATA;
232193

@@ -264,6 +225,8 @@ intorel_startup(DestReceiver *self, int operation, TupleDesc typeinfo)
264225
{
265226
DR_intorel*myState= (DR_intorel*)self;
266227
IntoClause*into=myState->into;
228+
boolis_matview;
229+
charrelkind;
267230
CreateStmt*create;
268231
OidintoRelationId;
269232
RelationintoRelationDesc;
@@ -275,6 +238,10 @@ intorel_startup(DestReceiver *self, int operation, TupleDesc typeinfo)
275238

276239
Assert(into!=NULL);/* else somebody forgot to set it */
277240

241+
/* This code supports both CREATE TABLE AS and CREATE MATERIALIZED VIEW */
242+
is_matview= (into->viewQuery!=NULL);
243+
relkind=is_matview ?RELKIND_MATVIEW :RELKIND_RELATION;
244+
278245
/*
279246
* Create the target relation by faking up a CREATE TABLE parsetree and
280247
* passing it to DefineRelation.
@@ -352,38 +319,12 @@ intorel_startup(DestReceiver *self, int operation, TupleDesc typeinfo)
352319
if (lc!=NULL)
353320
ereport(ERROR,
354321
(errcode(ERRCODE_SYNTAX_ERROR),
355-
errmsg("too many column names are specified")));
356-
357-
/*
358-
* Enforce validations needed for materialized views only.
359-
*/
360-
if (into->relkind==RELKIND_MATVIEW)
361-
{
362-
/*
363-
* Prohibit a data-modifying CTE in the query used to create a
364-
* materialized view. It's not sufficiently clear what the user would
365-
* want to happen if the MV is refreshed or incrementally maintained.
366-
*/
367-
if (myState->viewParse->hasModifyingCTE)
368-
ereport(ERROR,
369-
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
370-
errmsg("materialized views must not use data-modifying statements in WITH")));
371-
372-
/*
373-
* Check whether any temporary database objects are used in the
374-
* creation query. It would be hard to refresh data or incrementally
375-
* maintain it if a source disappeared.
376-
*/
377-
if (isQueryUsingTempRelation(myState->viewParse))
378-
ereport(ERROR,
379-
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
380-
errmsg("materialized views must not use temporary tables or views")));
381-
}
322+
errmsg("too many column names were specified")));
382323

383324
/*
384325
* Actually create the target table
385326
*/
386-
intoRelationId=DefineRelation(create,into->relkind,InvalidOid);
327+
intoRelationId=DefineRelation(create,relkind,InvalidOid);
387328

388329
/*
389330
* If necessary, create a TOAST table for the target table. Note that
@@ -404,9 +345,12 @@ intorel_startup(DestReceiver *self, int operation, TupleDesc typeinfo)
404345
AlterTableCreateToastTable(intoRelationId,toast_options);
405346

406347
/* Create the "view" part of a materialized view. */
407-
if (into->relkind==RELKIND_MATVIEW)
348+
if (is_matview)
408349
{
409-
StoreViewQuery(intoRelationId,myState->viewParse, false);
350+
/* StoreViewQuery scribbles on tree, so make a copy */
351+
Query*query= (Query*)copyObject(into->viewQuery);
352+
353+
StoreViewQuery(intoRelationId,query, false);
410354
CommandCounterIncrement();
411355
}
412356

@@ -415,7 +359,7 @@ intorel_startup(DestReceiver *self, int operation, TupleDesc typeinfo)
415359
*/
416360
intoRelationDesc=heap_open(intoRelationId,AccessExclusiveLock);
417361

418-
if (into->relkind==RELKIND_MATVIEW&& !into->skipData)
362+
if (is_matview&& !into->skipData)
419363
/* Make sure the heap looks good even if no rows are written. */
420364
SetMatViewToPopulated(intoRelationDesc);
421365

@@ -428,7 +372,7 @@ intorel_startup(DestReceiver *self, int operation, TupleDesc typeinfo)
428372
rte=makeNode(RangeTblEntry);
429373
rte->rtekind=RTE_RELATION;
430374
rte->relid=intoRelationId;
431-
rte->relkind=into->relkind;
375+
rte->relkind=relkind;
432376
rte->isResultRel= true;
433377
rte->requiredPerms=ACL_INSERT;
434378

‎src/backend/commands/explain.c

Lines changed: 21 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ explain_get_index_name_hook_type explain_get_index_name_hook = NULL;
4747
#defineX_NOWHITESPACE 4
4848

4949
staticvoidExplainOneQuery(Query*query,IntoClause*into,ExplainState*es,
50-
constchar*queryString,DestReceiver*dest,ParamListInfoparams);
50+
constchar*queryString,ParamListInfoparams);
5151
staticvoidreport_triggers(ResultRelInfo*rInfo,boolshow_relname,
5252
ExplainState*es);
5353
staticdoubleelapsed_time(instr_time*starttime);
@@ -219,7 +219,7 @@ ExplainQuery(ExplainStmt *stmt, const char *queryString,
219219
foreach(l,rewritten)
220220
{
221221
ExplainOneQuery((Query*)lfirst(l),NULL,&es,
222-
queryString,None_Receiver,params);
222+
queryString,params);
223223

224224
/* Separate plans with an appropriate separator */
225225
if (lnext(l)!=NULL)
@@ -300,8 +300,7 @@ ExplainResultDesc(ExplainStmt *stmt)
300300
*/
301301
staticvoid
302302
ExplainOneQuery(Query*query,IntoClause*into,ExplainState*es,
303-
constchar*queryString,DestReceiver*dest,
304-
ParamListInfoparams)
303+
constchar*queryString,ParamListInfoparams)
305304
{
306305
/* planner will not cope with utility statements */
307306
if (query->commandType==CMD_UTILITY)
@@ -312,7 +311,7 @@ ExplainOneQuery(Query *query, IntoClause *into, ExplainState *es,
312311

313312
/* if an advisor plugin is present, let it manage things */
314313
if (ExplainOneQuery_hook)
315-
(*ExplainOneQuery_hook) (query,into,es,queryString,dest,params);
314+
(*ExplainOneQuery_hook) (query,into,es,queryString,params);
316315
else
317316
{
318317
PlannedStmt*plan;
@@ -321,7 +320,7 @@ ExplainOneQuery(Query *query, IntoClause *into, ExplainState *es,
321320
plan=pg_plan_query(query,0,params);
322321

323322
/* run it (if needed) and produce output */
324-
ExplainOnePlan(plan,into,es,queryString,dest,params);
323+
ExplainOnePlan(plan,into,es,queryString,params);
325324
}
326325
}
327326

@@ -345,23 +344,19 @@ ExplainOneUtility(Node *utilityStmt, IntoClause *into, ExplainState *es,
345344

346345
if (IsA(utilityStmt,CreateTableAsStmt))
347346
{
348-
DestReceiver*dest;
349-
350347
/*
351348
* We have to rewrite the contained SELECT and then pass it back to
352349
* ExplainOneQuery. It's probably not really necessary to copy the
353350
* contained parsetree another time, but let's be safe.
354351
*/
355352
CreateTableAsStmt*ctas= (CreateTableAsStmt*)utilityStmt;
356-
Query*query= (Query*)ctas->query;
357-
358-
dest=CreateIntoRelDestReceiver(into);
353+
List*rewritten;
359354

360355
Assert(IsA(ctas->query,Query));
361-
362-
query=SetupForCreateTableAs(query,ctas->into,queryString,params,dest);
363-
364-
ExplainOneQuery(query,ctas->into,es,queryString,dest,params);
356+
rewritten=QueryRewrite((Query*)copyObject(ctas->query));
357+
Assert(list_length(rewritten)==1);
358+
ExplainOneQuery((Query*)linitial(rewritten),ctas->into,es,
359+
queryString,params);
365360
}
366361
elseif (IsA(utilityStmt,ExecuteStmt))
367362
ExplainExecuteQuery((ExecuteStmt*)utilityStmt,into,es,
@@ -402,8 +397,9 @@ ExplainOneUtility(Node *utilityStmt, IntoClause *into, ExplainState *es,
402397
*/
403398
void
404399
ExplainOnePlan(PlannedStmt*plannedstmt,IntoClause*into,ExplainState*es,
405-
constchar*queryString,DestReceiver*dest,ParamListInfoparams)
400+
constchar*queryString,ParamListInfoparams)
406401
{
402+
DestReceiver*dest;
407403
QueryDesc*queryDesc;
408404
instr_timestarttime;
409405
doubletotaltime=0;
@@ -427,6 +423,15 @@ ExplainOnePlan(PlannedStmt *plannedstmt, IntoClause *into, ExplainState *es,
427423
PushCopiedSnapshot(GetActiveSnapshot());
428424
UpdateActiveSnapshotCommandId();
429425

426+
/*
427+
* Normally we discard the query's output, but if explaining CREATE TABLE
428+
* AS, we'd better use the appropriate tuple receiver.
429+
*/
430+
if (into)
431+
dest=CreateIntoRelDestReceiver(into);
432+
else
433+
dest=None_Receiver;
434+
430435
/* Create a QueryDesc for the query */
431436
queryDesc=CreateQueryDesc(plannedstmt,queryString,
432437
GetActiveSnapshot(),InvalidSnapshot,

‎src/backend/commands/prepare.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -665,7 +665,7 @@ ExplainExecuteQuery(ExecuteStmt *execstmt, IntoClause *into, ExplainState *es,
665665
PlannedStmt*pstmt= (PlannedStmt*)lfirst(p);
666666

667667
if (IsA(pstmt,PlannedStmt))
668-
ExplainOnePlan(pstmt,into,es,query_string,None_Receiver,paramLI);
668+
ExplainOnePlan(pstmt,into,es,query_string,paramLI);
669669
else
670670
ExplainOneUtility((Node*)pstmt,into,es,query_string,paramLI);
671671

‎src/backend/commands/sequence.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -210,7 +210,7 @@ DefineSequence(CreateSeqStmt *seq)
210210
stmt->relation=seq->sequence;
211211
stmt->inhRelations=NIL;
212212
stmt->constraints=NIL;
213-
stmt->options=list_make1(defWithOids(false));
213+
stmt->options=NIL;
214214
stmt->oncommit=ONCOMMIT_NOOP;
215215
stmt->tablespacename=NULL;
216216
stmt->if_not_exists= false;

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp