PostgreSQL Source Code  git master
createas.h File Reference
Include dependency graph for createas.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Functions

ObjectAddress ExecCreateTableAs (ParseState *pstate, CreateTableAsStmt *stmt, ParamListInfo params, QueryEnvironment *queryEnv, QueryCompletion *qc)
 
int GetIntoRelEFlags (IntoClause *intoClause)
 
DestReceiverCreateIntoRelDestReceiver (IntoClause *intoClause)
 
bool CreateTableAsRelExists (CreateTableAsStmt *ctas)
 

Function Documentation

◆ 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:3409
#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:743
#define IsA(nodeptr, _type_)
Definition: nodes.h:587
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:607
#define castNode(_type_, nodeptr)
Definition: nodes.h:605
void FreeQueryDesc(QueryDesc *qdesc)
Definition: pquery.c:105
void ExecutorStart(QueryDesc *queryDesc, int eflags)
Definition: execMain.c:130
Snapshot GetActiveSnapshot(void)
Definition: snapmgr.c:801
void PopActiveSnapshot(void)
Definition: snapmgr.c:774
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:731
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:600
void AtEOXact_GUC(bool isCommit, int nestLevel)
Definition: guc.c:6242
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:3409
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:6228
#define CURSOR_OPT_PARALLEL_OK
Definition: parsenodes.h:2828
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