PostgreSQL Source Code git master
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
createas.c File Reference
#include "postgres.h"
#include "access/heapam.h"
#include "access/reloptions.h"
#include "access/tableam.h"
#include "access/xact.h"
#include "catalog/namespace.h"
#include "catalog/toasting.h"
#include "commands/createas.h"
#include "commands/matview.h"
#include "commands/prepare.h"
#include "commands/tablecmds.h"
#include "commands/view.h"
#include "executor/execdesc.h"
#include "executor/executor.h"
#include "nodes/makefuncs.h"
#include "nodes/nodeFuncs.h"
#include "nodes/queryjumble.h"
#include "parser/analyze.h"
#include "rewrite/rewriteHandler.h"
#include "tcop/tcopprot.h"
#include "utils/builtins.h"
#include "utils/lsyscache.h"
#include "utils/rls.h"
#include "utils/snapmgr.h"
Include dependency graph for createas.c:

Go to the source code of this file.

Data Structures

struct  DR_intorel
 

Functions

static ObjectAddress create_ctas_internal (List *attrList, IntoClause *into)
 
static ObjectAddress create_ctas_nodata (List *tlist, IntoClause *into)
 
static void intorel_startup (DestReceiver *self, int operation, TupleDesc typeinfo)
 
static bool intorel_receive (TupleTableSlot *slot, DestReceiver *self)
 
static void intorel_shutdown (DestReceiver *self)
 
static void intorel_destroy (DestReceiver *self)
 
ObjectAddress ExecCreateTableAs (ParseState *pstate, CreateTableAsStmt *stmt, ParamListInfo params, QueryEnvironment *queryEnv, QueryCompletion *qc)
 
int GetIntoRelEFlags (IntoClause *intoClause)
 
bool CreateTableAsRelExists (CreateTableAsStmt *ctas)
 
DestReceiverCreateIntoRelDestReceiver (IntoClause *intoClause)
 

Function Documentation

◆ create_ctas_internal()

static ObjectAddress create_ctas_internal ( List attrList,
IntoClause into 
)
static

Definition at line 82 of file createas.c.

83{
85 bool is_matview;
86 char relkind;
87 Datum toast_options;
88 const char *const validnsps[] = HEAP_RELOPT_NAMESPACES;
89 ObjectAddress intoRelationAddr;
90
91 /* This code supports both CREATE TABLE AS and CREATE MATERIALIZED VIEW */
92 is_matview = (into->viewQuery != NULL);
93 relkind = is_matview ? RELKIND_MATVIEW : RELKIND_RELATION;
94
95 /*
96 * Create the target relation by faking up a CREATE TABLE parsetree and
97 * passing it to DefineRelation.
98 */
99 create->relation = into->rel;
100 create->tableElts = attrList;
101 create->inhRelations = NIL;
102 create->ofTypename = NULL;
103 create->constraints = NIL;
104 create->options = into->options;
105 create->oncommit = into->onCommit;
106 create->tablespacename = into->tableSpaceName;
107 create->if_not_exists = false;
108 create->accessMethod = into->accessMethod;
109
110 /*
111 * Create the relation. (This will error out if there's an existing view,
112 * so we don't need more code to complain if "replace" is false.)
113 */
114 intoRelationAddr = DefineRelation(create, relkind, InvalidOid, NULL, NULL);
115
116 /*
117 * If necessary, create a TOAST table for the target table. Note that
118 * NewRelationCreateToastTable ends with CommandCounterIncrement(), so
119 * that the TOAST table will be visible for insertion.
120 */
122
123 /* parse and validate reloptions for the toast table */
124 toast_options = transformRelOptions((Datum) 0,
125 create->options,
126 "toast",
127 validnsps,
128 true, false);
129
130 (void) heap_reloptions(RELKIND_TOASTVALUE, toast_options, true);
131
132 NewRelationCreateToastTable(intoRelationAddr.objectId, toast_options);
133
134 /* Create the "view" part of a materialized view. */
135 if (is_matview)
136 {
137 /* StoreViewQuery scribbles on tree, so make a copy */
138 Query *query = copyObject(into->viewQuery);
139
140 StoreViewQuery(intoRelationAddr.objectId, query, false);
142 }
143
144 return intoRelationAddr;
145}
#define copyObject(obj)
Definition: nodes.h:230
#define makeNode(_type_)
Definition: nodes.h:161
#define NIL
Definition: pg_list.h:68
uintptr_t Datum
Definition: postgres.h:69
#define InvalidOid
Definition: postgres_ext.h:35
Datum transformRelOptions(Datum oldOptions, List *defList, const char *namspace, const char *const validnsps[], bool acceptOidsOff, bool isReset)
Definition: reloptions.c:1167
bytea * heap_reloptions(char relkind, Datum reloptions, bool validate)
Definition: reloptions.c:2046
#define HEAP_RELOPT_NAMESPACES
Definition: reloptions.h:61
List * tableElts
Definition: parsenodes.h:2740
TypeName * ofTypename
Definition: parsenodes.h:2745
OnCommitAction oncommit
Definition: parsenodes.h:2749
List * options
Definition: parsenodes.h:2748
bool if_not_exists
Definition: parsenodes.h:2752
List * inhRelations
Definition: parsenodes.h:2741
RangeVar * relation
Definition: parsenodes.h:2739
char * tablespacename
Definition: parsenodes.h:2750
char * accessMethod
Definition: parsenodes.h:2751
List * constraints
Definition: parsenodes.h:2746
char * tableSpaceName
Definition: primnodes.h:168
OnCommitAction onCommit
Definition: primnodes.h:167
List * options
Definition: primnodes.h:166
char * accessMethod
Definition: primnodes.h:165
RangeVar * rel
Definition: primnodes.h:163
ObjectAddress DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId, ObjectAddress *typaddress, const char *queryString)
Definition: tablecmds.c:764
void NewRelationCreateToastTable(Oid relOid, Datum reloptions)
Definition: toasting.c:71
void StoreViewQuery(Oid viewOid, Query *viewParse, bool replace)
Definition: view.c:511
void CommandCounterIncrement(void)
Definition: xact.c:1100

References CreateStmt::accessMethod, IntoClause::accessMethod, CommandCounterIncrement(), CreateStmt::constraints, copyObject, DefineRelation(), HEAP_RELOPT_NAMESPACES, heap_reloptions(), CreateStmt::if_not_exists, CreateStmt::inhRelations, InvalidOid, makeNode, NewRelationCreateToastTable(), NIL, ObjectAddress::objectId, CreateStmt::ofTypename, CreateStmt::oncommit, IntoClause::onCommit, CreateStmt::options, IntoClause::options, IntoClause::rel, CreateStmt::relation, StoreViewQuery(), CreateStmt::tableElts, CreateStmt::tablespacename, IntoClause::tableSpaceName, and transformRelOptions().

Referenced by create_ctas_nodata(), and intorel_startup().

◆ create_ctas_nodata()

static ObjectAddress create_ctas_nodata ( List tlist,
IntoClause into 
)
static

Definition at line 155 of file createas.c.

156{
157 List *attrList;
158 ListCell *t,
159 *lc;
160
161 /*
162 * Build list of ColumnDefs from non-junk elements of the tlist. If a
163 * column name list was specified in CREATE TABLE AS, override the column
164 * names in the query. (Too few column names are OK, too many are not.)
165 */
166 attrList = NIL;
167 lc = list_head(into->colNames);
168 foreach(t, tlist)
169 {
170 TargetEntry *tle = (TargetEntry *) lfirst(t);
171
172 if (!tle->resjunk)
173 {
174 ColumnDef *col;
175 char *colname;
176
177 if (lc)
178 {
179 colname = strVal(lfirst(lc));
180 lc = lnext(into->colNames, lc);
181 }
182 else
183 colname = tle->resname;
184
185 col = makeColumnDef(colname,
186 exprType((Node *) tle->expr),
187 exprTypmod((Node *) tle->expr),
188 exprCollation((Node *) tle->expr));
189
190 /*
191 * It's possible that the column is of a collatable type but the
192 * collation could not be resolved, so double-check. (We must
193 * check this here because DefineRelation would adopt the type's
194 * default collation rather than complaining.)
195 */
196 if (!OidIsValid(col->collOid) &&
199 (errcode(ERRCODE_INDETERMINATE_COLLATION),
200 errmsg("no collation was derived for column \"%s\" with collatable type %s",
201 col->colname,
203 errhint("Use the COLLATE clause to set the collation explicitly.")));
204
205 attrList = lappend(attrList, col);
206 }
207 }
208
209 if (lc != NULL)
211 (errcode(ERRCODE_SYNTAX_ERROR),
212 errmsg("too many column names were specified")));
213
214 /* Create the relation definition using the ColumnDef list */
215 return create_ctas_internal(attrList, into);
216}
#define OidIsValid(objectId)
Definition: c.h:746
static ObjectAddress create_ctas_internal(List *attrList, IntoClause *into)
Definition: createas.c:82
int errhint(const char *fmt,...)
Definition: elog.c:1318
int errcode(int sqlerrcode)
Definition: elog.c:854
int errmsg(const char *fmt,...)
Definition: elog.c:1071
#define ERROR
Definition: elog.h:39
#define ereport(elevel,...)
Definition: elog.h:149
char * format_type_be(Oid type_oid)
Definition: format_type.c:343
List * lappend(List *list, void *datum)
Definition: list.c:339
bool type_is_collatable(Oid typid)
Definition: lsyscache.c:3221
ColumnDef * makeColumnDef(const char *colname, Oid typeOid, int32 typmod, Oid collOid)
Definition: makefuncs.c:565
Oid exprType(const Node *expr)
Definition: nodeFuncs.c:42
int32 exprTypmod(const Node *expr)
Definition: nodeFuncs.c:301
Oid exprCollation(const Node *expr)
Definition: nodeFuncs.c:821
#define lfirst(lc)
Definition: pg_list.h:172
static ListCell * list_head(const List *l)
Definition: pg_list.h:128
static ListCell * lnext(const List *l, const ListCell *c)
Definition: pg_list.h:343
char * colname
Definition: parsenodes.h:737
TypeName * typeName
Definition: parsenodes.h:738
Oid collOid
Definition: parsenodes.h:753
List * colNames
Definition: primnodes.h:164
Definition: pg_list.h:54
Definition: nodes.h:135
Expr * expr
Definition: primnodes.h:2219
Oid typeOid
Definition: parsenodes.h:280
#define strVal(v)
Definition: value.h:82

References ColumnDef::collOid, ColumnDef::colname, IntoClause::colNames, create_ctas_internal(), ereport, errcode(), errhint(), errmsg(), ERROR, TargetEntry::expr, exprCollation(), exprType(), exprTypmod(), format_type_be(), lappend(), lfirst, list_head(), lnext(), makeColumnDef(), NIL, OidIsValid, strVal, type_is_collatable(), ColumnDef::typeName, and TypeName::typeOid.

Referenced by ExecCreateTableAs().

◆ CreateIntoRelDestReceiver()

DestReceiver * CreateIntoRelDestReceiver ( IntoClause intoClause)

Definition at line 441 of file createas.c.

442{
443 DR_intorel *self = (DR_intorel *) palloc0(sizeof(DR_intorel));
444
449 self->pub.mydest = DestIntoRel;
450 self->into = intoClause;
451 /* other private fields will be set during intorel_startup */
452
453 return (DestReceiver *) self;
454}
static void intorel_shutdown(DestReceiver *self)
Definition: createas.c:615
static bool intorel_receive(TupleTableSlot *slot, DestReceiver *self)
Definition: createas.c:584
static void intorel_startup(DestReceiver *self, int operation, TupleDesc typeinfo)
Definition: createas.c:460
static void intorel_destroy(DestReceiver *self)
Definition: createas.c:635
@ DestIntoRel
Definition: dest.h:94
void * palloc0(Size size)
Definition: mcxt.c:1973
IntoClause * into
Definition: createas.c:54
DestReceiver pub
Definition: createas.c:53
void(* rStartup)(DestReceiver *self, int operation, TupleDesc typeinfo)
Definition: dest.h:121
void(* rShutdown)(DestReceiver *self)
Definition: dest.h:124
bool(* receiveSlot)(TupleTableSlot *slot, DestReceiver *self)
Definition: dest.h:118
void(* rDestroy)(DestReceiver *self)
Definition: dest.h:126
CommandDest mydest
Definition: dest.h:128

References DestIntoRel, DR_intorel::into, intorel_destroy(), intorel_receive(), intorel_shutdown(), intorel_startup(), _DestReceiver::mydest, palloc0(), DR_intorel::pub, _DestReceiver::rDestroy, _DestReceiver::receiveSlot, _DestReceiver::rShutdown, and _DestReceiver::rStartup.

Referenced by CreateDestReceiver(), ExecCreateTableAs(), and ExplainOnePlan().

◆ CreateTableAsRelExists()

bool CreateTableAsRelExists ( CreateTableAsStmt ctas)

Definition at line 394 of file createas.c.

395{
396 Oid nspid;
397 Oid oldrelid;
398 ObjectAddress address;
399 IntoClause *into = ctas->into;
400
402
403 oldrelid = get_relname_relid(into->rel->relname, nspid);
404 if (OidIsValid(oldrelid))
405 {
406 if (!ctas->if_not_exists)
408 (errcode(ERRCODE_DUPLICATE_TABLE),
409 errmsg("relation \"%s\" already exists",
410 into->rel->relname)));
411
412 /*
413 * The relation exists and IF NOT EXISTS has been specified.
414 *
415 * If we are in an extension script, insist that the pre-existing
416 * object be a member of the extension, to avoid security risks.
417 */
418 ObjectAddressSet(address, RelationRelationId, oldrelid);
420
421 /* OK to skip */
423 (errcode(ERRCODE_DUPLICATE_TABLE),
424 errmsg("relation \"%s\" already exists, skipping",
425 into->rel->relname)));
426 return true;
427 }
428
429 /* Relation does not exist, it can be created */
430 return false;
431}
int nspid
#define NOTICE
Definition: elog.h:35
Oid get_relname_relid(const char *relname, Oid relnamespace)
Definition: lsyscache.c:2025
Oid RangeVarGetCreationNamespace(const RangeVar *newRelation)
Definition: namespace.c:654
#define ObjectAddressSet(addr, class_id, object_id)
Definition: objectaddress.h:40
void checkMembershipInCurrentExtension(const ObjectAddress *object)
Definition: pg_depend.c:258
unsigned int Oid
Definition: postgres_ext.h:30
IntoClause * into
Definition: parsenodes.h:3988
char * relname
Definition: primnodes.h:83

References checkMembershipInCurrentExtension(), ereport, errcode(), errmsg(), ERROR, get_relname_relid(), CreateTableAsStmt::if_not_exists, CreateTableAsStmt::into, NOTICE, nspid, ObjectAddressSet, OidIsValid, RangeVarGetCreationNamespace(), IntoClause::rel, and RangeVar::relname.

Referenced by ExecCreateTableAs(), and ExplainOneUtility().

◆ ExecCreateTableAs()

ObjectAddress ExecCreateTableAs ( ParseState pstate,
CreateTableAsStmt stmt,
ParamListInfo  params,
QueryEnvironment queryEnv,
QueryCompletion qc 
)

Definition at line 223 of file createas.c.

226{
227 Query *query = castNode(Query, stmt->query);
228 IntoClause *into = stmt->into;
229 JumbleState *jstate = NULL;
230 bool is_matview = (into->viewQuery != NULL);
231 bool do_refresh = false;
233 ObjectAddress address;
234
235 /* Check if the relation exists or not */
238
239 /*
240 * Create the tuple receiver object and insert info it will need
241 */
243
244 /* Query contained by CTAS needs to be jumbled if requested */
245 if (IsQueryIdEnabled())
246 jstate = JumbleQuery(query);
247
249 (*post_parse_analyze_hook) (pstate, query, jstate);
250
251 /*
252 * The contained Query could be a SELECT, or an EXECUTE utility command.
253 * If the latter, we just pass it off to ExecuteQuery.
254 */
255 if (query->commandType == CMD_UTILITY &&
256 IsA(query->utilityStmt, ExecuteStmt))
257 {
258 ExecuteStmt *estmt = castNode(ExecuteStmt, query->utilityStmt);
259
260 Assert(!is_matview); /* excluded by syntax */
261 ExecuteQuery(pstate, estmt, into, params, dest, qc);
262
263 /* get object address that intorel_startup saved for us */
264 address = ((DR_intorel *) dest)->reladdr;
265
266 return address;
267 }
268 Assert(query->commandType == CMD_SELECT);
269
270 /*
271 * For materialized views, always skip data during table creation, and use
272 * REFRESH instead (see below).
273 */
274 if (is_matview)
275 {
276 do_refresh = !into->skipData;
277 into->skipData = true;
278 }
279
280 if (into->skipData)
281 {
282 /*
283 * If WITH NO DATA was specified, do not go through the rewriter,
284 * planner and executor. Just define the relation using a code path
285 * similar to CREATE VIEW. This avoids dump/restore problems stemming
286 * from running the planner before all dependencies are set up.
287 */
288 address = create_ctas_nodata(query->targetList, into);
289
290 /*
291 * For materialized views, reuse the REFRESH logic, which locks down
292 * security-restricted operations and restricts the search_path. This
293 * reduces the chance that a subsequent refresh will fail.
294 */
295 if (do_refresh)
296 RefreshMatViewByOid(address.objectId, true, false, false,
297 pstate->p_sourcetext, qc);
298
299 }
300 else
301 {
302 List *rewritten;
304 QueryDesc *queryDesc;
305
306 Assert(!is_matview);
307
308 /*
309 * Parse analysis was done already, but we still have to run the rule
310 * rewriter. We do not do AcquireRewriteLocks: we assume the query
311 * either came straight from the parser, or suitable locks were
312 * acquired by plancache.c.
313 */
314 rewritten = QueryRewrite(query);
315
316 /* SELECT should never rewrite to more or less than one SELECT query */
317 if (list_length(rewritten) != 1)
318 elog(ERROR, "unexpected rewrite result for CREATE TABLE AS SELECT");
319 query = linitial_node(Query, rewritten);
320 Assert(query->commandType == CMD_SELECT);
321
322 /* plan the query */
323 plan = pg_plan_query(query, pstate->p_sourcetext,
324 CURSOR_OPT_PARALLEL_OK, params);
325
326 /*
327 * Use a snapshot with an updated command ID to ensure this query sees
328 * results of any previously executed queries. (This could only
329 * matter if the planner executed an allegedly-stable function that
330 * changed the database contents, but let's do it anyway to be
331 * parallel to the EXPLAIN code path.)
332 */
335
336 /* Create a QueryDesc, redirecting output to our tuple receiver */
337 queryDesc = CreateQueryDesc(plan, NULL, pstate->p_sourcetext,
339 dest, params, queryEnv, 0);
340
341 /* call ExecutorStart to prepare the plan for execution */
342 if (!ExecutorStart(queryDesc, GetIntoRelEFlags(into)))
343 elog(ERROR, "ExecutorStart() failed unexpectedly");
344
345 /* run the plan to completion */
346 ExecutorRun(queryDesc, ForwardScanDirection, 0);
347
348 /* save the rowcount if we're given a qc to fill */
349 if (qc)
350 SetQueryCompletion(qc, CMDTAG_SELECT, queryDesc->estate->es_processed);
351
352 /* get object address that intorel_startup saved for us */
353 address = ((DR_intorel *) dest)->reladdr;
354
355 /* and clean up */
356 ExecutorFinish(queryDesc);
357 ExecutorEnd(queryDesc);
358
359 FreeQueryDesc(queryDesc);
360
362 }
363
364 return address;
365}
void ExecuteQuery(ParseState *pstate, ExecuteStmt *stmt, IntoClause *intoClause, ParamListInfo params, DestReceiver *dest, QueryCompletion *qc)
Definition: prepare.c:150
static void SetQueryCompletion(QueryCompletion *qc, CommandTag commandTag, uint64 nprocessed)
Definition: cmdtag.h:37
bool CreateTableAsRelExists(CreateTableAsStmt *ctas)
Definition: createas.c:394
static ObjectAddress create_ctas_nodata(List *tlist, IntoClause *into)
Definition: createas.c:155
int GetIntoRelEFlags(IntoClause *intoClause)
Definition: createas.c:376
DestReceiver * CreateIntoRelDestReceiver(IntoClause *intoClause)
Definition: createas.c:441
#define elog(elevel,...)
Definition: elog.h:225
bool ExecutorStart(QueryDesc *queryDesc, int eflags)
Definition: execMain.c:128
void ExecutorEnd(QueryDesc *queryDesc)
Definition: execMain.c:538
void ExecutorFinish(QueryDesc *queryDesc)
Definition: execMain.c:475
void ExecutorRun(QueryDesc *queryDesc, ScanDirection direction, uint64 count)
Definition: execMain.c:365
Assert(PointerIsAligned(start, uint64))
#define stmt
Definition: indent_codes.h:59
ObjectAddress RefreshMatViewByOid(Oid matviewOid, bool is_create, bool skipData, bool concurrent, const char *queryString, QueryCompletion *qc)
Definition: matview.c:165
#define IsA(nodeptr, _type_)
Definition: nodes.h:164
@ CMD_UTILITY
Definition: nodes.h:276
@ CMD_SELECT
Definition: nodes.h:271
#define castNode(_type_, nodeptr)
Definition: nodes.h:182
const ObjectAddress InvalidObjectAddress
#define CURSOR_OPT_PARALLEL_OK
Definition: parsenodes.h:3385
post_parse_analyze_hook_type post_parse_analyze_hook
Definition: analyze.c:59
static int list_length(const List *l)
Definition: pg_list.h:152
#define linitial_node(type, l)
Definition: pg_list.h:181
#define plan(x)
Definition: pg_regress.c:161
PlannedStmt * pg_plan_query(Query *querytree, const char *query_string, int cursorOptions, ParamListInfo boundParams)
Definition: postgres.c:882
void FreeQueryDesc(QueryDesc *qdesc)
Definition: pquery.c:112
QueryDesc * CreateQueryDesc(PlannedStmt *plannedstmt, CachedPlan *cplan, const char *sourceText, Snapshot snapshot, Snapshot crosscheck_snapshot, DestReceiver *dest, ParamListInfo params, QueryEnvironment *queryEnv, int instrument_options)
Definition: pquery.c:72
static bool IsQueryIdEnabled(void)
Definition: queryjumble.h:95
JumbleState * JumbleQuery(Query *query)
List * QueryRewrite(Query *parsetree)
@ ForwardScanDirection
Definition: sdir.h:28
void UpdateActiveSnapshotCommandId(void)
Definition: snapmgr.c:731
void PopActiveSnapshot(void)
Definition: snapmgr.c:762
void PushCopiedSnapshot(Snapshot snapshot)
Definition: snapmgr.c:719
Snapshot GetActiveSnapshot(void)
Definition: snapmgr.c:787
#define InvalidSnapshot
Definition: snapshot.h:119
uint64 es_processed
Definition: execnodes.h:712
bool skipData
Definition: primnodes.h:171
EState * estate
Definition: execdesc.h:49

References Assert(), castNode, CMD_SELECT, CMD_UTILITY, Query::commandType, create_ctas_nodata(), CreateIntoRelDestReceiver(), CreateQueryDesc(), CreateTableAsRelExists(), CURSOR_OPT_PARALLEL_OK, generate_unaccent_rules::dest, elog, ERROR, EState::es_processed, QueryDesc::estate, ExecuteQuery(), ExecutorEnd(), ExecutorFinish(), ExecutorRun(), ExecutorStart(), ForwardScanDirection, FreeQueryDesc(), GetActiveSnapshot(), GetIntoRelEFlags(), InvalidObjectAddress, InvalidSnapshot, IsA, IsQueryIdEnabled(), JumbleQuery(), linitial_node, list_length(), ObjectAddress::objectId, ParseState::p_sourcetext, pg_plan_query(), plan, PopActiveSnapshot(), post_parse_analyze_hook, PushCopiedSnapshot(), QueryRewrite(), RefreshMatViewByOid(), SetQueryCompletion(), IntoClause::skipData, stmt, Query::targetList, UpdateActiveSnapshotCommandId(), and Query::utilityStmt.

Referenced by ProcessUtilitySlow().

◆ GetIntoRelEFlags()

int GetIntoRelEFlags ( IntoClause intoClause)

Definition at line 376 of file createas.c.

377{
378 int flags = 0;
379
380 if (intoClause->skipData)
381 flags |= EXEC_FLAG_WITH_NO_DATA;
382
383 return flags;
384}
#define EXEC_FLAG_WITH_NO_DATA
Definition: executor.h:72

References EXEC_FLAG_WITH_NO_DATA, and IntoClause::skipData.

Referenced by ExecCreateTableAs(), ExecuteQuery(), and ExplainOnePlan().

◆ intorel_destroy()

static void intorel_destroy ( DestReceiver self)
static

Definition at line 635 of file createas.c.

636{
637 pfree(self);
638}
void pfree(void *pointer)
Definition: mcxt.c:2150

References pfree().

Referenced by CreateIntoRelDestReceiver().

◆ intorel_receive()

static bool intorel_receive ( TupleTableSlot slot,
DestReceiver self 
)
static

Definition at line 584 of file createas.c.

585{
586 DR_intorel *myState = (DR_intorel *) self;
587
588 /* Nothing to insert if WITH NO DATA is specified. */
589 if (!myState->into->skipData)
590 {
591 /*
592 * Note that the input slot might not be of the type of the target
593 * relation. That's supported by table_tuple_insert(), but slightly
594 * less efficient than inserting with the right slot - but the
595 * alternative would be to copy into a slot of the right type, which
596 * would not be cheap either. This also doesn't allow accessing per-AM
597 * data (say a tuple's xmin), but since we don't do that here...
598 */
599 table_tuple_insert(myState->rel,
600 slot,
601 myState->output_cid,
602 myState->ti_options,
603 myState->bistate);
604 }
605
606 /* We know this is a newly created relation, so there are no indexes */
607
608 return true;
609}
Relation rel
Definition: createas.c:56
BulkInsertState bistate
Definition: createas.c:60
int ti_options
Definition: createas.c:59
CommandId output_cid
Definition: createas.c:58
static void table_tuple_insert(Relation rel, TupleTableSlot *slot, CommandId cid, int options, struct BulkInsertStateData *bistate)
Definition: tableam.h:1362

References DR_intorel::bistate, DR_intorel::into, DR_intorel::output_cid, DR_intorel::rel, IntoClause::skipData, table_tuple_insert(), and DR_intorel::ti_options.

Referenced by CreateIntoRelDestReceiver().

◆ intorel_shutdown()

static void intorel_shutdown ( DestReceiver self)
static

Definition at line 615 of file createas.c.

616{
617 DR_intorel *myState = (DR_intorel *) self;
618 IntoClause *into = myState->into;
619
620 if (!into->skipData)
621 {
623 table_finish_bulk_insert(myState->rel, myState->ti_options);
624 }
625
626 /* close rel, but keep lock until commit */
627 table_close(myState->rel, NoLock);
628 myState->rel = NULL;
629}
void FreeBulkInsertState(BulkInsertState bistate)
Definition: heapam.c:2006
#define NoLock
Definition: lockdefs.h:34
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:126
static void table_finish_bulk_insert(Relation rel, int options)
Definition: tableam.h:1555

References DR_intorel::bistate, FreeBulkInsertState(), DR_intorel::into, NoLock, DR_intorel::rel, IntoClause::skipData, table_close(), table_finish_bulk_insert(), and DR_intorel::ti_options.

Referenced by CreateIntoRelDestReceiver().

◆ intorel_startup()

static void intorel_startup ( DestReceiver self,
int  operation,
TupleDesc  typeinfo 
)
static

Definition at line 460 of file createas.c.

461{
462 DR_intorel *myState = (DR_intorel *) self;
463 IntoClause *into = myState->into;
464 bool is_matview;
465 List *attrList;
466 ObjectAddress intoRelationAddr;
467 Relation intoRelationDesc;
468 ListCell *lc;
469 int attnum;
470
471 Assert(into != NULL); /* else somebody forgot to set it */
472
473 /* This code supports both CREATE TABLE AS and CREATE MATERIALIZED VIEW */
474 is_matview = (into->viewQuery != NULL);
475
476 /*
477 * Build column definitions using "pre-cooked" type and collation info. If
478 * a column name list was specified in CREATE TABLE AS, override the
479 * column names derived from the query. (Too few column names are OK, too
480 * many are not.)
481 */
482 attrList = NIL;
483 lc = list_head(into->colNames);
484 for (attnum = 0; attnum < typeinfo->natts; attnum++)
485 {
486 Form_pg_attribute attribute = TupleDescAttr(typeinfo, attnum);
487 ColumnDef *col;
488 char *colname;
489
490 if (lc)
491 {
492 colname = strVal(lfirst(lc));
493 lc = lnext(into->colNames, lc);
494 }
495 else
496 colname = NameStr(attribute->attname);
497
498 col = makeColumnDef(colname,
499 attribute->atttypid,
500 attribute->atttypmod,
501 attribute->attcollation);
502
503 /*
504 * It's possible that the column is of a collatable type but the
505 * collation could not be resolved, so double-check. (We must check
506 * this here because DefineRelation would adopt the type's default
507 * collation rather than complaining.)
508 */
509 if (!OidIsValid(col->collOid) &&
512 (errcode(ERRCODE_INDETERMINATE_COLLATION),
513 errmsg("no collation was derived for column \"%s\" with collatable type %s",
514 col->colname,
516 errhint("Use the COLLATE clause to set the collation explicitly.")));
517
518 attrList = lappend(attrList, col);
519 }
520
521 if (lc != NULL)
523 (errcode(ERRCODE_SYNTAX_ERROR),
524 errmsg("too many column names were specified")));
525
526 /*
527 * Actually create the target table
528 */
529 intoRelationAddr = create_ctas_internal(attrList, into);
530
531 /*
532 * Finally we can open the target table
533 */
534 intoRelationDesc = table_open(intoRelationAddr.objectId, AccessExclusiveLock);
535
536 /*
537 * Make sure the constructed table does not have RLS enabled.
538 *
539 * check_enable_rls() will ereport(ERROR) itself if the user has requested
540 * something invalid, and otherwise will return RLS_ENABLED if RLS should
541 * be enabled here. We don't actually support that currently, so throw
542 * our own ereport(ERROR) if that happens.
543 */
544 if (check_enable_rls(intoRelationAddr.objectId, InvalidOid, false) == RLS_ENABLED)
546 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
547 errmsg("policies not yet implemented for this command")));
548
549 /*
550 * Tentatively mark the target as populated, if it's a matview and we're
551 * going to fill it; otherwise, no change needed.
552 */
553 if (is_matview && !into->skipData)
554 SetMatViewPopulatedState(intoRelationDesc, true);
555
556 /*
557 * Fill private fields of myState for use by later routines
558 */
559 myState->rel = intoRelationDesc;
560 myState->reladdr = intoRelationAddr;
561 myState->output_cid = GetCurrentCommandId(true);
563
564 /*
565 * If WITH NO DATA is specified, there is no need to set up the state for
566 * bulk inserts as there are no tuples to insert.
567 */
568 if (!into->skipData)
569 myState->bistate = GetBulkInsertState();
570 else
571 myState->bistate = NULL;
572
573 /*
574 * Valid smgr_targblock implies something already wrote to the relation.
575 * This may be harmless, but this function hasn't planned for it.
576 */
578}
#define InvalidBlockNumber
Definition: block.h:33
#define NameStr(name)
Definition: c.h:717
BulkInsertState GetBulkInsertState(void)
Definition: heapam.c:1989
#define AccessExclusiveLock
Definition: lockdefs.h:43
void SetMatViewPopulatedState(Relation relation, bool newstate)
Definition: matview.c:79
int16 attnum
Definition: pg_attribute.h:74
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:202
#define RelationGetTargetBlock(relation)
Definition: rel.h:612
int check_enable_rls(Oid relid, Oid checkAsUser, bool noError)
Definition: rls.c:52
@ RLS_ENABLED
Definition: rls.h:45
ObjectAddress reladdr
Definition: createas.c:57
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:40
#define TABLE_INSERT_SKIP_FSM
Definition: tableam.h:253
static FormData_pg_attribute * TupleDescAttr(TupleDesc tupdesc, int i)
Definition: tupdesc.h:160
CommandId GetCurrentCommandId(bool used)
Definition: xact.c:829

References AccessExclusiveLock, Assert(), attnum, DR_intorel::bistate, check_enable_rls(), ColumnDef::collOid, ColumnDef::colname, IntoClause::colNames, create_ctas_internal(), ereport, errcode(), errhint(), errmsg(), ERROR, format_type_be(), GetBulkInsertState(), GetCurrentCommandId(), DR_intorel::into, InvalidBlockNumber, InvalidOid, lappend(), lfirst, list_head(), lnext(), makeColumnDef(), NameStr, TupleDescData::natts, NIL, ObjectAddress::objectId, OidIsValid, DR_intorel::output_cid, DR_intorel::rel, DR_intorel::reladdr, RelationGetTargetBlock, RLS_ENABLED, SetMatViewPopulatedState(), IntoClause::skipData, strVal, TABLE_INSERT_SKIP_FSM, table_open(), DR_intorel::ti_options, TupleDescAttr(), type_is_collatable(), ColumnDef::typeName, and TypeName::typeOid.

Referenced by CreateIntoRelDestReceiver().