PostgreSQL Source Code  git master
createas.c File Reference
#include "postgres.h"
#include "access/heapam.h"
#include "access/htup_details.h"
#include "access/reloptions.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 (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 85 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, StoreViewQuery(), CreateStmt::tableElts, IntoClause::tableSpaceName, CreateStmt::tablespacename, transformRelOptions(), and IntoClause::viewQuery.

Referenced by create_ctas_nodata(), and intorel_startup().

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

◆ create_ctas_nodata()

static ObjectAddress create_ctas_nodata ( List tlist,
IntoClause into 
)
static

Definition at line 158 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().

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

◆ CreateIntoRelDestReceiver()

DestReceiver* CreateIntoRelDestReceiver ( IntoClause intoClause)

Definition at line 428 of file createas.c.

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

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

429 {
430  DR_intorel *self = (DR_intorel *) palloc0(sizeof(DR_intorel));
431 
432  self->pub.receiveSlot = intorel_receive;
433  self->pub.rStartup = intorel_startup;
434  self->pub.rShutdown = intorel_shutdown;
435  self->pub.rDestroy = intorel_destroy;
436  self->pub.mydest = DestIntoRel;
437  self->into = intoClause;
438  /* other private fields will be set during intorel_startup */
439 
440  return (DestReceiver *) self;
441 }
static void intorel_shutdown(DestReceiver *self)
Definition: createas.c:602
static bool intorel_receive(TupleTableSlot *slot, DestReceiver *self)
Definition: createas.c:571
void * palloc0(Size size)
Definition: mcxt.c:1093
static void intorel_destroy(DestReceiver *self)
Definition: createas.c:622
static void intorel_startup(DestReceiver *self, int operation, TupleDesc typeinfo)
Definition: createas.c:447

◆ CreateTableAsRelExists()

bool CreateTableAsRelExists ( CreateTableAsStmt ctas)

Definition at line 393 of file createas.c.

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

Referenced by ExecCreateTableAs(), and ExplainOneUtility().

394 {
395  Oid nspid;
396  IntoClause *into = ctas->into;
397 
398  nspid = RangeVarGetCreationNamespace(into->rel);
399 
400  if (get_relname_relid(into->rel->relname, nspid))
401  {
402  if (!ctas->if_not_exists)
403  ereport(ERROR,
404  (errcode(ERRCODE_DUPLICATE_TABLE),
405  errmsg("relation \"%s\" already exists",
406  into->rel->relname)));
407 
408  /* The relation exists and IF NOT EXISTS has been specified */
409  ereport(NOTICE,
410  (errcode(ERRCODE_DUPLICATE_TABLE),
411  errmsg("relation \"%s\" already exists, skipping",
412  into->rel->relname)));
413  return true;
414  }
415 
416  /* Relation does not exist, it can be created */
417  return false;
418 }
int errcode(int sqlerrcode)
Definition: elog.c:698
unsigned int Oid
Definition: postgres_ext.h:31
char * relname
Definition: primnodes.h:68
#define ERROR
Definition: elog.h:46
Oid get_relname_relid(const char *relname, Oid relnamespace)
Definition: lsyscache.c:1856
#define ereport(elevel,...)
Definition: elog.h:157
IntoClause * into
Definition: parsenodes.h:3397
#define NOTICE
Definition: elog.h:37
int errmsg(const char *fmt,...)
Definition: elog.c:909
RangeVar * rel
Definition: primnodes.h:112
Oid RangeVarGetCreationNamespace(const RangeVar *newRelation)
Definition: namespace.c:450

◆ ExecCreateTableAs()

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

Definition at line 226 of file createas.c.

References Assert, AtEOXact_GUC(), 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(), GetUserIdAndSecContext(), CreateTableAsStmt::into, InvalidObjectAddress, InvalidOid, InvalidSnapshot, IsA, linitial_node, list_length(), NewGUCNestLevel(), ParseState::p_sourcetext, pg_plan_query(), PopActiveSnapshot(), PushCopiedSnapshot(), CreateTableAsStmt::query, QueryRewrite(), SECURITY_RESTRICTED_OPERATION, SetQueryCompletion(), SetUserIdAndSecContext(), IntoClause::skipData, Query::targetList, UpdateActiveSnapshotCommandId(), Query::utilityStmt, and IntoClause::viewQuery.

Referenced by ProcessUtilitySlow().

229 {
230  Query *query = castNode(Query, stmt->query);
231  IntoClause *into = stmt->into;
232  bool is_matview = (into->viewQuery != NULL);
234  Oid save_userid = InvalidOid;
235  int save_sec_context = 0;
236  int save_nestlevel = 0;
237  ObjectAddress address;
238  List *rewritten;
239  PlannedStmt *plan;
240  QueryDesc *queryDesc;
241 
242  /* Check if the relation exists or not */
243  if (CreateTableAsRelExists(stmt))
244  return InvalidObjectAddress;
245 
246  /*
247  * Create the tuple receiver object and insert info it will need
248  */
249  dest = CreateIntoRelDestReceiver(into);
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, lock down security-restricted operations and
272  * arrange to make GUC variable changes local to this command. This is
273  * not necessary for security, but this keeps the behavior similar to
274  * REFRESH MATERIALIZED VIEW. Otherwise, one could create a materialized
275  * view not possible to refresh.
276  */
277  if (is_matview)
278  {
279  GetUserIdAndSecContext(&save_userid, &save_sec_context);
280  SetUserIdAndSecContext(save_userid,
281  save_sec_context | SECURITY_RESTRICTED_OPERATION);
282  save_nestlevel = NewGUCNestLevel();
283  }
284 
285  if (into->skipData)
286  {
287  /*
288  * If WITH NO DATA was specified, do not go through the rewriter,
289  * planner and executor. Just define the relation using a code path
290  * similar to CREATE VIEW. This avoids dump/restore problems stemming
291  * from running the planner before all dependencies are set up.
292  */
293  address = create_ctas_nodata(query->targetList, into);
294  }
295  else
296  {
297  /*
298  * Parse analysis was done already, but we still have to run the rule
299  * rewriter. We do not do AcquireRewriteLocks: we assume the query
300  * either came straight from the parser, or suitable locks were
301  * acquired by plancache.c.
302  */
303  rewritten = QueryRewrite(query);
304 
305  /* SELECT should never rewrite to more or less than one SELECT query */
306  if (list_length(rewritten) != 1)
307  elog(ERROR, "unexpected rewrite result for %s",
308  is_matview ? "CREATE MATERIALIZED VIEW" :
309  "CREATE TABLE AS SELECT");
310  query = linitial_node(Query, rewritten);
311  Assert(query->commandType == CMD_SELECT);
312 
313  /* plan the query */
314  plan = pg_plan_query(query, pstate->p_sourcetext,
315  CURSOR_OPT_PARALLEL_OK, params);
316 
317  /*
318  * Use a snapshot with an updated command ID to ensure this query sees
319  * results of any previously executed queries. (This could only
320  * matter if the planner executed an allegedly-stable function that
321  * changed the database contents, but let's do it anyway to be
322  * parallel to the EXPLAIN code path.)
323  */
326 
327  /* Create a QueryDesc, redirecting output to our tuple receiver */
328  queryDesc = CreateQueryDesc(plan, pstate->p_sourcetext,
330  dest, params, queryEnv, 0);
331 
332  /* call ExecutorStart to prepare the plan for execution */
333  ExecutorStart(queryDesc, GetIntoRelEFlags(into));
334 
335  /* run the plan to completion */
336  ExecutorRun(queryDesc, ForwardScanDirection, 0L, true);
337 
338  /* save the rowcount if we're given a qc to fill */
339  if (qc)
340  SetQueryCompletion(qc, CMDTAG_SELECT, queryDesc->estate->es_processed);
341 
342  /* get object address that intorel_startup saved for us */
343  address = ((DR_intorel *) dest)->reladdr;
344 
345  /* and clean up */
346  ExecutorFinish(queryDesc);
347  ExecutorEnd(queryDesc);
348 
349  FreeQueryDesc(queryDesc);
350 
352  }
353 
354  if (is_matview)
355  {
356  /* Roll back any GUC changes */
357  AtEOXact_GUC(false, save_nestlevel);
358 
359  /* Restore userid and security context */
360  SetUserIdAndSecContext(save_userid, save_sec_context);
361  }
362 
363  return address;
364 }
void UpdateActiveSnapshotCommandId(void)
Definition: snapmgr.c:728
#define IsA(nodeptr, _type_)
Definition: nodes.h:590
List * QueryRewrite(Query *parsetree)
EState * estate
Definition: execdesc.h:48
#define SECURITY_RESTRICTED_OPERATION
Definition: miscadmin.h:312
void SetUserIdAndSecContext(Oid userid, int sec_context)
Definition: miscinit.c:590
#define castNode(_type_, nodeptr)
Definition: nodes.h:608
void FreeQueryDesc(QueryDesc *qdesc)
Definition: pquery.c:105
void ExecutorStart(QueryDesc *queryDesc, int eflags)
Definition: execMain.c:130
Snapshot GetActiveSnapshot(void)
Definition: snapmgr.c:786
void PopActiveSnapshot(void)
Definition: snapmgr.c:759
bool skipData
Definition: primnodes.h:119
unsigned int Oid
Definition: postgres_ext.h:31
Node * utilityStmt
Definition: parsenodes.h:128
#define linitial_node(type, l)
Definition: pg_list.h:177
List * targetList
Definition: parsenodes.h:150
void ExecutorEnd(QueryDesc *queryDesc)
Definition: execMain.c:459
int GetIntoRelEFlags(IntoClause *intoClause)
Definition: createas.c:375
#define ERROR
Definition: elog.h:46
Node * viewQuery
Definition: primnodes.h:118
void ExecutorRun(QueryDesc *queryDesc, ScanDirection direction, uint64 count, bool execute_once)
Definition: execMain.c:298
void PushCopiedSnapshot(Snapshot snapshot)
Definition: snapmgr.c:716
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
void GetUserIdAndSecContext(Oid *userid, int *sec_context)
Definition: miscinit.c:583
void AtEOXact_GUC(bool isCommit, int nestLevel)
Definition: guc.c:6218
void ExecuteQuery(ParseState *pstate, ExecuteStmt *stmt, IntoClause *intoClause, ParamListInfo params, DestReceiver *dest, QueryCompletion *qc)
Definition: prepare.c:184
DestReceiver * CreateIntoRelDestReceiver(IntoClause *intoClause)
Definition: createas.c:428
bool CreateTableAsRelExists(CreateTableAsStmt *ctas)
Definition: createas.c:393
const char * p_sourcetext
Definition: parse_node.h:181
void ExecutorFinish(QueryDesc *queryDesc)
Definition: execMain.c:399
#define InvalidSnapshot
Definition: snapshot.h:123
#define InvalidOid
Definition: postgres_ext.h:36
IntoClause * into
Definition: parsenodes.h:3397
CmdType commandType
Definition: parsenodes.h:120
#define Assert(condition)
Definition: c.h:804
static void SetQueryCompletion(QueryCompletion *qc, CommandTag commandTag, uint64 nprocessed)
Definition: cmdtag.h:36
uint64 es_processed
Definition: execnodes.h:604
static int list_length(const List *l)
Definition: pg_list.h:149
static ObjectAddress create_ctas_nodata(List *tlist, IntoClause *into)
Definition: createas.c:158
int NewGUCNestLevel(void)
Definition: guc.c:6204
#define CURSOR_OPT_PARALLEL_OK
Definition: parsenodes.h:2816
const ObjectAddress InvalidObjectAddress
#define elog(elevel,...)
Definition: elog.h:232
PlannedStmt * pg_plan_query(Query *querytree, const char *query_string, int cursorOptions, ParamListInfo boundParams)
Definition: postgres.c:829
Definition: pg_list.h:50

◆ GetIntoRelEFlags()

int GetIntoRelEFlags ( IntoClause intoClause)

Definition at line 375 of file createas.c.

References EXEC_FLAG_WITH_NO_DATA, and IntoClause::skipData.

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

376 {
377  int flags = 0;
378 
379  if (intoClause->skipData)
380  flags |= EXEC_FLAG_WITH_NO_DATA;
381 
382  return flags;
383 }
#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 622 of file createas.c.

References pfree().

Referenced by CreateIntoRelDestReceiver().

623 {
624  pfree(self);
625 }
void pfree(void *pointer)
Definition: mcxt.c:1169

◆ intorel_receive()

static bool intorel_receive ( TupleTableSlot slot,
DestReceiver self 
)
static

Definition at line 571 of file createas.c.

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().

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

◆ intorel_shutdown()

static void intorel_shutdown ( DestReceiver self)
static

Definition at line 602 of file createas.c.

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().

603 {
604  DR_intorel *myState = (DR_intorel *) self;
605  IntoClause *into = myState->into;
606 
607  if (!into->skipData)
608  {
609  FreeBulkInsertState(myState->bistate);
610  table_finish_bulk_insert(myState->rel, myState->ti_options);
611  }
612 
613  /* close rel, but keep lock until commit */
614  table_close(myState->rel, NoLock);
615  myState->rel = NULL;
616 }
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:167
int ti_options
Definition: createas.c:62
static void table_finish_bulk_insert(Relation rel, int options)
Definition: tableam.h:1564
bool skipData
Definition: primnodes.h:119
BulkInsertState bistate
Definition: createas.c:63
#define NoLock
Definition: lockdefs.h:34
Relation rel
Definition: createas.c:59
void FreeBulkInsertState(BulkInsertState bistate)
Definition: heapam.c:2021
IntoClause * into
Definition: createas.c:57

◆ intorel_startup()

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

Definition at line 447 of file createas.c.

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, TypeName::typeOid, and IntoClause::viewQuery.

Referenced by CreateIntoRelDestReceiver().

448 {
449  DR_intorel *myState = (DR_intorel *) self;
450  IntoClause *into = myState->into;
451  bool is_matview;
452  List *attrList;
453  ObjectAddress intoRelationAddr;
454  Relation intoRelationDesc;
455  ListCell *lc;
456  int attnum;
457 
458  Assert(into != NULL); /* else somebody forgot to set it */
459 
460  /* This code supports both CREATE TABLE AS and CREATE MATERIALIZED VIEW */
461  is_matview = (into->viewQuery != NULL);
462 
463  /*
464  * Build column definitions using "pre-cooked" type and collation info. If
465  * a column name list was specified in CREATE TABLE AS, override the
466  * column names derived from the query. (Too few column names are OK, too
467  * many are not.)
468  */
469  attrList = NIL;
470  lc = list_head(into->colNames);
471  for (attnum = 0; attnum < typeinfo->natts; attnum++)
472  {
473  Form_pg_attribute attribute = TupleDescAttr(typeinfo, attnum);
474  ColumnDef *col;
475  char *colname;
476 
477  if (lc)
478  {
479  colname = strVal(lfirst(lc));
480  lc = lnext(into->colNames, lc);
481  }
482  else
483  colname = NameStr(attribute->attname);
484 
485  col = makeColumnDef(colname,
486  attribute->atttypid,
487  attribute->atttypmod,
488  attribute->attcollation);
489 
490  /*
491  * It's possible that the column is of a collatable type but the
492  * collation could not be resolved, so double-check. (We must check
493  * this here because DefineRelation would adopt the type's default
494  * collation rather than complaining.)
495  */
496  if (!OidIsValid(col->collOid) &&
498  ereport(ERROR,
499  (errcode(ERRCODE_INDETERMINATE_COLLATION),
500  errmsg("no collation was derived for column \"%s\" with collatable type %s",
501  col->colname,
503  errhint("Use the COLLATE clause to set the collation explicitly.")));
504 
505  attrList = lappend(attrList, col);
506  }
507 
508  if (lc != NULL)
509  ereport(ERROR,
510  (errcode(ERRCODE_SYNTAX_ERROR),
511  errmsg("too many column names were specified")));
512 
513  /*
514  * Actually create the target table
515  */
516  intoRelationAddr = create_ctas_internal(attrList, into);
517 
518  /*
519  * Finally we can open the target table
520  */
521  intoRelationDesc = table_open(intoRelationAddr.objectId, AccessExclusiveLock);
522 
523  /*
524  * Make sure the constructed table does not have RLS enabled.
525  *
526  * check_enable_rls() will ereport(ERROR) itself if the user has requested
527  * something invalid, and otherwise will return RLS_ENABLED if RLS should
528  * be enabled here. We don't actually support that currently, so throw
529  * our own ereport(ERROR) if that happens.
530  */
531  if (check_enable_rls(intoRelationAddr.objectId, InvalidOid, false) == RLS_ENABLED)
532  ereport(ERROR,
533  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
534  errmsg("policies not yet implemented for this command")));
535 
536  /*
537  * Tentatively mark the target as populated, if it's a matview and we're
538  * going to fill it; otherwise, no change needed.
539  */
540  if (is_matview && !into->skipData)
541  SetMatViewPopulatedState(intoRelationDesc, true);
542 
543  /*
544  * Fill private fields of myState for use by later routines
545  */
546  myState->rel = intoRelationDesc;
547  myState->reladdr = intoRelationAddr;
548  myState->output_cid = GetCurrentCommandId(true);
550 
551  /*
552  * If WITH NO DATA is specified, there is no need to set up the state for
553  * bulk inserts as there are no tuples to insert.
554  */
555  if (!into->skipData)
556  myState->bistate = GetBulkInsertState();
557  else
558  myState->bistate = NULL;
559 
560  /*
561  * Valid smgr_targblock implies something already wrote to the relation.
562  * This may be harmless, but this function hasn't planned for it.
563  */
564  Assert(RelationGetTargetBlock(intoRelationDesc) == InvalidBlockNumber);
565 }
#define NIL
Definition: pg_list.h:65
Oid typeOid
Definition: parsenodes.h:222
int errhint(const char *fmt,...)
Definition: elog.c:1156
static ListCell * lnext(const List *l, const ListCell *c)
Definition: pg_list.h:322
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92
int ti_options
Definition: createas.c:62
#define strVal(v)
Definition: value.h:54
int errcode(int sqlerrcode)
Definition: elog.c:698
char * format_type_be(Oid type_oid)
Definition: format_type.c:339
CommandId output_cid
Definition: createas.c:61
bool skipData
Definition: primnodes.h:119
BulkInsertState bistate
Definition: createas.c:63
#define OidIsValid(objectId)
Definition: c.h:710
#define RelationGetTargetBlock(relation)
Definition: rel.h:574
BulkInsertState GetBulkInsertState(void)
Definition: heapam.c:2007
ObjectAddress reladdr
Definition: createas.c:60
static ObjectAddress create_ctas_internal(List *attrList, IntoClause *into)
Definition: createas.c:85
#define ERROR
Definition: elog.h:46
Node * viewQuery
Definition: primnodes.h:118
Oid collOid
Definition: parsenodes.h:673
Relation rel
Definition: createas.c:59
static ListCell * list_head(const List *l)
Definition: pg_list.h:125
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:207
List * lappend(List *list, void *datum)
Definition: list.c:336
#define TABLE_INSERT_SKIP_FSM
Definition: tableam.h:234
#define InvalidOid
Definition: postgres_ext.h:36
int16 attnum
Definition: pg_attribute.h:83
#define ereport(elevel,...)
Definition: elog.h:157
int check_enable_rls(Oid relid, Oid checkAsUser, bool noError)
Definition: rls.c:52
#define Assert(condition)
Definition: c.h:804
#define lfirst(lc)
Definition: pg_list.h:169
#define InvalidBlockNumber
Definition: block.h:33
TypeName * typeName
Definition: parsenodes.h:659
IntoClause * into
Definition: createas.c:57
#define AccessExclusiveLock
Definition: lockdefs.h:45
int errmsg(const char *fmt,...)
Definition: elog.c:909
#define NameStr(name)
Definition: c.h:681
char * colname
Definition: parsenodes.h:658
CommandId GetCurrentCommandId(bool used)
Definition: xact.c:761
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:3028
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:490