PostgreSQL Source Code  git master
createas.c File Reference
#include "postgres.h"
#include "access/heapam.h"
#include "access/reloptions.h"
#include "access/htup_details.h"
#include "access/sysattr.h"
#include "access/tableam.h"
#include "access/xact.h"
#include "access/xlog.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 "miscadmin.h"
#include "nodes/makefuncs.h"
#include "nodes/nodeFuncs.h"
#include "parser/parse_clause.h"
#include "rewrite/rewriteHandler.h"
#include "storage/smgr.h"
#include "tcop/tcopprot.h"
#include "utils/builtins.h"
#include "utils/lsyscache.h"
#include "utils/rel.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 (CreateTableAsStmt *stmt, const char *queryString, ParamListInfo params, QueryEnvironment *queryEnv, char *completionTag)
 
int GetIntoRelEFlags (IntoClause *intoClause)
 
DestReceiverCreateIntoRelDestReceiver (IntoClause *intoClause)
 

Function Documentation

◆ create_ctas_internal()

static ObjectAddress create_ctas_internal ( List attrList,
IntoClause into 
)
static

Definition at line 86 of file createas.c.

References IntoClause::accessMethod, CreateStmt::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, IntoClause::onCommit, CreateStmt::oncommit, IntoClause::options, CreateStmt::options, IntoClause::rel, CreateStmt::relation, relkind, StoreViewQuery(), CreateStmt::tableElts, IntoClause::tableSpaceName, CreateStmt::tablespacename, transformRelOptions(), and IntoClause::viewQuery.

Referenced by create_ctas_nodata(), and intorel_startup().

87 {
88  CreateStmt *create = makeNode(CreateStmt);
89  bool is_matview;
90  char relkind;
91  Datum toast_options;
92  static char *validnsps[] = HEAP_RELOPT_NAMESPACES;
93  ObjectAddress intoRelationAddr;
94 
95  /* This code supports both CREATE TABLE AS and CREATE MATERIALIZED VIEW */
96  is_matview = (into->viewQuery != NULL);
97  relkind = is_matview ? RELKIND_MATVIEW : RELKIND_RELATION;
98 
99  /*
100  * Create the target relation by faking up a CREATE TABLE parsetree and
101  * passing it to DefineRelation.
102  */
103  create->relation = into->rel;
104  create->tableElts = attrList;
105  create->inhRelations = NIL;
106  create->ofTypename = NULL;
107  create->constraints = NIL;
108  create->options = into->options;
109  create->oncommit = into->onCommit;
110  create->tablespacename = into->tableSpaceName;
111  create->if_not_exists = false;
112  create->accessMethod = into->accessMethod;
113 
114  /*
115  * Create the relation. (This will error out if there's an existing view,
116  * so we don't need more code to complain if "replace" is false.)
117  */
118  intoRelationAddr = DefineRelation(create, relkind, InvalidOid, NULL, NULL);
119 
120  /*
121  * If necessary, create a TOAST table for the target table. Note that
122  * NewRelationCreateToastTable ends with CommandCounterIncrement(), so
123  * that the TOAST table will be visible for insertion.
124  */
126 
127  /* parse and validate reloptions for the toast table */
128  toast_options = transformRelOptions((Datum) 0,
129  create->options,
130  "toast",
131  validnsps,
132  true, false);
133 
134  (void) heap_reloptions(RELKIND_TOASTVALUE, toast_options, true);
135 
136  NewRelationCreateToastTable(intoRelationAddr.objectId, toast_options);
137 
138  /* Create the "view" part of a materialized view. */
139  if (is_matview)
140  {
141  /* StoreViewQuery scribbles on tree, so make a copy */
142  Query *query = (Query *) copyObject(into->viewQuery);
143 
144  StoreViewQuery(intoRelationAddr.objectId, query, false);
146  }
147 
148  return intoRelationAddr;
149 }
RangeVar * relation
Definition: parsenodes.h:2049
bytea * heap_reloptions(char relkind, Datum reloptions, bool validate)
Definition: reloptions.c:1470
#define NIL
Definition: pg_list.h:65
OnCommitAction oncommit
Definition: parsenodes.h:2058
List * inhRelations
Definition: parsenodes.h:2051
OnCommitAction onCommit
Definition: primnodes.h:116
Datum transformRelOptions(Datum oldOptions, List *defList, const char *namspace, char *validnsps[], bool acceptOidsOff, bool isReset)
Definition: reloptions.c:784
char * tableSpaceName
Definition: primnodes.h:117
void NewRelationCreateToastTable(Oid relOid, Datum reloptions)
Definition: toasting.c:72
char relkind
Definition: pg_class.h:81
List * constraints
Definition: parsenodes.h:2056
bool if_not_exists
Definition: parsenodes.h:2061
char * accessMethod
Definition: parsenodes.h:2060
Node * viewQuery
Definition: primnodes.h:118
List * options
Definition: parsenodes.h:2057
#define HEAP_RELOPT_NAMESPACES
Definition: reloptions.h:59
ObjectAddress DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId, ObjectAddress *typaddress, const char *queryString)
Definition: tablecmds.c:555
List * options
Definition: primnodes.h:115
char * tablespacename
Definition: parsenodes.h:2059
uintptr_t Datum
Definition: postgres.h:367
void CommandCounterIncrement(void)
Definition: xact.c:1003
void StoreViewQuery(Oid viewOid, Query *viewParse, bool replace)
Definition: view.c:575
#define InvalidOid
Definition: postgres_ext.h:36
List * tableElts
Definition: parsenodes.h:2050
#define makeNode(_type_)
Definition: nodes.h:572
RangeVar * rel
Definition: primnodes.h:112
#define copyObject(obj)
Definition: nodes.h:640
char * accessMethod
Definition: primnodes.h:114
TypeName * ofTypename
Definition: parsenodes.h:2055

◆ create_ctas_nodata()

static ObjectAddress create_ctas_nodata ( List tlist,
IntoClause into 
)
static

Definition at line 159 of file createas.c.

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, TargetEntry::resjunk, TargetEntry::resname, strVal, type_is_collatable(), ColumnDef::typeName, and TypeName::typeOid.

Referenced by ExecCreateTableAs().

160 {
161  List *attrList;
162  ListCell *t,
163  *lc;
164 
165  /*
166  * Build list of ColumnDefs from non-junk elements of the tlist. If a
167  * column name list was specified in CREATE TABLE AS, override the column
168  * names in the query. (Too few column names are OK, too many are not.)
169  */
170  attrList = NIL;
171  lc = list_head(into->colNames);
172  foreach(t, tlist)
173  {
174  TargetEntry *tle = (TargetEntry *) lfirst(t);
175 
176  if (!tle->resjunk)
177  {
178  ColumnDef *col;
179  char *colname;
180 
181  if (lc)
182  {
183  colname = strVal(lfirst(lc));
184  lc = lnext(into->colNames, lc);
185  }
186  else
187  colname = tle->resname;
188 
189  col = makeColumnDef(colname,
190  exprType((Node *) tle->expr),
191  exprTypmod((Node *) tle->expr),
192  exprCollation((Node *) tle->expr));
193 
194  /*
195  * It's possible that the column is of a collatable type but the
196  * collation could not be resolved, so double-check. (We must
197  * check this here because DefineRelation would adopt the type's
198  * default collation rather than complaining.)
199  */
200  if (!OidIsValid(col->collOid) &&
202  ereport(ERROR,
203  (errcode(ERRCODE_INDETERMINATE_COLLATION),
204  errmsg("no collation was derived for column \"%s\" with collatable type %s",
205  col->colname,
207  errhint("Use the COLLATE clause to set the collation explicitly.")));
208 
209  attrList = lappend(attrList, col);
210  }
211  }
212 
213  if (lc != NULL)
214  ereport(ERROR,
215  (errcode(ERRCODE_SYNTAX_ERROR),
216  errmsg("too many column names were specified")));
217 
218  /* Create the relation definition using the ColumnDef list */
219  return create_ctas_internal(attrList, into);
220 }
#define NIL
Definition: pg_list.h:65
Oid typeOid
Definition: parsenodes.h:210
int errhint(const char *fmt,...)
Definition: elog.c:974
static ListCell * lnext(const List *l, const ListCell *c)
Definition: pg_list.h:321
int32 exprTypmod(const Node *expr)
Definition: nodeFuncs.c:276
Definition: nodes.h:524
#define strVal(v)
Definition: value.h:54
int errcode(int sqlerrcode)
Definition: elog.c:570
char * format_type_be(Oid type_oid)
Definition: format_type.c:326
char * resname
Definition: primnodes.h:1395
#define OidIsValid(objectId)
Definition: c.h:638
static ObjectAddress create_ctas_internal(List *attrList, IntoClause *into)
Definition: createas.c:86
bool resjunk
Definition: primnodes.h:1400
#define ERROR
Definition: elog.h:43
Oid collOid
Definition: parsenodes.h:660
static ListCell * list_head(const List *l)
Definition: pg_list.h:125
#define ereport(elevel, rest)
Definition: elog.h:141
List * lappend(List *list, void *datum)
Definition: list.c:321
#define lfirst(lc)
Definition: pg_list.h:190
Expr * expr
Definition: primnodes.h:1393
Oid exprType(const Node *expr)
Definition: nodeFuncs.c:42
Oid exprCollation(const Node *expr)
Definition: nodeFuncs.c:720
TypeName * typeName
Definition: parsenodes.h:647
int errmsg(const char *fmt,...)
Definition: elog.c:784
char * colname
Definition: parsenodes.h:646
List * colNames
Definition: primnodes.h:113
bool type_is_collatable(Oid typid)
Definition: lsyscache.c:2848
Definition: pg_list.h:50
ColumnDef * makeColumnDef(const char *colname, Oid typeOid, int32 typmod, Oid collOid)
Definition: makefuncs.c:488

◆ CreateIntoRelDestReceiver()

DestReceiver* CreateIntoRelDestReceiver ( IntoClause intoClause)

Definition at line 413 of file createas.c.

References DestIntoRel, intorel_destroy(), intorel_receive(), intorel_shutdown(), intorel_startup(), and palloc0().

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

414 {
415  DR_intorel *self = (DR_intorel *) palloc0(sizeof(DR_intorel));
416 
417  self->pub.receiveSlot = intorel_receive;
418  self->pub.rStartup = intorel_startup;
419  self->pub.rShutdown = intorel_shutdown;
420  self->pub.rDestroy = intorel_destroy;
421  self->pub.mydest = DestIntoRel;
422  self->into = intoClause;
423  /* other private fields will be set during intorel_startup */
424 
425  return (DestReceiver *) self;
426 }
static void intorel_shutdown(DestReceiver *self)
Definition: createas.c:601
static bool intorel_receive(TupleTableSlot *slot, DestReceiver *self)
Definition: createas.c:573
void * palloc0(Size size)
Definition: mcxt.c:955
static void intorel_destroy(DestReceiver *self)
Definition: createas.c:618
static void intorel_startup(DestReceiver *self, int operation, TupleDesc typeinfo)
Definition: createas.c:432

◆ ExecCreateTableAs()

ObjectAddress ExecCreateTableAs ( CreateTableAsStmt stmt,
const char *  queryString,
ParamListInfo  params,
QueryEnvironment queryEnv,
char *  completionTag 
)

Definition at line 227 of file createas.c.

References Assert, AtEOXact_GUC(), castNode, CMD_SELECT, CMD_UTILITY, Query::commandType, COMPLETION_TAG_BUFSIZE, copyObject, create_ctas_nodata(), CreateIntoRelDestReceiver(), CreateQueryDesc(), CURSOR_OPT_PARALLEL_OK, generate_unaccent_rules::dest, elog, ereport, errcode(), errmsg(), ERROR, EState::es_processed, QueryDesc::estate, ExecuteQuery(), ExecutorEnd(), ExecutorFinish(), ExecutorRun(), ExecutorStart(), ForwardScanDirection, FreeQueryDesc(), get_relname_relid(), GetActiveSnapshot(), GetIntoRelEFlags(), GetUserIdAndSecContext(), CreateTableAsStmt::if_not_exists, CreateTableAsStmt::into, InvalidObjectAddress, InvalidOid, InvalidSnapshot, IsA, linitial_node, list_length(), NewGUCNestLevel(), NOTICE, pg_plan_query(), PopActiveSnapshot(), PushCopiedSnapshot(), CreateTableAsStmt::query, QueryRewrite(), RangeVarGetCreationNamespace(), IntoClause::rel, RangeVar::relname, SECURITY_RESTRICTED_OPERATION, SetUserIdAndSecContext(), IntoClause::skipData, snprintf, Query::targetList, UINT64_FORMAT, UpdateActiveSnapshotCommandId(), Query::utilityStmt, and IntoClause::viewQuery.

Referenced by ProcessUtilitySlow().

230 {
231  Query *query = castNode(Query, stmt->query);
232  IntoClause *into = stmt->into;
233  bool is_matview = (into->viewQuery != NULL);
235  Oid save_userid = InvalidOid;
236  int save_sec_context = 0;
237  int save_nestlevel = 0;
238  ObjectAddress address;
239  List *rewritten;
240  PlannedStmt *plan;
241  QueryDesc *queryDesc;
242 
243  if (stmt->if_not_exists)
244  {
245  Oid nspid;
246 
247  nspid = RangeVarGetCreationNamespace(stmt->into->rel);
248 
249  if (get_relname_relid(stmt->into->rel->relname, nspid))
250  {
251  ereport(NOTICE,
252  (errcode(ERRCODE_DUPLICATE_TABLE),
253  errmsg("relation \"%s\" already exists, skipping",
254  stmt->into->rel->relname)));
255  return InvalidObjectAddress;
256  }
257  }
258 
259  /*
260  * Create the tuple receiver object and insert info it will need
261  */
262  dest = CreateIntoRelDestReceiver(into);
263 
264  /*
265  * The contained Query could be a SELECT, or an EXECUTE utility command.
266  * If the latter, we just pass it off to ExecuteQuery.
267  */
268  if (query->commandType == CMD_UTILITY &&
269  IsA(query->utilityStmt, ExecuteStmt))
270  {
271  ExecuteStmt *estmt = castNode(ExecuteStmt, query->utilityStmt);
272 
273  Assert(!is_matview); /* excluded by syntax */
274  ExecuteQuery(estmt, into, queryString, params, dest, completionTag);
275 
276  /* get object address that intorel_startup saved for us */
277  address = ((DR_intorel *) dest)->reladdr;
278 
279  return address;
280  }
281  Assert(query->commandType == CMD_SELECT);
282 
283  /*
284  * For materialized views, lock down security-restricted operations and
285  * arrange to make GUC variable changes local to this command. This is
286  * not necessary for security, but this keeps the behavior similar to
287  * REFRESH MATERIALIZED VIEW. Otherwise, one could create a materialized
288  * view not possible to refresh.
289  */
290  if (is_matview)
291  {
292  GetUserIdAndSecContext(&save_userid, &save_sec_context);
293  SetUserIdAndSecContext(save_userid,
294  save_sec_context | SECURITY_RESTRICTED_OPERATION);
295  save_nestlevel = NewGUCNestLevel();
296  }
297 
298  if (into->skipData)
299  {
300  /*
301  * If WITH NO DATA was specified, do not go through the rewriter,
302  * planner and executor. Just define the relation using a code path
303  * similar to CREATE VIEW. This avoids dump/restore problems stemming
304  * from running the planner before all dependencies are set up.
305  */
306  address = create_ctas_nodata(query->targetList, into);
307  }
308  else
309  {
310  /*
311  * Parse analysis was done already, but we still have to run the rule
312  * rewriter. We do not do AcquireRewriteLocks: we assume the query
313  * either came straight from the parser, or suitable locks were
314  * acquired by plancache.c.
315  *
316  * Because the rewriter and planner tend to scribble on the input, we
317  * make a preliminary copy of the source querytree. This prevents
318  * problems in the case that CTAS is in a portal or plpgsql function
319  * and is executed repeatedly. (See also the same hack in EXPLAIN and
320  * PREPARE.)
321  */
322  rewritten = QueryRewrite(copyObject(query));
323 
324  /* SELECT should never rewrite to more or less than one SELECT query */
325  if (list_length(rewritten) != 1)
326  elog(ERROR, "unexpected rewrite result for %s",
327  is_matview ? "CREATE MATERIALIZED VIEW" :
328  "CREATE TABLE AS SELECT");
329  query = linitial_node(Query, rewritten);
330  Assert(query->commandType == CMD_SELECT);
331 
332  /* plan the query */
333  plan = pg_plan_query(query, CURSOR_OPT_PARALLEL_OK, params);
334 
335  /*
336  * Use a snapshot with an updated command ID to ensure this query sees
337  * results of any previously executed queries. (This could only
338  * matter if the planner executed an allegedly-stable function that
339  * changed the database contents, but let's do it anyway to be
340  * parallel to the EXPLAIN code path.)
341  */
344 
345  /* Create a QueryDesc, redirecting output to our tuple receiver */
346  queryDesc = CreateQueryDesc(plan, queryString,
348  dest, params, queryEnv, 0);
349 
350  /* call ExecutorStart to prepare the plan for execution */
351  ExecutorStart(queryDesc, GetIntoRelEFlags(into));
352 
353  /* run the plan to completion */
354  ExecutorRun(queryDesc, ForwardScanDirection, 0L, true);
355 
356  /* save the rowcount if we're given a completionTag to fill */
357  if (completionTag)
358  snprintf(completionTag, COMPLETION_TAG_BUFSIZE,
359  "SELECT " UINT64_FORMAT,
360  queryDesc->estate->es_processed);
361 
362  /* get object address that intorel_startup saved for us */
363  address = ((DR_intorel *) dest)->reladdr;
364 
365  /* and clean up */
366  ExecutorFinish(queryDesc);
367  ExecutorEnd(queryDesc);
368 
369  FreeQueryDesc(queryDesc);
370 
372  }
373 
374  if (is_matview)
375  {
376  /* Roll back any GUC changes */
377  AtEOXact_GUC(false, save_nestlevel);
378 
379  /* Restore userid and security context */
380  SetUserIdAndSecContext(save_userid, save_sec_context);
381  }
382 
383  return address;
384 }
void UpdateActiveSnapshotCommandId(void)
Definition: snapmgr.c:783
#define IsA(nodeptr, _type_)
Definition: nodes.h:575
List * QueryRewrite(Query *parsetree)
EState * estate
Definition: execdesc.h:48
#define SECURITY_RESTRICTED_OPERATION
Definition: miscadmin.h:300
void SetUserIdAndSecContext(Oid userid, int sec_context)
Definition: miscinit.c:492
#define castNode(_type_, nodeptr)
Definition: nodes.h:593
void FreeQueryDesc(QueryDesc *qdesc)
Definition: pquery.c:105
void ExecutorStart(QueryDesc *queryDesc, int eflags)
Definition: execMain.c:144
Snapshot GetActiveSnapshot(void)
Definition: snapmgr.c:841
int errcode(int sqlerrcode)
Definition: elog.c:570
void PopActiveSnapshot(void)
Definition: snapmgr.c:814
bool skipData
Definition: primnodes.h:119
unsigned int Oid
Definition: postgres_ext.h:31
Node * utilityStmt
Definition: parsenodes.h:120
#define linitial_node(type, l)
Definition: pg_list.h:198
void ExecuteQuery(ExecuteStmt *stmt, IntoClause *intoClause, const char *queryString, ParamListInfo params, DestReceiver *dest, char *completionTag)
Definition: prepare.c:200
List * targetList
Definition: parsenodes.h:140
void ExecutorEnd(QueryDesc *queryDesc)
Definition: execMain.c:463
char * relname
Definition: primnodes.h:68
int GetIntoRelEFlags(IntoClause *intoClause)
Definition: createas.c:395
#define ERROR
Definition: elog.h:43
Node * viewQuery
Definition: primnodes.h:118
void ExecutorRun(QueryDesc *queryDesc, ScanDirection direction, uint64 count, bool execute_once)
Definition: execMain.c:302
void PushCopiedSnapshot(Snapshot snapshot)
Definition: snapmgr.c:771
QueryDesc * CreateQueryDesc(PlannedStmt *plannedstmt, const char *sourceText, Snapshot snapshot, Snapshot crosscheck_snapshot, DestReceiver *dest, ParamListInfo params, QueryEnvironment *queryEnv, int instrument_options)
Definition: pquery.c:67
Oid get_relname_relid(const char *relname, Oid relnamespace)
Definition: lsyscache.c:1687
void GetUserIdAndSecContext(Oid *userid, int *sec_context)
Definition: miscinit.c:485
void AtEOXact_GUC(bool isCommit, int nestLevel)
Definition: guc.c:5729
DestReceiver * CreateIntoRelDestReceiver(IntoClause *intoClause)
Definition: createas.c:413
#define ereport(elevel, rest)
Definition: elog.h:141
void ExecutorFinish(QueryDesc *queryDesc)
Definition: execMain.c:403
#define InvalidSnapshot
Definition: snapshot.h:123
#define InvalidOid
Definition: postgres_ext.h:36
IntoClause * into
Definition: parsenodes.h:3228
#define NOTICE
Definition: elog.h:37
CmdType commandType
Definition: parsenodes.h:112
#define COMPLETION_TAG_BUFSIZE
Definition: dest.h:74
#define Assert(condition)
Definition: c.h:732
uint64 es_processed
Definition: execnodes.h:554
static int list_length(const List *l)
Definition: pg_list.h:169
static ObjectAddress create_ctas_nodata(List *tlist, IntoClause *into)
Definition: createas.c:159
int NewGUCNestLevel(void)
Definition: guc.c:5715
#define CURSOR_OPT_PARALLEL_OK
Definition: parsenodes.h:2692
const ObjectAddress InvalidObjectAddress
int errmsg(const char *fmt,...)
Definition: elog.c:784
RangeVar * rel
Definition: primnodes.h:112
#define elog(elevel,...)
Definition: elog.h:226
#define copyObject(obj)
Definition: nodes.h:640
Definition: pg_list.h:50
#define snprintf
Definition: port.h:192
#define UINT64_FORMAT
Definition: c.h:401
Oid RangeVarGetCreationNamespace(const RangeVar *newRelation)
Definition: namespace.c:441
PlannedStmt * pg_plan_query(Query *querytree, int cursorOptions, ParamListInfo boundParams)
Definition: postgres.c:861

◆ GetIntoRelEFlags()

int GetIntoRelEFlags ( IntoClause intoClause)

Definition at line 395 of file createas.c.

References EXEC_FLAG_WITH_NO_DATA, and IntoClause::skipData.

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

396 {
397  int flags = 0;
398 
399  if (intoClause->skipData)
400  flags |= EXEC_FLAG_WITH_NO_DATA;
401 
402  return flags;
403 }
#define EXEC_FLAG_WITH_NO_DATA
Definition: executor.h:61
bool skipData
Definition: primnodes.h:119

◆ intorel_destroy()

static void intorel_destroy ( DestReceiver self)
static

Definition at line 618 of file createas.c.

References pfree().

Referenced by CreateIntoRelDestReceiver().

619 {
620  pfree(self);
621 }
void pfree(void *pointer)
Definition: mcxt.c:1031

◆ intorel_receive()

static bool intorel_receive ( TupleTableSlot slot,
DestReceiver self 
)
static

Definition at line 573 of file createas.c.

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

Referenced by CreateIntoRelDestReceiver().

574 {
575  DR_intorel *myState = (DR_intorel *) self;
576 
577  /*
578  * Note that the input slot might not be of the type of the target
579  * relation. That's supported by table_tuple_insert(), but slightly less
580  * efficient than inserting with the right slot - but the alternative
581  * would be to copy into a slot of the right type, which would not be
582  * cheap either. This also doesn't allow accessing per-AM data (say a
583  * tuple's xmin), but since we don't do that here...
584  */
585 
586  table_tuple_insert(myState->rel,
587  slot,
588  myState->output_cid,
589  myState->ti_options,
590  myState->bistate);
591 
592  /* We know this is a newly created relation, so there are no indexes */
593 
594  return true;
595 }
int ti_options
Definition: createas.c:63
CommandId output_cid
Definition: createas.c:62
BulkInsertState bistate
Definition: createas.c:64
static void table_tuple_insert(Relation rel, TupleTableSlot *slot, CommandId cid, int options, struct BulkInsertStateData *bistate)
Definition: tableam.h:1123
Relation rel
Definition: createas.c:60

◆ intorel_shutdown()

static void intorel_shutdown ( DestReceiver self)
static

Definition at line 601 of file createas.c.

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

Referenced by CreateIntoRelDestReceiver().

602 {
603  DR_intorel *myState = (DR_intorel *) self;
604 
605  FreeBulkInsertState(myState->bistate);
606 
607  table_finish_bulk_insert(myState->rel, myState->ti_options);
608 
609  /* close rel, but keep lock until commit */
610  table_close(myState->rel, NoLock);
611  myState->rel = NULL;
612 }
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:133
int ti_options
Definition: createas.c:63
static void table_finish_bulk_insert(Relation rel, int options)
Definition: tableam.h:1318
BulkInsertState bistate
Definition: createas.c:64
#define NoLock
Definition: lockdefs.h:34
Relation rel
Definition: createas.c:60
void FreeBulkInsertState(BulkInsertState bistate)
Definition: heapam.c:1829

◆ intorel_startup()

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

Definition at line 432 of file createas.c.

References AccessExclusiveLock, ACL_INSERT, Assert, attnum, DR_intorel::bistate, bms_add_member(), check_enable_rls(), ColumnDef::collOid, ColumnDef::colname, IntoClause::colNames, create_ctas_internal(), ereport, errcode(), errhint(), errmsg(), ERROR, ExecCheckRTPerms(), FirstLowInvalidHeapAttributeNumber, format_type_be(), GetBulkInsertState(), GetCurrentCommandId(), RangeTblEntry::insertedCols, DR_intorel::into, InvalidBlockNumber, InvalidOid, lappend(), lfirst, list_head(), list_make1, lnext(), makeColumnDef(), makeNode, NameStr, TupleDescData::natts, NIL, ObjectAddress::objectId, OidIsValid, DR_intorel::output_cid, RelationData::rd_att, DR_intorel::rel, DR_intorel::reladdr, RelationGetTargetBlock, RangeTblEntry::relid, relkind, RangeTblEntry::relkind, RangeTblEntry::rellockmode, RangeTblEntry::requiredPerms, RLS_ENABLED, RowExclusiveLock, RTE_RELATION, RangeTblEntry::rtekind, SetMatViewPopulatedState(), IntoClause::skipData, strVal, TABLE_INSERT_SKIP_FSM, TABLE_INSERT_SKIP_WAL, table_open(), DR_intorel::ti_options, TupleDescAttr, type_is_collatable(), ColumnDef::typeName, TypeName::typeOid, IntoClause::viewQuery, and XLogIsNeeded.

Referenced by CreateIntoRelDestReceiver().

433 {
434  DR_intorel *myState = (DR_intorel *) self;
435  IntoClause *into = myState->into;
436  bool is_matview;
437  char relkind;
438  List *attrList;
439  ObjectAddress intoRelationAddr;
440  Relation intoRelationDesc;
441  RangeTblEntry *rte;
442  ListCell *lc;
443  int attnum;
444 
445  Assert(into != NULL); /* else somebody forgot to set it */
446 
447  /* This code supports both CREATE TABLE AS and CREATE MATERIALIZED VIEW */
448  is_matview = (into->viewQuery != NULL);
449  relkind = is_matview ? RELKIND_MATVIEW : RELKIND_RELATION;
450 
451  /*
452  * Build column definitions using "pre-cooked" type and collation info. If
453  * a column name list was specified in CREATE TABLE AS, override the
454  * column names derived from the query. (Too few column names are OK, too
455  * many are not.)
456  */
457  attrList = NIL;
458  lc = list_head(into->colNames);
459  for (attnum = 0; attnum < typeinfo->natts; attnum++)
460  {
461  Form_pg_attribute attribute = TupleDescAttr(typeinfo, attnum);
462  ColumnDef *col;
463  char *colname;
464 
465  if (lc)
466  {
467  colname = strVal(lfirst(lc));
468  lc = lnext(into->colNames, lc);
469  }
470  else
471  colname = NameStr(attribute->attname);
472 
473  col = makeColumnDef(colname,
474  attribute->atttypid,
475  attribute->atttypmod,
476  attribute->attcollation);
477 
478  /*
479  * It's possible that the column is of a collatable type but the
480  * collation could not be resolved, so double-check. (We must check
481  * this here because DefineRelation would adopt the type's default
482  * collation rather than complaining.)
483  */
484  if (!OidIsValid(col->collOid) &&
486  ereport(ERROR,
487  (errcode(ERRCODE_INDETERMINATE_COLLATION),
488  errmsg("no collation was derived for column \"%s\" with collatable type %s",
489  col->colname,
491  errhint("Use the COLLATE clause to set the collation explicitly.")));
492 
493  attrList = lappend(attrList, col);
494  }
495 
496  if (lc != NULL)
497  ereport(ERROR,
498  (errcode(ERRCODE_SYNTAX_ERROR),
499  errmsg("too many column names were specified")));
500 
501  /*
502  * Actually create the target table
503  */
504  intoRelationAddr = create_ctas_internal(attrList, into);
505 
506  /*
507  * Finally we can open the target table
508  */
509  intoRelationDesc = table_open(intoRelationAddr.objectId, AccessExclusiveLock);
510 
511  /*
512  * Check INSERT permission on the constructed table.
513  *
514  * XXX: It would arguably make sense to skip this check if into->skipData
515  * is true.
516  */
517  rte = makeNode(RangeTblEntry);
518  rte->rtekind = RTE_RELATION;
519  rte->relid = intoRelationAddr.objectId;
520  rte->relkind = relkind;
522  rte->requiredPerms = ACL_INSERT;
523 
524  for (attnum = 1; attnum <= intoRelationDesc->rd_att->natts; attnum++)
527 
528  ExecCheckRTPerms(list_make1(rte), true);
529 
530  /*
531  * Make sure the constructed table does not have RLS enabled.
532  *
533  * check_enable_rls() will ereport(ERROR) itself if the user has requested
534  * something invalid, and otherwise will return RLS_ENABLED if RLS should
535  * be enabled here. We don't actually support that currently, so throw
536  * our own ereport(ERROR) if that happens.
537  */
538  if (check_enable_rls(intoRelationAddr.objectId, InvalidOid, false) == RLS_ENABLED)
539  ereport(ERROR,
540  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
541  (errmsg("policies not yet implemented for this command"))));
542 
543  /*
544  * Tentatively mark the target as populated, if it's a matview and we're
545  * going to fill it; otherwise, no change needed.
546  */
547  if (is_matview && !into->skipData)
548  SetMatViewPopulatedState(intoRelationDesc, true);
549 
550  /*
551  * Fill private fields of myState for use by later routines
552  */
553  myState->rel = intoRelationDesc;
554  myState->reladdr = intoRelationAddr;
555  myState->output_cid = GetCurrentCommandId(true);
556 
557  /*
558  * We can skip WAL-logging the insertions, unless PITR or streaming
559  * replication is in use. We can skip the FSM in any case.
560  */
561  myState->ti_options = TABLE_INSERT_SKIP_FSM |
563  myState->bistate = GetBulkInsertState();
564 
565  /* Not using WAL requires smgr_targblock be initially invalid */
566  Assert(RelationGetTargetBlock(intoRelationDesc) == InvalidBlockNumber);
567 }
#define NIL
Definition: pg_list.h:65
Oid typeOid
Definition: parsenodes.h:210
int errhint(const char *fmt,...)
Definition: elog.c:974
static ListCell * lnext(const List *l, const ListCell *c)
Definition: pg_list.h:321
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92
#define XLogIsNeeded()
Definition: xlog.h:181
int ti_options
Definition: createas.c:63
#define strVal(v)
Definition: value.h:54
int errcode(int sqlerrcode)
Definition: elog.c:570
char * format_type_be(Oid type_oid)
Definition: format_type.c:326
CommandId output_cid
Definition: createas.c:62
#define FirstLowInvalidHeapAttributeNumber
Definition: sysattr.h:27
AclMode requiredPerms
Definition: parsenodes.h:1096
bool skipData
Definition: primnodes.h:119
BulkInsertState bistate
Definition: createas.c:64
#define OidIsValid(objectId)
Definition: c.h:638
#define RelationGetTargetBlock(relation)
Definition: rel.h:501
char relkind
Definition: pg_class.h:81
#define list_make1(x1)
Definition: pg_list.h:227
BulkInsertState GetBulkInsertState(void)
Definition: heapam.c:1815
ObjectAddress reladdr
Definition: createas.c:61
static ObjectAddress create_ctas_internal(List *attrList, IntoClause *into)
Definition: createas.c:86
#define ERROR
Definition: elog.h:43
Node * viewQuery
Definition: primnodes.h:118
Oid collOid
Definition: parsenodes.h:660
#define RowExclusiveLock
Definition: lockdefs.h:38
Relation rel
Definition: createas.c:60
static ListCell * list_head(const List *l)
Definition: pg_list.h:125
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:200
#define TABLE_INSERT_SKIP_WAL
Definition: tableam.h:130
#define ereport(elevel, rest)
Definition: elog.h:141
List * lappend(List *list, void *datum)
Definition: list.c:321
#define TABLE_INSERT_SKIP_FSM
Definition: tableam.h:131
TupleDesc rd_att
Definition: rel.h:84
#define InvalidOid
Definition: postgres_ext.h:36
int16 attnum
Definition: pg_attribute.h:79
int check_enable_rls(Oid relid, Oid checkAsUser, bool noError)
Definition: rls.c:52
#define makeNode(_type_)
Definition: nodes.h:572
#define Assert(condition)
Definition: c.h:732
#define lfirst(lc)
Definition: pg_list.h:190
#define ACL_INSERT
Definition: parsenodes.h:74
#define InvalidBlockNumber
Definition: block.h:33
TypeName * typeName
Definition: parsenodes.h:647
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:736
IntoClause * into
Definition: createas.c:58
RTEKind rtekind
Definition: parsenodes.h:974
#define AccessExclusiveLock
Definition: lockdefs.h:45
int errmsg(const char *fmt,...)
Definition: elog.c:784
Bitmapset * insertedCols
Definition: parsenodes.h:1099
bool ExecCheckRTPerms(List *rangeTable, bool ereport_on_violation)
Definition: execMain.c:572
#define NameStr(name)
Definition: c.h:609
char * colname
Definition: parsenodes.h:646
CommandId GetCurrentCommandId(bool used)
Definition: xact.c:746
List * colNames
Definition: primnodes.h:113
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
bool type_is_collatable(Oid typid)
Definition: lsyscache.c:2848
Definition: pg_list.h:50
void SetMatViewPopulatedState(Relation relation, bool newstate)
Definition: matview.c:84
ColumnDef * makeColumnDef(const char *colname, Oid typeOid, int32 typmod, Oid collOid)
Definition: makefuncs.c:488