1 /*-------------------------------------------------------------------------
4 * Execution of CREATE TABLE ... AS, a/k/a SELECT INTO.
5 * Since CREATE MATERIALIZED VIEW shares syntax and most behaviors,
6 * we implement that here, too.
8 * We implement this by diverting the query's normal output to a
9 * specialized DestReceiver type.
11 * Formerly, CTAS was implemented as a variant of SELECT, which led
12 * to assorted legacy behaviors that we still try to preserve, notably that
13 * we must return a tuples-processed count in the QueryCompletion. (We no
14 * longer do that for CTAS ... WITH NO DATA, however.)
16 * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
17 * Portions Copyright (c) 1994, Regents of the University of California
21 * src/backend/commands/createas.c
23 *-------------------------------------------------------------------------
27 #include "access/heapam.h"
28 #include "access/reloptions.h"
29 #include "access/tableam.h"
30 #include "access/xact.h"
31 #include "catalog/namespace.h"
32 #include "catalog/toasting.h"
33 #include "commands/createas.h"
34 #include "commands/matview.h"
35 #include "commands/prepare.h"
36 #include "commands/tablecmds.h"
37 #include "commands/view.h"
38 #include "nodes/makefuncs.h"
39 #include "nodes/nodeFuncs.h"
40 #include "nodes/queryjumble.h"
41 #include "parser/analyze.h"
42 #include "rewrite/rewriteHandler.h"
43 #include "tcop/tcopprot.h"
44 #include "utils/builtins.h"
45 #include "utils/lsyscache.h"
46 #include "utils/rls.h"
47 #include "utils/snapmgr.h"
51 DestReceiver pub
; /* publicly-known function pointers */
52 IntoClause
*into
; /* target relation specification */
53 /* These fields are filled by intorel_startup: */
54 Relation rel
; /* relation to write to */
55 ObjectAddress reladdr
; /* address of rel, for ExecCreateTableAs */
56 CommandId output_cid
; /* cmin to insert in output tuples */
57 int ti_options
; /* table_tuple_insert performance options */
58 BulkInsertState bistate
; /* bulk insert state */
61 /* utility functions for CTAS definition creation */
62 static ObjectAddress
create_ctas_internal(List
*attrList
, IntoClause
*into
);
63 static ObjectAddress
create_ctas_nodata(List
*tlist
, IntoClause
*into
);
65 /* DestReceiver routines for collecting data */
66 static void intorel_startup(DestReceiver
*self
, int operation
, TupleDesc typeinfo
);
67 static bool intorel_receive(TupleTableSlot
*slot
, DestReceiver
*self
);
68 static void intorel_shutdown(DestReceiver
*self
);
69 static void intorel_destroy(DestReceiver
*self
);
73 * create_ctas_internal
75 * Internal utility used for the creation of the definition of a relation
76 * created via CREATE TABLE AS or a materialized view. Caller needs to
77 * provide a list of attributes (ColumnDef nodes).
80 create_ctas_internal(List
*attrList
, IntoClause
*into
)
82 CreateStmt
*create
= makeNode(CreateStmt
);
86 const char *const validnsps
[] = HEAP_RELOPT_NAMESPACES
;
87 ObjectAddress intoRelationAddr
;
89 /* This code supports both CREATE TABLE AS and CREATE MATERIALIZED VIEW */
90 is_matview
= (into
->viewQuery
!= NULL
);
91 relkind
= is_matview
? RELKIND_MATVIEW
: RELKIND_RELATION
;
94 * Create the target relation by faking up a CREATE TABLE parsetree and
95 * passing it to DefineRelation.
97 create
->relation
= into
->rel
;
98 create
->tableElts
= attrList
;
99 create
->inhRelations
= NIL
;
100 create
->ofTypename
= NULL
;
101 create
->constraints
= NIL
;
102 create
->options
= into
->options
;
103 create
->oncommit
= into
->onCommit
;
104 create
->tablespacename
= into
->tableSpaceName
;
105 create
->if_not_exists
= false;
106 create
->accessMethod
= into
->accessMethod
;
109 * Create the relation. (This will error out if there's an existing view,
110 * so we don't need more code to complain if "replace" is false.)
112 intoRelationAddr
= DefineRelation(create
, relkind
, InvalidOid
, NULL
, NULL
);
115 * If necessary, create a TOAST table for the target table. Note that
116 * NewRelationCreateToastTable ends with CommandCounterIncrement(), so
117 * that the TOAST table will be visible for insertion.
119 CommandCounterIncrement();
121 /* parse and validate reloptions for the toast table */
122 toast_options
= transformRelOptions((Datum
) 0,
128 (void) heap_reloptions(RELKIND_TOASTVALUE
, toast_options
, true);
130 NewRelationCreateToastTable(intoRelationAddr
.objectId
, toast_options
);
132 /* Create the "view" part of a materialized view. */
135 /* StoreViewQuery scribbles on tree, so make a copy */
136 Query
*query
= copyObject(into
->viewQuery
);
138 StoreViewQuery(intoRelationAddr
.objectId
, query
, false);
139 CommandCounterIncrement();
142 return intoRelationAddr
;
149 * Create CTAS or materialized view when WITH NO DATA is used, starting from
150 * the targetlist of the SELECT or view definition.
153 create_ctas_nodata(List
*tlist
, IntoClause
*into
)
160 * Build list of ColumnDefs from non-junk elements of the tlist. If a
161 * column name list was specified in CREATE TABLE AS, override the column
162 * names in the query. (Too few column names are OK, too many are not.)
165 lc
= list_head(into
->colNames
);
168 TargetEntry
*tle
= (TargetEntry
*) lfirst(t
);
177 colname
= strVal(lfirst(lc
));
178 lc
= lnext(into
->colNames
, lc
);
181 colname
= tle
->resname
;
183 col
= makeColumnDef(colname
,
184 exprType((Node
*) tle
->expr
),
185 exprTypmod((Node
*) tle
->expr
),
186 exprCollation((Node
*) tle
->expr
));
189 * It's possible that the column is of a collatable type but the
190 * collation could not be resolved, so double-check. (We must
191 * check this here because DefineRelation would adopt the type's
192 * default collation rather than complaining.)
194 if (!OidIsValid(col
->collOid
) &&
195 type_is_collatable(col
->typeName
->typeOid
))
197 (errcode(ERRCODE_INDETERMINATE_COLLATION
),
198 errmsg("no collation was derived for column \"%s\" with collatable type %s",
200 format_type_be(col
->typeName
->typeOid
)),
201 errhint("Use the COLLATE clause to set the collation explicitly.")));
203 attrList
= lappend(attrList
, col
);
209 (errcode(ERRCODE_SYNTAX_ERROR
),
210 errmsg("too many column names were specified")));
212 /* Create the relation definition using the ColumnDef list */
213 return create_ctas_internal(attrList
, into
);
218 * ExecCreateTableAs -- execute a CREATE TABLE AS command
221 ExecCreateTableAs(ParseState
*pstate
, CreateTableAsStmt
*stmt
,
222 ParamListInfo params
, QueryEnvironment
*queryEnv
,
225 Query
*query
= castNode(Query
, stmt
->query
);
226 IntoClause
*into
= stmt
->into
;
227 JumbleState
*jstate
= NULL
;
228 bool is_matview
= (into
->viewQuery
!= NULL
);
229 bool do_refresh
= false;
231 ObjectAddress address
;
233 /* Check if the relation exists or not */
234 if (CreateTableAsRelExists(stmt
))
235 return InvalidObjectAddress
;
238 * Create the tuple receiver object and insert info it will need
240 dest
= CreateIntoRelDestReceiver(into
);
242 /* Query contained by CTAS needs to be jumbled if requested */
243 if (IsQueryIdEnabled())
244 jstate
= JumbleQuery(query
);
246 if (post_parse_analyze_hook
)
247 (*post_parse_analyze_hook
) (pstate
, query
, jstate
);
250 * The contained Query could be a SELECT, or an EXECUTE utility command.
251 * If the latter, we just pass it off to ExecuteQuery.
253 if (query
->commandType
== CMD_UTILITY
&&
254 IsA(query
->utilityStmt
, ExecuteStmt
))
256 ExecuteStmt
*estmt
= castNode(ExecuteStmt
, query
->utilityStmt
);
258 Assert(!is_matview
); /* excluded by syntax */
259 ExecuteQuery(pstate
, estmt
, into
, params
, dest
, qc
);
261 /* get object address that intorel_startup saved for us */
262 address
= ((DR_intorel
*) dest
)->reladdr
;
266 Assert(query
->commandType
== CMD_SELECT
);
269 * For materialized views, always skip data during table creation, and use
270 * REFRESH instead (see below).
274 do_refresh
= !into
->skipData
;
275 into
->skipData
= true;
281 * If WITH NO DATA was specified, do not go through the rewriter,
282 * planner and executor. Just define the relation using a code path
283 * similar to CREATE VIEW. This avoids dump/restore problems stemming
284 * from running the planner before all dependencies are set up.
286 address
= create_ctas_nodata(query
->targetList
, into
);
289 * For materialized views, reuse the REFRESH logic, which locks down
290 * security-restricted operations and restricts the search_path. This
291 * reduces the chance that a subsequent refresh will fail.
294 RefreshMatViewByOid(address
.objectId
, true, false, false,
295 pstate
->p_sourcetext
, qc
);
302 QueryDesc
*queryDesc
;
307 * Parse analysis was done already, but we still have to run the rule
308 * rewriter. We do not do AcquireRewriteLocks: we assume the query
309 * either came straight from the parser, or suitable locks were
310 * acquired by plancache.c.
312 rewritten
= QueryRewrite(query
);
314 /* SELECT should never rewrite to more or less than one SELECT query */
315 if (list_length(rewritten
) != 1)
316 elog(ERROR
, "unexpected rewrite result for CREATE TABLE AS SELECT");
317 query
= linitial_node(Query
, rewritten
);
318 Assert(query
->commandType
== CMD_SELECT
);
321 plan
= pg_plan_query(query
, pstate
->p_sourcetext
,
322 CURSOR_OPT_PARALLEL_OK
, params
);
325 * Use a snapshot with an updated command ID to ensure this query sees
326 * results of any previously executed queries. (This could only
327 * matter if the planner executed an allegedly-stable function that
328 * changed the database contents, but let's do it anyway to be
329 * parallel to the EXPLAIN code path.)
331 PushCopiedSnapshot(GetActiveSnapshot());
332 UpdateActiveSnapshotCommandId();
334 /* Create a QueryDesc, redirecting output to our tuple receiver */
335 queryDesc
= CreateQueryDesc(plan
, pstate
->p_sourcetext
,
336 GetActiveSnapshot(), InvalidSnapshot
,
337 dest
, params
, queryEnv
, 0);
339 /* call ExecutorStart to prepare the plan for execution */
340 ExecutorStart(queryDesc
, GetIntoRelEFlags(into
));
342 /* run the plan to completion */
343 ExecutorRun(queryDesc
, ForwardScanDirection
, 0);
345 /* save the rowcount if we're given a qc to fill */
347 SetQueryCompletion(qc
, CMDTAG_SELECT
, queryDesc
->estate
->es_processed
);
349 /* get object address that intorel_startup saved for us */
350 address
= ((DR_intorel
*) dest
)->reladdr
;
353 ExecutorFinish(queryDesc
);
354 ExecutorEnd(queryDesc
);
356 FreeQueryDesc(queryDesc
);
365 * GetIntoRelEFlags --- compute executor flags needed for CREATE TABLE AS
367 * This is exported because EXPLAIN and PREPARE need it too. (Note: those
368 * callers still need to deal explicitly with the skipData flag; since they
369 * use different methods for suppressing execution, it doesn't seem worth
370 * trying to encapsulate that part.)
373 GetIntoRelEFlags(IntoClause
*intoClause
)
377 if (intoClause
->skipData
)
378 flags
|= EXEC_FLAG_WITH_NO_DATA
;
384 * CreateTableAsRelExists --- check existence of relation for CreateTableAsStmt
386 * Utility wrapper checking if the relation pending for creation in this
387 * CreateTableAsStmt query already exists or not. Returns true if the
388 * relation exists, otherwise false.
391 CreateTableAsRelExists(CreateTableAsStmt
*ctas
)
395 ObjectAddress address
;
396 IntoClause
*into
= ctas
->into
;
398 nspid
= RangeVarGetCreationNamespace(into
->rel
);
400 oldrelid
= get_relname_relid(into
->rel
->relname
, nspid
);
401 if (OidIsValid(oldrelid
))
403 if (!ctas
->if_not_exists
)
405 (errcode(ERRCODE_DUPLICATE_TABLE
),
406 errmsg("relation \"%s\" already exists",
407 into
->rel
->relname
)));
410 * The relation exists and IF NOT EXISTS has been specified.
412 * If we are in an extension script, insist that the pre-existing
413 * object be a member of the extension, to avoid security risks.
415 ObjectAddressSet(address
, RelationRelationId
, oldrelid
);
416 checkMembershipInCurrentExtension(&address
);
420 (errcode(ERRCODE_DUPLICATE_TABLE
),
421 errmsg("relation \"%s\" already exists, skipping",
422 into
->rel
->relname
)));
426 /* Relation does not exist, it can be created */
431 * CreateIntoRelDestReceiver -- create a suitable DestReceiver object
433 * intoClause will be NULL if called from CreateDestReceiver(), in which
434 * case it has to be provided later. However, it is convenient to allow
435 * self->into to be filled in immediately for other callers.
438 CreateIntoRelDestReceiver(IntoClause
*intoClause
)
440 DR_intorel
*self
= (DR_intorel
*) palloc0(sizeof(DR_intorel
));
442 self
->pub
.receiveSlot
= intorel_receive
;
443 self
->pub
.rStartup
= intorel_startup
;
444 self
->pub
.rShutdown
= intorel_shutdown
;
445 self
->pub
.rDestroy
= intorel_destroy
;
446 self
->pub
.mydest
= DestIntoRel
;
447 self
->into
= intoClause
;
448 /* other private fields will be set during intorel_startup */
450 return (DestReceiver
*) self
;
454 * intorel_startup --- executor startup
457 intorel_startup(DestReceiver
*self
, int operation
, TupleDesc typeinfo
)
459 DR_intorel
*myState
= (DR_intorel
*) self
;
460 IntoClause
*into
= myState
->into
;
463 ObjectAddress intoRelationAddr
;
464 Relation intoRelationDesc
;
468 Assert(into
!= NULL
); /* else somebody forgot to set it */
470 /* This code supports both CREATE TABLE AS and CREATE MATERIALIZED VIEW */
471 is_matview
= (into
->viewQuery
!= NULL
);
474 * Build column definitions using "pre-cooked" type and collation info. If
475 * a column name list was specified in CREATE TABLE AS, override the
476 * column names derived from the query. (Too few column names are OK, too
480 lc
= list_head(into
->colNames
);
481 for (attnum
= 0; attnum
< typeinfo
->natts
; attnum
++)
483 Form_pg_attribute attribute
= TupleDescAttr(typeinfo
, attnum
);
489 colname
= strVal(lfirst(lc
));
490 lc
= lnext(into
->colNames
, lc
);
493 colname
= NameStr(attribute
->attname
);
495 col
= makeColumnDef(colname
,
497 attribute
->atttypmod
,
498 attribute
->attcollation
);
501 * It's possible that the column is of a collatable type but the
502 * collation could not be resolved, so double-check. (We must check
503 * this here because DefineRelation would adopt the type's default
504 * collation rather than complaining.)
506 if (!OidIsValid(col
->collOid
) &&
507 type_is_collatable(col
->typeName
->typeOid
))
509 (errcode(ERRCODE_INDETERMINATE_COLLATION
),
510 errmsg("no collation was derived for column \"%s\" with collatable type %s",
512 format_type_be(col
->typeName
->typeOid
)),
513 errhint("Use the COLLATE clause to set the collation explicitly.")));
515 attrList
= lappend(attrList
, col
);
520 (errcode(ERRCODE_SYNTAX_ERROR
),
521 errmsg("too many column names were specified")));
524 * Actually create the target table
526 intoRelationAddr
= create_ctas_internal(attrList
, into
);
529 * Finally we can open the target table
531 intoRelationDesc
= table_open(intoRelationAddr
.objectId
, AccessExclusiveLock
);
534 * Make sure the constructed table does not have RLS enabled.
536 * check_enable_rls() will ereport(ERROR) itself if the user has requested
537 * something invalid, and otherwise will return RLS_ENABLED if RLS should
538 * be enabled here. We don't actually support that currently, so throw
539 * our own ereport(ERROR) if that happens.
541 if (check_enable_rls(intoRelationAddr
.objectId
, InvalidOid
, false) == RLS_ENABLED
)
543 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED
),
544 errmsg("policies not yet implemented for this command")));
547 * Tentatively mark the target as populated, if it's a matview and we're
548 * going to fill it; otherwise, no change needed.
550 if (is_matview
&& !into
->skipData
)
551 SetMatViewPopulatedState(intoRelationDesc
, true);
554 * Fill private fields of myState for use by later routines
556 myState
->rel
= intoRelationDesc
;
557 myState
->reladdr
= intoRelationAddr
;
558 myState
->output_cid
= GetCurrentCommandId(true);
559 myState
->ti_options
= TABLE_INSERT_SKIP_FSM
;
562 * If WITH NO DATA is specified, there is no need to set up the state for
563 * bulk inserts as there are no tuples to insert.
566 myState
->bistate
= GetBulkInsertState();
568 myState
->bistate
= NULL
;
571 * Valid smgr_targblock implies something already wrote to the relation.
572 * This may be harmless, but this function hasn't planned for it.
574 Assert(RelationGetTargetBlock(intoRelationDesc
) == InvalidBlockNumber
);
578 * intorel_receive --- receive one tuple
581 intorel_receive(TupleTableSlot
*slot
, DestReceiver
*self
)
583 DR_intorel
*myState
= (DR_intorel
*) self
;
585 /* Nothing to insert if WITH NO DATA is specified. */
586 if (!myState
->into
->skipData
)
589 * Note that the input slot might not be of the type of the target
590 * relation. That's supported by table_tuple_insert(), but slightly
591 * less efficient than inserting with the right slot - but the
592 * alternative would be to copy into a slot of the right type, which
593 * would not be cheap either. This also doesn't allow accessing per-AM
594 * data (say a tuple's xmin), but since we don't do that here...
596 table_tuple_insert(myState
->rel
,
603 /* We know this is a newly created relation, so there are no indexes */
609 * intorel_shutdown --- executor end
612 intorel_shutdown(DestReceiver
*self
)
614 DR_intorel
*myState
= (DR_intorel
*) self
;
615 IntoClause
*into
= myState
->into
;
619 FreeBulkInsertState(myState
->bistate
);
620 table_finish_bulk_insert(myState
->rel
, myState
->ti_options
);
623 /* close rel, but keep lock until commit */
624 table_close(myState
->rel
, NoLock
);
629 * intorel_destroy --- release DestReceiver object
632 intorel_destroy(DestReceiver
*self
)