PostgreSQL Source Code  git master
createas.c File Reference
#include "postgres.h"
#include "access/heapam.h"
#include "access/reloptions.h"
#include "access/tableam.h"
#include "access/xact.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 "rewrite/rewriteHandler.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 80 of file createas.c.

81 {
82  CreateStmt *create = makeNode(CreateStmt);
83  bool is_matview;
84  char relkind;
85  Datum toast_options;
86  const char *const validnsps[] = HEAP_RELOPT_NAMESPACES;
87  ObjectAddress intoRelationAddr;
88 
89  /* This code supports both CREATE TABLE AS and CREATE MATERIALIZED VIEW */
90  is_matview = (into->viewQuery != NULL);
91  relkind = is_matview ? RELKIND_MATVIEW : RELKIND_RELATION;
92 
93  /*
94  * Create the target relation by faking up a CREATE TABLE parsetree and
95  * passing it to DefineRelation.
96  */
97  create->relation = into->rel;
98  create->tableElts = attrList;
99  create->inhRelations = NIL;
100  create->ofTypename = NULL;
101  create->constraints = NIL;
102  create->options = into->options;
103  create->oncommit = into->onCommit;
104  create->tablespacename = into->tableSpaceName;
105  create->if_not_exists = false;
106  create->accessMethod = into->accessMethod;
107 
108  /*
109  * Create the relation. (This will error out if there's an existing view,
110  * so we don't need more code to complain if "replace" is false.)
111  */
112  intoRelationAddr = DefineRelation(create, relkind, InvalidOid, NULL, NULL);
113 
114  /*
115  * If necessary, create a TOAST table for the target table. Note that
116  * NewRelationCreateToastTable ends with CommandCounterIncrement(), so
117  * that the TOAST table will be visible for insertion.
118  */
120 
121  /* parse and validate reloptions for the toast table */
122  toast_options = transformRelOptions((Datum) 0,
123  create->options,
124  "toast",
125  validnsps,
126  true, false);
127 
128  (void) heap_reloptions(RELKIND_TOASTVALUE, toast_options, true);
129 
130  NewRelationCreateToastTable(intoRelationAddr.objectId, toast_options);
131 
132  /* Create the "view" part of a materialized view. */
133  if (is_matview)
134  {
135  /* StoreViewQuery scribbles on tree, so make a copy */
136  Query *query = (Query *) copyObject(into->viewQuery);
137 
138  StoreViewQuery(intoRelationAddr.objectId, query, false);
140  }
141 
142  return intoRelationAddr;
143 }
#define copyObject(obj)
Definition: nodes.h:224
#define makeNode(_type_)
Definition: nodes.h:155
#define NIL
Definition: pg_list.h:68
uintptr_t Datum
Definition: postgres.h:64
#define InvalidOid
Definition: postgres_ext.h:36
Datum transformRelOptions(Datum oldOptions, List *defList, const char *namspace, const char *const validnsps[], bool acceptOidsOff, bool isReset)
Definition: reloptions.c:1156
bytea * heap_reloptions(char relkind, Datum reloptions, bool validate)
Definition: reloptions.c:2019
#define HEAP_RELOPT_NAMESPACES
Definition: reloptions.h:61
List * tableElts
Definition: parsenodes.h:2651
TypeName * ofTypename
Definition: parsenodes.h:2656
OnCommitAction oncommit
Definition: parsenodes.h:2659
List * options
Definition: parsenodes.h:2658
bool if_not_exists
Definition: parsenodes.h:2662
List * inhRelations
Definition: parsenodes.h:2652
RangeVar * relation
Definition: parsenodes.h:2650
char * tablespacename
Definition: parsenodes.h:2660
char * accessMethod
Definition: parsenodes.h:2661
List * constraints
Definition: parsenodes.h:2657
char * tableSpaceName
Definition: primnodes.h:167
OnCommitAction onCommit
Definition: primnodes.h:166
List * options
Definition: primnodes.h:165
char * accessMethod
Definition: primnodes.h:164
RangeVar * rel
Definition: primnodes.h:162
ObjectAddress DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId, ObjectAddress *typaddress, const char *queryString)
Definition: tablecmds.c:682
void NewRelationCreateToastTable(Oid relOid, Datum reloptions)
Definition: toasting.c:70
void StoreViewQuery(Oid viewOid, Query *viewParse, bool replace)
Definition: view.c:511
void CommandCounterIncrement(void)
Definition: xact.c:1099

References CreateStmt::accessMethod, IntoClause::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, CreateStmt::oncommit, IntoClause::onCommit, CreateStmt::options, IntoClause::options, IntoClause::rel, CreateStmt::relation, StoreViewQuery(), CreateStmt::tableElts, CreateStmt::tablespacename, IntoClause::tableSpaceName, and transformRelOptions().

Referenced by create_ctas_nodata(), and intorel_startup().

◆ create_ctas_nodata()

static ObjectAddress create_ctas_nodata ( List tlist,
IntoClause into 
)
static

Definition at line 153 of file createas.c.

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

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, strVal, type_is_collatable(), ColumnDef::typeName, and TypeName::typeOid.

Referenced by ExecCreateTableAs().

◆ CreateIntoRelDestReceiver()

DestReceiver* CreateIntoRelDestReceiver ( IntoClause intoClause)

Definition at line 430 of file createas.c.

431 {
432  DR_intorel *self = (DR_intorel *) palloc0(sizeof(DR_intorel));
433 
434  self->pub.receiveSlot = intorel_receive;
435  self->pub.rStartup = intorel_startup;
436  self->pub.rShutdown = intorel_shutdown;
437  self->pub.rDestroy = intorel_destroy;
438  self->pub.mydest = DestIntoRel;
439  self->into = intoClause;
440  /* other private fields will be set during intorel_startup */
441 
442  return (DestReceiver *) self;
443 }
static void intorel_shutdown(DestReceiver *self)
Definition: createas.c:604
static bool intorel_receive(TupleTableSlot *slot, DestReceiver *self)
Definition: createas.c:573
static void intorel_startup(DestReceiver *self, int operation, TupleDesc typeinfo)
Definition: createas.c:449
static void intorel_destroy(DestReceiver *self)
Definition: createas.c:624
@ DestIntoRel
Definition: dest.h:94
void * palloc0(Size size)
Definition: mcxt.c:1347

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

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

◆ CreateTableAsRelExists()

bool CreateTableAsRelExists ( CreateTableAsStmt ctas)

Definition at line 383 of file createas.c.

384 {
385  Oid nspid;
386  Oid oldrelid;
387  ObjectAddress address;
388  IntoClause *into = ctas->into;
389 
391 
392  oldrelid = get_relname_relid(into->rel->relname, nspid);
393  if (OidIsValid(oldrelid))
394  {
395  if (!ctas->if_not_exists)
396  ereport(ERROR,
397  (errcode(ERRCODE_DUPLICATE_TABLE),
398  errmsg("relation \"%s\" already exists",
399  into->rel->relname)));
400 
401  /*
402  * The relation exists and IF NOT EXISTS has been specified.
403  *
404  * If we are in an extension script, insist that the pre-existing
405  * object be a member of the extension, to avoid security risks.
406  */
407  ObjectAddressSet(address, RelationRelationId, oldrelid);
409 
410  /* OK to skip */
411  ereport(NOTICE,
412  (errcode(ERRCODE_DUPLICATE_TABLE),
413  errmsg("relation \"%s\" already exists, skipping",
414  into->rel->relname)));
415  return true;
416  }
417 
418  /* Relation does not exist, it can be created */
419  return false;
420 }
int nspid
#define NOTICE
Definition: elog.h:35
Oid get_relname_relid(const char *relname, Oid relnamespace)
Definition: lsyscache.c:1885
Oid RangeVarGetCreationNamespace(const RangeVar *newRelation)
Definition: namespace.c:639
#define ObjectAddressSet(addr, class_id, object_id)
Definition: objectaddress.h:40
void checkMembershipInCurrentExtension(const ObjectAddress *object)
Definition: pg_depend.c:259
unsigned int Oid
Definition: postgres_ext.h:31
IntoClause * into
Definition: parsenodes.h:3891
char * relname
Definition: primnodes.h:82

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

Referenced by ExecCreateTableAs(), and ExplainOneUtility().

◆ ExecCreateTableAs()

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

Definition at line 221 of file createas.c.

224 {
225  Query *query = castNode(Query, stmt->query);
226  IntoClause *into = stmt->into;
227  bool is_matview = (into->viewQuery != NULL);
228  bool do_refresh = false;
230  ObjectAddress address;
231 
232  /* Check if the relation exists or not */
234  return InvalidObjectAddress;
235 
236  /*
237  * Create the tuple receiver object and insert info it will need
238  */
240 
241  /*
242  * The contained Query could be a SELECT, or an EXECUTE utility command.
243  * If the latter, we just pass it off to ExecuteQuery.
244  */
245  if (query->commandType == CMD_UTILITY &&
246  IsA(query->utilityStmt, ExecuteStmt))
247  {
248  ExecuteStmt *estmt = castNode(ExecuteStmt, query->utilityStmt);
249 
250  Assert(!is_matview); /* excluded by syntax */
251  ExecuteQuery(pstate, estmt, into, params, dest, qc);
252 
253  /* get object address that intorel_startup saved for us */
254  address = ((DR_intorel *) dest)->reladdr;
255 
256  return address;
257  }
258  Assert(query->commandType == CMD_SELECT);
259 
260  /*
261  * For materialized views, always skip data during table creation, and use
262  * REFRESH instead (see below).
263  */
264  if (is_matview)
265  {
266  do_refresh = !into->skipData;
267  into->skipData = true;
268  }
269 
270  if (into->skipData)
271  {
272  /*
273  * If WITH NO DATA was specified, do not go through the rewriter,
274  * planner and executor. Just define the relation using a code path
275  * similar to CREATE VIEW. This avoids dump/restore problems stemming
276  * from running the planner before all dependencies are set up.
277  */
278  address = create_ctas_nodata(query->targetList, into);
279 
280  /*
281  * For materialized views, reuse the REFRESH logic, which locks down
282  * security-restricted operations and restricts the search_path. This
283  * reduces the chance that a subsequent refresh will fail.
284  */
285  if (do_refresh)
286  RefreshMatViewByOid(address.objectId, true, false, false,
287  pstate->p_sourcetext, qc);
288 
289  }
290  else
291  {
292  List *rewritten;
293  PlannedStmt *plan;
294  QueryDesc *queryDesc;
295 
296  Assert(!is_matview);
297 
298  /*
299  * Parse analysis was done already, but we still have to run the rule
300  * rewriter. We do not do AcquireRewriteLocks: we assume the query
301  * either came straight from the parser, or suitable locks were
302  * acquired by plancache.c.
303  */
304  rewritten = QueryRewrite(query);
305 
306  /* SELECT should never rewrite to more or less than one SELECT query */
307  if (list_length(rewritten) != 1)
308  elog(ERROR, "unexpected rewrite result for CREATE TABLE AS SELECT");
309  query = linitial_node(Query, rewritten);
310  Assert(query->commandType == CMD_SELECT);
311 
312  /* plan the query */
313  plan = pg_plan_query(query, pstate->p_sourcetext,
314  CURSOR_OPT_PARALLEL_OK, params);
315 
316  /*
317  * Use a snapshot with an updated command ID to ensure this query sees
318  * results of any previously executed queries. (This could only
319  * matter if the planner executed an allegedly-stable function that
320  * changed the database contents, but let's do it anyway to be
321  * parallel to the EXPLAIN code path.)
322  */
325 
326  /* Create a QueryDesc, redirecting output to our tuple receiver */
327  queryDesc = CreateQueryDesc(plan, pstate->p_sourcetext,
329  dest, params, queryEnv, 0);
330 
331  /* call ExecutorStart to prepare the plan for execution */
332  ExecutorStart(queryDesc, GetIntoRelEFlags(into));
333 
334  /* run the plan to completion */
335  ExecutorRun(queryDesc, ForwardScanDirection, 0, true);
336 
337  /* save the rowcount if we're given a qc to fill */
338  if (qc)
339  SetQueryCompletion(qc, CMDTAG_SELECT, queryDesc->estate->es_processed);
340 
341  /* get object address that intorel_startup saved for us */
342  address = ((DR_intorel *) dest)->reladdr;
343 
344  /* and clean up */
345  ExecutorFinish(queryDesc);
346  ExecutorEnd(queryDesc);
347 
348  FreeQueryDesc(queryDesc);
349 
351  }
352 
353  return address;
354 }
void ExecuteQuery(ParseState *pstate, ExecuteStmt *stmt, IntoClause *intoClause, ParamListInfo params, DestReceiver *dest, QueryCompletion *qc)
Definition: prepare.c:147
#define Assert(condition)
Definition: c.h:858
static void SetQueryCompletion(QueryCompletion *qc, CommandTag commandTag, uint64 nprocessed)
Definition: cmdtag.h:37
bool CreateTableAsRelExists(CreateTableAsStmt *ctas)
Definition: createas.c:383
DestReceiver * CreateIntoRelDestReceiver(IntoClause *intoClause)
Definition: createas.c:430
static ObjectAddress create_ctas_nodata(List *tlist, IntoClause *into)
Definition: createas.c:153
int GetIntoRelEFlags(IntoClause *intoClause)
Definition: createas.c:365
#define elog(elevel,...)
Definition: elog.h:225
void ExecutorEnd(QueryDesc *queryDesc)
Definition: execMain.c:462
void ExecutorFinish(QueryDesc *queryDesc)
Definition: execMain.c:402
void ExecutorStart(QueryDesc *queryDesc, int eflags)
Definition: execMain.c:119
void ExecutorRun(QueryDesc *queryDesc, ScanDirection direction, uint64 count, bool execute_once)
Definition: execMain.c:292
#define stmt
Definition: indent_codes.h:59
ObjectAddress RefreshMatViewByOid(Oid matviewOid, bool is_create, bool skipData, bool concurrent, const char *queryString, QueryCompletion *qc)
Definition: matview.c:165
#define IsA(nodeptr, _type_)
Definition: nodes.h:158
@ CMD_UTILITY
Definition: nodes.h:270
@ CMD_SELECT
Definition: nodes.h:265
#define castNode(_type_, nodeptr)
Definition: nodes.h:176
const ObjectAddress InvalidObjectAddress
#define CURSOR_OPT_PARALLEL_OK
Definition: parsenodes.h:3290
static int list_length(const List *l)
Definition: pg_list.h:152
#define linitial_node(type, l)
Definition: pg_list.h:181
#define plan(x)
Definition: pg_regress.c:162
PlannedStmt * pg_plan_query(Query *querytree, const char *query_string, int cursorOptions, ParamListInfo boundParams)
Definition: postgres.c:894
void FreeQueryDesc(QueryDesc *qdesc)
Definition: pquery.c:105
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
List * QueryRewrite(Query *parsetree)
@ ForwardScanDirection
Definition: sdir.h:28
void UpdateActiveSnapshotCommandId(void)
Definition: snapmgr.c:712
void PopActiveSnapshot(void)
Definition: snapmgr.c:743
void PushCopiedSnapshot(Snapshot snapshot)
Definition: snapmgr.c:700
Snapshot GetActiveSnapshot(void)
Definition: snapmgr.c:770
#define InvalidSnapshot
Definition: snapshot.h:123
uint64 es_processed
Definition: execnodes.h:675
bool skipData
Definition: primnodes.h:170
const char * p_sourcetext
Definition: parse_node.h:195
EState * estate
Definition: execdesc.h:48
CmdType commandType
Definition: parsenodes.h:121
Node * utilityStmt
Definition: parsenodes.h:136
List * targetList
Definition: parsenodes.h:193

References Assert, 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(), InvalidObjectAddress, InvalidSnapshot, IsA, linitial_node, list_length(), ObjectAddress::objectId, ParseState::p_sourcetext, pg_plan_query(), plan, PopActiveSnapshot(), PushCopiedSnapshot(), QueryRewrite(), RefreshMatViewByOid(), SetQueryCompletion(), IntoClause::skipData, stmt, Query::targetList, UpdateActiveSnapshotCommandId(), and Query::utilityStmt.

Referenced by ProcessUtilitySlow().

◆ GetIntoRelEFlags()

int GetIntoRelEFlags ( IntoClause intoClause)

Definition at line 365 of file createas.c.

366 {
367  int flags = 0;
368 
369  if (intoClause->skipData)
370  flags |= EXEC_FLAG_WITH_NO_DATA;
371 
372  return flags;
373 }
#define EXEC_FLAG_WITH_NO_DATA
Definition: executor.h:71

References EXEC_FLAG_WITH_NO_DATA, and IntoClause::skipData.

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

◆ intorel_destroy()

static void intorel_destroy ( DestReceiver self)
static

Definition at line 624 of file createas.c.

625 {
626  pfree(self);
627 }
void pfree(void *pointer)
Definition: mcxt.c:1521

References pfree().

Referenced by CreateIntoRelDestReceiver().

◆ intorel_receive()

static bool intorel_receive ( TupleTableSlot slot,
DestReceiver self 
)
static

Definition at line 573 of file createas.c.

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

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

◆ intorel_shutdown()

static void intorel_shutdown ( DestReceiver self)
static

Definition at line 604 of file createas.c.

605 {
606  DR_intorel *myState = (DR_intorel *) self;
607  IntoClause *into = myState->into;
608 
609  if (!into->skipData)
610  {
611  FreeBulkInsertState(myState->bistate);
612  table_finish_bulk_insert(myState->rel, myState->ti_options);
613  }
614 
615  /* close rel, but keep lock until commit */
616  table_close(myState->rel, NoLock);
617  myState->rel = NULL;
618 }
void FreeBulkInsertState(BulkInsertState bistate)
Definition: heapam.c:1926
#define NoLock
Definition: lockdefs.h:34
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:126
static void table_finish_bulk_insert(Relation rel, int options)
Definition: tableam.h:1595

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

◆ intorel_startup()

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

Definition at line 449 of file createas.c.

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

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

Referenced by CreateIntoRelDestReceiver().