PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
createas.c File Reference
#include "postgres.h"
#include "access/reloptions.h"
#include "access/htup_details.h"
#include "access/sysattr.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

static ObjectAddress create_ctas_internal ( List attrList,
IntoClause into 
)
static

Definition at line 84 of file createas.c.

References 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_MATVIEW, RELKIND_RELATION, RELKIND_TOASTVALUE, StoreViewQuery(), CreateStmt::tableElts, IntoClause::tableSpaceName, CreateStmt::tablespacename, transformRelOptions(), and IntoClause::viewQuery.

Referenced by create_ctas_nodata(), and intorel_startup().

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

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

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

Definition at line 423 of file createas.c.

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

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

424 {
425  DR_intorel *self = (DR_intorel *) palloc0(sizeof(DR_intorel));
426 
427  self->pub.receiveSlot = intorel_receive;
428  self->pub.rStartup = intorel_startup;
429  self->pub.rShutdown = intorel_shutdown;
430  self->pub.rDestroy = intorel_destroy;
431  self->pub.mydest = DestIntoRel;
432  self->into = intoClause;
433  /* other private fields will be set during intorel_startup */
434 
435  return (DestReceiver *) self;
436 }
static void intorel_shutdown(DestReceiver *self)
Definition: createas.c:614
static bool intorel_receive(TupleTableSlot *slot, DestReceiver *self)
Definition: createas.c:582
void * palloc0(Size size)
Definition: mcxt.c:877
static void intorel_destroy(DestReceiver *self)
Definition: createas.c:633
static void intorel_startup(DestReceiver *self, int operation, TupleDesc typeinfo)
Definition: createas.c:442
ObjectAddress ExecCreateTableAs ( CreateTableAsStmt stmt,
const char *  queryString,
ParamListInfo  params,
QueryEnvironment queryEnv,
char *  completionTag 
)

Definition at line 224 of file createas.c.

References Assert, AtEOXact_GUC(), castNode, CMD_SELECT, CMD_UTILITY, Query::commandType, COMPLETION_TAG_BUFSIZE, copyObject, create_ctas_nodata(), CreateIntoRelDestReceiver(), CreateQueryDesc(), 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().

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

Definition at line 392 of file createas.c.

References EXEC_FLAG_WITH_NO_DATA, EXEC_FLAG_WITH_OIDS, EXEC_FLAG_WITHOUT_OIDS, interpretOidsOption(), IntoClause::options, IntoClause::skipData, and IntoClause::viewQuery.

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

393 {
394  int flags;
395 
396  /*
397  * We need to tell the executor whether it has to produce OIDs or not,
398  * because it doesn't have enough information to do so itself (since we
399  * can't build the target relation until after ExecutorStart).
400  *
401  * Disallow the OIDS option for materialized views.
402  */
403  if (interpretOidsOption(intoClause->options,
404  (intoClause->viewQuery == NULL)))
405  flags = EXEC_FLAG_WITH_OIDS;
406  else
407  flags = EXEC_FLAG_WITHOUT_OIDS;
408 
409  if (intoClause->skipData)
410  flags |= EXEC_FLAG_WITH_NO_DATA;
411 
412  return flags;
413 }
#define EXEC_FLAG_WITH_NO_DATA
Definition: executor.h:65
bool skipData
Definition: primnodes.h:115
#define EXEC_FLAG_WITHOUT_OIDS
Definition: executor.h:64
Node * viewQuery
Definition: primnodes.h:114
List * options
Definition: primnodes.h:111
bool interpretOidsOption(List *defList, bool allowOids)
Definition: parse_clause.c:255
#define EXEC_FLAG_WITH_OIDS
Definition: executor.h:63
static void intorel_destroy ( DestReceiver self)
static

Definition at line 633 of file createas.c.

References pfree().

Referenced by CreateIntoRelDestReceiver().

634 {
635  pfree(self);
636 }
void pfree(void *pointer)
Definition: mcxt.c:949
static bool intorel_receive ( TupleTableSlot slot,
DestReceiver self 
)
static

Definition at line 582 of file createas.c.

References DR_intorel::bistate, ExecMaterializeSlot(), heap_insert(), HeapTupleSetOid, DR_intorel::hi_options, InvalidOid, DR_intorel::output_cid, RelationData::rd_rel, and DR_intorel::rel.

Referenced by CreateIntoRelDestReceiver().

583 {
584  DR_intorel *myState = (DR_intorel *) self;
585  HeapTuple tuple;
586 
587  /*
588  * get the heap tuple out of the tuple table slot, making sure we have a
589  * writable copy
590  */
591  tuple = ExecMaterializeSlot(slot);
592 
593  /*
594  * force assignment of new OID (see comments in ExecInsert)
595  */
596  if (myState->rel->rd_rel->relhasoids)
597  HeapTupleSetOid(tuple, InvalidOid);
598 
599  heap_insert(myState->rel,
600  tuple,
601  myState->output_cid,
602  myState->hi_options,
603  myState->bistate);
604 
605  /* We know this is a newly created relation, so there are no indexes */
606 
607  return true;
608 }
CommandId output_cid
Definition: createas.c:60
BulkInsertState bistate
Definition: createas.c:62
Form_pg_class rd_rel
Definition: rel.h:114
int hi_options
Definition: createas.c:61
#define HeapTupleSetOid(tuple, oid)
Definition: htup_details.h:698
Relation rel
Definition: createas.c:58
Oid heap_insert(Relation relation, HeapTuple tup, CommandId cid, int options, BulkInsertState bistate)
Definition: heapam.c:2413
#define InvalidOid
Definition: postgres_ext.h:36
HeapTuple ExecMaterializeSlot(TupleTableSlot *slot)
Definition: execTuples.c:725
static void intorel_shutdown ( DestReceiver self)
static

Definition at line 614 of file createas.c.

References DR_intorel::bistate, FreeBulkInsertState(), heap_close, HEAP_INSERT_SKIP_WAL, heap_sync(), DR_intorel::hi_options, NoLock, and DR_intorel::rel.

Referenced by CreateIntoRelDestReceiver().

615 {
616  DR_intorel *myState = (DR_intorel *) self;
617 
618  FreeBulkInsertState(myState->bistate);
619 
620  /* If we skipped using WAL, must heap_sync before commit */
621  if (myState->hi_options & HEAP_INSERT_SKIP_WAL)
622  heap_sync(myState->rel);
623 
624  /* close rel, but keep lock until commit */
625  heap_close(myState->rel, NoLock);
626  myState->rel = NULL;
627 }
void heap_sync(Relation rel)
Definition: heapam.c:9135
#define HEAP_INSERT_SKIP_WAL
Definition: heapam.h:28
#define heap_close(r, l)
Definition: heapam.h:97
BulkInsertState bistate
Definition: createas.c:62
int hi_options
Definition: createas.c:61
#define NoLock
Definition: lockdefs.h:34
Relation rel
Definition: createas.c:58
void FreeBulkInsertState(BulkInsertState bistate)
Definition: heapam.c:2350
static void intorel_startup ( DestReceiver self,
int  operation,
TupleDesc  typeinfo 
)
static

Definition at line 442 of file createas.c.

References AccessExclusiveLock, ACL_INSERT, Assert, 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(), HEAP_INSERT_SKIP_FSM, HEAP_INSERT_SKIP_WAL, heap_open(), DR_intorel::hi_options, RangeTblEntry::insertedCols, DR_intorel::into, InvalidBlockNumber, InvalidOid, lappend(), lfirst, list_head(), list_make1, lnext, makeColumnDef(), makeNode, NameStr, tupleDesc::natts, NIL, ObjectAddress::objectId, OidIsValid, DR_intorel::output_cid, RelationData::rd_att, DR_intorel::rel, DR_intorel::reladdr, RelationGetTargetBlock, RangeTblEntry::relid, RangeTblEntry::relkind, RELKIND_MATVIEW, RELKIND_RELATION, RangeTblEntry::requiredPerms, RLS_ENABLED, RTE_RELATION, RangeTblEntry::rtekind, SetMatViewPopulatedState(), IntoClause::skipData, strVal, TupleDescAttr, type_is_collatable(), ColumnDef::typeName, TypeName::typeOid, IntoClause::viewQuery, and XLogIsNeeded.

Referenced by CreateIntoRelDestReceiver().

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