PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
createas.h File Reference
#include "catalog/objectaddress.h"
#include "nodes/params.h"
#include "nodes/parsenodes.h"
#include "tcop/dest.h"
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 (CreateTableAsStmt *stmt, const char *queryString, ParamListInfo params, char *completionTag)
 
int GetIntoRelEFlags (IntoClause *intoClause)
 
DestReceiverCreateIntoRelDestReceiver (IntoClause *intoClause)
 

Function Documentation

DestReceiver* CreateIntoRelDestReceiver ( IntoClause intoClause)

Definition at line 422 of file createas.c.

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

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

423 {
424  DR_intorel *self = (DR_intorel *) palloc0(sizeof(DR_intorel));
425 
426  self->pub.receiveSlot = intorel_receive;
427  self->pub.rStartup = intorel_startup;
428  self->pub.rShutdown = intorel_shutdown;
429  self->pub.rDestroy = intorel_destroy;
430  self->pub.mydest = DestIntoRel;
431  self->into = intoClause;
432  /* other private fields will be set during intorel_startup */
433 
434  return (DestReceiver *) self;
435 }
static void intorel_shutdown(DestReceiver *self)
Definition: createas.c:613
static bool intorel_receive(TupleTableSlot *slot, DestReceiver *self)
Definition: createas.c:581
void * palloc0(Size size)
Definition: mcxt.c:878
static void intorel_destroy(DestReceiver *self)
Definition: createas.c:632
static void intorel_startup(DestReceiver *self, int operation, TupleDesc typeinfo)
Definition: createas.c:441
ObjectAddress ExecCreateTableAs ( CreateTableAsStmt stmt,
const char *  queryString,
ParamListInfo  params,
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, list_length(), NewGUCNestLevel(), NOTICE, NULL, 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().

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

Definition at line 391 of file createas.c.

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

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

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