PostgreSQL Source Code  git master
createas.h File Reference
#include "catalog/objectaddress.h"
#include "nodes/params.h"
#include "nodes/parsenodes.h"
#include "tcop/dest.h"
#include "utils/queryenvironment.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, QueryEnvironment *queryEnv, char *completionTag)
 
int GetIntoRelEFlags (IntoClause *intoClause)
 
DestReceiverCreateIntoRelDestReceiver (IntoClause *intoClause)
 

Function Documentation

◆ CreateIntoRelDestReceiver()

DestReceiver* CreateIntoRelDestReceiver ( IntoClause intoClause)

Definition at line 413 of file createas.c.

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

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

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

◆ ExecCreateTableAs()

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

Definition at line 227 of file createas.c.

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

Referenced by ProcessUtilitySlow().

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

◆ GetIntoRelEFlags()

int GetIntoRelEFlags ( IntoClause intoClause)

Definition at line 395 of file createas.c.

References EXEC_FLAG_WITH_NO_DATA, and IntoClause::skipData.

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

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