PostgreSQL Source Code  git master
tablecmds.c
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------
2  *
3  * tablecmds.c
4  * Commands for creating and altering table structures and settings
5  *
6  * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  *
10  * IDENTIFICATION
11  * src/backend/commands/tablecmds.c
12  *
13  *-------------------------------------------------------------------------
14  */
15 #include "postgres.h"
16 
17 #include "access/attmap.h"
18 #include "access/genam.h"
19 #include "access/heapam.h"
20 #include "access/heapam_xlog.h"
21 #include "access/multixact.h"
22 #include "access/reloptions.h"
23 #include "access/relscan.h"
24 #include "access/sysattr.h"
25 #include "access/tableam.h"
27 #include "access/xact.h"
28 #include "access/xlog.h"
29 #include "access/xloginsert.h"
30 #include "catalog/catalog.h"
31 #include "catalog/heap.h"
32 #include "catalog/index.h"
33 #include "catalog/namespace.h"
34 #include "catalog/objectaccess.h"
35 #include "catalog/partition.h"
36 #include "catalog/pg_am.h"
37 #include "catalog/pg_attrdef.h"
38 #include "catalog/pg_collation.h"
39 #include "catalog/pg_constraint.h"
40 #include "catalog/pg_depend.h"
42 #include "catalog/pg_inherits.h"
43 #include "catalog/pg_largeobject.h"
44 #include "catalog/pg_namespace.h"
45 #include "catalog/pg_opclass.h"
46 #include "catalog/pg_policy.h"
47 #include "catalog/pg_proc.h"
49 #include "catalog/pg_rewrite.h"
51 #include "catalog/pg_tablespace.h"
52 #include "catalog/pg_trigger.h"
53 #include "catalog/pg_type.h"
54 #include "catalog/storage.h"
55 #include "catalog/storage_xlog.h"
56 #include "catalog/toasting.h"
57 #include "commands/cluster.h"
58 #include "commands/comment.h"
59 #include "commands/defrem.h"
60 #include "commands/event_trigger.h"
61 #include "commands/sequence.h"
62 #include "commands/tablecmds.h"
63 #include "commands/tablespace.h"
64 #include "commands/trigger.h"
65 #include "commands/typecmds.h"
66 #include "commands/user.h"
67 #include "commands/vacuum.h"
68 #include "executor/executor.h"
69 #include "foreign/fdwapi.h"
70 #include "foreign/foreign.h"
71 #include "miscadmin.h"
72 #include "nodes/makefuncs.h"
73 #include "nodes/nodeFuncs.h"
74 #include "nodes/parsenodes.h"
75 #include "optimizer/optimizer.h"
76 #include "parser/parse_coerce.h"
77 #include "parser/parse_collate.h"
78 #include "parser/parse_expr.h"
79 #include "parser/parse_relation.h"
80 #include "parser/parse_type.h"
81 #include "parser/parse_utilcmd.h"
82 #include "parser/parser.h"
84 #include "partitioning/partdesc.h"
85 #include "pgstat.h"
86 #include "rewrite/rewriteDefine.h"
87 #include "rewrite/rewriteHandler.h"
88 #include "rewrite/rewriteManip.h"
89 #include "storage/bufmgr.h"
90 #include "storage/lmgr.h"
91 #include "storage/lock.h"
92 #include "storage/predicate.h"
93 #include "storage/smgr.h"
94 #include "tcop/utility.h"
95 #include "utils/acl.h"
96 #include "utils/builtins.h"
97 #include "utils/fmgroids.h"
98 #include "utils/inval.h"
99 #include "utils/lsyscache.h"
100 #include "utils/memutils.h"
101 #include "utils/partcache.h"
102 #include "utils/relcache.h"
103 #include "utils/ruleutils.h"
104 #include "utils/snapmgr.h"
105 #include "utils/syscache.h"
106 #include "utils/timestamp.h"
107 #include "utils/typcache.h"
108 #include "utils/usercontext.h"
109 
110 /*
111  * ON COMMIT action list
112  */
113 typedef struct OnCommitItem
114 {
115  Oid relid; /* relid of relation */
116  OnCommitAction oncommit; /* what to do at end of xact */
117 
118  /*
119  * If this entry was created during the current transaction,
120  * creating_subid is the ID of the creating subxact; if created in a prior
121  * transaction, creating_subid is zero. If deleted during the current
122  * transaction, deleting_subid is the ID of the deleting subxact; if no
123  * deletion request is pending, deleting_subid is zero.
124  */
128 
129 static List *on_commits = NIL;
130 
131 
132 /*
133  * State information for ALTER TABLE
134  *
135  * The pending-work queue for an ALTER TABLE is a List of AlteredTableInfo
136  * structs, one for each table modified by the operation (the named table
137  * plus any child tables that are affected). We save lists of subcommands
138  * to apply to this table (possibly modified by parse transformation steps);
139  * these lists will be executed in Phase 2. If a Phase 3 step is needed,
140  * necessary information is stored in the constraints and newvals lists.
141  *
142  * Phase 2 is divided into multiple passes; subcommands are executed in
143  * a pass determined by subcommand type.
144  */
145 
146 typedef enum AlterTablePass
147 {
148  AT_PASS_UNSET = -1, /* UNSET will cause ERROR */
149  AT_PASS_DROP, /* DROP (all flavors) */
150  AT_PASS_ALTER_TYPE, /* ALTER COLUMN TYPE */
151  AT_PASS_ADD_COL, /* ADD COLUMN */
152  AT_PASS_SET_EXPRESSION, /* ALTER SET EXPRESSION */
153  AT_PASS_OLD_INDEX, /* re-add existing indexes */
154  AT_PASS_OLD_CONSTR, /* re-add existing constraints */
155  /* We could support a RENAME COLUMN pass here, but not currently used */
156  AT_PASS_ADD_CONSTR, /* ADD constraints (initial examination) */
157  AT_PASS_COL_ATTRS, /* set column attributes, eg NOT NULL */
158  AT_PASS_ADD_INDEXCONSTR, /* ADD index-based constraints */
159  AT_PASS_ADD_INDEX, /* ADD indexes */
160  AT_PASS_ADD_OTHERCONSTR, /* ADD other constraints, defaults */
161  AT_PASS_MISC, /* other stuff */
163 
164 #define AT_NUM_PASSES (AT_PASS_MISC + 1)
165 
166 typedef struct AlteredTableInfo
167 {
168  /* Information saved before any work commences: */
169  Oid relid; /* Relation to work on */
170  char relkind; /* Its relkind */
171  TupleDesc oldDesc; /* Pre-modification tuple descriptor */
172 
173  /*
174  * Transiently set during Phase 2, normally set to NULL.
175  *
176  * ATRewriteCatalogs sets this when it starts, and closes when ATExecCmd
177  * returns control. This can be exploited by ATExecCmd subroutines to
178  * close/reopen across transaction boundaries.
179  */
181 
182  /* Information saved by Phase 1 for Phase 2: */
183  List *subcmds[AT_NUM_PASSES]; /* Lists of AlterTableCmd */
184  /* Information saved by Phases 1/2 for Phase 3: */
185  List *constraints; /* List of NewConstraint */
186  List *newvals; /* List of NewColumnValue */
187  List *afterStmts; /* List of utility command parsetrees */
188  bool verify_new_notnull; /* T if we should recheck NOT NULL */
189  int rewrite; /* Reason for forced rewrite, if any */
190  bool chgAccessMethod; /* T if SET ACCESS METHOD is used */
191  Oid newAccessMethod; /* new access method; 0 means no change,
192  * if above is true */
193  Oid newTableSpace; /* new tablespace; 0 means no change */
194  bool chgPersistence; /* T if SET LOGGED/UNLOGGED is used */
195  char newrelpersistence; /* if above is true */
196  Expr *partition_constraint; /* for attach partition validation */
197  /* true, if validating default due to some other attach/detach */
199  /* Objects to rebuild after completing ALTER TYPE operations */
200  List *changedConstraintOids; /* OIDs of constraints to rebuild */
201  List *changedConstraintDefs; /* string definitions of same */
202  List *changedIndexOids; /* OIDs of indexes to rebuild */
203  List *changedIndexDefs; /* string definitions of same */
204  char *replicaIdentityIndex; /* index to reset as REPLICA IDENTITY */
205  char *clusterOnIndex; /* index to use for CLUSTER */
206  List *changedStatisticsOids; /* OIDs of statistics to rebuild */
207  List *changedStatisticsDefs; /* string definitions of same */
209 
210 /* Struct describing one new constraint to check in Phase 3 scan */
211 /* Note: new not-null constraints are handled elsewhere */
212 typedef struct NewConstraint
213 {
214  char *name; /* Constraint name, or NULL if none */
215  ConstrType contype; /* CHECK or FOREIGN */
216  Oid refrelid; /* PK rel, if FOREIGN */
217  Oid refindid; /* OID of PK's index, if FOREIGN */
218  Oid conid; /* OID of pg_constraint entry, if FOREIGN */
219  Node *qual; /* Check expr or CONSTR_FOREIGN Constraint */
220  ExprState *qualstate; /* Execution state for CHECK expr */
222 
223 /*
224  * Struct describing one new column value that needs to be computed during
225  * Phase 3 copy (this could be either a new column with a non-null default, or
226  * a column that we're changing the type of). Columns without such an entry
227  * are just copied from the old table during ATRewriteTable. Note that the
228  * expr is an expression over *old* table values, except when is_generated
229  * is true; then it is an expression over columns of the *new* tuple.
230  */
231 typedef struct NewColumnValue
232 {
233  AttrNumber attnum; /* which column */
234  Expr *expr; /* expression to compute */
235  ExprState *exprstate; /* execution state */
236  bool is_generated; /* is it a GENERATED expression? */
238 
239 /*
240  * Error-reporting support for RemoveRelations
241  */
243 {
244  char kind;
246  const char *nonexistent_msg;
247  const char *skipping_msg;
248  const char *nota_msg;
249  const char *drophint_msg;
250 };
251 
252 static const struct dropmsgstrings dropmsgstringarray[] = {
253  {RELKIND_RELATION,
255  gettext_noop("table \"%s\" does not exist"),
256  gettext_noop("table \"%s\" does not exist, skipping"),
257  gettext_noop("\"%s\" is not a table"),
258  gettext_noop("Use DROP TABLE to remove a table.")},
259  {RELKIND_SEQUENCE,
261  gettext_noop("sequence \"%s\" does not exist"),
262  gettext_noop("sequence \"%s\" does not exist, skipping"),
263  gettext_noop("\"%s\" is not a sequence"),
264  gettext_noop("Use DROP SEQUENCE to remove a sequence.")},
265  {RELKIND_VIEW,
267  gettext_noop("view \"%s\" does not exist"),
268  gettext_noop("view \"%s\" does not exist, skipping"),
269  gettext_noop("\"%s\" is not a view"),
270  gettext_noop("Use DROP VIEW to remove a view.")},
271  {RELKIND_MATVIEW,
273  gettext_noop("materialized view \"%s\" does not exist"),
274  gettext_noop("materialized view \"%s\" does not exist, skipping"),
275  gettext_noop("\"%s\" is not a materialized view"),
276  gettext_noop("Use DROP MATERIALIZED VIEW to remove a materialized view.")},
277  {RELKIND_INDEX,
278  ERRCODE_UNDEFINED_OBJECT,
279  gettext_noop("index \"%s\" does not exist"),
280  gettext_noop("index \"%s\" does not exist, skipping"),
281  gettext_noop("\"%s\" is not an index"),
282  gettext_noop("Use DROP INDEX to remove an index.")},
283  {RELKIND_COMPOSITE_TYPE,
284  ERRCODE_UNDEFINED_OBJECT,
285  gettext_noop("type \"%s\" does not exist"),
286  gettext_noop("type \"%s\" does not exist, skipping"),
287  gettext_noop("\"%s\" is not a type"),
288  gettext_noop("Use DROP TYPE to remove a type.")},
289  {RELKIND_FOREIGN_TABLE,
290  ERRCODE_UNDEFINED_OBJECT,
291  gettext_noop("foreign table \"%s\" does not exist"),
292  gettext_noop("foreign table \"%s\" does not exist, skipping"),
293  gettext_noop("\"%s\" is not a foreign table"),
294  gettext_noop("Use DROP FOREIGN TABLE to remove a foreign table.")},
295  {RELKIND_PARTITIONED_TABLE,
297  gettext_noop("table \"%s\" does not exist"),
298  gettext_noop("table \"%s\" does not exist, skipping"),
299  gettext_noop("\"%s\" is not a table"),
300  gettext_noop("Use DROP TABLE to remove a table.")},
301  {RELKIND_PARTITIONED_INDEX,
302  ERRCODE_UNDEFINED_OBJECT,
303  gettext_noop("index \"%s\" does not exist"),
304  gettext_noop("index \"%s\" does not exist, skipping"),
305  gettext_noop("\"%s\" is not an index"),
306  gettext_noop("Use DROP INDEX to remove an index.")},
307  {'\0', 0, NULL, NULL, NULL, NULL}
308 };
309 
310 /* communication between RemoveRelations and RangeVarCallbackForDropRelation */
312 {
313  /* These fields are set by RemoveRelations: */
316  /* These fields are state to track which subsidiary locks are held: */
319  /* These fields are passed back by RangeVarCallbackForDropRelation: */
322 };
323 
324 /* Alter table target-type flags for ATSimplePermissions */
325 #define ATT_TABLE 0x0001
326 #define ATT_VIEW 0x0002
327 #define ATT_MATVIEW 0x0004
328 #define ATT_INDEX 0x0008
329 #define ATT_COMPOSITE_TYPE 0x0010
330 #define ATT_FOREIGN_TABLE 0x0020
331 #define ATT_PARTITIONED_INDEX 0x0040
332 #define ATT_SEQUENCE 0x0080
333 
334 /*
335  * ForeignTruncateInfo
336  *
337  * Information related to truncation of foreign tables. This is used for
338  * the elements in a hash table. It uses the server OID as lookup key,
339  * and includes a per-server list of all foreign tables involved in the
340  * truncation.
341  */
342 typedef struct ForeignTruncateInfo
343 {
347 
348 /*
349  * Partition tables are expected to be dropped when the parent partitioned
350  * table gets dropped. Hence for partitioning we use AUTO dependency.
351  * Otherwise, for regular inheritance use NORMAL dependency.
352  */
353 #define child_dependency_type(child_is_partition) \
354  ((child_is_partition) ? DEPENDENCY_AUTO : DEPENDENCY_NORMAL)
355 
356 static void truncate_check_rel(Oid relid, Form_pg_class reltuple);
357 static void truncate_check_perms(Oid relid, Form_pg_class reltuple);
358 static void truncate_check_activity(Relation rel);
359 static void RangeVarCallbackForTruncate(const RangeVar *relation,
360  Oid relId, Oid oldRelId, void *arg);
361 static List *MergeAttributes(List *columns, const List *supers, char relpersistence,
362  bool is_partition, List **supconstr);
363 static List *MergeCheckConstraint(List *constraints, const char *name, Node *expr);
364 static void MergeChildAttribute(List *inh_columns, int exist_attno, int newcol_attno, const ColumnDef *newdef);
365 static ColumnDef *MergeInheritedAttribute(List *inh_columns, int exist_attno, const ColumnDef *newdef);
366 static void MergeAttributesIntoExisting(Relation child_rel, Relation parent_rel, bool ispartition);
367 static void MergeConstraintsIntoExisting(Relation child_rel, Relation parent_rel);
368 static void StoreCatalogInheritance(Oid relationId, List *supers,
369  bool child_is_partition);
370 static void StoreCatalogInheritance1(Oid relationId, Oid parentOid,
371  int32 seqNumber, Relation inhRelation,
372  bool child_is_partition);
373 static int findAttrByName(const char *attributeName, const List *columns);
374 static void AlterIndexNamespaces(Relation classRel, Relation rel,
375  Oid oldNspOid, Oid newNspOid, ObjectAddresses *objsMoved);
376 static void AlterSeqNamespaces(Relation classRel, Relation rel,
377  Oid oldNspOid, Oid newNspOid, ObjectAddresses *objsMoved,
378  LOCKMODE lockmode);
380  bool recurse, bool recursing, LOCKMODE lockmode);
381 static bool ATExecAlterConstrRecurse(Constraint *cmdcon, Relation conrel, Relation tgrel,
382  Relation rel, HeapTuple contuple, List **otherrelids,
383  LOCKMODE lockmode);
385  Relation rel, char *constrName,
386  bool recurse, bool recursing, LOCKMODE lockmode);
387 static int transformColumnNameList(Oid relId, List *colList,
388  int16 *attnums, Oid *atttypids);
389 static int transformFkeyGetPrimaryKey(Relation pkrel, Oid *indexOid,
390  List **attnamelist,
391  int16 *attnums, Oid *atttypids,
392  Oid *opclasses);
394  int numattrs, int16 *attnums,
395  Oid *opclasses);
396 static void checkFkeyPermissions(Relation rel, int16 *attnums, int natts);
397 static CoercionPathType findFkeyCast(Oid targetTypeId, Oid sourceTypeId,
398  Oid *funcid);
399 static void validateForeignKeyConstraint(char *conname,
400  Relation rel, Relation pkrel,
401  Oid pkindOid, Oid constraintOid);
402 static void CheckAlterTableIsSafe(Relation rel);
403 static void ATController(AlterTableStmt *parsetree,
404  Relation rel, List *cmds, bool recurse, LOCKMODE lockmode,
406 static void ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd,
407  bool recurse, bool recursing, LOCKMODE lockmode,
409 static void ATRewriteCatalogs(List **wqueue, LOCKMODE lockmode,
411 static void ATExecCmd(List **wqueue, AlteredTableInfo *tab,
412  AlterTableCmd *cmd, LOCKMODE lockmode, AlterTablePass cur_pass,
415  Relation rel, AlterTableCmd *cmd,
416  bool recurse, LOCKMODE lockmode,
417  AlterTablePass cur_pass,
419 static void ATRewriteTables(AlterTableStmt *parsetree,
420  List **wqueue, LOCKMODE lockmode,
422 static void ATRewriteTable(AlteredTableInfo *tab, Oid OIDNewHeap, LOCKMODE lockmode);
423 static AlteredTableInfo *ATGetQueueEntry(List **wqueue, Relation rel);
424 static void ATSimplePermissions(AlterTableType cmdtype, Relation rel, int allowed_targets);
425 static void ATSimpleRecursion(List **wqueue, Relation rel,
426  AlterTableCmd *cmd, bool recurse, LOCKMODE lockmode,
428 static void ATCheckPartitionsNotInUse(Relation rel, LOCKMODE lockmode);
429 static void ATTypedTableRecursion(List **wqueue, Relation rel, AlterTableCmd *cmd,
430  LOCKMODE lockmode,
432 static List *find_typed_table_dependencies(Oid typeOid, const char *typeName,
433  DropBehavior behavior);
434 static void ATPrepAddColumn(List **wqueue, Relation rel, bool recurse, bool recursing,
435  bool is_view, AlterTableCmd *cmd, LOCKMODE lockmode,
437 static ObjectAddress ATExecAddColumn(List **wqueue, AlteredTableInfo *tab,
438  Relation rel, AlterTableCmd **cmd,
439  bool recurse, bool recursing,
440  LOCKMODE lockmode, AlterTablePass cur_pass,
442 static bool check_for_column_name_collision(Relation rel, const char *colname,
443  bool if_not_exists);
444 static void add_column_datatype_dependency(Oid relid, int32 attnum, Oid typid);
446 static void ATPrepDropNotNull(Relation rel, bool recurse, bool recursing);
447 static ObjectAddress ATExecDropNotNull(Relation rel, const char *colName, LOCKMODE lockmode);
448 static void ATPrepSetNotNull(List **wqueue, Relation rel,
449  AlterTableCmd *cmd, bool recurse, bool recursing,
450  LOCKMODE lockmode,
453  const char *colName, LOCKMODE lockmode);
454 static void ATExecCheckNotNull(AlteredTableInfo *tab, Relation rel,
455  const char *colName, LOCKMODE lockmode);
457 static bool ConstraintImpliedByRelConstraint(Relation scanrel,
458  List *testConstraint, List *provenConstraint);
459 static ObjectAddress ATExecColumnDefault(Relation rel, const char *colName,
460  Node *newDefault, LOCKMODE lockmode);
462  Node *newDefault);
463 static ObjectAddress ATExecAddIdentity(Relation rel, const char *colName,
464  Node *def, LOCKMODE lockmode, bool recurse, bool recursing);
465 static ObjectAddress ATExecSetIdentity(Relation rel, const char *colName,
466  Node *def, LOCKMODE lockmode, bool recurse, bool recursing);
467 static ObjectAddress ATExecDropIdentity(Relation rel, const char *colName, bool missing_ok, LOCKMODE lockmode,
468  bool recurse, bool recursing);
469 static ObjectAddress ATExecSetExpression(AlteredTableInfo *tab, Relation rel, const char *colName,
470  Node *newExpr, LOCKMODE lockmode);
471 static void ATPrepDropExpression(Relation rel, AlterTableCmd *cmd, bool recurse, bool recursing, LOCKMODE lockmode);
472 static ObjectAddress ATExecDropExpression(Relation rel, const char *colName, bool missing_ok, LOCKMODE lockmode);
473 static ObjectAddress ATExecSetStatistics(Relation rel, const char *colName, int16 colNum,
474  Node *newValue, LOCKMODE lockmode);
475 static ObjectAddress ATExecSetOptions(Relation rel, const char *colName,
476  Node *options, bool isReset, LOCKMODE lockmode);
477 static ObjectAddress ATExecSetStorage(Relation rel, const char *colName,
478  Node *newValue, LOCKMODE lockmode);
479 static void ATPrepDropColumn(List **wqueue, Relation rel, bool recurse, bool recursing,
480  AlterTableCmd *cmd, LOCKMODE lockmode,
482 static ObjectAddress ATExecDropColumn(List **wqueue, Relation rel, const char *colName,
483  DropBehavior behavior,
484  bool recurse, bool recursing,
485  bool missing_ok, LOCKMODE lockmode,
486  ObjectAddresses *addrs);
488  IndexStmt *stmt, bool is_rebuild, LOCKMODE lockmode);
490  CreateStatsStmt *stmt, bool is_rebuild, LOCKMODE lockmode);
491 static ObjectAddress ATExecAddConstraint(List **wqueue,
492  AlteredTableInfo *tab, Relation rel,
493  Constraint *newConstraint, bool recurse, bool is_readd,
494  LOCKMODE lockmode);
495 static char *ChooseForeignKeyConstraintNameAddition(List *colnames);
497  IndexStmt *stmt, LOCKMODE lockmode);
498 static ObjectAddress ATAddCheckConstraint(List **wqueue,
499  AlteredTableInfo *tab, Relation rel,
500  Constraint *constr,
501  bool recurse, bool recursing, bool is_readd,
502  LOCKMODE lockmode);
504  Relation rel, Constraint *fkconstraint,
505  bool recurse, bool recursing,
506  LOCKMODE lockmode);
507 static ObjectAddress addFkRecurseReferenced(List **wqueue, Constraint *fkconstraint,
508  Relation rel, Relation pkrel, Oid indexOid, Oid parentConstr,
509  int numfks, int16 *pkattnum, int16 *fkattnum,
510  Oid *pfeqoperators, Oid *ppeqoperators, Oid *ffeqoperators,
511  int numfkdelsetcols, int16 *fkdelsetcols,
512  bool old_check_ok,
513  Oid parentDelTrigger, Oid parentUpdTrigger);
514 static void validateFkOnDeleteSetColumns(int numfks, const int16 *fkattnums,
515  int numfksetcols, const int16 *fksetcolsattnums,
516  List *fksetcols);
517 static void addFkRecurseReferencing(List **wqueue, Constraint *fkconstraint,
518  Relation rel, Relation pkrel, Oid indexOid, Oid parentConstr,
519  int numfks, int16 *pkattnum, int16 *fkattnum,
520  Oid *pfeqoperators, Oid *ppeqoperators, Oid *ffeqoperators,
521  int numfkdelsetcols, int16 *fkdelsetcols,
522  bool old_check_ok, LOCKMODE lockmode,
523  Oid parentInsTrigger, Oid parentUpdTrigger);
524 static void CloneForeignKeyConstraints(List **wqueue, Relation parentRel,
525  Relation partitionRel);
526 static void CloneFkReferenced(Relation parentRel, Relation partitionRel);
527 static void CloneFkReferencing(List **wqueue, Relation parentRel,
528  Relation partRel);
529 static void createForeignKeyCheckTriggers(Oid myRelOid, Oid refRelOid,
530  Constraint *fkconstraint, Oid constraintOid,
531  Oid indexOid,
532  Oid parentInsTrigger, Oid parentUpdTrigger,
533  Oid *insertTrigOid, Oid *updateTrigOid);
534 static void createForeignKeyActionTriggers(Relation rel, Oid refRelOid,
535  Constraint *fkconstraint, Oid constraintOid,
536  Oid indexOid,
537  Oid parentDelTrigger, Oid parentUpdTrigger,
538  Oid *deleteTrigOid, Oid *updateTrigOid);
540  Oid partRelid,
541  Oid parentConstrOid, int numfks,
542  AttrNumber *mapped_conkey, AttrNumber *confkey,
543  Oid *conpfeqop,
544  Oid parentInsTrigger,
545  Oid parentUpdTrigger,
546  Relation trigrel);
547 static void GetForeignKeyActionTriggers(Relation trigrel,
548  Oid conoid, Oid confrelid, Oid conrelid,
549  Oid *deleteTriggerOid,
550  Oid *updateTriggerOid);
551 static void GetForeignKeyCheckTriggers(Relation trigrel,
552  Oid conoid, Oid confrelid, Oid conrelid,
553  Oid *insertTriggerOid,
554  Oid *updateTriggerOid);
555 static void ATExecDropConstraint(Relation rel, const char *constrName,
556  DropBehavior behavior,
557  bool recurse, bool recursing,
558  bool missing_ok, LOCKMODE lockmode);
559 static void ATPrepAlterColumnType(List **wqueue,
560  AlteredTableInfo *tab, Relation rel,
561  bool recurse, bool recursing,
562  AlterTableCmd *cmd, LOCKMODE lockmode,
564 static bool ATColumnChangeRequiresRewrite(Node *expr, AttrNumber varattno);
566  AlterTableCmd *cmd, LOCKMODE lockmode);
568  Relation rel, AttrNumber attnum, const char *colName);
569 static void RememberConstraintForRebuilding(Oid conoid, AlteredTableInfo *tab);
570 static void RememberIndexForRebuilding(Oid indoid, AlteredTableInfo *tab);
571 static void RememberStatisticsForRebuilding(Oid stxoid, AlteredTableInfo *tab);
572 static void ATPostAlterTypeCleanup(List **wqueue, AlteredTableInfo *tab,
573  LOCKMODE lockmode);
574 static void ATPostAlterTypeParse(Oid oldId, Oid oldRelId, Oid refRelId,
575  char *cmd, List **wqueue, LOCKMODE lockmode,
576  bool rewrite);
578  Oid objid, Relation rel, List *domname,
579  const char *conname);
580 static void TryReuseIndex(Oid oldId, IndexStmt *stmt);
581 static void TryReuseForeignKey(Oid oldId, Constraint *con);
582 static ObjectAddress ATExecAlterColumnGenericOptions(Relation rel, const char *colName,
583  List *options, LOCKMODE lockmode);
584 static void change_owner_fix_column_acls(Oid relationOid,
585  Oid oldOwnerId, Oid newOwnerId);
586 static void change_owner_recurse_to_sequences(Oid relationOid,
587  Oid newOwnerId, LOCKMODE lockmode);
588 static ObjectAddress ATExecClusterOn(Relation rel, const char *indexName,
589  LOCKMODE lockmode);
590 static void ATExecDropCluster(Relation rel, LOCKMODE lockmode);
591 static void ATPrepSetAccessMethod(AlteredTableInfo *tab, Relation rel, const char *amname);
592 static void ATExecSetAccessMethodNoStorage(Relation rel, Oid newAccessMethodId);
593 static bool ATPrepChangePersistence(Relation rel, bool toLogged);
594 static void ATPrepSetTableSpace(AlteredTableInfo *tab, Relation rel,
595  const char *tablespacename, LOCKMODE lockmode);
596 static void ATExecSetTableSpace(Oid tableOid, Oid newTableSpace, LOCKMODE lockmode);
597 static void ATExecSetTableSpaceNoStorage(Relation rel, Oid newTableSpace);
598 static void ATExecSetRelOptions(Relation rel, List *defList,
599  AlterTableType operation,
600  LOCKMODE lockmode);
601 static void ATExecEnableDisableTrigger(Relation rel, const char *trigname,
602  char fires_when, bool skip_system, bool recurse,
603  LOCKMODE lockmode);
604 static void ATExecEnableDisableRule(Relation rel, const char *rulename,
605  char fires_when, LOCKMODE lockmode);
606 static void ATPrepAddInherit(Relation child_rel);
607 static ObjectAddress ATExecAddInherit(Relation child_rel, RangeVar *parent, LOCKMODE lockmode);
608 static ObjectAddress ATExecDropInherit(Relation rel, RangeVar *parent, LOCKMODE lockmode);
609 static void drop_parent_dependency(Oid relid, Oid refclassid, Oid refobjid,
610  DependencyType deptype);
611 static ObjectAddress ATExecAddOf(Relation rel, const TypeName *ofTypename, LOCKMODE lockmode);
612 static void ATExecDropOf(Relation rel, LOCKMODE lockmode);
613 static void ATExecReplicaIdentity(Relation rel, ReplicaIdentityStmt *stmt, LOCKMODE lockmode);
614 static void ATExecGenericOptions(Relation rel, List *options);
615 static void ATExecSetRowSecurity(Relation rel, bool rls);
616 static void ATExecForceNoForceRowSecurity(Relation rel, bool force_rls);
618  const char *column, Node *newValue, LOCKMODE lockmode);
619 
620 static void index_copy_data(Relation rel, RelFileLocator newrlocator);
621 static const char *storage_name(char c);
622 
623 static void RangeVarCallbackForDropRelation(const RangeVar *rel, Oid relOid,
624  Oid oldRelOid, void *arg);
625 static void RangeVarCallbackForAlterRelation(const RangeVar *rv, Oid relid,
626  Oid oldrelid, void *arg);
628 static void ComputePartitionAttrs(ParseState *pstate, Relation rel, List *partParams, AttrNumber *partattrs,
629  List **partexprs, Oid *partopclass, Oid *partcollation,
630  PartitionStrategy strategy);
631 static void CreateInheritance(Relation child_rel, Relation parent_rel, bool ispartition);
632 static void RemoveInheritance(Relation child_rel, Relation parent_rel,
633  bool expect_detached);
634 static ObjectAddress ATExecAttachPartition(List **wqueue, Relation rel,
635  PartitionCmd *cmd,
637 static void AttachPartitionEnsureIndexes(List **wqueue, Relation rel, Relation attachrel);
638 static void QueuePartitionConstraintValidation(List **wqueue, Relation scanrel,
639  List *partConstraint,
640  bool validate_default);
641 static void CloneRowTriggersToPartition(Relation parent, Relation partition);
642 static void DetachAddConstraintIfNeeded(List **wqueue, Relation partRel);
643 static void DropClonedTriggersFromPartition(Oid partitionId);
645  Relation rel, RangeVar *name,
646  bool concurrent);
647 static void DetachPartitionFinalize(Relation rel, Relation partRel,
648  bool concurrent, Oid defaultPartOid);
650 static ObjectAddress ATExecAttachPartitionIdx(List **wqueue, Relation parentIdx,
651  RangeVar *name);
652 static void validatePartitionedIndex(Relation partedIdx, Relation partedTbl);
653 static void refuseDupeIndexAttach(Relation parentIdx, Relation partIdx,
654  Relation partitionTbl);
655 static List *GetParentedForeignKeyRefs(Relation partition);
656 static void ATDetachCheckNoForeignKeyRefs(Relation partition);
657 static char GetAttributeCompression(Oid atttypid, const char *compression);
658 static char GetAttributeStorage(Oid atttypid, const char *storagemode);
659 
660 static void ATExecSplitPartition(List **wqueue, AlteredTableInfo *tab,
661  Relation rel, PartitionCmd *cmd,
663 static void ATExecMergePartitions(List **wqueue, AlteredTableInfo *tab, Relation rel,
665 
666 /* ----------------------------------------------------------------
667  * DefineRelation
668  * Creates a new relation.
669  *
670  * stmt carries parsetree information from an ordinary CREATE TABLE statement.
671  * The other arguments are used to extend the behavior for other cases:
672  * relkind: relkind to assign to the new relation
673  * ownerId: if not InvalidOid, use this as the new relation's owner.
674  * typaddress: if not null, it's set to the pg_type entry's address.
675  * queryString: for error reporting
676  *
677  * Note that permissions checks are done against current user regardless of
678  * ownerId. A nonzero ownerId is used when someone is creating a relation
679  * "on behalf of" someone else, so we still want to see that the current user
680  * has permissions to do it.
681  *
682  * If successful, returns the address of the new relation.
683  * ----------------------------------------------------------------
684  */
686 DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId,
687  ObjectAddress *typaddress, const char *queryString)
688 {
689  char relname[NAMEDATALEN];
690  Oid namespaceId;
691  Oid relationId;
692  Oid tablespaceId;
693  Relation rel;
695  List *inheritOids;
696  List *old_constraints;
697  List *rawDefaults;
698  List *cookedDefaults;
699  Datum reloptions;
700  ListCell *listptr;
702  bool partitioned;
703  static char *validnsps[] = HEAP_RELOPT_NAMESPACES;
704  Oid ofTypeId;
705  ObjectAddress address;
706  LOCKMODE parentLockmode;
707  Oid accessMethodId = InvalidOid;
708 
709  /*
710  * Truncate relname to appropriate length (probably a waste of time, as
711  * parser should have done this already).
712  */
713  strlcpy(relname, stmt->relation->relname, NAMEDATALEN);
714 
715  /*
716  * Check consistency of arguments
717  */
718  if (stmt->oncommit != ONCOMMIT_NOOP
719  && stmt->relation->relpersistence != RELPERSISTENCE_TEMP)
720  ereport(ERROR,
721  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
722  errmsg("ON COMMIT can only be used on temporary tables")));
723 
724  if (stmt->partspec != NULL)
725  {
726  if (relkind != RELKIND_RELATION)
727  elog(ERROR, "unexpected relkind: %d", (int) relkind);
728 
729  relkind = RELKIND_PARTITIONED_TABLE;
730  partitioned = true;
731  }
732  else
733  partitioned = false;
734 
735  /*
736  * Look up the namespace in which we are supposed to create the relation,
737  * check we have permission to create there, lock it against concurrent
738  * drop, and mark stmt->relation as RELPERSISTENCE_TEMP if a temporary
739  * namespace is selected.
740  */
741  namespaceId =
743 
744  /*
745  * Security check: disallow creating temp tables from security-restricted
746  * code. This is needed because calling code might not expect untrusted
747  * tables to appear in pg_temp at the front of its search path.
748  */
749  if (stmt->relation->relpersistence == RELPERSISTENCE_TEMP
751  ereport(ERROR,
752  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
753  errmsg("cannot create temporary table within security-restricted operation")));
754 
755  /*
756  * Determine the lockmode to use when scanning parents. A self-exclusive
757  * lock is needed here.
758  *
759  * For regular inheritance, if two backends attempt to add children to the
760  * same parent simultaneously, and that parent has no pre-existing
761  * children, then both will attempt to update the parent's relhassubclass
762  * field, leading to a "tuple concurrently updated" error. Also, this
763  * interlocks against a concurrent ANALYZE on the parent table, which
764  * might otherwise be attempting to clear the parent's relhassubclass
765  * field, if its previous children were recently dropped.
766  *
767  * If the child table is a partition, then we instead grab an exclusive
768  * lock on the parent because its partition descriptor will be changed by
769  * addition of the new partition.
770  */
771  parentLockmode = (stmt->partbound != NULL ? AccessExclusiveLock :
773 
774  /* Determine the list of OIDs of the parents. */
775  inheritOids = NIL;
776  foreach(listptr, stmt->inhRelations)
777  {
778  RangeVar *rv = (RangeVar *) lfirst(listptr);
779  Oid parentOid;
780 
781  parentOid = RangeVarGetRelid(rv, parentLockmode, false);
782 
783  /*
784  * Reject duplications in the list of parents.
785  */
786  if (list_member_oid(inheritOids, parentOid))
787  ereport(ERROR,
788  (errcode(ERRCODE_DUPLICATE_TABLE),
789  errmsg("relation \"%s\" would be inherited from more than once",
790  get_rel_name(parentOid))));
791 
792  inheritOids = lappend_oid(inheritOids, parentOid);
793  }
794 
795  /*
796  * Select tablespace to use: an explicitly indicated one, or (in the case
797  * of a partitioned table) the parent's, if it has one.
798  */
799  if (stmt->tablespacename)
800  {
801  tablespaceId = get_tablespace_oid(stmt->tablespacename, false);
802 
803  if (partitioned && tablespaceId == MyDatabaseTableSpace)
804  ereport(ERROR,
805  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
806  errmsg("cannot specify default tablespace for partitioned relations")));
807  }
808  else if (stmt->partbound)
809  {
810  Assert(list_length(inheritOids) == 1);
811  tablespaceId = get_rel_tablespace(linitial_oid(inheritOids));
812  }
813  else
814  tablespaceId = InvalidOid;
815 
816  /* still nothing? use the default */
817  if (!OidIsValid(tablespaceId))
818  tablespaceId = GetDefaultTablespace(stmt->relation->relpersistence,
819  partitioned);
820 
821  /* Check permissions except when using database's default */
822  if (OidIsValid(tablespaceId) && tablespaceId != MyDatabaseTableSpace)
823  {
824  AclResult aclresult;
825 
826  aclresult = object_aclcheck(TableSpaceRelationId, tablespaceId, GetUserId(),
827  ACL_CREATE);
828  if (aclresult != ACLCHECK_OK)
830  get_tablespace_name(tablespaceId));
831  }
832 
833  /* In all cases disallow placing user relations in pg_global */
834  if (tablespaceId == GLOBALTABLESPACE_OID)
835  ereport(ERROR,
836  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
837  errmsg("only shared relations can be placed in pg_global tablespace")));
838 
839  /* Identify user ID that will own the table */
840  if (!OidIsValid(ownerId))
841  ownerId = GetUserId();
842 
843  /*
844  * Parse and validate reloptions, if any.
845  */
846  reloptions = transformRelOptions((Datum) 0, stmt->options, NULL, validnsps,
847  true, false);
848 
849  switch (relkind)
850  {
851  case RELKIND_VIEW:
852  (void) view_reloptions(reloptions, true);
853  break;
854  case RELKIND_PARTITIONED_TABLE:
855  (void) partitioned_table_reloptions(reloptions, true);
856  break;
857  default:
858  (void) heap_reloptions(relkind, reloptions, true);
859  }
860 
861  if (stmt->ofTypename)
862  {
863  AclResult aclresult;
864 
865  ofTypeId = typenameTypeId(NULL, stmt->ofTypename);
866 
867  aclresult = object_aclcheck(TypeRelationId, ofTypeId, GetUserId(), ACL_USAGE);
868  if (aclresult != ACLCHECK_OK)
869  aclcheck_error_type(aclresult, ofTypeId);
870  }
871  else
872  ofTypeId = InvalidOid;
873 
874  /*
875  * Look up inheritance ancestors and generate relation schema, including
876  * inherited attributes. (Note that stmt->tableElts is destructively
877  * modified by MergeAttributes.)
878  */
879  stmt->tableElts =
880  MergeAttributes(stmt->tableElts, inheritOids,
881  stmt->relation->relpersistence,
882  stmt->partbound != NULL,
883  &old_constraints);
884 
885  /*
886  * Create a tuple descriptor from the relation schema. Note that this
887  * deals with column names, types, and not-null constraints, but not
888  * default values or CHECK constraints; we handle those below.
889  */
890  descriptor = BuildDescForRelation(stmt->tableElts);
891 
892  /*
893  * Find columns with default values and prepare for insertion of the
894  * defaults. Pre-cooked (that is, inherited) defaults go into a list of
895  * CookedConstraint structs that we'll pass to heap_create_with_catalog,
896  * while raw defaults go into a list of RawColumnDefault structs that will
897  * be processed by AddRelationNewConstraints. (We can't deal with raw
898  * expressions until we can do transformExpr.)
899  *
900  * We can set the atthasdef flags now in the tuple descriptor; this just
901  * saves StoreAttrDefault from having to do an immediate update of the
902  * pg_attribute rows.
903  */
904  rawDefaults = NIL;
905  cookedDefaults = NIL;
906  attnum = 0;
907 
908  foreach(listptr, stmt->tableElts)
909  {
910  ColumnDef *colDef = lfirst(listptr);
911  Form_pg_attribute attr;
912 
913  attnum++;
914  attr = TupleDescAttr(descriptor, attnum - 1);
915 
916  if (colDef->raw_default != NULL)
917  {
918  RawColumnDefault *rawEnt;
919 
920  Assert(colDef->cooked_default == NULL);
921 
922  rawEnt = (RawColumnDefault *) palloc(sizeof(RawColumnDefault));
923  rawEnt->attnum = attnum;
924  rawEnt->raw_default = colDef->raw_default;
925  rawEnt->missingMode = false;
926  rawEnt->generated = colDef->generated;
927  rawDefaults = lappend(rawDefaults, rawEnt);
928  attr->atthasdef = true;
929  }
930  else if (colDef->cooked_default != NULL)
931  {
932  CookedConstraint *cooked;
933 
934  cooked = (CookedConstraint *) palloc(sizeof(CookedConstraint));
935  cooked->contype = CONSTR_DEFAULT;
936  cooked->conoid = InvalidOid; /* until created */
937  cooked->name = NULL;
938  cooked->attnum = attnum;
939  cooked->expr = colDef->cooked_default;
940  cooked->skip_validation = false;
941  cooked->is_local = true; /* not used for defaults */
942  cooked->inhcount = 0; /* ditto */
943  cooked->is_no_inherit = false;
944  cookedDefaults = lappend(cookedDefaults, cooked);
945  attr->atthasdef = true;
946  }
947  }
948 
949  /*
950  * For relations with table AM and partitioned tables, select access
951  * method to use: an explicitly indicated one, or (in the case of a
952  * partitioned table) the parent's, if it has one.
953  */
954  if (stmt->accessMethod != NULL)
955  {
956  Assert(RELKIND_HAS_TABLE_AM(relkind) || relkind == RELKIND_PARTITIONED_TABLE);
957  accessMethodId = get_table_am_oid(stmt->accessMethod, false);
958  }
959  else if (RELKIND_HAS_TABLE_AM(relkind) || relkind == RELKIND_PARTITIONED_TABLE)
960  {
961  if (stmt->partbound)
962  {
963  Assert(list_length(inheritOids) == 1);
964  accessMethodId = get_rel_relam(linitial_oid(inheritOids));
965  }
966 
967  if (RELKIND_HAS_TABLE_AM(relkind) && !OidIsValid(accessMethodId))
968  accessMethodId = get_table_am_oid(default_table_access_method, false);
969  }
970 
971  /*
972  * Create the relation. Inherited defaults and constraints are passed in
973  * for immediate handling --- since they don't need parsing, they can be
974  * stored immediately.
975  */
976  relationId = heap_create_with_catalog(relname,
977  namespaceId,
978  tablespaceId,
979  InvalidOid,
980  InvalidOid,
981  ofTypeId,
982  ownerId,
983  accessMethodId,
984  descriptor,
985  list_concat(cookedDefaults,
986  old_constraints),
987  relkind,
988  stmt->relation->relpersistence,
989  false,
990  false,
991  stmt->oncommit,
992  reloptions,
993  true,
995  false,
996  InvalidOid,
997  typaddress);
998 
999  /*
1000  * We must bump the command counter to make the newly-created relation
1001  * tuple visible for opening.
1002  */
1004 
1005  /*
1006  * Open the new relation and acquire exclusive lock on it. This isn't
1007  * really necessary for locking out other backends (since they can't see
1008  * the new rel anyway until we commit), but it keeps the lock manager from
1009  * complaining about deadlock risks.
1010  */
1011  rel = relation_open(relationId, AccessExclusiveLock);
1012 
1013  /*
1014  * Now add any newly specified column default and generation expressions
1015  * to the new relation. These are passed to us in the form of raw
1016  * parsetrees; we need to transform them to executable expression trees
1017  * before they can be added. The most convenient way to do that is to
1018  * apply the parser's transformExpr routine, but transformExpr doesn't
1019  * work unless we have a pre-existing relation. So, the transformation has
1020  * to be postponed to this final step of CREATE TABLE.
1021  *
1022  * This needs to be before processing the partitioning clauses because
1023  * those could refer to generated columns.
1024  */
1025  if (rawDefaults)
1026  AddRelationNewConstraints(rel, rawDefaults, NIL,
1027  true, true, false, queryString);
1028 
1029  /*
1030  * Make column generation expressions visible for use by partitioning.
1031  */
1033 
1034  /* Process and store partition bound, if any. */
1035  if (stmt->partbound)
1036  {
1037  PartitionBoundSpec *bound;
1038  ParseState *pstate;
1039  Oid parentId = linitial_oid(inheritOids),
1040  defaultPartOid;
1041  Relation parent,
1042  defaultRel = NULL;
1043  ParseNamespaceItem *nsitem;
1044 
1045  /* Already have strong enough lock on the parent */
1046  parent = table_open(parentId, NoLock);
1047 
1048  /*
1049  * We are going to try to validate the partition bound specification
1050  * against the partition key of parentRel, so it better have one.
1051  */
1052  if (parent->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
1053  ereport(ERROR,
1054  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1055  errmsg("\"%s\" is not partitioned",
1056  RelationGetRelationName(parent))));
1057 
1058  /*
1059  * The partition constraint of the default partition depends on the
1060  * partition bounds of every other partition. It is possible that
1061  * another backend might be about to execute a query on the default
1062  * partition table, and that the query relies on previously cached
1063  * default partition constraints. We must therefore take a table lock
1064  * strong enough to prevent all queries on the default partition from
1065  * proceeding until we commit and send out a shared-cache-inval notice
1066  * that will make them update their index lists.
1067  *
1068  * Order of locking: The relation being added won't be visible to
1069  * other backends until it is committed, hence here in
1070  * DefineRelation() the order of locking the default partition and the
1071  * relation being added does not matter. But at all other places we
1072  * need to lock the default relation before we lock the relation being
1073  * added or removed i.e. we should take the lock in same order at all
1074  * the places such that lock parent, lock default partition and then
1075  * lock the partition so as to avoid a deadlock.
1076  */
1077  defaultPartOid =
1079  true));
1080  if (OidIsValid(defaultPartOid))
1081  defaultRel = table_open(defaultPartOid, AccessExclusiveLock);
1082 
1083  /* Transform the bound values */
1084  pstate = make_parsestate(NULL);
1085  pstate->p_sourcetext = queryString;
1086 
1087  /*
1088  * Add an nsitem containing this relation, so that transformExpr
1089  * called on partition bound expressions is able to report errors
1090  * using a proper context.
1091  */
1092  nsitem = addRangeTableEntryForRelation(pstate, rel, AccessShareLock,
1093  NULL, false, false);
1094  addNSItemToQuery(pstate, nsitem, false, true, true);
1095 
1096  bound = transformPartitionBound(pstate, parent, stmt->partbound);
1097 
1098  /*
1099  * Check first that the new partition's bound is valid and does not
1100  * overlap with any of existing partitions of the parent.
1101  */
1102  check_new_partition_bound(relname, parent, bound, pstate);
1103 
1104  /*
1105  * If the default partition exists, its partition constraints will
1106  * change after the addition of this new partition such that it won't
1107  * allow any row that qualifies for this new partition. So, check that
1108  * the existing data in the default partition satisfies the constraint
1109  * as it will exist after adding this partition.
1110  */
1111  if (OidIsValid(defaultPartOid))
1112  {
1113  check_default_partition_contents(parent, defaultRel, bound);
1114  /* Keep the lock until commit. */
1115  table_close(defaultRel, NoLock);
1116  }
1117 
1118  /* Update the pg_class entry. */
1119  StorePartitionBound(rel, parent, bound);
1120 
1121  table_close(parent, NoLock);
1122  }
1123 
1124  /* Store inheritance information for new rel. */
1125  StoreCatalogInheritance(relationId, inheritOids, stmt->partbound != NULL);
1126 
1127  /*
1128  * Process the partitioning specification (if any) and store the partition
1129  * key information into the catalog.
1130  */
1131  if (partitioned)
1132  {
1133  ParseState *pstate;
1134  int partnatts;
1135  AttrNumber partattrs[PARTITION_MAX_KEYS];
1136  Oid partopclass[PARTITION_MAX_KEYS];
1137  Oid partcollation[PARTITION_MAX_KEYS];
1138  List *partexprs = NIL;
1139 
1140  pstate = make_parsestate(NULL);
1141  pstate->p_sourcetext = queryString;
1142 
1143  partnatts = list_length(stmt->partspec->partParams);
1144 
1145  /* Protect fixed-size arrays here and in executor */
1146  if (partnatts > PARTITION_MAX_KEYS)
1147  ereport(ERROR,
1148  (errcode(ERRCODE_TOO_MANY_COLUMNS),
1149  errmsg("cannot partition using more than %d columns",
1150  PARTITION_MAX_KEYS)));
1151 
1152  /*
1153  * We need to transform the raw parsetrees corresponding to partition
1154  * expressions into executable expression trees. Like column defaults
1155  * and CHECK constraints, we could not have done the transformation
1156  * earlier.
1157  */
1158  stmt->partspec = transformPartitionSpec(rel, stmt->partspec);
1159 
1160  ComputePartitionAttrs(pstate, rel, stmt->partspec->partParams,
1161  partattrs, &partexprs, partopclass,
1162  partcollation, stmt->partspec->strategy);
1163 
1164  StorePartitionKey(rel, stmt->partspec->strategy, partnatts, partattrs,
1165  partexprs,
1166  partopclass, partcollation);
1167 
1168  /* make it all visible */
1170  }
1171 
1172  /*
1173  * If we're creating a partition, create now all the indexes, triggers,
1174  * FKs defined in the parent.
1175  *
1176  * We can't do it earlier, because DefineIndex wants to know the partition
1177  * key which we just stored.
1178  */
1179  if (stmt->partbound)
1180  {
1181  Oid parentId = linitial_oid(inheritOids);
1182  Relation parent;
1183  List *idxlist;
1184  ListCell *cell;
1185 
1186  /* Already have strong enough lock on the parent */
1187  parent = table_open(parentId, NoLock);
1188  idxlist = RelationGetIndexList(parent);
1189 
1190  /*
1191  * For each index in the parent table, create one in the partition
1192  */
1193  foreach(cell, idxlist)
1194  {
1195  Relation idxRel = index_open(lfirst_oid(cell), AccessShareLock);
1196  AttrMap *attmap;
1197  IndexStmt *idxstmt;
1198  Oid constraintOid;
1199 
1200  if (rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
1201  {
1202  if (idxRel->rd_index->indisunique)
1203  ereport(ERROR,
1204  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1205  errmsg("cannot create foreign partition of partitioned table \"%s\"",
1206  RelationGetRelationName(parent)),
1207  errdetail("Table \"%s\" contains indexes that are unique.",
1208  RelationGetRelationName(parent))));
1209  else
1210  {
1211  index_close(idxRel, AccessShareLock);
1212  continue;
1213  }
1214  }
1215 
1217  RelationGetDescr(parent),
1218  false);
1219  idxstmt =
1220  generateClonedIndexStmt(NULL, idxRel,
1221  attmap, &constraintOid);
1223  idxstmt,
1224  InvalidOid,
1225  RelationGetRelid(idxRel),
1226  constraintOid,
1227  -1,
1228  false, false, false, false, false);
1229 
1230  index_close(idxRel, AccessShareLock);
1231  }
1232 
1233  list_free(idxlist);
1234 
1235  /*
1236  * If there are any row-level triggers, clone them to the new
1237  * partition.
1238  */
1239  if (parent->trigdesc != NULL)
1240  CloneRowTriggersToPartition(parent, rel);
1241 
1242  /*
1243  * And foreign keys too. Note that because we're freshly creating the
1244  * table, there is no need to verify these new constraints.
1245  */
1246  CloneForeignKeyConstraints(NULL, parent, rel);
1247 
1248  table_close(parent, NoLock);
1249  }
1250 
1251  /*
1252  * Now add any newly specified CHECK constraints to the new relation. Same
1253  * as for defaults above, but these need to come after partitioning is set
1254  * up.
1255  */
1256  if (stmt->constraints)
1257  AddRelationNewConstraints(rel, NIL, stmt->constraints,
1258  true, true, false, queryString);
1259 
1260  ObjectAddressSet(address, RelationRelationId, relationId);
1261 
1262  /*
1263  * Clean up. We keep lock on new relation (although it shouldn't be
1264  * visible to anyone else anyway, until commit).
1265  */
1266  relation_close(rel, NoLock);
1267 
1268  return address;
1269 }
1270 
1271 /*
1272  * BuildDescForRelation
1273  *
1274  * Given a list of ColumnDef nodes, build a TupleDesc.
1275  *
1276  * Note: This is only for the limited purpose of table and view creation. Not
1277  * everything is filled in. A real tuple descriptor should be obtained from
1278  * the relcache.
1279  */
1280 TupleDesc
1282 {
1283  int natts;
1285  ListCell *l;
1286  TupleDesc desc;
1287  char *attname;
1288  Oid atttypid;
1289  int32 atttypmod;
1290  Oid attcollation;
1291  int attdim;
1292 
1293  /*
1294  * allocate a new tuple descriptor
1295  */
1296  natts = list_length(columns);
1297  desc = CreateTemplateTupleDesc(natts);
1298 
1299  attnum = 0;
1300 
1301  foreach(l, columns)
1302  {
1303  ColumnDef *entry = lfirst(l);
1304  AclResult aclresult;
1305  Form_pg_attribute att;
1306 
1307  /*
1308  * for each entry in the list, get the name and type information from
1309  * the list and have TupleDescInitEntry fill in the attribute
1310  * information we need.
1311  */
1312  attnum++;
1313 
1314  attname = entry->colname;
1315  typenameTypeIdAndMod(NULL, entry->typeName, &atttypid, &atttypmod);
1316 
1317  aclresult = object_aclcheck(TypeRelationId, atttypid, GetUserId(), ACL_USAGE);
1318  if (aclresult != ACLCHECK_OK)
1319  aclcheck_error_type(aclresult, atttypid);
1320 
1321  attcollation = GetColumnDefCollation(NULL, entry, atttypid);
1322  attdim = list_length(entry->typeName->arrayBounds);
1323  if (attdim > PG_INT16_MAX)
1324  ereport(ERROR,
1325  errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
1326  errmsg("too many array dimensions"));
1327 
1328  if (entry->typeName->setof)
1329  ereport(ERROR,
1330  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
1331  errmsg("column \"%s\" cannot be declared SETOF",
1332  attname)));
1333 
1335  atttypid, atttypmod, attdim);
1336  att = TupleDescAttr(desc, attnum - 1);
1337 
1338  /* Override TupleDescInitEntry's settings as requested */
1339  TupleDescInitEntryCollation(desc, attnum, attcollation);
1340 
1341  /* Fill in additional stuff not handled by TupleDescInitEntry */
1342  att->attnotnull = entry->is_not_null;
1343  att->attislocal = entry->is_local;
1344  att->attinhcount = entry->inhcount;
1345  att->attidentity = entry->identity;
1346  att->attgenerated = entry->generated;
1347  att->attcompression = GetAttributeCompression(att->atttypid, entry->compression);
1348  if (entry->storage)
1349  att->attstorage = entry->storage;
1350  else if (entry->storage_name)
1351  att->attstorage = GetAttributeStorage(att->atttypid, entry->storage_name);
1352  }
1353 
1354  return desc;
1355 }
1356 
1357 /*
1358  * Emit the right error or warning message for a "DROP" command issued on a
1359  * non-existent relation
1360  */
1361 static void
1362 DropErrorMsgNonExistent(RangeVar *rel, char rightkind, bool missing_ok)
1363 {
1364  const struct dropmsgstrings *rentry;
1365 
1366  if (rel->schemaname != NULL &&
1368  {
1369  if (!missing_ok)
1370  {
1371  ereport(ERROR,
1372  (errcode(ERRCODE_UNDEFINED_SCHEMA),
1373  errmsg("schema \"%s\" does not exist", rel->schemaname)));
1374  }
1375  else
1376  {
1377  ereport(NOTICE,
1378  (errmsg("schema \"%s\" does not exist, skipping",
1379  rel->schemaname)));
1380  }
1381  return;
1382  }
1383 
1384  for (rentry = dropmsgstringarray; rentry->kind != '\0'; rentry++)
1385  {
1386  if (rentry->kind == rightkind)
1387  {
1388  if (!missing_ok)
1389  {
1390  ereport(ERROR,
1391  (errcode(rentry->nonexistent_code),
1392  errmsg(rentry->nonexistent_msg, rel->relname)));
1393  }
1394  else
1395  {
1396  ereport(NOTICE, (errmsg(rentry->skipping_msg, rel->relname)));
1397  break;
1398  }
1399  }
1400  }
1401 
1402  Assert(rentry->kind != '\0'); /* Should be impossible */
1403 }
1404 
1405 /*
1406  * Emit the right error message for a "DROP" command issued on a
1407  * relation of the wrong type
1408  */
1409 static void
1410 DropErrorMsgWrongType(const char *relname, char wrongkind, char rightkind)
1411 {
1412  const struct dropmsgstrings *rentry;
1413  const struct dropmsgstrings *wentry;
1414 
1415  for (rentry = dropmsgstringarray; rentry->kind != '\0'; rentry++)
1416  if (rentry->kind == rightkind)
1417  break;
1418  Assert(rentry->kind != '\0');
1419 
1420  for (wentry = dropmsgstringarray; wentry->kind != '\0'; wentry++)
1421  if (wentry->kind == wrongkind)
1422  break;
1423  /* wrongkind could be something we don't have in our table... */
1424 
1425  ereport(ERROR,
1426  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1427  errmsg(rentry->nota_msg, relname),
1428  (wentry->kind != '\0') ? errhint("%s", _(wentry->drophint_msg)) : 0));
1429 }
1430 
1431 /*
1432  * RemoveRelations
1433  * Implements DROP TABLE, DROP INDEX, DROP SEQUENCE, DROP VIEW,
1434  * DROP MATERIALIZED VIEW, DROP FOREIGN TABLE
1435  */
1436 void
1438 {
1439  ObjectAddresses *objects;
1440  char relkind;
1441  ListCell *cell;
1442  int flags = 0;
1443  LOCKMODE lockmode = AccessExclusiveLock;
1444 
1445  /* DROP CONCURRENTLY uses a weaker lock, and has some restrictions */
1446  if (drop->concurrent)
1447  {
1448  /*
1449  * Note that for temporary relations this lock may get upgraded later
1450  * on, but as no other session can access a temporary relation, this
1451  * is actually fine.
1452  */
1453  lockmode = ShareUpdateExclusiveLock;
1454  Assert(drop->removeType == OBJECT_INDEX);
1455  if (list_length(drop->objects) != 1)
1456  ereport(ERROR,
1457  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1458  errmsg("DROP INDEX CONCURRENTLY does not support dropping multiple objects")));
1459  if (drop->behavior == DROP_CASCADE)
1460  ereport(ERROR,
1461  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1462  errmsg("DROP INDEX CONCURRENTLY does not support CASCADE")));
1463  }
1464 
1465  /*
1466  * First we identify all the relations, then we delete them in a single
1467  * performMultipleDeletions() call. This is to avoid unwanted DROP
1468  * RESTRICT errors if one of the relations depends on another.
1469  */
1470 
1471  /* Determine required relkind */
1472  switch (drop->removeType)
1473  {
1474  case OBJECT_TABLE:
1475  relkind = RELKIND_RELATION;
1476  break;
1477 
1478  case OBJECT_INDEX:
1479  relkind = RELKIND_INDEX;
1480  break;
1481 
1482  case OBJECT_SEQUENCE:
1483  relkind = RELKIND_SEQUENCE;
1484  break;
1485 
1486  case OBJECT_VIEW:
1487  relkind = RELKIND_VIEW;
1488  break;
1489 
1490  case OBJECT_MATVIEW:
1491  relkind = RELKIND_MATVIEW;
1492  break;
1493 
1494  case OBJECT_FOREIGN_TABLE:
1495  relkind = RELKIND_FOREIGN_TABLE;
1496  break;
1497 
1498  default:
1499  elog(ERROR, "unrecognized drop object type: %d",
1500  (int) drop->removeType);
1501  relkind = 0; /* keep compiler quiet */
1502  break;
1503  }
1504 
1505  /* Lock and validate each relation; build a list of object addresses */
1506  objects = new_object_addresses();
1507 
1508  foreach(cell, drop->objects)
1509  {
1510  RangeVar *rel = makeRangeVarFromNameList((List *) lfirst(cell));
1511  Oid relOid;
1512  ObjectAddress obj;
1514 
1515  /*
1516  * These next few steps are a great deal like relation_openrv, but we
1517  * don't bother building a relcache entry since we don't need it.
1518  *
1519  * Check for shared-cache-inval messages before trying to access the
1520  * relation. This is needed to cover the case where the name
1521  * identifies a rel that has been dropped and recreated since the
1522  * start of our transaction: if we don't flush the old syscache entry,
1523  * then we'll latch onto that entry and suffer an error later.
1524  */
1526 
1527  /* Look up the appropriate relation using namespace search. */
1528  state.expected_relkind = relkind;
1529  state.heap_lockmode = drop->concurrent ?
1531  /* We must initialize these fields to show that no locks are held: */
1532  state.heapOid = InvalidOid;
1533  state.partParentOid = InvalidOid;
1534 
1535  relOid = RangeVarGetRelidExtended(rel, lockmode, RVR_MISSING_OK,
1537  (void *) &state);
1538 
1539  /* Not there? */
1540  if (!OidIsValid(relOid))
1541  {
1542  DropErrorMsgNonExistent(rel, relkind, drop->missing_ok);
1543  continue;
1544  }
1545 
1546  /*
1547  * Decide if concurrent mode needs to be used here or not. The
1548  * callback retrieved the rel's persistence for us.
1549  */
1550  if (drop->concurrent &&
1551  state.actual_relpersistence != RELPERSISTENCE_TEMP)
1552  {
1553  Assert(list_length(drop->objects) == 1 &&
1554  drop->removeType == OBJECT_INDEX);
1556  }
1557 
1558  /*
1559  * Concurrent index drop cannot be used with partitioned indexes,
1560  * either.
1561  */
1562  if ((flags & PERFORM_DELETION_CONCURRENTLY) != 0 &&
1563  state.actual_relkind == RELKIND_PARTITIONED_INDEX)
1564  ereport(ERROR,
1565  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1566  errmsg("cannot drop partitioned index \"%s\" concurrently",
1567  rel->relname)));
1568 
1569  /*
1570  * If we're told to drop a partitioned index, we must acquire lock on
1571  * all the children of its parent partitioned table before proceeding.
1572  * Otherwise we'd try to lock the child index partitions before their
1573  * tables, leading to potential deadlock against other sessions that
1574  * will lock those objects in the other order.
1575  */
1576  if (state.actual_relkind == RELKIND_PARTITIONED_INDEX)
1577  (void) find_all_inheritors(state.heapOid,
1578  state.heap_lockmode,
1579  NULL);
1580 
1581  /* OK, we're ready to delete this one */
1582  obj.classId = RelationRelationId;
1583  obj.objectId = relOid;
1584  obj.objectSubId = 0;
1585 
1586  add_exact_object_address(&obj, objects);
1587  }
1588 
1589  performMultipleDeletions(objects, drop->behavior, flags);
1590 
1591  free_object_addresses(objects);
1592 }
1593 
1594 /*
1595  * Before acquiring a table lock, check whether we have sufficient rights.
1596  * In the case of DROP INDEX, also try to lock the table before the index.
1597  * Also, if the table to be dropped is a partition, we try to lock the parent
1598  * first.
1599  */
1600 static void
1601 RangeVarCallbackForDropRelation(const RangeVar *rel, Oid relOid, Oid oldRelOid,
1602  void *arg)
1603 {
1604  HeapTuple tuple;
1606  char expected_relkind;
1607  bool is_partition;
1608  Form_pg_class classform;
1610  bool invalid_system_index = false;
1611 
1612  state = (struct DropRelationCallbackState *) arg;
1613  heap_lockmode = state->heap_lockmode;
1614 
1615  /*
1616  * If we previously locked some other index's heap, and the name we're
1617  * looking up no longer refers to that relation, release the now-useless
1618  * lock.
1619  */
1620  if (relOid != oldRelOid && OidIsValid(state->heapOid))
1621  {
1623  state->heapOid = InvalidOid;
1624  }
1625 
1626  /*
1627  * Similarly, if we previously locked some other partition's heap, and the
1628  * name we're looking up no longer refers to that relation, release the
1629  * now-useless lock.
1630  */
1631  if (relOid != oldRelOid && OidIsValid(state->partParentOid))
1632  {
1633  UnlockRelationOid(state->partParentOid, AccessExclusiveLock);
1634  state->partParentOid = InvalidOid;
1635  }
1636 
1637  /* Didn't find a relation, so no need for locking or permission checks. */
1638  if (!OidIsValid(relOid))
1639  return;
1640 
1641  tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relOid));
1642  if (!HeapTupleIsValid(tuple))
1643  return; /* concurrently dropped, so nothing to do */
1644  classform = (Form_pg_class) GETSTRUCT(tuple);
1645  is_partition = classform->relispartition;
1646 
1647  /* Pass back some data to save lookups in RemoveRelations */
1648  state->actual_relkind = classform->relkind;
1649  state->actual_relpersistence = classform->relpersistence;
1650 
1651  /*
1652  * Both RELKIND_RELATION and RELKIND_PARTITIONED_TABLE are OBJECT_TABLE,
1653  * but RemoveRelations() can only pass one relkind for a given relation.
1654  * It chooses RELKIND_RELATION for both regular and partitioned tables.
1655  * That means we must be careful before giving the wrong type error when
1656  * the relation is RELKIND_PARTITIONED_TABLE. An equivalent problem
1657  * exists with indexes.
1658  */
1659  if (classform->relkind == RELKIND_PARTITIONED_TABLE)
1660  expected_relkind = RELKIND_RELATION;
1661  else if (classform->relkind == RELKIND_PARTITIONED_INDEX)
1662  expected_relkind = RELKIND_INDEX;
1663  else
1664  expected_relkind = classform->relkind;
1665 
1666  if (state->expected_relkind != expected_relkind)
1667  DropErrorMsgWrongType(rel->relname, classform->relkind,
1668  state->expected_relkind);
1669 
1670  /* Allow DROP to either table owner or schema owner */
1671  if (!object_ownercheck(RelationRelationId, relOid, GetUserId()) &&
1672  !object_ownercheck(NamespaceRelationId, classform->relnamespace, GetUserId()))
1674  get_relkind_objtype(classform->relkind),
1675  rel->relname);
1676 
1677  /*
1678  * Check the case of a system index that might have been invalidated by a
1679  * failed concurrent process and allow its drop. For the time being, this
1680  * only concerns indexes of toast relations that became invalid during a
1681  * REINDEX CONCURRENTLY process.
1682  */
1683  if (IsSystemClass(relOid, classform) && classform->relkind == RELKIND_INDEX)
1684  {
1685  HeapTuple locTuple;
1686  Form_pg_index indexform;
1687  bool indisvalid;
1688 
1689  locTuple = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(relOid));
1690  if (!HeapTupleIsValid(locTuple))
1691  {
1692  ReleaseSysCache(tuple);
1693  return;
1694  }
1695 
1696  indexform = (Form_pg_index) GETSTRUCT(locTuple);
1697  indisvalid = indexform->indisvalid;
1698  ReleaseSysCache(locTuple);
1699 
1700  /* Mark object as being an invalid index of system catalogs */
1701  if (!indisvalid)
1702  invalid_system_index = true;
1703  }
1704 
1705  /* In the case of an invalid index, it is fine to bypass this check */
1706  if (!invalid_system_index && !allowSystemTableMods && IsSystemClass(relOid, classform))
1707  ereport(ERROR,
1708  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1709  errmsg("permission denied: \"%s\" is a system catalog",
1710  rel->relname)));
1711 
1712  ReleaseSysCache(tuple);
1713 
1714  /*
1715  * In DROP INDEX, attempt to acquire lock on the parent table before
1716  * locking the index. index_drop() will need this anyway, and since
1717  * regular queries lock tables before their indexes, we risk deadlock if
1718  * we do it the other way around. No error if we don't find a pg_index
1719  * entry, though --- the relation may have been dropped. Note that this
1720  * code will execute for either plain or partitioned indexes.
1721  */
1722  if (expected_relkind == RELKIND_INDEX &&
1723  relOid != oldRelOid)
1724  {
1725  state->heapOid = IndexGetRelation(relOid, true);
1726  if (OidIsValid(state->heapOid))
1727  LockRelationOid(state->heapOid, heap_lockmode);
1728  }
1729 
1730  /*
1731  * Similarly, if the relation is a partition, we must acquire lock on its
1732  * parent before locking the partition. That's because queries lock the
1733  * parent before its partitions, so we risk deadlock if we do it the other
1734  * way around.
1735  */
1736  if (is_partition && relOid != oldRelOid)
1737  {
1738  state->partParentOid = get_partition_parent(relOid, true);
1739  if (OidIsValid(state->partParentOid))
1740  LockRelationOid(state->partParentOid, AccessExclusiveLock);
1741  }
1742 }
1743 
1744 /*
1745  * ExecuteTruncate
1746  * Executes a TRUNCATE command.
1747  *
1748  * This is a multi-relation truncate. We first open and grab exclusive
1749  * lock on all relations involved, checking permissions and otherwise
1750  * verifying that the relation is OK for truncation. Note that if relations
1751  * are foreign tables, at this stage, we have not yet checked that their
1752  * foreign data in external data sources are OK for truncation. These are
1753  * checked when foreign data are actually truncated later. In CASCADE mode,
1754  * relations having FK references to the targeted relations are automatically
1755  * added to the group; in RESTRICT mode, we check that all FK references are
1756  * internal to the group that's being truncated. Finally all the relations
1757  * are truncated and reindexed.
1758  */
1759 void
1761 {
1762  List *rels = NIL;
1763  List *relids = NIL;
1764  List *relids_logged = NIL;
1765  ListCell *cell;
1766 
1767  /*
1768  * Open, exclusive-lock, and check all the explicitly-specified relations
1769  */
1770  foreach(cell, stmt->relations)
1771  {
1772  RangeVar *rv = lfirst(cell);
1773  Relation rel;
1774  bool recurse = rv->inh;
1775  Oid myrelid;
1776  LOCKMODE lockmode = AccessExclusiveLock;
1777 
1778  myrelid = RangeVarGetRelidExtended(rv, lockmode,
1780  NULL);
1781 
1782  /* don't throw error for "TRUNCATE foo, foo" */
1783  if (list_member_oid(relids, myrelid))
1784  continue;
1785 
1786  /* open the relation, we already hold a lock on it */
1787  rel = table_open(myrelid, NoLock);
1788 
1789  /*
1790  * RangeVarGetRelidExtended() has done most checks with its callback,
1791  * but other checks with the now-opened Relation remain.
1792  */
1794 
1795  rels = lappend(rels, rel);
1796  relids = lappend_oid(relids, myrelid);
1797 
1798  /* Log this relation only if needed for logical decoding */
1799  if (RelationIsLogicallyLogged(rel))
1800  relids_logged = lappend_oid(relids_logged, myrelid);
1801 
1802  if (recurse)
1803  {
1804  ListCell *child;
1805  List *children;
1806 
1807  children = find_all_inheritors(myrelid, lockmode, NULL);
1808 
1809  foreach(child, children)
1810  {
1811  Oid childrelid = lfirst_oid(child);
1812 
1813  if (list_member_oid(relids, childrelid))
1814  continue;
1815 
1816  /* find_all_inheritors already got lock */
1817  rel = table_open(childrelid, NoLock);
1818 
1819  /*
1820  * It is possible that the parent table has children that are
1821  * temp tables of other backends. We cannot safely access
1822  * such tables (because of buffering issues), and the best
1823  * thing to do is to silently ignore them. Note that this
1824  * check is the same as one of the checks done in
1825  * truncate_check_activity() called below, still it is kept
1826  * here for simplicity.
1827  */
1828  if (RELATION_IS_OTHER_TEMP(rel))
1829  {
1830  table_close(rel, lockmode);
1831  continue;
1832  }
1833 
1834  /*
1835  * Inherited TRUNCATE commands perform access permission
1836  * checks on the parent table only. So we skip checking the
1837  * children's permissions and don't call
1838  * truncate_check_perms() here.
1839  */
1842 
1843  rels = lappend(rels, rel);
1844  relids = lappend_oid(relids, childrelid);
1845 
1846  /* Log this relation only if needed for logical decoding */
1847  if (RelationIsLogicallyLogged(rel))
1848  relids_logged = lappend_oid(relids_logged, childrelid);
1849  }
1850  }
1851  else if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
1852  ereport(ERROR,
1853  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1854  errmsg("cannot truncate only a partitioned table"),
1855  errhint("Do not specify the ONLY keyword, or use TRUNCATE ONLY on the partitions directly.")));
1856  }
1857 
1858  ExecuteTruncateGuts(rels, relids, relids_logged,
1859  stmt->behavior, stmt->restart_seqs, false);
1860 
1861  /* And close the rels */
1862  foreach(cell, rels)
1863  {
1864  Relation rel = (Relation) lfirst(cell);
1865 
1866  table_close(rel, NoLock);
1867  }
1868 }
1869 
1870 /*
1871  * ExecuteTruncateGuts
1872  *
1873  * Internal implementation of TRUNCATE. This is called by the actual TRUNCATE
1874  * command (see above) as well as replication subscribers that execute a
1875  * replicated TRUNCATE action.
1876  *
1877  * explicit_rels is the list of Relations to truncate that the command
1878  * specified. relids is the list of Oids corresponding to explicit_rels.
1879  * relids_logged is the list of Oids (a subset of relids) that require
1880  * WAL-logging. This is all a bit redundant, but the existing callers have
1881  * this information handy in this form.
1882  */
1883 void
1884 ExecuteTruncateGuts(List *explicit_rels,
1885  List *relids,
1886  List *relids_logged,
1887  DropBehavior behavior, bool restart_seqs,
1888  bool run_as_table_owner)
1889 {
1890  List *rels;
1891  List *seq_relids = NIL;
1892  HTAB *ft_htab = NULL;
1893  EState *estate;
1894  ResultRelInfo *resultRelInfos;
1895  ResultRelInfo *resultRelInfo;
1896  SubTransactionId mySubid;
1897  ListCell *cell;
1898  Oid *logrelids;
1899 
1900  /*
1901  * Check the explicitly-specified relations.
1902  *
1903  * In CASCADE mode, suck in all referencing relations as well. This
1904  * requires multiple iterations to find indirectly-dependent relations. At
1905  * each phase, we need to exclusive-lock new rels before looking for their
1906  * dependencies, else we might miss something. Also, we check each rel as
1907  * soon as we open it, to avoid a faux pas such as holding lock for a long
1908  * time on a rel we have no permissions for.
1909  */
1910  rels = list_copy(explicit_rels);
1911  if (behavior == DROP_CASCADE)
1912  {
1913  for (;;)
1914  {
1915  List *newrelids;
1916 
1917  newrelids = heap_truncate_find_FKs(relids);
1918  if (newrelids == NIL)
1919  break; /* nothing else to add */
1920 
1921  foreach(cell, newrelids)
1922  {
1923  Oid relid = lfirst_oid(cell);
1924  Relation rel;
1925 
1926  rel = table_open(relid, AccessExclusiveLock);
1927  ereport(NOTICE,
1928  (errmsg("truncate cascades to table \"%s\"",
1929  RelationGetRelationName(rel))));
1930  truncate_check_rel(relid, rel->rd_rel);
1931  truncate_check_perms(relid, rel->rd_rel);
1933  rels = lappend(rels, rel);
1934  relids = lappend_oid(relids, relid);
1935 
1936  /* Log this relation only if needed for logical decoding */
1937  if (RelationIsLogicallyLogged(rel))
1938  relids_logged = lappend_oid(relids_logged, relid);
1939  }
1940  }
1941  }
1942 
1943  /*
1944  * Check foreign key references. In CASCADE mode, this should be
1945  * unnecessary since we just pulled in all the references; but as a
1946  * cross-check, do it anyway if in an Assert-enabled build.
1947  */
1948 #ifdef USE_ASSERT_CHECKING
1949  heap_truncate_check_FKs(rels, false);
1950 #else
1951  if (behavior == DROP_RESTRICT)
1952  heap_truncate_check_FKs(rels, false);
1953 #endif
1954 
1955  /*
1956  * If we are asked to restart sequences, find all the sequences, lock them
1957  * (we need AccessExclusiveLock for ResetSequence), and check permissions.
1958  * We want to do this early since it's pointless to do all the truncation
1959  * work only to fail on sequence permissions.
1960  */
1961  if (restart_seqs)
1962  {
1963  foreach(cell, rels)
1964  {
1965  Relation rel = (Relation) lfirst(cell);
1966  List *seqlist = getOwnedSequences(RelationGetRelid(rel));
1967  ListCell *seqcell;
1968 
1969  foreach(seqcell, seqlist)
1970  {
1971  Oid seq_relid = lfirst_oid(seqcell);
1972  Relation seq_rel;
1973 
1974  seq_rel = relation_open(seq_relid, AccessExclusiveLock);
1975 
1976  /* This check must match AlterSequence! */
1977  if (!object_ownercheck(RelationRelationId, seq_relid, GetUserId()))
1979  RelationGetRelationName(seq_rel));
1980 
1981  seq_relids = lappend_oid(seq_relids, seq_relid);
1982 
1983  relation_close(seq_rel, NoLock);
1984  }
1985  }
1986  }
1987 
1988  /* Prepare to catch AFTER triggers. */
1990 
1991  /*
1992  * To fire triggers, we'll need an EState as well as a ResultRelInfo for
1993  * each relation. We don't need to call ExecOpenIndices, though.
1994  *
1995  * We put the ResultRelInfos in the es_opened_result_relations list, even
1996  * though we don't have a range table and don't populate the
1997  * es_result_relations array. That's a bit bogus, but it's enough to make
1998  * ExecGetTriggerResultRel() find them.
1999  */
2000  estate = CreateExecutorState();
2001  resultRelInfos = (ResultRelInfo *)
2002  palloc(list_length(rels) * sizeof(ResultRelInfo));
2003  resultRelInfo = resultRelInfos;
2004  foreach(cell, rels)
2005  {
2006  Relation rel = (Relation) lfirst(cell);
2007 
2008  InitResultRelInfo(resultRelInfo,
2009  rel,
2010  0, /* dummy rangetable index */
2011  NULL,
2012  0);
2013  estate->es_opened_result_relations =
2014  lappend(estate->es_opened_result_relations, resultRelInfo);
2015  resultRelInfo++;
2016  }
2017 
2018  /*
2019  * Process all BEFORE STATEMENT TRUNCATE triggers before we begin
2020  * truncating (this is because one of them might throw an error). Also, if
2021  * we were to allow them to prevent statement execution, that would need
2022  * to be handled here.
2023  */
2024  resultRelInfo = resultRelInfos;
2025  foreach(cell, rels)
2026  {
2027  UserContext ucxt;
2028 
2029  if (run_as_table_owner)
2030  SwitchToUntrustedUser(resultRelInfo->ri_RelationDesc->rd_rel->relowner,
2031  &ucxt);
2032  ExecBSTruncateTriggers(estate, resultRelInfo);
2033  if (run_as_table_owner)
2034  RestoreUserContext(&ucxt);
2035  resultRelInfo++;
2036  }
2037 
2038  /*
2039  * OK, truncate each table.
2040  */
2041  mySubid = GetCurrentSubTransactionId();
2042 
2043  foreach(cell, rels)
2044  {
2045  Relation rel = (Relation) lfirst(cell);
2046 
2047  /* Skip partitioned tables as there is nothing to do */
2048  if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
2049  continue;
2050 
2051  /*
2052  * Build the lists of foreign tables belonging to each foreign server
2053  * and pass each list to the foreign data wrapper's callback function,
2054  * so that each server can truncate its all foreign tables in bulk.
2055  * Each list is saved as a single entry in a hash table that uses the
2056  * server OID as lookup key.
2057  */
2058  if (rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
2059  {
2061  bool found;
2062  ForeignTruncateInfo *ft_info;
2063 
2064  /* First time through, initialize hashtable for foreign tables */
2065  if (!ft_htab)
2066  {
2067  HASHCTL hctl;
2068 
2069  memset(&hctl, 0, sizeof(HASHCTL));
2070  hctl.keysize = sizeof(Oid);
2071  hctl.entrysize = sizeof(ForeignTruncateInfo);
2072  hctl.hcxt = CurrentMemoryContext;
2073 
2074  ft_htab = hash_create("TRUNCATE for Foreign Tables",
2075  32, /* start small and extend */
2076  &hctl,
2078  }
2079 
2080  /* Find or create cached entry for the foreign table */
2081  ft_info = hash_search(ft_htab, &serverid, HASH_ENTER, &found);
2082  if (!found)
2083  ft_info->rels = NIL;
2084 
2085  /*
2086  * Save the foreign table in the entry of the server that the
2087  * foreign table belongs to.
2088  */
2089  ft_info->rels = lappend(ft_info->rels, rel);
2090  continue;
2091  }
2092 
2093  /*
2094  * Normally, we need a transaction-safe truncation here. However, if
2095  * the table was either created in the current (sub)transaction or has
2096  * a new relfilenumber in the current (sub)transaction, then we can
2097  * just truncate it in-place, because a rollback would cause the whole
2098  * table or the current physical file to be thrown away anyway.
2099  */
2100  if (rel->rd_createSubid == mySubid ||
2101  rel->rd_newRelfilelocatorSubid == mySubid)
2102  {
2103  /* Immediate, non-rollbackable truncation is OK */
2104  heap_truncate_one_rel(rel);
2105  }
2106  else
2107  {
2108  Oid heap_relid;
2109  Oid toast_relid;
2110  ReindexParams reindex_params = {0};
2111 
2112  /*
2113  * This effectively deletes all rows in the table, and may be done
2114  * in a serializable transaction. In that case we must record a
2115  * rw-conflict in to this transaction from each transaction
2116  * holding a predicate lock on the table.
2117  */
2119 
2120  /*
2121  * Need the full transaction-safe pushups.
2122  *
2123  * Create a new empty storage file for the relation, and assign it
2124  * as the relfilenumber value. The old storage file is scheduled
2125  * for deletion at commit.
2126  */
2127  RelationSetNewRelfilenumber(rel, rel->rd_rel->relpersistence);
2128 
2129  heap_relid = RelationGetRelid(rel);
2130 
2131  /*
2132  * The same for the toast table, if any.
2133  */
2134  toast_relid = rel->rd_rel->reltoastrelid;
2135  if (OidIsValid(toast_relid))
2136  {
2137  Relation toastrel = relation_open(toast_relid,
2139 
2140  RelationSetNewRelfilenumber(toastrel,
2141  toastrel->rd_rel->relpersistence);
2142  table_close(toastrel, NoLock);
2143  }
2144 
2145  /*
2146  * Reconstruct the indexes to match, and we're done.
2147  */
2148  reindex_relation(NULL, heap_relid, REINDEX_REL_PROCESS_TOAST,
2149  &reindex_params);
2150  }
2151 
2152  pgstat_count_truncate(rel);
2153  }
2154 
2155  /* Now go through the hash table, and truncate foreign tables */
2156  if (ft_htab)
2157  {
2158  ForeignTruncateInfo *ft_info;
2159  HASH_SEQ_STATUS seq;
2160 
2161  hash_seq_init(&seq, ft_htab);
2162 
2163  PG_TRY();
2164  {
2165  while ((ft_info = hash_seq_search(&seq)) != NULL)
2166  {
2167  FdwRoutine *routine = GetFdwRoutineByServerId(ft_info->serverid);
2168 
2169  /* truncate_check_rel() has checked that already */
2170  Assert(routine->ExecForeignTruncate != NULL);
2171 
2172  routine->ExecForeignTruncate(ft_info->rels,
2173  behavior,
2174  restart_seqs);
2175  }
2176  }
2177  PG_FINALLY();
2178  {
2179  hash_destroy(ft_htab);
2180  }
2181  PG_END_TRY();
2182  }
2183 
2184  /*
2185  * Restart owned sequences if we were asked to.
2186  */
2187  foreach(cell, seq_relids)
2188  {
2189  Oid seq_relid = lfirst_oid(cell);
2190 
2191  ResetSequence(seq_relid);
2192  }
2193 
2194  /*
2195  * Write a WAL record to allow this set of actions to be logically
2196  * decoded.
2197  *
2198  * Assemble an array of relids so we can write a single WAL record for the
2199  * whole action.
2200  */
2201  if (relids_logged != NIL)
2202  {
2203  xl_heap_truncate xlrec;
2204  int i = 0;
2205 
2206  /* should only get here if wal_level >= logical */
2208 
2209  logrelids = palloc(list_length(relids_logged) * sizeof(Oid));
2210  foreach(cell, relids_logged)
2211  logrelids[i++] = lfirst_oid(cell);
2212 
2213  xlrec.dbId = MyDatabaseId;
2214  xlrec.nrelids = list_length(relids_logged);
2215  xlrec.flags = 0;
2216  if (behavior == DROP_CASCADE)
2217  xlrec.flags |= XLH_TRUNCATE_CASCADE;
2218  if (restart_seqs)
2220 
2221  XLogBeginInsert();
2222  XLogRegisterData((char *) &xlrec, SizeOfHeapTruncate);
2223  XLogRegisterData((char *) logrelids, list_length(relids_logged) * sizeof(Oid));
2224 
2226 
2227  (void) XLogInsert(RM_HEAP_ID, XLOG_HEAP_TRUNCATE);
2228  }
2229 
2230  /*
2231  * Process all AFTER STATEMENT TRUNCATE triggers.
2232  */
2233  resultRelInfo = resultRelInfos;
2234  foreach(cell, rels)
2235  {
2236  UserContext ucxt;
2237 
2238  if (run_as_table_owner)
2239  SwitchToUntrustedUser(resultRelInfo->ri_RelationDesc->rd_rel->relowner,
2240  &ucxt);
2241  ExecASTruncateTriggers(estate, resultRelInfo);
2242  if (run_as_table_owner)
2243  RestoreUserContext(&ucxt);
2244  resultRelInfo++;
2245  }
2246 
2247  /* Handle queued AFTER triggers */
2248  AfterTriggerEndQuery(estate);
2249 
2250  /* We can clean up the EState now */
2251  FreeExecutorState(estate);
2252 
2253  /*
2254  * Close any rels opened by CASCADE (can't do this while EState still
2255  * holds refs)
2256  */
2257  rels = list_difference_ptr(rels, explicit_rels);
2258  foreach(cell, rels)
2259  {
2260  Relation rel = (Relation) lfirst(cell);
2261 
2262  table_close(rel, NoLock);
2263  }
2264 }
2265 
2266 /*
2267  * Check that a given relation is safe to truncate. Subroutine for
2268  * ExecuteTruncate() and RangeVarCallbackForTruncate().
2269  */
2270 static void
2272 {
2273  char *relname = NameStr(reltuple->relname);
2274 
2275  /*
2276  * Only allow truncate on regular tables, foreign tables using foreign
2277  * data wrappers supporting TRUNCATE and partitioned tables (although, the
2278  * latter are only being included here for the following checks; no
2279  * physical truncation will occur in their case.).
2280  */
2281  if (reltuple->relkind == RELKIND_FOREIGN_TABLE)
2282  {
2283  Oid serverid = GetForeignServerIdByRelId(relid);
2284  FdwRoutine *fdwroutine = GetFdwRoutineByServerId(serverid);
2285 
2286  if (!fdwroutine->ExecForeignTruncate)
2287  ereport(ERROR,
2288  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2289  errmsg("cannot truncate foreign table \"%s\"",
2290  relname)));
2291  }
2292  else if (reltuple->relkind != RELKIND_RELATION &&
2293  reltuple->relkind != RELKIND_PARTITIONED_TABLE)
2294  ereport(ERROR,
2295  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2296  errmsg("\"%s\" is not a table", relname)));
2297 
2298  /*
2299  * Most system catalogs can't be truncated at all, or at least not unless
2300  * allow_system_table_mods=on. As an exception, however, we allow
2301  * pg_largeobject to be truncated as part of pg_upgrade, because we need
2302  * to change its relfilenode to match the old cluster, and allowing a
2303  * TRUNCATE command to be executed is the easiest way of doing that.
2304  */
2305  if (!allowSystemTableMods && IsSystemClass(relid, reltuple)
2306  && (!IsBinaryUpgrade || relid != LargeObjectRelationId))
2307  ereport(ERROR,
2308  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
2309  errmsg("permission denied: \"%s\" is a system catalog",
2310  relname)));
2311 
2312  InvokeObjectTruncateHook(relid);
2313 }
2314 
2315 /*
2316  * Check that current user has the permission to truncate given relation.
2317  */
2318 static void
2320 {
2321  char *relname = NameStr(reltuple->relname);
2322  AclResult aclresult;
2323 
2324  /* Permissions checks */
2325  aclresult = pg_class_aclcheck(relid, GetUserId(), ACL_TRUNCATE);
2326  if (aclresult != ACLCHECK_OK)
2327  aclcheck_error(aclresult, get_relkind_objtype(reltuple->relkind),
2328  relname);
2329 }
2330 
2331 /*
2332  * Set of extra sanity checks to check if a given relation is safe to
2333  * truncate. This is split with truncate_check_rel() as
2334  * RangeVarCallbackForTruncate() cannot open a Relation yet.
2335  */
2336 static void
2338 {
2339  /*
2340  * Don't allow truncate on temp tables of other backends ... their local
2341  * buffer manager is not going to cope.
2342  */
2343  if (RELATION_IS_OTHER_TEMP(rel))
2344  ereport(ERROR,
2345  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2346  errmsg("cannot truncate temporary tables of other sessions")));
2347 
2348  /*
2349  * Also check for active uses of the relation in the current transaction,
2350  * including open scans and pending AFTER trigger events.
2351  */
2352  CheckTableNotInUse(rel, "TRUNCATE");
2353 }
2354 
2355 /*
2356  * storage_name
2357  * returns the name corresponding to a typstorage/attstorage enum value
2358  */
2359 static const char *
2361 {
2362  switch (c)
2363  {
2364  case TYPSTORAGE_PLAIN:
2365  return "PLAIN";
2366  case TYPSTORAGE_EXTERNAL:
2367  return "EXTERNAL";
2368  case TYPSTORAGE_EXTENDED:
2369  return "EXTENDED";
2370  case TYPSTORAGE_MAIN:
2371  return "MAIN";
2372  default:
2373  return "???";
2374  }
2375 }
2376 
2377 /*----------
2378  * MergeAttributes
2379  * Returns new schema given initial schema and superclasses.
2380  *
2381  * Input arguments:
2382  * 'columns' is the column/attribute definition for the table. (It's a list
2383  * of ColumnDef's.) It is destructively changed.
2384  * 'supers' is a list of OIDs of parent relations, already locked by caller.
2385  * 'relpersistence' is the persistence type of the table.
2386  * 'is_partition' tells if the table is a partition.
2387  *
2388  * Output arguments:
2389  * 'supconstr' receives a list of constraints belonging to the parents,
2390  * updated as necessary to be valid for the child.
2391  *
2392  * Return value:
2393  * Completed schema list.
2394  *
2395  * Notes:
2396  * The order in which the attributes are inherited is very important.
2397  * Intuitively, the inherited attributes should come first. If a table
2398  * inherits from multiple parents, the order of those attributes are
2399  * according to the order of the parents specified in CREATE TABLE.
2400  *
2401  * Here's an example:
2402  *
2403  * create table person (name text, age int4, location point);
2404  * create table emp (salary int4, manager text) inherits(person);
2405  * create table student (gpa float8) inherits (person);
2406  * create table stud_emp (percent int4) inherits (emp, student);
2407  *
2408  * The order of the attributes of stud_emp is:
2409  *
2410  * person {1:name, 2:age, 3:location}
2411  * / \
2412  * {6:gpa} student emp {4:salary, 5:manager}
2413  * \ /
2414  * stud_emp {7:percent}
2415  *
2416  * If the same attribute name appears multiple times, then it appears
2417  * in the result table in the proper location for its first appearance.
2418  *
2419  * Constraints (including not-null constraints) for the child table
2420  * are the union of all relevant constraints, from both the child schema
2421  * and parent tables.
2422  *
2423  * The default value for a child column is defined as:
2424  * (1) If the child schema specifies a default, that value is used.
2425  * (2) If neither the child nor any parent specifies a default, then
2426  * the column will not have a default.
2427  * (3) If conflicting defaults are inherited from different parents
2428  * (and not overridden by the child), an error is raised.
2429  * (4) Otherwise the inherited default is used.
2430  *
2431  * Note that the default-value infrastructure is used for generated
2432  * columns' expressions too, so most of the preceding paragraph applies
2433  * to generation expressions too. We insist that a child column be
2434  * generated if and only if its parent(s) are, but it need not have
2435  * the same generation expression.
2436  *----------
2437  */
2438 static List *
2439 MergeAttributes(List *columns, const List *supers, char relpersistence,
2440  bool is_partition, List **supconstr)
2441 {
2442  List *inh_columns = NIL;
2443  List *constraints = NIL;
2444  bool have_bogus_defaults = false;
2445  int child_attno;
2446  static Node bogus_marker = {0}; /* marks conflicting defaults */
2447  List *saved_columns = NIL;
2448  ListCell *lc;
2449 
2450  /*
2451  * Check for and reject tables with too many columns. We perform this
2452  * check relatively early for two reasons: (a) we don't run the risk of
2453  * overflowing an AttrNumber in subsequent code (b) an O(n^2) algorithm is
2454  * okay if we're processing <= 1600 columns, but could take minutes to
2455  * execute if the user attempts to create a table with hundreds of
2456  * thousands of columns.
2457  *
2458  * Note that we also need to check that we do not exceed this figure after
2459  * including columns from inherited relations.
2460  */
2461  if (list_length(columns) > MaxHeapAttributeNumber)
2462  ereport(ERROR,
2463  (errcode(ERRCODE_TOO_MANY_COLUMNS),
2464  errmsg("tables can have at most %d columns",
2466 
2467  /*
2468  * Check for duplicate names in the explicit list of attributes.
2469  *
2470  * Although we might consider merging such entries in the same way that we
2471  * handle name conflicts for inherited attributes, it seems to make more
2472  * sense to assume such conflicts are errors.
2473  *
2474  * We don't use foreach() here because we have two nested loops over the
2475  * columns list, with possible element deletions in the inner one. If we
2476  * used foreach_delete_current() it could only fix up the state of one of
2477  * the loops, so it seems cleaner to use looping over list indexes for
2478  * both loops. Note that any deletion will happen beyond where the outer
2479  * loop is, so its index never needs adjustment.
2480  */
2481  for (int coldefpos = 0; coldefpos < list_length(columns); coldefpos++)
2482  {
2483  ColumnDef *coldef = list_nth_node(ColumnDef, columns, coldefpos);
2484 
2485  if (!is_partition && coldef->typeName == NULL)
2486  {
2487  /*
2488  * Typed table column option that does not belong to a column from
2489  * the type. This works because the columns from the type come
2490  * first in the list. (We omit this check for partition column
2491  * lists; those are processed separately below.)
2492  */
2493  ereport(ERROR,
2494  (errcode(ERRCODE_UNDEFINED_COLUMN),
2495  errmsg("column \"%s\" does not exist",
2496  coldef->colname)));
2497  }
2498 
2499  /* restpos scans all entries beyond coldef; incr is in loop body */
2500  for (int restpos = coldefpos + 1; restpos < list_length(columns);)
2501  {
2502  ColumnDef *restdef = list_nth_node(ColumnDef, columns, restpos);
2503 
2504  if (strcmp(coldef->colname, restdef->colname) == 0)
2505  {
2506  if (coldef->is_from_type)
2507  {
2508  /*
2509  * merge the column options into the column from the type
2510  */
2511  coldef->is_not_null = restdef->is_not_null;
2512  coldef->raw_default = restdef->raw_default;
2513  coldef->cooked_default = restdef->cooked_default;
2514  coldef->constraints = restdef->constraints;
2515  coldef->is_from_type = false;
2516  columns = list_delete_nth_cell(columns, restpos);
2517  }
2518  else
2519  ereport(ERROR,
2520  (errcode(ERRCODE_DUPLICATE_COLUMN),
2521  errmsg("column \"%s\" specified more than once",
2522  coldef->colname)));
2523  }
2524  else
2525  restpos++;
2526  }
2527  }
2528 
2529  /*
2530  * In case of a partition, there are no new column definitions, only dummy
2531  * ColumnDefs created for column constraints. Set them aside for now and
2532  * process them at the end.
2533  */
2534  if (is_partition)
2535  {
2536  saved_columns = columns;
2537  columns = NIL;
2538  }
2539 
2540  /*
2541  * Scan the parents left-to-right, and merge their attributes to form a
2542  * list of inherited columns (inh_columns).
2543  */
2544  child_attno = 0;
2545  foreach(lc, supers)
2546  {
2547  Oid parent = lfirst_oid(lc);
2548  Relation relation;
2549  TupleDesc tupleDesc;
2550  TupleConstr *constr;
2551  AttrMap *newattmap;
2552  List *inherited_defaults;
2553  List *cols_with_defaults;
2554  ListCell *lc1;
2555  ListCell *lc2;
2556 
2557  /* caller already got lock */
2558  relation = table_open(parent, NoLock);
2559 
2560  /*
2561  * Check for active uses of the parent partitioned table in the
2562  * current transaction, such as being used in some manner by an
2563  * enclosing command.
2564  */
2565  if (is_partition)
2566  CheckTableNotInUse(relation, "CREATE TABLE .. PARTITION OF");
2567 
2568  /*
2569  * We do not allow partitioned tables and partitions to participate in
2570  * regular inheritance.
2571  */
2572  if (relation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE && !is_partition)
2573  ereport(ERROR,
2574  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2575  errmsg("cannot inherit from partitioned table \"%s\"",
2576  RelationGetRelationName(relation))));
2577  if (relation->rd_rel->relispartition && !is_partition)
2578  ereport(ERROR,
2579  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2580  errmsg("cannot inherit from partition \"%s\"",
2581  RelationGetRelationName(relation))));
2582 
2583  if (relation->rd_rel->relkind != RELKIND_RELATION &&
2584  relation->rd_rel->relkind != RELKIND_FOREIGN_TABLE &&
2585  relation->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
2586  ereport(ERROR,
2587  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2588  errmsg("inherited relation \"%s\" is not a table or foreign table",
2589  RelationGetRelationName(relation))));
2590 
2591  /*
2592  * If the parent is permanent, so must be all of its partitions. Note
2593  * that inheritance allows that case.
2594  */
2595  if (is_partition &&
2596  relation->rd_rel->relpersistence != RELPERSISTENCE_TEMP &&
2597  relpersistence == RELPERSISTENCE_TEMP)
2598  ereport(ERROR,
2599  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2600  errmsg("cannot create a temporary relation as partition of permanent relation \"%s\"",
2601  RelationGetRelationName(relation))));
2602 
2603  /* Permanent rels cannot inherit from temporary ones */
2604  if (relpersistence != RELPERSISTENCE_TEMP &&
2605  relation->rd_rel->relpersistence == RELPERSISTENCE_TEMP)
2606  ereport(ERROR,
2607  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2608  errmsg(!is_partition
2609  ? "cannot inherit from temporary relation \"%s\""
2610  : "cannot create a permanent relation as partition of temporary relation \"%s\"",
2611  RelationGetRelationName(relation))));
2612 
2613  /* If existing rel is temp, it must belong to this session */
2614  if (relation->rd_rel->relpersistence == RELPERSISTENCE_TEMP &&
2615  !relation->rd_islocaltemp)
2616  ereport(ERROR,
2617  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2618  errmsg(!is_partition
2619  ? "cannot inherit from temporary relation of another session"
2620  : "cannot create as partition of temporary relation of another session")));
2621 
2622  /*
2623  * We should have an UNDER permission flag for this, but for now,
2624  * demand that creator of a child table own the parent.
2625  */
2626  if (!object_ownercheck(RelationRelationId, RelationGetRelid(relation), GetUserId()))
2628  RelationGetRelationName(relation));
2629 
2630  tupleDesc = RelationGetDescr(relation);
2631  constr = tupleDesc->constr;
2632 
2633  /*
2634  * newattmap->attnums[] will contain the child-table attribute numbers
2635  * for the attributes of this parent table. (They are not the same
2636  * for parents after the first one, nor if we have dropped columns.)
2637  */
2638  newattmap = make_attrmap(tupleDesc->natts);
2639 
2640  /* We can't process inherited defaults until newattmap is complete. */
2641  inherited_defaults = cols_with_defaults = NIL;
2642 
2643  for (AttrNumber parent_attno = 1; parent_attno <= tupleDesc->natts;
2644  parent_attno++)
2645  {
2646  Form_pg_attribute attribute = TupleDescAttr(tupleDesc,
2647  parent_attno - 1);
2648  char *attributeName = NameStr(attribute->attname);
2649  int exist_attno;
2650  ColumnDef *newdef;
2651  ColumnDef *mergeddef;
2652 
2653  /*
2654  * Ignore dropped columns in the parent.
2655  */
2656  if (attribute->attisdropped)
2657  continue; /* leave newattmap->attnums entry as zero */
2658 
2659  /*
2660  * Create new column definition
2661  */
2662  newdef = makeColumnDef(attributeName, attribute->atttypid,
2663  attribute->atttypmod, attribute->attcollation);
2664  newdef->is_not_null = attribute->attnotnull;
2665  newdef->storage = attribute->attstorage;
2666  newdef->generated = attribute->attgenerated;
2667  if (CompressionMethodIsValid(attribute->attcompression))
2668  newdef->compression =
2669  pstrdup(GetCompressionMethodName(attribute->attcompression));
2670 
2671  /*
2672  * Regular inheritance children are independent enough not to
2673  * inherit identity columns. But partitions are integral part of
2674  * a partitioned table and inherit identity column.
2675  */
2676  if (is_partition)
2677  newdef->identity = attribute->attidentity;
2678 
2679  /*
2680  * Does it match some previously considered column from another
2681  * parent?
2682  */
2683  exist_attno = findAttrByName(attributeName, inh_columns);
2684  if (exist_attno > 0)
2685  {
2686  /*
2687  * Yes, try to merge the two column definitions.
2688  */
2689  mergeddef = MergeInheritedAttribute(inh_columns, exist_attno, newdef);
2690 
2691  newattmap->attnums[parent_attno - 1] = exist_attno;
2692 
2693  /*
2694  * Partitions have only one parent, so conflict should never
2695  * occur.
2696  */
2697  Assert(!is_partition);
2698  }
2699  else
2700  {
2701  /*
2702  * No, create a new inherited column
2703  */
2704  newdef->inhcount = 1;
2705  newdef->is_local = false;
2706  inh_columns = lappend(inh_columns, newdef);
2707 
2708  newattmap->attnums[parent_attno - 1] = ++child_attno;
2709  mergeddef = newdef;
2710  }
2711 
2712  /*
2713  * Locate default/generation expression if any
2714  */
2715  if (attribute->atthasdef)
2716  {
2717  Node *this_default;
2718 
2719  this_default = TupleDescGetDefault(tupleDesc, parent_attno);
2720  if (this_default == NULL)
2721  elog(ERROR, "default expression not found for attribute %d of relation \"%s\"",
2722  parent_attno, RelationGetRelationName(relation));
2723 
2724  /*
2725  * If it's a GENERATED default, it might contain Vars that
2726  * need to be mapped to the inherited column(s)' new numbers.
2727  * We can't do that till newattmap is ready, so just remember
2728  * all the inherited default expressions for the moment.
2729  */
2730  inherited_defaults = lappend(inherited_defaults, this_default);
2731  cols_with_defaults = lappend(cols_with_defaults, mergeddef);
2732  }
2733  }
2734 
2735  /*
2736  * Now process any inherited default expressions, adjusting attnos
2737  * using the completed newattmap map.
2738  */
2739  forboth(lc1, inherited_defaults, lc2, cols_with_defaults)
2740  {
2741  Node *this_default = (Node *) lfirst(lc1);
2742  ColumnDef *def = (ColumnDef *) lfirst(lc2);
2743  bool found_whole_row;
2744 
2745  /* Adjust Vars to match new table's column numbering */
2746  this_default = map_variable_attnos(this_default,
2747  1, 0,
2748  newattmap,
2749  InvalidOid, &found_whole_row);
2750 
2751  /*
2752  * For the moment we have to reject whole-row variables. We could
2753  * convert them, if we knew the new table's rowtype OID, but that
2754  * hasn't been assigned yet. (A variable could only appear in a
2755  * generation expression, so the error message is correct.)
2756  */
2757  if (found_whole_row)
2758  ereport(ERROR,
2759  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2760  errmsg("cannot convert whole-row table reference"),
2761  errdetail("Generation expression for column \"%s\" contains a whole-row reference to table \"%s\".",
2762  def->colname,
2763  RelationGetRelationName(relation))));
2764 
2765  /*
2766  * If we already had a default from some prior parent, check to
2767  * see if they are the same. If so, no problem; if not, mark the
2768  * column as having a bogus default. Below, we will complain if
2769  * the bogus default isn't overridden by the child columns.
2770  */
2771  Assert(def->raw_default == NULL);
2772  if (def->cooked_default == NULL)
2773  def->cooked_default = this_default;
2774  else if (!equal(def->cooked_default, this_default))
2775  {
2776  def->cooked_default = &bogus_marker;
2777  have_bogus_defaults = true;
2778  }
2779  }
2780 
2781  /*
2782  * Now copy the CHECK constraints of this parent, adjusting attnos
2783  * using the completed newattmap map. Identically named constraints
2784  * are merged if possible, else we throw error.
2785  */
2786  if (constr && constr->num_check > 0)
2787  {
2788  ConstrCheck *check = constr->check;
2789 
2790  for (int i = 0; i < constr->num_check; i++)
2791  {
2792  char *name = check[i].ccname;
2793  Node *expr;
2794  bool found_whole_row;
2795 
2796  /* ignore if the constraint is non-inheritable */
2797  if (check[i].ccnoinherit)
2798  continue;
2799 
2800  /* Adjust Vars to match new table's column numbering */
2801  expr = map_variable_attnos(stringToNode(check[i].ccbin),
2802  1, 0,
2803  newattmap,
2804  InvalidOid, &found_whole_row);
2805 
2806  /*
2807  * For the moment we have to reject whole-row variables. We
2808  * could convert them, if we knew the new table's rowtype OID,
2809  * but that hasn't been assigned yet.
2810  */
2811  if (found_whole_row)
2812  ereport(ERROR,
2813  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2814  errmsg("cannot convert whole-row table reference"),
2815  errdetail("Constraint \"%s\" contains a whole-row reference to table \"%s\".",
2816  name,
2817  RelationGetRelationName(relation))));
2818 
2819  constraints = MergeCheckConstraint(constraints, name, expr);
2820  }
2821  }
2822 
2823  free_attrmap(newattmap);
2824 
2825  /*
2826  * Close the parent rel, but keep our lock on it until xact commit.
2827  * That will prevent someone else from deleting or ALTERing the parent
2828  * before the child is committed.
2829  */
2830  table_close(relation, NoLock);
2831  }
2832 
2833  /*
2834  * If we had no inherited attributes, the result columns are just the
2835  * explicitly declared columns. Otherwise, we need to merge the declared
2836  * columns into the inherited column list. Although, we never have any
2837  * explicitly declared columns if the table is a partition.
2838  */
2839  if (inh_columns != NIL)
2840  {
2841  int newcol_attno = 0;
2842 
2843  foreach(lc, columns)
2844  {
2845  ColumnDef *newdef = lfirst_node(ColumnDef, lc);
2846  char *attributeName = newdef->colname;
2847  int exist_attno;
2848 
2849  /*
2850  * Partitions have only one parent and have no column definitions
2851  * of their own, so conflict should never occur.
2852  */
2853  Assert(!is_partition);
2854 
2855  newcol_attno++;
2856 
2857  /*
2858  * Does it match some inherited column?
2859  */
2860  exist_attno = findAttrByName(attributeName, inh_columns);
2861  if (exist_attno > 0)
2862  {
2863  /*
2864  * Yes, try to merge the two column definitions.
2865  */
2866  MergeChildAttribute(inh_columns, exist_attno, newcol_attno, newdef);
2867  }
2868  else
2869  {
2870  /*
2871  * No, attach new column unchanged to result columns.
2872  */
2873  inh_columns = lappend(inh_columns, newdef);
2874  }
2875  }
2876 
2877  columns = inh_columns;
2878 
2879  /*
2880  * Check that we haven't exceeded the legal # of columns after merging
2881  * in inherited columns.
2882  */
2883  if (list_length(columns) > MaxHeapAttributeNumber)
2884  ereport(ERROR,
2885  (errcode(ERRCODE_TOO_MANY_COLUMNS),
2886  errmsg("tables can have at most %d columns",
2888  }
2889 
2890  /*
2891  * Now that we have the column definition list for a partition, we can
2892  * check whether the columns referenced in the column constraint specs
2893  * actually exist. Also, we merge parent's not-null constraints and
2894  * defaults into each corresponding column definition.
2895  */
2896  if (is_partition)
2897  {
2898  foreach(lc, saved_columns)
2899  {
2900  ColumnDef *restdef = lfirst(lc);
2901  bool found = false;
2902  ListCell *l;
2903 
2904  foreach(l, columns)
2905  {
2906  ColumnDef *coldef = lfirst(l);
2907 
2908  if (strcmp(coldef->colname, restdef->colname) == 0)
2909  {
2910  found = true;
2911  coldef->is_not_null |= restdef->is_not_null;
2912 
2913  /*
2914  * Check for conflicts related to generated columns.
2915  *
2916  * Same rules as above: generated-ness has to match the
2917  * parent, but the contents of the generation expression
2918  * can be different.
2919  */
2920  if (coldef->generated)
2921  {
2922  if (restdef->raw_default && !restdef->generated)
2923  ereport(ERROR,
2924  (errcode(ERRCODE_INVALID_COLUMN_DEFINITION),
2925  errmsg("column \"%s\" inherits from generated column but specifies default",
2926  restdef->colname)));
2927  if (restdef->identity)
2928  ereport(ERROR,
2929  (errcode(ERRCODE_INVALID_COLUMN_DEFINITION),
2930  errmsg("column \"%s\" inherits from generated column but specifies identity",
2931  restdef->colname)));
2932  }
2933  else
2934  {
2935  if (restdef->generated)
2936  ereport(ERROR,
2937  (errcode(ERRCODE_INVALID_COLUMN_DEFINITION),
2938  errmsg("child column \"%s\" specifies generation expression",
2939  restdef->colname),
2940  errhint("A child table column cannot be generated unless its parent column is.")));
2941  }
2942 
2943  /*
2944  * Override the parent's default value for this column
2945  * (coldef->cooked_default) with the partition's local
2946  * definition (restdef->raw_default), if there's one. It
2947  * should be physically impossible to get a cooked default
2948  * in the local definition or a raw default in the
2949  * inherited definition, but make sure they're nulls, for
2950  * future-proofing.
2951  */
2952  Assert(restdef->cooked_default == NULL);
2953  Assert(coldef->raw_default == NULL);
2954  if (restdef->raw_default)
2955  {
2956  coldef->raw_default = restdef->raw_default;
2957  coldef->cooked_default = NULL;
2958  }
2959  }
2960  }
2961 
2962  /* complain for constraints on columns not in parent */
2963  if (!found)
2964  ereport(ERROR,
2965  (errcode(ERRCODE_UNDEFINED_COLUMN),
2966  errmsg("column \"%s\" does not exist",
2967  restdef->colname)));
2968  }
2969  }
2970 
2971  /*
2972  * If we found any conflicting parent default values, check to make sure
2973  * they were overridden by the child.
2974  */
2975  if (have_bogus_defaults)
2976  {
2977  foreach(lc, columns)
2978  {
2979  ColumnDef *def = lfirst(lc);
2980 
2981  if (def->cooked_default == &bogus_marker)
2982  {
2983  if (def->generated)
2984  ereport(ERROR,
2985  (errcode(ERRCODE_INVALID_COLUMN_DEFINITION),
2986  errmsg("column \"%s\" inherits conflicting generation expressions",
2987  def->colname),
2988  errhint("To resolve the conflict, specify a generation expression explicitly.")));
2989  else
2990  ereport(ERROR,
2991  (errcode(ERRCODE_INVALID_COLUMN_DEFINITION),
2992  errmsg("column \"%s\" inherits conflicting default values",
2993  def->colname),
2994  errhint("To resolve the conflict, specify a default explicitly.")));
2995  }
2996  }
2997  }
2998 
2999  *supconstr = constraints;
3000 
3001  return columns;
3002 }
3003 
3004 
3005 /*
3006  * MergeCheckConstraint
3007  * Try to merge an inherited CHECK constraint with previous ones
3008  *
3009  * If we inherit identically-named constraints from multiple parents, we must
3010  * merge them, or throw an error if they don't have identical definitions.
3011  *
3012  * constraints is a list of CookedConstraint structs for previous constraints.
3013  *
3014  * If the new constraint matches an existing one, then the existing
3015  * constraint's inheritance count is updated. If there is a conflict (same
3016  * name but different expression), throw an error. If the constraint neither
3017  * matches nor conflicts with an existing one, a new constraint is appended to
3018  * the list.
3019  */
3020 static List *
3021 MergeCheckConstraint(List *constraints, const char *name, Node *expr)
3022 {
3023  ListCell *lc;
3024  CookedConstraint *newcon;
3025 
3026  foreach(lc, constraints)
3027  {
3028  CookedConstraint *ccon = (CookedConstraint *) lfirst(lc);
3029 
3030  Assert(ccon->contype == CONSTR_CHECK);
3031 
3032  /* Non-matching names never conflict */
3033  if (strcmp(ccon->name, name) != 0)
3034  continue;
3035 
3036  if (equal(expr, ccon->expr))
3037  {
3038  /* OK to merge constraint with existing */
3039  ccon->inhcount++;
3040  if (ccon->inhcount < 0)
3041  ereport(ERROR,
3042  errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
3043  errmsg("too many inheritance parents"));
3044  return constraints;
3045  }
3046 
3047  ereport(ERROR,
3049  errmsg("check constraint name \"%s\" appears multiple times but with different expressions",
3050  name)));
3051  }
3052 
3053  /*
3054  * Constraint couldn't be merged with an existing one and also didn't
3055  * conflict with an existing one, so add it as a new one to the list.
3056  */
3057  newcon = palloc0_object(CookedConstraint);
3058  newcon->contype = CONSTR_CHECK;
3059  newcon->name = pstrdup(name);
3060  newcon->expr = expr;
3061  newcon->inhcount = 1;
3062  return lappend(constraints, newcon);
3063 }
3064 
3065 /*
3066  * MergeChildAttribute
3067  * Merge given child attribute definition into given inherited attribute.
3068  *
3069  * Input arguments:
3070  * 'inh_columns' is the list of inherited ColumnDefs.
3071  * 'exist_attno' is the number of the inherited attribute in inh_columns
3072  * 'newcol_attno' is the attribute number in child table's schema definition
3073  * 'newdef' is the column/attribute definition from the child table.
3074  *
3075  * The ColumnDef in 'inh_columns' list is modified. The child attribute's
3076  * ColumnDef remains unchanged.
3077  *
3078  * Notes:
3079  * - The attribute is merged according to the rules laid out in the prologue
3080  * of MergeAttributes().
3081  * - If matching inherited attribute exists but the child attribute can not be
3082  * merged into it, the function throws respective errors.
3083  * - A partition can not have its own column definitions. Hence this function
3084  * is applicable only to a regular inheritance child.
3085  */
3086 static void
3087 MergeChildAttribute(List *inh_columns, int exist_attno, int newcol_attno, const ColumnDef *newdef)
3088 {
3089  char *attributeName = newdef->colname;
3090  ColumnDef *inhdef;
3091  Oid inhtypeid,
3092  newtypeid;
3093  int32 inhtypmod,
3094  newtypmod;
3095  Oid inhcollid,
3096  newcollid;
3097 
3098  if (exist_attno == newcol_attno)
3099  ereport(NOTICE,
3100  (errmsg("merging column \"%s\" with inherited definition",
3101  attributeName)));
3102  else
3103  ereport(NOTICE,
3104  (errmsg("moving and merging column \"%s\" with inherited definition", attributeName),
3105  errdetail("User-specified column moved to the position of the inherited column.")));
3106 
3107  inhdef = list_nth_node(ColumnDef, inh_columns, exist_attno - 1);
3108 
3109  /*
3110  * Must have the same type and typmod
3111  */
3112  typenameTypeIdAndMod(NULL, inhdef->typeName, &inhtypeid, &inhtypmod);
3113  typenameTypeIdAndMod(NULL, newdef->typeName, &newtypeid, &newtypmod);
3114  if (inhtypeid != newtypeid || inhtypmod != newtypmod)
3115  ereport(ERROR,
3116  (errcode(ERRCODE_DATATYPE_MISMATCH),
3117  errmsg("column \"%s\" has a type conflict",
3118  attributeName),
3119  errdetail("%s versus %s",
3120  format_type_with_typemod(inhtypeid, inhtypmod),
3121  format_type_with_typemod(newtypeid, newtypmod))));
3122 
3123  /*
3124  * Must have the same collation
3125  */
3126  inhcollid = GetColumnDefCollation(NULL, inhdef, inhtypeid);
3127  newcollid = GetColumnDefCollation(NULL, newdef, newtypeid);
3128  if (inhcollid != newcollid)
3129  ereport(ERROR,
3130  (errcode(ERRCODE_COLLATION_MISMATCH),
3131  errmsg("column \"%s\" has a collation conflict",
3132  attributeName),
3133  errdetail("\"%s\" versus \"%s\"",
3134  get_collation_name(inhcollid),
3135  get_collation_name(newcollid))));
3136 
3137  /*
3138  * Identity is never inherited by a regular inheritance child. Pick
3139  * child's identity definition if there's one.
3140  */
3141  inhdef->identity = newdef->identity;
3142 
3143  /*
3144  * Copy storage parameter
3145  */
3146  if (inhdef->storage == 0)
3147  inhdef->storage = newdef->storage;
3148  else if (newdef->storage != 0 && inhdef->storage != newdef->storage)
3149  ereport(ERROR,
3150  (errcode(ERRCODE_DATATYPE_MISMATCH),
3151  errmsg("column \"%s\" has a storage parameter conflict",
3152  attributeName),
3153  errdetail("%s versus %s",
3154  storage_name(inhdef->storage),
3155  storage_name(newdef->storage))));
3156 
3157  /*
3158  * Copy compression parameter
3159  */
3160  if (inhdef->compression == NULL)
3161  inhdef->compression = newdef->compression;
3162  else if (newdef->compression != NULL)
3163  {
3164  if (strcmp(inhdef->compression, newdef->compression) != 0)
3165  ereport(ERROR,
3166  (errcode(ERRCODE_DATATYPE_MISMATCH),
3167  errmsg("column \"%s\" has a compression method conflict",
3168  attributeName),
3169  errdetail("%s versus %s", inhdef->compression, newdef->compression)));
3170  }
3171 
3172  /*
3173  * Merge of not-null constraints = OR 'em together
3174  */
3175  inhdef->is_not_null |= newdef->is_not_null;
3176 
3177  /*
3178  * Check for conflicts related to generated columns.
3179  *
3180  * If the parent column is generated, the child column will be made a
3181  * generated column if it isn't already. If it is a generated column,
3182  * we'll take its generation expression in preference to the parent's. We
3183  * must check that the child column doesn't specify a default value or
3184  * identity, which matches the rules for a single column in
3185  * parse_utilcmd.c.
3186  *
3187  * Conversely, if the parent column is not generated, the child column
3188  * can't be either. (We used to allow that, but it results in being able
3189  * to override the generation expression via UPDATEs through the parent.)
3190  */
3191  if (inhdef->generated)
3192  {
3193  if (newdef->raw_default && !newdef->generated)
3194  ereport(ERROR,
3195  (errcode(ERRCODE_INVALID_COLUMN_DEFINITION),
3196  errmsg("column \"%s\" inherits from generated column but specifies default",
3197  inhdef->colname)));
3198  if (newdef->identity)
3199  ereport(ERROR,
3200  (errcode(ERRCODE_INVALID_COLUMN_DEFINITION),
3201  errmsg("column \"%s\" inherits from generated column but specifies identity",
3202  inhdef->colname)));
3203  }
3204  else
3205  {
3206  if (newdef->generated)
3207  ereport(ERROR,
3208  (errcode(ERRCODE_INVALID_COLUMN_DEFINITION),
3209  errmsg("child column \"%s\" specifies generation expression",
3210  inhdef->colname),
3211  errhint("A child table column cannot be generated unless its parent column is.")));
3212  }
3213 
3214  /*
3215  * If new def has a default, override previous default
3216  */
3217  if (newdef->raw_default != NULL)
3218  {
3219  inhdef->raw_default = newdef->raw_default;
3220  inhdef->cooked_default = newdef->cooked_default;
3221  }
3222 
3223  /* Mark the column as locally defined */
3224  inhdef->is_local = true;
3225 }
3226 
3227 /*
3228  * MergeInheritedAttribute
3229  * Merge given parent attribute definition into specified attribute
3230  * inherited from the previous parents.
3231  *
3232  * Input arguments:
3233  * 'inh_columns' is the list of previously inherited ColumnDefs.
3234  * 'exist_attno' is the number the existing matching attribute in inh_columns.
3235  * 'newdef' is the new parent column/attribute definition to be merged.
3236  *
3237  * The matching ColumnDef in 'inh_columns' list is modified and returned.
3238  *
3239  * Notes:
3240  * - The attribute is merged according to the rules laid out in the prologue
3241  * of MergeAttributes().
3242  * - If matching inherited attribute exists but the new attribute can not be
3243  * merged into it, the function throws respective errors.
3244  * - A partition inherits from only a single parent. Hence this function is
3245  * applicable only to a regular inheritance.
3246  */
3247 static ColumnDef *
3249  int exist_attno,
3250  const ColumnDef *newdef)
3251 {
3252  char *attributeName = newdef->colname;
3253  ColumnDef *prevdef;
3254  Oid prevtypeid,
3255  newtypeid;
3256  int32 prevtypmod,
3257  newtypmod;
3258  Oid prevcollid,
3259  newcollid;
3260 
3261  ereport(NOTICE,
3262  (errmsg("merging multiple inherited definitions of column \"%s\"",
3263  attributeName)));
3264  prevdef = list_nth_node(ColumnDef, inh_columns, exist_attno - 1);
3265 
3266  /*
3267  * Must have the same type and typmod
3268  */
3269  typenameTypeIdAndMod(NULL, prevdef->typeName, &prevtypeid, &prevtypmod);
3270  typenameTypeIdAndMod(NULL, newdef->typeName, &newtypeid, &newtypmod);
3271  if (prevtypeid != newtypeid || prevtypmod != newtypmod)
3272  ereport(ERROR,
3273  (errcode(ERRCODE_DATATYPE_MISMATCH),
3274  errmsg("inherited column \"%s\" has a type conflict",
3275  attributeName),
3276  errdetail("%s versus %s",
3277  format_type_with_typemod(prevtypeid, prevtypmod),
3278  format_type_with_typemod(newtypeid, newtypmod))));
3279 
3280  /*
3281  * Merge of not-null constraints = OR 'em together
3282  */
3283  prevdef->is_not_null |= newdef->is_not_null;
3284 
3285  /*
3286  * Must have the same collation
3287  */
3288  prevcollid = GetColumnDefCollation(NULL, prevdef, prevtypeid);
3289  newcollid = GetColumnDefCollation(NULL, newdef, newtypeid);
3290  if (prevcollid != newcollid)
3291  ereport(ERROR,
3292  (errcode(ERRCODE_COLLATION_MISMATCH),
3293  errmsg("inherited column \"%s\" has a collation conflict",
3294  attributeName),
3295  errdetail("\"%s\" versus \"%s\"",
3296  get_collation_name(prevcollid),
3297  get_collation_name(newcollid))));
3298 
3299  /*
3300  * Copy/check storage parameter
3301  */
3302  if (prevdef->storage == 0)
3303  prevdef->storage = newdef->storage;
3304  else if (prevdef->storage != newdef->storage)
3305  ereport(ERROR,
3306  (errcode(ERRCODE_DATATYPE_MISMATCH),
3307  errmsg("inherited column \"%s\" has a storage parameter conflict",
3308  attributeName),
3309  errdetail("%s versus %s",
3310  storage_name(prevdef->storage),
3311  storage_name(newdef->storage))));
3312 
3313  /*
3314  * Copy/check compression parameter
3315  */
3316  if (prevdef->compression == NULL)
3317  prevdef->compression = newdef->compression;
3318  else if (newdef->compression != NULL)
3319  {
3320  if (strcmp(prevdef->compression, newdef->compression) != 0)
3321  ereport(ERROR,
3322  (errcode(ERRCODE_DATATYPE_MISMATCH),
3323  errmsg("column \"%s\" has a compression method conflict",
3324  attributeName),
3325  errdetail("%s versus %s",
3326  prevdef->compression, newdef->compression)));
3327  }
3328 
3329  /*
3330  * Check for GENERATED conflicts
3331  */
3332  if (prevdef->generated != newdef->generated)
3333  ereport(ERROR,
3334  (errcode(ERRCODE_DATATYPE_MISMATCH),
3335  errmsg("inherited column \"%s\" has a generation conflict",
3336  attributeName)));
3337 
3338  /*
3339  * Default and other constraints are handled by the caller.
3340  */
3341 
3342  prevdef->inhcount++;
3343  if (prevdef->inhcount < 0)
3344  ereport(ERROR,
3345  errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
3346  errmsg("too many inheritance parents"));
3347 
3348  return prevdef;
3349 }
3350 
3351 /*
3352  * StoreCatalogInheritance
3353  * Updates the system catalogs with proper inheritance information.
3354  *
3355  * supers is a list of the OIDs of the new relation's direct ancestors.
3356  */
3357 static void
3358 StoreCatalogInheritance(Oid relationId, List *supers,
3359  bool child_is_partition)
3360 {
3361  Relation relation;
3362  int32 seqNumber;
3363  ListCell *entry;
3364 
3365  /*
3366  * sanity checks
3367  */
3368  Assert(OidIsValid(relationId));
3369 
3370  if (supers == NIL)
3371  return;
3372 
3373  /*
3374  * Store INHERITS information in pg_inherits using direct ancestors only.
3375  * Also enter dependencies on the direct ancestors, and make sure they are
3376  * marked with relhassubclass = true.
3377  *
3378  * (Once upon a time, both direct and indirect ancestors were found here
3379  * and then entered into pg_ipl. Since that catalog doesn't exist
3380  * anymore, there's no need to look for indirect ancestors.)
3381  */
3382  relation = table_open(InheritsRelationId, RowExclusiveLock);
3383 
3384  seqNumber = 1;
3385  foreach(entry, supers)
3386  {
3387  Oid parentOid = lfirst_oid(entry);
3388 
3389  StoreCatalogInheritance1(relationId, parentOid, seqNumber, relation,
3390  child_is_partition);
3391  seqNumber++;
3392  }
3393 
3394  table_close(relation, RowExclusiveLock);
3395 }
3396 
3397 /*
3398  * Make catalog entries showing relationId as being an inheritance child
3399  * of parentOid. inhRelation is the already-opened pg_inherits catalog.
3400  */
3401 static void
3402 StoreCatalogInheritance1(Oid relationId, Oid parentOid,
3403  int32 seqNumber, Relation inhRelation,
3404  bool child_is_partition)
3405 {
3406  ObjectAddress childobject,
3407  parentobject;
3408 
3409  /* store the pg_inherits row */
3410  StoreSingleInheritance(relationId, parentOid, seqNumber);
3411 
3412  /*
3413  * Store a dependency too
3414  */
3415  parentobject.classId = RelationRelationId;
3416  parentobject.objectId = parentOid;
3417  parentobject.objectSubId = 0;
3418  childobject.classId = RelationRelationId;
3419  childobject.objectId = relationId;
3420  childobject.objectSubId = 0;
3421 
3422  recordDependencyOn(&childobject, &parentobject,
3423  child_dependency_type(child_is_partition));
3424 
3425  /*
3426  * Post creation hook of this inheritance. Since object_access_hook
3427  * doesn't take multiple object identifiers, we relay oid of parent
3428  * relation using auxiliary_id argument.
3429  */
3430  InvokeObjectPostAlterHookArg(InheritsRelationId,
3431  relationId, 0,
3432  parentOid, false);
3433 
3434  /*
3435  * Mark the parent as having subclasses.
3436  */
3437  SetRelationHasSubclass(parentOid, true);
3438 }
3439 
3440 /*
3441  * Look for an existing column entry with the given name.
3442  *
3443  * Returns the index (starting with 1) if attribute already exists in columns,
3444  * 0 if it doesn't.
3445  */
3446 static int
3447 findAttrByName(const char *attributeName, const List *columns)
3448 {
3449  ListCell *lc;
3450  int i = 1;
3451 
3452  foreach(lc, columns)
3453  {
3454  if (strcmp(attributeName, lfirst_node(ColumnDef, lc)->colname) == 0)
3455  return i;
3456 
3457  i++;
3458  }
3459  return 0;
3460 }
3461 
3462 
3463 /*
3464  * SetRelationHasSubclass
3465  * Set the value of the relation's relhassubclass field in pg_class.
3466  *
3467  * It's always safe to set this field to true, because all SQL commands are
3468  * ready to see true and then find no children. On the other hand, commands
3469  * generally assume zero children if this is false.
3470  *
3471  * Caller must hold any self-exclusive lock until end of transaction. If the
3472  * new value is false, caller must have acquired that lock before reading the
3473  * evidence that justified the false value. That way, it properly waits if
3474  * another backend is simultaneously concluding no need to change the tuple
3475  * (new and old values are true).
3476  *
3477  * NOTE: an important side-effect of this operation is that an SI invalidation
3478  * message is sent out to all backends --- including me --- causing plans
3479  * referencing the relation to be rebuilt with the new list of children.
3480  * This must happen even if we find that no change is needed in the pg_class
3481  * row.
3482  */
3483 void
3484 SetRelationHasSubclass(Oid relationId, bool relhassubclass)
3485 {
3486  Relation relationRelation;
3487  HeapTuple tuple;
3488  Form_pg_class classtuple;
3489 
3491  ShareUpdateExclusiveLock, false) ||
3492  CheckRelationOidLockedByMe(relationId,
3493  ShareRowExclusiveLock, true));
3494 
3495  /*
3496  * Fetch a modifiable copy of the tuple, modify it, update pg_class.
3497  */
3498  relationRelation = table_open(RelationRelationId, RowExclusiveLock);
3499  tuple = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relationId));
3500  if (!HeapTupleIsValid(tuple))
3501  elog(ERROR, "cache lookup failed for relation %u", relationId);
3502  classtuple = (Form_pg_class) GETSTRUCT(tuple);
3503 
3504  if (classtuple->relhassubclass != relhassubclass)
3505  {
3506  classtuple->relhassubclass = relhassubclass;
3507  CatalogTupleUpdate(relationRelation, &tuple->t_self, tuple);
3508  }
3509  else
3510  {
3511  /* no need to change tuple, but force relcache rebuild anyway */
3513  }
3514 
3515  heap_freetuple(tuple);
3516  table_close(relationRelation, RowExclusiveLock);
3517 }
3518 
3519 /*
3520  * CheckRelationTableSpaceMove
3521  * Check if relation can be moved to new tablespace.
3522  *
3523  * NOTE: The caller must hold AccessExclusiveLock on the relation.
3524  *
3525  * Returns true if the relation can be moved to the new tablespace; raises
3526  * an error if it is not possible to do the move; returns false if the move
3527  * would have no effect.
3528  */
3529 bool
3531 {
3532  Oid oldTableSpaceId;
3533 
3534  /*
3535  * No work if no change in tablespace. Note that MyDatabaseTableSpace is
3536  * stored as 0.
3537  */
3538  oldTableSpaceId = rel->rd_rel->reltablespace;
3539  if (newTableSpaceId == oldTableSpaceId ||
3540  (newTableSpaceId == MyDatabaseTableSpace && oldTableSpaceId == 0))
3541  return false;
3542 
3543  /*
3544  * We cannot support moving mapped relations into different tablespaces.
3545  * (In particular this eliminates all shared catalogs.)
3546  */
3547  if (RelationIsMapped(rel))
3548  ereport(ERROR,
3549  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3550  errmsg("cannot move system relation \"%s\"",
3551  RelationGetRelationName(rel))));
3552 
3553  /* Cannot move a non-shared relation into pg_global */
3554  if (newTableSpaceId == GLOBALTABLESPACE_OID)
3555  ereport(ERROR,
3556  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
3557  errmsg("only shared relations can be placed in pg_global tablespace")));
3558 
3559  /*
3560  * Do not allow moving temp tables of other backends ... their local
3561  * buffer manager is not going to cope.
3562  */
3563  if (RELATION_IS_OTHER_TEMP(rel))
3564  ereport(ERROR,
3565  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3566  errmsg("cannot move temporary tables of other sessions")));
3567 
3568  return true;
3569 }
3570 
3571 /*
3572  * SetRelationTableSpace
3573  * Set new reltablespace and relfilenumber in pg_class entry.
3574  *
3575  * newTableSpaceId is the new tablespace for the relation, and
3576  * newRelFilenumber its new filenumber. If newRelFilenumber is
3577  * InvalidRelFileNumber, this field is not updated.
3578  *
3579  * NOTE: The caller must hold AccessExclusiveLock on the relation.
3580  *
3581  * The caller of this routine had better check if a relation can be
3582  * moved to this new tablespace by calling CheckRelationTableSpaceMove()
3583  * first, and is responsible for making the change visible with
3584  * CommandCounterIncrement().
3585  */
3586 void
3588  Oid newTableSpaceId,
3589  RelFileNumber newRelFilenumber)
3590 {
3591  Relation pg_class;
3592  HeapTuple tuple;
3593  Form_pg_class rd_rel;
3594  Oid reloid = RelationGetRelid(rel);
3595 
3596  Assert(CheckRelationTableSpaceMove(rel, newTableSpaceId));
3597 
3598  /* Get a modifiable copy of the relation's pg_class row. */
3599  pg_class = table_open(RelationRelationId, RowExclusiveLock);
3600 
3601  tuple = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(reloid));
3602  if (!HeapTupleIsValid(tuple))
3603  elog(ERROR, "cache lookup failed for relation %u", reloid);
3604  rd_rel = (Form_pg_class) GETSTRUCT(tuple);
3605 
3606  /* Update the pg_class row. */
3607  rd_rel->reltablespace = (newTableSpaceId == MyDatabaseTableSpace) ?
3608  InvalidOid : newTableSpaceId;
3609  if (RelFileNumberIsValid(newRelFilenumber))
3610  rd_rel->relfilenode = newRelFilenumber;
3611  CatalogTupleUpdate(pg_class, &tuple->t_self, tuple);
3612 
3613  /*
3614  * Record dependency on tablespace. This is only required for relations
3615  * that have no physical storage.
3616  */
3617  if (!RELKIND_HAS_STORAGE(rel->rd_rel->relkind))
3618  changeDependencyOnTablespace(RelationRelationId, reloid,
3619  rd_rel->reltablespace);
3620 
3621  heap_freetuple(tuple);
3622  table_close(pg_class, RowExclusiveLock);
3623 }
3624 
3625 /*
3626  * renameatt_check - basic sanity checks before attribute rename
3627  */
3628 static void
3629 renameatt_check(Oid myrelid, Form_pg_class classform, bool recursing)
3630 {
3631  char relkind = classform->relkind;
3632 
3633  if (classform->reloftype && !recursing)
3634  ereport(ERROR,
3635  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3636  errmsg("cannot rename column of typed table")));
3637 
3638  /*
3639  * Renaming the columns of sequences or toast tables doesn't actually
3640  * break anything from the system's point of view, since internal
3641  * references are by attnum. But it doesn't seem right to allow users to
3642  * change names that are hardcoded into the system, hence the following
3643  * restriction.
3644  */
3645  if (relkind != RELKIND_RELATION &&
3646  relkind != RELKIND_VIEW &&
3647  relkind != RELKIND_MATVIEW &&
3648  relkind != RELKIND_COMPOSITE_TYPE &&
3649  relkind != RELKIND_INDEX &&
3650  relkind != RELKIND_PARTITIONED_INDEX &&
3651  relkind != RELKIND_FOREIGN_TABLE &&
3652  relkind != RELKIND_PARTITIONED_TABLE)
3653  ereport(ERROR,
3654  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3655  errmsg("cannot rename columns of relation \"%s\"",
3656  NameStr(classform->relname)),
3658 
3659  /*
3660  * permissions checking. only the owner of a class can change its schema.
3661  */
3662  if (!object_ownercheck(RelationRelationId, myrelid, GetUserId()))
3664  NameStr(classform->relname));
3665  if (!allowSystemTableMods && IsSystemClass(myrelid, classform))
3666  ereport(ERROR,
3667  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
3668  errmsg("permission denied: \"%s\" is a system catalog",
3669  NameStr(classform->relname))));
3670 }
3671 
3672 /*
3673  * renameatt_internal - workhorse for renameatt
3674  *
3675  * Return value is the attribute number in the 'myrelid' relation.
3676  */
3677 static AttrNumber
3679  const char *oldattname,
3680  const char *newattname,
3681  bool recurse,
3682  bool recursing,
3683  int expected_parents,
3684  DropBehavior behavior)
3685 {
3686  Relation targetrelation;
3687  Relation attrelation;
3688  HeapTuple atttup;
3689  Form_pg_attribute attform;
3691 
3692  /*
3693  * Grab an exclusive lock on the target table, which we will NOT release
3694  * until end of transaction.
3695  */
3696  targetrelation = relation_open(myrelid, AccessExclusiveLock);
3697  renameatt_check(myrelid, RelationGetForm(targetrelation), recursing);
3698 
3699  /*
3700  * if the 'recurse' flag is set then we are supposed to rename this
3701  * attribute in all classes that inherit from 'relname' (as well as in
3702  * 'relname').
3703  *
3704  * any permissions or problems with duplicate attributes will cause the
3705  * whole transaction to abort, which is what we want -- all or nothing.
3706  */
3707  if (recurse)
3708  {
3709  List *child_oids,
3710  *child_numparents;
3711  ListCell *lo,
3712  *li;
3713 
3714  /*
3715  * we need the number of parents for each child so that the recursive
3716  * calls to renameatt() can determine whether there are any parents
3717  * outside the inheritance hierarchy being processed.
3718  */
3719  child_oids = find_all_inheritors(myrelid, AccessExclusiveLock,
3720  &child_numparents);
3721 
3722  /*
3723  * find_all_inheritors does the recursive search of the inheritance
3724  * hierarchy, so all we have to do is process all of the relids in the
3725  * list that it returns.
3726  */
3727  forboth(lo, child_oids, li, child_numparents)
3728  {
3729  Oid childrelid = lfirst_oid(lo);
3730  int numparents = lfirst_int(li);
3731 
3732  if (childrelid == myrelid)
3733  continue;
3734  /* note we need not recurse again */
3735  renameatt_internal(childrelid, oldattname, newattname, false, true, numparents, behavior);
3736  }
3737  }
3738  else
3739  {
3740  /*
3741  * If we are told not to recurse, there had better not be any child
3742  * tables; else the rename would put them out of step.
3743  *
3744  * expected_parents will only be 0 if we are not already recursing.
3745  */
3746  if (expected_parents == 0 &&
3747  find_inheritance_children(myrelid, NoLock) != NIL)
3748  ereport(ERROR,
3749  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
3750  errmsg("inherited column \"%s\" must be renamed in child tables too",
3751  oldattname)));
3752  }
3753 
3754  /* rename attributes in typed tables of composite type */
3755  if (targetrelation->rd_rel->relkind == RELKIND_COMPOSITE_TYPE)
3756  {
3757  List *child_oids;
3758  ListCell *lo;
3759 
3760  child_oids = find_typed_table_dependencies(targetrelation->rd_rel->reltype,
3761  RelationGetRelationName(targetrelation),
3762  behavior);
3763 
3764  foreach(lo, child_oids)
3765  renameatt_internal(lfirst_oid(lo), oldattname, newattname, true, true, 0, behavior);
3766  }
3767 
3768  attrelation = table_open(AttributeRelationId, RowExclusiveLock);
3769 
3770  atttup = SearchSysCacheCopyAttName(myrelid, oldattname);
3771  if (!HeapTupleIsValid(atttup))
3772  ereport(ERROR,
3773  (errcode(ERRCODE_UNDEFINED_COLUMN),
3774  errmsg("column \"%s\" does not exist",
3775  oldattname)));
3776  attform = (Form_pg_attribute) GETSTRUCT(atttup);
3777 
3778  attnum = attform->attnum;
3779  if (attnum <= 0)
3780  ereport(ERROR,
3781  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3782  errmsg("cannot rename system column \"%s\"",
3783  oldattname)));
3784 
3785  /*
3786  * if the attribute is inherited, forbid the renaming. if this is a
3787  * top-level call to renameatt(), then expected_parents will be 0, so the
3788  * effect of this code will be to prohibit the renaming if the attribute
3789  * is inherited at all. if this is a recursive call to renameatt(),
3790  * expected_parents will be the number of parents the current relation has
3791  * within the inheritance hierarchy being processed, so we'll prohibit the
3792  * renaming only if there are additional parents from elsewhere.
3793  */
3794  if (attform->attinhcount > expected_parents)
3795  ereport(ERROR,
3796  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
3797  errmsg("cannot rename inherited column \"%s\"",
3798  oldattname)));
3799 
3800  /* new name should not already exist */
3801  (void) check_for_column_name_collision(targetrelation, newattname, false);
3802 
3803  /* apply the update */
3804  namestrcpy(&(attform->attname), newattname);
3805 
3806  CatalogTupleUpdate(attrelation, &atttup->t_self, atttup);
3807 
3808  InvokeObjectPostAlterHook(RelationRelationId, myrelid, attnum);
3809 
3810  heap_freetuple(atttup);
3811 
3812  table_close(attrelation, RowExclusiveLock);
3813 
3814  relation_close(targetrelation, NoLock); /* close rel but keep lock */
3815 
3816  return attnum;
3817 }
3818 
3819 /*
3820  * Perform permissions and integrity checks before acquiring a relation lock.
3821  */
3822 static void
3824  void *arg)
3825 {
3826  HeapTuple tuple;
3827  Form_pg_class form;
3828 
3829  tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
3830  if (!HeapTupleIsValid(tuple))
3831  return; /* concurrently dropped */
3832  form = (Form_pg_class) GETSTRUCT(tuple);
3833  renameatt_check(relid, form, false);
3834  ReleaseSysCache(tuple);
3835 }
3836 
3837 /*
3838  * renameatt - changes the name of an attribute in a relation
3839  *
3840  * The returned ObjectAddress is that of the renamed column.
3841  */
3844 {
3845  Oid relid;
3847  ObjectAddress address;
3848 
3849  /* lock level taken here should match renameatt_internal */
3851  stmt->missing_ok ? RVR_MISSING_OK : 0,
3853  NULL);
3854 
3855  if (!OidIsValid(relid))
3856  {
3857  ereport(NOTICE,
3858  (errmsg("relation \"%s\" does not exist, skipping",
3859  stmt->relation->relname)));
3860  return InvalidObjectAddress;
3861  }
3862 
3863  attnum =
3864  renameatt_internal(relid,
3865  stmt->subname, /* old att name */
3866  stmt->newname, /* new att name */
3867  stmt->relation->inh, /* recursive? */
3868  false, /* recursing? */
3869  0, /* expected inhcount */
3870  stmt->behavior);
3871 
3872  ObjectAddressSubSet(address, RelationRelationId, relid, attnum);
3873 
3874  return address;
3875 }
3876 
3877 /*
3878  * same logic as renameatt_internal
3879  */
3880 static ObjectAddress
3882  Oid mytypid,
3883  const char *oldconname,
3884  const char *newconname,
3885  bool recurse,
3886  bool recursing,
3887  int expected_parents)
3888 {
3889  Relation targetrelation = NULL;
3890  Oid constraintOid;
3891  HeapTuple tuple;
3892  Form_pg_constraint con;
3893  ObjectAddress address;
3894 
3895  Assert(!myrelid || !mytypid);
3896 
3897  if (mytypid)
3898  {
3899  constraintOid = get_domain_constraint_oid(mytypid, oldconname, false);
3900  }
3901  else
3902  {
3903  targetrelation = relation_open(myrelid, AccessExclusiveLock);
3904 
3905  /*
3906  * don't tell it whether we're recursing; we allow changing typed
3907  * tables here
3908  */
3909  renameatt_check(myrelid, RelationGetForm(targetrelation), false);
3910 
3911  constraintOid = get_relation_constraint_oid(myrelid, oldconname, false);
3912  }
3913 
3914  tuple = SearchSysCache1(CONSTROID, ObjectIdGetDatum(constraintOid));
3915  if (!HeapTupleIsValid(tuple))
3916  elog(ERROR, "cache lookup failed for constraint %u",
3917  constraintOid);
3918  con = (Form_pg_constraint) GETSTRUCT(tuple);
3919 
3920  if (myrelid && con->contype == CONSTRAINT_CHECK && !con->connoinherit)
3921  {
3922  if (recurse)
3923  {
3924  List *child_oids,
3925  *child_numparents;
3926  ListCell *lo,
3927  *li;
3928 
3929  child_oids = find_all_inheritors(myrelid, AccessExclusiveLock,
3930  &child_numparents);
3931 
3932  forboth(lo, child_oids, li, child_numparents)
3933  {
3934  Oid childrelid = lfirst_oid(lo);
3935  int numparents = lfirst_int(li);
3936 
3937  if (childrelid == myrelid)
3938  continue;
3939 
3940  rename_constraint_internal(childrelid, InvalidOid, oldconname, newconname, false, true, numparents);
3941  }
3942  }
3943  else
3944  {
3945  if (expected_parents == 0 &&
3946  find_inheritance_children(myrelid, NoLock) != NIL)
3947  ereport(ERROR,
3948  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
3949  errmsg("inherited constraint \"%s\" must be renamed in child tables too",
3950  oldconname)));
3951  }
3952 
3953  if (con->coninhcount > expected_parents)
3954  ereport(ERROR,
3955  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
3956  errmsg("cannot rename inherited constraint \"%s\"",
3957  oldconname)));
3958  }
3959 
3960  if (con->conindid
3961  && (con->contype == CONSTRAINT_PRIMARY
3962  || con->contype == CONSTRAINT_UNIQUE
3963  || con->contype == CONSTRAINT_EXCLUSION))
3964  /* rename the index; this renames the constraint as well */
3965  RenameRelationInternal(con->conindid, newconname, false, true);
3966  else
3967  RenameConstraintById(constraintOid, newconname);
3968 
3969  ObjectAddressSet(address, ConstraintRelationId, constraintOid);
3970 
3971  ReleaseSysCache(tuple);
3972 
3973  if (targetrelation)
3974  {
3975  /*
3976  * Invalidate relcache so as others can see the new constraint name.
3977  */
3978  CacheInvalidateRelcache(targetrelation);
3979 
3980  relation_close(targetrelation, NoLock); /* close rel but keep lock */
3981  }
3982 
3983  return address;
3984 }
3985 
3988 {
3989  Oid relid = InvalidOid;
3990  Oid typid = InvalidOid;
3991 
3992  if (stmt->renameType == OBJECT_DOMCONSTRAINT)
3993  {
3994  Relation rel;
3995  HeapTuple tup;
3996 
3997  typid = typenameTypeId(NULL, makeTypeNameFromNameList(castNode(List, stmt->object)));
3998  rel = table_open(TypeRelationId, RowExclusiveLock);
3999  tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
4000  if (!HeapTupleIsValid(tup))
4001  elog(ERROR, "cache lookup failed for type %u", typid);
4002  checkDomainOwner(tup);
4003  ReleaseSysCache(tup);
4004  table_close(rel, NoLock);
4005  }
4006  else
4007  {
4008  /* lock level taken here should match rename_constraint_internal */
4010  stmt->missing_ok ? RVR_MISSING_OK : 0,
4012  NULL);
4013  if (!OidIsValid(relid))
4014  {
4015  ereport(NOTICE,
4016  (errmsg("relation \"%s\" does not exist, skipping",
4017  stmt->relation->relname)));
4018  return InvalidObjectAddress;
4019  }
4020  }
4021 
4022  return
4023  rename_constraint_internal(relid, typid,
4024  stmt->subname,
4025  stmt->newname,
4026  (stmt->relation &&
4027  stmt->relation->inh), /* recursive? */
4028  false, /* recursing? */
4029  0 /* expected inhcount */ );
4030 }
4031 
4032 /*
4033  * Execute ALTER TABLE/INDEX/SEQUENCE/VIEW/MATERIALIZED VIEW/FOREIGN TABLE
4034  * RENAME
4035  */
4038 {
4039  bool is_index_stmt = stmt->renameType == OBJECT_INDEX;
4040  Oid relid;
4041  ObjectAddress address;
4042 
4043  /*
4044  * Grab an exclusive lock on the target table, index, sequence, view,
4045  * materialized view, or foreign table, which we will NOT release until
4046  * end of transaction.
4047  *
4048  * Lock level used here should match RenameRelationInternal, to avoid lock
4049  * escalation. However, because ALTER INDEX can be used with any relation
4050  * type, we mustn't believe without verification.
4051  */
4052  for (;;)
4053  {
4054  LOCKMODE lockmode;
4055  char relkind;
4056  bool obj_is_index;
4057 
4058  lockmode = is_index_stmt ? ShareUpdateExclusiveLock : AccessExclusiveLock;
4059 
4060  relid = RangeVarGetRelidExtended(stmt->relation, lockmode,
4061  stmt->missing_ok ? RVR_MISSING_OK : 0,
4063  (void *) stmt);
4064 
4065  if (!OidIsValid(relid))
4066  {
4067  ereport(NOTICE,
4068  (errmsg("relation \"%s\" does not exist, skipping",
4069  stmt->relation->relname)));
4070  return InvalidObjectAddress;
4071  }
4072 
4073  /*
4074  * We allow mismatched statement and object types (e.g., ALTER INDEX
4075  * to rename a table), but we might've used the wrong lock level. If
4076  * that happens, retry with the correct lock level. We don't bother
4077  * if we already acquired AccessExclusiveLock with an index, however.
4078  */
4079  relkind = get_rel_relkind(relid);
4080  obj_is_index = (relkind == RELKIND_INDEX ||
4081  relkind == RELKIND_PARTITIONED_INDEX);
4082  if (obj_is_index || is_index_stmt == obj_is_index)
4083  break;
4084 
4085  UnlockRelationOid(relid, lockmode);
4086  is_index_stmt = obj_is_index;
4087  }
4088 
4089  /* Do the work */
4090  RenameRelationInternal(relid, stmt->newname, false, is_index_stmt);
4091 
4092  ObjectAddressSet(address, RelationRelationId, relid);
4093 
4094  return address;
4095 }
4096 
4097 /*
4098  * RenameRelationInternal - change the name of a relation
4099  */
4100 void
4101 RenameRelationInternal(Oid myrelid, const char *newrelname, bool is_internal, bool is_index)
4102 {
4103  Relation targetrelation;
4104  Relation relrelation; /* for RELATION relation */
4105  HeapTuple reltup;
4106  Form_pg_class relform;
4107  Oid namespaceId;
4108 
4109  /*
4110  * Grab a lock on the target relation, which we will NOT release until end
4111  * of transaction. We need at least a self-exclusive lock so that
4112  * concurrent DDL doesn't overwrite the rename if they start updating
4113  * while still seeing the old version. The lock also guards against
4114  * triggering relcache reloads in concurrent sessions, which might not
4115  * handle this information changing under them. For indexes, we can use a
4116  * reduced lock level because RelationReloadIndexInfo() handles indexes
4117  * specially.
4118  */
4119  targetrelation = relation_open(myrelid, is_index ? ShareUpdateExclusiveLock : AccessExclusiveLock);
4120  namespaceId = RelationGetNamespace(targetrelation);
4121 
4122  /*
4123  * Find relation's pg_class tuple, and make sure newrelname isn't in use.
4124  */
4125  relrelation = table_open(RelationRelationId, RowExclusiveLock);
4126 
4127  reltup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(myrelid));
4128  if (!HeapTupleIsValid(reltup)) /* shouldn't happen */
4129  elog(ERROR, "cache lookup failed for relation %u", myrelid);
4130  relform = (Form_pg_class) GETSTRUCT(reltup);
4131 
4132  if (get_relname_relid(newrelname, namespaceId) != InvalidOid)
4133  ereport(ERROR,
4134  (errcode(ERRCODE_DUPLICATE_TABLE),
4135  errmsg("relation \"%s\" already exists",
4136  newrelname)));
4137 
4138  /*
4139  * RenameRelation is careful not to believe the caller's idea of the
4140  * relation kind being handled. We don't have to worry about this, but
4141  * let's not be totally oblivious to it. We can process an index as
4142  * not-an-index, but not the other way around.
4143  */
4144  Assert(!is_index ||
4145  is_index == (targetrelation->rd_rel->relkind == RELKIND_INDEX ||
4146  targetrelation->rd_rel->relkind == RELKIND_PARTITIONED_INDEX));
4147 
4148  /*
4149  * Update pg_class tuple with new relname. (Scribbling on reltup is OK
4150  * because it's a copy...)
4151  */
4152  namestrcpy(&(relform->relname), newrelname);
4153 
4154  CatalogTupleUpdate(relrelation, &reltup->t_self, reltup);
4155 
4156  InvokeObjectPostAlterHookArg(RelationRelationId, myrelid, 0,
4157  InvalidOid, is_internal);
4158 
4159  heap_freetuple(reltup);
4160  table_close(relrelation, RowExclusiveLock);
4161 
4162  /*
4163  * Also rename the associated type, if any.
4164  */
4165  if (OidIsValid(targetrelation->rd_rel->reltype))
4166  RenameTypeInternal(targetrelation->rd_rel->reltype,
4167  newrelname, namespaceId);
4168 
4169  /*
4170  * Also rename the associated constraint, if any.
4171  */
4172  if (targetrelation->rd_rel->relkind == RELKIND_INDEX ||
4173  targetrelation->rd_rel->relkind == RELKIND_PARTITIONED_INDEX)
4174  {
4175  Oid constraintId = get_index_constraint(myrelid);
4176 
4177  if (OidIsValid(constraintId))
4178  RenameConstraintById(constraintId, newrelname);
4179  }
4180 
4181  /*
4182  * Close rel, but keep lock!
4183  */
4184  relation_close(targetrelation, NoLock);
4185 }
4186 
4187 /*
4188  * ResetRelRewrite - reset relrewrite
4189  */
4190 void
4192 {
4193  Relation relrelation; /* for RELATION relation */
4194  HeapTuple reltup;
4195  Form_pg_class relform;
4196 
4197  /*
4198  * Find relation's pg_class tuple.
4199  */
4200  relrelation = table_open(RelationRelationId, RowExclusiveLock);
4201 
4202  reltup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(myrelid));
4203  if (!HeapTupleIsValid(reltup)) /* shouldn't happen */
4204  elog(ERROR, "cache lookup failed for relation %u", myrelid);
4205  relform = (Form_pg_class) GETSTRUCT(reltup);
4206 
4207  /*
4208  * Update pg_class tuple.
4209  */
4210  relform->relrewrite = InvalidOid;
4211 
4212  CatalogTupleUpdate(relrelation, &reltup->t_self, reltup);
4213 
4214  heap_freetuple(reltup);
4215  table_close(relrelation, RowExclusiveLock);
4216 }
4217 
4218 /*
4219  * Disallow ALTER TABLE (and similar commands) when the current backend has
4220  * any open reference to the target table besides the one just acquired by
4221  * the calling command; this implies there's an open cursor or active plan.
4222  * We need this check because our lock doesn't protect us against stomping
4223  * on our own foot, only other people's feet!
4224  *
4225  * For ALTER TABLE, the only case known to cause serious trouble is ALTER
4226  * COLUMN TYPE, and some changes are obviously pretty benign, so this could
4227  * possibly be relaxed to only error out for certain types of alterations.
4228  * But the use-case for allowing any of these things is not obvious, so we
4229  * won't work hard at it for now.
4230  *
4231  * We also reject these commands if there are any pending AFTER trigger events
4232  * for the rel. This is certainly necessary for the rewriting variants of
4233  * ALTER TABLE, because they don't preserve tuple TIDs and so the pending
4234  * events would try to fetch the wrong tuples. It might be overly cautious
4235  * in other cases, but again it seems better to err on the side of paranoia.
4236  *
4237  * REINDEX calls this with "rel" referencing the index to be rebuilt; here
4238  * we are worried about active indexscans on the index. The trigger-event
4239  * check can be skipped, since we are doing no damage to the parent table.
4240  *
4241  * The statement name (eg, "ALTER TABLE") is passed for use in error messages.
4242  */
4243 void
4245 {
4246  int expected_refcnt;
4247 
4248  expected_refcnt = rel->rd_isnailed ? 2 : 1;
4249  if (rel->rd_refcnt != expected_refcnt)
4250  ereport(ERROR,
4251  (errcode(ERRCODE_OBJECT_IN_USE),
4252  /* translator: first %s is a SQL command, eg ALTER TABLE */
4253  errmsg("cannot %s \"%s\" because it is being used by active queries in this session",
4254  stmt, RelationGetRelationName(rel))));
4255 
4256  if (rel->rd_rel->relkind != RELKIND_INDEX &&
4257  rel->rd_rel->relkind != RELKIND_PARTITIONED_INDEX &&
4259  ereport(ERROR,
4260  (errcode(ERRCODE_OBJECT_IN_USE),
4261  /* translator: first %s is a SQL command, eg ALTER TABLE */
4262  errmsg("cannot %s \"%s\" because it has pending trigger events",
4263  stmt, RelationGetRelationName(rel))));
4264 }
4265 
4266 /*
4267  * CheckAlterTableIsSafe
4268  * Verify that it's safe to allow ALTER TABLE on this relation.
4269  *
4270  * This consists of CheckTableNotInUse() plus a check that the relation
4271  * isn't another session's temp table. We must split out the temp-table
4272  * check because there are callers of CheckTableNotInUse() that don't want
4273  * that, notably DROP TABLE. (We must allow DROP or we couldn't clean out
4274  * an orphaned temp schema.) Compare truncate_check_activity().
4275  */
4276 static void
4278 {
4279  /*
4280  * Don't allow ALTER on temp tables of other backends. Their local buffer
4281  * manager is not going to cope if we need to change the table's contents.
4282  * Even if we don't, there may be optimizations that assume temp tables
4283  * aren't subject to such interference.
4284  */
4285  if (RELATION_IS_OTHER_TEMP(rel))
4286  ereport(ERROR,
4287  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
4288  errmsg("cannot alter temporary tables of other sessions")));
4289 
4290  /*
4291  * Also check for active uses of the relation in the current transaction,
4292  * including open scans and pending AFTER trigger events.
4293  */
4294  CheckTableNotInUse(rel, "ALTER TABLE");
4295 }
4296 
4297 /*
4298  * AlterTableLookupRelation
4299  * Look up, and lock, the OID for the relation named by an alter table
4300  * statement.
4301  */
4302 Oid
4304 {
4305  return RangeVarGetRelidExtended(stmt->relation, lockmode,
4306  stmt->missing_ok ? RVR_MISSING_OK : 0,
4308  (void *) stmt);
4309 }
4310 
4311 /*
4312  * AlterTable
4313  * Execute ALTER TABLE, which can be a list of subcommands
4314  *
4315  * ALTER TABLE is performed in three phases:
4316  * 1. Examine subcommands and perform pre-transformation checking.
4317  * 2. Validate and transform subcommands, and update system catalogs.
4318  * 3. Scan table(s) to check new constraints, and optionally recopy
4319  * the data into new table(s).
4320  * Phase 3 is not performed unless one or more of the subcommands requires
4321  * it. The intention of this design is to allow multiple independent
4322  * updates of the table schema to be performed with only one pass over the
4323  * data.
4324  *
4325  * ATPrepCmd performs phase 1. A "work queue" entry is created for
4326  * each table to be affected (there may be multiple affected tables if the
4327  * commands traverse a table inheritance hierarchy). Also we do preliminary
4328  * validation of the subcommands. Because earlier subcommands may change
4329  * the catalog state seen by later commands, there are limits to what can
4330  * be done in this phase. Generally, this phase acquires table locks,
4331  * checks permissions and relkind, and recurses to find child tables.
4332  *
4333  * ATRewriteCatalogs performs phase 2 for each affected table.
4334  * Certain subcommands need to be performed before others to avoid
4335  * unnecessary conflicts; for example, DROP COLUMN should come before
4336  * ADD COLUMN. Therefore phase 1 divides the subcommands into multiple
4337  * lists, one for each logical "pass" of phase 2.
4338  *
4339  * ATRewriteTables performs phase 3 for those tables that need it.
4340  *
4341  * For most subcommand types, phases 2 and 3 do no explicit recursion,
4342  * since phase 1 already does it. However, for certain subcommand types
4343  * it is only possible to determine how to recurse at phase 2 time; for
4344  * those cases, phase 1 sets the cmd->recurse flag.
4345  *
4346  * Thanks to the magic of MVCC, an error anywhere along the way rolls back
4347  * the whole operation; we don't have to do anything special to clean up.
4348  *
4349  * The caller must lock the relation, with an appropriate lock level
4350  * for the subcommands requested, using AlterTableGetLockLevel(stmt->cmds)
4351  * or higher. We pass the lock level down
4352  * so that we can apply it recursively to inherited tables. Note that the
4353  * lock level we want as we recurse might well be higher than required for
4354  * that specific subcommand. So we pass down the overall lock requirement,
4355  * rather than reassess it at lower levels.
4356  *
4357  * The caller also provides a "context" which is to be passed back to
4358  * utility.c when we need to execute a subcommand such as CREATE INDEX.
4359  * Some of the fields therein, such as the relid, are used here as well.
4360  */
4361 void
4364 {
4365  Relation rel;
4366 
4367  /* Caller is required to provide an adequate lock. */
4368  rel = relation_open(context->relid, NoLock);
4369 
4370  CheckAlterTableIsSafe(rel);
4371 
4372  ATController(stmt, rel, stmt->cmds, stmt->relation->inh, lockmode, context);
4373 }
4374 
4375 /*
4376  * AlterTableInternal
4377  *
4378  * ALTER TABLE with target specified by OID
4379  *
4380  * We do not reject if the relation is already open, because it's quite
4381  * likely that one or more layers of caller have it open. That means it
4382  * is unsafe to use this entry point for alterations that could break
4383  * existing query plans. On the assumption it's not used for such, we
4384  * don't have to reject pending AFTER triggers, either.
4385  *
4386  * Also, since we don't have an AlterTableUtilityContext, this cannot be
4387  * used for any subcommand types that require parse transformation or
4388  * could generate subcommands that have to be passed to ProcessUtility.
4389  */
4390 void
4391 AlterTableInternal(Oid relid, List *cmds, bool recurse)
4392 {
4393  Relation rel;
4394  LOCKMODE lockmode = AlterTableGetLockLevel(cmds);
4395 
4396  rel = relation_open(relid, lockmode);
4397 
4399 
4400  ATController(NULL, rel, cmds, recurse, lockmode, NULL);
4401 }
4402 
4403 /*
4404  * AlterTableGetLockLevel
4405  *
4406  * Sets the overall lock level required for the supplied list of subcommands.
4407  * Policy for doing this set according to needs of AlterTable(), see
4408  * comments there for overall explanation.
4409  *
4410  * Function is called before and after parsing, so it must give same
4411  * answer each time it is called. Some subcommands are transformed
4412  * into other subcommand types, so the transform must never be made to a
4413  * lower lock level than previously assigned. All transforms are noted below.
4414  *
4415  * Since this is called before we lock the table we cannot use table metadata
4416  * to influence the type of lock we acquire.
4417  *
4418  * There should be no lockmodes hardcoded into the subcommand functions. All
4419  * lockmode decisions for ALTER TABLE are made here only. The one exception is
4420  * ALTER TABLE RENAME which is treated as a different statement type T_RenameStmt
4421  * and does not travel through this section of code and cannot be combined with
4422  * any of the subcommands given here.
4423  *
4424  * Note that Hot Standby only knows about AccessExclusiveLocks on the primary
4425  * so any changes that might affect SELECTs running on standbys need to use
4426  * AccessExclusiveLocks even if you think a lesser lock would do, unless you
4427  * have a solution for that also.
4428  *
4429  * Also note that pg_dump uses only an AccessShareLock, meaning that anything
4430  * that takes a lock less than AccessExclusiveLock can change object definitions
4431  * while pg_dump is running. Be careful to check that the appropriate data is
4432  * derived by pg_dump using an MVCC snapshot, rather than syscache lookups,
4433  * otherwise we might end up with an inconsistent dump that can't restore.
4434  */
4435 LOCKMODE
4437 {
4438  /*
4439  * This only works if we read catalog tables using MVCC snapshots.
4440  */
4441  ListCell *lcmd;
4443 
4444  foreach(lcmd, cmds)
4445  {
4446  AlterTableCmd *cmd = (AlterTableCmd *) lfirst(lcmd);
4447  LOCKMODE cmd_lockmode = AccessExclusiveLock; /* default for compiler */
4448 
4449  switch (cmd->subtype)
4450  {
4451  /*
4452  * These subcommands rewrite the heap, so require full locks.
4453  */
4454  case AT_AddColumn: /* may rewrite heap, in some cases and visible
4455  * to SELECT */
4456  case AT_SetAccessMethod: /* must rewrite heap */
4457  case AT_SetTableSpace: /* must rewrite heap */
4458  case AT_AlterColumnType: /* must rewrite heap */
4459  cmd_lockmode = AccessExclusiveLock;
4460  break;
4461 
4462  /*
4463  * These subcommands may require addition of toast tables. If
4464  * we add a toast table to a table currently being scanned, we
4465  * might miss data added to the new toast table by concurrent
4466  * insert transactions.
4467  */
4468  case AT_SetStorage: /* may add toast tables, see
4469  * ATRewriteCatalogs() */
4470  cmd_lockmode = AccessExclusiveLock;
4471  break;
4472 
4473  /*
4474  * Removing constraints can affect SELECTs that have been
4475  * optimized assuming the constraint holds true. See also
4476  * CloneFkReferenced.
4477  */
4478  case AT_DropConstraint: /* as DROP INDEX */
4479  case AT_DropNotNull: /* may change some SQL plans */
4480  cmd_lockmode = AccessExclusiveLock;
4481  break;
4482 
4483  /*
4484  * Subcommands that may be visible to concurrent SELECTs
4485  */
4486  case AT_DropColumn: /* change visible to SELECT */
4487  case AT_AddColumnToView: /* CREATE VIEW */
4488  case AT_DropOids: /* used to equiv to DropColumn */
4489  case AT_EnableAlwaysRule: /* may change SELECT rules */
4490  case AT_EnableReplicaRule: /* may change SELECT rules */
4491  case AT_EnableRule: /* may change SELECT rules */
4492  case AT_DisableRule: /* may change SELECT rules */
4493  cmd_lockmode = AccessExclusiveLock;
4494  break;
4495 
4496  /*
4497  * Changing owner may remove implicit SELECT privileges
4498  */
4499  case AT_ChangeOwner: /* change visible to SELECT */
4500  cmd_lockmode = AccessExclusiveLock;
4501  break;
4502 
4503  /*
4504  * Changing foreign table options may affect optimization.
4505  */
4506  case AT_GenericOptions:
4508  cmd_lockmode = AccessExclusiveLock;
4509  break;
4510 
4511  /*
4512  * These subcommands affect write operations only.
4513  */
4514  case AT_EnableTrig:
4515  case AT_EnableAlwaysTrig:
4516  case AT_EnableReplicaTrig:
4517  case AT_EnableTrigAll:
4518  case AT_EnableTrigUser:
4519  case AT_DisableTrig:
4520  case AT_DisableTrigAll:
4521  case AT_DisableTrigUser:
4522  cmd_lockmode = ShareRowExclusiveLock;
4523  break;
4524 
4525  /*
4526  * These subcommands affect write operations only. XXX
4527  * Theoretically, these could be ShareRowExclusiveLock.
4528  */
4529  case AT_ColumnDefault:
4531  case AT_AlterConstraint:
4532  case AT_AddIndex: /* from ADD CONSTRAINT */
4533  case AT_AddIndexConstraint:
4534  case AT_ReplicaIdentity:
4535  case AT_SetNotNull:
4536  case AT_EnableRowSecurity:
4537  case AT_DisableRowSecurity:
4538  case AT_ForceRowSecurity:
4539  case AT_NoForceRowSecurity:
4540  case AT_AddIdentity:
4541  case AT_DropIdentity:
4542  case AT_SetIdentity:
4543  case AT_SetExpression:
4544  case AT_DropExpression:
4545  case AT_SetCompression:
4546  cmd_lockmode = AccessExclusiveLock;
4547  break;
4548 
4549  case AT_AddConstraint:
4550  case AT_ReAddConstraint: /* becomes AT_AddConstraint */
4551  case AT_ReAddDomainConstraint: /* becomes AT_AddConstraint */
4552  if (IsA(cmd->def, Constraint))
4553  {
4554  Constraint *con = (Constraint *) cmd->def;
4555 
4556  switch (con->contype)
4557  {
4558  case CONSTR_EXCLUSION:
4559  case CONSTR_PRIMARY:
4560  case CONSTR_UNIQUE:
4561 
4562  /*
4563  * Cases essentially the same as CREATE INDEX. We
4564  * could reduce the lock strength to ShareLock if
4565  * we can work out how to allow concurrent catalog
4566  * updates. XXX Might be set down to
4567  * ShareRowExclusiveLock but requires further
4568  * analysis.
4569  */
4570  cmd_lockmode = AccessExclusiveLock;
4571  break;
4572  case CONSTR_FOREIGN:
4573 
4574  /*
4575  * We add triggers to both tables when we add a
4576  * Foreign Key, so the lock level must be at least
4577  * as strong as CREATE TRIGGER.
4578  */
4579  cmd_lockmode = ShareRowExclusiveLock;
4580  break;
4581 
4582  default:
4583  cmd_lockmode = AccessExclusiveLock;
4584  }
4585  }
4586  break;
4587 
4588  /*
4589  * These subcommands affect inheritance behaviour. Queries
4590  * started before us will continue to see the old inheritance
4591  * behaviour, while queries started after we commit will see
4592  * new behaviour. No need to prevent reads or writes to the
4593  * subtable while we hook it up though. Changing the TupDesc
4594  * may be a problem, so keep highest lock.
4595  */
4596  case AT_AddInherit:
4597  case AT_DropInherit:
4598  cmd_lockmode = AccessExclusiveLock;
4599  break;
4600 
4601  /*
4602  * These subcommands affect implicit row type conversion. They
4603  * have affects similar to CREATE/DROP CAST on queries. don't
4604  * provide for invalidating parse trees as a result of such
4605  * changes, so we keep these at AccessExclusiveLock.
4606  */
4607  case AT_AddOf:
4608  case AT_DropOf:
4609  cmd_lockmode = AccessExclusiveLock;
4610  break;
4611 
4612  /*
4613  * Only used by CREATE OR REPLACE VIEW which must conflict
4614  * with an SELECTs currently using the view.
4615  */
4616  case AT_ReplaceRelOptions:
4617  cmd_lockmode = AccessExclusiveLock;
4618  break;
4619 
4620  /*
4621  * These subcommands affect general strategies for performance
4622  * and maintenance, though don't change the semantic results
4623  * from normal data reads and writes. Delaying an ALTER TABLE
4624  * behind currently active writes only delays the point where
4625  * the new strategy begins to take effect, so there is no
4626  * benefit in waiting. In this case the minimum restriction
4627  * applies: we don't currently allow concurrent catalog
4628  * updates.
4629  */
4630  case AT_SetStatistics: /* Uses MVCC in getTableAttrs() */
4631  case AT_ClusterOn: /* Uses MVCC in getIndexes() */
4632  case AT_DropCluster: /* Uses MVCC in getIndexes() */
4633  case AT_SetOptions: /* Uses MVCC in getTableAttrs() */
4634  case AT_ResetOptions: /* Uses MVCC in getTableAttrs() */
4635  cmd_lockmode = ShareUpdateExclusiveLock;
4636  break;
4637 
4638  case AT_SetLogged:
4639  case AT_SetUnLogged:
4640  cmd_lockmode = AccessExclusiveLock;
4641  break;
4642 
4643  case AT_ValidateConstraint: /* Uses MVCC in getConstraints() */
4644  cmd_lockmode = ShareUpdateExclusiveLock;
4645  break;
4646 
4647  /*
4648  * Rel options are more complex than first appears. Options
4649  * are set here for tables, views and indexes; for historical
4650  * reasons these can all be used with ALTER TABLE, so we can't
4651  * decide between them using the basic grammar.
4652  */
4653  case AT_SetRelOptions: /* Uses MVCC in getIndexes() and
4654  * getTables() */
4655  case AT_ResetRelOptions: /* Uses MVCC in getIndexes() and
4656  * getTables() */
4657  cmd_lockmode = AlterTableGetRelOptionsLockLevel((List *) cmd->def);
4658  break;
4659 
4660  case AT_AttachPartition:
4661  cmd_lockmode = ShareUpdateExclusiveLock;
4662  break;
4663 
4664  case AT_DetachPartition:
4665  if (((PartitionCmd *) cmd->def)->concurrent)
4666  cmd_lockmode = ShareUpdateExclusiveLock;
4667  else
4668  cmd_lockmode = AccessExclusiveLock;
4669  break;
4670 
4672  cmd_lockmode = ShareUpdateExclusiveLock;
4673  break;
4674 
4675  case AT_SplitPartition:
4676  cmd_lockmode = AccessExclusiveLock;
4677  break;
4678 
4679  case AT_MergePartitions:
4680  cmd_lockmode = AccessExclusiveLock;
4681  break;
4682 
4683  case AT_CheckNotNull:
4684 
4685  /*
4686  * This only examines the table's schema; but lock must be
4687  * strong enough to prevent concurrent DROP NOT NULL.
4688  */
4689  cmd_lockmode = AccessShareLock;
4690  break;
4691 
4692  default: /* oops */
4693  elog(ERROR, "unrecognized alter table type: %d",
4694  (int) cmd->subtype);
4695  break;
4696  }
4697 
4698  /*
4699  * Take the greatest lockmode from any subcommand
4700  */
4701  if (cmd_lockmode > lockmode)
4702  lockmode = cmd_lockmode;
4703  }
4704 
4705  return lockmode;
4706 }
4707 
4708 /*
4709  * ATController provides top level control over the phases.
4710  *
4711  * parsetree is passed in to allow it to be passed to event triggers
4712  * when requested.
4713  */
4714 static void
4716  Relation rel, List *cmds, bool recurse, LOCKMODE lockmode,
4718 {
4719  List *wqueue = NIL;
4720  ListCell *lcmd;
4721 
4722  /* Phase 1: preliminary examination of commands, create work queue */
4723  foreach(lcmd, cmds)
4724  {
4725  AlterTableCmd *cmd = (AlterTableCmd *) lfirst(lcmd);
4726 
4727  ATPrepCmd(&wqueue, rel, cmd, recurse, false, lockmode, context);
4728  }
4729 
4730  /* Close the relation, but keep lock until commit */
4731  relation_close(rel, NoLock);
4732 
4733  /* Phase 2: update system catalogs */
4734  ATRewriteCatalogs(&wqueue, lockmode, context);
4735 
4736  /* Phase 3: scan/rewrite tables as needed, and run afterStmts */
4737  ATRewriteTables(parsetree, &wqueue, lockmode, context);
4738 }
4739 
4740 /*
4741  * ATPrepCmd
4742  *
4743  * Traffic cop for ALTER TABLE Phase 1 operations, including simple
4744  * recursion and permission checks.
4745  *
4746  * Caller must have acquired appropriate lock type on relation already.
4747  * This lock should be held until commit.
4748  */
4749 static void
4750 ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd,
4751  bool recurse, bool recursing, LOCKMODE lockmode,
4753 {
4754  AlteredTableInfo *tab;
4756 
4757  /* Find or create work queue entry for this table */
4758  tab = ATGetQueueEntry(wqueue, rel);
4759 
4760  /*
4761  * Disallow any ALTER TABLE other than ALTER TABLE DETACH FINALIZE on
4762  * partitions that are pending detach.
4763  */
4764  if (rel->rd_rel->relispartition &&
4767  ereport(ERROR,
4768  errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
4769  errmsg("cannot alter partition \"%s\" with an incomplete detach",
4771  errhint("Use ALTER TABLE ... DETACH PARTITION ... FINALIZE to complete the pending detach operation."));
4772 
4773  /*
4774  * Copy the original subcommand for each table, so we can scribble on it.
4775  * This avoids conflicts when different child tables need to make
4776  * different parse transformations (for example, the same column may have
4777  * different column numbers in different children).
4778  */
4779  cmd = copyObject(cmd);
4780 
4781  /*
4782  * Do permissions and relkind checking, recursion to child tables if
4783  * needed, and any additional phase-1 processing needed. (But beware of
4784  * adding any processing that looks at table details that another
4785  * subcommand could change. In some cases we reject multiple subcommands
4786  * that could try to change the same state in contrary ways.)
4787  */
4788  switch (cmd->subtype)
4789  {
4790  case AT_AddColumn: /* ADD COLUMN */
4791  ATSimplePermissions(cmd->subtype, rel,
4793  ATPrepAddColumn(wqueue, rel, recurse, recursing, false, cmd,
4794  lockmode, context);
4795  /* Recursion occurs during execution phase */
4796  pass = AT_PASS_ADD_COL;
4797  break;
4798  case AT_AddColumnToView: /* add column via CREATE OR REPLACE VIEW */
4799  ATSimplePermissions(cmd->subtype, rel, ATT_VIEW);
4800  ATPrepAddColumn(wqueue, rel, recurse, recursing, true, cmd,
4801  lockmode, context);
4802  /* Recursion occurs during execution phase */
4803  pass = AT_PASS_ADD_COL;
4804  break;
4805  case AT_ColumnDefault: /* ALTER COLUMN DEFAULT */
4806 
4807  /*
4808  * We allow defaults on views so that INSERT into a view can have
4809  * default-ish behavior. This works because the rewriter
4810  * substitutes default values into INSERTs before it expands
4811  * rules.
4812  */
4814  ATSimpleRecursion(wqueue, rel, cmd, recurse, lockmode, context);
4815  /* No command-specific prep needed */
4816  pass = cmd->def ? AT_PASS_ADD_OTHERCONSTR : AT_PASS_DROP;
4817  break;
4818  case AT_CookedColumnDefault: /* add a pre-cooked default */
4819  /* This is currently used only in CREATE TABLE */
4820  /* (so the permission check really isn't necessary) */
4822  /* This command never recurses */
4823  pass = AT_PASS_ADD_OTHERCONSTR;
4824  break;
4825  case AT_AddIdentity:
4827  /* Set up recursion for phase 2; no other prep needed */
4828  if (recurse)
4829  cmd->recurse = true;
4830  pass = AT_PASS_ADD_OTHERCONSTR;
4831  break;
4832  case AT_SetIdentity:
4834  /* Set up recursion for phase 2; no other prep needed */
4835  if (recurse)
4836  cmd->recurse = true;
4837  /* This should run after AddIdentity, so do it in MISC pass */
4838  pass = AT_PASS_MISC;
4839  break;
4840  case AT_DropIdentity:
4842  /* Set up recursion for phase 2; no other prep needed */
4843  if (recurse)
4844  cmd->recurse = true;
4845  pass = AT_PASS_DROP;
4846  break;
4847  case AT_DropNotNull: /* ALTER COLUMN DROP NOT NULL */
4849  ATPrepDropNotNull(rel, recurse, recursing);
4850  ATSimpleRecursion(wqueue, rel, cmd, recurse, lockmode, context);
4851  pass = AT_PASS_DROP;
4852  break;
4853  case AT_SetNotNull: /* ALTER COLUMN SET NOT NULL */
4855  /* Need command-specific recursion decision */
4856  ATPrepSetNotNull(wqueue, rel, cmd, recurse, recursing,
4857  lockmode, context);
4858  pass = AT_PASS_COL_ATTRS;
4859  break;
4860  case AT_CheckNotNull: /* check column is already marked NOT NULL */
4862  ATSimpleRecursion(wqueue, rel, cmd, recurse, lockmode, context);
4863  /* No command-specific prep needed */
4864  pass = AT_PASS_COL_ATTRS;
4865  break;
4866  case AT_SetExpression: /* ALTER COLUMN SET EXPRESSION */
4868  ATSimpleRecursion(wqueue, rel, cmd, recurse, lockmode, context);
4869  pass = AT_PASS_SET_EXPRESSION;
4870  break;
4871  case AT_DropExpression: /* ALTER COLUMN DROP EXPRESSION */
4873  ATSimpleRecursion(wqueue, rel, cmd, recurse, lockmode, context);
4874  ATPrepDropExpression(rel, cmd, recurse, recursing, lockmode);
4875  pass = AT_PASS_DROP;
4876  break;
4877  case AT_SetStatistics: /* ALTER COLUMN SET STATISTICS */
4879  ATSimpleRecursion(wqueue, rel, cmd, recurse, lockmode, context);
4880  /* No command-specific prep needed */
4881  pass = AT_PASS_MISC;
4882  break;
4883  case AT_SetOptions: /* ALTER COLUMN SET ( options ) */
4884  case AT_ResetOptions: /* ALTER COLUMN RESET ( options ) */
4886  /* This command never recurses */
4887  pass = AT_PASS_MISC;
4888  break;
4889  case AT_SetStorage: /* ALTER COLUMN SET STORAGE */
4891  ATSimpleRecursion(wqueue, rel, cmd, recurse, lockmode, context);
4892  /* No command-specific prep needed */
4893  pass = AT_PASS_MISC;
4894  break;
4895  case AT_SetCompression: /* ALTER COLUMN SET COMPRESSION */
4897  /* This command never recurses */
4898  /* No command-specific prep needed */
4899  pass = AT_PASS_MISC;
4900  break;
4901  case AT_DropColumn: /* DROP COLUMN */
4902  ATSimplePermissions(cmd->subtype, rel,
4904  ATPrepDropColumn(wqueue, rel, recurse, recursing, cmd,
4905  lockmode, context);
4906  /* Recursion occurs during execution phase */
4907  pass = AT_PASS_DROP;
4908  break;
4909  case AT_AddIndex: /* ADD INDEX */
4911  /* This command never recurses */
4912  /* No command-specific prep needed */
4913  pass = AT_PASS_ADD_INDEX;
4914  break;
4915  case AT_AddConstraint: /* ADD CONSTRAINT */
4917  /* Recursion occurs during execution phase */
4918  /* No command-specific prep needed except saving recurse flag */
4919  if (recurse)
4920  cmd->recurse = true;
4921  pass = AT_PASS_ADD_CONSTR;
4922  break;
4923  case AT_AddIndexConstraint: /* ADD CONSTRAINT USING INDEX */
4925  /* This command never recurses */
4926  /* No command-specific prep needed */
4927  pass = AT_PASS_ADD_INDEXCONSTR;
4928  break;
4929  case AT_DropConstraint: /* DROP CONSTRAINT */
4931  ATCheckPartitionsNotInUse(rel, lockmode);
4932  /* Other recursion occurs during execution phase */
4933  /* No command-specific prep needed except saving recurse flag */
4934  if (recurse)
4935  cmd->recurse = true;
4936  pass = AT_PASS_DROP;
4937  break;
4938  case AT_AlterColumnType: /* ALTER COLUMN TYPE */
4939  ATSimplePermissions(cmd->subtype, rel,
4941  /* See comments for ATPrepAlterColumnType */
4942  cmd = ATParseTransformCmd(wqueue, tab, rel, cmd, recurse, lockmode,
4944  Assert(cmd != NULL);
4945  /* Performs own recursion */
4946  ATPrepAlterColumnType(wqueue, tab, rel, recurse, recursing, cmd,
4947  lockmode, context);
4948  pass = AT_PASS_ALTER_TYPE;
4949  break;
4952  /* This command never recurses */
4953  /* No command-specific prep needed */
4954  pass = AT_PASS_MISC;
4955  break;
4956  case AT_ChangeOwner: /* ALTER OWNER */
4957  /* This command never recurses */
4958  /* No command-specific prep needed */
4959  pass = AT_PASS_MISC;
4960  break;
4961  case AT_ClusterOn: /* CLUSTER ON */
4962  case AT_DropCluster: /* SET WITHOUT CLUSTER */
4964  /* These commands never recurse */
4965  /* No command-specific prep needed */
4966  pass = AT_PASS_MISC;
4967  break;
4968  case AT_SetLogged: /* SET LOGGED */
4970  if (tab->chgPersistence)
4971  ereport(ERROR,
4972  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
4973  errmsg("cannot change persistence setting twice")));
4974  tab->chgPersistence = ATPrepChangePersistence(rel, true);
4975  /* force rewrite if necessary; see comment in ATRewriteTables */
4976  if (tab->chgPersistence)
4977  {
4979  tab->newrelpersistence = RELPERSISTENCE_PERMANENT;
4980  }
4981  pass = AT_PASS_MISC;
4982  break;
4983  case AT_SetUnLogged: /* SET UNLOGGED */
4985  if (tab->chgPersistence)
4986  ereport(ERROR,
4987  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
4988  errmsg("cannot change persistence setting twice")));
4989  tab->chgPersistence = ATPrepChangePersistence(rel, false);
4990  /* force rewrite if necessary; see comment in ATRewriteTables */
4991  if (tab->chgPersistence)
4992  {
4994  tab->newrelpersistence = RELPERSISTENCE_UNLOGGED;
4995  }
4996  pass = AT_PASS_MISC;
4997  break;
4998  case AT_DropOids: /* SET WITHOUT OIDS */
5000  pass = AT_PASS_DROP;
5001  break;
5002  case AT_SetAccessMethod: /* SET ACCESS METHOD */
5004 
5005  /* check if another access method change was already requested */
5006  if (tab->chgAccessMethod)
5007  ereport(ERROR,
5008  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
5009  errmsg("cannot have multiple SET ACCESS METHOD subcommands")));
5010 
5011  ATPrepSetAccessMethod(tab, rel, cmd->name);
5012  pass = AT_PASS_MISC; /* does not matter; no work in Phase 2 */
5013  break;
5014  case AT_SetTableSpace: /* SET TABLESPACE */
5017  /* This command never recurses */
5018  ATPrepSetTableSpace(tab, rel, cmd->name, lockmode);
5019  pass = AT_PASS_MISC; /* doesn't actually matter */
5020  break;
5021  case AT_SetRelOptions: /* SET (...) */
5022  case AT_ResetRelOptions: /* RESET (...) */
5023  case AT_ReplaceRelOptions: /* reset them all, then set just these */
5025  /* This command never recurses */
5026  /* No command-specific prep needed */
5027  pass = AT_PASS_MISC;
5028  break;
5029  case AT_AddInherit: /* INHERIT */
5031  /* This command never recurses */
5032  ATPrepAddInherit(rel);
5033  pass = AT_PASS_MISC;
5034  break;
5035  case AT_DropInherit: /* NO INHERIT */
5037  /* This command never recurses */
5038  /* No command-specific prep needed */
5039  pass = AT_PASS_MISC;
5040  break;
5041  case AT_AlterConstraint: /* ALTER CONSTRAINT */
5043  /* Recursion occurs during execution phase */
5044  pass = AT_PASS_MISC;
5045  break;
5046  case AT_ValidateConstraint: /* VALIDATE CONSTRAINT */
5048  /* Recursion occurs during execution phase */
5049  /* No command-specific prep needed except saving recurse flag */
5050  if (recurse)
5051  cmd->recurse = true;
5052  pass = AT_PASS_MISC;
5053  break;
5054  case AT_ReplicaIdentity: /* REPLICA IDENTITY ... */
5056  pass = AT_PASS_MISC;
5057  /* This command never recurses */
5058  /* No command-specific prep needed */
5059  break;
5060  case AT_EnableTrig: /* ENABLE TRIGGER variants */
5061  case AT_EnableAlwaysTrig:
5062  case AT_EnableReplicaTrig:
5063  case AT_EnableTrigAll:
5064  case AT_EnableTrigUser:
5065  case AT_DisableTrig: /* DISABLE TRIGGER variants */
5066  case AT_DisableTrigAll:
5067  case AT_DisableTrigUser:
5069  /* Set up recursion for phase 2; no other prep needed */
5070  if (recurse)
5071  cmd->recurse = true;
5072  pass = AT_PASS_MISC;
5073  break;
5074  case AT_EnableRule: /* ENABLE/DISABLE RULE variants */
5075  case AT_EnableAlwaysRule:
5076  case AT_EnableReplicaRule:
5077  case AT_DisableRule:
5078  case AT_AddOf: /* OF */
5079  case AT_DropOf: /* NOT OF */
5080  case AT_EnableRowSecurity:
5081  case AT_DisableRowSecurity:
5082  case AT_ForceRowSecurity:
5083  case AT_NoForceRowSecurity:
5085  /* These commands never recurse */
5086  /* No command-specific prep needed */
5087  pass = AT_PASS_MISC;
5088  break;
5089  case AT_GenericOptions:
5091  /* No command-specific prep needed */
5092  pass = AT_PASS_MISC;
5093  break;
5094  case AT_AttachPartition:
5096  /* No command-specific prep needed */
5097  pass = AT_PASS_MISC;
5098  break;
5099  case AT_DetachPartition:
5101  /* No command-specific prep needed */
5102  pass = AT_PASS_MISC;
5103  break;
5106  /* No command-specific prep needed */
5107  pass = AT_PASS_MISC;
5108  break;
5109  case AT_SplitPartition:
5111  /* No command-specific prep needed */
5112  pass = AT_PASS_MISC;
5113  break;
5114  case AT_MergePartitions:
5116  /* No command-specific prep needed */
5117  pass = AT_PASS_MISC;
5118  break;
5119  default: /* oops */
5120  elog(ERROR, "unrecognized alter table type: %d",
5121  (int) cmd->subtype);
5122  pass = AT_PASS_UNSET; /* keep compiler quiet */
5123  break;
5124  }
5125  Assert(pass > AT_PASS_UNSET);
5126 
5127  /* Add the subcommand to the appropriate list for phase 2 */
5128  tab->subcmds[pass] = lappend(tab->subcmds[pass], cmd);
5129 }
5130 
5131 /*
5132  * ATRewriteCatalogs
5133  *
5134  * Traffic cop for ALTER TABLE Phase 2 operations. Subcommands are
5135  * dispatched in a "safe" execution order (designed to avoid unnecessary
5136  * conflicts).
5137  */
5138 static void
5139 ATRewriteCatalogs(List **wqueue, LOCKMODE lockmode,
5141 {
5142  ListCell *ltab;
5143 
5144  /*
5145  * We process all the tables "in parallel", one pass at a time. This is
5146  * needed because we may have to propagate work from one table to another
5147  * (specifically, ALTER TYPE on a foreign key's PK has to dispatch the
5148  * re-adding of the foreign key constraint to the other table). Work can
5149  * only be propagated into later passes, however.
5150  */
5151  for (AlterTablePass pass = 0; pass < AT_NUM_PASSES; pass++)
5152  {
5153  /* Go through each table that needs to be processed */
5154  foreach(ltab, *wqueue)
5155  {
5156  AlteredTableInfo *tab = (AlteredTableInfo *) lfirst(ltab);
5157  List *subcmds = tab->subcmds[pass];
5158  ListCell *lcmd;
5159 
5160  if (subcmds == NIL)
5161  continue;
5162 
5163  /*
5164  * Open the relation and store it in tab. This allows subroutines
5165  * close and reopen, if necessary. Appropriate lock was obtained
5166  * by phase 1, needn't get it again.
5167  */
5168  tab->rel = relation_open(tab->relid, NoLock);
5169 
5170  foreach(lcmd, subcmds)
5171  ATExecCmd(wqueue, tab,
5172  lfirst_node(AlterTableCmd, lcmd),
5173  lockmode, pass, context);
5174 
5175  /*
5176  * After the ALTER TYPE or SET EXPRESSION pass, do cleanup work
5177  * (this is not done in ATExecAlterColumnType since it should be
5178  * done only once if multiple columns of a table are altered).
5179  */
5180  if (pass == AT_PASS_ALTER_TYPE || pass == AT_PASS_SET_EXPRESSION)
5181  ATPostAlterTypeCleanup(wqueue, tab, lockmode);
5182 
5183  if (tab->rel)
5184  {
5185  relation_close(tab->rel, NoLock);
5186  tab->rel = NULL;
5187  }
5188  }
5189  }
5190 
5191  /* Check to see if a toast table must be added. */
5192  foreach(ltab, *wqueue)
5193  {
5194  AlteredTableInfo *tab = (AlteredTableInfo *) lfirst(ltab);
5195 
5196  /*
5197  * If the table is source table of ATTACH PARTITION command, we did
5198  * not modify anything about it that will change its toasting
5199  * requirement, so no need to check.
5200  */
5201  if (((tab->relkind == RELKIND_RELATION ||
5202  tab->relkind == RELKIND_PARTITIONED_TABLE) &&
5203  tab->partition_constraint == NULL) ||
5204  tab->relkind == RELKIND_MATVIEW)
5205  AlterTableCreateToastTable(tab->relid, (Datum) 0, lockmode);
5206  }
5207 }
5208 
5209 /*
5210  * ATExecCmd: dispatch a subcommand to appropriate execution routine
5211  */
5212 static void
5214  AlterTableCmd *cmd, LOCKMODE lockmode, AlterTablePass cur_pass,
5216 {
5218  Relation rel = tab->rel;
5219 
5220  switch (cmd->subtype)
5221  {
5222  case AT_AddColumn: /* ADD COLUMN */
5223  case AT_AddColumnToView: /* add column via CREATE OR REPLACE VIEW */
5224  address = ATExecAddColumn(wqueue, tab, rel, &cmd,
5225  cmd->recurse, false,
5226  lockmode, cur_pass, context);
5227  break;
5228  case AT_ColumnDefault: /* ALTER COLUMN DEFAULT */
5229  address = ATExecColumnDefault(rel, cmd->name, cmd->def, lockmode);
5230  break;
5231  case AT_CookedColumnDefault: /* add a pre-cooked default */
5232  address = ATExecCookedColumnDefault(rel, cmd->num, cmd->def);
5233  break;
5234  case AT_AddIdentity:
5235  cmd = ATParseTransformCmd(wqueue, tab, rel, cmd, false, lockmode,
5236  cur_pass, context);
5237  Assert(cmd != NULL);
5238  address = ATExecAddIdentity(rel, cmd->name, cmd->def, lockmode, cmd->recurse, false);
5239  break;
5240  case AT_SetIdentity:
5241  cmd = ATParseTransformCmd(wqueue, tab, rel, cmd, false, lockmode,
5242  cur_pass, context);
5243  Assert(cmd != NULL);
5244  address = ATExecSetIdentity(rel, cmd->name, cmd->def, lockmode, cmd->recurse, false);
5245  break;
5246  case AT_DropIdentity:
5247  address = ATExecDropIdentity(rel, cmd->name, cmd->missing_ok, lockmode, cmd->recurse, false);
5248  break;
5249  case AT_DropNotNull: /* ALTER COLUMN DROP NOT NULL */
5250  address = ATExecDropNotNull(rel, cmd->name, lockmode);
5251  break;
5252  case AT_SetNotNull: /* ALTER COLUMN SET NOT NULL */
5253  address = ATExecSetNotNull(tab, rel, cmd->name, lockmode);
5254  break;
5255  case AT_CheckNotNull: /* check column is already marked NOT NULL */
5256  ATExecCheckNotNull(tab, rel, cmd->name, lockmode);
5257  break;
5258  case AT_SetExpression:
5259  address = ATExecSetExpression(tab, rel, cmd->name, cmd->def, lockmode);
5260  break;
5261  case AT_DropExpression:
5262  address = ATExecDropExpression(rel, cmd->name, cmd->missing_ok, lockmode);
5263  break;
5264  case AT_SetStatistics: /* ALTER COLUMN SET STATISTICS */
5265  address = ATExecSetStatistics(rel, cmd->name, cmd->num, cmd->def, lockmode);
5266  break;
5267  case AT_SetOptions: /* ALTER COLUMN SET ( options ) */
5268  address = ATExecSetOptions(rel, cmd->name, cmd->def, false, lockmode);
5269  break;
5270  case AT_ResetOptions: /* ALTER COLUMN RESET ( options ) */
5271  address = ATExecSetOptions(rel, cmd->name, cmd->def, true, lockmode);
5272  break;
5273  case AT_SetStorage: /* ALTER COLUMN SET STORAGE */
5274  address = ATExecSetStorage(rel, cmd->name, cmd->def, lockmode);
5275  break;
5276  case AT_SetCompression: /* ALTER COLUMN SET COMPRESSION */
5277  address = ATExecSetCompression(rel, cmd->name, cmd->def,
5278  lockmode);
5279  break;
5280  case AT_DropColumn: /* DROP COLUMN */
5281  address = ATExecDropColumn(wqueue, rel, cmd->name,
5282  cmd->behavior, cmd->recurse, false,
5283  cmd->missing_ok, lockmode,
5284  NULL);
5285  break;
5286  case AT_AddIndex: /* ADD INDEX */
5287  address = ATExecAddIndex(tab, rel, (IndexStmt *) cmd->def, false,
5288  lockmode);
5289  break;
5290  case AT_ReAddIndex: /* ADD INDEX */
5291  address = ATExecAddIndex(tab, rel, (IndexStmt *) cmd->def, true,
5292  lockmode);
5293  break;
5294  case AT_ReAddStatistics: /* ADD STATISTICS */
5295  address = ATExecAddStatistics(tab, rel, (CreateStatsStmt *) cmd->def,
5296  true, lockmode);
5297  break;
5298  case AT_AddConstraint: /* ADD CONSTRAINT */
5299  /* Transform the command only during initial examination */
5300  if (cur_pass == AT_PASS_ADD_CONSTR)
5301  cmd = ATParseTransformCmd(wqueue, tab, rel, cmd,
5302  cmd->recurse, lockmode,
5303  cur_pass, context);
5304  /* Depending on constraint type, might be no more work to do now */
5305  if (cmd != NULL)
5306  address =
5307  ATExecAddConstraint(wqueue, tab, rel,
5308  (Constraint *) cmd->def,
5309  cmd->recurse, false, lockmode);
5310  break;
5311  case AT_ReAddConstraint: /* Re-add pre-existing check constraint */
5312  address =
5313  ATExecAddConstraint(wqueue, tab, rel, (Constraint *) cmd->def,
5314  true, true, lockmode);
5315  break;
5316  case AT_ReAddDomainConstraint: /* Re-add pre-existing domain check
5317  * constraint */
5318  address =
5319  AlterDomainAddConstraint(((AlterDomainStmt *) cmd->def)->typeName,
5320  ((AlterDomainStmt *) cmd->def)->def,
5321  NULL);
5322  break;
5323  case AT_ReAddComment: /* Re-add existing comment */
5324  address = CommentObject((CommentStmt *) cmd->def);
5325  break;
5326  case AT_AddIndexConstraint: /* ADD CONSTRAINT USING INDEX */
5327  address = ATExecAddIndexConstraint(tab, rel, (IndexStmt *) cmd->def,
5328  lockmode);
5329  break;
5330  case AT_AlterConstraint: /* ALTER CONSTRAINT */
5331  address = ATExecAlterConstraint(rel, cmd, false, false, lockmode);
5332  break;
5333  case AT_ValidateConstraint: /* VALIDATE CONSTRAINT */
5334  address = ATExecValidateConstraint(wqueue, rel, cmd->name, cmd->recurse,
5335  false, lockmode);
5336  break;
5337  case AT_DropConstraint: /* DROP CONSTRAINT */
5338  ATExecDropConstraint(rel, cmd->name, cmd->behavior,
5339  cmd->recurse, false,
5340  cmd->missing_ok, lockmode);
5341  break;
5342  case AT_AlterColumnType: /* ALTER COLUMN TYPE */
5343  /* parse transformation was done earlier */
5344  address = ATExecAlterColumnType(tab, rel, cmd, lockmode);
5345  break;
5346  case AT_AlterColumnGenericOptions: /* ALTER COLUMN OPTIONS */
5347  address =
5349  (List *) cmd->def, lockmode);
5350  break;
5351  case AT_ChangeOwner: /* ALTER OWNER */
5353  get_rolespec_oid(cmd->newowner, false),
5354  false, lockmode);
5355  break;
5356  case AT_ClusterOn: /* CLUSTER ON */
5357  address = ATExecClusterOn(rel, cmd->name, lockmode);
5358  break;
5359  case AT_DropCluster: /* SET WITHOUT CLUSTER */
5360  ATExecDropCluster(rel, lockmode);
5361  break;
5362  case AT_SetLogged: /* SET LOGGED */
5363  case AT_SetUnLogged: /* SET UNLOGGED */
5364  break;
5365  case AT_DropOids: /* SET WITHOUT OIDS */
5366  /* nothing to do here, oid columns don't exist anymore */
5367  break;
5368  case AT_SetAccessMethod: /* SET ACCESS METHOD */
5369 
5370  /*
5371  * Only do this for partitioned tables, for which this is just a
5372  * catalog change. Tables with storage are handled by Phase 3.
5373  */
5374  if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE &&
5375  tab->chgAccessMethod)
5377  break;
5378  case AT_SetTableSpace: /* SET TABLESPACE */
5379 
5380  /*
5381  * Only do this for partitioned tables and indexes, for which this
5382  * is just a catalog change. Other relation types which have
5383  * storage are handled by Phase 3.
5384  */
5385  if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE ||
5386  rel->rd_rel->relkind == RELKIND_PARTITIONED_INDEX)
5388 
5389  break;
5390  case AT_SetRelOptions: /* SET (...) */
5391  case AT_ResetRelOptions: /* RESET (...) */
5392  case AT_ReplaceRelOptions: /* replace entire option list */
5393  ATExecSetRelOptions(rel, (List *) cmd->def, cmd->subtype, lockmode);
5394  break;
5395  case AT_EnableTrig: /* ENABLE TRIGGER name */
5396  ATExecEnableDisableTrigger(rel, cmd->name,
5397  TRIGGER_FIRES_ON_ORIGIN, false,
5398  cmd->recurse,
5399  lockmode);
5400  break;
5401  case AT_EnableAlwaysTrig: /* ENABLE ALWAYS TRIGGER name */
5402  ATExecEnableDisableTrigger(rel, cmd->name,
5403  TRIGGER_FIRES_ALWAYS, false,
5404  cmd->recurse,
5405  lockmode);
5406  break;
5407  case AT_EnableReplicaTrig: /* ENABLE REPLICA TRIGGER name */
5408  ATExecEnableDisableTrigger(rel, cmd->name,
5409  TRIGGER_FIRES_ON_REPLICA, false,
5410  cmd->recurse,
5411  lockmode);
5412  break;
5413  case AT_DisableTrig: /* DISABLE TRIGGER name */
5414  ATExecEnableDisableTrigger(rel, cmd->name,
5415  TRIGGER_DISABLED, false,
5416  cmd->recurse,
5417  lockmode);
5418  break;
5419  case AT_EnableTrigAll: /* ENABLE TRIGGER ALL */
5420  ATExecEnableDisableTrigger(rel, NULL,
5421  TRIGGER_FIRES_ON_ORIGIN, false,
5422  cmd->recurse,
5423  lockmode);
5424  break;
5425  case AT_DisableTrigAll: /* DISABLE TRIGGER ALL */
5426  ATExecEnableDisableTrigger(rel, NULL,
5427  TRIGGER_DISABLED, false,
5428  cmd->recurse,
5429  lockmode);
5430  break;
5431  case AT_EnableTrigUser: /* ENABLE TRIGGER USER */
5432  ATExecEnableDisableTrigger(rel, NULL,
5434  cmd->recurse,
5435  lockmode);
5436  break;
5437  case AT_DisableTrigUser: /* DISABLE TRIGGER USER */
5438  ATExecEnableDisableTrigger(rel, NULL,
5439  TRIGGER_DISABLED, true,
5440  cmd->recurse,
5441  lockmode);
5442  break;
5443 
5444  case AT_EnableRule: /* ENABLE RULE name */
5445  ATExecEnableDisableRule(rel, cmd->name,
5446  RULE_FIRES_ON_ORIGIN, lockmode);
5447  break;
5448  case AT_EnableAlwaysRule: /* ENABLE ALWAYS RULE name */
5449  ATExecEnableDisableRule(rel, cmd->name,
5450  RULE_FIRES_ALWAYS, lockmode);
5451  break;
5452  case AT_EnableReplicaRule: /* ENABLE REPLICA RULE name */
5453  ATExecEnableDisableRule(rel, cmd->name,
5454  RULE_FIRES_ON_REPLICA, lockmode);
5455  break;
5456  case AT_DisableRule: /* DISABLE RULE name */
5457  ATExecEnableDisableRule(rel, cmd->name,
5458  RULE_DISABLED, lockmode);
5459  break;
5460 
5461  case AT_AddInherit:
5462  address = ATExecAddInherit(rel, (RangeVar *) cmd->def, lockmode);
5463  break;
5464  case AT_DropInherit:
5465  address = ATExecDropInherit(rel, (RangeVar *) cmd->def, lockmode);
5466  break;
5467  case AT_AddOf:
5468  address = ATExecAddOf(rel, (TypeName *) cmd->def, lockmode);
5469  break;
5470  case AT_DropOf:
5471  ATExecDropOf(rel, lockmode);
5472  break;
5473  case AT_ReplicaIdentity:
5474  ATExecReplicaIdentity(rel, (ReplicaIdentityStmt *) cmd->def, lockmode);
5475  break;
5476  case AT_EnableRowSecurity:
5477  ATExecSetRowSecurity(rel, true);
5478  break;
5479  case AT_DisableRowSecurity:
5480  ATExecSetRowSecurity(rel, false);
5481  break;
5482  case AT_ForceRowSecurity:
5483  ATExecForceNoForceRowSecurity(rel, true);
5484  break;
5485  case AT_NoForceRowSecurity:
5486  ATExecForceNoForceRowSecurity(rel, false);
5487  break;
5488  case AT_GenericOptions:
5489  ATExecGenericOptions(rel, (List *) cmd->def);
5490  break;
5491  case AT_AttachPartition:
5492  cmd = ATParseTransformCmd(wqueue, tab, rel, cmd, false, lockmode,
5493  cur_pass, context);
5494  Assert(cmd != NULL);
5495  if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
5496  address = ATExecAttachPartition(wqueue, rel, (PartitionCmd *) cmd->def,
5497  context);
5498  else
5499  address = ATExecAttachPartitionIdx(wqueue, rel,
5500  ((PartitionCmd *) cmd->def)->name);
5501  break;
5502  case AT_DetachPartition:
5503  cmd = ATParseTransformCmd(wqueue, tab, rel, cmd, false, lockmode,
5504  cur_pass, context);
5505  Assert(cmd != NULL);
5506  /* ATPrepCmd ensures it must be a table */
5507  Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
5508  address = ATExecDetachPartition(wqueue, tab, rel,
5509  ((PartitionCmd *) cmd->def)->name,
5510  ((PartitionCmd *) cmd->def)->concurrent);
5511  break;
5513  address = ATExecDetachPartitionFinalize(rel, ((PartitionCmd *) cmd->def)->name);
5514  break;
5515  case AT_SplitPartition:
5516  cmd = ATParseTransformCmd(wqueue, tab, rel, cmd, false, lockmode,
5517  cur_pass, context);
5518  Assert(cmd != NULL);
5519  Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
5520  ATExecSplitPartition(wqueue, tab, rel, (PartitionCmd *) cmd->def,
5521  context);
5522  break;
5523  case AT_MergePartitions:
5524  cmd = ATParseTransformCmd(wqueue, tab, rel, cmd, false, lockmode,
5525  cur_pass, context);
5526  Assert(cmd != NULL);
5527  Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
5528  ATExecMergePartitions(wqueue, tab, rel, (PartitionCmd *) cmd->def,
5529  context);
5530  break;
5531  default: /* oops */
5532  elog(ERROR, "unrecognized alter table type: %d",
5533  (int) cmd->subtype);
5534  break;
5535  }
5536 
5537  /*
5538  * Report the subcommand to interested event triggers.
5539  */
5540  if (cmd)
5541  EventTriggerCollectAlterTableSubcmd((Node *) cmd, address);
5542 
5543  /*
5544  * Bump the command counter to ensure the next subcommand in the sequence
5545  * can see the changes so far
5546  */
5548 }
5549 
5550 /*
5551  * ATParseTransformCmd: perform parse transformation for one subcommand
5552  *
5553  * Returns the transformed subcommand tree, if there is one, else NULL.
5554  *
5555  * The parser may hand back additional AlterTableCmd(s) and/or other
5556  * utility statements, either before or after the original subcommand.
5557  * Other AlterTableCmds are scheduled into the appropriate slot of the
5558  * AlteredTableInfo (they had better be for later passes than the current one).
5559  * Utility statements that are supposed to happen before the AlterTableCmd
5560  * are executed immediately. Those that are supposed to happen afterwards
5561  * are added to the tab->afterStmts list to be done at the very end.
5562  */
5563 static AlterTableCmd *
5565  AlterTableCmd *cmd, bool recurse, LOCKMODE lockmode,
5567 {
5568  AlterTableCmd *newcmd = NULL;
5570  List *beforeStmts;
5571  List *afterStmts;
5572  ListCell *lc;
5573 
5574  /* Gin up an AlterTableStmt with just this subcommand and this table */
5575  atstmt->relation =
5578  -1);
5579  atstmt->relation->inh = recurse;
5580  atstmt->cmds = list_make1(cmd);
5581  atstmt->objtype = OBJECT_TABLE; /* needn't be picky here */
5582  atstmt->missing_ok = false;
5583 
5584  /* Transform the AlterTableStmt */
5586  atstmt,
5587  context->queryString,
5588  &beforeStmts,
5589  &afterStmts);
5590 
5591  /* Execute any statements that should happen before these subcommand(s) */
5592  foreach(lc, beforeStmts)
5593  {
5594  Node *stmt = (Node *) lfirst(lc);
5595 
5598  }
5599 
5600  /* Examine the transformed subcommands and schedule them appropriately */
5601  foreach(lc, atstmt->cmds)
5602  {
5604  AlterTablePass pass;
5605 
5606  /*
5607  * This switch need only cover the subcommand types that can be added
5608  * by parse_utilcmd.c; otherwise, we'll use the default strategy of
5609  * executing the subcommand immediately, as a substitute for the
5610  * original subcommand. (Note, however, that this does cause
5611  * AT_AddConstraint subcommands to be rescheduled into later passes,
5612  * which is important for index and foreign key constraints.)
5613  *
5614  * We assume we needn't do any phase-1 checks for added subcommands.
5615  */
5616  switch (cmd2->subtype)
5617  {
5618  case AT_SetNotNull:
5619  /* Need command-specific recursion decision */
5620  ATPrepSetNotNull(wqueue, rel, cmd2,
5621  recurse, false,
5622  lockmode, context);
5623  pass = AT_PASS_COL_ATTRS;
5624  break;
5625  case AT_AddIndex:
5626  /* This command never recurses */
5627  /* No command-specific prep needed */
5628  pass = AT_PASS_ADD_INDEX;
5629  break;
5630  case AT_AddIndexConstraint:
5631  /* This command never recurses */
5632  /* No command-specific prep needed */
5633  pass = AT_PASS_ADD_INDEXCONSTR;
5634  break;
5635  case AT_AddConstraint:
5636  /* Recursion occurs during execution phase */
5637  if (recurse)
5638  cmd2->recurse = true;
5639  switch (castNode(Constraint, cmd2->def)->contype)
5640  {
5641  case CONSTR_PRIMARY:
5642  case CONSTR_UNIQUE:
5643  case CONSTR_EXCLUSION:
5644  pass = AT_PASS_ADD_INDEXCONSTR;
5645  break;
5646  default:
5647  pass = AT_PASS_ADD_OTHERCONSTR;
5648  break;
5649  }
5650  break;
5652  /* This command never recurses */
5653  /* No command-specific prep needed */
5654  pass = AT_PASS_MISC;
5655  break;
5656  default:
5657  pass = cur_pass;
5658  break;
5659  }
5660 
5661  if (pass < cur_pass)
5662  {
5663  /* Cannot schedule into a pass we already finished */
5664  elog(ERROR, "ALTER TABLE scheduling failure: too late for pass %d",
5665  pass);
5666  }
5667  else if (pass > cur_pass)
5668  {
5669  /* OK, queue it up for later */
5670  tab->subcmds[pass] = lappend(tab->subcmds[pass], cmd2);
5671  }
5672  else
5673  {
5674  /*
5675  * We should see at most one subcommand for the current pass,
5676  * which is the transformed version of the original subcommand.
5677  */
5678  if (newcmd == NULL && cmd->subtype == cmd2->subtype)
5679  {
5680  /* Found the transformed version of our subcommand */
5681  newcmd = cmd2;
5682  }
5683  else
5684  elog(ERROR, "ALTER TABLE scheduling failure: bogus item for pass %d",
5685  pass);
5686  }
5687  }
5688 
5689  /* Queue up any after-statements to happen at the end */
5690  tab->afterStmts = list_concat(tab->afterStmts, afterStmts);
5691 
5692  return newcmd;
5693 }
5694 
5695 /*
5696  * ATRewriteTables: ALTER TABLE phase 3
5697  */
5698 static void
5699 ATRewriteTables(AlterTableStmt *parsetree, List **wqueue, LOCKMODE lockmode,
5701 {
5702  ListCell *ltab;
5703 
5704  /* Go through each table that needs to be checked or rewritten */
5705  foreach(ltab, *wqueue)
5706  {
5707  AlteredTableInfo *tab = (AlteredTableInfo *) lfirst(ltab);
5708 
5709  /* Relations without storage may be ignored here */
5710  if (!RELKIND_HAS_STORAGE(tab->relkind))
5711  continue;
5712 
5713  /*
5714  * If we change column data types, the operation has to be propagated
5715  * to tables that use this table's rowtype as a column type.
5716  * tab->newvals will also be non-NULL in the case where we're adding a
5717  * column with a default. We choose to forbid that case as well,
5718  * since composite types might eventually support defaults.
5719  *
5720  * (Eventually we'll probably need to check for composite type
5721  * dependencies even when we're just scanning the table without a
5722  * rewrite, but at the moment a composite type does not enforce any
5723  * constraints, so it's not necessary/appropriate to enforce them just
5724  * during ALTER.)
5725  */
5726  if (tab->newvals != NIL || tab->rewrite > 0)
5727  {
5728  Relation rel;
5729 
5730  rel = table_open(tab->relid, NoLock);
5731  find_composite_type_dependencies(rel->rd_rel->reltype, rel, NULL);
5732  table_close(rel, NoLock);
5733  }
5734 
5735  /*
5736  * We only need to rewrite the table if at least one column needs to
5737  * be recomputed, or we are changing its persistence or access method.
5738  *
5739  * There are two reasons for requiring a rewrite when changing
5740  * persistence: on one hand, we need to ensure that the buffers
5741  * belonging to each of the two relations are marked with or without
5742  * BM_PERMANENT properly. On the other hand, since rewriting creates
5743  * and assigns a new relfilenumber, we automatically create or drop an
5744  * init fork for the relation as appropriate.
5745  */
5746  if (tab->rewrite > 0 && tab->relkind != RELKIND_SEQUENCE)
5747  {
5748  /* Build a temporary relation and copy data */
5749  Relation OldHeap;
5750  Oid OIDNewHeap;
5751  Oid NewAccessMethod;
5752  Oid NewTableSpace;
5753  char persistence;
5754 
5755  OldHeap = table_open(tab->relid, NoLock);
5756 
5757  /*
5758  * We don't support rewriting of system catalogs; there are too
5759  * many corner cases and too little benefit. In particular this
5760  * is certainly not going to work for mapped catalogs.
5761  */
5762  if (IsSystemRelation(OldHeap))
5763  ereport(ERROR,
5764  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
5765  errmsg("cannot rewrite system relation \"%s\"",
5766  RelationGetRelationName(OldHeap))));
5767 
5768  if (RelationIsUsedAsCatalogTable(OldHeap))
5769  ereport(ERROR,
5770  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
5771  errmsg("cannot rewrite table \"%s\" used as a catalog table",
5772  RelationGetRelationName(OldHeap))));
5773 
5774  /*
5775  * Don't allow rewrite on temp tables of other backends ... their
5776  * local buffer manager is not going to cope. (This is redundant
5777  * with the check in CheckAlterTableIsSafe, but for safety we'll
5778  * check here too.)
5779  */
5780  if (RELATION_IS_OTHER_TEMP(OldHeap))
5781  ereport(ERROR,
5782  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
5783  errmsg("cannot rewrite temporary tables of other sessions")));
5784 
5785  /*
5786  * Select destination tablespace (same as original unless user
5787  * requested a change)
5788  */
5789  if (tab->newTableSpace)
5790  NewTableSpace = tab->newTableSpace;
5791  else
5792  NewTableSpace = OldHeap->rd_rel->reltablespace;
5793 
5794  /*
5795  * Select destination access method (same as original unless user
5796  * requested a change)
5797  */
5798  if (tab->chgAccessMethod)
5799  NewAccessMethod = tab->newAccessMethod;
5800  else
5801  NewAccessMethod = OldHeap->rd_rel->relam;
5802 
5803  /*
5804  * Select persistence of transient table (same as original unless
5805  * user requested a change)
5806  */
5807  persistence = tab->chgPersistence ?
5808  tab->newrelpersistence : OldHeap->rd_rel->relpersistence;
5809 
5810  table_close(OldHeap, NoLock);
5811 
5812  /*
5813  * Fire off an Event Trigger now, before actually rewriting the
5814  * table.
5815  *
5816  * We don't support Event Trigger for nested commands anywhere,
5817  * here included, and parsetree is given NULL when coming from
5818  * AlterTableInternal.
5819  *
5820  * And fire it only once.
5821  */
5822  if (parsetree)
5823  EventTriggerTableRewrite((Node *) parsetree,
5824  tab->relid,
5825  tab->rewrite);
5826 
5827  /*
5828  * Create transient table that will receive the modified data.
5829  *
5830  * Ensure it is marked correctly as logged or unlogged. We have
5831  * to do this here so that buffers for the new relfilenumber will
5832  * have the right persistence set, and at the same time ensure
5833  * that the original filenumbers's buffers will get read in with
5834  * the correct setting (i.e. the original one). Otherwise a
5835  * rollback after the rewrite would possibly result with buffers
5836  * for the original filenumbers having the wrong persistence
5837  * setting.
5838  *
5839  * NB: This relies on swap_relation_files() also swapping the
5840  * persistence. That wouldn't work for pg_class, but that can't be
5841  * unlogged anyway.
5842  */
5843  OIDNewHeap = make_new_heap(tab->relid, NewTableSpace, NewAccessMethod,
5844  persistence, lockmode);
5845 
5846  /*
5847  * Copy the heap data into the new table with the desired
5848  * modifications, and test the current data within the table
5849  * against new constraints generated by ALTER TABLE commands.
5850  */
5851  ATRewriteTable(tab, OIDNewHeap, lockmode);
5852 
5853  /*
5854  * Swap the physical files of the old and new heaps, then rebuild
5855  * indexes and discard the old heap. We can use RecentXmin for
5856  * the table's new relfrozenxid because we rewrote all the tuples
5857  * in ATRewriteTable, so no older Xid remains in the table. Also,
5858  * we never try to swap toast tables by content, since we have no
5859  * interest in letting this code work on system catalogs.
5860  */
5861  finish_heap_swap(tab->relid, OIDNewHeap,
5862  false, false, true,
5863  !OidIsValid(tab->newTableSpace),
5864  RecentXmin,
5866  persistence);
5867 
5868  InvokeObjectPostAlterHook(RelationRelationId, tab->relid, 0);
5869  }
5870  else if (tab->rewrite > 0 && tab->relkind == RELKIND_SEQUENCE)
5871  {
5872  if (tab->chgPersistence)
5874  }
5875  else
5876  {
5877  /*
5878  * If required, test the current data within the table against new
5879  * constraints generated by ALTER TABLE commands, but don't
5880  * rebuild data.
5881  */
5882  if (tab->constraints != NIL || tab->verify_new_notnull ||
5883  tab->partition_constraint != NULL)
5884  ATRewriteTable(tab, InvalidOid, lockmode);
5885 
5886  /*
5887  * If we had SET TABLESPACE but no reason to reconstruct tuples,
5888  * just do a block-by-block copy.
5889  */
5890  if (tab->newTableSpace)
5891  ATExecSetTableSpace(tab->relid, tab->newTableSpace, lockmode);
5892  }
5893 
5894  /*
5895  * Also change persistence of owned sequences, so that it matches the
5896  * table persistence.
5897  */
5898  if (tab->chgPersistence)
5899  {
5900  List *seqlist = getOwnedSequences(tab->relid);
5901  ListCell *lc;
5902 
5903  foreach(lc, seqlist)
5904  {
5905  Oid seq_relid = lfirst_oid(lc);
5906 
5908  }
5909  }
5910  }
5911 
5912  /*
5913  * Foreign key constraints are checked in a final pass, since (a) it's
5914  * generally best to examine each one separately, and (b) it's at least
5915  * theoretically possible that we have changed both relations of the
5916  * foreign key, and we'd better have finished both rewrites before we try
5917  * to read the tables.
5918  */
5919  foreach(ltab, *wqueue)
5920  {
5921  AlteredTableInfo *tab = (AlteredTableInfo *) lfirst(ltab);
5922  Relation rel = NULL;
5923  ListCell *lcon;
5924 
5925  /* Relations without storage may be ignored here too */
5926  if (!RELKIND_HAS_STORAGE(tab->relkind))
5927  continue;
5928 
5929  foreach(lcon, tab->constraints)
5930  {
5931  NewConstraint *con = lfirst(lcon);
5932 
5933  if (con->contype == CONSTR_FOREIGN)
5934  {
5935  Constraint *fkconstraint = (Constraint *) con->qual;
5936  Relation refrel;
5937 
5938  if (rel == NULL)
5939  {
5940  /* Long since locked, no need for another */
5941  rel = table_open(tab->relid, NoLock);
5942  }
5943 
5944  refrel = table_open(con->refrelid, RowShareLock);
5945 
5946  validateForeignKeyConstraint(fkconstraint->conname, rel, refrel,
5947  con->refindid,
5948  con->conid);
5949 
5950  /*
5951  * No need to mark the constraint row as validated, we did
5952  * that when we inserted the row earlier.
5953  */
5954 
5955  table_close(refrel, NoLock);
5956  }
5957  }
5958 
5959  if (rel)
5960  table_close(rel, NoLock);
5961  }
5962 
5963  /* Finally, run any afterStmts that were queued up */
5964  foreach(ltab, *wqueue)
5965  {
5966  AlteredTableInfo *tab = (AlteredTableInfo *) lfirst(ltab);
5967  ListCell *lc;
5968 
5969  foreach(lc, tab->afterStmts)
5970  {
5971  Node *stmt = (Node *) lfirst(lc);
5972 
5975  }
5976  }
5977 }
5978 
5979 /*
5980  * ATRewriteTable: scan or rewrite one table
5981  *
5982  * OIDNewHeap is InvalidOid if we don't need to rewrite
5983  */
5984 static void
5985 ATRewriteTable(AlteredTableInfo *tab, Oid OIDNewHeap, LOCKMODE lockmode)
5986 {
5987  Relation oldrel;
5988  Relation newrel;
5989  TupleDesc oldTupDesc;
5990  TupleDesc newTupDesc;
5991  bool needscan = false;
5992  List *notnull_attrs;
5993  int i;
5994  ListCell *l;
5995  EState *estate;
5996  CommandId mycid;
5997  BulkInsertState bistate;
5998  int ti_options;
5999  ExprState *partqualstate = NULL;
6000 
6001  /*
6002  * Open the relation(s). We have surely already locked the existing
6003  * table.
6004  */
6005  oldrel = table_open(tab->relid, NoLock);
6006  oldTupDesc = tab->oldDesc;
6007  newTupDesc = RelationGetDescr(oldrel); /* includes all mods */
6008 
6009  if (OidIsValid(OIDNewHeap))
6010  newrel = table_open(OIDNewHeap, lockmode);
6011  else
6012  newrel = NULL;
6013 
6014  /*
6015  * Prepare a BulkInsertState and options for table_tuple_insert. The FSM
6016  * is empty, so don't bother using it.
6017  */
6018  if (newrel)
6019  {
6020  mycid = GetCurrentCommandId(true);
6021  bistate = GetBulkInsertState();
6022  ti_options = TABLE_INSERT_SKIP_FSM;
6023  }
6024  else
6025  {
6026  /* keep compiler quiet about using these uninitialized */
6027  mycid = 0;
6028  bistate = NULL;
6029  ti_options = 0;
6030  }
6031 
6032  /*
6033  * Generate the constraint and default execution states
6034  */
6035 
6036  estate = CreateExecutorState();
6037 
6038  /* Build the needed expression execution states */
6039  foreach(l, tab->constraints)
6040  {
6041  NewConstraint *con = lfirst(l);
6042 
6043  switch (con->contype)
6044  {
6045  case CONSTR_CHECK:
6046  needscan = true;
6047  con->qualstate = ExecPrepareExpr((Expr *) con->qual, estate);
6048  break;
6049  case CONSTR_FOREIGN:
6050  /* Nothing to do here */
6051  break;
6052  default:
6053  elog(ERROR, "unrecognized constraint type: %d",
6054  (int) con->contype);
6055  }
6056  }
6057 
6058  /* Build expression execution states for partition check quals */
6059  if (tab->partition_constraint)
6060  {
6061  needscan = true;
6062  partqualstate = ExecPrepareExpr(tab->partition_constraint, estate);
6063  }
6064 
6065  foreach(l, tab->newvals)
6066  {
6067  NewColumnValue *ex = lfirst(l);
6068 
6069  /* expr already planned */
6070  ex->exprstate = ExecInitExpr((Expr *) ex->expr, NULL);
6071  }
6072 
6073  notnull_attrs = NIL;
6074  if (newrel || tab->verify_new_notnull)
6075  {
6076  /*
6077  * If we are rebuilding the tuples OR if we added any new but not
6078  * verified not-null constraints, check all not-null constraints. This
6079  * is a bit of overkill but it minimizes risk of bugs, and
6080  * heap_attisnull is a pretty cheap test anyway.
6081  */
6082  for (i = 0; i < newTupDesc->natts; i++)
6083  {
6084  Form_pg_attribute attr = TupleDescAttr(newTupDesc, i);
6085 
6086  if (attr->attnotnull && !attr->attisdropped)
6087  notnull_attrs = lappend_int(notnull_attrs, i);
6088  }
6089  if (notnull_attrs)
6090  needscan = true;
6091  }
6092 
6093  if (newrel || needscan)
6094  {
6095  ExprContext *econtext;
6096  TupleTableSlot *oldslot;
6097  TupleTableSlot *newslot;
6098  TableScanDesc scan;
6099  MemoryContext oldCxt;
6100  List *dropped_attrs = NIL;
6101  ListCell *lc;
6102  Snapshot snapshot;
6103 
6104  if (newrel)
6105  ereport(DEBUG1,
6106  (errmsg_internal("rewriting table \"%s\"",
6107  RelationGetRelationName(oldrel))));
6108  else
6109  ereport(DEBUG1,
6110  (errmsg_internal("verifying table \"%s\"",
6111  RelationGetRelationName(oldrel))));
6112 
6113  if (newrel)
6114  {
6115  /*
6116  * All predicate locks on the tuples or pages are about to be made
6117  * invalid, because we move tuples around. Promote them to
6118  * relation locks.
6119  */
6121  }
6122 
6123  econtext = GetPerTupleExprContext(estate);
6124 
6125  /*
6126  * Create necessary tuple slots. When rewriting, two slots are needed,
6127  * otherwise one suffices. In the case where one slot suffices, we
6128  * need to use the new tuple descriptor, otherwise some constraints
6129  * can't be evaluated. Note that even when the tuple layout is the
6130  * same and no rewrite is required, the tupDescs might not be
6131  * (consider ADD COLUMN without a default).
6132  */
6133  if (tab->rewrite)
6134  {
6135  Assert(newrel != NULL);
6136  oldslot = MakeSingleTupleTableSlot(oldTupDesc,
6137  table_slot_callbacks(oldrel));
6138  newslot = MakeSingleTupleTableSlot(newTupDesc,
6139  table_slot_callbacks(newrel));
6140 
6141  /*
6142  * Set all columns in the new slot to NULL initially, to ensure
6143  * columns added as part of the rewrite are initialized to NULL.
6144  * That is necessary as tab->newvals will not contain an
6145  * expression for columns with a NULL default, e.g. when adding a
6146  * column without a default together with a column with a default
6147  * requiring an actual rewrite.
6148  */
6149  ExecStoreAllNullTuple(newslot);
6150  }
6151  else
6152  {
6153  oldslot = MakeSingleTupleTableSlot(newTupDesc,
6154  table_slot_callbacks(oldrel));
6155  newslot = NULL;
6156  }
6157 
6158  /*
6159  * Any attributes that are dropped according to the new tuple
6160  * descriptor can be set to NULL. We precompute the list of dropped
6161  * attributes to avoid needing to do so in the per-tuple loop.
6162  */
6163  for (i = 0; i < newTupDesc->natts; i++)
6164  {
6165  if (TupleDescAttr(newTupDesc, i)->attisdropped)
6166  dropped_attrs = lappend_int(dropped_attrs, i);
6167  }
6168 
6169  /*
6170  * Scan through the rows, generating a new row if needed and then
6171  * checking all the constraints.
6172  */
6173  snapshot = RegisterSnapshot(GetLatestSnapshot());
6174  scan = table_beginscan(oldrel, snapshot, 0, NULL);
6175 
6176  /*
6177  * Switch to per-tuple memory context and reset it for each tuple
6178  * produced, so we don't leak memory.
6179  */
6181 
6182  while (table_scan_getnextslot(scan, ForwardScanDirection, oldslot))
6183  {
6184  TupleTableSlot *insertslot;
6185 
6186  if (tab->rewrite > 0)
6187  {
6188  /* Extract data from old tuple */
6189  slot_getallattrs(oldslot);
6190  ExecClearTuple(newslot);
6191 
6192  /* copy attributes */
6193  memcpy(newslot->tts_values, oldslot->tts_values,
6194  sizeof(Datum) * oldslot->tts_nvalid);
6195  memcpy(newslot->tts_isnull, oldslot->tts_isnull,
6196  sizeof(bool) * oldslot->tts_nvalid);
6197 
6198  /* Set dropped attributes to null in new tuple */
6199  foreach(lc, dropped_attrs)
6200  newslot->tts_isnull[lfirst_int(lc)] = true;
6201 
6202  /*
6203  * Constraints and GENERATED expressions might reference the
6204  * tableoid column, so fill tts_tableOid with the desired
6205  * value. (We must do this each time, because it gets
6206  * overwritten with newrel's OID during storing.)
6207  */
6208  newslot->tts_tableOid = RelationGetRelid(oldrel);
6209 
6210  /*
6211  * Process supplied expressions to replace selected columns.
6212  *
6213  * First, evaluate expressions whose inputs come from the old
6214  * tuple.
6215  */
6216  econtext->ecxt_scantuple = oldslot;
6217 
6218  foreach(l, tab->newvals)
6219  {
6220  NewColumnValue *ex = lfirst(l);
6221 
6222  if (ex->is_generated)
6223  continue;
6224 
6225  newslot->tts_values[ex->attnum - 1]
6226  = ExecEvalExpr(ex->exprstate,
6227  econtext,
6228  &newslot->tts_isnull[ex->attnum - 1]);
6229  }
6230 
6231  ExecStoreVirtualTuple(newslot);
6232 
6233  /*
6234  * Now, evaluate any expressions whose inputs come from the
6235  * new tuple. We assume these columns won't reference each
6236  * other, so that there's no ordering dependency.
6237  */
6238  econtext->ecxt_scantuple = newslot;
6239 
6240  foreach(l, tab->newvals)
6241  {
6242  NewColumnValue *ex = lfirst(l);
6243 
6244  if (!ex->is_generated)
6245  continue;
6246 
6247  newslot->tts_values[ex->attnum - 1]
6248  = ExecEvalExpr(ex->exprstate,
6249  econtext,
6250  &newslot->tts_isnull[ex->attnum - 1]);
6251  }
6252 
6253  insertslot = newslot;
6254  }
6255  else
6256  {
6257  /*
6258  * If there's no rewrite, old and new table are guaranteed to
6259  * have the same AM, so we can just use the old slot to verify
6260  * new constraints etc.
6261  */
6262  insertslot = oldslot;
6263  }
6264 
6265  /* Now check any constraints on the possibly-changed tuple */
6266  econtext->ecxt_scantuple = insertslot;
6267 
6268  foreach(l, notnull_attrs)
6269  {
6270  int attn = lfirst_int(l);
6271 
6272  if (slot_attisnull(insertslot, attn + 1))
6273  {
6274  Form_pg_attribute attr = TupleDescAttr(newTupDesc, attn);
6275 
6276  ereport(ERROR,
6277  (errcode(ERRCODE_NOT_NULL_VIOLATION),
6278  errmsg("column \"%s\" of relation \"%s\" contains null values",
6279  NameStr(attr->attname),
6280  RelationGetRelationName(oldrel)),
6281  errtablecol(oldrel, attn + 1)));
6282  }
6283  }
6284 
6285  foreach(l, tab->constraints)
6286  {
6287  NewConstraint *con = lfirst(l);
6288 
6289  switch (con->contype)
6290  {
6291  case CONSTR_CHECK:
6292  if (!ExecCheck(con->qualstate, econtext))
6293  ereport(ERROR,
6294  (errcode(ERRCODE_CHECK_VIOLATION),
6295  errmsg("check constraint \"%s\" of relation \"%s\" is violated by some row",
6296  con->name,
6297  RelationGetRelationName(oldrel)),
6298  errtableconstraint(oldrel, con->name)));
6299  break;
6300  case CONSTR_FOREIGN:
6301  /* Nothing to do here */
6302  break;
6303  default:
6304  elog(ERROR, "unrecognized constraint type: %d",
6305  (int) con->contype);
6306  }
6307  }
6308 
6309  if (partqualstate && !ExecCheck(partqualstate, econtext))
6310  {
6311  if (tab->validate_default)
6312  ereport(ERROR,
6313  (errcode(ERRCODE_CHECK_VIOLATION),
6314  errmsg("updated partition constraint for default partition \"%s\" would be violated by some row",
6315  RelationGetRelationName(oldrel)),
6316  errtable(oldrel)));
6317  else
6318  ereport(ERROR,
6319  (errcode(ERRCODE_CHECK_VIOLATION),
6320  errmsg("partition constraint of relation \"%s\" is violated by some row",
6321  RelationGetRelationName(oldrel)),
6322  errtable(oldrel)));
6323  }
6324 
6325  /* Write the tuple out to the new relation */
6326  if (newrel)
6327  table_tuple_insert(newrel, insertslot, mycid,
6328  ti_options, bistate);
6329 
6330  ResetExprContext(econtext);
6331 
6333  }
6334 
6335  MemoryContextSwitchTo(oldCxt);
6336  table_endscan(scan);
6337  UnregisterSnapshot(snapshot);
6338 
6340  if (newslot)
6342  }
6343 
6344  FreeExecutorState(estate);
6345 
6346  table_close(oldrel, NoLock);
6347  if (newrel)
6348  {
6349  FreeBulkInsertState(bistate);
6350 
6351  table_finish_bulk_insert(newrel, ti_options);
6352 
6353  table_close(newrel, NoLock);
6354  }
6355 }
6356 
6357 /*
6358  * ATGetQueueEntry: find or create an entry in the ALTER TABLE work queue
6359  */
6360 static AlteredTableInfo *
6362 {
6363  Oid relid = RelationGetRelid(rel);
6364  AlteredTableInfo *tab;
6365  ListCell *ltab;
6366 
6367  foreach(ltab, *wqueue)
6368  {
6369  tab = (AlteredTableInfo *) lfirst(ltab);
6370  if (tab->relid == relid)
6371  return tab;
6372  }
6373 
6374  /*
6375  * Not there, so add it. Note that we make a copy of the relation's
6376  * existing descriptor before anything interesting can happen to it.
6377  */
6378  tab = (AlteredTableInfo *) palloc0(sizeof(AlteredTableInfo));
6379  tab->relid = relid;
6380  tab->rel = NULL; /* set later */
6381  tab->relkind = rel->rd_rel->relkind;
6383  tab->newAccessMethod = InvalidOid;
6384  tab->chgAccessMethod = false;
6385  tab->newTableSpace = InvalidOid;
6386  tab->newrelpersistence = RELPERSISTENCE_PERMANENT;
6387  tab->chgPersistence = false;
6388 
6389  *wqueue = lappend(*wqueue, tab);
6390 
6391  return tab;
6392 }
6393 
6394 static const char *
6396 {
6397  switch (cmdtype)
6398  {
6399  case AT_AddColumn:
6400  case AT_AddColumnToView:
6401  return "ADD COLUMN";
6402  case AT_ColumnDefault:
6404  return "ALTER COLUMN ... SET DEFAULT";
6405  case AT_DropNotNull:
6406  return "ALTER COLUMN ... DROP NOT NULL";
6407  case AT_SetNotNull:
6408  return "ALTER COLUMN ... SET NOT NULL";
6409  case AT_SetExpression:
6410  return "ALTER COLUMN ... SET EXPRESSION";
6411  case AT_DropExpression:
6412  return "ALTER COLUMN ... DROP EXPRESSION";
6413  case AT_CheckNotNull:
6414  return NULL; /* not real grammar */
6415  case AT_SetStatistics:
6416  return "ALTER COLUMN ... SET STATISTICS";
6417  case AT_SetOptions:
6418  return "ALTER COLUMN ... SET";
6419  case AT_ResetOptions:
6420  return "ALTER COLUMN ... RESET";
6421  case AT_SetStorage:
6422  return "ALTER COLUMN ... SET STORAGE";
6423  case AT_SetCompression:
6424  return "ALTER COLUMN ... SET COMPRESSION";
6425  case AT_DropColumn:
6426  return "DROP COLUMN";
6427  case AT_AddIndex:
6428  case AT_ReAddIndex:
6429  return NULL; /* not real grammar */
6430  case AT_AddConstraint:
6431  case AT_ReAddConstraint:
6433  case AT_AddIndexConstraint:
6434  return "ADD CONSTRAINT";
6435  case AT_AlterConstraint:
6436  return "ALTER CONSTRAINT";
6437  case AT_ValidateConstraint:
6438  return "VALIDATE CONSTRAINT";
6439  case AT_DropConstraint:
6440  return "DROP CONSTRAINT";
6441  case AT_ReAddComment:
6442  return NULL; /* not real grammar */
6443  case AT_AlterColumnType:
6444  return "ALTER COLUMN ... SET DATA TYPE";
6446  return "ALTER COLUMN ... OPTIONS";
6447  case AT_ChangeOwner:
6448  return "OWNER TO";
6449  case AT_ClusterOn:
6450  return "CLUSTER ON";
6451  case AT_DropCluster:
6452  return "SET WITHOUT CLUSTER";
6453  case AT_SetAccessMethod:
6454  return "SET ACCESS METHOD";
6455  case AT_SetLogged:
6456  return "SET LOGGED";
6457  case AT_SetUnLogged:
6458  return "SET UNLOGGED";
6459  case AT_DropOids:
6460  return "SET WITHOUT OIDS";
6461  case AT_SetTableSpace:
6462  return "SET TABLESPACE";
6463  case AT_SetRelOptions:
6464  return "SET";
6465  case AT_ResetRelOptions:
6466  return "RESET";
6467  case AT_ReplaceRelOptions:
6468  return NULL; /* not real grammar */
6469  case AT_EnableTrig:
6470  return "ENABLE TRIGGER";
6471  case AT_EnableAlwaysTrig:
6472  return "ENABLE ALWAYS TRIGGER";
6473  case AT_EnableReplicaTrig:
6474  return "ENABLE REPLICA TRIGGER";
6475  case AT_DisableTrig:
6476  return "DISABLE TRIGGER";
6477  case AT_EnableTrigAll:
6478  return "ENABLE TRIGGER ALL";
6479  case AT_DisableTrigAll:
6480  return "DISABLE TRIGGER ALL";
6481  case AT_EnableTrigUser:
6482  return "ENABLE TRIGGER USER";
6483  case AT_DisableTrigUser:
6484  return "DISABLE TRIGGER USER";
6485  case AT_EnableRule:
6486  return "ENABLE RULE";
6487  case AT_EnableAlwaysRule:
6488  return "ENABLE ALWAYS RULE";
6489  case AT_EnableReplicaRule:
6490  return "ENABLE REPLICA RULE";
6491  case AT_DisableRule:
6492  return "DISABLE RULE";
6493  case AT_AddInherit:
6494  return "INHERIT";
6495  case AT_DropInherit:
6496  return "NO INHERIT";
6497  case AT_AddOf:
6498  return "OF";
6499  case AT_DropOf:
6500  return "NOT OF";
6501  case AT_ReplicaIdentity:
6502  return "REPLICA IDENTITY";
6503  case AT_EnableRowSecurity:
6504  return "ENABLE ROW SECURITY";
6505  case AT_DisableRowSecurity:
6506  return "DISABLE ROW SECURITY";
6507  case AT_ForceRowSecurity:
6508  return "FORCE ROW SECURITY";
6509  case AT_NoForceRowSecurity:
6510  return "NO FORCE ROW SECURITY";
6511  case AT_GenericOptions:
6512  return "OPTIONS";
6513  case AT_AttachPartition:
6514  return "ATTACH PARTITION";
6515  case AT_DetachPartition:
6516  return "DETACH PARTITION";
6518  return "DETACH PARTITION ... FINALIZE";
6519  case AT_SplitPartition:
6520  return "SPLIT PARTITION";
6521  case AT_MergePartitions:
6522  return "MERGE PARTITIONS";
6523  case AT_AddIdentity:
6524  return "ALTER COLUMN ... ADD IDENTITY";
6525  case AT_SetIdentity:
6526  return "ALTER COLUMN ... SET";
6527  case AT_DropIdentity:
6528  return "ALTER COLUMN ... DROP IDENTITY";
6529  case AT_ReAddStatistics:
6530  return NULL; /* not real grammar */
6531  }
6532 
6533  return NULL;
6534 }
6535 
6536 /*
6537  * ATSimplePermissions
6538  *
6539  * - Ensure that it is a relation (or possibly a view)
6540  * - Ensure this user is the owner
6541  * - Ensure that it is not a system table
6542  */
6543 static void
6544 ATSimplePermissions(AlterTableType cmdtype, Relation rel, int allowed_targets)
6545 {
6546  int actual_target;
6547 
6548  switch (rel->rd_rel->relkind)
6549  {
6550  case RELKIND_RELATION:
6551  case RELKIND_PARTITIONED_TABLE:
6552  actual_target = ATT_TABLE;
6553  break;
6554  case RELKIND_VIEW:
6555  actual_target = ATT_VIEW;
6556  break;
6557  case RELKIND_MATVIEW:
6558  actual_target = ATT_MATVIEW;
6559  break;
6560  case RELKIND_INDEX:
6561  actual_target = ATT_INDEX;
6562  break;
6563  case RELKIND_PARTITIONED_INDEX:
6564  actual_target = ATT_PARTITIONED_INDEX;
6565  break;
6566  case RELKIND_COMPOSITE_TYPE:
6567  actual_target = ATT_COMPOSITE_TYPE;
6568  break;
6569  case RELKIND_FOREIGN_TABLE:
6570  actual_target = ATT_FOREIGN_TABLE;
6571  break;
6572  case RELKIND_SEQUENCE:
6573  actual_target = ATT_SEQUENCE;
6574  break;
6575  default:
6576  actual_target = 0;
6577  break;
6578  }
6579 
6580  /* Wrong target type? */
6581  if ((actual_target & allowed_targets) == 0)
6582  {
6583  const char *action_str = alter_table_type_to_string(cmdtype);
6584 
6585  if (action_str)
6586  ereport(ERROR,
6587  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
6588  /* translator: %s is a group of some SQL keywords */
6589  errmsg("ALTER action %s cannot be performed on relation \"%s\"",
6590  action_str, RelationGetRelationName(rel)),
6591  errdetail_relkind_not_supported(rel->rd_rel->relkind)));
6592  else
6593  /* internal error? */
6594  elog(ERROR, "invalid ALTER action attempted on relation \"%s\"",
6596  }
6597 
6598  /* Permissions checks */
6599  if (!object_ownercheck(RelationRelationId, RelationGetRelid(rel), GetUserId()))
6602 
6604  ereport(ERROR,
6605  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
6606  errmsg("permission denied: \"%s\" is a system catalog",
6607  RelationGetRelationName(rel))));
6608 }
6609 
6610 /*
6611  * ATSimpleRecursion
6612  *
6613  * Simple table recursion sufficient for most ALTER TABLE operations.
6614  * All direct and indirect children are processed in an unspecified order.
6615  * Note that if a child inherits from the original table via multiple
6616  * inheritance paths, it will be visited just once.
6617  */
6618 static void
6620  AlterTableCmd *cmd, bool recurse, LOCKMODE lockmode,
6622 {
6623  /*
6624  * Propagate to children, if desired and if there are (or might be) any
6625  * children.
6626  */
6627  if (recurse && rel->rd_rel->relhassubclass)
6628  {
6629  Oid relid = RelationGetRelid(rel);
6630  ListCell *child;
6631  List *children;
6632 
6633  children = find_all_inheritors(relid, lockmode, NULL);
6634 
6635  /*
6636  * find_all_inheritors does the recursive search of the inheritance
6637  * hierarchy, so all we have to do is process all of the relids in the
6638  * list that it returns.
6639  */
6640  foreach(child, children)
6641  {
6642  Oid childrelid = lfirst_oid(child);
6643  Relation childrel;
6644 
6645  if (childrelid == relid)
6646  continue;
6647  /* find_all_inheritors already got lock */
6648  childrel = relation_open(childrelid, NoLock);
6649  CheckAlterTableIsSafe(childrel);
6650  ATPrepCmd(wqueue, childrel, cmd, false, true, lockmode, context);
6651  relation_close(childrel, NoLock);
6652  }
6653  }
6654 }
6655 
6656 /*
6657  * Obtain list of partitions of the given table, locking them all at the given
6658  * lockmode and ensuring that they all pass CheckAlterTableIsSafe.
6659  *
6660  * This function is a no-op if the given relation is not a partitioned table;
6661  * in particular, nothing is done if it's a legacy inheritance parent.
6662  */
6663 static void
6665 {
6666  if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
6667  {
6668  List *inh;
6669  ListCell *cell;
6670 
6671  inh = find_all_inheritors(RelationGetRelid(rel), lockmode, NULL);
6672  /* first element is the parent rel; must ignore it */
6673  for_each_from(cell, inh, 1)
6674  {
6675  Relation childrel;
6676 
6677  /* find_all_inheritors already got lock */
6678  childrel = table_open(lfirst_oid(cell), NoLock);
6679  CheckAlterTableIsSafe(childrel);
6680  table_close(childrel, NoLock);
6681  }
6682  list_free(inh);
6683  }
6684 }
6685 
6686 /*
6687  * ATTypedTableRecursion
6688  *
6689  * Propagate ALTER TYPE operations to the typed tables of that type.
6690  * Also check the RESTRICT/CASCADE behavior. Given CASCADE, also permit
6691  * recursion to inheritance children of the typed tables.
6692  */
6693 static void
6696 {
6697  ListCell *child;
6698  List *children;
6699 
6700  Assert(rel->rd_rel->relkind == RELKIND_COMPOSITE_TYPE);
6701 
6702  children = find_typed_table_dependencies(rel->rd_rel->reltype,
6704  cmd->behavior);
6705 
6706  foreach(child, children)
6707  {
6708  Oid childrelid = lfirst_oid(child);
6709  Relation childrel;
6710 
6711  childrel = relation_open(childrelid, lockmode);
6712  CheckAlterTableIsSafe(childrel);
6713  ATPrepCmd(wqueue, childrel, cmd, true, true, lockmode, context);
6714  relation_close(childrel, NoLock);
6715  }
6716 }
6717 
6718 
6719 /*
6720  * find_composite_type_dependencies
6721  *
6722  * Check to see if the type "typeOid" is being used as a column in some table
6723  * (possibly nested several levels deep in composite types, arrays, etc!).
6724  * Eventually, we'd like to propagate the check or rewrite operation
6725  * into such tables, but for now, just error out if we find any.
6726  *
6727  * Caller should provide either the associated relation of a rowtype,
6728  * or a type name (not both) for use in the error message, if any.
6729  *
6730  * Note that "typeOid" is not necessarily a composite type; it could also be
6731  * another container type such as an array or range, or a domain over one of
6732  * these things. The name of this function is therefore somewhat historical,
6733  * but it's not worth changing.
6734  *
6735  * We assume that functions and views depending on the type are not reasons
6736  * to reject the ALTER. (How safe is this really?)
6737  */
6738 void
6740  const char *origTypeName)
6741 {
6742  Relation depRel;
6743  ScanKeyData key[2];
6744  SysScanDesc depScan;
6745  HeapTuple depTup;
6746 
6747  /* since this function recurses, it could be driven to stack overflow */
6749 
6750  /*
6751  * We scan pg_depend to find those things that depend on the given type.
6752  * (We assume we can ignore refobjsubid for a type.)
6753  */
6754  depRel = table_open(DependRelationId, AccessShareLock);
6755 
6756  ScanKeyInit(&key[0],
6757  Anum_pg_depend_refclassid,
6758  BTEqualStrategyNumber, F_OIDEQ,
6759  ObjectIdGetDatum(TypeRelationId));
6760  ScanKeyInit(&key[1],
6761  Anum_pg_depend_refobjid,
6762  BTEqualStrategyNumber, F_OIDEQ,
6763  ObjectIdGetDatum(typeOid));
6764 
6765  depScan = systable_beginscan(depRel, DependReferenceIndexId, true,
6766  NULL, 2, key);
6767 
6768  while (HeapTupleIsValid(depTup = systable_getnext(depScan)))
6769  {
6770  Form_pg_depend pg_depend = (Form_pg_depend) GETSTRUCT(depTup);
6771  Relation rel;
6772  TupleDesc tupleDesc;
6773  Form_pg_attribute att;
6774 
6775  /* Check for directly dependent types */
6776  if (pg_depend->classid == TypeRelationId)
6777  {
6778  /*
6779  * This must be an array, domain, or range containing the given
6780  * type, so recursively check for uses of this type. Note that
6781  * any error message will mention the original type not the
6782  * container; this is intentional.
6783  */
6784  find_composite_type_dependencies(pg_depend->objid,
6785  origRelation, origTypeName);
6786  continue;
6787  }
6788 
6789  /* Else, ignore dependees that aren't relations */
6790  if (pg_depend->classid != RelationRelationId)
6791  continue;
6792 
6793  rel = relation_open(pg_depend->objid, AccessShareLock);
6794  tupleDesc = RelationGetDescr(rel);
6795 
6796  /*
6797  * If objsubid identifies a specific column, refer to that in error
6798  * messages. Otherwise, search to see if there's a user column of the
6799  * type. (We assume system columns are never of interesting types.)
6800  * The search is needed because an index containing an expression
6801  * column of the target type will just be recorded as a whole-relation
6802  * dependency. If we do not find a column of the type, the dependency
6803  * must indicate that the type is transiently referenced in an index
6804  * expression but not stored on disk, which we assume is OK, just as
6805  * we do for references in views. (It could also be that the target
6806  * type is embedded in some container type that is stored in an index
6807  * column, but the previous recursion should catch such cases.)
6808  */
6809  if (pg_depend->objsubid > 0 && pg_depend->objsubid <= tupleDesc->natts)
6810  att = TupleDescAttr(tupleDesc, pg_depend->objsubid - 1);
6811  else
6812  {
6813  att = NULL;
6814  for (int attno = 1; attno <= tupleDesc->natts; attno++)
6815  {
6816  att = TupleDescAttr(tupleDesc, attno - 1);
6817  if (att->atttypid == typeOid && !att->attisdropped)
6818  break;
6819  att = NULL;
6820  }
6821  if (att == NULL)
6822  {
6823  /* No such column, so assume OK */
6825  continue;
6826  }
6827  }
6828 
6829  /*
6830  * We definitely should reject if the relation has storage. If it's
6831  * partitioned, then perhaps we don't have to reject: if there are
6832  * partitions then we'll fail when we find one, else there is no
6833  * stored data to worry about. However, it's possible that the type
6834  * change would affect conclusions about whether the type is sortable
6835  * or hashable and thus (if it's a partitioning column) break the
6836  * partitioning rule. For now, reject for partitioned rels too.
6837  */
6838  if (RELKIND_HAS_STORAGE(rel->rd_rel->relkind) ||
6839  RELKIND_HAS_PARTITIONS(rel->rd_rel->relkind))
6840  {
6841  if (origTypeName)
6842  ereport(ERROR,
6843  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
6844  errmsg("cannot alter type \"%s\" because column \"%s.%s\" uses it",
6845  origTypeName,
6847  NameStr(att->attname))));
6848  else if (origRelation->rd_rel->relkind == RELKIND_COMPOSITE_TYPE)
6849  ereport(ERROR,
6850  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
6851  errmsg("cannot alter type \"%s\" because column \"%s.%s\" uses it",
6852  RelationGetRelationName(origRelation),
6854  NameStr(att->attname))));
6855  else if (origRelation->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
6856  ereport(ERROR,
6857  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
6858  errmsg("cannot alter foreign table \"%s\" because column \"%s.%s\" uses its row type",
6859  RelationGetRelationName(origRelation),
6861  NameStr(att->attname))));
6862  else
6863  ereport(ERROR,
6864  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
6865  errmsg("cannot alter table \"%s\" because column \"%s.%s\" uses its row type",
6866  RelationGetRelationName(origRelation),
6868  NameStr(att->attname))));
6869  }
6870  else if (OidIsValid(rel->rd_rel->reltype))
6871  {
6872  /*
6873  * A view or composite type itself isn't a problem, but we must
6874  * recursively check for indirect dependencies via its rowtype.
6875  */
6877  origRelation, origTypeName);
6878  }
6879 
6881  }
6882 
6883  systable_endscan(depScan);
6884 
6886 }
6887 
6888 
6889 /*
6890  * find_typed_table_dependencies
6891  *
6892  * Check to see if a composite type is being used as the type of a
6893  * typed table. Abort if any are found and behavior is RESTRICT.
6894  * Else return the list of tables.
6895  */
6896 static List *
6897 find_typed_table_dependencies(Oid typeOid, const char *typeName, DropBehavior behavior)
6898 {
6899  Relation classRel;
6900  ScanKeyData key[1];
6901  TableScanDesc scan;
6902  HeapTuple tuple;
6903  List *result = NIL;
6904 
6905  classRel = table_open(RelationRelationId, AccessShareLock);
6906 
6907  ScanKeyInit(&key[0],
6908  Anum_pg_class_reloftype,
6909  BTEqualStrategyNumber, F_OIDEQ,
6910  ObjectIdGetDatum(typeOid));
6911 
6912  scan = table_beginscan_catalog(classRel, 1, key);
6913 
6914  while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
6915  {
6916  Form_pg_class classform = (Form_pg_class) GETSTRUCT(tuple);
6917 
6918  if (behavior == DROP_RESTRICT)
6919  ereport(ERROR,
6920  (errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
6921  errmsg("cannot alter type \"%s\" because it is the type of a typed table",
6922  typeName),
6923  errhint("Use ALTER ... CASCADE to alter the typed tables too.")));
6924  else
6925  result = lappend_oid(result, classform->oid);
6926  }
6927 
6928  table_endscan(scan);
6929  table_close(classRel, AccessShareLock);
6930 
6931  return result;
6932 }
6933 
6934 
6935 /*
6936  * check_of_type
6937  *
6938  * Check whether a type is suitable for CREATE TABLE OF/ALTER TABLE OF. If it
6939  * isn't suitable, throw an error. Currently, we require that the type
6940  * originated with CREATE TYPE AS. We could support any row type, but doing so
6941  * would require handling a number of extra corner cases in the DDL commands.
6942  * (Also, allowing domain-over-composite would open up a can of worms about
6943  * whether and how the domain's constraints should apply to derived tables.)
6944  */
6945 void
6947 {
6948  Form_pg_type typ = (Form_pg_type) GETSTRUCT(typetuple);
6949  bool typeOk = false;
6950 
6951  if (typ->typtype == TYPTYPE_COMPOSITE)
6952  {
6953  Relation typeRelation;
6954 
6955  Assert(OidIsValid(typ->typrelid));
6956  typeRelation = relation_open(typ->typrelid, AccessShareLock);
6957  typeOk = (typeRelation->rd_rel->relkind == RELKIND_COMPOSITE_TYPE);
6958 
6959  /*
6960  * Close the parent rel, but keep our AccessShareLock on it until xact
6961  * commit. That will prevent someone else from deleting or ALTERing
6962  * the type before the typed table creation/conversion commits.
6963  */
6964  relation_close(typeRelation, NoLock);
6965 
6966  if (!typeOk)
6967  ereport(ERROR,
6968  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
6969  errmsg("type %s is the row type of another table",
6970  format_type_be(typ->oid)),
6971  errdetail("A typed table must use a stand-alone composite type created with CREATE TYPE.")));
6972  }
6973  else
6974  ereport(ERROR,
6975  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
6976  errmsg("type %s is not a composite type",
6977  format_type_be(typ->oid))));
6978 }
6979 
6980 
6981 /*
6982  * ALTER TABLE ADD COLUMN
6983  *
6984  * Adds an additional attribute to a relation making the assumption that
6985  * CHECK, NOT NULL, and FOREIGN KEY constraints will be removed from the
6986  * AT_AddColumn AlterTableCmd by parse_utilcmd.c and added as independent
6987  * AlterTableCmd's.
6988  *
6989  * ADD COLUMN cannot use the normal ALTER TABLE recursion mechanism, because we
6990  * have to decide at runtime whether to recurse or not depending on whether we
6991  * actually add a column or merely merge with an existing column. (We can't
6992  * check this in a static pre-pass because it won't handle multiple inheritance
6993  * situations correctly.)
6994  */
6995 static void
6996 ATPrepAddColumn(List **wqueue, Relation rel, bool recurse, bool recursing,
6997  bool is_view, AlterTableCmd *cmd, LOCKMODE lockmode,
6999 {
7000  if (rel->rd_rel->reloftype && !recursing)
7001  ereport(ERROR,
7002  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
7003  errmsg("cannot add column to typed table")));
7004 
7005  if (rel->rd_rel->relkind == RELKIND_COMPOSITE_TYPE)
7006  ATTypedTableRecursion(wqueue, rel, cmd, lockmode, context);
7007 
7008  if (recurse && !is_view)
7009  cmd->recurse = true;
7010 }
7011 
7012 /*
7013  * Add a column to a table. The return value is the address of the
7014  * new column in the parent relation.
7015  *
7016  * cmd is pass-by-ref so that we can replace it with the parse-transformed
7017  * copy (but that happens only after we check for IF NOT EXISTS).
7018  */
7019 static ObjectAddress
7021  AlterTableCmd **cmd, bool recurse, bool recursing,
7022  LOCKMODE lockmode, AlterTablePass cur_pass,
7024 {
7025  Oid myrelid = RelationGetRelid(rel);
7026  ColumnDef *colDef = castNode(ColumnDef, (*cmd)->def);
7027  bool if_not_exists = (*cmd)->missing_ok;
7028  Relation pgclass,
7029  attrdesc;
7030  HeapTuple reltup;
7031  Form_pg_attribute attribute;
7032  int newattnum;
7033  char relkind;
7034  Expr *defval;
7035  List *children;
7036  ListCell *child;
7037  AlterTableCmd *childcmd;
7038  ObjectAddress address;
7039  TupleDesc tupdesc;
7040 
7041  /* since this function recurses, it could be driven to stack overflow */
7043 
7044  /* At top level, permission check was done in ATPrepCmd, else do it */
7045  if (recursing)
7046  ATSimplePermissions((*cmd)->subtype, rel, ATT_TABLE | ATT_FOREIGN_TABLE);
7047 
7048  if (rel->rd_rel->relispartition && !recursing)
7049  ereport(ERROR,
7050  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
7051  errmsg("cannot add column to a partition")));
7052 
7053  attrdesc = table_open(AttributeRelationId, RowExclusiveLock);
7054 
7055  /*
7056  * Are we adding the column to a recursion child? If so, check whether to
7057  * merge with an existing definition for the column. If we do merge, we
7058  * must not recurse. Children will already have the column, and recursing
7059  * into them would mess up attinhcount.
7060  */
7061  if (colDef->inhcount > 0)
7062  {
7063  HeapTuple tuple;
7064 
7065  /* Does child already have a column by this name? */
7066  tuple = SearchSysCacheCopyAttName(myrelid, colDef->colname);
7067  if (HeapTupleIsValid(tuple))
7068  {
7069  Form_pg_attribute childatt = (Form_pg_attribute) GETSTRUCT(tuple);
7070  Oid ctypeId;
7071  int32 ctypmod;
7072  Oid ccollid;
7073 
7074  /* Child column must match on type, typmod, and collation */
7075  typenameTypeIdAndMod(NULL, colDef->typeName, &ctypeId, &ctypmod);
7076  if (ctypeId != childatt->atttypid ||
7077  ctypmod != childatt->atttypmod)
7078  ereport(ERROR,
7079  (errcode(ERRCODE_DATATYPE_MISMATCH),
7080  errmsg("child table \"%s\" has different type for column \"%s\"",
7081  RelationGetRelationName(rel), colDef->colname)));
7082  ccollid = GetColumnDefCollation(NULL, colDef, ctypeId);
7083  if (ccollid != childatt->attcollation)
7084  ereport(ERROR,
7085  (errcode(ERRCODE_COLLATION_MISMATCH),
7086  errmsg("child table \"%s\" has different collation for column \"%s\"",
7087  RelationGetRelationName(rel), colDef->colname),
7088  errdetail("\"%s\" versus \"%s\"",
7089  get_collation_name(ccollid),
7090  get_collation_name(childatt->attcollation))));
7091 
7092  /* Bump the existing child att's inhcount */
7093  childatt->attinhcount++;
7094  if (childatt->attinhcount < 0)
7095  ereport(ERROR,
7096  errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
7097  errmsg("too many inheritance parents"));
7098  CatalogTupleUpdate(attrdesc, &tuple->t_self, tuple);
7099 
7100  heap_freetuple(tuple);
7101 
7102  /* Inform the user about the merge */
7103  ereport(NOTICE,
7104  (errmsg("merging definition of column \"%s\" for child \"%s\"",
7105  colDef->colname, RelationGetRelationName(rel))));
7106 
7107  table_close(attrdesc, RowExclusiveLock);
7108 
7109  /* Make the child column change visible */
7111 
7112  return InvalidObjectAddress;
7113  }
7114  }
7115 
7116  /* skip if the name already exists and if_not_exists is true */
7117  if (!check_for_column_name_collision(rel, colDef->colname, if_not_exists))
7118  {
7119  table_close(attrdesc, RowExclusiveLock);
7120  return InvalidObjectAddress;
7121  }
7122 
7123  /*
7124  * Okay, we need to add the column, so go ahead and do parse
7125  * transformation. This can result in queueing up, or even immediately
7126  * executing, subsidiary operations (such as creation of unique indexes);
7127  * so we mustn't do it until we have made the if_not_exists check.
7128  *
7129  * When recursing, the command was already transformed and we needn't do
7130  * so again. Also, if context isn't given we can't transform. (That
7131  * currently happens only for AT_AddColumnToView; we expect that view.c
7132  * passed us a ColumnDef that doesn't need work.)
7133  */
7134  if (context != NULL && !recursing)
7135  {
7136  *cmd = ATParseTransformCmd(wqueue, tab, rel, *cmd, recurse, lockmode,
7137  cur_pass, context);
7138  Assert(*cmd != NULL);
7139  colDef = castNode(ColumnDef, (*cmd)->def);
7140  }
7141 
7142  /*
7143  * Regular inheritance children are independent enough not to inherit the
7144  * identity column from parent hence cannot recursively add identity
7145  * column if the table has inheritance children.
7146  *
7147  * Partitions, on the other hand, are integral part of a partitioned table
7148  * and inherit identity column. Hence propagate identity column down the
7149  * partition hierarchy.
7150  */
7151  if (colDef->identity &&
7152  recurse &&
7153  rel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE &&
7154  find_inheritance_children(myrelid, NoLock) != NIL)
7155  ereport(ERROR,
7156  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
7157  errmsg("cannot recursively add identity column to table that has child tables")));
7158 
7159  pgclass = table_open(RelationRelationId, RowExclusiveLock);
7160 
7161  reltup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(myrelid));
7162  if (!HeapTupleIsValid(reltup))
7163  elog(ERROR, "cache lookup failed for relation %u", myrelid);
7164  relkind = ((Form_pg_class) GETSTRUCT(reltup))->relkind;
7165 
7166  /* Determine the new attribute's number */
7167  newattnum = ((Form_pg_class) GETSTRUCT(reltup))->relnatts + 1;
7168  if (newattnum > MaxHeapAttributeNumber)
7169  ereport(ERROR,
7170  (errcode(ERRCODE_TOO_MANY_COLUMNS),
7171  errmsg("tables can have at most %d columns",
7173 
7174  /*
7175  * Construct new attribute's pg_attribute entry.
7176  */
7177  tupdesc = BuildDescForRelation(list_make1(colDef));
7178 
7179  attribute = TupleDescAttr(tupdesc, 0);
7180 
7181  /* Fix up attribute number */
7182  attribute->attnum = newattnum;
7183 
7184  /* make sure datatype is legal for a column */
7185  CheckAttributeType(NameStr(attribute->attname), attribute->atttypid, attribute->attcollation,
7186  list_make1_oid(rel->rd_rel->reltype),
7187  0);
7188 
7189  InsertPgAttributeTuples(attrdesc, tupdesc, myrelid, NULL, NULL);
7190 
7191  table_close(attrdesc, RowExclusiveLock);
7192 
7193  /*
7194  * Update pg_class tuple as appropriate
7195  */
7196  ((Form_pg_class) GETSTRUCT(reltup))->relnatts = newattnum;
7197 
7198  CatalogTupleUpdate(pgclass, &reltup->t_self, reltup);
7199 
7200  heap_freetuple(reltup);
7201 
7202  /* Post creation hook for new attribute */
7203  InvokeObjectPostCreateHook(RelationRelationId, myrelid, newattnum);
7204 
7205  table_close(pgclass, RowExclusiveLock);
7206 
7207  /* Make the attribute's catalog entry visible */
7209 
7210  /*
7211  * Store the DEFAULT, if any, in the catalogs
7212  */
7213  if (colDef->raw_default)
7214  {
7215  RawColumnDefault *rawEnt;
7216 
7217  rawEnt = (RawColumnDefault *) palloc(sizeof(RawColumnDefault));
7218  rawEnt->attnum = attribute->attnum;
7219  rawEnt->raw_default = copyObject(colDef->raw_default);
7220 
7221  /*
7222  * Attempt to skip a complete table rewrite by storing the specified
7223  * DEFAULT value outside of the heap. This may be disabled inside
7224  * AddRelationNewConstraints if the optimization cannot be applied.
7225  */
7226  rawEnt->missingMode = (!colDef->generated);
7227 
7228  rawEnt->generated = colDef->generated;
7229 
7230  /*
7231  * This function is intended for CREATE TABLE, so it processes a
7232  * _list_ of defaults, but we just do one.
7233  */
7235  false, true, false, NULL);
7236 
7237  /* Make the additional catalog changes visible */
7239 
7240  /*
7241  * Did the request for a missing value work? If not we'll have to do a
7242  * rewrite
7243  */
7244  if (!rawEnt->missingMode)
7246  }
7247 
7248  /*
7249  * Tell Phase 3 to fill in the default expression, if there is one.
7250  *
7251  * If there is no default, Phase 3 doesn't have to do anything, because
7252  * that effectively means that the default is NULL. The heap tuple access
7253  * routines always check for attnum > # of attributes in tuple, and return
7254  * NULL if so, so without any modification of the tuple data we will get
7255  * the effect of NULL values in the new column.
7256  *
7257  * An exception occurs when the new column is of a domain type: the domain
7258  * might have a not-null constraint, or a check constraint that indirectly
7259  * rejects nulls. If there are any domain constraints then we construct
7260  * an explicit NULL default value that will be passed through
7261  * CoerceToDomain processing. (This is a tad inefficient, since it causes
7262  * rewriting the table which we really don't have to do, but the present
7263  * design of domain processing doesn't offer any simple way of checking
7264  * the constraints more directly.)
7265  *
7266  * Note: we use build_column_default, and not just the cooked default
7267  * returned by AddRelationNewConstraints, so that the right thing happens
7268  * when a datatype's default applies.
7269  *
7270  * Note: it might seem that this should happen at the end of Phase 2, so
7271  * that the effects of subsequent subcommands can be taken into account.
7272  * It's intentional that we do it now, though. The new column should be
7273  * filled according to what is said in the ADD COLUMN subcommand, so that
7274  * the effects are the same as if this subcommand had been run by itself
7275  * and the later subcommands had been issued in new ALTER TABLE commands.
7276  *
7277  * We can skip this entirely for relations without storage, since Phase 3
7278  * is certainly not going to touch them. System attributes don't have
7279  * interesting defaults, either.
7280  */
7281  if (RELKIND_HAS_STORAGE(relkind))
7282  {
7283  /*
7284  * For an identity column, we can't use build_column_default(),
7285  * because the sequence ownership isn't set yet. So do it manually.
7286  */
7287  if (colDef->identity)
7288  {
7290 
7291  nve->seqid = RangeVarGetRelid(colDef->identitySequence, NoLock, false);
7292  nve->typeId = attribute->atttypid;
7293 
7294  defval = (Expr *) nve;
7295 
7296  /* must do a rewrite for identity columns */
7298  }
7299  else
7300  defval = (Expr *) build_column_default(rel, attribute->attnum);
7301 
7302  if (!defval && DomainHasConstraints(attribute->atttypid))
7303  {
7304  Oid baseTypeId;
7305  int32 baseTypeMod;
7306  Oid baseTypeColl;
7307 
7308  baseTypeMod = attribute->atttypmod;
7309  baseTypeId = getBaseTypeAndTypmod(attribute->atttypid, &baseTypeMod);
7310  baseTypeColl = get_typcollation(baseTypeId);
7311  defval = (Expr *) makeNullConst(baseTypeId, baseTypeMod, baseTypeColl);
7312  defval = (Expr *) coerce_to_target_type(NULL,
7313  (Node *) defval,
7314  baseTypeId,
7315  attribute->atttypid,
7316  attribute->atttypmod,
7319  -1);
7320  if (defval == NULL) /* should not happen */
7321  elog(ERROR, "failed to coerce base type to domain");
7322  }
7323 
7324  if (defval)
7325  {
7327 
7329  newval->attnum = attribute->attnum;
7330  newval->expr = expression_planner(defval);
7331  newval->is_generated = (colDef->generated != '\0');
7332 
7333  tab->newvals = lappend(tab->newvals, newval);
7334  }
7335 
7336  if (DomainHasConstraints(attribute->atttypid))
7338 
7339  if (!TupleDescAttr(rel->rd_att, attribute->attnum - 1)->atthasmissing)
7340  {
7341  /*
7342  * If the new column is NOT NULL, and there is no missing value,
7343  * tell Phase 3 it needs to check for NULLs.
7344  */
7345  tab->verify_new_notnull |= colDef->is_not_null;
7346  }
7347  }
7348 
7349  /*
7350  * Add needed dependency entries for the new column.
7351  */
7352  add_column_datatype_dependency(myrelid, newattnum, attribute->atttypid);
7353  add_column_collation_dependency(myrelid, newattnum, attribute->attcollation);
7354 
7355  /*
7356  * Propagate to children as appropriate. Unlike most other ALTER
7357  * routines, we have to do this one level of recursion at a time; we can't
7358  * use find_all_inheritors to do it in one pass.
7359  */
7360  children =
7362 
7363  /*
7364  * If we are told not to recurse, there had better not be any child
7365  * tables; else the addition would put them out of step.
7366  */
7367  if (children && !recurse)
7368  ereport(ERROR,
7369  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
7370  errmsg("column must be added to child tables too")));
7371 
7372  /* Children should see column as singly inherited */
7373  if (!recursing)
7374  {
7375  childcmd = copyObject(*cmd);
7376  colDef = castNode(ColumnDef, childcmd->def);
7377  colDef->inhcount = 1;
7378  colDef->is_local = false;
7379  }
7380  else
7381  childcmd = *cmd; /* no need to copy again */
7382 
7383  foreach(child, children)
7384  {
7385  Oid childrelid = lfirst_oid(child);
7386  Relation childrel;
7387  AlteredTableInfo *childtab;
7388 
7389  /* find_inheritance_children already got lock */
7390  childrel = table_open(childrelid, NoLock);
7391  CheckAlterTableIsSafe(childrel);
7392 
7393  /* Find or create work queue entry for this table */
7394  childtab = ATGetQueueEntry(wqueue, childrel);
7395 
7396  /* Recurse to child; return value is ignored */
7397  ATExecAddColumn(wqueue, childtab, childrel,
7398  &childcmd, recurse, true,
7399  lockmode, cur_pass, context);
7400 
7401  table_close(childrel, NoLock);
7402  }
7403 
7404  ObjectAddressSubSet(address, RelationRelationId, myrelid, newattnum);
7405  return address;
7406 }
7407 
7408 /*
7409  * If a new or renamed column will collide with the name of an existing
7410  * column and if_not_exists is false then error out, else do nothing.
7411  */
7412 static bool
7414  bool if_not_exists)
7415 {
7416  HeapTuple attTuple;
7417  int attnum;
7418 
7419  /*
7420  * this test is deliberately not attisdropped-aware, since if one tries to
7421  * add a column matching a dropped column name, it's gonna fail anyway.
7422  */
7423  attTuple = SearchSysCache2(ATTNAME,
7425  PointerGetDatum(colname));
7426  if (!HeapTupleIsValid(attTuple))
7427  return true;
7428 
7429  attnum = ((Form_pg_attribute) GETSTRUCT(attTuple))->attnum;
7430  ReleaseSysCache(attTuple);
7431 
7432  /*
7433  * We throw a different error message for conflicts with system column
7434  * names, since they are normally not shown and the user might otherwise
7435  * be confused about the reason for the conflict.
7436  */
7437  if (attnum <= 0)
7438  ereport(ERROR,
7439  (errcode(ERRCODE_DUPLICATE_COLUMN),
7440  errmsg("column name \"%s\" conflicts with a system column name",
7441  colname)));
7442  else
7443  {
7444  if (if_not_exists)
7445  {
7446  ereport(NOTICE,
7447  (errcode(ERRCODE_DUPLICATE_COLUMN),
7448  errmsg("column \"%s\" of relation \"%s\" already exists, skipping",
7449  colname, RelationGetRelationName(rel))));
7450  return false;
7451  }
7452 
7453  ereport(ERROR,
7454  (errcode(ERRCODE_DUPLICATE_COLUMN),
7455  errmsg("column \"%s\" of relation \"%s\" already exists",
7456  colname, RelationGetRelationName(rel))));
7457  }
7458 
7459  return true;
7460 }
7461 
7462 /*
7463  * Install a column's dependency on its datatype.
7464  */
7465 static void
7467 {
7468  ObjectAddress myself,
7469  referenced;
7470 
7471  myself.classId = RelationRelationId;
7472  myself.objectId = relid;
7473  myself.objectSubId = attnum;
7474  referenced.classId = TypeRelationId;
7475  referenced.objectId = typid;
7476  referenced.objectSubId = 0;
7477  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
7478 }
7479 
7480 /*
7481  * Install a column's dependency on its collation.
7482  */
7483 static void
7485 {
7486  ObjectAddress myself,
7487  referenced;
7488 
7489  /* We know the default collation is pinned, so don't bother recording it */
7490  if (OidIsValid(collid) && collid != DEFAULT_COLLATION_OID)
7491  {
7492  myself.classId = RelationRelationId;
7493  myself.objectId = relid;
7494  myself.objectSubId = attnum;
7495  referenced.classId = CollationRelationId;
7496  referenced.objectId = collid;
7497  referenced.objectSubId = 0;
7498  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
7499  }
7500 }
7501 
7502 /*
7503  * ALTER TABLE ALTER COLUMN DROP NOT NULL
7504  */
7505 
7506 static void
7507 ATPrepDropNotNull(Relation rel, bool recurse, bool recursing)
7508 {
7509  /*
7510  * If the parent is a partitioned table, like check constraints, we do not
7511  * support removing the NOT NULL while partitions exist.
7512  */
7513  if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
7514  {
7515  PartitionDesc partdesc = RelationGetPartitionDesc(rel, true);
7516 
7517  Assert(partdesc != NULL);
7518  if (partdesc->nparts > 0 && !recurse && !recursing)
7519  ereport(ERROR,
7520  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
7521  errmsg("cannot remove constraint from only the partitioned table when partitions exist"),
7522  errhint("Do not specify the ONLY keyword.")));
7523  }
7524 }
7525 
7526 /*
7527  * Return the address of the modified column. If the column was already
7528  * nullable, InvalidObjectAddress is returned.
7529  */
7530 static ObjectAddress
7531 ATExecDropNotNull(Relation rel, const char *colName, LOCKMODE lockmode)
7532 {
7533  HeapTuple tuple;
7534  Form_pg_attribute attTup;
7536  Relation attr_rel;
7537  List *indexoidlist;
7538  ObjectAddress address;
7539 
7540  /*
7541  * lookup the attribute
7542  */
7543  attr_rel = table_open(AttributeRelationId, RowExclusiveLock);
7544 
7545  tuple = SearchSysCacheCopyAttName(RelationGetRelid(rel), colName);
7546  if (!HeapTupleIsValid(tuple))
7547  ereport(ERROR,
7548  (errcode(ERRCODE_UNDEFINED_COLUMN),
7549  errmsg("column \"%s\" of relation \"%s\" does not exist",
7550  colName, RelationGetRelationName(rel))));
7551  attTup = (Form_pg_attribute) GETSTRUCT(tuple);
7552  attnum = attTup->attnum;
7553 
7554  /* Prevent them from altering a system attribute */
7555  if (attnum <= 0)
7556  ereport(ERROR,
7557  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
7558  errmsg("cannot alter system column \"%s\"",
7559  colName)));
7560 
7561  if (attTup->attidentity)
7562  ereport(ERROR,
7563  (errcode(ERRCODE_SYNTAX_ERROR),
7564  errmsg("column \"%s\" of relation \"%s\" is an identity column",
7565  colName, RelationGetRelationName(rel))));
7566 
7567  /*
7568  * Check that the attribute is not in a primary key or in an index used as
7569  * a replica identity.
7570  *
7571  * Note: we'll throw error even if the pkey index is not valid.
7572  */
7573 
7574  /* Loop over all indexes on the relation */
7575  indexoidlist = RelationGetIndexList(rel);
7576 
7577  foreach_oid(indexoid, indexoidlist)
7578  {
7579  HeapTuple indexTuple;
7580  Form_pg_index indexStruct;
7581 
7582  indexTuple = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(indexoid));
7583  if (!HeapTupleIsValid(indexTuple))
7584  elog(ERROR, "cache lookup failed for index %u", indexoid);
7585  indexStruct = (Form_pg_index) GETSTRUCT(indexTuple);
7586 
7587  /*
7588  * If the index is not a primary key or an index used as replica
7589  * identity, skip the check.
7590  */
7591  if (indexStruct->indisprimary || indexStruct->indisreplident)
7592  {
7593  /*
7594  * Loop over each attribute in the primary key or the index used
7595  * as replica identity and see if it matches the to-be-altered
7596  * attribute.
7597  */
7598  for (int i = 0; i < indexStruct->indnkeyatts; i++)
7599  {
7600  if (indexStruct->indkey.values[i] == attnum)
7601  {
7602  if (indexStruct->indisprimary)
7603  ereport(ERROR,
7604  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
7605  errmsg("column \"%s\" is in a primary key",
7606  colName)));
7607  else
7608  ereport(ERROR,
7609  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
7610  errmsg("column \"%s\" is in index used as replica identity",
7611  colName)));
7612  }
7613  }
7614  }
7615 
7616  ReleaseSysCache(indexTuple);
7617  }
7618 
7619  list_free(indexoidlist);
7620 
7621  /* If rel is partition, shouldn't drop NOT NULL if parent has the same */
7622  if (rel->rd_rel->relispartition)
7623  {
7624  Oid parentId = get_partition_parent(RelationGetRelid(rel), false);
7625  Relation parent = table_open(parentId, AccessShareLock);
7626  TupleDesc tupDesc = RelationGetDescr(parent);
7627  AttrNumber parent_attnum;
7628 
7629  parent_attnum = get_attnum(parentId, colName);
7630  if (TupleDescAttr(tupDesc, parent_attnum - 1)->attnotnull)
7631  ereport(ERROR,
7632  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
7633  errmsg("column \"%s\" is marked NOT NULL in parent table",
7634  colName)));
7635  table_close(parent, AccessShareLock);
7636  }
7637 
7638  /*
7639  * Okay, actually perform the catalog change ... if needed
7640  */
7641  if (attTup->attnotnull)
7642  {
7643  attTup->attnotnull = false;
7644 
7645  CatalogTupleUpdate(attr_rel, &tuple->t_self, tuple);
7646 
7647  ObjectAddressSubSet(address, RelationRelationId,
7648  RelationGetRelid(rel), attnum);
7649  }
7650  else
7651  address = InvalidObjectAddress;
7652 
7653  InvokeObjectPostAlterHook(RelationRelationId,
7654  RelationGetRelid(rel), attnum);
7655 
7656  table_close(attr_rel, RowExclusiveLock);
7657 
7658  return address;
7659 }
7660 
7661 /*
7662  * ALTER TABLE ALTER COLUMN SET NOT NULL
7663  */
7664 
7665 static void
7667  AlterTableCmd *cmd, bool recurse, bool recursing,
7669 {
7670  /*
7671  * If we're already recursing, there's nothing to do; the topmost
7672  * invocation of ATSimpleRecursion already visited all children.
7673  */
7674  if (recursing)
7675  return;
7676 
7677  /*
7678  * If the target column is already marked NOT NULL, we can skip recursing
7679  * to children, because their columns should already be marked NOT NULL as
7680  * well. But there's no point in checking here unless the relation has
7681  * some children; else we can just wait till execution to check. (If it
7682  * does have children, however, this can save taking per-child locks
7683  * unnecessarily. This greatly improves concurrency in some parallel
7684  * restore scenarios.)
7685  *
7686  * Unfortunately, we can only apply this optimization to partitioned
7687  * tables, because traditional inheritance doesn't enforce that child
7688  * columns be NOT NULL when their parent is. (That's a bug that should
7689  * get fixed someday.)
7690  */
7691  if (rel->rd_rel->relhassubclass &&
7692  rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
7693  {
7694  HeapTuple tuple;
7695  bool attnotnull;
7696 
7697  tuple = SearchSysCacheAttName(RelationGetRelid(rel), cmd->name);
7698 
7699  /* Might as well throw the error now, if name is bad */
7700  if (!HeapTupleIsValid(tuple))
7701  ereport(ERROR,
7702  (errcode(ERRCODE_UNDEFINED_COLUMN),
7703  errmsg("column \"%s\" of relation \"%s\" does not exist",
7704  cmd->name, RelationGetRelationName(rel))));
7705 
7707  ReleaseSysCache(tuple);
7708  if (attnotnull)
7709  return;
7710  }
7711 
7712  /*
7713  * If we have ALTER TABLE ONLY ... SET NOT NULL on a partitioned table,
7714  * apply ALTER TABLE ... CHECK NOT NULL to every child. Otherwise, use
7715  * normal recursion logic.
7716  */
7717  if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE &&
7718  !recurse)
7719  {
7721 
7722  newcmd->subtype = AT_CheckNotNull;
7723  newcmd->name = pstrdup(cmd->name);
7724  ATSimpleRecursion(wqueue, rel, newcmd, true, lockmode, context);
7725  }
7726  else
7727  ATSimpleRecursion(wqueue, rel, cmd, recurse, lockmode, context);
7728 }
7729 
7730 /*
7731  * Return the address of the modified column. If the column was already NOT
7732  * NULL, InvalidObjectAddress is returned.
7733  */
7734 static ObjectAddress
7736  const char *colName, LOCKMODE lockmode)
7737 {
7738  HeapTuple tuple;
7740  Relation attr_rel;
7741  ObjectAddress address;
7742 
7743  /*
7744  * lookup the attribute
7745  */
7746  attr_rel = table_open(AttributeRelationId, RowExclusiveLock);
7747 
7748  tuple = SearchSysCacheCopyAttName(RelationGetRelid(rel), colName);
7749 
7750  if (!HeapTupleIsValid(tuple))
7751  ereport(ERROR,
7752  (errcode(ERRCODE_UNDEFINED_COLUMN),
7753  errmsg("column \"%s\" of relation \"%s\" does not exist",
7754  colName, RelationGetRelationName(rel))));
7755 
7756  attnum = ((Form_pg_attribute) GETSTRUCT(tuple))->attnum;
7757 
7758  /* Prevent them from altering a system attribute */
7759  if (attnum <= 0)
7760  ereport(ERROR,
7761  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
7762  errmsg("cannot alter system column \"%s\"",
7763  colName)));
7764 
7765  /*
7766  * Okay, actually perform the catalog change ... if needed
7767  */
7768  if (!((Form_pg_attribute) GETSTRUCT(tuple))->attnotnull)
7769  {
7770  ((Form_pg_attribute) GETSTRUCT(tuple))->attnotnull = true;
7771 
7772  CatalogTupleUpdate(attr_rel, &tuple->t_self, tuple);
7773 
7774  /*
7775  * Ordinarily phase 3 must ensure that no NULLs exist in columns that
7776  * are set NOT NULL; however, if we can find a constraint which proves
7777  * this then we can skip that. We needn't bother looking if we've
7778  * already found that we must verify some other not-null constraint.
7779  */
7780  if (!tab->verify_new_notnull &&
7782  {
7783  /* Tell Phase 3 it needs to test the constraint */
7784  tab->verify_new_notnull = true;
7785  }
7786 
7787  ObjectAddressSubSet(address, RelationRelationId,
7788  RelationGetRelid(rel), attnum);
7789  }
7790  else
7791  address = InvalidObjectAddress;
7792 
7793  InvokeObjectPostAlterHook(RelationRelationId,
7794  RelationGetRelid(rel), attnum);
7795 
7796  table_close(attr_rel, RowExclusiveLock);
7797 
7798  return address;
7799 }
7800 
7801 /*
7802  * ALTER TABLE ALTER COLUMN CHECK NOT NULL
7803  *
7804  * This doesn't exist in the grammar, but we generate AT_CheckNotNull
7805  * commands against the partitions of a partitioned table if the user
7806  * writes ALTER TABLE ONLY ... SET NOT NULL on the partitioned table,
7807  * or tries to create a primary key on it (which internally creates
7808  * AT_SetNotNull on the partitioned table). Such a command doesn't
7809  * allow us to actually modify any partition, but we want to let it
7810  * go through if the partitions are already properly marked.
7811  *
7812  * In future, this might need to adjust the child table's state, likely
7813  * by incrementing an inheritance count for the attnotnull constraint.
7814  * For now we need only check for the presence of the flag.
7815  */
7816 static void
7818  const char *colName, LOCKMODE lockmode)
7819 {
7820  HeapTuple tuple;
7821 
7822  tuple = SearchSysCacheAttName(RelationGetRelid(rel), colName);
7823 
7824  if (!HeapTupleIsValid(tuple))
7825  ereport(ERROR,
7826  errcode(ERRCODE_UNDEFINED_COLUMN),
7827  errmsg("column \"%s\" of relation \"%s\" does not exist",
7828  colName, RelationGetRelationName(rel)));
7829 
7830  if (!((Form_pg_attribute) GETSTRUCT(tuple))->attnotnull)
7831  ereport(ERROR,
7832  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
7833  errmsg("constraint must be added to child tables too"),
7834  errdetail("Column \"%s\" of relation \"%s\" is not already NOT NULL.",
7835  colName, RelationGetRelationName(rel)),
7836  errhint("Do not specify the ONLY keyword.")));
7837 
7838  ReleaseSysCache(tuple);
7839 }
7840 
7841 /*
7842  * NotNullImpliedByRelConstraints
7843  * Does rel's existing constraints imply NOT NULL for the given attribute?
7844  */
7845 static bool
7847 {
7848  NullTest *nnulltest = makeNode(NullTest);
7849 
7850  nnulltest->arg = (Expr *) makeVar(1,
7851  attr->attnum,
7852  attr->atttypid,
7853  attr->atttypmod,
7854  attr->attcollation,
7855  0);
7856  nnulltest->nulltesttype = IS_NOT_NULL;
7857 
7858  /*
7859  * argisrow = false is correct even for a composite column, because
7860  * attnotnull does not represent a SQL-spec IS NOT NULL test in such a
7861  * case, just IS DISTINCT FROM NULL.
7862  */
7863  nnulltest->argisrow = false;
7864  nnulltest->location = -1;
7865 
7866  if (ConstraintImpliedByRelConstraint(rel, list_make1(nnulltest), NIL))
7867  {
7868  ereport(DEBUG1,
7869  (errmsg_internal("existing constraints on column \"%s.%s\" are sufficient to prove that it does not contain nulls",
7870  RelationGetRelationName(rel), NameStr(attr->attname))));
7871  return true;
7872  }
7873 
7874  return false;
7875 }
7876 
7877 /*
7878  * ALTER TABLE ALTER COLUMN SET/DROP DEFAULT
7879  *
7880  * Return the address of the affected column.
7881  */
7882 static ObjectAddress
7883 ATExecColumnDefault(Relation rel, const char *colName,
7884  Node *newDefault, LOCKMODE lockmode)
7885 {
7886  TupleDesc tupdesc = RelationGetDescr(rel);
7888  ObjectAddress address;
7889 
7890  /*
7891  * get the number of the attribute
7892  */
7893  attnum = get_attnum(RelationGetRelid(rel), colName);
7894  if (attnum == InvalidAttrNumber)
7895  ereport(ERROR,
7896  (errcode(ERRCODE_UNDEFINED_COLUMN),
7897  errmsg("column \"%s\" of relation \"%s\" does not exist",
7898  colName, RelationGetRelationName(rel))));
7899 
7900  /* Prevent them from altering a system attribute */
7901  if (attnum <= 0)
7902  ereport(ERROR,
7903  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
7904  errmsg("cannot alter system column \"%s\"",
7905  colName)));
7906 
7907  if (TupleDescAttr(tupdesc, attnum - 1)->attidentity)
7908  ereport(ERROR,
7909  (errcode(ERRCODE_SYNTAX_ERROR),
7910  errmsg("column \"%s\" of relation \"%s\" is an identity column",
7911  colName, RelationGetRelationName(rel)),
7912  /* translator: %s is an SQL ALTER command */
7913  newDefault ? 0 : errhint("Use %s instead.",
7914  "ALTER TABLE ... ALTER COLUMN ... DROP IDENTITY")));
7915 
7916  if (TupleDescAttr(tupdesc, attnum - 1)->attgenerated)
7917  ereport(ERROR,
7918  (errcode(ERRCODE_SYNTAX_ERROR),
7919  errmsg("column \"%s\" of relation \"%s\" is a generated column",
7920  colName, RelationGetRelationName(rel)),
7921  newDefault ?
7922  /* translator: %s is an SQL ALTER command */
7923  errhint("Use %s instead.", "ALTER TABLE ... ALTER COLUMN ... SET EXPRESSION") :
7924  (TupleDescAttr(tupdesc, attnum - 1)->attgenerated == ATTRIBUTE_GENERATED_STORED ?
7925  errhint("Use %s instead.", "ALTER TABLE ... ALTER COLUMN ... DROP EXPRESSION") : 0)));
7926 
7927  /*
7928  * Remove any old default for the column. We use RESTRICT here for
7929  * safety, but at present we do not expect anything to depend on the
7930  * default.
7931  *
7932  * We treat removing the existing default as an internal operation when it
7933  * is preparatory to adding a new default, but as a user-initiated
7934  * operation when the user asked for a drop.
7935  */
7937  newDefault != NULL);
7938 
7939  if (newDefault)
7940  {
7941  /* SET DEFAULT */
7942  RawColumnDefault *rawEnt;
7943 
7944  rawEnt = (RawColumnDefault *) palloc(sizeof(RawColumnDefault));
7945  rawEnt->attnum = attnum;
7946  rawEnt->raw_default = newDefault;
7947  rawEnt->missingMode = false;
7948  rawEnt->generated = '\0';
7949 
7950  /*
7951  * This function is intended for CREATE TABLE, so it processes a
7952  * _list_ of defaults, but we just do one.
7953  */
7955  false, true, false, NULL);
7956  }
7957 
7958  ObjectAddressSubSet(address, RelationRelationId,
7959  RelationGetRelid(rel), attnum);
7960  return address;
7961 }
7962 
7963 /*
7964  * Add a pre-cooked default expression.
7965  *
7966  * Return the address of the affected column.
7967  */
7968 static ObjectAddress
7970  Node *newDefault)
7971 {
7972  ObjectAddress address;
7973 
7974  /* We assume no checking is required */
7975 
7976  /*
7977  * Remove any old default for the column. We use RESTRICT here for
7978  * safety, but at present we do not expect anything to depend on the
7979  * default. (In ordinary cases, there could not be a default in place
7980  * anyway, but it's possible when combining LIKE with inheritance.)
7981  */
7983  true);
7984 
7985  (void) StoreAttrDefault(rel, attnum, newDefault, true, false);
7986 
7987  ObjectAddressSubSet(address, RelationRelationId,
7988  RelationGetRelid(rel), attnum);
7989  return address;
7990 }
7991 
7992 /*
7993  * ALTER TABLE ALTER COLUMN ADD IDENTITY
7994  *
7995  * Return the address of the affected column.
7996  */
7997 static ObjectAddress
7998 ATExecAddIdentity(Relation rel, const char *colName,
7999  Node *def, LOCKMODE lockmode, bool recurse, bool recursing)
8000 {
8001  Relation attrelation;
8002  HeapTuple tuple;
8003  Form_pg_attribute attTup;
8005  ObjectAddress address;
8006  ColumnDef *cdef = castNode(ColumnDef, def);
8007  bool ispartitioned;
8008 
8009  ispartitioned = (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
8010  if (ispartitioned && !recurse)
8011  ereport(ERROR,
8012  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
8013  errmsg("cannot add identity to a column of only the partitioned table"),
8014  errhint("Do not specify the ONLY keyword.")));
8015 
8016  if (rel->rd_rel->relispartition && !recursing)
8017  ereport(ERROR,
8018  errcode(ERRCODE_INVALID_TABLE_DEFINITION),
8019  errmsg("cannot add identity to a column of a partition"));
8020 
8021  attrelation = table_open(AttributeRelationId, RowExclusiveLock);
8022 
8023  tuple = SearchSysCacheCopyAttName(RelationGetRelid(rel), colName);
8024  if (!HeapTupleIsValid(tuple))
8025  ereport(ERROR,
8026  (errcode(ERRCODE_UNDEFINED_COLUMN),
8027  errmsg("column \"%s\" of relation \"%s\" does not exist",
8028  colName, RelationGetRelationName(rel))));
8029  attTup = (Form_pg_attribute) GETSTRUCT(tuple);
8030  attnum = attTup->attnum;
8031 
8032  /* Can't alter a system attribute */
8033  if (attnum <= 0)
8034  ereport(ERROR,
8035  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
8036  errmsg("cannot alter system column \"%s\"",
8037  colName)));
8038 
8039  /*
8040  * Creating a column as identity implies NOT NULL, so adding the identity
8041  * to an existing column that is not NOT NULL would create a state that
8042  * cannot be reproduced without contortions.
8043  */
8044  if (!attTup->attnotnull)
8045  ereport(ERROR,
8046  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
8047  errmsg("column \"%s\" of relation \"%s\" must be declared NOT NULL before identity can be added",
8048  colName, RelationGetRelationName(rel))));
8049 
8050  if (attTup->attidentity)
8051  ereport(ERROR,
8052  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
8053  errmsg("column \"%s\" of relation \"%s\" is already an identity column",
8054  colName, RelationGetRelationName(rel))));
8055 
8056  if (attTup->atthasdef)
8057  ereport(ERROR,
8058  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
8059  errmsg("column \"%s\" of relation \"%s\" already has a default value",
8060  colName, RelationGetRelationName(rel))));
8061 
8062  attTup->attidentity = cdef->identity;
8063  CatalogTupleUpdate(attrelation, &tuple->t_self, tuple);
8064 
8065  InvokeObjectPostAlterHook(RelationRelationId,
8066  RelationGetRelid(rel),
8067  attTup->attnum);
8068  ObjectAddressSubSet(address, RelationRelationId,
8069  RelationGetRelid(rel), attnum);
8070  heap_freetuple(tuple);
8071 
8072  table_close(attrelation, RowExclusiveLock);
8073 
8074  /*
8075  * Recurse to propagate the identity column to partitions. Identity is
8076  * not inherited in regular inheritance children.
8077  */
8078  if (recurse && ispartitioned)
8079  {
8080  List *children;
8081  ListCell *lc;
8082 
8083  children = find_inheritance_children(RelationGetRelid(rel), lockmode);
8084 
8085  foreach(lc, children)
8086  {
8087  Relation childrel;
8088 
8089  childrel = table_open(lfirst_oid(lc), NoLock);
8090  ATExecAddIdentity(childrel, colName, def, lockmode, recurse, true);
8091  table_close(childrel, NoLock);
8092  }
8093  }
8094 
8095  return address;
8096 }
8097 
8098 /*
8099  * ALTER TABLE ALTER COLUMN SET { GENERATED or sequence options }
8100  *
8101  * Return the address of the affected column.
8102  */
8103 static ObjectAddress
8104 ATExecSetIdentity(Relation rel, const char *colName, Node *def,
8105  LOCKMODE lockmode, bool recurse, bool recursing)
8106 {
8107  ListCell *option;
8108  DefElem *generatedEl = NULL;
8109  HeapTuple tuple;
8110  Form_pg_attribute attTup;
8112  Relation attrelation;
8113  ObjectAddress address;
8114  bool ispartitioned;
8115 
8116  ispartitioned = (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
8117  if (ispartitioned && !recurse)
8118  ereport(ERROR,
8119  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
8120  errmsg("cannot change identity column of only the partitioned table"),
8121  errhint("Do not specify the ONLY keyword.")));
8122 
8123  if (rel->rd_rel->relispartition && !recursing)
8124  ereport(ERROR,
8125  errcode(ERRCODE_INVALID_TABLE_DEFINITION),
8126  errmsg("cannot change identity column of a partition"));
8127 
8128  foreach(option, castNode(List, def))
8129  {
8130  DefElem *defel = lfirst_node(DefElem, option);
8131 
8132  if (strcmp(defel->defname, "generated") == 0)
8133  {
8134  if (generatedEl)
8135  ereport(ERROR,
8136  (errcode(ERRCODE_SYNTAX_ERROR),
8137  errmsg("conflicting or redundant options")));
8138  generatedEl = defel;
8139  }
8140  else
8141  elog(ERROR, "option \"%s\" not recognized",
8142  defel->defname);
8143  }
8144 
8145  /*
8146  * Even if there is nothing to change here, we run all the checks. There
8147  * will be a subsequent ALTER SEQUENCE that relies on everything being
8148  * there.
8149  */
8150 
8151  attrelation = table_open(AttributeRelationId, RowExclusiveLock);
8152  tuple = SearchSysCacheCopyAttName(RelationGetRelid(rel), colName);
8153  if (!HeapTupleIsValid(tuple))
8154  ereport(ERROR,
8155  (errcode(ERRCODE_UNDEFINED_COLUMN),
8156  errmsg("column \"%s\" of relation \"%s\" does not exist",
8157  colName, RelationGetRelationName(rel))));
8158 
8159  attTup = (Form_pg_attribute) GETSTRUCT(tuple);
8160  attnum = attTup->attnum;
8161 
8162  if (attnum <= 0)
8163  ereport(ERROR,
8164  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
8165  errmsg("cannot alter system column \"%s\"",
8166  colName)));
8167 
8168  if (!attTup->attidentity)
8169  ereport(ERROR,
8170  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
8171  errmsg("column \"%s\" of relation \"%s\" is not an identity column",
8172  colName, RelationGetRelationName(rel))));
8173 
8174  if (generatedEl)
8175  {
8176  attTup->attidentity = defGetInt32(generatedEl);
8177  CatalogTupleUpdate(attrelation, &tuple->t_self, tuple);
8178 
8179  InvokeObjectPostAlterHook(RelationRelationId,
8180  RelationGetRelid(rel),
8181  attTup->attnum);
8182  ObjectAddressSubSet(address, RelationRelationId,
8183  RelationGetRelid(rel), attnum);
8184  }
8185  else
8186  address = InvalidObjectAddress;
8187 
8188  heap_freetuple(tuple);
8189  table_close(attrelation, RowExclusiveLock);
8190 
8191  /*
8192  * Recurse to propagate the identity change to partitions. Identity is not
8193  * inherited in regular inheritance children.
8194  */
8195  if (generatedEl && recurse && ispartitioned)
8196  {
8197  List *children;
8198  ListCell *lc;
8199 
8200  children = find_inheritance_children(RelationGetRelid(rel), lockmode);
8201 
8202  foreach(lc, children)
8203  {
8204  Relation childrel;
8205 
8206  childrel = table_open(lfirst_oid(lc), NoLock);
8207  ATExecSetIdentity(childrel, colName, def, lockmode, recurse, true);
8208  table_close(childrel, NoLock);
8209  }
8210  }
8211 
8212  return address;
8213 }
8214 
8215 /*
8216  * ALTER TABLE ALTER COLUMN DROP IDENTITY
8217  *
8218  * Return the address of the affected column.
8219  */
8220 static ObjectAddress
8221 ATExecDropIdentity(Relation rel, const char *colName, bool missing_ok, LOCKMODE lockmode,
8222  bool recurse, bool recursing)
8223 {
8224  HeapTuple tuple;
8225  Form_pg_attribute attTup;
8227  Relation attrelation;
8228  ObjectAddress address;
8229  Oid seqid;
8230  ObjectAddress seqaddress;
8231  bool ispartitioned;
8232 
8233  ispartitioned = (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
8234  if (ispartitioned && !recurse)
8235  ereport(ERROR,
8236  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
8237  errmsg("cannot drop identity from a column of only the partitioned table"),
8238  errhint("Do not specify the ONLY keyword.")));
8239 
8240  if (rel->rd_rel->relispartition && !recursing)
8241  ereport(ERROR,
8242  errcode(ERRCODE_INVALID_TABLE_DEFINITION),
8243  errmsg("cannot drop identity from a column of a partition"));
8244 
8245  attrelation = table_open(AttributeRelationId, RowExclusiveLock);
8246  tuple = SearchSysCacheCopyAttName(RelationGetRelid(rel), colName);
8247  if (!HeapTupleIsValid(tuple))
8248  ereport(ERROR,
8249  (errcode(ERRCODE_UNDEFINED_COLUMN),
8250  errmsg("column \"%s\" of relation \"%s\" does not exist",
8251  colName, RelationGetRelationName(rel))));
8252 
8253  attTup = (Form_pg_attribute) GETSTRUCT(tuple);
8254  attnum = attTup->attnum;
8255 
8256  if (attnum <= 0)
8257  ereport(ERROR,
8258  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
8259  errmsg("cannot alter system column \"%s\"",
8260  colName)));
8261 
8262  if (!attTup->attidentity)
8263  {
8264  if (!missing_ok)
8265  ereport(ERROR,
8266  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
8267  errmsg("column \"%s\" of relation \"%s\" is not an identity column",
8268  colName, RelationGetRelationName(rel))));
8269  else
8270  {
8271  ereport(NOTICE,
8272  (errmsg("column \"%s\" of relation \"%s\" is not an identity column, skipping",
8273  colName, RelationGetRelationName(rel))));
8274  heap_freetuple(tuple);
8275  table_close(attrelation, RowExclusiveLock);
8276  return InvalidObjectAddress;
8277  }
8278  }
8279 
8280  attTup->attidentity = '\0';
8281  CatalogTupleUpdate(attrelation, &tuple->t_self, tuple);
8282 
8283  InvokeObjectPostAlterHook(RelationRelationId,
8284  RelationGetRelid(rel),
8285  attTup->attnum);
8286  ObjectAddressSubSet(address, RelationRelationId,
8287  RelationGetRelid(rel), attnum);
8288  heap_freetuple(tuple);
8289 
8290  table_close(attrelation, RowExclusiveLock);
8291 
8292  /*
8293  * Recurse to drop the identity from column in partitions. Identity is
8294  * not inherited in regular inheritance children so ignore them.
8295  */
8296  if (recurse && ispartitioned)
8297  {
8298  List *children;
8299  ListCell *lc;
8300 
8301  children = find_inheritance_children(RelationGetRelid(rel), lockmode);
8302 
8303  foreach(lc, children)
8304  {
8305  Relation childrel;
8306 
8307  childrel = table_open(lfirst_oid(lc), NoLock);
8308  ATExecDropIdentity(childrel, colName, false, lockmode, recurse, true);
8309  table_close(childrel, NoLock);
8310  }
8311  }
8312 
8313  if (!recursing)
8314  {
8315  /* drop the internal sequence */
8316  seqid = getIdentitySequence(rel, attnum, false);
8317  deleteDependencyRecordsForClass(RelationRelationId, seqid,
8318  RelationRelationId, DEPENDENCY_INTERNAL);
8320  seqaddress.classId = RelationRelationId;
8321  seqaddress.objectId = seqid;
8322  seqaddress.objectSubId = 0;
8324  }
8325 
8326  return address;
8327 }
8328 
8329 /*
8330  * ALTER TABLE ALTER COLUMN SET EXPRESSION
8331  *
8332  * Return the address of the affected column.
8333  */
8334 static ObjectAddress
8335 ATExecSetExpression(AlteredTableInfo *tab, Relation rel, const char *colName,
8336  Node *newExpr, LOCKMODE lockmode)
8337 {
8338  HeapTuple tuple;
8339  Form_pg_attribute attTup;
8341  Oid attrdefoid;
8342  ObjectAddress address;
8343  Expr *defval;
8345  RawColumnDefault *rawEnt;
8346 
8347  tuple = SearchSysCacheAttName(RelationGetRelid(rel), colName);
8348  if (!HeapTupleIsValid(tuple))
8349  ereport(ERROR,
8350  (errcode(ERRCODE_UNDEFINED_COLUMN),
8351  errmsg("column \"%s\" of relation \"%s\" does not exist",
8352  colName, RelationGetRelationName(rel))));
8353 
8354  attTup = (Form_pg_attribute) GETSTRUCT(tuple);
8355  attnum = attTup->attnum;
8356 
8357  if (attnum <= 0)
8358  ereport(ERROR,
8359  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
8360  errmsg("cannot alter system column \"%s\"",
8361  colName)));
8362 
8363  if (attTup->attgenerated != ATTRIBUTE_GENERATED_STORED)
8364  ereport(ERROR,
8365  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
8366  errmsg("column \"%s\" of relation \"%s\" is not a generated column",
8367  colName, RelationGetRelationName(rel))));
8368  ReleaseSysCache(tuple);
8369 
8370  /*
8371  * Clear all the missing values if we're rewriting the table, since this
8372  * renders them pointless.
8373  */
8374  RelationClearMissing(rel);
8375 
8376  /* make sure we don't conflict with later attribute modifications */
8378 
8379  /*
8380  * Find everything that depends on the column (constraints, indexes, etc),
8381  * and record enough information to let us recreate the objects after
8382  * rewrite.
8383  */
8385 
8386  /*
8387  * Drop the dependency records of the GENERATED expression, in particular
8388  * its INTERNAL dependency on the column, which would otherwise cause
8389  * dependency.c to refuse to perform the deletion.
8390  */
8391  attrdefoid = GetAttrDefaultOid(RelationGetRelid(rel), attnum);
8392  if (!OidIsValid(attrdefoid))
8393  elog(ERROR, "could not find attrdef tuple for relation %u attnum %d",
8394  RelationGetRelid(rel), attnum);
8395  (void) deleteDependencyRecordsFor(AttrDefaultRelationId, attrdefoid, false);
8396 
8397  /* Make above changes visible */
8399 
8400  /*
8401  * Get rid of the GENERATED expression itself. We use RESTRICT here for
8402  * safety, but at present we do not expect anything to depend on the
8403  * expression.
8404  */
8406  false, false);
8407 
8408  /* Prepare to store the new expression, in the catalogs */
8409  rawEnt = (RawColumnDefault *) palloc(sizeof(RawColumnDefault));
8410  rawEnt->attnum = attnum;
8411  rawEnt->raw_default = newExpr;
8412  rawEnt->missingMode = false;
8413  rawEnt->generated = ATTRIBUTE_GENERATED_STORED;
8414 
8415  /* Store the generated expression */
8417  false, true, false, NULL);
8418 
8419  /* Make above new expression visible */
8421 
8422  /* Prepare for table rewrite */
8423  defval = (Expr *) build_column_default(rel, attnum);
8424 
8426  newval->attnum = attnum;
8427  newval->expr = expression_planner(defval);
8428  newval->is_generated = true;
8429 
8430  tab->newvals = lappend(tab->newvals, newval);
8432 
8433  /* Drop any pg_statistic entry for the column */
8435 
8436  InvokeObjectPostAlterHook(RelationRelationId,
8437  RelationGetRelid(rel), attnum);
8438 
8439  ObjectAddressSubSet(address, RelationRelationId,
8440  RelationGetRelid(rel), attnum);
8441  return address;
8442 }
8443 
8444 /*
8445  * ALTER TABLE ALTER COLUMN DROP EXPRESSION
8446  */
8447 static void
8448 ATPrepDropExpression(Relation rel, AlterTableCmd *cmd, bool recurse, bool recursing, LOCKMODE lockmode)
8449 {
8450  /*
8451  * Reject ONLY if there are child tables. We could implement this, but it
8452  * is a bit complicated. GENERATED clauses must be attached to the column
8453  * definition and cannot be added later like DEFAULT, so if a child table
8454  * has a generation expression that the parent does not have, the child
8455  * column will necessarily be an attislocal column. So to implement ONLY
8456  * here, we'd need extra code to update attislocal of the direct child
8457  * tables, somewhat similar to how DROP COLUMN does it, so that the
8458  * resulting state can be properly dumped and restored.
8459  */
8460  if (!recurse &&
8462  ereport(ERROR,
8463  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
8464  errmsg("ALTER TABLE / DROP EXPRESSION must be applied to child tables too")));
8465 
8466  /*
8467  * Cannot drop generation expression from inherited columns.
8468  */
8469  if (!recursing)
8470  {
8471  HeapTuple tuple;
8472  Form_pg_attribute attTup;
8473 
8474  tuple = SearchSysCacheCopyAttName(RelationGetRelid(rel), cmd->name);
8475  if (!HeapTupleIsValid(tuple))
8476  ereport(ERROR,
8477  (errcode(ERRCODE_UNDEFINED_COLUMN),
8478  errmsg("column \"%s\" of relation \"%s\" does not exist",
8479  cmd->name, RelationGetRelationName(rel))));
8480 
8481  attTup = (Form_pg_attribute) GETSTRUCT(tuple);
8482 
8483  if (attTup->attinhcount > 0)
8484  ereport(ERROR,
8485  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
8486  errmsg("cannot drop generation expression from inherited column")));
8487  }
8488 }
8489 
8490 /*
8491  * Return the address of the affected column.
8492  */
8493 static ObjectAddress
8494 ATExecDropExpression(Relation rel, const char *colName, bool missing_ok, LOCKMODE lockmode)
8495 {
8496  HeapTuple tuple;
8497  Form_pg_attribute attTup;
8499  Relation attrelation;
8500  Oid attrdefoid;
8501  ObjectAddress address;
8502 
8503  attrelation = table_open(AttributeRelationId, RowExclusiveLock);
8504  tuple = SearchSysCacheCopyAttName(RelationGetRelid(rel), colName);
8505  if (!HeapTupleIsValid(tuple))
8506  ereport(ERROR,
8507  (errcode(ERRCODE_UNDEFINED_COLUMN),
8508  errmsg("column \"%s\" of relation \"%s\" does not exist",
8509  colName, RelationGetRelationName(rel))));
8510 
8511  attTup = (Form_pg_attribute) GETSTRUCT(tuple);
8512  attnum = attTup->attnum;
8513 
8514  if (attnum <= 0)
8515  ereport(ERROR,
8516  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
8517  errmsg("cannot alter system column \"%s\"",
8518  colName)));
8519 
8520  if (attTup->attgenerated != ATTRIBUTE_GENERATED_STORED)
8521  {
8522  if (!missing_ok)
8523  ereport(ERROR,
8524  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
8525  errmsg("column \"%s\" of relation \"%s\" is not a stored generated column",
8526  colName, RelationGetRelationName(rel))));
8527  else
8528  {
8529  ereport(NOTICE,
8530  (errmsg("column \"%s\" of relation \"%s\" is not a stored generated column, skipping",
8531  colName, RelationGetRelationName(rel))));
8532  heap_freetuple(tuple);
8533  table_close(attrelation, RowExclusiveLock);
8534  return InvalidObjectAddress;
8535  }
8536  }
8537 
8538  /*
8539  * Mark the column as no longer generated. (The atthasdef flag needs to
8540  * get cleared too, but RemoveAttrDefault will handle that.)
8541  */
8542  attTup->attgenerated = '\0';
8543  CatalogTupleUpdate(attrelation, &tuple->t_self, tuple);
8544 
8545  InvokeObjectPostAlterHook(RelationRelationId,
8546  RelationGetRelid(rel),
8547  attnum);
8548  heap_freetuple(tuple);
8549 
8550  table_close(attrelation, RowExclusiveLock);
8551 
8552  /*
8553  * Drop the dependency records of the GENERATED expression, in particular
8554  * its INTERNAL dependency on the column, which would otherwise cause
8555  * dependency.c to refuse to perform the deletion.
8556  */
8557  attrdefoid = GetAttrDefaultOid(RelationGetRelid(rel), attnum);
8558  if (!OidIsValid(attrdefoid))
8559  elog(ERROR, "could not find attrdef tuple for relation %u attnum %d",
8560  RelationGetRelid(rel), attnum);
8561  (void) deleteDependencyRecordsFor(AttrDefaultRelationId, attrdefoid, false);
8562 
8563  /* Make above changes visible */
8565 
8566  /*
8567  * Get rid of the GENERATED expression itself. We use RESTRICT here for
8568  * safety, but at present we do not expect anything to depend on the
8569  * default.
8570  */
8572  false, false);
8573 
8574  ObjectAddressSubSet(address, RelationRelationId,
8575  RelationGetRelid(rel), attnum);
8576  return address;
8577 }
8578 
8579 /*
8580  * ALTER TABLE ALTER COLUMN SET STATISTICS
8581  *
8582  * Return value is the address of the modified column
8583  */
8584 static ObjectAddress
8585 ATExecSetStatistics(Relation rel, const char *colName, int16 colNum, Node *newValue, LOCKMODE lockmode)
8586 {
8587  int newtarget = 0;
8588  bool newtarget_default;
8589  Relation attrelation;
8590  HeapTuple tuple,
8591  newtuple;
8592  Form_pg_attribute attrtuple;
8594  ObjectAddress address;
8595  Datum repl_val[Natts_pg_attribute];
8596  bool repl_null[Natts_pg_attribute];
8597  bool repl_repl[Natts_pg_attribute];
8598 
8599  /*
8600  * We allow referencing columns by numbers only for indexes, since table
8601  * column numbers could contain gaps if columns are later dropped.
8602  */
8603  if (rel->rd_rel->relkind != RELKIND_INDEX &&
8604  rel->rd_rel->relkind != RELKIND_PARTITIONED_INDEX &&
8605  !colName)
8606  ereport(ERROR,
8607  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
8608  errmsg("cannot refer to non-index column by number")));
8609 
8610  /* -1 was used in previous versions for the default setting */
8611  if (newValue && intVal(newValue) != -1)
8612  {
8613  newtarget = intVal(newValue);
8614  newtarget_default = false;
8615  }
8616  else
8617  newtarget_default = true;
8618 
8619  if (!newtarget_default)
8620  {
8621  /*
8622  * Limit target to a sane range
8623  */
8624  if (newtarget < 0)
8625  {
8626  ereport(ERROR,
8627  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
8628  errmsg("statistics target %d is too low",
8629  newtarget)));
8630  }
8631  else if (newtarget > MAX_STATISTICS_TARGET)
8632  {
8633  newtarget = MAX_STATISTICS_TARGET;
8634  ereport(WARNING,
8635  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
8636  errmsg("lowering statistics target to %d",
8637  newtarget)));
8638  }
8639  }
8640 
8641  attrelation = table_open(AttributeRelationId, RowExclusiveLock);
8642 
8643  if (colName)
8644  {
8645  tuple = SearchSysCacheAttName(RelationGetRelid(rel), colName);
8646 
8647  if (!HeapTupleIsValid(tuple))
8648  ereport(ERROR,
8649  (errcode(ERRCODE_UNDEFINED_COLUMN),
8650  errmsg("column \"%s\" of relation \"%s\" does not exist",
8651  colName, RelationGetRelationName(rel))));
8652  }
8653  else
8654  {
8655  tuple = SearchSysCacheAttNum(RelationGetRelid(rel), colNum);
8656 
8657  if (!HeapTupleIsValid(tuple))
8658  ereport(ERROR,
8659  (errcode(ERRCODE_UNDEFINED_COLUMN),
8660  errmsg("column number %d of relation \"%s\" does not exist",
8661  colNum, RelationGetRelationName(rel))));
8662  }
8663 
8664  attrtuple = (Form_pg_attribute) GETSTRUCT(tuple);
8665 
8666  attnum = attrtuple->attnum;
8667  if (attnum <= 0)
8668  ereport(ERROR,
8669  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
8670  errmsg("cannot alter system column \"%s\"",
8671  colName)));
8672 
8673  if (rel->rd_rel->relkind == RELKIND_INDEX ||
8674  rel->rd_rel->relkind == RELKIND_PARTITIONED_INDEX)
8675  {
8676  if (attnum > rel->rd_index->indnkeyatts)
8677  ereport(ERROR,
8678  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
8679  errmsg("cannot alter statistics on included column \"%s\" of index \"%s\"",
8680  NameStr(attrtuple->attname), RelationGetRelationName(rel))));
8681  else if (rel->rd_index->indkey.values[attnum - 1] != 0)
8682  ereport(ERROR,
8683  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
8684  errmsg("cannot alter statistics on non-expression column \"%s\" of index \"%s\"",
8685  NameStr(attrtuple->attname), RelationGetRelationName(rel)),
8686  errhint("Alter statistics on table column instead.")));
8687  }
8688 
8689  /* Build new tuple. */
8690  memset(repl_null, false, sizeof(repl_null));
8691  memset(repl_repl, false, sizeof(repl_repl));
8692  if (!newtarget_default)
8693  repl_val[Anum_pg_attribute_attstattarget - 1] = newtarget;
8694  else
8695  repl_null[Anum_pg_attribute_attstattarget - 1] = true;
8696  repl_repl[Anum_pg_attribute_attstattarget - 1] = true;
8697  newtuple = heap_modify_tuple(tuple, RelationGetDescr(attrelation),
8698  repl_val, repl_null, repl_repl);
8699  CatalogTupleUpdate(attrelation, &tuple->t_self, newtuple);
8700 
8701  InvokeObjectPostAlterHook(RelationRelationId,
8702  RelationGetRelid(rel),
8703  attrtuple->attnum);
8704  ObjectAddressSubSet(address, RelationRelationId,
8705  RelationGetRelid(rel), attnum);
8706 
8707  heap_freetuple(newtuple);
8708 
8709  ReleaseSysCache(tuple);
8710 
8711  table_close(attrelation, RowExclusiveLock);
8712 
8713  return address;
8714 }
8715 
8716 /*
8717  * Return value is the address of the modified column
8718  */
8719 static ObjectAddress
8720 ATExecSetOptions(Relation rel, const char *colName, Node *options,
8721  bool isReset, LOCKMODE lockmode)
8722 {
8723  Relation attrelation;
8724  HeapTuple tuple,
8725  newtuple;
8726  Form_pg_attribute attrtuple;
8728  Datum datum,
8729  newOptions;
8730  bool isnull;
8731  ObjectAddress address;
8732  Datum repl_val[Natts_pg_attribute];
8733  bool repl_null[Natts_pg_attribute];
8734  bool repl_repl[Natts_pg_attribute];
8735 
8736  attrelation = table_open(AttributeRelationId, RowExclusiveLock);
8737 
8738  tuple = SearchSysCacheAttName(RelationGetRelid(rel), colName);
8739 
8740  if (!HeapTupleIsValid(tuple))
8741  ereport(ERROR,
8742  (errcode(ERRCODE_UNDEFINED_COLUMN),
8743  errmsg("column \"%s\" of relation \"%s\" does not exist",
8744  colName, RelationGetRelationName(rel))));
8745  attrtuple = (Form_pg_attribute) GETSTRUCT(tuple);
8746 
8747  attnum = attrtuple->attnum;
8748  if (attnum <= 0)
8749  ereport(ERROR,
8750  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
8751  errmsg("cannot alter system column \"%s\"",
8752  colName)));
8753 
8754  /* Generate new proposed attoptions (text array) */
8755  datum = SysCacheGetAttr(ATTNAME, tuple, Anum_pg_attribute_attoptions,
8756  &isnull);
8757  newOptions = transformRelOptions(isnull ? (Datum) 0 : datum,
8758  castNode(List, options), NULL, NULL,
8759  false, isReset);
8760  /* Validate new options */
8761  (void) attribute_reloptions(newOptions, true);
8762 
8763  /* Build new tuple. */
8764  memset(repl_null, false, sizeof(repl_null));
8765  memset(repl_repl, false, sizeof(repl_repl));
8766  if (newOptions != (Datum) 0)
8767  repl_val[Anum_pg_attribute_attoptions - 1] = newOptions;
8768  else
8769  repl_null[Anum_pg_attribute_attoptions - 1] = true;
8770  repl_repl[Anum_pg_attribute_attoptions - 1] = true;
8771  newtuple = heap_modify_tuple(tuple, RelationGetDescr(attrelation),
8772  repl_val, repl_null, repl_repl);
8773 
8774  /* Update system catalog. */
8775  CatalogTupleUpdate(attrelation, &newtuple->t_self, newtuple);
8776 
8777  InvokeObjectPostAlterHook(RelationRelationId,
8778  RelationGetRelid(rel),
8779  attrtuple->attnum);
8780  ObjectAddressSubSet(address, RelationRelationId,
8781  RelationGetRelid(rel), attnum);
8782 
8783  heap_freetuple(newtuple);
8784 
8785  ReleaseSysCache(tuple);
8786 
8787  table_close(attrelation, RowExclusiveLock);
8788 
8789  return address;
8790 }
8791 
8792 /*
8793  * Helper function for ATExecSetStorage and ATExecSetCompression
8794  *
8795  * Set the attstorage and/or attcompression fields for index columns
8796  * associated with the specified table column.
8797  */
8798 static void
8801  bool setstorage, char newstorage,
8802  bool setcompression, char newcompression,
8803  LOCKMODE lockmode)
8804 {
8805  ListCell *lc;
8806 
8807  foreach(lc, RelationGetIndexList(rel))
8808  {
8809  Oid indexoid = lfirst_oid(lc);
8810  Relation indrel;
8811  AttrNumber indattnum = 0;
8812  HeapTuple tuple;
8813 
8814  indrel = index_open(indexoid, lockmode);
8815 
8816  for (int i = 0; i < indrel->rd_index->indnatts; i++)
8817  {
8818  if (indrel->rd_index->indkey.values[i] == attnum)
8819  {
8820  indattnum = i + 1;
8821  break;
8822  }
8823  }
8824 
8825  if (indattnum == 0)
8826  {
8827  index_close(indrel, lockmode);
8828  continue;
8829  }
8830 
8831  tuple = SearchSysCacheCopyAttNum(RelationGetRelid(indrel), indattnum);
8832 
8833  if (HeapTupleIsValid(tuple))
8834  {
8835  Form_pg_attribute attrtuple = (Form_pg_attribute) GETSTRUCT(tuple);
8836 
8837  if (setstorage)
8838  attrtuple->attstorage = newstorage;
8839 
8840  if (setcompression)
8841  attrtuple->attcompression = newcompression;
8842 
8843  CatalogTupleUpdate(attrelation, &tuple->t_self, tuple);
8844 
8845  InvokeObjectPostAlterHook(RelationRelationId,
8846  RelationGetRelid(rel),
8847  attrtuple->attnum);
8848 
8849  heap_freetuple(tuple);
8850  }
8851 
8852  index_close(indrel, lockmode);
8853  }
8854 }
8855 
8856 /*
8857  * ALTER TABLE ALTER COLUMN SET STORAGE
8858  *
8859  * Return value is the address of the modified column
8860  */
8861 static ObjectAddress
8862 ATExecSetStorage(Relation rel, const char *colName, Node *newValue, LOCKMODE lockmode)
8863 {
8864  Relation attrelation;
8865  HeapTuple tuple;
8866  Form_pg_attribute attrtuple;
8868  ObjectAddress address;
8869 
8870  attrelation = table_open(AttributeRelationId, RowExclusiveLock);
8871 
8872  tuple = SearchSysCacheCopyAttName(RelationGetRelid(rel), colName);
8873 
8874  if (!HeapTupleIsValid(tuple))
8875  ereport(ERROR,
8876  (errcode(ERRCODE_UNDEFINED_COLUMN),
8877  errmsg("column \"%s\" of relation \"%s\" does not exist",
8878  colName, RelationGetRelationName(rel))));
8879  attrtuple = (Form_pg_attribute) GETSTRUCT(tuple);
8880 
8881  attnum = attrtuple->attnum;
8882  if (attnum <= 0)
8883  ereport(ERROR,
8884  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
8885  errmsg("cannot alter system column \"%s\"",
8886  colName)));
8887 
8888  attrtuple->attstorage = GetAttributeStorage(attrtuple->atttypid, strVal(newValue));
8889 
8890  CatalogTupleUpdate(attrelation, &tuple->t_self, tuple);
8891 
8892  InvokeObjectPostAlterHook(RelationRelationId,
8893  RelationGetRelid(rel),
8894  attrtuple->attnum);
8895 
8896  /*
8897  * Apply the change to indexes as well (only for simple index columns,
8898  * matching behavior of index.c ConstructTupleDescriptor()).
8899  */
8900  SetIndexStorageProperties(rel, attrelation, attnum,
8901  true, attrtuple->attstorage,
8902  false, 0,
8903  lockmode);
8904 
8905  heap_freetuple(tuple);
8906 
8907  table_close(attrelation, RowExclusiveLock);
8908 
8909  ObjectAddressSubSet(address, RelationRelationId,
8910  RelationGetRelid(rel), attnum);
8911  return address;
8912 }
8913 
8914 
8915 /*
8916  * ALTER TABLE DROP COLUMN
8917  *
8918  * DROP COLUMN cannot use the normal ALTER TABLE recursion mechanism,
8919  * because we have to decide at runtime whether to recurse or not depending
8920  * on whether attinhcount goes to zero or not. (We can't check this in a
8921  * static pre-pass because it won't handle multiple inheritance situations
8922  * correctly.)
8923  */
8924 static void
8925 ATPrepDropColumn(List **wqueue, Relation rel, bool recurse, bool recursing,
8926  AlterTableCmd *cmd, LOCKMODE lockmode,
8928 {
8929  if (rel->rd_rel->reloftype && !recursing)
8930  ereport(ERROR,
8931  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
8932  errmsg("cannot drop column from typed table")));
8933 
8934  if (rel->rd_rel->relkind == RELKIND_COMPOSITE_TYPE)
8935  ATTypedTableRecursion(wqueue, rel, cmd, lockmode, context);
8936 
8937  if (recurse)
8938  cmd->recurse = true;
8939 }
8940 
8941 /*
8942  * Drops column 'colName' from relation 'rel' and returns the address of the
8943  * dropped column. The column is also dropped (or marked as no longer
8944  * inherited from relation) from the relation's inheritance children, if any.
8945  *
8946  * In the recursive invocations for inheritance child relations, instead of
8947  * dropping the column directly (if to be dropped at all), its object address
8948  * is added to 'addrs', which must be non-NULL in such invocations. All
8949  * columns are dropped at the same time after all the children have been
8950  * checked recursively.
8951  */
8952 static ObjectAddress
8953 ATExecDropColumn(List **wqueue, Relation rel, const char *colName,
8954  DropBehavior behavior,
8955  bool recurse, bool recursing,
8956  bool missing_ok, LOCKMODE lockmode,
8957  ObjectAddresses *addrs)
8958 {
8959  HeapTuple tuple;
8960  Form_pg_attribute targetatt;
8962  List *children;
8963  ObjectAddress object;
8964  bool is_expr;
8965 
8966  /* At top level, permission check was done in ATPrepCmd, else do it */
8967  if (recursing)
8969 
8970  /* Initialize addrs on the first invocation */
8971  Assert(!recursing || addrs != NULL);
8972 
8973  /* since this function recurses, it could be driven to stack overflow */
8975 
8976  if (!recursing)
8977  addrs = new_object_addresses();
8978 
8979  /*
8980  * get the number of the attribute
8981  */
8982  tuple = SearchSysCacheAttName(RelationGetRelid(rel), colName);
8983  if (!HeapTupleIsValid(tuple))
8984  {
8985  if (!missing_ok)
8986  {
8987  ereport(ERROR,
8988  (errcode(ERRCODE_UNDEFINED_COLUMN),
8989  errmsg("column \"%s\" of relation \"%s\" does not exist",
8990  colName, RelationGetRelationName(rel))));
8991  }
8992  else
8993  {
8994  ereport(NOTICE,
8995  (errmsg("column \"%s\" of relation \"%s\" does not exist, skipping",
8996  colName, RelationGetRelationName(rel))));
8997  return InvalidObjectAddress;
8998  }
8999  }
9000  targetatt = (Form_pg_attribute) GETSTRUCT(tuple);
9001 
9002  attnum = targetatt->attnum;
9003 
9004  /* Can't drop a system attribute */
9005  if (attnum <= 0)
9006  ereport(ERROR,
9007  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
9008  errmsg("cannot drop system column \"%s\"",
9009  colName)));
9010 
9011  /*
9012  * Don't drop inherited columns, unless recursing (presumably from a drop
9013  * of the parent column)
9014  */
9015  if (targetatt->attinhcount > 0 && !recursing)
9016  ereport(ERROR,
9017  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
9018  errmsg("cannot drop inherited column \"%s\"",
9019  colName)));
9020 
9021  /*
9022  * Don't drop columns used in the partition key, either. (If we let this
9023  * go through, the key column's dependencies would cause a cascaded drop
9024  * of the whole table, which is surely not what the user expected.)
9025  */
9026  if (has_partition_attrs(rel,
9028  &is_expr))
9029  ereport(ERROR,
9030  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
9031  errmsg("cannot drop column \"%s\" because it is part of the partition key of relation \"%s\"",
9032  colName, RelationGetRelationName(rel))));
9033 
9034  ReleaseSysCache(tuple);
9035 
9036  /*
9037  * Propagate to children as appropriate. Unlike most other ALTER
9038  * routines, we have to do this one level of recursion at a time; we can't
9039  * use find_all_inheritors to do it in one pass.
9040  */
9041  children =
9043 
9044  if (children)
9045  {
9046  Relation attr_rel;
9047  ListCell *child;
9048 
9049  /*
9050  * In case of a partitioned table, the column must be dropped from the
9051  * partitions as well.
9052  */
9053  if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE && !recurse)
9054  ereport(ERROR,
9055  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
9056  errmsg("cannot drop column from only the partitioned table when partitions exist"),
9057  errhint("Do not specify the ONLY keyword.")));
9058 
9059  attr_rel = table_open(AttributeRelationId, RowExclusiveLock);
9060  foreach(child, children)
9061  {
9062  Oid childrelid = lfirst_oid(child);
9063  Relation childrel;
9064  Form_pg_attribute childatt;
9065 
9066  /* find_inheritance_children already got lock */
9067  childrel = table_open(childrelid, NoLock);
9068  CheckAlterTableIsSafe(childrel);
9069 
9070  tuple = SearchSysCacheCopyAttName(childrelid, colName);
9071  if (!HeapTupleIsValid(tuple)) /* shouldn't happen */
9072  elog(ERROR, "cache lookup failed for attribute \"%s\" of relation %u",
9073  colName, childrelid);
9074  childatt = (Form_pg_attribute) GETSTRUCT(tuple);
9075 
9076  if (childatt->attinhcount <= 0) /* shouldn't happen */
9077  elog(ERROR, "relation %u has non-inherited attribute \"%s\"",
9078  childrelid, colName);
9079 
9080  if (recurse)
9081  {
9082  /*
9083  * If the child column has other definition sources, just
9084  * decrement its inheritance count; if not, recurse to delete
9085  * it.
9086  */
9087  if (childatt->attinhcount == 1 && !childatt->attislocal)
9088  {
9089  /* Time to delete this child column, too */
9090  ATExecDropColumn(wqueue, childrel, colName,
9091  behavior, true, true,
9092  false, lockmode, addrs);
9093  }
9094  else
9095  {
9096  /* Child column must survive my deletion */
9097  childatt->attinhcount--;
9098 
9099  CatalogTupleUpdate(attr_rel, &tuple->t_self, tuple);
9100 
9101  /* Make update visible */
9103  }
9104  }
9105  else
9106  {
9107  /*
9108  * If we were told to drop ONLY in this table (no recursion),
9109  * we need to mark the inheritors' attributes as locally
9110  * defined rather than inherited.
9111  */
9112  childatt->attinhcount--;
9113  childatt->attislocal = true;
9114 
9115  CatalogTupleUpdate(attr_rel, &tuple->t_self, tuple);
9116 
9117  /* Make update visible */
9119  }
9120 
9121  heap_freetuple(tuple);
9122 
9123  table_close(childrel, NoLock);
9124  }
9125  table_close(attr_rel, RowExclusiveLock);
9126  }
9127 
9128  /* Add object to delete */
9129  object.classId = RelationRelationId;
9130  object.objectId = RelationGetRelid(rel);
9131  object.objectSubId = attnum;
9132  add_exact_object_address(&object, addrs);
9133 
9134  if (!recursing)
9135  {
9136  /* Recursion has ended, drop everything that was collected */
9137  performMultipleDeletions(addrs, behavior, 0);
9138  free_object_addresses(addrs);
9139  }
9140 
9141  return object;
9142 }
9143 
9144 /*
9145  * ALTER TABLE ADD INDEX
9146  *
9147  * There is no such command in the grammar, but parse_utilcmd.c converts
9148  * UNIQUE and PRIMARY KEY constraints into AT_AddIndex subcommands. This lets
9149  * us schedule creation of the index at the appropriate time during ALTER.
9150  *
9151  * Return value is the address of the new index.
9152  */
9153 static ObjectAddress
9155  IndexStmt *stmt, bool is_rebuild, LOCKMODE lockmode)
9156 {
9157  bool check_rights;
9158  bool skip_build;
9159  bool quiet;
9160  ObjectAddress address;
9161 
9162  Assert(IsA(stmt, IndexStmt));
9163  Assert(!stmt->concurrent);
9164 
9165  /* The IndexStmt has already been through transformIndexStmt */
9166  Assert(stmt->transformed);
9167 
9168  /* suppress schema rights check when rebuilding existing index */
9169  check_rights = !is_rebuild;
9170  /* skip index build if phase 3 will do it or we're reusing an old one */
9171  skip_build = tab->rewrite > 0 || RelFileNumberIsValid(stmt->oldNumber);
9172  /* suppress notices when rebuilding existing index */
9173  quiet = is_rebuild;
9174 
9175  address = DefineIndex(RelationGetRelid(rel),
9176  stmt,
9177  InvalidOid, /* no predefined OID */
9178  InvalidOid, /* no parent index */
9179  InvalidOid, /* no parent constraint */
9180  -1, /* total_parts unknown */
9181  true, /* is_alter_table */
9182  check_rights,
9183  false, /* check_not_in_use - we did it already */
9184  skip_build,
9185  quiet);
9186 
9187  /*
9188  * If TryReuseIndex() stashed a relfilenumber for us, we used it for the
9189  * new index instead of building from scratch. Restore associated fields.
9190  * This may store InvalidSubTransactionId in both fields, in which case
9191  * relcache.c will assume it can rebuild the relcache entry. Hence, do
9192  * this after the CCI that made catalog rows visible to any rebuild. The
9193  * DROP of the old edition of this index will have scheduled the storage
9194  * for deletion at commit, so cancel that pending deletion.
9195  */
9196  if (RelFileNumberIsValid(stmt->oldNumber))
9197  {
9198  Relation irel = index_open(address.objectId, NoLock);
9199 
9200  irel->rd_createSubid = stmt->oldCreateSubid;
9201  irel->rd_firstRelfilelocatorSubid = stmt->oldFirstRelfilelocatorSubid;
9202  RelationPreserveStorage(irel->rd_locator, true);
9203  index_close(irel, NoLock);
9204  }
9205 
9206  return address;
9207 }
9208 
9209 /*
9210  * ALTER TABLE ADD STATISTICS
9211  *
9212  * This is no such command in the grammar, but we use this internally to add
9213  * AT_ReAddStatistics subcommands to rebuild extended statistics after a table
9214  * column type change.
9215  */
9216 static ObjectAddress
9218  CreateStatsStmt *stmt, bool is_rebuild, LOCKMODE lockmode)
9219 {
9220  ObjectAddress address;
9221 
9223 
9224  /* The CreateStatsStmt has already been through transformStatsStmt */
9225  Assert(stmt->transformed);
9226 
9227  address = CreateStatistics(stmt);
9228 
9229  return address;
9230 }
9231 
9232 /*
9233  * ALTER TABLE ADD CONSTRAINT USING INDEX
9234  *
9235  * Returns the address of the new constraint.
9236  */
9237 static ObjectAddress
9239  IndexStmt *stmt, LOCKMODE lockmode)
9240 {
9241  Oid index_oid = stmt->indexOid;
9242  Relation indexRel;
9243  char *indexName;
9244  IndexInfo *indexInfo;
9245  char *constraintName;
9246  char constraintType;
9247  ObjectAddress address;
9248  bits16 flags;
9249 
9250  Assert(IsA(stmt, IndexStmt));
9251  Assert(OidIsValid(index_oid));
9252  Assert(stmt->isconstraint);
9253 
9254  /*
9255  * Doing this on partitioned tables is not a simple feature to implement,
9256  * so let's punt for now.
9257  */
9258  if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
9259  ereport(ERROR,
9260  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
9261  errmsg("ALTER TABLE / ADD CONSTRAINT USING INDEX is not supported on partitioned tables")));
9262 
9263  indexRel = index_open(index_oid, AccessShareLock);
9264 
9265  indexName = pstrdup(RelationGetRelationName(indexRel));
9266 
9267  indexInfo = BuildIndexInfo(indexRel);
9268 
9269  /* this should have been checked at parse time */
9270  if (!indexInfo->ii_Unique)
9271  elog(ERROR, "index \"%s\" is not unique", indexName);
9272 
9273  /*
9274  * Determine name to assign to constraint. We require a constraint to
9275  * have the same name as the underlying index; therefore, use the index's
9276  * existing name as the default constraint name, and if the user
9277  * explicitly gives some other name for the constraint, rename the index
9278  * to match.
9279  */
9280  constraintName = stmt->idxname;
9281  if (constraintName == NULL)
9282  constraintName = indexName;
9283  else if (strcmp(constraintName, indexName) != 0)
9284  {
9285  ereport(NOTICE,
9286  (errmsg("ALTER TABLE / ADD CONSTRAINT USING INDEX will rename index \"%s\" to \"%s\"",
9287  indexName, constraintName)));
9288  RenameRelationInternal(index_oid, constraintName, false, true);
9289  }
9290 
9291  /* Extra checks needed if making primary key */
9292  if (stmt->primary)
9293  index_check_primary_key(rel, indexInfo, true, stmt);
9294 
9295  /* Note we currently don't support EXCLUSION constraints here */
9296  if (stmt->primary)
9297  constraintType = CONSTRAINT_PRIMARY;
9298  else
9299  constraintType = CONSTRAINT_UNIQUE;
9300 
9301  /* Create the catalog entries for the constraint */
9304  (stmt->initdeferred ? INDEX_CONSTR_CREATE_INIT_DEFERRED : 0) |
9305  (stmt->deferrable ? INDEX_CONSTR_CREATE_DEFERRABLE : 0) |
9306  (stmt->primary ? INDEX_CONSTR_CREATE_MARK_AS_PRIMARY : 0);
9307 
9308  address = index_constraint_create(rel,
9309  index_oid,
9310  InvalidOid,
9311  indexInfo,
9312  constraintName,
9313  constraintType,
9314  flags,
9316  false); /* is_internal */
9317 
9318  index_close(indexRel, NoLock);
9319 
9320  return address;
9321 }
9322 
9323 /*
9324  * ALTER TABLE ADD CONSTRAINT
9325  *
9326  * Return value is the address of the new constraint; if no constraint was
9327  * added, InvalidObjectAddress is returned.
9328  */
9329 static ObjectAddress
9331  Constraint *newConstraint, bool recurse, bool is_readd,
9332  LOCKMODE lockmode)
9333 {
9335 
9336  Assert(IsA(newConstraint, Constraint));
9337 
9338  /*
9339  * Currently, we only expect to see CONSTR_CHECK and CONSTR_FOREIGN nodes
9340  * arriving here (see the preprocessing done in parse_utilcmd.c). Use a
9341  * switch anyway to make it easier to add more code later.
9342  */
9343  switch (newConstraint->contype)
9344  {
9345  case CONSTR_CHECK:
9346  address =
9347  ATAddCheckConstraint(wqueue, tab, rel,
9348  newConstraint, recurse, false, is_readd,
9349  lockmode);
9350  break;
9351 
9352  case CONSTR_FOREIGN:
9353 
9354  /*
9355  * Assign or validate constraint name
9356  */
9357  if (newConstraint->conname)
9358  {
9360  RelationGetRelid(rel),
9361  newConstraint->conname))
9362  ereport(ERROR,
9364  errmsg("constraint \"%s\" for relation \"%s\" already exists",
9365  newConstraint->conname,
9366  RelationGetRelationName(rel))));
9367  }
9368  else
9369  newConstraint->conname =
9372  "fkey",
9373  RelationGetNamespace(rel),
9374  NIL);
9375 
9376  address = ATAddForeignKeyConstraint(wqueue, tab, rel,
9377  newConstraint,
9378  recurse, false,
9379  lockmode);
9380  break;
9381 
9382  default:
9383  elog(ERROR, "unrecognized constraint type: %d",
9384  (int) newConstraint->contype);
9385  }
9386 
9387  return address;
9388 }
9389 
9390 /*
9391  * Generate the column-name portion of the constraint name for a new foreign
9392  * key given the list of column names that reference the referenced
9393  * table. This will be passed to ChooseConstraintName along with the parent
9394  * table name and the "fkey" suffix.
9395  *
9396  * We know that less than NAMEDATALEN characters will actually be used, so we
9397  * can truncate the result once we've generated that many.
9398  *
9399  * XXX see also ChooseExtendedStatisticNameAddition and
9400  * ChooseIndexNameAddition.
9401  */
9402 static char *
9404 {
9405  char buf[NAMEDATALEN * 2];
9406  int buflen = 0;
9407  ListCell *lc;
9408 
9409  buf[0] = '\0';
9410  foreach(lc, colnames)
9411  {
9412  const char *name = strVal(lfirst(lc));
9413 
9414  if (buflen > 0)
9415  buf[buflen++] = '_'; /* insert _ between names */
9416 
9417  /*
9418  * At this point we have buflen <= NAMEDATALEN. name should be less
9419  * than NAMEDATALEN already, but use strlcpy for paranoia.
9420  */
9421  strlcpy(buf + buflen, name, NAMEDATALEN);
9422  buflen += strlen(buf + buflen);
9423  if (buflen >= NAMEDATALEN)
9424  break;
9425  }
9426  return pstrdup(buf);
9427 }
9428 
9429 /*
9430  * Add a check constraint to a single table and its children. Returns the
9431  * address of the constraint added to the parent relation, if one gets added,
9432  * or InvalidObjectAddress otherwise.
9433  *
9434  * Subroutine for ATExecAddConstraint.
9435  *
9436  * We must recurse to child tables during execution, rather than using
9437  * ALTER TABLE's normal prep-time recursion. The reason is that all the
9438  * constraints *must* be given the same name, else they won't be seen as
9439  * related later. If the user didn't explicitly specify a name, then
9440  * AddRelationNewConstraints would normally assign different names to the
9441  * child constraints. To fix that, we must capture the name assigned at
9442  * the parent table and pass that down.
9443  */
9444 static ObjectAddress
9446  Constraint *constr, bool recurse, bool recursing,
9447  bool is_readd, LOCKMODE lockmode)
9448 {
9449  List *newcons;
9450  ListCell *lcon;
9451  List *children;
9452  ListCell *child;
9454 
9455  /* At top level, permission check was done in ATPrepCmd, else do it */
9456  if (recursing)
9458 
9459  /*
9460  * Call AddRelationNewConstraints to do the work, making sure it works on
9461  * a copy of the Constraint so transformExpr can't modify the original. It
9462  * returns a list of cooked constraints.
9463  *
9464  * If the constraint ends up getting merged with a pre-existing one, it's
9465  * omitted from the returned list, which is what we want: we do not need
9466  * to do any validation work. That can only happen at child tables,
9467  * though, since we disallow merging at the top level.
9468  */
9469  newcons = AddRelationNewConstraints(rel, NIL,
9470  list_make1(copyObject(constr)),
9471  recursing || is_readd, /* allow_merge */
9472  !recursing, /* is_local */
9473  is_readd, /* is_internal */
9474  NULL); /* queryString not available
9475  * here */
9476 
9477  /* we don't expect more than one constraint here */
9478  Assert(list_length(newcons) <= 1);
9479 
9480  /* Add each to-be-validated constraint to Phase 3's queue */
9481  foreach(lcon, newcons)
9482  {
9483  CookedConstraint *ccon = (CookedConstraint *) lfirst(lcon);
9484 
9485  if (!ccon->skip_validation)
9486  {
9487  NewConstraint *newcon;
9488 
9489  newcon = (NewConstraint *) palloc0(sizeof(NewConstraint));
9490  newcon->name = ccon->name;
9491  newcon->contype = ccon->contype;
9492  newcon->qual = ccon->expr;
9493 
9494  tab->constraints = lappend(tab->constraints, newcon);
9495  }
9496 
9497  /* Save the actually assigned name if it was defaulted */
9498  if (constr->conname == NULL)
9499  constr->conname = ccon->name;
9500 
9501  ObjectAddressSet(address, ConstraintRelationId, ccon->conoid);
9502  }
9503 
9504  /* At this point we must have a locked-down name to use */
9505  Assert(constr->conname != NULL);
9506 
9507  /* Advance command counter in case same table is visited multiple times */
9509 
9510  /*
9511  * If the constraint got merged with an existing constraint, we're done.
9512  * We mustn't recurse to child tables in this case, because they've
9513  * already got the constraint, and visiting them again would lead to an
9514  * incorrect value for coninhcount.
9515  */
9516  if (newcons == NIL)
9517  return address;
9518 
9519  /*
9520  * If adding a NO INHERIT constraint, no need to find our children.
9521  */
9522  if (constr->is_no_inherit)
9523  return address;
9524 
9525  /*
9526  * Propagate to children as appropriate. Unlike most other ALTER
9527  * routines, we have to do this one level of recursion at a time; we can't
9528  * use find_all_inheritors to do it in one pass.
9529  */
9530  children =
9532 
9533  /*
9534  * Check if ONLY was specified with ALTER TABLE. If so, allow the
9535  * constraint creation only if there are no children currently. Error out
9536  * otherwise.
9537  */
9538  if (!recurse && children != NIL)
9539  ereport(ERROR,
9540  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
9541  errmsg("constraint must be added to child tables too")));
9542 
9543  foreach(child, children)
9544  {
9545  Oid childrelid = lfirst_oid(child);
9546  Relation childrel;
9547  AlteredTableInfo *childtab;
9548 
9549  /* find_inheritance_children already got lock */
9550  childrel = table_open(childrelid, NoLock);
9551  CheckAlterTableIsSafe(childrel);
9552 
9553  /* Find or create work queue entry for this table */
9554  childtab = ATGetQueueEntry(wqueue, childrel);
9555 
9556  /* Recurse to child */
9557  ATAddCheckConstraint(wqueue, childtab, childrel,
9558  constr, recurse, true, is_readd, lockmode);
9559 
9560  table_close(childrel, NoLock);
9561  }
9562 
9563  return address;
9564 }
9565 
9566 /*
9567  * Add a foreign-key constraint to a single table; return the new constraint's
9568  * address.
9569  *
9570  * Subroutine for ATExecAddConstraint. Must already hold exclusive
9571  * lock on the rel, and have done appropriate validity checks for it.
9572  * We do permissions checks here, however.
9573  *
9574  * When the referenced or referencing tables (or both) are partitioned,
9575  * multiple pg_constraint rows are required -- one for each partitioned table
9576  * and each partition on each side (fortunately, not one for every combination
9577  * thereof). We also need action triggers on each leaf partition on the
9578  * referenced side, and check triggers on each leaf partition on the
9579  * referencing side.
9580  */
9581 static ObjectAddress
9583  Constraint *fkconstraint,
9584  bool recurse, bool recursing, LOCKMODE lockmode)
9585 {
9586  Relation pkrel;
9587  int16 pkattnum[INDEX_MAX_KEYS] = {0};
9588  int16 fkattnum[INDEX_MAX_KEYS] = {0};
9589  Oid pktypoid[INDEX_MAX_KEYS] = {0};
9590  Oid fktypoid[INDEX_MAX_KEYS] = {0};
9591  Oid opclasses[INDEX_MAX_KEYS] = {0};
9592  Oid pfeqoperators[INDEX_MAX_KEYS] = {0};
9593  Oid ppeqoperators[INDEX_MAX_KEYS] = {0};
9594  Oid ffeqoperators[INDEX_MAX_KEYS] = {0};
9595  int16 fkdelsetcols[INDEX_MAX_KEYS] = {0};
9596  int i;
9597  int numfks,
9598  numpks,
9599  numfkdelsetcols;
9600  Oid indexOid;
9601  bool old_check_ok;
9602  ObjectAddress address;
9603  ListCell *old_pfeqop_item = list_head(fkconstraint->old_conpfeqop);
9604 
9605  /*
9606  * Grab ShareRowExclusiveLock on the pk table, so that someone doesn't
9607  * delete rows out from under us.
9608  */
9609  if (OidIsValid(fkconstraint->old_pktable_oid))
9610  pkrel = table_open(fkconstraint->old_pktable_oid, ShareRowExclusiveLock);
9611  else
9612  pkrel = table_openrv(fkconstraint->pktable, ShareRowExclusiveLock);
9613 
9614  /*
9615  * Validity checks (permission checks wait till we have the column
9616  * numbers)
9617  */
9618  if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
9619  {
9620  if (!recurse)
9621  ereport(ERROR,
9622  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
9623  errmsg("cannot use ONLY for foreign key on partitioned table \"%s\" referencing relation \"%s\"",
9625  RelationGetRelationName(pkrel))));
9626  if (fkconstraint->skip_validation && !fkconstraint->initially_valid)
9627  ereport(ERROR,
9628  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
9629  errmsg("cannot add NOT VALID foreign key on partitioned table \"%s\" referencing relation \"%s\"",
9631  RelationGetRelationName(pkrel)),
9632  errdetail("This feature is not yet supported on partitioned tables.")));
9633  }
9634 
9635  if (pkrel->rd_rel->relkind != RELKIND_RELATION &&
9636  pkrel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
9637  ereport(ERROR,
9638  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
9639  errmsg("referenced relation \"%s\" is not a table",
9640  RelationGetRelationName(pkrel))));
9641 
9642  if (!allowSystemTableMods && IsSystemRelation(pkrel))
9643  ereport(ERROR,
9644  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
9645  errmsg("permission denied: \"%s\" is a system catalog",
9646  RelationGetRelationName(pkrel))));
9647 
9648  /*
9649  * References from permanent or unlogged tables to temp tables, and from
9650  * permanent tables to unlogged tables, are disallowed because the
9651  * referenced data can vanish out from under us. References from temp
9652  * tables to any other table type are also disallowed, because other
9653  * backends might need to run the RI triggers on the perm table, but they
9654  * can't reliably see tuples in the local buffers of other backends.
9655  */
9656  switch (rel->rd_rel->relpersistence)
9657  {
9658  case RELPERSISTENCE_PERMANENT:
9659  if (!RelationIsPermanent(pkrel))
9660  ereport(ERROR,
9661  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
9662  errmsg("constraints on permanent tables may reference only permanent tables")));
9663  break;
9664  case RELPERSISTENCE_UNLOGGED:
9665  if (!RelationIsPermanent(pkrel)
9666  && pkrel->rd_rel->relpersistence != RELPERSISTENCE_UNLOGGED)
9667  ereport(ERROR,
9668  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
9669  errmsg("constraints on unlogged tables may reference only permanent or unlogged tables")));
9670  break;
9671  case RELPERSISTENCE_TEMP:
9672  if (pkrel->rd_rel->relpersistence != RELPERSISTENCE_TEMP)
9673  ereport(ERROR,
9674  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
9675  errmsg("constraints on temporary tables may reference only temporary tables")));
9676  if (!pkrel->rd_islocaltemp || !rel->rd_islocaltemp)
9677  ereport(ERROR,
9678  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
9679  errmsg("constraints on temporary tables must involve temporary tables of this session")));
9680  break;
9681  }
9682 
9683  /*
9684  * Look up the referencing attributes to make sure they exist, and record
9685  * their attnums and type OIDs.
9686  */
9688  fkconstraint->fk_attrs,
9689  fkattnum, fktypoid);
9690 
9691  numfkdelsetcols = transformColumnNameList(RelationGetRelid(rel),
9692  fkconstraint->fk_del_set_cols,
9693  fkdelsetcols, NULL);
9694  validateFkOnDeleteSetColumns(numfks, fkattnum,
9695  numfkdelsetcols, fkdelsetcols,
9696  fkconstraint->fk_del_set_cols);
9697 
9698  /*
9699  * If the attribute list for the referenced table was omitted, lookup the
9700  * definition of the primary key and use it. Otherwise, validate the
9701  * supplied attribute list. In either case, discover the index OID and
9702  * index opclasses, and the attnums and type OIDs of the attributes.
9703  */
9704  if (fkconstraint->pk_attrs == NIL)
9705  {
9706  numpks = transformFkeyGetPrimaryKey(pkrel, &indexOid,
9707  &fkconstraint->pk_attrs,
9708  pkattnum, pktypoid,
9709  opclasses);
9710  }
9711  else
9712  {
9713  numpks = transformColumnNameList(RelationGetRelid(pkrel),
9714  fkconstraint->pk_attrs,
9715  pkattnum, pktypoid);
9716  /* Look for an index matching the column list */
9717  indexOid = transformFkeyCheckAttrs(pkrel, numpks, pkattnum,
9718  opclasses);
9719  }
9720 
9721  /*
9722  * Now we can check permissions.
9723  */
9724  checkFkeyPermissions(pkrel, pkattnum, numpks);
9725 
9726  /*
9727  * Check some things for generated columns.
9728  */
9729  for (i = 0; i < numfks; i++)
9730  {
9731  char attgenerated = TupleDescAttr(RelationGetDescr(rel), fkattnum[i] - 1)->attgenerated;
9732 
9733  if (attgenerated)
9734  {
9735  /*
9736  * Check restrictions on UPDATE/DELETE actions, per SQL standard
9737  */
9738  if (fkconstraint->fk_upd_action == FKCONSTR_ACTION_SETNULL ||
9739  fkconstraint->fk_upd_action == FKCONSTR_ACTION_SETDEFAULT ||
9740  fkconstraint->fk_upd_action == FKCONSTR_ACTION_CASCADE)
9741  ereport(ERROR,
9742  (errcode(ERRCODE_SYNTAX_ERROR),
9743  errmsg("invalid %s action for foreign key constraint containing generated column",
9744  "ON UPDATE")));
9745  if (fkconstraint->fk_del_action == FKCONSTR_ACTION_SETNULL ||
9746  fkconstraint->fk_del_action == FKCONSTR_ACTION_SETDEFAULT)
9747  ereport(ERROR,
9748  (errcode(ERRCODE_SYNTAX_ERROR),
9749  errmsg("invalid %s action for foreign key constraint containing generated column",
9750  "ON DELETE")));
9751  }
9752  }
9753 
9754  /*
9755  * Look up the equality operators to use in the constraint.
9756  *
9757  * Note that we have to be careful about the difference between the actual
9758  * PK column type and the opclass' declared input type, which might be
9759  * only binary-compatible with it. The declared opcintype is the right
9760  * thing to probe pg_amop with.
9761  */
9762  if (numfks != numpks)
9763  ereport(ERROR,
9764  (errcode(ERRCODE_INVALID_FOREIGN_KEY),
9765  errmsg("number of referencing and referenced columns for foreign key disagree")));
9766 
9767  /*
9768  * On the strength of a previous constraint, we might avoid scanning
9769  * tables to validate this one. See below.
9770  */
9771  old_check_ok = (fkconstraint->old_conpfeqop != NIL);
9772  Assert(!old_check_ok || numfks == list_length(fkconstraint->old_conpfeqop));
9773 
9774  for (i = 0; i < numpks; i++)
9775  {
9776  Oid pktype = pktypoid[i];
9777  Oid fktype = fktypoid[i];
9778  Oid fktyped;
9779  HeapTuple cla_ht;
9780  Form_pg_opclass cla_tup;
9781  Oid amid;
9782  Oid opfamily;
9783  Oid opcintype;
9784  Oid pfeqop;
9785  Oid ppeqop;
9786  Oid ffeqop;
9787  int16 eqstrategy;
9788  Oid pfeqop_right;
9789 
9790  /* We need several fields out of the pg_opclass entry */
9791  cla_ht = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclasses[i]));
9792  if (!HeapTupleIsValid(cla_ht))
9793  elog(ERROR, "cache lookup failed for opclass %u", opclasses[i]);
9794  cla_tup = (Form_pg_opclass) GETSTRUCT(cla_ht);
9795  amid = cla_tup->opcmethod;
9796  opfamily = cla_tup->opcfamily;
9797  opcintype = cla_tup->opcintype;
9798  ReleaseSysCache(cla_ht);
9799 
9800  /*
9801  * Check it's a btree; currently this can never fail since no other
9802  * index AMs support unique indexes. If we ever did have other types
9803  * of unique indexes, we'd need a way to determine which operator
9804  * strategy number is equality. (Is it reasonable to insist that
9805  * every such index AM use btree's number for equality?)
9806  */
9807  if (amid != BTREE_AM_OID)
9808  elog(ERROR, "only b-tree indexes are supported for foreign keys");
9809  eqstrategy = BTEqualStrategyNumber;
9810 
9811  /*
9812  * There had better be a primary equality operator for the index.
9813  * We'll use it for PK = PK comparisons.
9814  */
9815  ppeqop = get_opfamily_member(opfamily, opcintype, opcintype,
9816  eqstrategy);
9817 
9818  if (!OidIsValid(ppeqop))
9819  elog(ERROR, "missing operator %d(%u,%u) in opfamily %u",
9820  eqstrategy, opcintype, opcintype, opfamily);
9821 
9822  /*
9823  * Are there equality operators that take exactly the FK type? Assume
9824  * we should look through any domain here.
9825  */
9826  fktyped = getBaseType(fktype);
9827 
9828  pfeqop = get_opfamily_member(opfamily, opcintype, fktyped,
9829  eqstrategy);
9830  if (OidIsValid(pfeqop))
9831  {
9832  pfeqop_right = fktyped;
9833  ffeqop = get_opfamily_member(opfamily, fktyped, fktyped,
9834  eqstrategy);
9835  }
9836  else
9837  {
9838  /* keep compiler quiet */
9839  pfeqop_right = InvalidOid;
9840  ffeqop = InvalidOid;
9841  }
9842 
9843  if (!(OidIsValid(pfeqop) && OidIsValid(ffeqop)))
9844  {
9845  /*
9846  * Otherwise, look for an implicit cast from the FK type to the
9847  * opcintype, and if found, use the primary equality operator.
9848  * This is a bit tricky because opcintype might be a polymorphic
9849  * type such as ANYARRAY or ANYENUM; so what we have to test is
9850  * whether the two actual column types can be concurrently cast to
9851  * that type. (Otherwise, we'd fail to reject combinations such
9852  * as int[] and point[].)
9853  */
9854  Oid input_typeids[2];
9855  Oid target_typeids[2];
9856 
9857  input_typeids[0] = pktype;
9858  input_typeids[1] = fktype;
9859  target_typeids[0] = opcintype;
9860  target_typeids[1] = opcintype;
9861  if (can_coerce_type(2, input_typeids, target_typeids,
9863  {
9864  pfeqop = ffeqop = ppeqop;
9865  pfeqop_right = opcintype;
9866  }
9867  }
9868 
9869  if (!(OidIsValid(pfeqop) && OidIsValid(ffeqop)))
9870  ereport(ERROR,
9871  (errcode(ERRCODE_DATATYPE_MISMATCH),
9872  errmsg("foreign key constraint \"%s\" cannot be implemented",
9873  fkconstraint->conname),
9874  errdetail("Key columns \"%s\" and \"%s\" "
9875  "are of incompatible types: %s and %s.",
9876  strVal(list_nth(fkconstraint->fk_attrs, i)),
9877  strVal(list_nth(fkconstraint->pk_attrs, i)),
9878  format_type_be(fktype),
9879  format_type_be(pktype))));
9880 
9881  if (old_check_ok)
9882  {
9883  /*
9884  * When a pfeqop changes, revalidate the constraint. We could
9885  * permit intra-opfamily changes, but that adds subtle complexity
9886  * without any concrete benefit for core types. We need not
9887  * assess ppeqop or ffeqop, which RI_Initial_Check() does not use.
9888  */
9889  old_check_ok = (pfeqop == lfirst_oid(old_pfeqop_item));
9890  old_pfeqop_item = lnext(fkconstraint->old_conpfeqop,
9891  old_pfeqop_item);
9892  }
9893  if (old_check_ok)
9894  {
9895  Oid old_fktype;
9896  Oid new_fktype;
9897  CoercionPathType old_pathtype;
9898  CoercionPathType new_pathtype;
9899  Oid old_castfunc;
9900  Oid new_castfunc;
9902  fkattnum[i] - 1);
9903 
9904  /*
9905  * Identify coercion pathways from each of the old and new FK-side
9906  * column types to the right (foreign) operand type of the pfeqop.
9907  * We may assume that pg_constraint.conkey is not changing.
9908  */
9909  old_fktype = attr->atttypid;
9910  new_fktype = fktype;
9911  old_pathtype = findFkeyCast(pfeqop_right, old_fktype,
9912  &old_castfunc);
9913  new_pathtype = findFkeyCast(pfeqop_right, new_fktype,
9914  &new_castfunc);
9915 
9916  /*
9917  * Upon a change to the cast from the FK column to its pfeqop
9918  * operand, revalidate the constraint. For this evaluation, a
9919  * binary coercion cast is equivalent to no cast at all. While
9920  * type implementors should design implicit casts with an eye
9921  * toward consistency of operations like equality, we cannot
9922  * assume here that they have done so.
9923  *
9924  * A function with a polymorphic argument could change behavior
9925  * arbitrarily in response to get_fn_expr_argtype(). Therefore,
9926  * when the cast destination is polymorphic, we only avoid
9927  * revalidation if the input type has not changed at all. Given
9928  * just the core data types and operator classes, this requirement
9929  * prevents no would-be optimizations.
9930  *
9931  * If the cast converts from a base type to a domain thereon, then
9932  * that domain type must be the opcintype of the unique index.
9933  * Necessarily, the primary key column must then be of the domain
9934  * type. Since the constraint was previously valid, all values on
9935  * the foreign side necessarily exist on the primary side and in
9936  * turn conform to the domain. Consequently, we need not treat
9937  * domains specially here.
9938  *
9939  * Since we require that all collations share the same notion of
9940  * equality (which they do, because texteq reduces to bitwise
9941  * equality), we don't compare collation here.
9942  *
9943  * We need not directly consider the PK type. It's necessarily
9944  * binary coercible to the opcintype of the unique index column,
9945  * and ri_triggers.c will only deal with PK datums in terms of
9946  * that opcintype. Changing the opcintype also changes pfeqop.
9947  */
9948  old_check_ok = (new_pathtype == old_pathtype &&
9949  new_castfunc == old_castfunc &&
9950  (!IsPolymorphicType(pfeqop_right) ||
9951  new_fktype == old_fktype));
9952  }
9953 
9954  pfeqoperators[i] = pfeqop;
9955  ppeqoperators[i] = ppeqop;
9956  ffeqoperators[i] = ffeqop;
9957  }
9958 
9959  /*
9960  * Create all the constraint and trigger objects, recursing to partitions
9961  * as necessary. First handle the referenced side.
9962  */
9963  address = addFkRecurseReferenced(wqueue, fkconstraint, rel, pkrel,
9964  indexOid,
9965  InvalidOid, /* no parent constraint */
9966  numfks,
9967  pkattnum,
9968  fkattnum,
9969  pfeqoperators,
9970  ppeqoperators,
9971  ffeqoperators,
9972  numfkdelsetcols,
9973  fkdelsetcols,
9974  old_check_ok,
9976 
9977  /* Now handle the referencing side. */
9978  addFkRecurseReferencing(wqueue, fkconstraint, rel, pkrel,
9979  indexOid,
9980  address.objectId,
9981  numfks,
9982  pkattnum,
9983  fkattnum,
9984  pfeqoperators,
9985  ppeqoperators,
9986  ffeqoperators,
9987  numfkdelsetcols,
9988  fkdelsetcols,
9989  old_check_ok,
9990  lockmode,
9992 
9993  /*
9994  * Done. Close pk table, but keep lock until we've committed.
9995  */
9996  table_close(pkrel, NoLock);
9997 
9998  return address;
9999 }
10000 
10001 /*
10002  * validateFkOnDeleteSetColumns
10003  * Verifies that columns used in ON DELETE SET NULL/DEFAULT (...)
10004  * column lists are valid.
10005  */
10006 void
10007 validateFkOnDeleteSetColumns(int numfks, const int16 *fkattnums,
10008  int numfksetcols, const int16 *fksetcolsattnums,
10009  List *fksetcols)
10010 {
10011  for (int i = 0; i < numfksetcols; i++)
10012  {
10013  int16 setcol_attnum = fksetcolsattnums[i];
10014  bool seen = false;
10015 
10016  for (int j = 0; j < numfks; j++)
10017  {
10018  if (fkattnums[j] == setcol_attnum)
10019  {
10020  seen = true;
10021  break;
10022  }
10023  }
10024 
10025  if (!seen)
10026  {
10027  char *col = strVal(list_nth(fksetcols, i));
10028 
10029  ereport(ERROR,
10030  (errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
10031  errmsg("column \"%s\" referenced in ON DELETE SET action must be part of foreign key", col)));
10032  }
10033  }
10034 }
10035 
10036 /*
10037  * addFkRecurseReferenced
10038  * subroutine for ATAddForeignKeyConstraint; recurses on the referenced
10039  * side of the constraint
10040  *
10041  * Create pg_constraint rows for the referenced side of the constraint,
10042  * referencing the parent of the referencing side; also create action triggers
10043  * on leaf partitions. If the table is partitioned, recurse to handle each
10044  * partition.
10045  *
10046  * wqueue is the ALTER TABLE work queue; can be NULL when not running as part
10047  * of an ALTER TABLE sequence.
10048  * fkconstraint is the constraint being added.
10049  * rel is the root referencing relation.
10050  * pkrel is the referenced relation; might be a partition, if recursing.
10051  * indexOid is the OID of the index (on pkrel) implementing this constraint.
10052  * parentConstr is the OID of a parent constraint; InvalidOid if this is a
10053  * top-level constraint.
10054  * numfks is the number of columns in the foreign key
10055  * pkattnum is the attnum array of referenced attributes.
10056  * fkattnum is the attnum array of referencing attributes.
10057  * numfkdelsetcols is the number of columns in the ON DELETE SET NULL/DEFAULT
10058  * (...) clause
10059  * fkdelsetcols is the attnum array of the columns in the ON DELETE SET
10060  * NULL/DEFAULT clause
10061  * pf/pp/ffeqoperators are OID array of operators between columns.
10062  * old_check_ok signals that this constraint replaces an existing one that
10063  * was already validated (thus this one doesn't need validation).
10064  * parentDelTrigger and parentUpdTrigger, when being recursively called on
10065  * a partition, are the OIDs of the parent action triggers for DELETE and
10066  * UPDATE respectively.
10067  */
10068 static ObjectAddress
10069 addFkRecurseReferenced(List **wqueue, Constraint *fkconstraint, Relation rel,
10070  Relation pkrel, Oid indexOid, Oid parentConstr,
10071  int numfks,
10072  int16 *pkattnum, int16 *fkattnum, Oid *pfeqoperators,
10073  Oid *ppeqoperators, Oid *ffeqoperators,
10074  int numfkdelsetcols, int16 *fkdelsetcols,
10075  bool old_check_ok,
10076  Oid parentDelTrigger, Oid parentUpdTrigger)
10077 {
10078  ObjectAddress address;
10079  Oid constrOid;
10080  char *conname;
10081  bool conislocal;
10082  int coninhcount;
10083  bool connoinherit;
10084  Oid deleteTriggerOid,
10085  updateTriggerOid;
10086 
10087  /*
10088  * Verify relkind for each referenced partition. At the top level, this
10089  * is redundant with a previous check, but we need it when recursing.
10090  */
10091  if (pkrel->rd_rel->relkind != RELKIND_RELATION &&
10092  pkrel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
10093  ereport(ERROR,
10094  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
10095  errmsg("referenced relation \"%s\" is not a table",
10096  RelationGetRelationName(pkrel))));
10097 
10098  /*
10099  * Caller supplies us with a constraint name; however, it may be used in
10100  * this partition, so come up with a different one in that case.
10101  */
10103  RelationGetRelid(rel),
10104  fkconstraint->conname))
10107  "fkey",
10108  RelationGetNamespace(rel), NIL);
10109  else
10110  conname = fkconstraint->conname;
10111 
10112  if (OidIsValid(parentConstr))
10113  {
10114  conislocal = false;
10115  coninhcount = 1;
10116  connoinherit = false;
10117  }
10118  else
10119  {
10120  conislocal = true;
10121  coninhcount = 0;
10122 
10123  /*
10124  * always inherit for partitioned tables, never for legacy inheritance
10125  */
10126  connoinherit = rel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE;
10127  }
10128 
10129  /*
10130  * Record the FK constraint in pg_constraint.
10131  */
10132  constrOid = CreateConstraintEntry(conname,
10133  RelationGetNamespace(rel),
10134  CONSTRAINT_FOREIGN,
10135  fkconstraint->deferrable,
10136  fkconstraint->initdeferred,
10137  fkconstraint->initially_valid,
10138  parentConstr,
10139  RelationGetRelid(rel),
10140  fkattnum,
10141  numfks,
10142  numfks,
10143  InvalidOid, /* not a domain constraint */
10144  indexOid,
10145  RelationGetRelid(pkrel),
10146  pkattnum,
10147  pfeqoperators,
10148  ppeqoperators,
10149  ffeqoperators,
10150  numfks,
10151  fkconstraint->fk_upd_action,
10152  fkconstraint->fk_del_action,
10153  fkdelsetcols,
10154  numfkdelsetcols,
10155  fkconstraint->fk_matchtype,
10156  NULL, /* no exclusion constraint */
10157  NULL, /* no check constraint */
10158  NULL,
10159  conislocal, /* islocal */
10160  coninhcount, /* inhcount */
10161  connoinherit, /* conNoInherit */
10162  false); /* is_internal */
10163 
10164  ObjectAddressSet(address, ConstraintRelationId, constrOid);
10165 
10166  /*
10167  * Mark the child constraint as part of the parent constraint; it must not
10168  * be dropped on its own. (This constraint is deleted when the partition
10169  * is detached, but a special check needs to occur that the partition
10170  * contains no referenced values.)
10171  */
10172  if (OidIsValid(parentConstr))
10173  {
10174  ObjectAddress referenced;
10175 
10176  ObjectAddressSet(referenced, ConstraintRelationId, parentConstr);
10177  recordDependencyOn(&address, &referenced, DEPENDENCY_INTERNAL);
10178  }
10179 
10180  /* make new constraint visible, in case we add more */
10182 
10183  /*
10184  * Create the action triggers that enforce the constraint.
10185  */
10187  fkconstraint,
10188  constrOid, indexOid,
10189  parentDelTrigger, parentUpdTrigger,
10190  &deleteTriggerOid, &updateTriggerOid);
10191 
10192  /*
10193  * If the referenced table is partitioned, recurse on ourselves to handle
10194  * each partition. We need one pg_constraint row created for each
10195  * partition in addition to the pg_constraint row for the parent table.
10196  */
10197  if (pkrel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
10198  {
10199  PartitionDesc pd = RelationGetPartitionDesc(pkrel, true);
10200 
10201  for (int i = 0; i < pd->nparts; i++)
10202  {
10203  Relation partRel;
10204  AttrMap *map;
10205  AttrNumber *mapped_pkattnum;
10206  Oid partIndexId;
10207 
10208  partRel = table_open(pd->oids[i], ShareRowExclusiveLock);
10209 
10210  /*
10211  * Map the attribute numbers in the referenced side of the FK
10212  * definition to match the partition's column layout.
10213  */
10215  RelationGetDescr(pkrel),
10216  false);
10217  if (map)
10218  {
10219  mapped_pkattnum = palloc(sizeof(AttrNumber) * numfks);
10220  for (int j = 0; j < numfks; j++)
10221  mapped_pkattnum[j] = map->attnums[pkattnum[j] - 1];
10222  }
10223  else
10224  mapped_pkattnum = pkattnum;
10225 
10226  /* do the deed */
10227  partIndexId = index_get_partition(partRel, indexOid);
10228  if (!OidIsValid(partIndexId))
10229  elog(ERROR, "index for %u not found in partition %s",
10230  indexOid, RelationGetRelationName(partRel));
10231  addFkRecurseReferenced(wqueue, fkconstraint, rel, partRel,
10232  partIndexId, constrOid, numfks,
10233  mapped_pkattnum, fkattnum,
10234  pfeqoperators, ppeqoperators, ffeqoperators,
10235  numfkdelsetcols, fkdelsetcols,
10236  old_check_ok,
10237  deleteTriggerOid, updateTriggerOid);
10238 
10239  /* Done -- clean up (but keep the lock) */
10240  table_close(partRel, NoLock);
10241  if (map)
10242  {
10243  pfree(mapped_pkattnum);
10244  free_attrmap(map);
10245  }
10246  }
10247  }
10248 
10249  return address;
10250 }
10251 
10252 /*
10253  * addFkRecurseReferencing
10254  * subroutine for ATAddForeignKeyConstraint and CloneFkReferencing
10255  *
10256  * If the referencing relation is a plain relation, create the necessary check
10257  * triggers that implement the constraint, and set up for Phase 3 constraint
10258  * verification. If the referencing relation is a partitioned table, then
10259  * we create a pg_constraint row for it and recurse on this routine for each
10260  * partition.
10261  *
10262  * We assume that the referenced relation is locked against concurrent
10263  * deletions. If it's a partitioned relation, every partition must be so
10264  * locked.
10265  *
10266  * wqueue is the ALTER TABLE work queue; can be NULL when not running as part
10267  * of an ALTER TABLE sequence.
10268  * fkconstraint is the constraint being added.
10269  * rel is the referencing relation; might be a partition, if recursing.
10270  * pkrel is the root referenced relation.
10271  * indexOid is the OID of the index (on pkrel) implementing this constraint.
10272  * parentConstr is the OID of the parent constraint (there is always one).
10273  * numfks is the number of columns in the foreign key
10274  * pkattnum is the attnum array of referenced attributes.
10275  * fkattnum is the attnum array of referencing attributes.
10276  * pf/pp/ffeqoperators are OID array of operators between columns.
10277  * numfkdelsetcols is the number of columns in the ON DELETE SET NULL/DEFAULT
10278  * (...) clause
10279  * fkdelsetcols is the attnum array of the columns in the ON DELETE SET
10280  * NULL/DEFAULT clause
10281  * old_check_ok signals that this constraint replaces an existing one that
10282  * was already validated (thus this one doesn't need validation).
10283  * lockmode is the lockmode to acquire on partitions when recursing.
10284  * parentInsTrigger and parentUpdTrigger, when being recursively called on
10285  * a partition, are the OIDs of the parent check triggers for INSERT and
10286  * UPDATE respectively.
10287  */
10288 static void
10289 addFkRecurseReferencing(List **wqueue, Constraint *fkconstraint, Relation rel,
10290  Relation pkrel, Oid indexOid, Oid parentConstr,
10291  int numfks, int16 *pkattnum, int16 *fkattnum,
10292  Oid *pfeqoperators, Oid *ppeqoperators, Oid *ffeqoperators,
10293  int numfkdelsetcols, int16 *fkdelsetcols,
10294  bool old_check_ok, LOCKMODE lockmode,
10295  Oid parentInsTrigger, Oid parentUpdTrigger)
10296 {
10297  Oid insertTriggerOid,
10298  updateTriggerOid;
10299 
10300  Assert(OidIsValid(parentConstr));
10301 
10302  if (rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
10303  ereport(ERROR,
10304  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
10305  errmsg("foreign key constraints are not supported on foreign tables")));
10306 
10307  /*
10308  * Add the check triggers to it and, if necessary, schedule it to be
10309  * checked in Phase 3.
10310  *
10311  * If the relation is partitioned, drill down to do it to its partitions.
10312  */
10314  RelationGetRelid(pkrel),
10315  fkconstraint,
10316  parentConstr,
10317  indexOid,
10318  parentInsTrigger, parentUpdTrigger,
10319  &insertTriggerOid, &updateTriggerOid);
10320 
10321  if (rel->rd_rel->relkind == RELKIND_RELATION)
10322  {
10323  /*
10324  * Tell Phase 3 to check that the constraint is satisfied by existing
10325  * rows. We can skip this during table creation, when requested
10326  * explicitly by specifying NOT VALID in an ADD FOREIGN KEY command,
10327  * and when we're recreating a constraint following a SET DATA TYPE
10328  * operation that did not impugn its validity.
10329  */
10330  if (wqueue && !old_check_ok && !fkconstraint->skip_validation)
10331  {
10332  NewConstraint *newcon;
10333  AlteredTableInfo *tab;
10334 
10335  tab = ATGetQueueEntry(wqueue, rel);
10336 
10337  newcon = (NewConstraint *) palloc0(sizeof(NewConstraint));
10338  newcon->name = get_constraint_name(parentConstr);
10339  newcon->contype = CONSTR_FOREIGN;
10340  newcon->refrelid = RelationGetRelid(pkrel);
10341  newcon->refindid = indexOid;
10342  newcon->conid = parentConstr;
10343  newcon->qual = (Node *) fkconstraint;
10344 
10345  tab->constraints = lappend(tab->constraints, newcon);
10346  }
10347  }
10348  else if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
10349  {
10350  PartitionDesc pd = RelationGetPartitionDesc(rel, true);
10351  Relation trigrel;
10352 
10353  /*
10354  * Triggers of the foreign keys will be manipulated a bunch of times
10355  * in the loop below. To avoid repeatedly opening/closing the trigger
10356  * catalog relation, we open it here and pass it to the subroutines
10357  * called below.
10358  */
10359  trigrel = table_open(TriggerRelationId, RowExclusiveLock);
10360 
10361  /*
10362  * Recurse to take appropriate action on each partition; either we
10363  * find an existing constraint to reparent to ours, or we create a new
10364  * one.
10365  */
10366  for (int i = 0; i < pd->nparts; i++)
10367  {
10368  Oid partitionId = pd->oids[i];
10369  Relation partition = table_open(partitionId, lockmode);
10370  List *partFKs;
10371  AttrMap *attmap;
10372  AttrNumber mapped_fkattnum[INDEX_MAX_KEYS];
10373  bool attached;
10374  char *conname;
10375  Oid constrOid;
10376  ObjectAddress address,
10377  referenced;
10378  ListCell *cell;
10379 
10380  CheckAlterTableIsSafe(partition);
10381 
10382  attmap = build_attrmap_by_name(RelationGetDescr(partition),
10383  RelationGetDescr(rel),
10384  false);
10385  for (int j = 0; j < numfks; j++)
10386  mapped_fkattnum[j] = attmap->attnums[fkattnum[j] - 1];
10387 
10388  /* Check whether an existing constraint can be repurposed */
10389  partFKs = copyObject(RelationGetFKeyList(partition));
10390  attached = false;
10391  foreach(cell, partFKs)
10392  {
10393  ForeignKeyCacheInfo *fk;
10394 
10395  fk = lfirst_node(ForeignKeyCacheInfo, cell);
10397  partitionId,
10398  parentConstr,
10399  numfks,
10400  mapped_fkattnum,
10401  pkattnum,
10402  pfeqoperators,
10403  insertTriggerOid,
10404  updateTriggerOid,
10405  trigrel))
10406  {
10407  attached = true;
10408  break;
10409  }
10410  }
10411  if (attached)
10412  {
10413  table_close(partition, NoLock);
10414  continue;
10415  }
10416 
10417  /*
10418  * No luck finding a good constraint to reuse; create our own.
10419  */
10421  RelationGetRelid(partition),
10422  fkconstraint->conname))
10423  conname = ChooseConstraintName(RelationGetRelationName(partition),
10425  "fkey",
10426  RelationGetNamespace(partition), NIL);
10427  else
10428  conname = fkconstraint->conname;
10429  constrOid =
10430  CreateConstraintEntry(conname,
10431  RelationGetNamespace(partition),
10432  CONSTRAINT_FOREIGN,
10433  fkconstraint->deferrable,
10434  fkconstraint->initdeferred,
10435  fkconstraint->initially_valid,
10436  parentConstr,
10437  partitionId,
10438  mapped_fkattnum,
10439  numfks,
10440  numfks,
10441  InvalidOid,
10442  indexOid,
10443  RelationGetRelid(pkrel),
10444  pkattnum,
10445  pfeqoperators,
10446  ppeqoperators,
10447  ffeqoperators,
10448  numfks,
10449  fkconstraint->fk_upd_action,
10450  fkconstraint->fk_del_action,
10451  fkdelsetcols,
10452  numfkdelsetcols,
10453  fkconstraint->fk_matchtype,
10454  NULL,
10455  NULL,
10456  NULL,
10457  false,
10458  1,
10459  false,
10460  false);
10461 
10462  /*
10463  * Give this constraint partition-type dependencies on the parent
10464  * constraint as well as the table.
10465  */
10466  ObjectAddressSet(address, ConstraintRelationId, constrOid);
10467  ObjectAddressSet(referenced, ConstraintRelationId, parentConstr);
10468  recordDependencyOn(&address, &referenced, DEPENDENCY_PARTITION_PRI);
10469  ObjectAddressSet(referenced, RelationRelationId, partitionId);
10470  recordDependencyOn(&address, &referenced, DEPENDENCY_PARTITION_SEC);
10471 
10472  /* Make all this visible before recursing */
10474 
10475  /* call ourselves to finalize the creation and we're done */
10476  addFkRecurseReferencing(wqueue, fkconstraint, partition, pkrel,
10477  indexOid,
10478  constrOid,
10479  numfks,
10480  pkattnum,
10481  mapped_fkattnum,
10482  pfeqoperators,
10483  ppeqoperators,
10484  ffeqoperators,
10485  numfkdelsetcols,
10486  fkdelsetcols,
10487  old_check_ok,
10488  lockmode,
10489  insertTriggerOid,
10490  updateTriggerOid);
10491 
10492  table_close(partition, NoLock);
10493  }
10494 
10495  table_close(trigrel, RowExclusiveLock);
10496  }
10497 }
10498 
10499 /*
10500  * CloneForeignKeyConstraints
10501  * Clone foreign keys from a partitioned table to a newly acquired
10502  * partition.
10503  *
10504  * partitionRel is a partition of parentRel, so we can be certain that it has
10505  * the same columns with the same datatypes. The columns may be in different
10506  * order, though.
10507  *
10508  * wqueue must be passed to set up phase 3 constraint checking, unless the
10509  * referencing-side partition is known to be empty (such as in CREATE TABLE /
10510  * PARTITION OF).
10511  */
10512 static void
10514  Relation partitionRel)
10515 {
10516  /* This only works for declarative partitioning */
10517  Assert(parentRel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
10518 
10519  /*
10520  * Clone constraints for which the parent is on the referenced side.
10521  */
10522  CloneFkReferenced(parentRel, partitionRel);
10523 
10524  /*
10525  * Now clone constraints where the parent is on the referencing side.
10526  */
10527  CloneFkReferencing(wqueue, parentRel, partitionRel);
10528 }
10529 
10530 /*
10531  * CloneFkReferenced
10532  * Subroutine for CloneForeignKeyConstraints
10533  *
10534  * Find all the FKs that have the parent relation on the referenced side;
10535  * clone those constraints to the given partition. This is to be called
10536  * when the partition is being created or attached.
10537  *
10538  * This ignores self-referencing FKs; those are handled by CloneFkReferencing.
10539  *
10540  * This recurses to partitions, if the relation being attached is partitioned.
10541  * Recursion is done by calling addFkRecurseReferenced.
10542  */
10543 static void
10544 CloneFkReferenced(Relation parentRel, Relation partitionRel)
10545 {
10546  Relation pg_constraint;
10547  AttrMap *attmap;
10548  ListCell *cell;
10549  SysScanDesc scan;
10550  ScanKeyData key[2];
10551  HeapTuple tuple;
10552  List *clone = NIL;
10553  Relation trigrel;
10554 
10555  /*
10556  * Search for any constraints where this partition's parent is in the
10557  * referenced side. However, we must not clone any constraint whose
10558  * parent constraint is also going to be cloned, to avoid duplicates. So
10559  * do it in two steps: first construct the list of constraints to clone,
10560  * then go over that list cloning those whose parents are not in the list.
10561  * (We must not rely on the parent being seen first, since the catalog
10562  * scan could return children first.)
10563  */
10564  pg_constraint = table_open(ConstraintRelationId, RowShareLock);
10565  ScanKeyInit(&key[0],
10566  Anum_pg_constraint_confrelid, BTEqualStrategyNumber,
10567  F_OIDEQ, ObjectIdGetDatum(RelationGetRelid(parentRel)));
10568  ScanKeyInit(&key[1],
10569  Anum_pg_constraint_contype, BTEqualStrategyNumber,
10570  F_CHAREQ, CharGetDatum(CONSTRAINT_FOREIGN));
10571  /* This is a seqscan, as we don't have a usable index ... */
10572  scan = systable_beginscan(pg_constraint, InvalidOid, true,
10573  NULL, 2, key);
10574  while ((tuple = systable_getnext(scan)) != NULL)
10575  {
10576  Form_pg_constraint constrForm = (Form_pg_constraint) GETSTRUCT(tuple);
10577 
10578  clone = lappend_oid(clone, constrForm->oid);
10579  }
10580  systable_endscan(scan);
10581  table_close(pg_constraint, RowShareLock);
10582 
10583  /*
10584  * Triggers of the foreign keys will be manipulated a bunch of times in
10585  * the loop below. To avoid repeatedly opening/closing the trigger
10586  * catalog relation, we open it here and pass it to the subroutines called
10587  * below.
10588  */
10589  trigrel = table_open(TriggerRelationId, RowExclusiveLock);
10590 
10591  attmap = build_attrmap_by_name(RelationGetDescr(partitionRel),
10592  RelationGetDescr(parentRel),
10593  false);
10594  foreach(cell, clone)
10595  {
10596  Oid constrOid = lfirst_oid(cell);
10597  Form_pg_constraint constrForm;
10598  Relation fkRel;
10599  Oid indexOid;
10600  Oid partIndexId;
10601  int numfks;
10602  AttrNumber conkey[INDEX_MAX_KEYS];
10603  AttrNumber mapped_confkey[INDEX_MAX_KEYS];
10604  AttrNumber confkey[INDEX_MAX_KEYS];
10605  Oid conpfeqop[INDEX_MAX_KEYS];
10606  Oid conppeqop[INDEX_MAX_KEYS];
10607  Oid conffeqop[INDEX_MAX_KEYS];
10608  int numfkdelsetcols;
10609  AttrNumber confdelsetcols[INDEX_MAX_KEYS];
10610  Constraint *fkconstraint;
10611  Oid deleteTriggerOid,
10612  updateTriggerOid;
10613 
10614  tuple = SearchSysCache1(CONSTROID, ObjectIdGetDatum(constrOid));
10615  if (!HeapTupleIsValid(tuple))
10616  elog(ERROR, "cache lookup failed for constraint %u", constrOid);
10617  constrForm = (Form_pg_constraint) GETSTRUCT(tuple);
10618 
10619  /*
10620  * As explained above: don't try to clone a constraint for which we're
10621  * going to clone the parent.
10622  */
10623  if (list_member_oid(clone, constrForm->conparentid))
10624  {
10625  ReleaseSysCache(tuple);
10626  continue;
10627  }
10628 
10629  /*
10630  * Don't clone self-referencing foreign keys, which can be in the
10631  * partitioned table or in the partition-to-be.
10632  */
10633  if (constrForm->conrelid == RelationGetRelid(parentRel) ||
10634  constrForm->conrelid == RelationGetRelid(partitionRel))
10635  {
10636  ReleaseSysCache(tuple);
10637  continue;
10638  }
10639 
10640  /*
10641  * Because we're only expanding the key space at the referenced side,
10642  * we don't need to prevent any operation in the referencing table, so
10643  * AccessShareLock suffices (assumes that dropping the constraint
10644  * acquires AEL).
10645  */
10646  fkRel = table_open(constrForm->conrelid, AccessShareLock);
10647 
10648  indexOid = constrForm->conindid;
10650  &numfks,
10651  conkey,
10652  confkey,
10653  conpfeqop,
10654  conppeqop,
10655  conffeqop,
10656  &numfkdelsetcols,
10657  confdelsetcols);
10658 
10659  for (int i = 0; i < numfks; i++)
10660  mapped_confkey[i] = attmap->attnums[confkey[i] - 1];
10661 
10662  fkconstraint = makeNode(Constraint);
10663  fkconstraint->contype = CONSTRAINT_FOREIGN;
10664  fkconstraint->conname = NameStr(constrForm->conname);
10665  fkconstraint->deferrable = constrForm->condeferrable;
10666  fkconstraint->initdeferred = constrForm->condeferred;
10667  fkconstraint->location = -1;
10668  fkconstraint->pktable = NULL;
10669  /* ->fk_attrs determined below */
10670  fkconstraint->pk_attrs = NIL;
10671  fkconstraint->fk_matchtype = constrForm->confmatchtype;
10672  fkconstraint->fk_upd_action = constrForm->confupdtype;
10673  fkconstraint->fk_del_action = constrForm->confdeltype;
10674  fkconstraint->fk_del_set_cols = NIL;
10675  fkconstraint->old_conpfeqop = NIL;
10676  fkconstraint->old_pktable_oid = InvalidOid;
10677  fkconstraint->skip_validation = false;
10678  fkconstraint->initially_valid = true;
10679 
10680  /* set up colnames that are used to generate the constraint name */
10681  for (int i = 0; i < numfks; i++)
10682  {
10683  Form_pg_attribute att;
10684 
10685  att = TupleDescAttr(RelationGetDescr(fkRel),
10686  conkey[i] - 1);
10687  fkconstraint->fk_attrs = lappend(fkconstraint->fk_attrs,
10688  makeString(NameStr(att->attname)));
10689  }
10690 
10691  /*
10692  * Add the new foreign key constraint pointing to the new partition.
10693  * Because this new partition appears in the referenced side of the
10694  * constraint, we don't need to set up for Phase 3 check.
10695  */
10696  partIndexId = index_get_partition(partitionRel, indexOid);
10697  if (!OidIsValid(partIndexId))
10698  elog(ERROR, "index for %u not found in partition %s",
10699  indexOid, RelationGetRelationName(partitionRel));
10700 
10701  /*
10702  * Get the "action" triggers belonging to the constraint to pass as
10703  * parent OIDs for similar triggers that will be created on the
10704  * partition in addFkRecurseReferenced().
10705  */
10706  GetForeignKeyActionTriggers(trigrel, constrOid,
10707  constrForm->confrelid, constrForm->conrelid,
10708  &deleteTriggerOid, &updateTriggerOid);
10709 
10711  fkconstraint,
10712  fkRel,
10713  partitionRel,
10714  partIndexId,
10715  constrOid,
10716  numfks,
10717  mapped_confkey,
10718  conkey,
10719  conpfeqop,
10720  conppeqop,
10721  conffeqop,
10722  numfkdelsetcols,
10723  confdelsetcols,
10724  true,
10725  deleteTriggerOid,
10726  updateTriggerOid);
10727 
10728  table_close(fkRel, NoLock);
10729  ReleaseSysCache(tuple);
10730  }
10731 
10732  table_close(trigrel, RowExclusiveLock);
10733 }
10734 
10735 /*
10736  * CloneFkReferencing
10737  * Subroutine for CloneForeignKeyConstraints
10738  *
10739  * For each FK constraint of the parent relation in the given list, find an
10740  * equivalent constraint in its partition relation that can be reparented;
10741  * if one cannot be found, create a new constraint in the partition as its
10742  * child.
10743  *
10744  * If wqueue is given, it is used to set up phase-3 verification for each
10745  * cloned constraint; if omitted, we assume that such verification is not
10746  * needed (example: the partition is being created anew).
10747  */
10748 static void
10749 CloneFkReferencing(List **wqueue, Relation parentRel, Relation partRel)
10750 {
10751  AttrMap *attmap;
10752  List *partFKs;
10753  List *clone = NIL;
10754  ListCell *cell;
10755  Relation trigrel;
10756 
10757  /* obtain a list of constraints that we need to clone */
10758  foreach(cell, RelationGetFKeyList(parentRel))
10759  {
10760  ForeignKeyCacheInfo *fk = lfirst(cell);
10761 
10762  clone = lappend_oid(clone, fk->conoid);
10763  }
10764 
10765  /*
10766  * Silently do nothing if there's nothing to do. In particular, this
10767  * avoids throwing a spurious error for foreign tables.
10768  */
10769  if (clone == NIL)
10770  return;
10771 
10772  if (partRel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
10773  ereport(ERROR,
10774  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
10775  errmsg("foreign key constraints are not supported on foreign tables")));
10776 
10777  /*
10778  * Triggers of the foreign keys will be manipulated a bunch of times in
10779  * the loop below. To avoid repeatedly opening/closing the trigger
10780  * catalog relation, we open it here and pass it to the subroutines called
10781  * below.
10782  */
10783  trigrel = table_open(TriggerRelationId, RowExclusiveLock);
10784 
10785  /*
10786  * The constraint key may differ, if the columns in the partition are
10787  * different. This map is used to convert them.
10788  */
10789  attmap = build_attrmap_by_name(RelationGetDescr(partRel),
10790  RelationGetDescr(parentRel),
10791  false);
10792 
10793  partFKs = copyObject(RelationGetFKeyList(partRel));
10794 
10795  foreach(cell, clone)
10796  {
10797  Oid parentConstrOid = lfirst_oid(cell);
10798  Form_pg_constraint constrForm;
10799  Relation pkrel;
10800  HeapTuple tuple;
10801  int numfks;
10802  AttrNumber conkey[INDEX_MAX_KEYS];
10803  AttrNumber mapped_conkey[INDEX_MAX_KEYS];
10804  AttrNumber confkey[INDEX_MAX_KEYS];
10805  Oid conpfeqop[INDEX_MAX_KEYS];
10806  Oid conppeqop[INDEX_MAX_KEYS];
10807  Oid conffeqop[INDEX_MAX_KEYS];
10808  int numfkdelsetcols;
10809  AttrNumber confdelsetcols[INDEX_MAX_KEYS];
10810  Constraint *fkconstraint;
10811  bool attached;
10812  Oid indexOid;
10813  Oid constrOid;
10814  ObjectAddress address,
10815  referenced;
10816  ListCell *lc;
10817  Oid insertTriggerOid,
10818  updateTriggerOid;
10819 
10820  tuple = SearchSysCache1(CONSTROID, ObjectIdGetDatum(parentConstrOid));
10821  if (!HeapTupleIsValid(tuple))
10822  elog(ERROR, "cache lookup failed for constraint %u",
10823  parentConstrOid);
10824  constrForm = (Form_pg_constraint) GETSTRUCT(tuple);
10825 
10826  /* Don't clone constraints whose parents are being cloned */
10827  if (list_member_oid(clone, constrForm->conparentid))
10828  {
10829  ReleaseSysCache(tuple);
10830  continue;
10831  }
10832 
10833  /*
10834  * Need to prevent concurrent deletions. If pkrel is a partitioned
10835  * relation, that means to lock all partitions.
10836  */
10837  pkrel = table_open(constrForm->confrelid, ShareRowExclusiveLock);
10838  if (pkrel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
10839  (void) find_all_inheritors(RelationGetRelid(pkrel),
10840  ShareRowExclusiveLock, NULL);
10841 
10842  DeconstructFkConstraintRow(tuple, &numfks, conkey, confkey,
10843  conpfeqop, conppeqop, conffeqop,
10844  &numfkdelsetcols, confdelsetcols);
10845  for (int i = 0; i < numfks; i++)
10846  mapped_conkey[i] = attmap->attnums[conkey[i] - 1];
10847 
10848  /*
10849  * Get the "check" triggers belonging to the constraint to pass as
10850  * parent OIDs for similar triggers that will be created on the
10851  * partition in addFkRecurseReferencing(). They are also passed to
10852  * tryAttachPartitionForeignKey() below to simply assign as parents to
10853  * the partition's existing "check" triggers, that is, if the
10854  * corresponding constraints is deemed attachable to the parent
10855  * constraint.
10856  */
10857  GetForeignKeyCheckTriggers(trigrel, constrForm->oid,
10858  constrForm->confrelid, constrForm->conrelid,
10859  &insertTriggerOid, &updateTriggerOid);
10860 
10861  /*
10862  * Before creating a new constraint, see whether any existing FKs are
10863  * fit for the purpose. If one is, attach the parent constraint to
10864  * it, and don't clone anything. This way we avoid the expensive
10865  * verification step and don't end up with a duplicate FK, and we
10866  * don't need to recurse to partitions for this constraint.
10867  */
10868  attached = false;
10869  foreach(lc, partFKs)
10870  {
10872 
10874  RelationGetRelid(partRel),
10875  parentConstrOid,
10876  numfks,
10877  mapped_conkey,
10878  confkey,
10879  conpfeqop,
10880  insertTriggerOid,
10881  updateTriggerOid,
10882  trigrel))
10883  {
10884  attached = true;
10885  table_close(pkrel, NoLock);
10886  break;
10887  }
10888  }
10889  if (attached)
10890  {
10891  ReleaseSysCache(tuple);
10892  continue;
10893  }
10894 
10895  /* No dice. Set up to create our own constraint */
10896  fkconstraint = makeNode(Constraint);
10897  fkconstraint->contype = CONSTRAINT_FOREIGN;
10898  /* ->conname determined below */
10899  fkconstraint->deferrable = constrForm->condeferrable;
10900  fkconstraint->initdeferred = constrForm->condeferred;
10901  fkconstraint->location = -1;
10902  fkconstraint->pktable = NULL;
10903  /* ->fk_attrs determined below */
10904  fkconstraint->pk_attrs = NIL;
10905  fkconstraint->fk_matchtype = constrForm->confmatchtype;
10906  fkconstraint->fk_upd_action = constrForm->confupdtype;
10907  fkconstraint->fk_del_action = constrForm->confdeltype;
10908  fkconstraint->fk_del_set_cols = NIL;
10909  fkconstraint->old_conpfeqop = NIL;
10910  fkconstraint->old_pktable_oid = InvalidOid;
10911  fkconstraint->skip_validation = false;
10912  fkconstraint->initially_valid = true;
10913  for (int i = 0; i < numfks; i++)
10914  {
10915  Form_pg_attribute att;
10916 
10917  att = TupleDescAttr(RelationGetDescr(partRel),
10918  mapped_conkey[i] - 1);
10919  fkconstraint->fk_attrs = lappend(fkconstraint->fk_attrs,
10920  makeString(NameStr(att->attname)));
10921  }
10923  RelationGetRelid(partRel),
10924  NameStr(constrForm->conname)))
10925  fkconstraint->conname =
10928  "fkey",
10929  RelationGetNamespace(partRel), NIL);
10930  else
10931  fkconstraint->conname = pstrdup(NameStr(constrForm->conname));
10932 
10933  indexOid = constrForm->conindid;
10934  constrOid =
10935  CreateConstraintEntry(fkconstraint->conname,
10936  constrForm->connamespace,
10937  CONSTRAINT_FOREIGN,
10938  fkconstraint->deferrable,
10939  fkconstraint->initdeferred,
10940  constrForm->convalidated,
10941  parentConstrOid,
10942  RelationGetRelid(partRel),
10943  mapped_conkey,
10944  numfks,
10945  numfks,
10946  InvalidOid, /* not a domain constraint */
10947  indexOid,
10948  constrForm->confrelid, /* same foreign rel */
10949  confkey,
10950  conpfeqop,
10951  conppeqop,
10952  conffeqop,
10953  numfks,
10954  fkconstraint->fk_upd_action,
10955  fkconstraint->fk_del_action,
10956  confdelsetcols,
10957  numfkdelsetcols,
10958  fkconstraint->fk_matchtype,
10959  NULL,
10960  NULL,
10961  NULL,
10962  false, /* islocal */
10963  1, /* inhcount */
10964  false, /* conNoInherit */
10965  true);
10966 
10967  /* Set up partition dependencies for the new constraint */
10968  ObjectAddressSet(address, ConstraintRelationId, constrOid);
10969  ObjectAddressSet(referenced, ConstraintRelationId, parentConstrOid);
10970  recordDependencyOn(&address, &referenced, DEPENDENCY_PARTITION_PRI);
10971  ObjectAddressSet(referenced, RelationRelationId,
10972  RelationGetRelid(partRel));
10973  recordDependencyOn(&address, &referenced, DEPENDENCY_PARTITION_SEC);
10974 
10975  /* Done with the cloned constraint's tuple */
10976  ReleaseSysCache(tuple);
10977 
10978  /* Make all this visible before recursing */
10980 
10981  addFkRecurseReferencing(wqueue,
10982  fkconstraint,
10983  partRel,
10984  pkrel,
10985  indexOid,
10986  constrOid,
10987  numfks,
10988  confkey,
10989  mapped_conkey,
10990  conpfeqop,
10991  conppeqop,
10992  conffeqop,
10993  numfkdelsetcols,
10994  confdelsetcols,
10995  false, /* no old check exists */
10997  insertTriggerOid,
10998  updateTriggerOid);
10999  table_close(pkrel, NoLock);
11000  }
11001 
11002  table_close(trigrel, RowExclusiveLock);
11003 }
11004 
11005 /*
11006  * When the parent of a partition receives [the referencing side of] a foreign
11007  * key, we must propagate that foreign key to the partition. However, the
11008  * partition might already have an equivalent foreign key; this routine
11009  * compares the given ForeignKeyCacheInfo (in the partition) to the FK defined
11010  * by the other parameters. If they are equivalent, create the link between
11011  * the two constraints and return true.
11012  *
11013  * If the given FK does not match the one defined by rest of the params,
11014  * return false.
11015  */
11016 static bool
11018  Oid partRelid,
11019  Oid parentConstrOid,
11020  int numfks,
11021  AttrNumber *mapped_conkey,
11022  AttrNumber *confkey,
11023  Oid *conpfeqop,
11024  Oid parentInsTrigger,
11025  Oid parentUpdTrigger,
11026  Relation trigrel)
11027 {
11028  HeapTuple parentConstrTup;
11029  Form_pg_constraint parentConstr;
11030  HeapTuple partcontup;
11031  Form_pg_constraint partConstr;
11032  ScanKeyData key;
11033  SysScanDesc scan;
11034  HeapTuple trigtup;
11035  Oid insertTriggerOid,
11036  updateTriggerOid;
11037 
11038  parentConstrTup = SearchSysCache1(CONSTROID,
11039  ObjectIdGetDatum(parentConstrOid));
11040  if (!HeapTupleIsValid(parentConstrTup))
11041  elog(ERROR, "cache lookup failed for constraint %u", parentConstrOid);
11042  parentConstr = (Form_pg_constraint) GETSTRUCT(parentConstrTup);
11043 
11044  /*
11045  * Do some quick & easy initial checks. If any of these fail, we cannot
11046  * use this constraint.
11047  */
11048  if (fk->confrelid != parentConstr->confrelid || fk->nkeys != numfks)
11049  {
11050  ReleaseSysCache(parentConstrTup);
11051  return false;
11052  }
11053  for (int i = 0; i < numfks; i++)
11054  {
11055  if (fk->conkey[i] != mapped_conkey[i] ||
11056  fk->confkey[i] != confkey[i] ||
11057  fk->conpfeqop[i] != conpfeqop[i])
11058  {
11059  ReleaseSysCache(parentConstrTup);
11060  return false;
11061  }
11062  }
11063 
11064  /*
11065  * Looks good so far; do some more extensive checks. Presumably the check
11066  * for 'convalidated' could be dropped, since we don't really care about
11067  * that, but let's be careful for now.
11068  */
11069  partcontup = SearchSysCache1(CONSTROID,
11070  ObjectIdGetDatum(fk->conoid));
11071  if (!HeapTupleIsValid(partcontup))
11072  elog(ERROR, "cache lookup failed for constraint %u", fk->conoid);
11073  partConstr = (Form_pg_constraint) GETSTRUCT(partcontup);
11074  if (OidIsValid(partConstr->conparentid) ||
11075  !partConstr->convalidated ||
11076  partConstr->condeferrable != parentConstr->condeferrable ||
11077  partConstr->condeferred != parentConstr->condeferred ||
11078  partConstr->confupdtype != parentConstr->confupdtype ||
11079  partConstr->confdeltype != parentConstr->confdeltype ||
11080  partConstr->confmatchtype != parentConstr->confmatchtype)
11081  {
11082  ReleaseSysCache(parentConstrTup);
11083  ReleaseSysCache(partcontup);
11084  return false;
11085  }
11086 
11087  ReleaseSysCache(partcontup);
11088  ReleaseSysCache(parentConstrTup);
11089 
11090  /*
11091  * Looks good! Attach this constraint. The action triggers in the new
11092  * partition become redundant -- the parent table already has equivalent
11093  * ones, and those will be able to reach the partition. Remove the ones
11094  * in the partition. We identify them because they have our constraint
11095  * OID, as well as being on the referenced rel.
11096  */
11097  ScanKeyInit(&key,
11098  Anum_pg_trigger_tgconstraint,
11099  BTEqualStrategyNumber, F_OIDEQ,
11100  ObjectIdGetDatum(fk->conoid));
11101  scan = systable_beginscan(trigrel, TriggerConstraintIndexId, true,
11102  NULL, 1, &key);
11103  while ((trigtup = systable_getnext(scan)) != NULL)
11104  {
11105  Form_pg_trigger trgform = (Form_pg_trigger) GETSTRUCT(trigtup);
11106  ObjectAddress trigger;
11107 
11108  if (trgform->tgconstrrelid != fk->conrelid)
11109  continue;
11110  if (trgform->tgrelid != fk->confrelid)
11111  continue;
11112 
11113  /*
11114  * The constraint is originally set up to contain this trigger as an
11115  * implementation object, so there's a dependency record that links
11116  * the two; however, since the trigger is no longer needed, we remove
11117  * the dependency link in order to be able to drop the trigger while
11118  * keeping the constraint intact.
11119  */
11120  deleteDependencyRecordsFor(TriggerRelationId,
11121  trgform->oid,
11122  false);
11123  /* make dependency deletion visible to performDeletion */
11125  ObjectAddressSet(trigger, TriggerRelationId,
11126  trgform->oid);
11127  performDeletion(&trigger, DROP_RESTRICT, 0);
11128  /* make trigger drop visible, in case the loop iterates */
11130  }
11131 
11132  systable_endscan(scan);
11133 
11134  ConstraintSetParentConstraint(fk->conoid, parentConstrOid, partRelid);
11135 
11136  /*
11137  * Like the constraint, attach partition's "check" triggers to the
11138  * corresponding parent triggers.
11139  */
11141  fk->conoid, fk->confrelid, fk->conrelid,
11142  &insertTriggerOid, &updateTriggerOid);
11143  Assert(OidIsValid(insertTriggerOid) && OidIsValid(parentInsTrigger));
11144  TriggerSetParentTrigger(trigrel, insertTriggerOid, parentInsTrigger,
11145  partRelid);
11146  Assert(OidIsValid(updateTriggerOid) && OidIsValid(parentUpdTrigger));
11147  TriggerSetParentTrigger(trigrel, updateTriggerOid, parentUpdTrigger,
11148  partRelid);
11149 
11151  return true;
11152 }
11153 
11154 /*
11155  * GetForeignKeyActionTriggers
11156  * Returns delete and update "action" triggers of the given relation
11157  * belonging to the given constraint
11158  */
11159 static void
11161  Oid conoid, Oid confrelid, Oid conrelid,
11162  Oid *deleteTriggerOid,
11163  Oid *updateTriggerOid)
11164 {
11165  ScanKeyData key;
11166  SysScanDesc scan;
11167  HeapTuple trigtup;
11168 
11169  *deleteTriggerOid = *updateTriggerOid = InvalidOid;
11170  ScanKeyInit(&key,
11171  Anum_pg_trigger_tgconstraint,
11172  BTEqualStrategyNumber, F_OIDEQ,
11173  ObjectIdGetDatum(conoid));
11174 
11175  scan = systable_beginscan(trigrel, TriggerConstraintIndexId, true,
11176  NULL, 1, &key);
11177  while ((trigtup = systable_getnext(scan)) != NULL)
11178  {
11179  Form_pg_trigger trgform = (Form_pg_trigger) GETSTRUCT(trigtup);
11180 
11181  if (trgform->tgconstrrelid != conrelid)
11182  continue;
11183  if (trgform->tgrelid != confrelid)
11184  continue;
11185  /* Only ever look at "action" triggers on the PK side. */
11186  if (RI_FKey_trigger_type(trgform->tgfoid) != RI_TRIGGER_PK)
11187  continue;
11188  if (TRIGGER_FOR_DELETE(trgform->tgtype))
11189  {
11190  Assert(*deleteTriggerOid == InvalidOid);
11191  *deleteTriggerOid = trgform->oid;
11192  }
11193  else if (TRIGGER_FOR_UPDATE(trgform->tgtype))
11194  {
11195  Assert(*updateTriggerOid == InvalidOid);
11196  *updateTriggerOid = trgform->oid;
11197  }
11198 #ifndef USE_ASSERT_CHECKING
11199  /* In an assert-enabled build, continue looking to find duplicates */
11200  if (OidIsValid(*deleteTriggerOid) && OidIsValid(*updateTriggerOid))
11201  break;
11202 #endif
11203  }
11204 
11205  if (!OidIsValid(*deleteTriggerOid))
11206  elog(ERROR, "could not find ON DELETE action trigger of foreign key constraint %u",
11207  conoid);
11208  if (!OidIsValid(*updateTriggerOid))
11209  elog(ERROR, "could not find ON UPDATE action trigger of foreign key constraint %u",
11210  conoid);
11211 
11212  systable_endscan(scan);
11213 }
11214 
11215 /*
11216  * GetForeignKeyCheckTriggers
11217  * Returns insert and update "check" triggers of the given relation
11218  * belonging to the given constraint
11219  */
11220 static void
11222  Oid conoid, Oid confrelid, Oid conrelid,
11223  Oid *insertTriggerOid,
11224  Oid *updateTriggerOid)
11225 {
11226  ScanKeyData key;
11227  SysScanDesc scan;
11228  HeapTuple trigtup;
11229 
11230  *insertTriggerOid = *updateTriggerOid = InvalidOid;
11231  ScanKeyInit(&key,
11232  Anum_pg_trigger_tgconstraint,
11233  BTEqualStrategyNumber, F_OIDEQ,
11234  ObjectIdGetDatum(conoid));
11235 
11236  scan = systable_beginscan(trigrel, TriggerConstraintIndexId, true,
11237  NULL, 1, &key);
11238  while ((trigtup = systable_getnext(scan)) != NULL)
11239  {
11240  Form_pg_trigger trgform = (Form_pg_trigger) GETSTRUCT(trigtup);
11241 
11242  if (trgform->tgconstrrelid != confrelid)
11243  continue;
11244  if (trgform->tgrelid != conrelid)
11245  continue;
11246  /* Only ever look at "check" triggers on the FK side. */
11247  if (RI_FKey_trigger_type(trgform->tgfoid) != RI_TRIGGER_FK)
11248  continue;
11249  if (TRIGGER_FOR_INSERT(trgform->tgtype))
11250  {
11251  Assert(*insertTriggerOid == InvalidOid);
11252  *insertTriggerOid = trgform->oid;
11253  }
11254  else if (TRIGGER_FOR_UPDATE(trgform->tgtype))
11255  {
11256  Assert(*updateTriggerOid == InvalidOid);
11257  *updateTriggerOid = trgform->oid;
11258  }
11259 #ifndef USE_ASSERT_CHECKING
11260  /* In an assert-enabled build, continue looking to find duplicates. */
11261  if (OidIsValid(*insertTriggerOid) && OidIsValid(*updateTriggerOid))
11262  break;
11263 #endif
11264  }
11265 
11266  if (!OidIsValid(*insertTriggerOid))
11267  elog(ERROR, "could not find ON INSERT check triggers of foreign key constraint %u",
11268  conoid);
11269  if (!OidIsValid(*updateTriggerOid))
11270  elog(ERROR, "could not find ON UPDATE check triggers of foreign key constraint %u",
11271  conoid);
11272 
11273  systable_endscan(scan);
11274 }
11275 
11276 /*
11277  * ALTER TABLE ALTER CONSTRAINT
11278  *
11279  * Update the attributes of a constraint.
11280  *
11281  * Currently only works for Foreign Key constraints.
11282  *
11283  * If the constraint is modified, returns its address; otherwise, return
11284  * InvalidObjectAddress.
11285  */
11286 static ObjectAddress
11288  bool recursing, LOCKMODE lockmode)
11289 {
11290  Constraint *cmdcon;
11291  Relation conrel;
11292  Relation tgrel;
11293  SysScanDesc scan;
11294  ScanKeyData skey[3];
11295  HeapTuple contuple;
11296  Form_pg_constraint currcon;
11297  ObjectAddress address;
11298  List *otherrelids = NIL;
11299  ListCell *lc;
11300 
11301  cmdcon = castNode(Constraint, cmd->def);
11302 
11303  conrel = table_open(ConstraintRelationId, RowExclusiveLock);
11304  tgrel = table_open(TriggerRelationId, RowExclusiveLock);
11305 
11306  /*
11307  * Find and check the target constraint
11308  */
11309  ScanKeyInit(&skey[0],
11310  Anum_pg_constraint_conrelid,
11311  BTEqualStrategyNumber, F_OIDEQ,
11313  ScanKeyInit(&skey[1],
11314  Anum_pg_constraint_contypid,
11315  BTEqualStrategyNumber, F_OIDEQ,
11317  ScanKeyInit(&skey[2],
11318  Anum_pg_constraint_conname,
11319  BTEqualStrategyNumber, F_NAMEEQ,
11320  CStringGetDatum(cmdcon->conname));
11321  scan = systable_beginscan(conrel, ConstraintRelidTypidNameIndexId,
11322  true, NULL, 3, skey);
11323 
11324  /* There can be at most one matching row */
11325  if (!HeapTupleIsValid(contuple = systable_getnext(scan)))
11326  ereport(ERROR,
11327  (errcode(ERRCODE_UNDEFINED_OBJECT),
11328  errmsg("constraint \"%s\" of relation \"%s\" does not exist",
11329  cmdcon->conname, RelationGetRelationName(rel))));
11330 
11331  currcon = (Form_pg_constraint) GETSTRUCT(contuple);
11332  if (currcon->contype != CONSTRAINT_FOREIGN)
11333  ereport(ERROR,
11334  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
11335  errmsg("constraint \"%s\" of relation \"%s\" is not a foreign key constraint",
11336  cmdcon->conname, RelationGetRelationName(rel))));
11337 
11338  /*
11339  * If it's not the topmost constraint, raise an error.
11340  *
11341  * Altering a non-topmost constraint leaves some triggers untouched, since
11342  * they are not directly connected to this constraint; also, pg_dump would
11343  * ignore the deferrability status of the individual constraint, since it
11344  * only dumps topmost constraints. Avoid these problems by refusing this
11345  * operation and telling the user to alter the parent constraint instead.
11346  */
11347  if (OidIsValid(currcon->conparentid))
11348  {
11349  HeapTuple tp;
11350  Oid parent = currcon->conparentid;
11351  char *ancestorname = NULL;
11352  char *ancestortable = NULL;
11353 
11354  /* Loop to find the topmost constraint */
11355  while (HeapTupleIsValid(tp = SearchSysCache1(CONSTROID, ObjectIdGetDatum(parent))))
11356  {
11358 
11359  /* If no parent, this is the constraint we want */
11360  if (!OidIsValid(contup->conparentid))
11361  {
11362  ancestorname = pstrdup(NameStr(contup->conname));
11363  ancestortable = get_rel_name(contup->conrelid);
11364  ReleaseSysCache(tp);
11365  break;
11366  }
11367 
11368  parent = contup->conparentid;
11369  ReleaseSysCache(tp);
11370  }
11371 
11372  ereport(ERROR,
11373  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
11374  errmsg("cannot alter constraint \"%s\" on relation \"%s\"",
11375  cmdcon->conname, RelationGetRelationName(rel)),
11376  ancestorname && ancestortable ?
11377  errdetail("Constraint \"%s\" is derived from constraint \"%s\" of relation \"%s\".",
11378  cmdcon->conname, ancestorname, ancestortable) : 0,
11379  errhint("You may alter the constraint it derives from instead.")));
11380  }
11381 
11382  /*
11383  * Do the actual catalog work. We can skip changing if already in the
11384  * desired state, but not if a partitioned table: partitions need to be
11385  * processed regardless, in case they had the constraint locally changed.
11386  */
11387  address = InvalidObjectAddress;
11388  if (currcon->condeferrable != cmdcon->deferrable ||
11389  currcon->condeferred != cmdcon->initdeferred ||
11390  rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
11391  {
11392  if (ATExecAlterConstrRecurse(cmdcon, conrel, tgrel, rel, contuple,
11393  &otherrelids, lockmode))
11394  ObjectAddressSet(address, ConstraintRelationId, currcon->oid);
11395  }
11396 
11397  /*
11398  * ATExecAlterConstrRecurse already invalidated relcache for the relations
11399  * having the constraint itself; here we also invalidate for relations
11400  * that have any triggers that are part of the constraint.
11401  */
11402  foreach(lc, otherrelids)
11404 
11405  systable_endscan(scan);
11406 
11407  table_close(tgrel, RowExclusiveLock);
11408  table_close(conrel, RowExclusiveLock);
11409 
11410  return address;
11411 }
11412 
11413 /*
11414  * Recursive subroutine of ATExecAlterConstraint. Returns true if the
11415  * constraint is altered.
11416  *
11417  * *otherrelids is appended OIDs of relations containing affected triggers.
11418  *
11419  * Note that we must recurse even when the values are correct, in case
11420  * indirect descendants have had their constraints altered locally.
11421  * (This could be avoided if we forbade altering constraints in partitions
11422  * but existing releases don't do that.)
11423  */
11424 static bool
11426  Relation rel, HeapTuple contuple, List **otherrelids,
11427  LOCKMODE lockmode)
11428 {
11429  Form_pg_constraint currcon;
11430  Oid conoid;
11431  Oid refrelid;
11432  bool changed = false;
11433 
11434  /* since this function recurses, it could be driven to stack overflow */
11436 
11437  currcon = (Form_pg_constraint) GETSTRUCT(contuple);
11438  conoid = currcon->oid;
11439  refrelid = currcon->confrelid;
11440 
11441  /*
11442  * Update pg_constraint with the flags from cmdcon.
11443  *
11444  * If called to modify a constraint that's already in the desired state,
11445  * silently do nothing.
11446  */
11447  if (currcon->condeferrable != cmdcon->deferrable ||
11448  currcon->condeferred != cmdcon->initdeferred)
11449  {
11450  HeapTuple copyTuple;
11451  Form_pg_constraint copy_con;
11452  HeapTuple tgtuple;
11453  ScanKeyData tgkey;
11454  SysScanDesc tgscan;
11455 
11456  copyTuple = heap_copytuple(contuple);
11457  copy_con = (Form_pg_constraint) GETSTRUCT(copyTuple);
11458  copy_con->condeferrable = cmdcon->deferrable;
11459  copy_con->condeferred = cmdcon->initdeferred;
11460  CatalogTupleUpdate(conrel, &copyTuple->t_self, copyTuple);
11461 
11462  InvokeObjectPostAlterHook(ConstraintRelationId,
11463  conoid, 0);
11464 
11465  heap_freetuple(copyTuple);
11466  changed = true;
11467 
11468  /* Make new constraint flags visible to others */
11470 
11471  /*
11472  * Now we need to update the multiple entries in pg_trigger that
11473  * implement the constraint.
11474  */
11475  ScanKeyInit(&tgkey,
11476  Anum_pg_trigger_tgconstraint,
11477  BTEqualStrategyNumber, F_OIDEQ,
11478  ObjectIdGetDatum(conoid));
11479  tgscan = systable_beginscan(tgrel, TriggerConstraintIndexId, true,
11480  NULL, 1, &tgkey);
11481  while (HeapTupleIsValid(tgtuple = systable_getnext(tgscan)))
11482  {
11483  Form_pg_trigger tgform = (Form_pg_trigger) GETSTRUCT(tgtuple);
11484  Form_pg_trigger copy_tg;
11485  HeapTuple tgCopyTuple;
11486 
11487  /*
11488  * Remember OIDs of other relation(s) involved in FK constraint.
11489  * (Note: it's likely that we could skip forcing a relcache inval
11490  * for other rels that don't have a trigger whose properties
11491  * change, but let's be conservative.)
11492  */
11493  if (tgform->tgrelid != RelationGetRelid(rel))
11494  *otherrelids = list_append_unique_oid(*otherrelids,
11495  tgform->tgrelid);
11496 
11497  /*
11498  * Update deferrability of RI_FKey_noaction_del,
11499  * RI_FKey_noaction_upd, RI_FKey_check_ins and RI_FKey_check_upd
11500  * triggers, but not others; see createForeignKeyActionTriggers
11501  * and CreateFKCheckTrigger.
11502  */
11503  if (tgform->tgfoid != F_RI_FKEY_NOACTION_DEL &&
11504  tgform->tgfoid != F_RI_FKEY_NOACTION_UPD &&
11505  tgform->tgfoid != F_RI_FKEY_CHECK_INS &&
11506  tgform->tgfoid != F_RI_FKEY_CHECK_UPD)
11507  continue;
11508 
11509  tgCopyTuple = heap_copytuple(tgtuple);
11510  copy_tg = (Form_pg_trigger) GETSTRUCT(tgCopyTuple);
11511 
11512  copy_tg->tgdeferrable = cmdcon->deferrable;
11513  copy_tg->tginitdeferred = cmdcon->initdeferred;
11514  CatalogTupleUpdate(tgrel, &tgCopyTuple->t_self, tgCopyTuple);
11515 
11516  InvokeObjectPostAlterHook(TriggerRelationId, tgform->oid, 0);
11517 
11518  heap_freetuple(tgCopyTuple);
11519  }
11520 
11521  systable_endscan(tgscan);
11522  }
11523 
11524  /*
11525  * If the table at either end of the constraint is partitioned, we need to
11526  * recurse and handle every constraint that is a child of this one.
11527  *
11528  * (This assumes that the recurse flag is forcibly set for partitioned
11529  * tables, and not set for legacy inheritance, though we don't check for
11530  * that here.)
11531  */
11532  if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE ||
11533  get_rel_relkind(refrelid) == RELKIND_PARTITIONED_TABLE)
11534  {
11535  ScanKeyData pkey;
11536  SysScanDesc pscan;
11537  HeapTuple childtup;
11538 
11539  ScanKeyInit(&pkey,
11540  Anum_pg_constraint_conparentid,
11541  BTEqualStrategyNumber, F_OIDEQ,
11542  ObjectIdGetDatum(conoid));
11543 
11544  pscan = systable_beginscan(conrel, ConstraintParentIndexId,
11545  true, NULL, 1, &pkey);
11546 
11547  while (HeapTupleIsValid(childtup = systable_getnext(pscan)))
11548  {
11549  Form_pg_constraint childcon = (Form_pg_constraint) GETSTRUCT(childtup);
11550  Relation childrel;
11551 
11552  childrel = table_open(childcon->conrelid, lockmode);
11553  ATExecAlterConstrRecurse(cmdcon, conrel, tgrel, childrel, childtup,
11554  otherrelids, lockmode);
11555  table_close(childrel, NoLock);
11556  }
11557 
11558  systable_endscan(pscan);
11559  }
11560 
11561  return changed;
11562 }
11563 
11564 /*
11565  * ALTER TABLE VALIDATE CONSTRAINT
11566  *
11567  * XXX The reason we handle recursion here rather than at Phase 1 is because
11568  * there's no good way to skip recursing when handling foreign keys: there is
11569  * no need to lock children in that case, yet we wouldn't be able to avoid
11570  * doing so at that level.
11571  *
11572  * Return value is the address of the validated constraint. If the constraint
11573  * was already validated, InvalidObjectAddress is returned.
11574  */
11575 static ObjectAddress
11576 ATExecValidateConstraint(List **wqueue, Relation rel, char *constrName,
11577  bool recurse, bool recursing, LOCKMODE lockmode)
11578 {
11579  Relation conrel;
11580  SysScanDesc scan;
11581  ScanKeyData skey[3];
11582  HeapTuple tuple;
11583  Form_pg_constraint con;
11584  ObjectAddress address;
11585 
11586  conrel = table_open(ConstraintRelationId, RowExclusiveLock);
11587 
11588  /*
11589  * Find and check the target constraint
11590  */
11591  ScanKeyInit(&skey[0],
11592  Anum_pg_constraint_conrelid,
11593  BTEqualStrategyNumber, F_OIDEQ,
11595  ScanKeyInit(&skey[1],
11596  Anum_pg_constraint_contypid,
11597  BTEqualStrategyNumber, F_OIDEQ,
11599  ScanKeyInit(&skey[2],
11600  Anum_pg_constraint_conname,
11601  BTEqualStrategyNumber, F_NAMEEQ,
11602  CStringGetDatum(constrName));
11603  scan = systable_beginscan(conrel, ConstraintRelidTypidNameIndexId,
11604  true, NULL, 3, skey);
11605 
11606  /* There can be at most one matching row */
11607  if (!HeapTupleIsValid(tuple = systable_getnext(scan)))
11608  ereport(ERROR,
11609  (errcode(ERRCODE_UNDEFINED_OBJECT),
11610  errmsg("constraint \"%s\" of relation \"%s\" does not exist",
11611  constrName, RelationGetRelationName(rel))));
11612 
11613  con = (Form_pg_constraint) GETSTRUCT(tuple);
11614  if (con->contype != CONSTRAINT_FOREIGN &&
11615  con->contype != CONSTRAINT_CHECK)
11616  ereport(ERROR,
11617  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
11618  errmsg("constraint \"%s\" of relation \"%s\" is not a foreign key or check constraint",
11619  constrName, RelationGetRelationName(rel))));
11620 
11621  if (!con->convalidated)
11622  {
11623  AlteredTableInfo *tab;
11624  HeapTuple copyTuple;
11625  Form_pg_constraint copy_con;
11626 
11627  if (con->contype == CONSTRAINT_FOREIGN)
11628  {
11629  NewConstraint *newcon;
11630  Constraint *fkconstraint;
11631 
11632  /* Queue validation for phase 3 */
11633  fkconstraint = makeNode(Constraint);
11634  /* for now this is all we need */
11635  fkconstraint->conname = constrName;
11636 
11637  newcon = (NewConstraint *) palloc0(sizeof(NewConstraint));
11638  newcon->name = constrName;
11639  newcon->contype = CONSTR_FOREIGN;
11640  newcon->refrelid = con->confrelid;
11641  newcon->refindid = con->conindid;
11642  newcon->conid = con->oid;
11643  newcon->qual = (Node *) fkconstraint;
11644 
11645  /* Find or create work queue entry for this table */
11646  tab = ATGetQueueEntry(wqueue, rel);
11647  tab->constraints = lappend(tab->constraints, newcon);
11648 
11649  /*
11650  * We disallow creating invalid foreign keys to or from
11651  * partitioned tables, so ignoring the recursion bit is okay.
11652  */
11653  }
11654  else if (con->contype == CONSTRAINT_CHECK)
11655  {
11656  List *children = NIL;
11657  ListCell *child;
11658  NewConstraint *newcon;
11659  Datum val;
11660  char *conbin;
11661 
11662  /*
11663  * If we're recursing, the parent has already done this, so skip
11664  * it. Also, if the constraint is a NO INHERIT constraint, we
11665  * shouldn't try to look for it in the children.
11666  */
11667  if (!recursing && !con->connoinherit)
11668  children = find_all_inheritors(RelationGetRelid(rel),
11669  lockmode, NULL);
11670 
11671  /*
11672  * For CHECK constraints, we must ensure that we only mark the
11673  * constraint as validated on the parent if it's already validated
11674  * on the children.
11675  *
11676  * We recurse before validating on the parent, to reduce risk of
11677  * deadlocks.
11678  */
11679  foreach(child, children)
11680  {
11681  Oid childoid = lfirst_oid(child);
11682  Relation childrel;
11683 
11684  if (childoid == RelationGetRelid(rel))
11685  continue;
11686 
11687  /*
11688  * If we are told not to recurse, there had better not be any
11689  * child tables, because we can't mark the constraint on the
11690  * parent valid unless it is valid for all child tables.
11691  */
11692  if (!recurse)
11693  ereport(ERROR,
11694  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
11695  errmsg("constraint must be validated on child tables too")));
11696 
11697  /* find_all_inheritors already got lock */
11698  childrel = table_open(childoid, NoLock);
11699 
11700  ATExecValidateConstraint(wqueue, childrel, constrName, false,
11701  true, lockmode);
11702  table_close(childrel, NoLock);
11703  }
11704 
11705  /* Queue validation for phase 3 */
11706  newcon = (NewConstraint *) palloc0(sizeof(NewConstraint));
11707  newcon->name = constrName;
11708  newcon->contype = CONSTR_CHECK;
11709  newcon->refrelid = InvalidOid;
11710  newcon->refindid = InvalidOid;
11711  newcon->conid = con->oid;
11712 
11713  val = SysCacheGetAttrNotNull(CONSTROID, tuple,
11714  Anum_pg_constraint_conbin);
11715  conbin = TextDatumGetCString(val);
11716  newcon->qual = (Node *) stringToNode(conbin);
11717 
11718  /* Find or create work queue entry for this table */
11719  tab = ATGetQueueEntry(wqueue, rel);
11720  tab->constraints = lappend(tab->constraints, newcon);
11721 
11722  /*
11723  * Invalidate relcache so that others see the new validated
11724  * constraint.
11725  */
11727  }
11728 
11729  /*
11730  * Now update the catalog, while we have the door open.
11731  */
11732  copyTuple = heap_copytuple(tuple);
11733  copy_con = (Form_pg_constraint) GETSTRUCT(copyTuple);
11734  copy_con->convalidated = true;
11735  CatalogTupleUpdate(conrel, &copyTuple->t_self, copyTuple);
11736 
11737  InvokeObjectPostAlterHook(ConstraintRelationId, con->oid, 0);
11738 
11739  heap_freetuple(copyTuple);
11740 
11741  ObjectAddressSet(address, ConstraintRelationId, con->oid);
11742  }
11743  else
11744  address = InvalidObjectAddress; /* already validated */
11745 
11746  systable_endscan(scan);
11747 
11748  table_close(conrel, RowExclusiveLock);
11749 
11750  return address;
11751 }
11752 
11753 
11754 /*
11755  * transformColumnNameList - transform list of column names
11756  *
11757  * Lookup each name and return its attnum and, optionally, type OID
11758  *
11759  * Note: the name of this function suggests that it's general-purpose,
11760  * but actually it's only used to look up names appearing in foreign-key
11761  * clauses. The error messages would need work to use it in other cases,
11762  * and perhaps the validity checks as well.
11763  */
11764 static int
11766  int16 *attnums, Oid *atttypids)
11767 {
11768  ListCell *l;
11769  int attnum;
11770 
11771  attnum = 0;
11772  foreach(l, colList)
11773  {
11774  char *attname = strVal(lfirst(l));
11775  HeapTuple atttuple;
11776  Form_pg_attribute attform;
11777 
11778  atttuple = SearchSysCacheAttName(relId, attname);
11779  if (!HeapTupleIsValid(atttuple))
11780  ereport(ERROR,
11781  (errcode(ERRCODE_UNDEFINED_COLUMN),
11782  errmsg("column \"%s\" referenced in foreign key constraint does not exist",
11783  attname)));
11784  attform = (Form_pg_attribute) GETSTRUCT(atttuple);
11785  if (attform->attnum < 0)
11786  ereport(ERROR,
11787  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
11788  errmsg("system columns cannot be used in foreign keys")));
11789  if (attnum >= INDEX_MAX_KEYS)
11790  ereport(ERROR,
11791  (errcode(ERRCODE_TOO_MANY_COLUMNS),
11792  errmsg("cannot have more than %d keys in a foreign key",
11793  INDEX_MAX_KEYS)));
11794  attnums[attnum] = attform->attnum;
11795  if (atttypids != NULL)
11796  atttypids[attnum] = attform->atttypid;
11797  ReleaseSysCache(atttuple);
11798  attnum++;
11799  }
11800 
11801  return attnum;
11802 }
11803 
11804 /*
11805  * transformFkeyGetPrimaryKey -
11806  *
11807  * Look up the names, attnums, and types of the primary key attributes
11808  * for the pkrel. Also return the index OID and index opclasses of the
11809  * index supporting the primary key.
11810  *
11811  * All parameters except pkrel are output parameters. Also, the function
11812  * return value is the number of attributes in the primary key.
11813  *
11814  * Used when the column list in the REFERENCES specification is omitted.
11815  */
11816 static int
11818  List **attnamelist,
11819  int16 *attnums, Oid *atttypids,
11820  Oid *opclasses)
11821 {
11822  List *indexoidlist;
11823  ListCell *indexoidscan;
11824  HeapTuple indexTuple = NULL;
11825  Form_pg_index indexStruct = NULL;
11826  Datum indclassDatum;
11827  oidvector *indclass;
11828  int i;
11829 
11830  /*
11831  * Get the list of index OIDs for the table from the relcache, and look up
11832  * each one in the pg_index syscache until we find one marked primary key
11833  * (hopefully there isn't more than one such). Insist it's valid, too.
11834  */
11835  *indexOid = InvalidOid;
11836 
11837  indexoidlist = RelationGetIndexList(pkrel);
11838 
11839  foreach(indexoidscan, indexoidlist)
11840  {
11841  Oid indexoid = lfirst_oid(indexoidscan);
11842 
11843  indexTuple = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(indexoid));
11844  if (!HeapTupleIsValid(indexTuple))
11845  elog(ERROR, "cache lookup failed for index %u", indexoid);
11846  indexStruct = (Form_pg_index) GETSTRUCT(indexTuple);
11847  if (indexStruct->indisprimary && indexStruct->indisvalid)
11848  {
11849  /*
11850  * Refuse to use a deferrable primary key. This is per SQL spec,
11851  * and there would be a lot of interesting semantic problems if we
11852  * tried to allow it.
11853  */
11854  if (!indexStruct->indimmediate)
11855  ereport(ERROR,
11856  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
11857  errmsg("cannot use a deferrable primary key for referenced table \"%s\"",
11858  RelationGetRelationName(pkrel))));
11859 
11860  *indexOid = indexoid;
11861  break;
11862  }
11863  ReleaseSysCache(indexTuple);
11864  }
11865 
11866  list_free(indexoidlist);
11867 
11868  /*
11869  * Check that we found it
11870  */
11871  if (!OidIsValid(*indexOid))
11872  ereport(ERROR,
11873  (errcode(ERRCODE_UNDEFINED_OBJECT),
11874  errmsg("there is no primary key for referenced table \"%s\"",
11875  RelationGetRelationName(pkrel))));
11876 
11877  /* Must get indclass the hard way */
11878  indclassDatum = SysCacheGetAttrNotNull(INDEXRELID, indexTuple,
11879  Anum_pg_index_indclass);
11880  indclass = (oidvector *) DatumGetPointer(indclassDatum);
11881 
11882  /*
11883  * Now build the list of PK attributes from the indkey definition (we
11884  * assume a primary key cannot have expressional elements)
11885  */
11886  *attnamelist = NIL;
11887  for (i = 0; i < indexStruct->indnkeyatts; i++)
11888  {
11889  int pkattno = indexStruct->indkey.values[i];
11890 
11891  attnums[i] = pkattno;
11892  atttypids[i] = attnumTypeId(pkrel, pkattno);
11893  opclasses[i] = indclass->values[i];
11894  *attnamelist = lappend(*attnamelist,
11895  makeString(pstrdup(NameStr(*attnumAttName(pkrel, pkattno)))));
11896  }
11897 
11898  ReleaseSysCache(indexTuple);
11899 
11900  return i;
11901 }
11902 
11903 /*
11904  * transformFkeyCheckAttrs -
11905  *
11906  * Validate that the 'attnums' columns in the 'pkrel' relation are valid to
11907  * reference as part of a foreign key constraint.
11908  *
11909  * Returns the OID of the unique index supporting the constraint and
11910  * populates the caller-provided 'opclasses' array with the opclasses
11911  * associated with the index columns.
11912  *
11913  * Raises an ERROR on validation failure.
11914  */
11915 static Oid
11917  int numattrs, int16 *attnums,
11918  Oid *opclasses)
11919 {
11920  Oid indexoid = InvalidOid;
11921  bool found = false;
11922  bool found_deferrable = false;
11923  List *indexoidlist;
11924  ListCell *indexoidscan;
11925  int i,
11926  j;
11927 
11928  /*
11929  * Reject duplicate appearances of columns in the referenced-columns list.
11930  * Such a case is forbidden by the SQL standard, and even if we thought it
11931  * useful to allow it, there would be ambiguity about how to match the
11932  * list to unique indexes (in particular, it'd be unclear which index
11933  * opclass goes with which FK column).
11934  */
11935  for (i = 0; i < numattrs; i++)
11936  {
11937  for (j = i + 1; j < numattrs; j++)
11938  {
11939  if (attnums[i] == attnums[j])
11940  ereport(ERROR,
11941  (errcode(ERRCODE_INVALID_FOREIGN_KEY),
11942  errmsg("foreign key referenced-columns list must not contain duplicates")));
11943  }
11944  }
11945 
11946  /*
11947  * Get the list of index OIDs for the table from the relcache, and look up
11948  * each one in the pg_index syscache, and match unique indexes to the list
11949  * of attnums we are given.
11950  */
11951  indexoidlist = RelationGetIndexList(pkrel);
11952 
11953  foreach(indexoidscan, indexoidlist)
11954  {
11955  HeapTuple indexTuple;
11956  Form_pg_index indexStruct;
11957 
11958  indexoid = lfirst_oid(indexoidscan);
11959  indexTuple = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(indexoid));
11960  if (!HeapTupleIsValid(indexTuple))
11961  elog(ERROR, "cache lookup failed for index %u", indexoid);
11962  indexStruct = (Form_pg_index) GETSTRUCT(indexTuple);
11963 
11964  /*
11965  * Must have the right number of columns; must be unique and not a
11966  * partial index; forget it if there are any expressions, too. Invalid
11967  * indexes are out as well.
11968  */
11969  if (indexStruct->indnkeyatts == numattrs &&
11970  indexStruct->indisunique &&
11971  indexStruct->indisvalid &&
11972  heap_attisnull(indexTuple, Anum_pg_index_indpred, NULL) &&
11973  heap_attisnull(indexTuple, Anum_pg_index_indexprs, NULL))
11974  {
11975  Datum indclassDatum;
11976  oidvector *indclass;
11977 
11978  /* Must get indclass the hard way */
11979  indclassDatum = SysCacheGetAttrNotNull(INDEXRELID, indexTuple,
11980  Anum_pg_index_indclass);
11981  indclass = (oidvector *) DatumGetPointer(indclassDatum);
11982 
11983  /*
11984  * The given attnum list may match the index columns in any order.
11985  * Check for a match, and extract the appropriate opclasses while
11986  * we're at it.
11987  *
11988  * We know that attnums[] is duplicate-free per the test at the
11989  * start of this function, and we checked above that the number of
11990  * index columns agrees, so if we find a match for each attnums[]
11991  * entry then we must have a one-to-one match in some order.
11992  */
11993  for (i = 0; i < numattrs; i++)
11994  {
11995  found = false;
11996  for (j = 0; j < numattrs; j++)
11997  {
11998  if (attnums[i] == indexStruct->indkey.values[j])
11999  {
12000  opclasses[i] = indclass->values[j];
12001  found = true;
12002  break;
12003  }
12004  }
12005  if (!found)
12006  break;
12007  }
12008 
12009  /*
12010  * Refuse to use a deferrable unique/primary key. This is per SQL
12011  * spec, and there would be a lot of interesting semantic problems
12012  * if we tried to allow it.
12013  */
12014  if (found && !indexStruct->indimmediate)
12015  {
12016  /*
12017  * Remember that we found an otherwise matching index, so that
12018  * we can generate a more appropriate error message.
12019  */
12020  found_deferrable = true;
12021  found = false;
12022  }
12023  }
12024  ReleaseSysCache(indexTuple);
12025  if (found)
12026  break;
12027  }
12028 
12029  if (!found)
12030  {
12031  if (found_deferrable)
12032  ereport(ERROR,
12033  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
12034  errmsg("cannot use a deferrable unique constraint for referenced table \"%s\"",
12035  RelationGetRelationName(pkrel))));
12036  else
12037  ereport(ERROR,
12038  (errcode(ERRCODE_INVALID_FOREIGN_KEY),
12039  errmsg("there is no unique constraint matching given keys for referenced table \"%s\"",
12040  RelationGetRelationName(pkrel))));
12041  }
12042 
12043  list_free(indexoidlist);
12044 
12045  return indexoid;
12046 }
12047 
12048 /*
12049  * findFkeyCast -
12050  *
12051  * Wrapper around find_coercion_pathway() for ATAddForeignKeyConstraint().
12052  * Caller has equal regard for binary coercibility and for an exact match.
12053 */
12054 static CoercionPathType
12055 findFkeyCast(Oid targetTypeId, Oid sourceTypeId, Oid *funcid)
12056 {
12057  CoercionPathType ret;
12058 
12059  if (targetTypeId == sourceTypeId)
12060  {
12062  *funcid = InvalidOid;
12063  }
12064  else
12065  {
12066  ret = find_coercion_pathway(targetTypeId, sourceTypeId,
12067  COERCION_IMPLICIT, funcid);
12068  if (ret == COERCION_PATH_NONE)
12069  /* A previously-relied-upon cast is now gone. */
12070  elog(ERROR, "could not find cast from %u to %u",
12071  sourceTypeId, targetTypeId);
12072  }
12073 
12074  return ret;
12075 }
12076 
12077 /*
12078  * Permissions checks on the referenced table for ADD FOREIGN KEY
12079  *
12080  * Note: we have already checked that the user owns the referencing table,
12081  * else we'd have failed much earlier; no additional checks are needed for it.
12082  */
12083 static void
12084 checkFkeyPermissions(Relation rel, int16 *attnums, int natts)
12085 {
12086  Oid roleid = GetUserId();
12087  AclResult aclresult;
12088  int i;
12089 
12090  /* Okay if we have relation-level REFERENCES permission */
12091  aclresult = pg_class_aclcheck(RelationGetRelid(rel), roleid,
12092  ACL_REFERENCES);
12093  if (aclresult == ACLCHECK_OK)
12094  return;
12095  /* Else we must have REFERENCES on each column */
12096  for (i = 0; i < natts; i++)
12097  {
12098  aclresult = pg_attribute_aclcheck(RelationGetRelid(rel), attnums[i],
12099  roleid, ACL_REFERENCES);
12100  if (aclresult != ACLCHECK_OK)
12101  aclcheck_error(aclresult, get_relkind_objtype(rel->rd_rel->relkind),
12103  }
12104 }
12105 
12106 /*
12107  * Scan the existing rows in a table to verify they meet a proposed FK
12108  * constraint.
12109  *
12110  * Caller must have opened and locked both relations appropriately.
12111  */
12112 static void
12114  Relation rel,
12115  Relation pkrel,
12116  Oid pkindOid,
12117  Oid constraintOid)
12118 {
12119  TupleTableSlot *slot;
12120  TableScanDesc scan;
12121  Trigger trig = {0};
12122  Snapshot snapshot;
12123  MemoryContext oldcxt;
12124  MemoryContext perTupCxt;
12125 
12126  ereport(DEBUG1,
12127  (errmsg_internal("validating foreign key constraint \"%s\"", conname)));
12128 
12129  /*
12130  * Build a trigger call structure; we'll need it either way.
12131  */
12132  trig.tgoid = InvalidOid;
12133  trig.tgname = conname;
12135  trig.tgisinternal = true;
12136  trig.tgconstrrelid = RelationGetRelid(pkrel);
12137  trig.tgconstrindid = pkindOid;
12138  trig.tgconstraint = constraintOid;
12139  trig.tgdeferrable = false;
12140  trig.tginitdeferred = false;
12141  /* we needn't fill in remaining fields */
12142 
12143  /*
12144  * See if we can do it with a single LEFT JOIN query. A false result
12145  * indicates we must proceed with the fire-the-trigger method.
12146  */
12147  if (RI_Initial_Check(&trig, rel, pkrel))
12148  return;
12149 
12150  /*
12151  * Scan through each tuple, calling RI_FKey_check_ins (insert trigger) as
12152  * if that tuple had just been inserted. If any of those fail, it should
12153  * ereport(ERROR) and that's that.
12154  */
12155  snapshot = RegisterSnapshot(GetLatestSnapshot());
12156  slot = table_slot_create(rel, NULL);
12157  scan = table_beginscan(rel, snapshot, 0, NULL);
12158 
12160  "validateForeignKeyConstraint",
12162  oldcxt = MemoryContextSwitchTo(perTupCxt);
12163 
12164  while (table_scan_getnextslot(scan, ForwardScanDirection, slot))
12165  {
12166  LOCAL_FCINFO(fcinfo, 0);
12167  TriggerData trigdata = {0};
12168 
12170 
12171  /*
12172  * Make a call to the trigger function
12173  *
12174  * No parameters are passed, but we do set a context
12175  */
12176  MemSet(fcinfo, 0, SizeForFunctionCallInfo(0));
12177 
12178  /*
12179  * We assume RI_FKey_check_ins won't look at flinfo...
12180  */
12181  trigdata.type = T_TriggerData;
12183  trigdata.tg_relation = rel;
12184  trigdata.tg_trigtuple = ExecFetchSlotHeapTuple(slot, false, NULL);
12185  trigdata.tg_trigslot = slot;
12186  trigdata.tg_trigger = &trig;
12187 
12188  fcinfo->context = (Node *) &trigdata;
12189 
12190  RI_FKey_check_ins(fcinfo);
12191 
12192  MemoryContextReset(perTupCxt);
12193  }
12194 
12195  MemoryContextSwitchTo(oldcxt);
12196  MemoryContextDelete(perTupCxt);
12197  table_endscan(scan);
12198  UnregisterSnapshot(snapshot);
12200 }
12201 
12202 /*
12203  * CreateFKCheckTrigger
12204  * Creates the insert (on_insert=true) or update "check" trigger that
12205  * implements a given foreign key
12206  *
12207  * Returns the OID of the so created trigger.
12208  */
12209 static Oid
12210 CreateFKCheckTrigger(Oid myRelOid, Oid refRelOid, Constraint *fkconstraint,
12211  Oid constraintOid, Oid indexOid, Oid parentTrigOid,
12212  bool on_insert)
12213 {
12214  ObjectAddress trigAddress;
12215  CreateTrigStmt *fk_trigger;
12216 
12217  /*
12218  * Note: for a self-referential FK (referencing and referenced tables are
12219  * the same), it is important that the ON UPDATE action fires before the
12220  * CHECK action, since both triggers will fire on the same row during an
12221  * UPDATE event; otherwise the CHECK trigger will be checking a non-final
12222  * state of the row. Triggers fire in name order, so we ensure this by
12223  * using names like "RI_ConstraintTrigger_a_NNNN" for the action triggers
12224  * and "RI_ConstraintTrigger_c_NNNN" for the check triggers.
12225  */
12226  fk_trigger = makeNode(CreateTrigStmt);
12227  fk_trigger->replace = false;
12228  fk_trigger->isconstraint = true;
12229  fk_trigger->trigname = "RI_ConstraintTrigger_c";
12230  fk_trigger->relation = NULL;
12231 
12232  /* Either ON INSERT or ON UPDATE */
12233  if (on_insert)
12234  {
12235  fk_trigger->funcname = SystemFuncName("RI_FKey_check_ins");
12236  fk_trigger->events = TRIGGER_TYPE_INSERT;
12237  }
12238  else
12239  {
12240  fk_trigger->funcname = SystemFuncName("RI_FKey_check_upd");
12241  fk_trigger->events = TRIGGER_TYPE_UPDATE;
12242  }
12243 
12244  fk_trigger->args = NIL;
12245  fk_trigger->row = true;
12246  fk_trigger->timing = TRIGGER_TYPE_AFTER;
12247  fk_trigger->columns = NIL;
12248  fk_trigger->whenClause = NULL;
12249  fk_trigger->transitionRels = NIL;
12250  fk_trigger->deferrable = fkconstraint->deferrable;
12251  fk_trigger->initdeferred = fkconstraint->initdeferred;
12252  fk_trigger->constrrel = NULL;
12253 
12254  trigAddress = CreateTrigger(fk_trigger, NULL, myRelOid, refRelOid,
12255  constraintOid, indexOid, InvalidOid,
12256  parentTrigOid, NULL, true, false);
12257 
12258  /* Make changes-so-far visible */
12260 
12261  return trigAddress.objectId;
12262 }
12263 
12264 /*
12265  * createForeignKeyActionTriggers
12266  * Create the referenced-side "action" triggers that implement a foreign
12267  * key.
12268  *
12269  * Returns the OIDs of the so created triggers in *deleteTrigOid and
12270  * *updateTrigOid.
12271  */
12272 static void
12274  Oid constraintOid, Oid indexOid,
12275  Oid parentDelTrigger, Oid parentUpdTrigger,
12276  Oid *deleteTrigOid, Oid *updateTrigOid)
12277 {
12278  CreateTrigStmt *fk_trigger;
12279  ObjectAddress trigAddress;
12280 
12281  /*
12282  * Build and execute a CREATE CONSTRAINT TRIGGER statement for the ON
12283  * DELETE action on the referenced table.
12284  */
12285  fk_trigger = makeNode(CreateTrigStmt);
12286  fk_trigger->replace = false;
12287  fk_trigger->isconstraint = true;
12288  fk_trigger->trigname = "RI_ConstraintTrigger_a";
12289  fk_trigger->relation = NULL;
12290  fk_trigger->args = NIL;
12291  fk_trigger->row = true;
12292  fk_trigger->timing = TRIGGER_TYPE_AFTER;
12293  fk_trigger->events = TRIGGER_TYPE_DELETE;
12294  fk_trigger->columns = NIL;
12295  fk_trigger->whenClause = NULL;
12296  fk_trigger->transitionRels = NIL;
12297  fk_trigger->constrrel = NULL;
12298  switch (fkconstraint->fk_del_action)
12299  {
12301  fk_trigger->deferrable = fkconstraint->deferrable;
12302  fk_trigger->initdeferred = fkconstraint->initdeferred;
12303  fk_trigger->funcname = SystemFuncName("RI_FKey_noaction_del");
12304  break;
12306  fk_trigger->deferrable = false;
12307  fk_trigger->initdeferred = false;
12308  fk_trigger->funcname = SystemFuncName("RI_FKey_restrict_del");
12309  break;
12311  fk_trigger->deferrable = false;
12312  fk_trigger->initdeferred = false;
12313  fk_trigger->funcname = SystemFuncName("RI_FKey_cascade_del");
12314  break;
12316  fk_trigger->deferrable = false;
12317  fk_trigger->initdeferred = false;
12318  fk_trigger->funcname = SystemFuncName("RI_FKey_setnull_del");
12319  break;
12321  fk_trigger->deferrable = false;
12322  fk_trigger->initdeferred = false;
12323  fk_trigger->funcname = SystemFuncName("RI_FKey_setdefault_del");
12324  break;
12325  default:
12326  elog(ERROR, "unrecognized FK action type: %d",
12327  (int) fkconstraint->fk_del_action);
12328  break;
12329  }
12330 
12331  trigAddress = CreateTrigger(fk_trigger, NULL, refRelOid,
12332  RelationGetRelid(rel),
12333  constraintOid, indexOid, InvalidOid,
12334  parentDelTrigger, NULL, true, false);
12335  if (deleteTrigOid)
12336  *deleteTrigOid = trigAddress.objectId;
12337 
12338  /* Make changes-so-far visible */
12340 
12341  /*
12342  * Build and execute a CREATE CONSTRAINT TRIGGER statement for the ON
12343  * UPDATE action on the referenced table.
12344  */
12345  fk_trigger = makeNode(CreateTrigStmt);
12346  fk_trigger->replace = false;
12347  fk_trigger->isconstraint = true;
12348  fk_trigger->trigname = "RI_ConstraintTrigger_a";
12349  fk_trigger->relation = NULL;
12350  fk_trigger->args = NIL;
12351  fk_trigger->row = true;
12352  fk_trigger->timing = TRIGGER_TYPE_AFTER;
12353  fk_trigger->events = TRIGGER_TYPE_UPDATE;
12354  fk_trigger->columns = NIL;
12355  fk_trigger->whenClause = NULL;
12356  fk_trigger->transitionRels = NIL;
12357  fk_trigger->constrrel = NULL;
12358  switch (fkconstraint->fk_upd_action)
12359  {
12361  fk_trigger->deferrable = fkconstraint->deferrable;
12362  fk_trigger->initdeferred = fkconstraint->initdeferred;
12363  fk_trigger->funcname = SystemFuncName("RI_FKey_noaction_upd");
12364  break;
12366  fk_trigger->deferrable = false;
12367  fk_trigger->initdeferred = false;
12368  fk_trigger->funcname = SystemFuncName("RI_FKey_restrict_upd");
12369  break;
12371  fk_trigger->deferrable = false;
12372  fk_trigger->initdeferred = false;
12373  fk_trigger->funcname = SystemFuncName("RI_FKey_cascade_upd");
12374  break;
12376  fk_trigger->deferrable = false;
12377  fk_trigger->initdeferred = false;
12378  fk_trigger->funcname = SystemFuncName("RI_FKey_setnull_upd");
12379  break;
12381  fk_trigger->deferrable = false;
12382  fk_trigger->initdeferred = false;
12383  fk_trigger->funcname = SystemFuncName("RI_FKey_setdefault_upd");
12384  break;
12385  default:
12386  elog(ERROR, "unrecognized FK action type: %d",
12387  (int) fkconstraint->fk_upd_action);
12388  break;
12389  }
12390 
12391  trigAddress = CreateTrigger(fk_trigger, NULL, refRelOid,
12392  RelationGetRelid(rel),
12393  constraintOid, indexOid, InvalidOid,
12394  parentUpdTrigger, NULL, true, false);
12395  if (updateTrigOid)
12396  *updateTrigOid = trigAddress.objectId;
12397 }
12398 
12399 /*
12400  * createForeignKeyCheckTriggers
12401  * Create the referencing-side "check" triggers that implement a foreign
12402  * key.
12403  *
12404  * Returns the OIDs of the so created triggers in *insertTrigOid and
12405  * *updateTrigOid.
12406  */
12407 static void
12409  Constraint *fkconstraint, Oid constraintOid,
12410  Oid indexOid,
12411  Oid parentInsTrigger, Oid parentUpdTrigger,
12412  Oid *insertTrigOid, Oid *updateTrigOid)
12413 {
12414  *insertTrigOid = CreateFKCheckTrigger(myRelOid, refRelOid, fkconstraint,
12415  constraintOid, indexOid,
12416  parentInsTrigger, true);
12417  *updateTrigOid = CreateFKCheckTrigger(myRelOid, refRelOid, fkconstraint,
12418  constraintOid, indexOid,
12419  parentUpdTrigger, false);
12420 }
12421 
12422 /*
12423  * ALTER TABLE DROP CONSTRAINT
12424  *
12425  * Like DROP COLUMN, we can't use the normal ALTER TABLE recursion mechanism.
12426  */
12427 static void
12428 ATExecDropConstraint(Relation rel, const char *constrName,
12429  DropBehavior behavior,
12430  bool recurse, bool recursing,
12431  bool missing_ok, LOCKMODE lockmode)
12432 {
12433  List *children;
12434  Relation conrel;
12435  Form_pg_constraint con;
12436  SysScanDesc scan;
12437  ScanKeyData skey[3];
12438  HeapTuple tuple;
12439  bool found = false;
12440  bool is_no_inherit_constraint = false;
12441  char contype;
12442 
12443  /* At top level, permission check was done in ATPrepCmd, else do it */
12444  if (recursing)
12446 
12447  conrel = table_open(ConstraintRelationId, RowExclusiveLock);
12448 
12449  /*
12450  * Find and drop the target constraint
12451  */
12452  ScanKeyInit(&skey[0],
12453  Anum_pg_constraint_conrelid,
12454  BTEqualStrategyNumber, F_OIDEQ,
12456  ScanKeyInit(&skey[1],
12457  Anum_pg_constraint_contypid,
12458  BTEqualStrategyNumber, F_OIDEQ,
12460  ScanKeyInit(&skey[2],
12461  Anum_pg_constraint_conname,
12462  BTEqualStrategyNumber, F_NAMEEQ,
12463  CStringGetDatum(constrName));
12464  scan = systable_beginscan(conrel, ConstraintRelidTypidNameIndexId,
12465  true, NULL, 3, skey);
12466 
12467  /* There can be at most one matching row */
12468  if (HeapTupleIsValid(tuple = systable_getnext(scan)))
12469  {
12470  ObjectAddress conobj;
12471 
12472  con = (Form_pg_constraint) GETSTRUCT(tuple);
12473 
12474  /* Don't drop inherited constraints */
12475  if (con->coninhcount > 0 && !recursing)
12476  ereport(ERROR,
12477  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
12478  errmsg("cannot drop inherited constraint \"%s\" of relation \"%s\"",
12479  constrName, RelationGetRelationName(rel))));
12480 
12481  is_no_inherit_constraint = con->connoinherit;
12482  contype = con->contype;
12483 
12484  /*
12485  * If it's a foreign-key constraint, we'd better lock the referenced
12486  * table and check that that's not in use, just as we've already done
12487  * for the constrained table (else we might, eg, be dropping a trigger
12488  * that has unfired events). But we can/must skip that in the
12489  * self-referential case.
12490  */
12491  if (contype == CONSTRAINT_FOREIGN &&
12492  con->confrelid != RelationGetRelid(rel))
12493  {
12494  Relation frel;
12495 
12496  /* Must match lock taken by RemoveTriggerById: */
12497  frel = table_open(con->confrelid, AccessExclusiveLock);
12498  CheckAlterTableIsSafe(frel);
12499  table_close(frel, NoLock);
12500  }
12501 
12502  /*
12503  * Perform the actual constraint deletion
12504  */
12505  conobj.classId = ConstraintRelationId;
12506  conobj.objectId = con->oid;
12507  conobj.objectSubId = 0;
12508 
12509  performDeletion(&conobj, behavior, 0);
12510 
12511  found = true;
12512  }
12513 
12514  systable_endscan(scan);
12515 
12516  if (!found)
12517  {
12518  if (!missing_ok)
12519  {
12520  ereport(ERROR,
12521  (errcode(ERRCODE_UNDEFINED_OBJECT),
12522  errmsg("constraint \"%s\" of relation \"%s\" does not exist",
12523  constrName, RelationGetRelationName(rel))));
12524  }
12525  else
12526  {
12527  ereport(NOTICE,
12528  (errmsg("constraint \"%s\" of relation \"%s\" does not exist, skipping",
12529  constrName, RelationGetRelationName(rel))));
12530  table_close(conrel, RowExclusiveLock);
12531  return;
12532  }
12533  }
12534 
12535  /*
12536  * For partitioned tables, non-CHECK inherited constraints are dropped via
12537  * the dependency mechanism, so we're done here.
12538  */
12539  if (contype != CONSTRAINT_CHECK &&
12540  rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
12541  {
12542  table_close(conrel, RowExclusiveLock);
12543  return;
12544  }
12545 
12546  /*
12547  * Propagate to children as appropriate. Unlike most other ALTER
12548  * routines, we have to do this one level of recursion at a time; we can't
12549  * use find_all_inheritors to do it in one pass.
12550  */
12551  if (!is_no_inherit_constraint)
12552  children = find_inheritance_children(RelationGetRelid(rel), lockmode);
12553  else
12554  children = NIL;
12555 
12556  /*
12557  * For a partitioned table, if partitions exist and we are told not to
12558  * recurse, it's a user error. It doesn't make sense to have a constraint
12559  * be defined only on the parent, especially if it's a partitioned table.
12560  */
12561  if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE &&
12562  children != NIL && !recurse)
12563  ereport(ERROR,
12564  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
12565  errmsg("cannot remove constraint from only the partitioned table when partitions exist"),
12566  errhint("Do not specify the ONLY keyword.")));
12567 
12568  foreach_oid(childrelid, children)
12569  {
12570  Relation childrel;
12571  HeapTuple copy_tuple;
12572 
12573  /* find_inheritance_children already got lock */
12574  childrel = table_open(childrelid, NoLock);
12575  CheckAlterTableIsSafe(childrel);
12576 
12577  ScanKeyInit(&skey[0],
12578  Anum_pg_constraint_conrelid,
12579  BTEqualStrategyNumber, F_OIDEQ,
12580  ObjectIdGetDatum(childrelid));
12581  ScanKeyInit(&skey[1],
12582  Anum_pg_constraint_contypid,
12583  BTEqualStrategyNumber, F_OIDEQ,
12585  ScanKeyInit(&skey[2],
12586  Anum_pg_constraint_conname,
12587  BTEqualStrategyNumber, F_NAMEEQ,
12588  CStringGetDatum(constrName));
12589  scan = systable_beginscan(conrel, ConstraintRelidTypidNameIndexId,
12590  true, NULL, 3, skey);
12591 
12592  /* There can be at most one matching row */
12593  if (!HeapTupleIsValid(tuple = systable_getnext(scan)))
12594  ereport(ERROR,
12595  (errcode(ERRCODE_UNDEFINED_OBJECT),
12596  errmsg("constraint \"%s\" of relation \"%s\" does not exist",
12597  constrName,
12598  RelationGetRelationName(childrel))));
12599 
12600  copy_tuple = heap_copytuple(tuple);
12601 
12602  systable_endscan(scan);
12603 
12604  con = (Form_pg_constraint) GETSTRUCT(copy_tuple);
12605 
12606  /* Right now only CHECK constraints can be inherited */
12607  if (con->contype != CONSTRAINT_CHECK)
12608  elog(ERROR, "inherited constraint is not a CHECK constraint");
12609 
12610  if (con->coninhcount <= 0) /* shouldn't happen */
12611  elog(ERROR, "relation %u has non-inherited constraint \"%s\"",
12612  childrelid, constrName);
12613 
12614  if (recurse)
12615  {
12616  /*
12617  * If the child constraint has other definition sources, just
12618  * decrement its inheritance count; if not, recurse to delete it.
12619  */
12620  if (con->coninhcount == 1 && !con->conislocal)
12621  {
12622  /* Time to delete this child constraint, too */
12623  ATExecDropConstraint(childrel, constrName, behavior,
12624  true, true,
12625  false, lockmode);
12626  }
12627  else
12628  {
12629  /* Child constraint must survive my deletion */
12630  con->coninhcount--;
12631  CatalogTupleUpdate(conrel, &copy_tuple->t_self, copy_tuple);
12632 
12633  /* Make update visible */
12635  }
12636  }
12637  else
12638  {
12639  /*
12640  * If we were told to drop ONLY in this table (no recursion), we
12641  * need to mark the inheritors' constraints as locally defined
12642  * rather than inherited.
12643  */
12644  con->coninhcount--;
12645  con->conislocal = true;
12646 
12647  CatalogTupleUpdate(conrel, &copy_tuple->t_self, copy_tuple);
12648 
12649  /* Make update visible */
12651  }
12652 
12653  heap_freetuple(copy_tuple);
12654 
12655  table_close(childrel, NoLock);
12656  }
12657 
12658  table_close(conrel, RowExclusiveLock);
12659 }
12660 
12661 /*
12662  * ALTER COLUMN TYPE
12663  *
12664  * Unlike other subcommand types, we do parse transformation for ALTER COLUMN
12665  * TYPE during phase 1 --- the AlterTableCmd passed in here is already
12666  * transformed (and must be, because we rely on some transformed fields).
12667  *
12668  * The point of this is that the execution of all ALTER COLUMN TYPEs for a
12669  * table will be done "in parallel" during phase 3, so all the USING
12670  * expressions should be parsed assuming the original column types. Also,
12671  * this allows a USING expression to refer to a field that will be dropped.
12672  *
12673  * To make this work safely, AT_PASS_DROP then AT_PASS_ALTER_TYPE must be
12674  * the first two execution steps in phase 2; they must not see the effects
12675  * of any other subcommand types, since the USING expressions are parsed
12676  * against the unmodified table's state.
12677  */
12678 static void
12680  AlteredTableInfo *tab, Relation rel,
12681  bool recurse, bool recursing,
12682  AlterTableCmd *cmd, LOCKMODE lockmode,
12684 {
12685  char *colName = cmd->name;
12686  ColumnDef *def = (ColumnDef *) cmd->def;
12687  TypeName *typeName = def->typeName;
12688  Node *transform = def->cooked_default;
12689  HeapTuple tuple;
12690  Form_pg_attribute attTup;
12692  Oid targettype;
12693  int32 targettypmod;
12694  Oid targetcollid;
12696  ParseState *pstate = make_parsestate(NULL);
12697  AclResult aclresult;
12698  bool is_expr;
12699 
12700  if (rel->rd_rel->reloftype && !recursing)
12701  ereport(ERROR,
12702  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
12703  errmsg("cannot alter column type of typed table")));
12704 
12705  /* lookup the attribute so we can check inheritance status */
12706  tuple = SearchSysCacheAttName(RelationGetRelid(rel), colName);
12707  if (!HeapTupleIsValid(tuple))
12708  ereport(ERROR,
12709  (errcode(ERRCODE_UNDEFINED_COLUMN),
12710  errmsg("column \"%s\" of relation \"%s\" does not exist",
12711  colName, RelationGetRelationName(rel))));
12712  attTup = (Form_pg_attribute) GETSTRUCT(tuple);
12713  attnum = attTup->attnum;
12714 
12715  /* Can't alter a system attribute */
12716  if (attnum <= 0)
12717  ereport(ERROR,
12718  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
12719  errmsg("cannot alter system column \"%s\"",
12720  colName)));
12721 
12722  /*
12723  * Don't alter inherited columns. At outer level, there had better not be
12724  * any inherited definition; when recursing, we assume this was checked at
12725  * the parent level (see below).
12726  */
12727  if (attTup->attinhcount > 0 && !recursing)
12728  ereport(ERROR,
12729  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
12730  errmsg("cannot alter inherited column \"%s\"",
12731  colName)));
12732 
12733  /* Don't alter columns used in the partition key */
12734  if (has_partition_attrs(rel,
12736  &is_expr))
12737  ereport(ERROR,
12738  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
12739  errmsg("cannot alter column \"%s\" because it is part of the partition key of relation \"%s\"",
12740  colName, RelationGetRelationName(rel))));
12741 
12742  /* Look up the target type */
12743  typenameTypeIdAndMod(NULL, typeName, &targettype, &targettypmod);
12744 
12745  aclresult = object_aclcheck(TypeRelationId, targettype, GetUserId(), ACL_USAGE);
12746  if (aclresult != ACLCHECK_OK)
12747  aclcheck_error_type(aclresult, targettype);
12748 
12749  /* And the collation */
12750  targetcollid = GetColumnDefCollation(NULL, def, targettype);
12751 
12752  /* make sure datatype is legal for a column */
12753  CheckAttributeType(colName, targettype, targetcollid,
12754  list_make1_oid(rel->rd_rel->reltype),
12755  0);
12756 
12757  if (tab->relkind == RELKIND_RELATION ||
12758  tab->relkind == RELKIND_PARTITIONED_TABLE)
12759  {
12760  /*
12761  * Set up an expression to transform the old data value to the new
12762  * type. If a USING option was given, use the expression as
12763  * transformed by transformAlterTableStmt, else just take the old
12764  * value and try to coerce it. We do this first so that type
12765  * incompatibility can be detected before we waste effort, and because
12766  * we need the expression to be parsed against the original table row
12767  * type.
12768  */
12769  if (!transform)
12770  {
12771  transform = (Node *) makeVar(1, attnum,
12772  attTup->atttypid, attTup->atttypmod,
12773  attTup->attcollation,
12774  0);
12775  }
12776 
12777  transform = coerce_to_target_type(pstate,
12778  transform, exprType(transform),
12779  targettype, targettypmod,
12782  -1);
12783  if (transform == NULL)
12784  {
12785  /* error text depends on whether USING was specified or not */
12786  if (def->cooked_default != NULL)
12787  ereport(ERROR,
12788  (errcode(ERRCODE_DATATYPE_MISMATCH),
12789  errmsg("result of USING clause for column \"%s\""
12790  " cannot be cast automatically to type %s",
12791  colName, format_type_be(targettype)),
12792  errhint("You might need to add an explicit cast.")));
12793  else
12794  ereport(ERROR,
12795  (errcode(ERRCODE_DATATYPE_MISMATCH),
12796  errmsg("column \"%s\" cannot be cast automatically to type %s",
12797  colName, format_type_be(targettype)),
12798  /* translator: USING is SQL, don't translate it */
12799  errhint("You might need to specify \"USING %s::%s\".",
12800  quote_identifier(colName),
12801  format_type_with_typemod(targettype,
12802  targettypmod))));
12803  }
12804 
12805  /* Fix collations after all else */
12806  assign_expr_collations(pstate, transform);
12807 
12808  /* Plan the expr now so we can accurately assess the need to rewrite. */
12809  transform = (Node *) expression_planner((Expr *) transform);
12810 
12811  /*
12812  * Add a work queue item to make ATRewriteTable update the column
12813  * contents.
12814  */
12816  newval->attnum = attnum;
12817  newval->expr = (Expr *) transform;
12818  newval->is_generated = false;
12819 
12820  tab->newvals = lappend(tab->newvals, newval);
12821  if (ATColumnChangeRequiresRewrite(transform, attnum))
12823  }
12824  else if (transform)
12825  ereport(ERROR,
12826  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
12827  errmsg("\"%s\" is not a table",
12828  RelationGetRelationName(rel))));
12829 
12830  if (!RELKIND_HAS_STORAGE(tab->relkind))
12831  {
12832  /*
12833  * For relations without storage, do this check now. Regular tables
12834  * will check it later when the table is being rewritten.
12835  */
12836  find_composite_type_dependencies(rel->rd_rel->reltype, rel, NULL);
12837  }
12838 
12839  ReleaseSysCache(tuple);
12840 
12841  /*
12842  * Recurse manually by queueing a new command for each child, if
12843  * necessary. We cannot apply ATSimpleRecursion here because we need to
12844  * remap attribute numbers in the USING expression, if any.
12845  *
12846  * If we are told not to recurse, there had better not be any child
12847  * tables; else the alter would put them out of step.
12848  */
12849  if (recurse)
12850  {
12851  Oid relid = RelationGetRelid(rel);
12852  List *child_oids,
12853  *child_numparents;
12854  ListCell *lo,
12855  *li;
12856 
12857  child_oids = find_all_inheritors(relid, lockmode,
12858  &child_numparents);
12859 
12860  /*
12861  * find_all_inheritors does the recursive search of the inheritance
12862  * hierarchy, so all we have to do is process all of the relids in the
12863  * list that it returns.
12864  */
12865  forboth(lo, child_oids, li, child_numparents)
12866  {
12867  Oid childrelid = lfirst_oid(lo);
12868  int numparents = lfirst_int(li);
12869  Relation childrel;
12870  HeapTuple childtuple;
12871  Form_pg_attribute childattTup;
12872 
12873  if (childrelid == relid)
12874  continue;
12875 
12876  /* find_all_inheritors already got lock */
12877  childrel = relation_open(childrelid, NoLock);
12878  CheckAlterTableIsSafe(childrel);
12879 
12880  /*
12881  * Verify that the child doesn't have any inherited definitions of
12882  * this column that came from outside this inheritance hierarchy.
12883  * (renameatt makes a similar test, though in a different way
12884  * because of its different recursion mechanism.)
12885  */
12886  childtuple = SearchSysCacheAttName(RelationGetRelid(childrel),
12887  colName);
12888  if (!HeapTupleIsValid(childtuple))
12889  ereport(ERROR,
12890  (errcode(ERRCODE_UNDEFINED_COLUMN),
12891  errmsg("column \"%s\" of relation \"%s\" does not exist",
12892  colName, RelationGetRelationName(childrel))));
12893  childattTup = (Form_pg_attribute) GETSTRUCT(childtuple);
12894 
12895  if (childattTup->attinhcount > numparents)
12896  ereport(ERROR,
12897  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
12898  errmsg("cannot alter inherited column \"%s\" of relation \"%s\"",
12899  colName, RelationGetRelationName(childrel))));
12900 
12901  ReleaseSysCache(childtuple);
12902 
12903  /*
12904  * Remap the attribute numbers. If no USING expression was
12905  * specified, there is no need for this step.
12906  */
12907  if (def->cooked_default)
12908  {
12909  AttrMap *attmap;
12910  bool found_whole_row;
12911 
12912  /* create a copy to scribble on */
12913  cmd = copyObject(cmd);
12914 
12915  attmap = build_attrmap_by_name(RelationGetDescr(childrel),
12916  RelationGetDescr(rel),
12917  false);
12918  ((ColumnDef *) cmd->def)->cooked_default =
12920  1, 0,
12921  attmap,
12922  InvalidOid, &found_whole_row);
12923  if (found_whole_row)
12924  ereport(ERROR,
12925  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
12926  errmsg("cannot convert whole-row table reference"),
12927  errdetail("USING expression contains a whole-row table reference.")));
12928  pfree(attmap);
12929  }
12930  ATPrepCmd(wqueue, childrel, cmd, false, true, lockmode, context);
12931  relation_close(childrel, NoLock);
12932  }
12933  }
12934  else if (!recursing &&
12936  ereport(ERROR,
12937  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
12938  errmsg("type of inherited column \"%s\" must be changed in child tables too",
12939  colName)));
12940 
12941  if (tab->relkind == RELKIND_COMPOSITE_TYPE)
12942  ATTypedTableRecursion(wqueue, rel, cmd, lockmode, context);
12943 }
12944 
12945 /*
12946  * When the data type of a column is changed, a rewrite might not be required
12947  * if the new type is sufficiently identical to the old one, and the USING
12948  * clause isn't trying to insert some other value. It's safe to skip the
12949  * rewrite in these cases:
12950  *
12951  * - the old type is binary coercible to the new type
12952  * - the new type is an unconstrained domain over the old type
12953  * - {NEW,OLD} or {OLD,NEW} is {timestamptz,timestamp} and the timezone is UTC
12954  *
12955  * In the case of a constrained domain, we could get by with scanning the
12956  * table and checking the constraint rather than actually rewriting it, but we
12957  * don't currently try to do that.
12958  */
12959 static bool
12961 {
12962  Assert(expr != NULL);
12963 
12964  for (;;)
12965  {
12966  /* only one varno, so no need to check that */
12967  if (IsA(expr, Var) && ((Var *) expr)->varattno == varattno)
12968  return false;
12969  else if (IsA(expr, RelabelType))
12970  expr = (Node *) ((RelabelType *) expr)->arg;
12971  else if (IsA(expr, CoerceToDomain))
12972  {
12973  CoerceToDomain *d = (CoerceToDomain *) expr;
12974 
12976  return true;
12977  expr = (Node *) d->arg;
12978  }
12979  else if (IsA(expr, FuncExpr))
12980  {
12981  FuncExpr *f = (FuncExpr *) expr;
12982 
12983  switch (f->funcid)
12984  {
12985  case F_TIMESTAMPTZ_TIMESTAMP:
12986  case F_TIMESTAMP_TIMESTAMPTZ:
12988  return true;
12989  else
12990  expr = linitial(f->args);
12991  break;
12992  default:
12993  return true;
12994  }
12995  }
12996  else
12997  return true;
12998  }
12999 }
13000 
13001 /*
13002  * ALTER COLUMN .. SET DATA TYPE
13003  *
13004  * Return the address of the modified column.
13005  */
13006 static ObjectAddress
13008  AlterTableCmd *cmd, LOCKMODE lockmode)
13009 {
13010  char *colName = cmd->name;
13011  ColumnDef *def = (ColumnDef *) cmd->def;
13012  TypeName *typeName = def->typeName;
13013  HeapTuple heapTup;
13014  Form_pg_attribute attTup,
13015  attOldTup;
13017  HeapTuple typeTuple;
13018  Form_pg_type tform;
13019  Oid targettype;
13020  int32 targettypmod;
13021  Oid targetcollid;
13022  Node *defaultexpr;
13023  Relation attrelation;
13024  Relation depRel;
13025  ScanKeyData key[3];
13026  SysScanDesc scan;
13027  HeapTuple depTup;
13028  ObjectAddress address;
13029 
13030  /*
13031  * Clear all the missing values if we're rewriting the table, since this
13032  * renders them pointless.
13033  */
13034  if (tab->rewrite)
13035  {
13036  Relation newrel;
13037 
13038  newrel = table_open(RelationGetRelid(rel), NoLock);
13039  RelationClearMissing(newrel);
13040  relation_close(newrel, NoLock);
13041  /* make sure we don't conflict with later attribute modifications */
13043  }
13044 
13045  attrelation = table_open(AttributeRelationId, RowExclusiveLock);
13046 
13047  /* Look up the target column */
13048  heapTup = SearchSysCacheCopyAttName(RelationGetRelid(rel), colName);
13049  if (!HeapTupleIsValid(heapTup)) /* shouldn't happen */
13050  ereport(ERROR,
13051  (errcode(ERRCODE_UNDEFINED_COLUMN),
13052  errmsg("column \"%s\" of relation \"%s\" does not exist",
13053  colName, RelationGetRelationName(rel))));
13054  attTup = (Form_pg_attribute) GETSTRUCT(heapTup);
13055  attnum = attTup->attnum;
13056  attOldTup = TupleDescAttr(tab->oldDesc, attnum - 1);
13057 
13058  /* Check for multiple ALTER TYPE on same column --- can't cope */
13059  if (attTup->atttypid != attOldTup->atttypid ||
13060  attTup->atttypmod != attOldTup->atttypmod)
13061  ereport(ERROR,
13062  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
13063  errmsg("cannot alter type of column \"%s\" twice",
13064  colName)));
13065 
13066  /* Look up the target type (should not fail, since prep found it) */
13067  typeTuple = typenameType(NULL, typeName, &targettypmod);
13068  tform = (Form_pg_type) GETSTRUCT(typeTuple);
13069  targettype = tform->oid;
13070  /* And the collation */
13071  targetcollid = GetColumnDefCollation(NULL, def, targettype);
13072 
13073  /*
13074  * If there is a default expression for the column, get it and ensure we
13075  * can coerce it to the new datatype. (We must do this before changing
13076  * the column type, because build_column_default itself will try to
13077  * coerce, and will not issue the error message we want if it fails.)
13078  *
13079  * We remove any implicit coercion steps at the top level of the old
13080  * default expression; this has been agreed to satisfy the principle of
13081  * least surprise. (The conversion to the new column type should act like
13082  * it started from what the user sees as the stored expression, and the
13083  * implicit coercions aren't going to be shown.)
13084  */
13085  if (attTup->atthasdef)
13086  {
13087  defaultexpr = build_column_default(rel, attnum);
13088  Assert(defaultexpr);
13089  defaultexpr = strip_implicit_coercions(defaultexpr);
13090  defaultexpr = coerce_to_target_type(NULL, /* no UNKNOWN params */
13091  defaultexpr, exprType(defaultexpr),
13092  targettype, targettypmod,
13095  -1);
13096  if (defaultexpr == NULL)
13097  {
13098  if (attTup->attgenerated)
13099  ereport(ERROR,
13100  (errcode(ERRCODE_DATATYPE_MISMATCH),
13101  errmsg("generation expression for column \"%s\" cannot be cast automatically to type %s",
13102  colName, format_type_be(targettype))));
13103  else
13104  ereport(ERROR,
13105  (errcode(ERRCODE_DATATYPE_MISMATCH),
13106  errmsg("default for column \"%s\" cannot be cast automatically to type %s",
13107  colName, format_type_be(targettype))));
13108  }
13109  }
13110  else
13111  defaultexpr = NULL;
13112 
13113  /*
13114  * Find everything that depends on the column (constraints, indexes, etc),
13115  * and record enough information to let us recreate the objects.
13116  *
13117  * The actual recreation does not happen here, but only after we have
13118  * performed all the individual ALTER TYPE operations. We have to save
13119  * the info before executing ALTER TYPE, though, else the deparser will
13120  * get confused.
13121  */
13123 
13124  /*
13125  * Now scan for dependencies of this column on other things. The only
13126  * things we should find are the dependency on the column datatype and
13127  * possibly a collation dependency. Those can be removed.
13128  */
13129  depRel = table_open(DependRelationId, RowExclusiveLock);
13130 
13131  ScanKeyInit(&key[0],
13132  Anum_pg_depend_classid,
13133  BTEqualStrategyNumber, F_OIDEQ,
13134  ObjectIdGetDatum(RelationRelationId));
13135  ScanKeyInit(&key[1],
13136  Anum_pg_depend_objid,
13137  BTEqualStrategyNumber, F_OIDEQ,
13139  ScanKeyInit(&key[2],
13140  Anum_pg_depend_objsubid,
13141  BTEqualStrategyNumber, F_INT4EQ,
13143 
13144  scan = systable_beginscan(depRel, DependDependerIndexId, true,
13145  NULL, 3, key);
13146 
13147  while (HeapTupleIsValid(depTup = systable_getnext(scan)))
13148  {
13149  Form_pg_depend foundDep = (Form_pg_depend) GETSTRUCT(depTup);
13150  ObjectAddress foundObject;
13151 
13152  foundObject.classId = foundDep->refclassid;
13153  foundObject.objectId = foundDep->refobjid;
13154  foundObject.objectSubId = foundDep->refobjsubid;
13155 
13156  if (foundDep->deptype != DEPENDENCY_NORMAL)
13157  elog(ERROR, "found unexpected dependency type '%c'",
13158  foundDep->deptype);
13159  if (!(foundDep->refclassid == TypeRelationId &&
13160  foundDep->refobjid == attTup->atttypid) &&
13161  !(foundDep->refclassid == CollationRelationId &&
13162  foundDep->refobjid == attTup->attcollation))
13163  elog(ERROR, "found unexpected dependency for column: %s",
13164  getObjectDescription(&foundObject, false));
13165 
13166  CatalogTupleDelete(depRel, &depTup->t_self);
13167  }
13168 
13169  systable_endscan(scan);
13170 
13171  table_close(depRel, RowExclusiveLock);
13172 
13173  /*
13174  * Here we go --- change the recorded column type and collation. (Note
13175  * heapTup is a copy of the syscache entry, so okay to scribble on.) First
13176  * fix up the missing value if any.
13177  */
13178  if (attTup->atthasmissing)
13179  {
13180  Datum missingval;
13181  bool missingNull;
13182 
13183  /* if rewrite is true the missing value should already be cleared */
13184  Assert(tab->rewrite == 0);
13185 
13186  /* Get the missing value datum */
13187  missingval = heap_getattr(heapTup,
13188  Anum_pg_attribute_attmissingval,
13189  attrelation->rd_att,
13190  &missingNull);
13191 
13192  /* if it's a null array there is nothing to do */
13193 
13194  if (!missingNull)
13195  {
13196  /*
13197  * Get the datum out of the array and repack it in a new array
13198  * built with the new type data. We assume that since the table
13199  * doesn't need rewriting, the actual Datum doesn't need to be
13200  * changed, only the array metadata.
13201  */
13202 
13203  int one = 1;
13204  bool isNull;
13205  Datum valuesAtt[Natts_pg_attribute] = {0};
13206  bool nullsAtt[Natts_pg_attribute] = {0};
13207  bool replacesAtt[Natts_pg_attribute] = {0};
13208  HeapTuple newTup;
13209 
13210  missingval = array_get_element(missingval,
13211  1,
13212  &one,
13213  0,
13214  attTup->attlen,
13215  attTup->attbyval,
13216  attTup->attalign,
13217  &isNull);
13218  missingval = PointerGetDatum(construct_array(&missingval,
13219  1,
13220  targettype,
13221  tform->typlen,
13222  tform->typbyval,
13223  tform->typalign));
13224 
13225  valuesAtt[Anum_pg_attribute_attmissingval - 1] = missingval;
13226  replacesAtt[Anum_pg_attribute_attmissingval - 1] = true;
13227  nullsAtt[Anum_pg_attribute_attmissingval - 1] = false;
13228 
13229  newTup = heap_modify_tuple(heapTup, RelationGetDescr(attrelation),
13230  valuesAtt, nullsAtt, replacesAtt);
13231  heap_freetuple(heapTup);
13232  heapTup = newTup;
13233  attTup = (Form_pg_attribute) GETSTRUCT(heapTup);
13234  }
13235  }
13236 
13237  attTup->atttypid = targettype;
13238  attTup->atttypmod = targettypmod;
13239  attTup->attcollation = targetcollid;
13240  if (list_length(typeName->arrayBounds) > PG_INT16_MAX)
13241  ereport(ERROR,
13242  errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
13243  errmsg("too many array dimensions"));
13244  attTup->attndims = list_length(typeName->arrayBounds);
13245  attTup->attlen = tform->typlen;
13246  attTup->attbyval = tform->typbyval;
13247  attTup->attalign = tform->typalign;
13248  attTup->attstorage = tform->typstorage;
13249  attTup->attcompression = InvalidCompressionMethod;
13250 
13251  ReleaseSysCache(typeTuple);
13252 
13253  CatalogTupleUpdate(attrelation, &heapTup->t_self, heapTup);
13254 
13255  table_close(attrelation, RowExclusiveLock);
13256 
13257  /* Install dependencies on new datatype and collation */
13260 
13261  /*
13262  * Drop any pg_statistic entry for the column, since it's now wrong type
13263  */
13265 
13266  InvokeObjectPostAlterHook(RelationRelationId,
13267  RelationGetRelid(rel), attnum);
13268 
13269  /*
13270  * Update the default, if present, by brute force --- remove and re-add
13271  * the default. Probably unsafe to take shortcuts, since the new version
13272  * may well have additional dependencies. (It's okay to do this now,
13273  * rather than after other ALTER TYPE commands, since the default won't
13274  * depend on other column types.)
13275  */
13276  if (defaultexpr)
13277  {
13278  /*
13279  * If it's a GENERATED default, drop its dependency records, in
13280  * particular its INTERNAL dependency on the column, which would
13281  * otherwise cause dependency.c to refuse to perform the deletion.
13282  */
13283  if (attTup->attgenerated)
13284  {
13285  Oid attrdefoid = GetAttrDefaultOid(RelationGetRelid(rel), attnum);
13286 
13287  if (!OidIsValid(attrdefoid))
13288  elog(ERROR, "could not find attrdef tuple for relation %u attnum %d",
13289  RelationGetRelid(rel), attnum);
13290  (void) deleteDependencyRecordsFor(AttrDefaultRelationId, attrdefoid, false);
13291  }
13292 
13293  /*
13294  * Make updates-so-far visible, particularly the new pg_attribute row
13295  * which will be updated again.
13296  */
13298 
13299  /*
13300  * We use RESTRICT here for safety, but at present we do not expect
13301  * anything to depend on the default.
13302  */
13304  true);
13305 
13306  StoreAttrDefault(rel, attnum, defaultexpr, true, false);
13307  }
13308 
13309  ObjectAddressSubSet(address, RelationRelationId,
13310  RelationGetRelid(rel), attnum);
13311 
13312  /* Cleanup */
13313  heap_freetuple(heapTup);
13314 
13315  return address;
13316 }
13317 
13318 /*
13319  * Subroutine for ATExecAlterColumnType and ATExecSetExpression: Find everything
13320  * that depends on the column (constraints, indexes, etc), and record enough
13321  * information to let us recreate the objects.
13322  */
13323 static void
13325  Relation rel, AttrNumber attnum, const char *colName)
13326 {
13327  Relation depRel;
13328  ScanKeyData key[3];
13329  SysScanDesc scan;
13330  HeapTuple depTup;
13331 
13332  Assert(subtype == AT_AlterColumnType || subtype == AT_SetExpression);
13333 
13334  depRel = table_open(DependRelationId, RowExclusiveLock);
13335 
13336  ScanKeyInit(&key[0],
13337  Anum_pg_depend_refclassid,
13338  BTEqualStrategyNumber, F_OIDEQ,
13339  ObjectIdGetDatum(RelationRelationId));
13340  ScanKeyInit(&key[1],
13341  Anum_pg_depend_refobjid,
13342  BTEqualStrategyNumber, F_OIDEQ,
13344  ScanKeyInit(&key[2],
13345  Anum_pg_depend_refobjsubid,
13346  BTEqualStrategyNumber, F_INT4EQ,
13348 
13349  scan = systable_beginscan(depRel, DependReferenceIndexId, true,
13350  NULL, 3, key);
13351 
13352  while (HeapTupleIsValid(depTup = systable_getnext(scan)))
13353  {
13354  Form_pg_depend foundDep = (Form_pg_depend) GETSTRUCT(depTup);
13355  ObjectAddress foundObject;
13356 
13357  foundObject.classId = foundDep->classid;
13358  foundObject.objectId = foundDep->objid;
13359  foundObject.objectSubId = foundDep->objsubid;
13360 
13361  switch (foundObject.classId)
13362  {
13363  case RelationRelationId:
13364  {
13365  char relKind = get_rel_relkind(foundObject.objectId);
13366 
13367  if (relKind == RELKIND_INDEX ||
13368  relKind == RELKIND_PARTITIONED_INDEX)
13369  {
13370  Assert(foundObject.objectSubId == 0);
13371  RememberIndexForRebuilding(foundObject.objectId, tab);
13372  }
13373  else if (relKind == RELKIND_SEQUENCE)
13374  {
13375  /*
13376  * This must be a SERIAL column's sequence. We need
13377  * not do anything to it.
13378  */
13379  Assert(foundObject.objectSubId == 0);
13380  }
13381  else
13382  {
13383  /* Not expecting any other direct dependencies... */
13384  elog(ERROR, "unexpected object depending on column: %s",
13385  getObjectDescription(&foundObject, false));
13386  }
13387  break;
13388  }
13389 
13390  case ConstraintRelationId:
13391  Assert(foundObject.objectSubId == 0);
13392  RememberConstraintForRebuilding(foundObject.objectId, tab);
13393  break;
13394 
13395  case ProcedureRelationId:
13396 
13397  /*
13398  * A new-style SQL function can depend on a column, if that
13399  * column is referenced in the parsed function body. Ideally
13400  * we'd automatically update the function by deparsing and
13401  * reparsing it, but that's risky and might well fail anyhow.
13402  * FIXME someday.
13403  *
13404  * This is only a problem for AT_AlterColumnType, not
13405  * AT_SetExpression.
13406  */
13407  if (subtype == AT_AlterColumnType)
13408  ereport(ERROR,
13409  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
13410  errmsg("cannot alter type of a column used by a function or procedure"),
13411  errdetail("%s depends on column \"%s\"",
13412  getObjectDescription(&foundObject, false),
13413  colName)));
13414  break;
13415 
13416  case RewriteRelationId:
13417 
13418  /*
13419  * View/rule bodies have pretty much the same issues as
13420  * function bodies. FIXME someday.
13421  */
13422  if (subtype == AT_AlterColumnType)
13423  ereport(ERROR,
13424  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
13425  errmsg("cannot alter type of a column used by a view or rule"),
13426  errdetail("%s depends on column \"%s\"",
13427  getObjectDescription(&foundObject, false),
13428  colName)));
13429  break;
13430 
13431  case TriggerRelationId:
13432 
13433  /*
13434  * A trigger can depend on a column because the column is
13435  * specified as an update target, or because the column is
13436  * used in the trigger's WHEN condition. The first case would
13437  * not require any extra work, but the second case would
13438  * require updating the WHEN expression, which has the same
13439  * issues as above. Since we can't easily tell which case
13440  * applies, we punt for both. FIXME someday.
13441  */
13442  if (subtype == AT_AlterColumnType)
13443  ereport(ERROR,
13444  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
13445  errmsg("cannot alter type of a column used in a trigger definition"),
13446  errdetail("%s depends on column \"%s\"",
13447  getObjectDescription(&foundObject, false),
13448  colName)));
13449  break;
13450 
13451  case PolicyRelationId:
13452 
13453  /*
13454  * A policy can depend on a column because the column is
13455  * specified in the policy's USING or WITH CHECK qual
13456  * expressions. It might be possible to rewrite and recheck
13457  * the policy expression, but punt for now. It's certainly
13458  * easy enough to remove and recreate the policy; still, FIXME
13459  * someday.
13460  */
13461  if (subtype == AT_AlterColumnType)
13462  ereport(ERROR,
13463  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
13464  errmsg("cannot alter type of a column used in a policy definition"),
13465  errdetail("%s depends on column \"%s\"",
13466  getObjectDescription(&foundObject, false),
13467  colName)));
13468  break;
13469 
13470  case AttrDefaultRelationId:
13471  {
13473 
13474  if (col.objectId == RelationGetRelid(rel) &&
13475  col.objectSubId == attnum)
13476  {
13477  /*
13478  * Ignore the column's own default expression. The
13479  * caller deals with it.
13480  */
13481  }
13482  else
13483  {
13484  /*
13485  * This must be a reference from the expression of a
13486  * generated column elsewhere in the same table.
13487  * Changing the type/generated expression of a column
13488  * that is used by a generated column is not allowed
13489  * by SQL standard, so just punt for now. It might be
13490  * doable with some thinking and effort.
13491  */
13492  if (subtype == AT_AlterColumnType)
13493  ereport(ERROR,
13494  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
13495  errmsg("cannot alter type of a column used by a generated column"),
13496  errdetail("Column \"%s\" is used by generated column \"%s\".",
13497  colName,
13498  get_attname(col.objectId,
13499  col.objectSubId,
13500  false))));
13501  }
13502  break;
13503  }
13504 
13505  case StatisticExtRelationId:
13506 
13507  /*
13508  * Give the extended-stats machinery a chance to fix anything
13509  * that this column type change would break.
13510  */
13511  RememberStatisticsForRebuilding(foundObject.objectId, tab);
13512  break;
13513 
13514  case PublicationRelRelationId:
13515 
13516  /*
13517  * Column reference in a PUBLICATION ... FOR TABLE ... WHERE
13518  * clause. Same issues as above. FIXME someday.
13519  */
13520  if (subtype == AT_AlterColumnType)
13521  ereport(ERROR,
13522  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
13523  errmsg("cannot alter type of a column used by a publication WHERE clause"),
13524  errdetail("%s depends on column \"%s\"",
13525  getObjectDescription(&foundObject, false),
13526  colName)));
13527  break;
13528 
13529  default:
13530 
13531  /*
13532  * We don't expect any other sorts of objects to depend on a
13533  * column.
13534  */
13535  elog(ERROR, "unexpected object depending on column: %s",
13536  getObjectDescription(&foundObject, false));
13537  break;
13538  }
13539  }
13540 
13541  systable_endscan(scan);
13542  table_close(depRel, NoLock);
13543 }
13544 
13545 /*
13546  * Subroutine for ATExecAlterColumnType: remember that a replica identity
13547  * needs to be reset.
13548  */
13549 static void
13551 {
13552  if (!get_index_isreplident(indoid))
13553  return;
13554 
13555  if (tab->replicaIdentityIndex)
13556  elog(ERROR, "relation %u has multiple indexes marked as replica identity", tab->relid);
13557 
13558  tab->replicaIdentityIndex = get_rel_name(indoid);
13559 }
13560 
13561 /*
13562  * Subroutine for ATExecAlterColumnType: remember any clustered index.
13563  */
13564 static void
13566 {
13567  if (!get_index_isclustered(indoid))
13568  return;
13569 
13570  if (tab->clusterOnIndex)
13571  elog(ERROR, "relation %u has multiple clustered indexes", tab->relid);
13572 
13573  tab->clusterOnIndex = get_rel_name(indoid);
13574 }
13575 
13576 /*
13577  * Subroutine for ATExecAlterColumnType: remember that a constraint needs
13578  * to be rebuilt (which we might already know).
13579  */
13580 static void
13582 {
13583  /*
13584  * This de-duplication check is critical for two independent reasons: we
13585  * mustn't try to recreate the same constraint twice, and if a constraint
13586  * depends on more than one column whose type is to be altered, we must
13587  * capture its definition string before applying any of the column type
13588  * changes. ruleutils.c will get confused if we ask again later.
13589  */
13590  if (!list_member_oid(tab->changedConstraintOids, conoid))
13591  {
13592  /* OK, capture the constraint's existing definition string */
13593  char *defstring = pg_get_constraintdef_command(conoid);
13594  Oid indoid;
13595 
13597  conoid);
13599  defstring);
13600 
13601  /*
13602  * For the index of a constraint, if any, remember if it is used for
13603  * the table's replica identity or if it is a clustered index, so that
13604  * ATPostAlterTypeCleanup() can queue up commands necessary to restore
13605  * those properties.
13606  */
13607  indoid = get_constraint_index(conoid);
13608  if (OidIsValid(indoid))
13609  {
13611  RememberClusterOnForRebuilding(indoid, tab);
13612  }
13613  }
13614 }
13615 
13616 /*
13617  * Subroutine for ATExecAlterColumnType: remember that an index needs
13618  * to be rebuilt (which we might already know).
13619  */
13620 static void
13622 {
13623  /*
13624  * This de-duplication check is critical for two independent reasons: we
13625  * mustn't try to recreate the same index twice, and if an index depends
13626  * on more than one column whose type is to be altered, we must capture
13627  * its definition string before applying any of the column type changes.
13628  * ruleutils.c will get confused if we ask again later.
13629  */
13630  if (!list_member_oid(tab->changedIndexOids, indoid))
13631  {
13632  /*
13633  * Before adding it as an index-to-rebuild, we'd better see if it
13634  * belongs to a constraint, and if so rebuild the constraint instead.
13635  * Typically this check fails, because constraint indexes normally
13636  * have only dependencies on their constraint. But it's possible for
13637  * such an index to also have direct dependencies on table columns,
13638  * for example with a partial exclusion constraint.
13639  */
13640  Oid conoid = get_index_constraint(indoid);
13641 
13642  if (OidIsValid(conoid))
13643  {
13644  RememberConstraintForRebuilding(conoid, tab);
13645  }
13646  else
13647  {
13648  /* OK, capture the index's existing definition string */
13649  char *defstring = pg_get_indexdef_string(indoid);
13650 
13652  indoid);
13654  defstring);
13655 
13656  /*
13657  * Remember if this index is used for the table's replica identity
13658  * or if it is a clustered index, so that ATPostAlterTypeCleanup()
13659  * can queue up commands necessary to restore those properties.
13660  */
13662  RememberClusterOnForRebuilding(indoid, tab);
13663  }
13664  }
13665 }
13666 
13667 /*
13668  * Subroutine for ATExecAlterColumnType: remember that a statistics object
13669  * needs to be rebuilt (which we might already know).
13670  */
13671 static void
13673 {
13674  /*
13675  * This de-duplication check is critical for two independent reasons: we
13676  * mustn't try to recreate the same statistics object twice, and if the
13677  * statistics object depends on more than one column whose type is to be
13678  * altered, we must capture its definition string before applying any of
13679  * the type changes. ruleutils.c will get confused if we ask again later.
13680  */
13681  if (!list_member_oid(tab->changedStatisticsOids, stxoid))
13682  {
13683  /* OK, capture the statistics object's existing definition string */
13684  char *defstring = pg_get_statisticsobjdef_string(stxoid);
13685 
13687  stxoid);
13689  defstring);
13690  }
13691 }
13692 
13693 /*
13694  * Cleanup after we've finished all the ALTER TYPE or SET EXPRESSION
13695  * operations for a particular relation. We have to drop and recreate all the
13696  * indexes and constraints that depend on the altered columns. We do the
13697  * actual dropping here, but re-creation is managed by adding work queue
13698  * entries to do those steps later.
13699  */
13700 static void
13702 {
13703  ObjectAddress obj;
13704  ObjectAddresses *objects;
13705  ListCell *def_item;
13706  ListCell *oid_item;
13707 
13708  /*
13709  * Collect all the constraints and indexes to drop so we can process them
13710  * in a single call. That way we don't have to worry about dependencies
13711  * among them.
13712  */
13713  objects = new_object_addresses();
13714 
13715  /*
13716  * Re-parse the index and constraint definitions, and attach them to the
13717  * appropriate work queue entries. We do this before dropping because in
13718  * the case of a FOREIGN KEY constraint, we might not yet have exclusive
13719  * lock on the table the constraint is attached to, and we need to get
13720  * that before reparsing/dropping.
13721  *
13722  * We can't rely on the output of deparsing to tell us which relation to
13723  * operate on, because concurrent activity might have made the name
13724  * resolve differently. Instead, we've got to use the OID of the
13725  * constraint or index we're processing to figure out which relation to
13726  * operate on.
13727  */
13728  forboth(oid_item, tab->changedConstraintOids,
13729  def_item, tab->changedConstraintDefs)
13730  {
13731  Oid oldId = lfirst_oid(oid_item);
13732  HeapTuple tup;
13733  Form_pg_constraint con;
13734  Oid relid;
13735  Oid confrelid;
13736  char contype;
13737  bool conislocal;
13738 
13739  tup = SearchSysCache1(CONSTROID, ObjectIdGetDatum(oldId));
13740  if (!HeapTupleIsValid(tup)) /* should not happen */
13741  elog(ERROR, "cache lookup failed for constraint %u", oldId);
13742  con = (Form_pg_constraint) GETSTRUCT(tup);
13743  if (OidIsValid(con->conrelid))
13744  relid = con->conrelid;
13745  else
13746  {
13747  /* must be a domain constraint */
13748  relid = get_typ_typrelid(getBaseType(con->contypid));
13749  if (!OidIsValid(relid))
13750  elog(ERROR, "could not identify relation associated with constraint %u", oldId);
13751  }
13752  confrelid = con->confrelid;
13753  contype = con->contype;
13754  conislocal = con->conislocal;
13755  ReleaseSysCache(tup);
13756 
13757  ObjectAddressSet(obj, ConstraintRelationId, oldId);
13758  add_exact_object_address(&obj, objects);
13759 
13760  /*
13761  * If the constraint is inherited (only), we don't want to inject a
13762  * new definition here; it'll get recreated when ATAddCheckConstraint
13763  * recurses from adding the parent table's constraint. But we had to
13764  * carry the info this far so that we can drop the constraint below.
13765  */
13766  if (!conislocal)
13767  continue;
13768 
13769  /*
13770  * When rebuilding an FK constraint that references the table we're
13771  * modifying, we might not yet have any lock on the FK's table, so get
13772  * one now. We'll need AccessExclusiveLock for the DROP CONSTRAINT
13773  * step, so there's no value in asking for anything weaker.
13774  */
13775  if (relid != tab->relid && contype == CONSTRAINT_FOREIGN)
13777 
13778  ATPostAlterTypeParse(oldId, relid, confrelid,
13779  (char *) lfirst(def_item),
13780  wqueue, lockmode, tab->rewrite);
13781  }
13782  forboth(oid_item, tab->changedIndexOids,
13783  def_item, tab->changedIndexDefs)
13784  {
13785  Oid oldId = lfirst_oid(oid_item);
13786  Oid relid;
13787 
13788  relid = IndexGetRelation(oldId, false);
13789  ATPostAlterTypeParse(oldId, relid, InvalidOid,
13790  (char *) lfirst(def_item),
13791  wqueue, lockmode, tab->rewrite);
13792 
13793  ObjectAddressSet(obj, RelationRelationId, oldId);
13794  add_exact_object_address(&obj, objects);
13795  }
13796 
13797  /* add dependencies for new statistics */
13798  forboth(oid_item, tab->changedStatisticsOids,
13799  def_item, tab->changedStatisticsDefs)
13800  {
13801  Oid oldId = lfirst_oid(oid_item);
13802  Oid relid;
13803 
13804  relid = StatisticsGetRelation(oldId, false);
13805  ATPostAlterTypeParse(oldId, relid, InvalidOid,
13806  (char *) lfirst(def_item),
13807  wqueue, lockmode, tab->rewrite);
13808 
13809  ObjectAddressSet(obj, StatisticExtRelationId, oldId);
13810  add_exact_object_address(&obj, objects);
13811  }
13812 
13813  /*
13814  * Queue up command to restore replica identity index marking
13815  */
13816  if (tab->replicaIdentityIndex)
13817  {
13820 
13821  subcmd->identity_type = REPLICA_IDENTITY_INDEX;
13822  subcmd->name = tab->replicaIdentityIndex;
13823  cmd->subtype = AT_ReplicaIdentity;
13824  cmd->def = (Node *) subcmd;
13825 
13826  /* do it after indexes and constraints */
13827  tab->subcmds[AT_PASS_OLD_CONSTR] =
13828  lappend(tab->subcmds[AT_PASS_OLD_CONSTR], cmd);
13829  }
13830 
13831  /*
13832  * Queue up command to restore marking of index used for cluster.
13833  */
13834  if (tab->clusterOnIndex)
13835  {
13837 
13838  cmd->subtype = AT_ClusterOn;
13839  cmd->name = tab->clusterOnIndex;
13840 
13841  /* do it after indexes and constraints */
13842  tab->subcmds[AT_PASS_OLD_CONSTR] =
13843  lappend(tab->subcmds[AT_PASS_OLD_CONSTR], cmd);
13844  }
13845 
13846  /*
13847  * It should be okay to use DROP_RESTRICT here, since nothing else should
13848  * be depending on these objects.
13849  */
13851 
13852  free_object_addresses(objects);
13853 
13854  /*
13855  * The objects will get recreated during subsequent passes over the work
13856  * queue.
13857  */
13858 }
13859 
13860 /*
13861  * Parse the previously-saved definition string for a constraint, index or
13862  * statistics object against the newly-established column data type(s), and
13863  * queue up the resulting command parsetrees for execution.
13864  *
13865  * This might fail if, for example, you have a WHERE clause that uses an
13866  * operator that's not available for the new column type.
13867  */
13868 static void
13869 ATPostAlterTypeParse(Oid oldId, Oid oldRelId, Oid refRelId, char *cmd,
13870  List **wqueue, LOCKMODE lockmode, bool rewrite)
13871 {
13872  List *raw_parsetree_list;
13873  List *querytree_list;
13874  ListCell *list_item;
13875  Relation rel;
13876 
13877  /*
13878  * We expect that we will get only ALTER TABLE and CREATE INDEX
13879  * statements. Hence, there is no need to pass them through
13880  * parse_analyze_*() or the rewriter, but instead we need to pass them
13881  * through parse_utilcmd.c to make them ready for execution.
13882  */
13883  raw_parsetree_list = raw_parser(cmd, RAW_PARSE_DEFAULT);
13884  querytree_list = NIL;
13885  foreach(list_item, raw_parsetree_list)
13886  {
13887  RawStmt *rs = lfirst_node(RawStmt, list_item);
13888  Node *stmt = rs->stmt;
13889 
13890  if (IsA(stmt, IndexStmt))
13891  querytree_list = lappend(querytree_list,
13892  transformIndexStmt(oldRelId,
13893  (IndexStmt *) stmt,
13894  cmd));
13895  else if (IsA(stmt, AlterTableStmt))
13896  {
13897  List *beforeStmts;
13898  List *afterStmts;
13899 
13900  stmt = (Node *) transformAlterTableStmt(oldRelId,
13901  (AlterTableStmt *) stmt,
13902  cmd,
13903  &beforeStmts,
13904  &afterStmts);
13905  querytree_list = list_concat(querytree_list, beforeStmts);
13906  querytree_list = lappend(querytree_list, stmt);
13907  querytree_list = list_concat(querytree_list, afterStmts);
13908  }
13909  else if (IsA(stmt, CreateStatsStmt))
13910  querytree_list = lappend(querytree_list,
13911  transformStatsStmt(oldRelId,
13912  (CreateStatsStmt *) stmt,
13913  cmd));
13914  else
13915  querytree_list = lappend(querytree_list, stmt);
13916  }
13917 
13918  /* Caller should already have acquired whatever lock we need. */
13919  rel = relation_open(oldRelId, NoLock);
13920 
13921  /*
13922  * Attach each generated command to the proper place in the work queue.
13923  * Note this could result in creation of entirely new work-queue entries.
13924  *
13925  * Also note that we have to tweak the command subtypes, because it turns
13926  * out that re-creation of indexes and constraints has to act a bit
13927  * differently from initial creation.
13928  */
13929  foreach(list_item, querytree_list)
13930  {
13931  Node *stm = (Node *) lfirst(list_item);
13932  AlteredTableInfo *tab;
13933 
13934  tab = ATGetQueueEntry(wqueue, rel);
13935 
13936  if (IsA(stm, IndexStmt))
13937  {
13938  IndexStmt *stmt = (IndexStmt *) stm;
13939  AlterTableCmd *newcmd;
13940 
13941  if (!rewrite)
13942  TryReuseIndex(oldId, stmt);
13943  stmt->reset_default_tblspc = true;
13944  /* keep the index's comment */
13945  stmt->idxcomment = GetComment(oldId, RelationRelationId, 0);
13946 
13947  newcmd = makeNode(AlterTableCmd);
13948  newcmd->subtype = AT_ReAddIndex;
13949  newcmd->def = (Node *) stmt;
13950  tab->subcmds[AT_PASS_OLD_INDEX] =
13951  lappend(tab->subcmds[AT_PASS_OLD_INDEX], newcmd);
13952  }
13953  else if (IsA(stm, AlterTableStmt))
13954  {
13955  AlterTableStmt *stmt = (AlterTableStmt *) stm;
13956  ListCell *lcmd;
13957 
13958  foreach(lcmd, stmt->cmds)
13959  {
13960  AlterTableCmd *cmd = lfirst_node(AlterTableCmd, lcmd);
13961 
13962  if (cmd->subtype == AT_AddIndex)
13963  {
13964  IndexStmt *indstmt;
13965  Oid indoid;
13966 
13967  indstmt = castNode(IndexStmt, cmd->def);
13968  indoid = get_constraint_index(oldId);
13969 
13970  if (!rewrite)
13971  TryReuseIndex(indoid, indstmt);
13972  /* keep any comment on the index */
13973  indstmt->idxcomment = GetComment(indoid,
13974  RelationRelationId, 0);
13975  indstmt->reset_default_tblspc = true;
13976 
13977  cmd->subtype = AT_ReAddIndex;
13978  tab->subcmds[AT_PASS_OLD_INDEX] =
13979  lappend(tab->subcmds[AT_PASS_OLD_INDEX], cmd);
13980 
13981  /* recreate any comment on the constraint */
13984  oldId,
13985  rel,
13986  NIL,
13987  indstmt->idxname);
13988  }
13989  else if (cmd->subtype == AT_AddConstraint)
13990  {
13991  Constraint *con = castNode(Constraint, cmd->def);
13992 
13993  con->old_pktable_oid = refRelId;
13994  /* rewriting neither side of a FK */
13995  if (con->contype == CONSTR_FOREIGN &&
13996  !rewrite && tab->rewrite == 0)
13997  TryReuseForeignKey(oldId, con);
13998  con->reset_default_tblspc = true;
13999  cmd->subtype = AT_ReAddConstraint;
14000  tab->subcmds[AT_PASS_OLD_CONSTR] =
14001  lappend(tab->subcmds[AT_PASS_OLD_CONSTR], cmd);
14002 
14003  /* recreate any comment on the constraint */
14006  oldId,
14007  rel,
14008  NIL,
14009  con->conname);
14010  }
14011  else if (cmd->subtype == AT_SetNotNull)
14012  {
14013  /*
14014  * The parser will create AT_SetNotNull subcommands for
14015  * columns of PRIMARY KEY indexes/constraints, but we need
14016  * not do anything with them here, because the columns'
14017  * NOT NULL marks will already have been propagated into
14018  * the new table definition.
14019  */
14020  }
14021  else
14022  elog(ERROR, "unexpected statement subtype: %d",
14023  (int) cmd->subtype);
14024  }
14025  }
14026  else if (IsA(stm, AlterDomainStmt))
14027  {
14029 
14030  if (stmt->subtype == 'C') /* ADD CONSTRAINT */
14031  {
14032  Constraint *con = castNode(Constraint, stmt->def);
14034 
14036  cmd->def = (Node *) stmt;
14037  tab->subcmds[AT_PASS_OLD_CONSTR] =
14038  lappend(tab->subcmds[AT_PASS_OLD_CONSTR], cmd);
14039 
14040  /* recreate any comment on the constraint */
14043  oldId,
14044  NULL,
14045  stmt->typeName,
14046  con->conname);
14047  }
14048  else
14049  elog(ERROR, "unexpected statement subtype: %d",
14050  (int) stmt->subtype);
14051  }
14052  else if (IsA(stm, CreateStatsStmt))
14053  {
14055  AlterTableCmd *newcmd;
14056 
14057  /* keep the statistics object's comment */
14058  stmt->stxcomment = GetComment(oldId, StatisticExtRelationId, 0);
14059 
14060  newcmd = makeNode(AlterTableCmd);
14061  newcmd->subtype = AT_ReAddStatistics;
14062  newcmd->def = (Node *) stmt;
14063  tab->subcmds[AT_PASS_MISC] =
14064  lappend(tab->subcmds[AT_PASS_MISC], newcmd);
14065  }
14066  else
14067  elog(ERROR, "unexpected statement type: %d",
14068  (int) nodeTag(stm));
14069  }
14070 
14071  relation_close(rel, NoLock);
14072 }
14073 
14074 /*
14075  * Subroutine for ATPostAlterTypeParse() to recreate any existing comment
14076  * for a table or domain constraint that is being rebuilt.
14077  *
14078  * objid is the OID of the constraint.
14079  * Pass "rel" for a table constraint, or "domname" (domain's qualified name
14080  * as a string list) for a domain constraint.
14081  * (We could dig that info, as well as the conname, out of the pg_constraint
14082  * entry; but callers already have them so might as well pass them.)
14083  */
14084 static void
14086  Relation rel, List *domname,
14087  const char *conname)
14088 {
14089  CommentStmt *cmd;
14090  char *comment_str;
14091  AlterTableCmd *newcmd;
14092 
14093  /* Look for comment for object wanted, and leave if none */
14094  comment_str = GetComment(objid, ConstraintRelationId, 0);
14095  if (comment_str == NULL)
14096  return;
14097 
14098  /* Build CommentStmt node, copying all input data for safety */
14099  cmd = makeNode(CommentStmt);
14100  if (rel)
14101  {
14103  cmd->object = (Node *)
14106  makeString(pstrdup(conname)));
14107  }
14108  else
14109  {
14111  cmd->object = (Node *)
14113  makeString(pstrdup(conname)));
14114  }
14115  cmd->comment = comment_str;
14116 
14117  /* Append it to list of commands */
14118  newcmd = makeNode(AlterTableCmd);
14119  newcmd->subtype = AT_ReAddComment;
14120  newcmd->def = (Node *) cmd;
14121  tab->subcmds[pass] = lappend(tab->subcmds[pass], newcmd);
14122 }
14123 
14124 /*
14125  * Subroutine for ATPostAlterTypeParse(). Calls out to CheckIndexCompatible()
14126  * for the real analysis, then mutates the IndexStmt based on that verdict.
14127  */
14128 static void
14130 {
14131  if (CheckIndexCompatible(oldId,
14132  stmt->accessMethod,
14133  stmt->indexParams,
14134  stmt->excludeOpNames))
14135  {
14136  Relation irel = index_open(oldId, NoLock);
14137 
14138  /* If it's a partitioned index, there is no storage to share. */
14139  if (irel->rd_rel->relkind != RELKIND_PARTITIONED_INDEX)
14140  {
14141  stmt->oldNumber = irel->rd_locator.relNumber;
14142  stmt->oldCreateSubid = irel->rd_createSubid;
14143  stmt->oldFirstRelfilelocatorSubid = irel->rd_firstRelfilelocatorSubid;
14144  }
14145  index_close(irel, NoLock);
14146  }
14147 }
14148 
14149 /*
14150  * Subroutine for ATPostAlterTypeParse().
14151  *
14152  * Stash the old P-F equality operator into the Constraint node, for possible
14153  * use by ATAddForeignKeyConstraint() in determining whether revalidation of
14154  * this constraint can be skipped.
14155  */
14156 static void
14158 {
14159  HeapTuple tup;
14160  Datum adatum;
14161  ArrayType *arr;
14162  Oid *rawarr;
14163  int numkeys;
14164  int i;
14165 
14166  Assert(con->contype == CONSTR_FOREIGN);
14167  Assert(con->old_conpfeqop == NIL); /* already prepared this node */
14168 
14169  tup = SearchSysCache1(CONSTROID, ObjectIdGetDatum(oldId));
14170  if (!HeapTupleIsValid(tup)) /* should not happen */
14171  elog(ERROR, "cache lookup failed for constraint %u", oldId);
14172 
14173  adatum = SysCacheGetAttrNotNull(CONSTROID, tup,
14174  Anum_pg_constraint_conpfeqop);
14175  arr = DatumGetArrayTypeP(adatum); /* ensure not toasted */
14176  numkeys = ARR_DIMS(arr)[0];
14177  /* test follows the one in ri_FetchConstraintInfo() */
14178  if (ARR_NDIM(arr) != 1 ||
14179  ARR_HASNULL(arr) ||
14180  ARR_ELEMTYPE(arr) != OIDOID)
14181  elog(ERROR, "conpfeqop is not a 1-D Oid array");
14182  rawarr = (Oid *) ARR_DATA_PTR(arr);
14183 
14184  /* stash a List of the operator Oids in our Constraint node */
14185  for (i = 0; i < numkeys; i++)
14186  con->old_conpfeqop = lappend_oid(con->old_conpfeqop, rawarr[i]);
14187 
14188  ReleaseSysCache(tup);
14189 }
14190 
14191 /*
14192  * ALTER COLUMN .. OPTIONS ( ... )
14193  *
14194  * Returns the address of the modified column
14195  */
14196 static ObjectAddress
14198  const char *colName,
14199  List *options,
14200  LOCKMODE lockmode)
14201 {
14202  Relation ftrel;
14203  Relation attrel;
14204  ForeignServer *server;
14205  ForeignDataWrapper *fdw;
14206  HeapTuple tuple;
14207  HeapTuple newtuple;
14208  bool isnull;
14209  Datum repl_val[Natts_pg_attribute];
14210  bool repl_null[Natts_pg_attribute];
14211  bool repl_repl[Natts_pg_attribute];
14212  Datum datum;
14213  Form_pg_foreign_table fttableform;
14214  Form_pg_attribute atttableform;
14216  ObjectAddress address;
14217 
14218  if (options == NIL)
14219  return InvalidObjectAddress;
14220 
14221  /* First, determine FDW validator associated to the foreign table. */
14222  ftrel = table_open(ForeignTableRelationId, AccessShareLock);
14223  tuple = SearchSysCache1(FOREIGNTABLEREL, ObjectIdGetDatum(rel->rd_id));
14224  if (!HeapTupleIsValid(tuple))
14225  ereport(ERROR,
14226  (errcode(ERRCODE_UNDEFINED_OBJECT),
14227  errmsg("foreign table \"%s\" does not exist",
14228  RelationGetRelationName(rel))));
14229  fttableform = (Form_pg_foreign_table) GETSTRUCT(tuple);
14230  server = GetForeignServer(fttableform->ftserver);
14231  fdw = GetForeignDataWrapper(server->fdwid);
14232 
14233  table_close(ftrel, AccessShareLock);
14234  ReleaseSysCache(tuple);
14235 
14236  attrel = table_open(AttributeRelationId, RowExclusiveLock);
14237  tuple = SearchSysCacheAttName(RelationGetRelid(rel), colName);
14238  if (!HeapTupleIsValid(tuple))
14239  ereport(ERROR,
14240  (errcode(ERRCODE_UNDEFINED_COLUMN),
14241  errmsg("column \"%s\" of relation \"%s\" does not exist",
14242  colName, RelationGetRelationName(rel))));
14243 
14244  /* Prevent them from altering a system attribute */
14245  atttableform = (Form_pg_attribute) GETSTRUCT(tuple);
14246  attnum = atttableform->attnum;
14247  if (attnum <= 0)
14248  ereport(ERROR,
14249  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
14250  errmsg("cannot alter system column \"%s\"", colName)));
14251 
14252 
14253  /* Initialize buffers for new tuple values */
14254  memset(repl_val, 0, sizeof(repl_val));
14255  memset(repl_null, false, sizeof(repl_null));
14256  memset(repl_repl, false, sizeof(repl_repl));
14257 
14258  /* Extract the current options */
14259  datum = SysCacheGetAttr(ATTNAME,
14260  tuple,
14261  Anum_pg_attribute_attfdwoptions,
14262  &isnull);
14263  if (isnull)
14264  datum = PointerGetDatum(NULL);
14265 
14266  /* Transform the options */
14267  datum = transformGenericOptions(AttributeRelationId,
14268  datum,
14269  options,
14270  fdw->fdwvalidator);
14271 
14272  if (PointerIsValid(DatumGetPointer(datum)))
14273  repl_val[Anum_pg_attribute_attfdwoptions - 1] = datum;
14274  else
14275  repl_null[Anum_pg_attribute_attfdwoptions - 1] = true;
14276 
14277  repl_repl[Anum_pg_attribute_attfdwoptions - 1] = true;
14278 
14279  /* Everything looks good - update the tuple */
14280 
14281  newtuple = heap_modify_tuple(tuple, RelationGetDescr(attrel),
14282  repl_val, repl_null, repl_repl);
14283 
14284  CatalogTupleUpdate(attrel, &newtuple->t_self, newtuple);
14285 
14286  InvokeObjectPostAlterHook(RelationRelationId,
14287  RelationGetRelid(rel),
14288  atttableform->attnum);
14289  ObjectAddressSubSet(address, RelationRelationId,
14290  RelationGetRelid(rel), attnum);
14291 
14292  ReleaseSysCache(tuple);
14293 
14294  table_close(attrel, RowExclusiveLock);
14295 
14296  heap_freetuple(newtuple);
14297 
14298  return address;
14299 }
14300 
14301 /*
14302  * ALTER TABLE OWNER
14303  *
14304  * recursing is true if we are recursing from a table to its indexes,
14305  * sequences, or toast table. We don't allow the ownership of those things to
14306  * be changed separately from the parent table. Also, we can skip permission
14307  * checks (this is necessary not just an optimization, else we'd fail to
14308  * handle toast tables properly).
14309  *
14310  * recursing is also true if ALTER TYPE OWNER is calling us to fix up a
14311  * free-standing composite type.
14312  */
14313 void
14314 ATExecChangeOwner(Oid relationOid, Oid newOwnerId, bool recursing, LOCKMODE lockmode)
14315 {
14316  Relation target_rel;
14317  Relation class_rel;
14318  HeapTuple tuple;
14319  Form_pg_class tuple_class;
14320 
14321  /*
14322  * Get exclusive lock till end of transaction on the target table. Use
14323  * relation_open so that we can work on indexes and sequences.
14324  */
14325  target_rel = relation_open(relationOid, lockmode);
14326 
14327  /* Get its pg_class tuple, too */
14328  class_rel = table_open(RelationRelationId, RowExclusiveLock);
14329 
14330  tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relationOid));
14331  if (!HeapTupleIsValid(tuple))
14332  elog(ERROR, "cache lookup failed for relation %u", relationOid);
14333  tuple_class = (Form_pg_class) GETSTRUCT(tuple);
14334 
14335  /* Can we change the ownership of this tuple? */
14336  switch (tuple_class->relkind)
14337  {
14338  case RELKIND_RELATION:
14339  case RELKIND_VIEW:
14340  case RELKIND_MATVIEW:
14341  case RELKIND_FOREIGN_TABLE:
14342  case RELKIND_PARTITIONED_TABLE:
14343  /* ok to change owner */
14344  break;
14345  case RELKIND_INDEX:
14346  if (!recursing)
14347  {
14348  /*
14349  * Because ALTER INDEX OWNER used to be allowed, and in fact
14350  * is generated by old versions of pg_dump, we give a warning
14351  * and do nothing rather than erroring out. Also, to avoid
14352  * unnecessary chatter while restoring those old dumps, say
14353  * nothing at all if the command would be a no-op anyway.
14354  */
14355  if (tuple_class->relowner != newOwnerId)
14356  ereport(WARNING,
14357  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
14358  errmsg("cannot change owner of index \"%s\"",
14359  NameStr(tuple_class->relname)),
14360  errhint("Change the ownership of the index's table instead.")));
14361  /* quick hack to exit via the no-op path */
14362  newOwnerId = tuple_class->relowner;
14363  }
14364  break;
14365  case RELKIND_PARTITIONED_INDEX:
14366  if (recursing)
14367  break;
14368  ereport(ERROR,
14369  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
14370  errmsg("cannot change owner of index \"%s\"",
14371  NameStr(tuple_class->relname)),
14372  errhint("Change the ownership of the index's table instead.")));
14373  break;
14374  case RELKIND_SEQUENCE:
14375  if (!recursing &&
14376  tuple_class->relowner != newOwnerId)
14377  {
14378  /* if it's an owned sequence, disallow changing it by itself */
14379  Oid tableId;
14380  int32 colId;
14381 
14382  if (sequenceIsOwned(relationOid, DEPENDENCY_AUTO, &tableId, &colId) ||
14383  sequenceIsOwned(relationOid, DEPENDENCY_INTERNAL, &tableId, &colId))
14384  ereport(ERROR,
14385  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
14386  errmsg("cannot change owner of sequence \"%s\"",
14387  NameStr(tuple_class->relname)),
14388  errdetail("Sequence \"%s\" is linked to table \"%s\".",
14389  NameStr(tuple_class->relname),
14390  get_rel_name(tableId))));
14391  }
14392  break;
14393  case RELKIND_COMPOSITE_TYPE:
14394  if (recursing)
14395  break;
14396  ereport(ERROR,
14397  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
14398  errmsg("\"%s\" is a composite type",
14399  NameStr(tuple_class->relname)),
14400  /* translator: %s is an SQL ALTER command */
14401  errhint("Use %s instead.",
14402  "ALTER TYPE")));
14403  break;
14404  case RELKIND_TOASTVALUE:
14405  if (recursing)
14406  break;
14407  /* FALL THRU */
14408  default:
14409  ereport(ERROR,
14410  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
14411  errmsg("cannot change owner of relation \"%s\"",
14412  NameStr(tuple_class->relname)),
14413  errdetail_relkind_not_supported(tuple_class->relkind)));
14414  }
14415 
14416  /*
14417  * If the new owner is the same as the existing owner, consider the
14418  * command to have succeeded. This is for dump restoration purposes.
14419  */
14420  if (tuple_class->relowner != newOwnerId)
14421  {
14422  Datum repl_val[Natts_pg_class];
14423  bool repl_null[Natts_pg_class];
14424  bool repl_repl[Natts_pg_class];
14425  Acl *newAcl;
14426  Datum aclDatum;
14427  bool isNull;
14428  HeapTuple newtuple;
14429 
14430  /* skip permission checks when recursing to index or toast table */
14431  if (!recursing)
14432  {
14433  /* Superusers can always do it */
14434  if (!superuser())
14435  {
14436  Oid namespaceOid = tuple_class->relnamespace;
14437  AclResult aclresult;
14438 
14439  /* Otherwise, must be owner of the existing object */
14440  if (!object_ownercheck(RelationRelationId, relationOid, GetUserId()))
14442  RelationGetRelationName(target_rel));
14443 
14444  /* Must be able to become new owner */
14445  check_can_set_role(GetUserId(), newOwnerId);
14446 
14447  /* New owner must have CREATE privilege on namespace */
14448  aclresult = object_aclcheck(NamespaceRelationId, namespaceOid, newOwnerId,
14449  ACL_CREATE);
14450  if (aclresult != ACLCHECK_OK)
14451  aclcheck_error(aclresult, OBJECT_SCHEMA,
14452  get_namespace_name(namespaceOid));
14453  }
14454  }
14455 
14456  memset(repl_null, false, sizeof(repl_null));
14457  memset(repl_repl, false, sizeof(repl_repl));
14458 
14459  repl_repl[Anum_pg_class_relowner - 1] = true;
14460  repl_val[Anum_pg_class_relowner - 1] = ObjectIdGetDatum(newOwnerId);
14461 
14462  /*
14463  * Determine the modified ACL for the new owner. This is only
14464  * necessary when the ACL is non-null.
14465  */
14466  aclDatum = SysCacheGetAttr(RELOID, tuple,
14467  Anum_pg_class_relacl,
14468  &isNull);
14469  if (!isNull)
14470  {
14471  newAcl = aclnewowner(DatumGetAclP(aclDatum),
14472  tuple_class->relowner, newOwnerId);
14473  repl_repl[Anum_pg_class_relacl - 1] = true;
14474  repl_val[Anum_pg_class_relacl - 1] = PointerGetDatum(newAcl);
14475  }
14476 
14477  newtuple = heap_modify_tuple(tuple, RelationGetDescr(class_rel), repl_val, repl_null, repl_repl);
14478 
14479  CatalogTupleUpdate(class_rel, &newtuple->t_self, newtuple);
14480 
14481  heap_freetuple(newtuple);
14482 
14483  /*
14484  * We must similarly update any per-column ACLs to reflect the new
14485  * owner; for neatness reasons that's split out as a subroutine.
14486  */
14487  change_owner_fix_column_acls(relationOid,
14488  tuple_class->relowner,
14489  newOwnerId);
14490 
14491  /*
14492  * Update owner dependency reference, if any. A composite type has
14493  * none, because it's tracked for the pg_type entry instead of here;
14494  * indexes and TOAST tables don't have their own entries either.
14495  */
14496  if (tuple_class->relkind != RELKIND_COMPOSITE_TYPE &&
14497  tuple_class->relkind != RELKIND_INDEX &&
14498  tuple_class->relkind != RELKIND_PARTITIONED_INDEX &&
14499  tuple_class->relkind != RELKIND_TOASTVALUE)
14500  changeDependencyOnOwner(RelationRelationId, relationOid,
14501  newOwnerId);
14502 
14503  /*
14504  * Also change the ownership of the table's row type, if it has one
14505  */
14506  if (OidIsValid(tuple_class->reltype))
14507  AlterTypeOwnerInternal(tuple_class->reltype, newOwnerId);
14508 
14509  /*
14510  * If we are operating on a table or materialized view, also change
14511  * the ownership of any indexes and sequences that belong to the
14512  * relation, as well as its toast table (if it has one).
14513  */
14514  if (tuple_class->relkind == RELKIND_RELATION ||
14515  tuple_class->relkind == RELKIND_PARTITIONED_TABLE ||
14516  tuple_class->relkind == RELKIND_MATVIEW ||
14517  tuple_class->relkind == RELKIND_TOASTVALUE)
14518  {
14519  List *index_oid_list;
14520  ListCell *i;
14521 
14522  /* Find all the indexes belonging to this relation */
14523  index_oid_list = RelationGetIndexList(target_rel);
14524 
14525  /* For each index, recursively change its ownership */
14526  foreach(i, index_oid_list)
14527  ATExecChangeOwner(lfirst_oid(i), newOwnerId, true, lockmode);
14528 
14529  list_free(index_oid_list);
14530  }
14531 
14532  /* If it has a toast table, recurse to change its ownership */
14533  if (tuple_class->reltoastrelid != InvalidOid)
14534  ATExecChangeOwner(tuple_class->reltoastrelid, newOwnerId,
14535  true, lockmode);
14536 
14537  /* If it has dependent sequences, recurse to change them too */
14538  change_owner_recurse_to_sequences(relationOid, newOwnerId, lockmode);
14539  }
14540 
14541  InvokeObjectPostAlterHook(RelationRelationId, relationOid, 0);
14542 
14543  ReleaseSysCache(tuple);
14544  table_close(class_rel, RowExclusiveLock);
14545  relation_close(target_rel, NoLock);
14546 }
14547 
14548 /*
14549  * change_owner_fix_column_acls
14550  *
14551  * Helper function for ATExecChangeOwner. Scan the columns of the table
14552  * and fix any non-null column ACLs to reflect the new owner.
14553  */
14554 static void
14555 change_owner_fix_column_acls(Oid relationOid, Oid oldOwnerId, Oid newOwnerId)
14556 {
14557  Relation attRelation;
14558  SysScanDesc scan;
14559  ScanKeyData key[1];
14560  HeapTuple attributeTuple;
14561 
14562  attRelation = table_open(AttributeRelationId, RowExclusiveLock);
14563  ScanKeyInit(&key[0],
14564  Anum_pg_attribute_attrelid,
14565  BTEqualStrategyNumber, F_OIDEQ,
14566  ObjectIdGetDatum(relationOid));
14567  scan = systable_beginscan(attRelation, AttributeRelidNumIndexId,
14568  true, NULL, 1, key);
14569  while (HeapTupleIsValid(attributeTuple = systable_getnext(scan)))
14570  {
14571  Form_pg_attribute att = (Form_pg_attribute) GETSTRUCT(attributeTuple);
14572  Datum repl_val[Natts_pg_attribute];
14573  bool repl_null[Natts_pg_attribute];
14574  bool repl_repl[Natts_pg_attribute];
14575  Acl *newAcl;
14576  Datum aclDatum;
14577  bool isNull;
14578  HeapTuple newtuple;
14579 
14580  /* Ignore dropped columns */
14581  if (att->attisdropped)
14582  continue;
14583 
14584  aclDatum = heap_getattr(attributeTuple,
14585  Anum_pg_attribute_attacl,
14586  RelationGetDescr(attRelation),
14587  &isNull);
14588  /* Null ACLs do not require changes */
14589  if (isNull)
14590  continue;
14591 
14592  memset(repl_null, false, sizeof(repl_null));
14593  memset(repl_repl, false, sizeof(repl_repl));
14594 
14595  newAcl = aclnewowner(DatumGetAclP(aclDatum),
14596  oldOwnerId, newOwnerId);
14597  repl_repl[Anum_pg_attribute_attacl - 1] = true;
14598  repl_val[Anum_pg_attribute_attacl - 1] = PointerGetDatum(newAcl);
14599 
14600  newtuple = heap_modify_tuple(attributeTuple,
14601  RelationGetDescr(attRelation),
14602  repl_val, repl_null, repl_repl);
14603 
14604  CatalogTupleUpdate(attRelation, &newtuple->t_self, newtuple);
14605 
14606  heap_freetuple(newtuple);
14607  }
14608  systable_endscan(scan);
14609  table_close(attRelation, RowExclusiveLock);
14610 }
14611 
14612 /*
14613  * change_owner_recurse_to_sequences
14614  *
14615  * Helper function for ATExecChangeOwner. Examines pg_depend searching
14616  * for sequences that are dependent on serial columns, and changes their
14617  * ownership.
14618  */
14619 static void
14620 change_owner_recurse_to_sequences(Oid relationOid, Oid newOwnerId, LOCKMODE lockmode)
14621 {
14622  Relation depRel;
14623  SysScanDesc scan;
14624  ScanKeyData key[2];
14625  HeapTuple tup;
14626 
14627  /*
14628  * SERIAL sequences are those having an auto dependency on one of the
14629  * table's columns (we don't care *which* column, exactly).
14630  */
14631  depRel = table_open(DependRelationId, AccessShareLock);
14632 
14633  ScanKeyInit(&key[0],
14634  Anum_pg_depend_refclassid,
14635  BTEqualStrategyNumber, F_OIDEQ,
14636  ObjectIdGetDatum(RelationRelationId));
14637  ScanKeyInit(&key[1],
14638  Anum_pg_depend_refobjid,
14639  BTEqualStrategyNumber, F_OIDEQ,
14640  ObjectIdGetDatum(relationOid));
14641  /* we leave refobjsubid unspecified */
14642 
14643  scan = systable_beginscan(depRel, DependReferenceIndexId, true,
14644  NULL, 2, key);
14645 
14646  while (HeapTupleIsValid(tup = systable_getnext(scan)))
14647  {
14648  Form_pg_depend depForm = (Form_pg_depend) GETSTRUCT(tup);
14649  Relation seqRel;
14650 
14651  /* skip dependencies other than auto dependencies on columns */
14652  if (depForm->refobjsubid == 0 ||
14653  depForm->classid != RelationRelationId ||
14654  depForm->objsubid != 0 ||
14655  !(depForm->deptype == DEPENDENCY_AUTO || depForm->deptype == DEPENDENCY_INTERNAL))
14656  continue;
14657 
14658  /* Use relation_open just in case it's an index */
14659  seqRel = relation_open(depForm->objid, lockmode);
14660 
14661  /* skip non-sequence relations */
14662  if (RelationGetForm(seqRel)->relkind != RELKIND_SEQUENCE)
14663  {
14664  /* No need to keep the lock */
14665  relation_close(seqRel, lockmode);
14666  continue;
14667  }
14668 
14669  /* We don't need to close the sequence while we alter it. */
14670  ATExecChangeOwner(depForm->objid, newOwnerId, true, lockmode);
14671 
14672  /* Now we can close it. Keep the lock till end of transaction. */
14673  relation_close(seqRel, NoLock);
14674  }
14675 
14676  systable_endscan(scan);
14677 
14679 }
14680 
14681 /*
14682  * ALTER TABLE CLUSTER ON
14683  *
14684  * The only thing we have to do is to change the indisclustered bits.
14685  *
14686  * Return the address of the new clustering index.
14687  */
14688 static ObjectAddress
14689 ATExecClusterOn(Relation rel, const char *indexName, LOCKMODE lockmode)
14690 {
14691  Oid indexOid;
14692  ObjectAddress address;
14693 
14694  indexOid = get_relname_relid(indexName, rel->rd_rel->relnamespace);
14695 
14696  if (!OidIsValid(indexOid))
14697  ereport(ERROR,
14698  (errcode(ERRCODE_UNDEFINED_OBJECT),
14699  errmsg("index \"%s\" for table \"%s\" does not exist",
14700  indexName, RelationGetRelationName(rel))));
14701 
14702  /* Check index is valid to cluster on */
14703  check_index_is_clusterable(rel, indexOid, lockmode);
14704 
14705  /* And do the work */
14706  mark_index_clustered(rel, indexOid, false);
14707 
14708  ObjectAddressSet(address,
14709  RelationRelationId, indexOid);
14710 
14711  return address;
14712 }
14713 
14714 /*
14715  * ALTER TABLE SET WITHOUT CLUSTER
14716  *
14717  * We have to find any indexes on the table that have indisclustered bit
14718  * set and turn it off.
14719  */
14720 static void
14722 {
14723  mark_index_clustered(rel, InvalidOid, false);
14724 }
14725 
14726 /*
14727  * Preparation phase for SET ACCESS METHOD
14728  *
14729  * Check that the access method exists and determine whether a change is
14730  * actually needed.
14731  */
14732 static void
14733 ATPrepSetAccessMethod(AlteredTableInfo *tab, Relation rel, const char *amname)
14734 {
14735  Oid amoid;
14736 
14737  /*
14738  * Look up the access method name and check that it differs from the
14739  * table's current AM. If DEFAULT was specified for a partitioned table
14740  * (amname is NULL), set it to InvalidOid to reset the catalogued AM.
14741  */
14742  if (amname != NULL)
14743  amoid = get_table_am_oid(amname, false);
14744  else if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
14745  amoid = InvalidOid;
14746  else
14748 
14749  /* if it's a match, phase 3 doesn't need to do anything */
14750  if (rel->rd_rel->relam == amoid)
14751  return;
14752 
14753  /* Save info for Phase 3 to do the real work */
14755  tab->newAccessMethod = amoid;
14756  tab->chgAccessMethod = true;
14757 }
14758 
14759 /*
14760  * Special handling of ALTER TABLE SET ACCESS METHOD for relations with no
14761  * storage that have an interest in preserving AM.
14762  *
14763  * Since these have no storage, setting the access method is a catalog only
14764  * operation.
14765  */
14766 static void
14768 {
14769  Relation pg_class;
14770  Oid oldAccessMethodId;
14771  HeapTuple tuple;
14772  Form_pg_class rd_rel;
14773  Oid reloid = RelationGetRelid(rel);
14774 
14775  /*
14776  * Shouldn't be called on relations having storage; these are processed in
14777  * phase 3.
14778  */
14779  Assert(!RELKIND_HAS_STORAGE(rel->rd_rel->relkind));
14780 
14781  /* Get a modifiable copy of the relation's pg_class row. */
14782  pg_class = table_open(RelationRelationId, RowExclusiveLock);
14783 
14784  tuple = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(reloid));
14785  if (!HeapTupleIsValid(tuple))
14786  elog(ERROR, "cache lookup failed for relation %u", reloid);
14787  rd_rel = (Form_pg_class) GETSTRUCT(tuple);
14788 
14789  /* Update the pg_class row. */
14790  oldAccessMethodId = rd_rel->relam;
14791  rd_rel->relam = newAccessMethodId;
14792 
14793  /* Leave if no update required */
14794  if (rd_rel->relam == oldAccessMethodId)
14795  {
14796  heap_freetuple(tuple);
14797  table_close(pg_class, RowExclusiveLock);
14798  return;
14799  }
14800 
14801  CatalogTupleUpdate(pg_class, &tuple->t_self, tuple);
14802 
14803  /*
14804  * Update the dependency on the new access method. No dependency is added
14805  * if the new access method is InvalidOid (default case). Be very careful
14806  * that this has to compare the previous value stored in pg_class with the
14807  * new one.
14808  */
14809  if (!OidIsValid(oldAccessMethodId) && OidIsValid(rd_rel->relam))
14810  {
14811  ObjectAddress relobj,
14812  referenced;
14813 
14814  /*
14815  * New access method is defined and there was no dependency
14816  * previously, so record a new one.
14817  */
14818  ObjectAddressSet(relobj, RelationRelationId, reloid);
14819  ObjectAddressSet(referenced, AccessMethodRelationId, rd_rel->relam);
14820  recordDependencyOn(&relobj, &referenced, DEPENDENCY_NORMAL);
14821  }
14822  else if (OidIsValid(oldAccessMethodId) &&
14823  !OidIsValid(rd_rel->relam))
14824  {
14825  /*
14826  * There was an access method defined, and no new one, so just remove
14827  * the existing dependency.
14828  */
14829  deleteDependencyRecordsForClass(RelationRelationId, reloid,
14830  AccessMethodRelationId,
14832  }
14833  else
14834  {
14835  Assert(OidIsValid(oldAccessMethodId) &&
14836  OidIsValid(rd_rel->relam));
14837 
14838  /* Both are valid, so update the dependency */
14839  changeDependencyFor(RelationRelationId, reloid,
14840  AccessMethodRelationId,
14841  oldAccessMethodId, rd_rel->relam);
14842  }
14843 
14844  /* make the relam and dependency changes visible */
14846 
14847  InvokeObjectPostAlterHook(RelationRelationId, RelationGetRelid(rel), 0);
14848 
14849  heap_freetuple(tuple);
14850  table_close(pg_class, RowExclusiveLock);
14851 }
14852 
14853 /*
14854  * ALTER TABLE SET TABLESPACE
14855  */
14856 static void
14857 ATPrepSetTableSpace(AlteredTableInfo *tab, Relation rel, const char *tablespacename, LOCKMODE lockmode)
14858 {
14859  Oid tablespaceId;
14860 
14861  /* Check that the tablespace exists */
14862  tablespaceId = get_tablespace_oid(tablespacename, false);
14863 
14864  /* Check permissions except when moving to database's default */
14865  if (OidIsValid(tablespaceId) && tablespaceId != MyDatabaseTableSpace)
14866  {
14867  AclResult aclresult;
14868 
14869  aclresult = object_aclcheck(TableSpaceRelationId, tablespaceId, GetUserId(), ACL_CREATE);
14870  if (aclresult != ACLCHECK_OK)
14871  aclcheck_error(aclresult, OBJECT_TABLESPACE, tablespacename);
14872  }
14873 
14874  /* Save info for Phase 3 to do the real work */
14875  if (OidIsValid(tab->newTableSpace))
14876  ereport(ERROR,
14877  (errcode(ERRCODE_SYNTAX_ERROR),
14878  errmsg("cannot have multiple SET TABLESPACE subcommands")));
14879 
14880  tab->newTableSpace = tablespaceId;
14881 }
14882 
14883 /*
14884  * Set, reset, or replace reloptions.
14885  */
14886 static void
14888  LOCKMODE lockmode)
14889 {
14890  Oid relid;
14891  Relation pgclass;
14892  HeapTuple tuple;
14893  HeapTuple newtuple;
14894  Datum datum;
14895  bool isnull;
14896  Datum newOptions;
14897  Datum repl_val[Natts_pg_class];
14898  bool repl_null[Natts_pg_class];
14899  bool repl_repl[Natts_pg_class];
14900  static char *validnsps[] = HEAP_RELOPT_NAMESPACES;
14901 
14902  if (defList == NIL && operation != AT_ReplaceRelOptions)
14903  return; /* nothing to do */
14904 
14905  pgclass = table_open(RelationRelationId, RowExclusiveLock);
14906 
14907  /* Fetch heap tuple */
14908  relid = RelationGetRelid(rel);
14909  tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
14910  if (!HeapTupleIsValid(tuple))
14911  elog(ERROR, "cache lookup failed for relation %u", relid);
14912 
14913  if (operation == AT_ReplaceRelOptions)
14914  {
14915  /*
14916  * If we're supposed to replace the reloptions list, we just pretend
14917  * there were none before.
14918  */
14919  datum = (Datum) 0;
14920  isnull = true;
14921  }
14922  else
14923  {
14924  /* Get the old reloptions */
14925  datum = SysCacheGetAttr(RELOID, tuple, Anum_pg_class_reloptions,
14926  &isnull);
14927  }
14928 
14929  /* Generate new proposed reloptions (text array) */
14930  newOptions = transformRelOptions(isnull ? (Datum) 0 : datum,
14931  defList, NULL, validnsps, false,
14932  operation == AT_ResetRelOptions);
14933 
14934  /* Validate */
14935  switch (rel->rd_rel->relkind)
14936  {
14937  case RELKIND_RELATION:
14938  case RELKIND_TOASTVALUE:
14939  case RELKIND_MATVIEW:
14940  (void) heap_reloptions(rel->rd_rel->relkind, newOptions, true);
14941  break;
14942  case RELKIND_PARTITIONED_TABLE:
14943  (void) partitioned_table_reloptions(newOptions, true);
14944  break;
14945  case RELKIND_VIEW:
14946  (void) view_reloptions(newOptions, true);
14947  break;
14948  case RELKIND_INDEX:
14949  case RELKIND_PARTITIONED_INDEX:
14950  (void) index_reloptions(rel->rd_indam->amoptions, newOptions, true);
14951  break;
14952  default:
14953  ereport(ERROR,
14954  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
14955  errmsg("cannot set options for relation \"%s\"",
14957  errdetail_relkind_not_supported(rel->rd_rel->relkind)));
14958  break;
14959  }
14960 
14961  /* Special-case validation of view options */
14962  if (rel->rd_rel->relkind == RELKIND_VIEW)
14963  {
14964  Query *view_query = get_view_query(rel);
14965  List *view_options = untransformRelOptions(newOptions);
14966  ListCell *cell;
14967  bool check_option = false;
14968 
14969  foreach(cell, view_options)
14970  {
14971  DefElem *defel = (DefElem *) lfirst(cell);
14972 
14973  if (strcmp(defel->defname, "check_option") == 0)
14974  check_option = true;
14975  }
14976 
14977  /*
14978  * If the check option is specified, look to see if the view is
14979  * actually auto-updatable or not.
14980  */
14981  if (check_option)
14982  {
14983  const char *view_updatable_error =
14984  view_query_is_auto_updatable(view_query, true);
14985 
14986  if (view_updatable_error)
14987  ereport(ERROR,
14988  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
14989  errmsg("WITH CHECK OPTION is supported only on automatically updatable views"),
14990  errhint("%s", _(view_updatable_error))));
14991  }
14992  }
14993 
14994  /*
14995  * All we need do here is update the pg_class row; the new options will be
14996  * propagated into relcaches during post-commit cache inval.
14997  */
14998  memset(repl_val, 0, sizeof(repl_val));
14999  memset(repl_null, false, sizeof(repl_null));
15000  memset(repl_repl, false, sizeof(repl_repl));
15001 
15002  if (newOptions != (Datum) 0)
15003  repl_val[Anum_pg_class_reloptions - 1] = newOptions;
15004  else
15005  repl_null[Anum_pg_class_reloptions - 1] = true;
15006 
15007  repl_repl[Anum_pg_class_reloptions - 1] = true;
15008 
15009  newtuple = heap_modify_tuple(tuple, RelationGetDescr(pgclass),
15010  repl_val, repl_null, repl_repl);
15011 
15012  CatalogTupleUpdate(pgclass, &newtuple->t_self, newtuple);
15013 
15014  InvokeObjectPostAlterHook(RelationRelationId, RelationGetRelid(rel), 0);
15015 
15016  heap_freetuple(newtuple);
15017 
15018  ReleaseSysCache(tuple);
15019 
15020  /* repeat the whole exercise for the toast table, if there's one */
15021  if (OidIsValid(rel->rd_rel->reltoastrelid))
15022  {
15023  Relation toastrel;
15024  Oid toastid = rel->rd_rel->reltoastrelid;
15025 
15026  toastrel = table_open(toastid, lockmode);
15027 
15028  /* Fetch heap tuple */
15029  tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(toastid));
15030  if (!HeapTupleIsValid(tuple))
15031  elog(ERROR, "cache lookup failed for relation %u", toastid);
15032 
15033  if (operation == AT_ReplaceRelOptions)
15034  {
15035  /*
15036  * If we're supposed to replace the reloptions list, we just
15037  * pretend there were none before.
15038  */
15039  datum = (Datum) 0;
15040  isnull = true;
15041  }
15042  else
15043  {
15044  /* Get the old reloptions */
15045  datum = SysCacheGetAttr(RELOID, tuple, Anum_pg_class_reloptions,
15046  &isnull);
15047  }
15048 
15049  newOptions = transformRelOptions(isnull ? (Datum) 0 : datum,
15050  defList, "toast", validnsps, false,
15051  operation == AT_ResetRelOptions);
15052 
15053  (void) heap_reloptions(RELKIND_TOASTVALUE, newOptions, true);
15054 
15055  memset(repl_val, 0, sizeof(repl_val));
15056  memset(repl_null, false, sizeof(repl_null));
15057  memset(repl_repl, false, sizeof(repl_repl));
15058 
15059  if (newOptions != (Datum) 0)
15060  repl_val[Anum_pg_class_reloptions - 1] = newOptions;
15061  else
15062  repl_null[Anum_pg_class_reloptions - 1] = true;
15063 
15064  repl_repl[Anum_pg_class_reloptions - 1] = true;
15065 
15066  newtuple = heap_modify_tuple(tuple, RelationGetDescr(pgclass),
15067  repl_val, repl_null, repl_repl);
15068 
15069  CatalogTupleUpdate(pgclass, &newtuple->t_self, newtuple);
15070 
15071  InvokeObjectPostAlterHookArg(RelationRelationId,
15072  RelationGetRelid(toastrel), 0,
15073  InvalidOid, true);
15074 
15075  heap_freetuple(newtuple);
15076 
15077  ReleaseSysCache(tuple);
15078 
15079  table_close(toastrel, NoLock);
15080  }
15081 
15082  table_close(pgclass, RowExclusiveLock);
15083 }
15084 
15085 /*
15086  * Execute ALTER TABLE SET TABLESPACE for cases where there is no tuple
15087  * rewriting to be done, so we just want to copy the data as fast as possible.
15088  */
15089 static void
15090 ATExecSetTableSpace(Oid tableOid, Oid newTableSpace, LOCKMODE lockmode)
15091 {
15092  Relation rel;
15093  Oid reltoastrelid;
15094  RelFileNumber newrelfilenumber;
15095  RelFileLocator newrlocator;
15096  List *reltoastidxids = NIL;
15097  ListCell *lc;
15098 
15099  /*
15100  * Need lock here in case we are recursing to toast table or index
15101  */
15102  rel = relation_open(tableOid, lockmode);
15103 
15104  /* Check first if relation can be moved to new tablespace */
15105  if (!CheckRelationTableSpaceMove(rel, newTableSpace))
15106  {
15107  InvokeObjectPostAlterHook(RelationRelationId,
15108  RelationGetRelid(rel), 0);
15109  relation_close(rel, NoLock);
15110  return;
15111  }
15112 
15113  reltoastrelid = rel->rd_rel->reltoastrelid;
15114  /* Fetch the list of indexes on toast relation if necessary */
15115  if (OidIsValid(reltoastrelid))
15116  {
15117  Relation toastRel = relation_open(reltoastrelid, lockmode);
15118 
15119  reltoastidxids = RelationGetIndexList(toastRel);
15120  relation_close(toastRel, lockmode);
15121  }
15122 
15123  /*
15124  * Relfilenumbers are not unique in databases across tablespaces, so we
15125  * need to allocate a new one in the new tablespace.
15126  */
15127  newrelfilenumber = GetNewRelFileNumber(newTableSpace, NULL,
15128  rel->rd_rel->relpersistence);
15129 
15130  /* Open old and new relation */
15131  newrlocator = rel->rd_locator;
15132  newrlocator.relNumber = newrelfilenumber;
15133  newrlocator.spcOid = newTableSpace;
15134 
15135  /* hand off to AM to actually create new rel storage and copy the data */
15136  if (rel->rd_rel->relkind == RELKIND_INDEX)
15137  {
15138  index_copy_data(rel, newrlocator);
15139  }
15140  else
15141  {
15142  Assert(RELKIND_HAS_TABLE_AM(rel->rd_rel->relkind));
15143  table_relation_copy_data(rel, &newrlocator);
15144  }
15145 
15146  /*
15147  * Update the pg_class row.
15148  *
15149  * NB: This wouldn't work if ATExecSetTableSpace() were allowed to be
15150  * executed on pg_class or its indexes (the above copy wouldn't contain
15151  * the updated pg_class entry), but that's forbidden with
15152  * CheckRelationTableSpaceMove().
15153  */
15154  SetRelationTableSpace(rel, newTableSpace, newrelfilenumber);
15155 
15156  InvokeObjectPostAlterHook(RelationRelationId, RelationGetRelid(rel), 0);
15157 
15159 
15160  relation_close(rel, NoLock);
15161 
15162  /* Make sure the reltablespace change is visible */
15164 
15165  /* Move associated toast relation and/or indexes, too */
15166  if (OidIsValid(reltoastrelid))
15167  ATExecSetTableSpace(reltoastrelid, newTableSpace, lockmode);
15168  foreach(lc, reltoastidxids)
15169  ATExecSetTableSpace(lfirst_oid(lc), newTableSpace, lockmode);
15170 
15171  /* Clean up */
15172  list_free(reltoastidxids);
15173 }
15174 
15175 /*
15176  * Special handling of ALTER TABLE SET TABLESPACE for relations with no
15177  * storage that have an interest in preserving tablespace.
15178  *
15179  * Since these have no storage the tablespace can be updated with a simple
15180  * metadata only operation to update the tablespace.
15181  */
15182 static void
15184 {
15185  /*
15186  * Shouldn't be called on relations having storage; these are processed in
15187  * phase 3.
15188  */
15189  Assert(!RELKIND_HAS_STORAGE(rel->rd_rel->relkind));
15190 
15191  /* check if relation can be moved to its new tablespace */
15192  if (!CheckRelationTableSpaceMove(rel, newTableSpace))
15193  {
15194  InvokeObjectPostAlterHook(RelationRelationId,
15195  RelationGetRelid(rel),
15196  0);
15197  return;
15198  }
15199 
15200  /* Update can be done, so change reltablespace */
15201  SetRelationTableSpace(rel, newTableSpace, InvalidOid);
15202 
15203  InvokeObjectPostAlterHook(RelationRelationId, RelationGetRelid(rel), 0);
15204 
15205  /* Make sure the reltablespace change is visible */
15207 }
15208 
15209 /*
15210  * Alter Table ALL ... SET TABLESPACE
15211  *
15212  * Allows a user to move all objects of some type in a given tablespace in the
15213  * current database to another tablespace. Objects can be chosen based on the
15214  * owner of the object also, to allow users to move only their objects.
15215  * The user must have CREATE rights on the new tablespace, as usual. The main
15216  * permissions handling is done by the lower-level table move function.
15217  *
15218  * All to-be-moved objects are locked first. If NOWAIT is specified and the
15219  * lock can't be acquired then we ereport(ERROR).
15220  */
15221 Oid
15223 {
15224  List *relations = NIL;
15225  ListCell *l;
15226  ScanKeyData key[1];
15227  Relation rel;
15228  TableScanDesc scan;
15229  HeapTuple tuple;
15230  Oid orig_tablespaceoid;
15231  Oid new_tablespaceoid;
15232  List *role_oids = roleSpecsToIds(stmt->roles);
15233 
15234  /* Ensure we were not asked to move something we can't */
15235  if (stmt->objtype != OBJECT_TABLE && stmt->objtype != OBJECT_INDEX &&
15236  stmt->objtype != OBJECT_MATVIEW)
15237  ereport(ERROR,
15238  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
15239  errmsg("only tables, indexes, and materialized views exist in tablespaces")));
15240 
15241  /* Get the orig and new tablespace OIDs */
15242  orig_tablespaceoid = get_tablespace_oid(stmt->orig_tablespacename, false);
15243  new_tablespaceoid = get_tablespace_oid(stmt->new_tablespacename, false);
15244 
15245  /* Can't move shared relations in to or out of pg_global */
15246  /* This is also checked by ATExecSetTableSpace, but nice to stop earlier */
15247  if (orig_tablespaceoid == GLOBALTABLESPACE_OID ||
15248  new_tablespaceoid == GLOBALTABLESPACE_OID)
15249  ereport(ERROR,
15250  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
15251  errmsg("cannot move relations in to or out of pg_global tablespace")));
15252 
15253  /*
15254  * Must have CREATE rights on the new tablespace, unless it is the
15255  * database default tablespace (which all users implicitly have CREATE
15256  * rights on).
15257  */
15258  if (OidIsValid(new_tablespaceoid) && new_tablespaceoid != MyDatabaseTableSpace)
15259  {
15260  AclResult aclresult;
15261 
15262  aclresult = object_aclcheck(TableSpaceRelationId, new_tablespaceoid, GetUserId(),
15263  ACL_CREATE);
15264  if (aclresult != ACLCHECK_OK)
15265  aclcheck_error(aclresult, OBJECT_TABLESPACE,
15266  get_tablespace_name(new_tablespaceoid));
15267  }
15268 
15269  /*
15270  * Now that the checks are done, check if we should set either to
15271  * InvalidOid because it is our database's default tablespace.
15272  */
15273  if (orig_tablespaceoid == MyDatabaseTableSpace)
15274  orig_tablespaceoid = InvalidOid;
15275 
15276  if (new_tablespaceoid == MyDatabaseTableSpace)
15277  new_tablespaceoid = InvalidOid;
15278 
15279  /* no-op */
15280  if (orig_tablespaceoid == new_tablespaceoid)
15281  return new_tablespaceoid;
15282 
15283  /*
15284  * Walk the list of objects in the tablespace and move them. This will
15285  * only find objects in our database, of course.
15286  */
15287  ScanKeyInit(&key[0],
15288  Anum_pg_class_reltablespace,
15289  BTEqualStrategyNumber, F_OIDEQ,
15290  ObjectIdGetDatum(orig_tablespaceoid));
15291 
15292  rel = table_open(RelationRelationId, AccessShareLock);
15293  scan = table_beginscan_catalog(rel, 1, key);
15294  while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
15295  {
15296  Form_pg_class relForm = (Form_pg_class) GETSTRUCT(tuple);
15297  Oid relOid = relForm->oid;
15298 
15299  /*
15300  * Do not move objects in pg_catalog as part of this, if an admin
15301  * really wishes to do so, they can issue the individual ALTER
15302  * commands directly.
15303  *
15304  * Also, explicitly avoid any shared tables, temp tables, or TOAST
15305  * (TOAST will be moved with the main table).
15306  */
15307  if (IsCatalogNamespace(relForm->relnamespace) ||
15308  relForm->relisshared ||
15309  isAnyTempNamespace(relForm->relnamespace) ||
15310  IsToastNamespace(relForm->relnamespace))
15311  continue;
15312 
15313  /* Only move the object type requested */
15314  if ((stmt->objtype == OBJECT_TABLE &&
15315  relForm->relkind != RELKIND_RELATION &&
15316  relForm->relkind != RELKIND_PARTITIONED_TABLE) ||
15317  (stmt->objtype == OBJECT_INDEX &&
15318  relForm->relkind != RELKIND_INDEX &&
15319  relForm->relkind != RELKIND_PARTITIONED_INDEX) ||
15320  (stmt->objtype == OBJECT_MATVIEW &&
15321  relForm->relkind != RELKIND_MATVIEW))
15322  continue;
15323 
15324  /* Check if we are only moving objects owned by certain roles */
15325  if (role_oids != NIL && !list_member_oid(role_oids, relForm->relowner))
15326  continue;
15327 
15328  /*
15329  * Handle permissions-checking here since we are locking the tables
15330  * and also to avoid doing a bunch of work only to fail part-way. Note
15331  * that permissions will also be checked by AlterTableInternal().
15332  *
15333  * Caller must be considered an owner on the table to move it.
15334  */
15335  if (!object_ownercheck(RelationRelationId, relOid, GetUserId()))
15337  NameStr(relForm->relname));
15338 
15339  if (stmt->nowait &&
15341  ereport(ERROR,
15342  (errcode(ERRCODE_OBJECT_IN_USE),
15343  errmsg("aborting because lock on relation \"%s.%s\" is not available",
15344  get_namespace_name(relForm->relnamespace),
15345  NameStr(relForm->relname))));
15346  else
15348 
15349  /* Add to our list of objects to move */
15350  relations = lappend_oid(relations, relOid);
15351  }
15352 
15353  table_endscan(scan);
15355 
15356  if (relations == NIL)
15357  ereport(NOTICE,
15358  (errcode(ERRCODE_NO_DATA_FOUND),
15359  errmsg("no matching relations in tablespace \"%s\" found",
15360  orig_tablespaceoid == InvalidOid ? "(database default)" :
15361  get_tablespace_name(orig_tablespaceoid))));
15362 
15363  /* Everything is locked, loop through and move all of the relations. */
15364  foreach(l, relations)
15365  {
15366  List *cmds = NIL;
15368 
15369  cmd->subtype = AT_SetTableSpace;
15370  cmd->name = stmt->new_tablespacename;
15371 
15372  cmds = lappend(cmds, cmd);
15373 
15375  /* OID is set by AlterTableInternal */
15376  AlterTableInternal(lfirst_oid(l), cmds, false);
15378  }
15379 
15380  return new_tablespaceoid;
15381 }
15382 
15383 static void
15385 {
15386  SMgrRelation dstrel;
15387 
15388  /*
15389  * Since we copy the file directly without looking at the shared buffers,
15390  * we'd better first flush out any pages of the source relation that are
15391  * in shared buffers. We assume no new changes will be made while we are
15392  * holding exclusive lock on the rel.
15393  */
15394  FlushRelationBuffers(rel);
15395 
15396  /*
15397  * Create and copy all forks of the relation, and schedule unlinking of
15398  * old physical files.
15399  *
15400  * NOTE: any conflict in relfilenumber value will be caught in
15401  * RelationCreateStorage().
15402  */
15403  dstrel = RelationCreateStorage(newrlocator, rel->rd_rel->relpersistence, true);
15404 
15405  /* copy main fork */
15407  rel->rd_rel->relpersistence);
15408 
15409  /* copy those extra forks that exist */
15410  for (ForkNumber forkNum = MAIN_FORKNUM + 1;
15411  forkNum <= MAX_FORKNUM; forkNum++)
15412  {
15413  if (smgrexists(RelationGetSmgr(rel), forkNum))
15414  {
15415  smgrcreate(dstrel, forkNum, false);
15416 
15417  /*
15418  * WAL log creation if the relation is persistent, or this is the
15419  * init fork of an unlogged relation.
15420  */
15421  if (RelationIsPermanent(rel) ||
15422  (rel->rd_rel->relpersistence == RELPERSISTENCE_UNLOGGED &&
15423  forkNum == INIT_FORKNUM))
15424  log_smgrcreate(&newrlocator, forkNum);
15425  RelationCopyStorage(RelationGetSmgr(rel), dstrel, forkNum,
15426  rel->rd_rel->relpersistence);
15427  }
15428  }
15429 
15430  /* drop old relation, and close new one */
15431  RelationDropStorage(rel);
15432  smgrclose(dstrel);
15433 }
15434 
15435 /*
15436  * ALTER TABLE ENABLE/DISABLE TRIGGER
15437  *
15438  * We just pass this off to trigger.c.
15439  */
15440 static void
15441 ATExecEnableDisableTrigger(Relation rel, const char *trigname,
15442  char fires_when, bool skip_system, bool recurse,
15443  LOCKMODE lockmode)
15444 {
15445  EnableDisableTrigger(rel, trigname, InvalidOid,
15446  fires_when, skip_system, recurse,
15447  lockmode);
15448 
15449  InvokeObjectPostAlterHook(RelationRelationId,
15450  RelationGetRelid(rel), 0);
15451 }
15452 
15453 /*
15454  * ALTER TABLE ENABLE/DISABLE RULE
15455  *
15456  * We just pass this off to rewriteDefine.c.
15457  */
15458 static void
15459 ATExecEnableDisableRule(Relation rel, const char *rulename,
15460  char fires_when, LOCKMODE lockmode)
15461 {
15462  EnableDisableRule(rel, rulename, fires_when);
15463 
15464  InvokeObjectPostAlterHook(RelationRelationId,
15465  RelationGetRelid(rel), 0);
15466 }
15467 
15468 /*
15469  * ALTER TABLE INHERIT
15470  *
15471  * Add a parent to the child's parents. This verifies that all the columns and
15472  * check constraints of the parent appear in the child and that they have the
15473  * same data types and expressions.
15474  */
15475 static void
15477 {
15478  if (child_rel->rd_rel->reloftype)
15479  ereport(ERROR,
15480  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
15481  errmsg("cannot change inheritance of typed table")));
15482 
15483  if (child_rel->rd_rel->relispartition)
15484  ereport(ERROR,
15485  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
15486  errmsg("cannot change inheritance of a partition")));
15487 
15488  if (child_rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
15489  ereport(ERROR,
15490  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
15491  errmsg("cannot change inheritance of partitioned table")));
15492 }
15493 
15494 /*
15495  * Return the address of the new parent relation.
15496  */
15497 static ObjectAddress
15498 ATExecAddInherit(Relation child_rel, RangeVar *parent, LOCKMODE lockmode)
15499 {
15500  Relation parent_rel;
15501  List *children;
15502  ObjectAddress address;
15503  const char *trigger_name;
15504 
15505  /*
15506  * A self-exclusive lock is needed here. See the similar case in
15507  * MergeAttributes() for a full explanation.
15508  */
15509  parent_rel = table_openrv(parent, ShareUpdateExclusiveLock);
15510 
15511  /*
15512  * Must be owner of both parent and child -- child was checked by
15513  * ATSimplePermissions call in ATPrepCmd
15514  */
15516 
15517  /* Permanent rels cannot inherit from temporary ones */
15518  if (parent_rel->rd_rel->relpersistence == RELPERSISTENCE_TEMP &&
15519  child_rel->rd_rel->relpersistence != RELPERSISTENCE_TEMP)
15520  ereport(ERROR,
15521  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
15522  errmsg("cannot inherit from temporary relation \"%s\"",
15523  RelationGetRelationName(parent_rel))));
15524 
15525  /* If parent rel is temp, it must belong to this session */
15526  if (parent_rel->rd_rel->relpersistence == RELPERSISTENCE_TEMP &&
15527  !parent_rel->rd_islocaltemp)
15528  ereport(ERROR,
15529  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
15530  errmsg("cannot inherit from temporary relation of another session")));
15531 
15532  /* Ditto for the child */
15533  if (child_rel->rd_rel->relpersistence == RELPERSISTENCE_TEMP &&
15534  !child_rel->rd_islocaltemp)
15535  ereport(ERROR,
15536  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
15537  errmsg("cannot inherit to temporary relation of another session")));
15538 
15539  /* Prevent partitioned tables from becoming inheritance parents */
15540  if (parent_rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
15541  ereport(ERROR,
15542  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
15543  errmsg("cannot inherit from partitioned table \"%s\"",
15544  parent->relname)));
15545 
15546  /* Likewise for partitions */
15547  if (parent_rel->rd_rel->relispartition)
15548  ereport(ERROR,
15549  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
15550  errmsg("cannot inherit from a partition")));
15551 
15552  /*
15553  * Prevent circularity by seeing if proposed parent inherits from child.
15554  * (In particular, this disallows making a rel inherit from itself.)
15555  *
15556  * This is not completely bulletproof because of race conditions: in
15557  * multi-level inheritance trees, someone else could concurrently be
15558  * making another inheritance link that closes the loop but does not join
15559  * either of the rels we have locked. Preventing that seems to require
15560  * exclusive locks on the entire inheritance tree, which is a cure worse
15561  * than the disease. find_all_inheritors() will cope with circularity
15562  * anyway, so don't sweat it too much.
15563  *
15564  * We use weakest lock we can on child's children, namely AccessShareLock.
15565  */
15566  children = find_all_inheritors(RelationGetRelid(child_rel),
15567  AccessShareLock, NULL);
15568 
15569  if (list_member_oid(children, RelationGetRelid(parent_rel)))
15570  ereport(ERROR,
15571  (errcode(ERRCODE_DUPLICATE_TABLE),
15572  errmsg("circular inheritance not allowed"),
15573  errdetail("\"%s\" is already a child of \"%s\".",
15574  parent->relname,
15575  RelationGetRelationName(child_rel))));
15576 
15577  /*
15578  * If child_rel has row-level triggers with transition tables, we
15579  * currently don't allow it to become an inheritance child. See also
15580  * prohibitions in ATExecAttachPartition() and CreateTrigger().
15581  */
15582  trigger_name = FindTriggerIncompatibleWithInheritance(child_rel->trigdesc);
15583  if (trigger_name != NULL)
15584  ereport(ERROR,
15585  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
15586  errmsg("trigger \"%s\" prevents table \"%s\" from becoming an inheritance child",
15587  trigger_name, RelationGetRelationName(child_rel)),
15588  errdetail("ROW triggers with transition tables are not supported in inheritance hierarchies.")));
15589 
15590  /* OK to create inheritance */
15591  CreateInheritance(child_rel, parent_rel, false);
15592 
15593  ObjectAddressSet(address, RelationRelationId,
15594  RelationGetRelid(parent_rel));
15595 
15596  /* keep our lock on the parent relation until commit */
15597  table_close(parent_rel, NoLock);
15598 
15599  return address;
15600 }
15601 
15602 /*
15603  * CreateInheritance
15604  * Catalog manipulation portion of creating inheritance between a child
15605  * table and a parent table.
15606  *
15607  * Common to ATExecAddInherit() and ATExecAttachPartition().
15608  */
15609 static void
15610 CreateInheritance(Relation child_rel, Relation parent_rel, bool ispartition)
15611 {
15612  Relation catalogRelation;
15613  SysScanDesc scan;
15614  ScanKeyData key;
15615  HeapTuple inheritsTuple;
15616  int32 inhseqno;
15617 
15618  /* Note: get RowExclusiveLock because we will write pg_inherits below. */
15619  catalogRelation = table_open(InheritsRelationId, RowExclusiveLock);
15620 
15621  /*
15622  * Check for duplicates in the list of parents, and determine the highest
15623  * inhseqno already present; we'll use the next one for the new parent.
15624  * Also, if proposed child is a partition, it cannot already be
15625  * inheriting.
15626  *
15627  * Note: we do not reject the case where the child already inherits from
15628  * the parent indirectly; CREATE TABLE doesn't reject comparable cases.
15629  */
15630  ScanKeyInit(&key,
15631  Anum_pg_inherits_inhrelid,
15632  BTEqualStrategyNumber, F_OIDEQ,
15633  ObjectIdGetDatum(RelationGetRelid(child_rel)));
15634  scan = systable_beginscan(catalogRelation, InheritsRelidSeqnoIndexId,
15635  true, NULL, 1, &key);
15636 
15637  /* inhseqno sequences start at 1 */
15638  inhseqno = 0;
15639  while (HeapTupleIsValid(inheritsTuple = systable_getnext(scan)))
15640  {
15641  Form_pg_inherits inh = (Form_pg_inherits) GETSTRUCT(inheritsTuple);
15642 
15643  if (inh->inhparent == RelationGetRelid(parent_rel))
15644  ereport(ERROR,
15645  (errcode(ERRCODE_DUPLICATE_TABLE),
15646  errmsg("relation \"%s\" would be inherited from more than once",
15647  RelationGetRelationName(parent_rel))));
15648 
15649  if (inh->inhseqno > inhseqno)
15650  inhseqno = inh->inhseqno;
15651  }
15652  systable_endscan(scan);
15653 
15654  /* Match up the columns and bump attinhcount as needed */
15655  MergeAttributesIntoExisting(child_rel, parent_rel, ispartition);
15656 
15657  /* Match up the constraints and bump coninhcount as needed */
15658  MergeConstraintsIntoExisting(child_rel, parent_rel);
15659 
15660  /*
15661  * OK, it looks valid. Make the catalog entries that show inheritance.
15662  */
15664  RelationGetRelid(parent_rel),
15665  inhseqno + 1,
15666  catalogRelation,
15667  parent_rel->rd_rel->relkind ==
15668  RELKIND_PARTITIONED_TABLE);
15669 
15670  /* Now we're done with pg_inherits */
15671  table_close(catalogRelation, RowExclusiveLock);
15672 }
15673 
15674 /*
15675  * Obtain the source-text form of the constraint expression for a check
15676  * constraint, given its pg_constraint tuple
15677  */
15678 static char *
15680 {
15681  Form_pg_constraint con;
15682  bool isnull;
15683  Datum attr;
15684  Datum expr;
15685 
15686  con = (Form_pg_constraint) GETSTRUCT(contup);
15687  attr = heap_getattr(contup, Anum_pg_constraint_conbin, tupdesc, &isnull);
15688  if (isnull)
15689  elog(ERROR, "null conbin for constraint %u", con->oid);
15690 
15691  expr = DirectFunctionCall2(pg_get_expr, attr,
15692  ObjectIdGetDatum(con->conrelid));
15693  return TextDatumGetCString(expr);
15694 }
15695 
15696 /*
15697  * Determine whether two check constraints are functionally equivalent
15698  *
15699  * The test we apply is to see whether they reverse-compile to the same
15700  * source string. This insulates us from issues like whether attributes
15701  * have the same physical column numbers in parent and child relations.
15702  */
15703 static bool
15705 {
15708 
15709  if (acon->condeferrable != bcon->condeferrable ||
15710  acon->condeferred != bcon->condeferred ||
15711  strcmp(decompile_conbin(a, tupleDesc),
15712  decompile_conbin(b, tupleDesc)) != 0)
15713  return false;
15714  else
15715  return true;
15716 }
15717 
15718 /*
15719  * Check columns in child table match up with columns in parent, and increment
15720  * their attinhcount.
15721  *
15722  * Called by CreateInheritance
15723  *
15724  * Currently all parent columns must be found in child. Missing columns are an
15725  * error. One day we might consider creating new columns like CREATE TABLE
15726  * does. However, that is widely unpopular --- in the common use case of
15727  * partitioned tables it's a foot-gun.
15728  *
15729  * The data type must match exactly. If the parent column is NOT NULL then
15730  * the child must be as well. Defaults are not compared, however.
15731  */
15732 static void
15733 MergeAttributesIntoExisting(Relation child_rel, Relation parent_rel, bool ispartition)
15734 {
15735  Relation attrrel;
15736  TupleDesc parent_desc;
15737 
15738  attrrel = table_open(AttributeRelationId, RowExclusiveLock);
15739  parent_desc = RelationGetDescr(parent_rel);
15740 
15741  for (AttrNumber parent_attno = 1; parent_attno <= parent_desc->natts; parent_attno++)
15742  {
15743  Form_pg_attribute parent_att = TupleDescAttr(parent_desc, parent_attno - 1);
15744  char *parent_attname = NameStr(parent_att->attname);
15745  HeapTuple tuple;
15746 
15747  /* Ignore dropped columns in the parent. */
15748  if (parent_att->attisdropped)
15749  continue;
15750 
15751  /* Find same column in child (matching on column name). */
15752  tuple = SearchSysCacheCopyAttName(RelationGetRelid(child_rel), parent_attname);
15753  if (HeapTupleIsValid(tuple))
15754  {
15755  Form_pg_attribute child_att = (Form_pg_attribute) GETSTRUCT(tuple);
15756 
15757  if (parent_att->atttypid != child_att->atttypid ||
15758  parent_att->atttypmod != child_att->atttypmod)
15759  ereport(ERROR,
15760  (errcode(ERRCODE_DATATYPE_MISMATCH),
15761  errmsg("child table \"%s\" has different type for column \"%s\"",
15762  RelationGetRelationName(child_rel), parent_attname)));
15763 
15764  if (parent_att->attcollation != child_att->attcollation)
15765  ereport(ERROR,
15766  (errcode(ERRCODE_COLLATION_MISMATCH),
15767  errmsg("child table \"%s\" has different collation for column \"%s\"",
15768  RelationGetRelationName(child_rel), parent_attname)));
15769 
15770  /*
15771  * Check child doesn't discard NOT NULL property. (Other
15772  * constraints are checked elsewhere.)
15773  */
15774  if (parent_att->attnotnull && !child_att->attnotnull)
15775  ereport(ERROR,
15776  (errcode(ERRCODE_DATATYPE_MISMATCH),
15777  errmsg("column \"%s\" in child table must be marked NOT NULL",
15778  parent_attname)));
15779 
15780  /*
15781  * Child column must be generated if and only if parent column is.
15782  */
15783  if (parent_att->attgenerated && !child_att->attgenerated)
15784  ereport(ERROR,
15785  (errcode(ERRCODE_DATATYPE_MISMATCH),
15786  errmsg("column \"%s\" in child table must be a generated column", parent_attname)));
15787  if (child_att->attgenerated && !parent_att->attgenerated)
15788  ereport(ERROR,
15789  (errcode(ERRCODE_DATATYPE_MISMATCH),
15790  errmsg("column \"%s\" in child table must not be a generated column", parent_attname)));
15791 
15792  /*
15793  * Regular inheritance children are independent enough not to
15794  * inherit identity columns. But partitions are integral part of
15795  * a partitioned table and inherit identity column.
15796  */
15797  if (ispartition)
15798  child_att->attidentity = parent_att->attidentity;
15799 
15800  /*
15801  * OK, bump the child column's inheritance count. (If we fail
15802  * later on, this change will just roll back.)
15803  */
15804  child_att->attinhcount++;
15805  if (child_att->attinhcount < 0)
15806  ereport(ERROR,
15807  errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
15808  errmsg("too many inheritance parents"));
15809 
15810  /*
15811  * In case of partitions, we must enforce that value of attislocal
15812  * is same in all partitions. (Note: there are only inherited
15813  * attributes in partitions)
15814  */
15815  if (parent_rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
15816  {
15817  Assert(child_att->attinhcount == 1);
15818  child_att->attislocal = false;
15819  }
15820 
15821  CatalogTupleUpdate(attrrel, &tuple->t_self, tuple);
15822  heap_freetuple(tuple);
15823  }
15824  else
15825  {
15826  ereport(ERROR,
15827  (errcode(ERRCODE_DATATYPE_MISMATCH),
15828  errmsg("child table is missing column \"%s\"", parent_attname)));
15829  }
15830  }
15831 
15832  table_close(attrrel, RowExclusiveLock);
15833 }
15834 
15835 /*
15836  * Check constraints in child table match up with constraints in parent,
15837  * and increment their coninhcount.
15838  *
15839  * Constraints that are marked ONLY in the parent are ignored.
15840  *
15841  * Called by CreateInheritance
15842  *
15843  * Currently all constraints in parent must be present in the child. One day we
15844  * may consider adding new constraints like CREATE TABLE does.
15845  *
15846  * XXX This is O(N^2) which may be an issue with tables with hundreds of
15847  * constraints. As long as tables have more like 10 constraints it shouldn't be
15848  * a problem though. Even 100 constraints ought not be the end of the world.
15849  *
15850  * XXX See MergeWithExistingConstraint too if you change this code.
15851  */
15852 static void
15854 {
15855  Relation constraintrel;
15856  SysScanDesc parent_scan;
15857  ScanKeyData parent_key;
15858  HeapTuple parent_tuple;
15859  Oid parent_relid = RelationGetRelid(parent_rel);
15860 
15861  constraintrel = table_open(ConstraintRelationId, RowExclusiveLock);
15862 
15863  /* Outer loop scans through the parent's constraint definitions */
15864  ScanKeyInit(&parent_key,
15865  Anum_pg_constraint_conrelid,
15866  BTEqualStrategyNumber, F_OIDEQ,
15867  ObjectIdGetDatum(parent_relid));
15868  parent_scan = systable_beginscan(constraintrel, ConstraintRelidTypidNameIndexId,
15869  true, NULL, 1, &parent_key);
15870 
15871  while (HeapTupleIsValid(parent_tuple = systable_getnext(parent_scan)))
15872  {
15873  Form_pg_constraint parent_con = (Form_pg_constraint) GETSTRUCT(parent_tuple);
15874  SysScanDesc child_scan;
15875  ScanKeyData child_key;
15876  HeapTuple child_tuple;
15877  bool found = false;
15878 
15879  if (parent_con->contype != CONSTRAINT_CHECK)
15880  continue;
15881 
15882  /* if the parent's constraint is marked NO INHERIT, it's not inherited */
15883  if (parent_con->connoinherit)
15884  continue;
15885 
15886  /* Search for a child constraint matching this one */
15887  ScanKeyInit(&child_key,
15888  Anum_pg_constraint_conrelid,
15889  BTEqualStrategyNumber, F_OIDEQ,
15890  ObjectIdGetDatum(RelationGetRelid(child_rel)));
15891  child_scan = systable_beginscan(constraintrel, ConstraintRelidTypidNameIndexId,
15892  true, NULL, 1, &child_key);
15893 
15894  while (HeapTupleIsValid(child_tuple = systable_getnext(child_scan)))
15895  {
15896  Form_pg_constraint child_con = (Form_pg_constraint) GETSTRUCT(child_tuple);
15897  HeapTuple child_copy;
15898 
15899  if (child_con->contype != CONSTRAINT_CHECK)
15900  continue;
15901 
15902  if (strcmp(NameStr(parent_con->conname),
15903  NameStr(child_con->conname)) != 0)
15904  continue;
15905 
15906  if (!constraints_equivalent(parent_tuple, child_tuple, RelationGetDescr(constraintrel)))
15907  ereport(ERROR,
15908  (errcode(ERRCODE_DATATYPE_MISMATCH),
15909  errmsg("child table \"%s\" has different definition for check constraint \"%s\"",
15910  RelationGetRelationName(child_rel), NameStr(parent_con->conname))));
15911 
15912  /* If the child constraint is "no inherit" then cannot merge */
15913  if (child_con->connoinherit)
15914  ereport(ERROR,
15915  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
15916  errmsg("constraint \"%s\" conflicts with non-inherited constraint on child table \"%s\"",
15917  NameStr(child_con->conname), RelationGetRelationName(child_rel))));
15918 
15919  /*
15920  * If the child constraint is "not valid" then cannot merge with a
15921  * valid parent constraint
15922  */
15923  if (parent_con->convalidated && !child_con->convalidated)
15924  ereport(ERROR,
15925  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
15926  errmsg("constraint \"%s\" conflicts with NOT VALID constraint on child table \"%s\"",
15927  NameStr(child_con->conname), RelationGetRelationName(child_rel))));
15928 
15929  /*
15930  * OK, bump the child constraint's inheritance count. (If we fail
15931  * later on, this change will just roll back.)
15932  */
15933  child_copy = heap_copytuple(child_tuple);
15934  child_con = (Form_pg_constraint) GETSTRUCT(child_copy);
15935  child_con->coninhcount++;
15936  if (child_con->coninhcount < 0)
15937  ereport(ERROR,
15938  errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
15939  errmsg("too many inheritance parents"));
15940 
15941  /*
15942  * In case of partitions, an inherited constraint must be
15943  * inherited only once since it cannot have multiple parents and
15944  * it is never considered local.
15945  */
15946  if (parent_rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
15947  {
15948  Assert(child_con->coninhcount == 1);
15949  child_con->conislocal = false;
15950  }
15951 
15952  CatalogTupleUpdate(constraintrel, &child_copy->t_self, child_copy);
15953  heap_freetuple(child_copy);
15954 
15955  found = true;
15956  break;
15957  }
15958 
15959  systable_endscan(child_scan);
15960 
15961  if (!found)
15962  ereport(ERROR,
15963  (errcode(ERRCODE_DATATYPE_MISMATCH),
15964  errmsg("child table is missing constraint \"%s\"",
15965  NameStr(parent_con->conname))));
15966  }
15967 
15968  systable_endscan(parent_scan);
15969  table_close(constraintrel, RowExclusiveLock);
15970 }
15971 
15972 /*
15973  * ALTER TABLE NO INHERIT
15974  *
15975  * Return value is the address of the relation that is no longer parent.
15976  */
15977 static ObjectAddress
15979 {
15980  ObjectAddress address;
15981  Relation parent_rel;
15982 
15983  if (rel->rd_rel->relispartition)
15984  ereport(ERROR,
15985  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
15986  errmsg("cannot change inheritance of a partition")));
15987 
15988  /*
15989  * AccessShareLock on the parent is probably enough, seeing that DROP
15990  * TABLE doesn't lock parent tables at all. We need some lock since we'll
15991  * be inspecting the parent's schema.
15992  */
15993  parent_rel = table_openrv(parent, AccessShareLock);
15994 
15995  /*
15996  * We don't bother to check ownership of the parent table --- ownership of
15997  * the child is presumed enough rights.
15998  */
15999 
16000  /* Off to RemoveInheritance() where most of the work happens */
16001  RemoveInheritance(rel, parent_rel, false);
16002 
16003  ObjectAddressSet(address, RelationRelationId,
16004  RelationGetRelid(parent_rel));
16005 
16006  /* keep our lock on the parent relation until commit */
16007  table_close(parent_rel, NoLock);
16008 
16009  return address;
16010 }
16011 
16012 /*
16013  * MarkInheritDetached
16014  *
16015  * Set inhdetachpending for a partition, for ATExecDetachPartition
16016  * in concurrent mode. While at it, verify that no other partition is
16017  * already pending detach.
16018  */
16019 static void
16020 MarkInheritDetached(Relation child_rel, Relation parent_rel)
16021 {
16022  Relation catalogRelation;
16023  SysScanDesc scan;
16024  ScanKeyData key;
16025  HeapTuple inheritsTuple;
16026  bool found = false;
16027 
16028  Assert(parent_rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
16029 
16030  /*
16031  * Find pg_inherits entries by inhparent. (We need to scan them all in
16032  * order to verify that no other partition is pending detach.)
16033  */
16034  catalogRelation = table_open(InheritsRelationId, RowExclusiveLock);
16035  ScanKeyInit(&key,
16036  Anum_pg_inherits_inhparent,
16037  BTEqualStrategyNumber, F_OIDEQ,
16038  ObjectIdGetDatum(RelationGetRelid(parent_rel)));
16039  scan = systable_beginscan(catalogRelation, InheritsParentIndexId,
16040  true, NULL, 1, &key);
16041 
16042  while (HeapTupleIsValid(inheritsTuple = systable_getnext(scan)))
16043  {
16044  Form_pg_inherits inhForm;
16045 
16046  inhForm = (Form_pg_inherits) GETSTRUCT(inheritsTuple);
16047  if (inhForm->inhdetachpending)
16048  ereport(ERROR,
16049  errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
16050  errmsg("partition \"%s\" already pending detach in partitioned table \"%s.%s\"",
16051  get_rel_name(inhForm->inhrelid),
16052  get_namespace_name(parent_rel->rd_rel->relnamespace),
16053  RelationGetRelationName(parent_rel)),
16054  errhint("Use ALTER TABLE ... DETACH PARTITION ... FINALIZE to complete the pending detach operation."));
16055 
16056  if (inhForm->inhrelid == RelationGetRelid(child_rel))
16057  {
16058  HeapTuple newtup;
16059 
16060  newtup = heap_copytuple(inheritsTuple);
16061  ((Form_pg_inherits) GETSTRUCT(newtup))->inhdetachpending = true;
16062 
16063  CatalogTupleUpdate(catalogRelation,
16064  &inheritsTuple->t_self,
16065  newtup);
16066  found = true;
16067  heap_freetuple(newtup);
16068  /* keep looking, to ensure we catch others pending detach */
16069  }
16070  }
16071 
16072  /* Done */
16073  systable_endscan(scan);
16074  table_close(catalogRelation, RowExclusiveLock);
16075 
16076  if (!found)
16077  ereport(ERROR,
16079  errmsg("relation \"%s\" is not a partition of relation \"%s\"",
16080  RelationGetRelationName(child_rel),
16081  RelationGetRelationName(parent_rel))));
16082 }
16083 
16084 /*
16085  * RemoveInheritance
16086  *
16087  * Drop a parent from the child's parents. This just adjusts the attinhcount
16088  * and attislocal of the columns and removes the pg_inherit and pg_depend
16089  * entries. expect_detached is passed down to DeleteInheritsTuple, q.v..
16090  *
16091  * If attinhcount goes to 0 then attislocal gets set to true. If it goes back
16092  * up attislocal stays true, which means if a child is ever removed from a
16093  * parent then its columns will never be automatically dropped which may
16094  * surprise. But at least we'll never surprise by dropping columns someone
16095  * isn't expecting to be dropped which would actually mean data loss.
16096  *
16097  * coninhcount and conislocal for inherited constraints are adjusted in
16098  * exactly the same way.
16099  *
16100  * Common to ATExecDropInherit() and ATExecDetachPartition().
16101  */
16102 static void
16103 RemoveInheritance(Relation child_rel, Relation parent_rel, bool expect_detached)
16104 {
16105  Relation catalogRelation;
16106  SysScanDesc scan;
16107  ScanKeyData key[3];
16108  HeapTuple attributeTuple,
16109  constraintTuple;
16110  List *connames;
16111  bool found;
16112  bool is_partitioning;
16113 
16114  is_partitioning = (parent_rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
16115 
16116  found = DeleteInheritsTuple(RelationGetRelid(child_rel),
16117  RelationGetRelid(parent_rel),
16118  expect_detached,
16119  RelationGetRelationName(child_rel));
16120  if (!found)
16121  {
16122  if (is_partitioning)
16123  ereport(ERROR,
16125  errmsg("relation \"%s\" is not a partition of relation \"%s\"",
16126  RelationGetRelationName(child_rel),
16127  RelationGetRelationName(parent_rel))));
16128  else
16129  ereport(ERROR,
16131  errmsg("relation \"%s\" is not a parent of relation \"%s\"",
16132  RelationGetRelationName(parent_rel),
16133  RelationGetRelationName(child_rel))));
16134  }
16135 
16136  /*
16137  * Search through child columns looking for ones matching parent rel
16138  */
16139  catalogRelation = table_open(AttributeRelationId, RowExclusiveLock);
16140  ScanKeyInit(&key[0],
16141  Anum_pg_attribute_attrelid,
16142  BTEqualStrategyNumber, F_OIDEQ,
16143  ObjectIdGetDatum(RelationGetRelid(child_rel)));
16144  scan = systable_beginscan(catalogRelation, AttributeRelidNumIndexId,
16145  true, NULL, 1, key);
16146  while (HeapTupleIsValid(attributeTuple = systable_getnext(scan)))
16147  {
16148  Form_pg_attribute att = (Form_pg_attribute) GETSTRUCT(attributeTuple);
16149 
16150  /* Ignore if dropped or not inherited */
16151  if (att->attisdropped)
16152  continue;
16153  if (att->attinhcount <= 0)
16154  continue;
16155 
16157  NameStr(att->attname)))
16158  {
16159  /* Decrement inhcount and possibly set islocal to true */
16160  HeapTuple copyTuple = heap_copytuple(attributeTuple);
16161  Form_pg_attribute copy_att = (Form_pg_attribute) GETSTRUCT(copyTuple);
16162 
16163  copy_att->attinhcount--;
16164  if (copy_att->attinhcount == 0)
16165  copy_att->attislocal = true;
16166 
16167  CatalogTupleUpdate(catalogRelation, &copyTuple->t_self, copyTuple);
16168  heap_freetuple(copyTuple);
16169  }
16170  }
16171  systable_endscan(scan);
16172  table_close(catalogRelation, RowExclusiveLock);
16173 
16174  /*
16175  * Likewise, find inherited check constraints and disinherit them. To do
16176  * this, we first need a list of the names of the parent's check
16177  * constraints. (We cheat a bit by only checking for name matches,
16178  * assuming that the expressions will match.)
16179  */
16180  catalogRelation = table_open(ConstraintRelationId, RowExclusiveLock);
16181  ScanKeyInit(&key[0],
16182  Anum_pg_constraint_conrelid,
16183  BTEqualStrategyNumber, F_OIDEQ,
16184  ObjectIdGetDatum(RelationGetRelid(parent_rel)));
16185  scan = systable_beginscan(catalogRelation, ConstraintRelidTypidNameIndexId,
16186  true, NULL, 1, key);
16187 
16188  connames = NIL;
16189 
16190  while (HeapTupleIsValid(constraintTuple = systable_getnext(scan)))
16191  {
16192  Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(constraintTuple);
16193 
16194  if (con->contype == CONSTRAINT_CHECK)
16195  connames = lappend(connames, pstrdup(NameStr(con->conname)));
16196  }
16197 
16198  systable_endscan(scan);
16199 
16200  /* Now scan the child's constraints */
16201  ScanKeyInit(&key[0],
16202  Anum_pg_constraint_conrelid,
16203  BTEqualStrategyNumber, F_OIDEQ,
16204  ObjectIdGetDatum(RelationGetRelid(child_rel)));
16205  scan = systable_beginscan(catalogRelation, ConstraintRelidTypidNameIndexId,
16206  true, NULL, 1, key);
16207 
16208  while (HeapTupleIsValid(constraintTuple = systable_getnext(scan)))
16209  {
16210  Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(constraintTuple);
16211  bool match;
16212 
16213  if (con->contype != CONSTRAINT_CHECK)
16214  continue;
16215 
16216  match = false;
16217  foreach_ptr(char, chkname, connames)
16218  {
16219  if (strcmp(NameStr(con->conname), chkname) == 0)
16220  {
16221  match = true;
16222  break;
16223  }
16224  }
16225 
16226  if (match)
16227  {
16228  /* Decrement inhcount and possibly set islocal to true */
16229  HeapTuple copyTuple = heap_copytuple(constraintTuple);
16230  Form_pg_constraint copy_con = (Form_pg_constraint) GETSTRUCT(copyTuple);
16231 
16232  if (copy_con->coninhcount <= 0) /* shouldn't happen */
16233  elog(ERROR, "relation %u has non-inherited constraint \"%s\"",
16234  RelationGetRelid(child_rel), NameStr(copy_con->conname));
16235 
16236  copy_con->coninhcount--;
16237  if (copy_con->coninhcount == 0)
16238  copy_con->conislocal = true;
16239 
16240  CatalogTupleUpdate(catalogRelation, &copyTuple->t_self, copyTuple);
16241  heap_freetuple(copyTuple);
16242  }
16243  }
16244 
16245  systable_endscan(scan);
16246  table_close(catalogRelation, RowExclusiveLock);
16247 
16249  RelationRelationId,
16250  RelationGetRelid(parent_rel),
16251  child_dependency_type(is_partitioning));
16252 
16253  /*
16254  * Post alter hook of this inherits. Since object_access_hook doesn't take
16255  * multiple object identifiers, we relay oid of parent relation using
16256  * auxiliary_id argument.
16257  */
16258  InvokeObjectPostAlterHookArg(InheritsRelationId,
16259  RelationGetRelid(child_rel), 0,
16260  RelationGetRelid(parent_rel), false);
16261 }
16262 
16263 /*
16264  * Drop the dependency created by StoreCatalogInheritance1 (CREATE TABLE
16265  * INHERITS/ALTER TABLE INHERIT -- refclassid will be RelationRelationId) or
16266  * heap_create_with_catalog (CREATE TABLE OF/ALTER TABLE OF -- refclassid will
16267  * be TypeRelationId). There's no convenient way to do this, so go trawling
16268  * through pg_depend.
16269  */
16270 static void
16271 drop_parent_dependency(Oid relid, Oid refclassid, Oid refobjid,
16272  DependencyType deptype)
16273 {
16274  Relation catalogRelation;
16275  SysScanDesc scan;
16276  ScanKeyData key[3];
16277  HeapTuple depTuple;
16278 
16279  catalogRelation = table_open(DependRelationId, RowExclusiveLock);
16280 
16281  ScanKeyInit(&key[0],
16282  Anum_pg_depend_classid,
16283  BTEqualStrategyNumber, F_OIDEQ,
16284  ObjectIdGetDatum(RelationRelationId));
16285  ScanKeyInit(&key[1],
16286  Anum_pg_depend_objid,
16287  BTEqualStrategyNumber, F_OIDEQ,
16288  ObjectIdGetDatum(relid));
16289  ScanKeyInit(&key[2],
16290  Anum_pg_depend_objsubid,
16291  BTEqualStrategyNumber, F_INT4EQ,
16292  Int32GetDatum(0));
16293 
16294  scan = systable_beginscan(catalogRelation, DependDependerIndexId, true,
16295  NULL, 3, key);
16296 
16297  while (HeapTupleIsValid(depTuple = systable_getnext(scan)))
16298  {
16299  Form_pg_depend dep = (Form_pg_depend) GETSTRUCT(depTuple);
16300 
16301  if (dep->refclassid == refclassid &&
16302  dep->refobjid == refobjid &&
16303  dep->refobjsubid == 0 &&
16304  dep->deptype == deptype)
16305  CatalogTupleDelete(catalogRelation, &depTuple->t_self);
16306  }
16307 
16308  systable_endscan(scan);
16309  table_close(catalogRelation, RowExclusiveLock);
16310 }
16311 
16312 /*
16313  * ALTER TABLE OF
16314  *
16315  * Attach a table to a composite type, as though it had been created with CREATE
16316  * TABLE OF. All attname, atttypid, atttypmod and attcollation must match. The
16317  * subject table must not have inheritance parents. These restrictions ensure
16318  * that you cannot create a configuration impossible with CREATE TABLE OF alone.
16319  *
16320  * The address of the type is returned.
16321  */
16322 static ObjectAddress
16323 ATExecAddOf(Relation rel, const TypeName *ofTypename, LOCKMODE lockmode)
16324 {
16325  Oid relid = RelationGetRelid(rel);
16326  Type typetuple;
16327  Form_pg_type typeform;
16328  Oid typeid;
16329  Relation inheritsRelation,
16330  relationRelation;
16331  SysScanDesc scan;
16332  ScanKeyData key;
16333  AttrNumber table_attno,
16334  type_attno;
16335  TupleDesc typeTupleDesc,
16336  tableTupleDesc;
16337  ObjectAddress tableobj,
16338  typeobj;
16339  HeapTuple classtuple;
16340 
16341  /* Validate the type. */
16342  typetuple = typenameType(NULL, ofTypename, NULL);
16343  check_of_type(typetuple);
16344  typeform = (Form_pg_type) GETSTRUCT(typetuple);
16345  typeid = typeform->oid;
16346 
16347  /* Fail if the table has any inheritance parents. */
16348  inheritsRelation = table_open(InheritsRelationId, AccessShareLock);
16349  ScanKeyInit(&key,
16350  Anum_pg_inherits_inhrelid,
16351  BTEqualStrategyNumber, F_OIDEQ,
16352  ObjectIdGetDatum(relid));
16353  scan = systable_beginscan(inheritsRelation, InheritsRelidSeqnoIndexId,
16354  true, NULL, 1, &key);
16356  ereport(ERROR,
16357  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
16358  errmsg("typed tables cannot inherit")));
16359  systable_endscan(scan);
16360  table_close(inheritsRelation, AccessShareLock);
16361 
16362  /*
16363  * Check the tuple descriptors for compatibility. Unlike inheritance, we
16364  * require that the order also match. However, attnotnull need not match.
16365  */
16366  typeTupleDesc = lookup_rowtype_tupdesc(typeid, -1);
16367  tableTupleDesc = RelationGetDescr(rel);
16368  table_attno = 1;
16369  for (type_attno = 1; type_attno <= typeTupleDesc->natts; type_attno++)
16370  {
16371  Form_pg_attribute type_attr,
16372  table_attr;
16373  const char *type_attname,
16374  *table_attname;
16375 
16376  /* Get the next non-dropped type attribute. */
16377  type_attr = TupleDescAttr(typeTupleDesc, type_attno - 1);
16378  if (type_attr->attisdropped)
16379  continue;
16380  type_attname = NameStr(type_attr->attname);
16381 
16382  /* Get the next non-dropped table attribute. */
16383  do
16384  {
16385  if (table_attno > tableTupleDesc->natts)
16386  ereport(ERROR,
16387  (errcode(ERRCODE_DATATYPE_MISMATCH),
16388  errmsg("table is missing column \"%s\"",
16389  type_attname)));
16390  table_attr = TupleDescAttr(tableTupleDesc, table_attno - 1);
16391  table_attno++;
16392  } while (table_attr->attisdropped);
16393  table_attname = NameStr(table_attr->attname);
16394 
16395  /* Compare name. */
16396  if (strncmp(table_attname, type_attname, NAMEDATALEN) != 0)
16397  ereport(ERROR,
16398  (errcode(ERRCODE_DATATYPE_MISMATCH),
16399  errmsg("table has column \"%s\" where type requires \"%s\"",
16400  table_attname, type_attname)));
16401 
16402  /* Compare type. */
16403  if (table_attr->atttypid != type_attr->atttypid ||
16404  table_attr->atttypmod != type_attr->atttypmod ||
16405  table_attr->attcollation != type_attr->attcollation)
16406  ereport(ERROR,
16407  (errcode(ERRCODE_DATATYPE_MISMATCH),
16408  errmsg("table \"%s\" has different type for column \"%s\"",
16409  RelationGetRelationName(rel), type_attname)));
16410  }
16411  ReleaseTupleDesc(typeTupleDesc);
16412 
16413  /* Any remaining columns at the end of the table had better be dropped. */
16414  for (; table_attno <= tableTupleDesc->natts; table_attno++)
16415  {
16416  Form_pg_attribute table_attr = TupleDescAttr(tableTupleDesc,
16417  table_attno - 1);
16418 
16419  if (!table_attr->attisdropped)
16420  ereport(ERROR,
16421  (errcode(ERRCODE_DATATYPE_MISMATCH),
16422  errmsg("table has extra column \"%s\"",
16423  NameStr(table_attr->attname))));
16424  }
16425 
16426  /* If the table was already typed, drop the existing dependency. */
16427  if (rel->rd_rel->reloftype)
16428  drop_parent_dependency(relid, TypeRelationId, rel->rd_rel->reloftype,
16430 
16431  /* Record a dependency on the new type. */
16432  tableobj.classId = RelationRelationId;
16433  tableobj.objectId = relid;
16434  tableobj.objectSubId = 0;
16435  typeobj.classId = TypeRelationId;
16436  typeobj.objectId = typeid;
16437  typeobj.objectSubId = 0;
16438  recordDependencyOn(&tableobj, &typeobj, DEPENDENCY_NORMAL);
16439 
16440  /* Update pg_class.reloftype */
16441  relationRelation = table_open(RelationRelationId, RowExclusiveLock);
16442  classtuple = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
16443  if (!HeapTupleIsValid(classtuple))
16444  elog(ERROR, "cache lookup failed for relation %u", relid);
16445  ((Form_pg_class) GETSTRUCT(classtuple))->reloftype = typeid;
16446  CatalogTupleUpdate(relationRelation, &classtuple->t_self, classtuple);
16447 
16448  InvokeObjectPostAlterHook(RelationRelationId, relid, 0);
16449 
16450  heap_freetuple(classtuple);
16451  table_close(relationRelation, RowExclusiveLock);
16452 
16453  ReleaseSysCache(typetuple);
16454 
16455  return typeobj;
16456 }
16457 
16458 /*
16459  * ALTER TABLE NOT OF
16460  *
16461  * Detach a typed table from its originating type. Just clear reloftype and
16462  * remove the dependency.
16463  */
16464 static void
16466 {
16467  Oid relid = RelationGetRelid(rel);
16468  Relation relationRelation;
16469  HeapTuple tuple;
16470 
16471  if (!OidIsValid(rel->rd_rel->reloftype))
16472  ereport(ERROR,
16473  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
16474  errmsg("\"%s\" is not a typed table",
16475  RelationGetRelationName(rel))));
16476 
16477  /*
16478  * We don't bother to check ownership of the type --- ownership of the
16479  * table is presumed enough rights. No lock required on the type, either.
16480  */
16481 
16482  drop_parent_dependency(relid, TypeRelationId, rel->rd_rel->reloftype,
16484 
16485  /* Clear pg_class.reloftype */
16486  relationRelation = table_open(RelationRelationId, RowExclusiveLock);
16487  tuple = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
16488  if (!HeapTupleIsValid(tuple))
16489  elog(ERROR, "cache lookup failed for relation %u", relid);
16490  ((Form_pg_class) GETSTRUCT(tuple))->reloftype = InvalidOid;
16491  CatalogTupleUpdate(relationRelation, &tuple->t_self, tuple);
16492 
16493  InvokeObjectPostAlterHook(RelationRelationId, relid, 0);
16494 
16495  heap_freetuple(tuple);
16496  table_close(relationRelation, RowExclusiveLock);
16497 }
16498 
16499 /*
16500  * relation_mark_replica_identity: Update a table's replica identity
16501  *
16502  * Iff ri_type = REPLICA_IDENTITY_INDEX, indexOid must be the Oid of a suitable
16503  * index. Otherwise, it must be InvalidOid.
16504  *
16505  * Caller had better hold an exclusive lock on the relation, as the results
16506  * of running two of these concurrently wouldn't be pretty.
16507  */
16508 static void
16509 relation_mark_replica_identity(Relation rel, char ri_type, Oid indexOid,
16510  bool is_internal)
16511 {
16512  Relation pg_index;
16513  Relation pg_class;
16514  HeapTuple pg_class_tuple;
16515  HeapTuple pg_index_tuple;
16516  Form_pg_class pg_class_form;
16517  Form_pg_index pg_index_form;
16518  ListCell *index;
16519 
16520  /*
16521  * Check whether relreplident has changed, and update it if so.
16522  */
16523  pg_class = table_open(RelationRelationId, RowExclusiveLock);
16524  pg_class_tuple = SearchSysCacheCopy1(RELOID,
16526  if (!HeapTupleIsValid(pg_class_tuple))
16527  elog(ERROR, "cache lookup failed for relation \"%s\"",
16529  pg_class_form = (Form_pg_class) GETSTRUCT(pg_class_tuple);
16530  if (pg_class_form->relreplident != ri_type)
16531  {
16532  pg_class_form->relreplident = ri_type;
16533  CatalogTupleUpdate(pg_class, &pg_class_tuple->t_self, pg_class_tuple);
16534  }
16535  table_close(pg_class, RowExclusiveLock);
16536  heap_freetuple(pg_class_tuple);
16537 
16538  /*
16539  * Update the per-index indisreplident flags correctly.
16540  */
16541  pg_index = table_open(IndexRelationId, RowExclusiveLock);
16542  foreach(index, RelationGetIndexList(rel))
16543  {
16544  Oid thisIndexOid = lfirst_oid(index);
16545  bool dirty = false;
16546 
16547  pg_index_tuple = SearchSysCacheCopy1(INDEXRELID,
16548  ObjectIdGetDatum(thisIndexOid));
16549  if (!HeapTupleIsValid(pg_index_tuple))
16550  elog(ERROR, "cache lookup failed for index %u", thisIndexOid);
16551  pg_index_form = (Form_pg_index) GETSTRUCT(pg_index_tuple);
16552 
16553  if (thisIndexOid == indexOid)
16554  {
16555  /* Set the bit if not already set. */
16556  if (!pg_index_form->indisreplident)
16557  {
16558  dirty = true;
16559  pg_index_form->indisreplident = true;
16560  }
16561  }
16562  else
16563  {
16564  /* Unset the bit if set. */
16565  if (pg_index_form->indisreplident)
16566  {
16567  dirty = true;
16568  pg_index_form->indisreplident = false;
16569  }
16570  }
16571 
16572  if (dirty)
16573  {
16574  CatalogTupleUpdate(pg_index, &pg_index_tuple->t_self, pg_index_tuple);
16575  InvokeObjectPostAlterHookArg(IndexRelationId, thisIndexOid, 0,
16576  InvalidOid, is_internal);
16577 
16578  /*
16579  * Invalidate the relcache for the table, so that after we commit
16580  * all sessions will refresh the table's replica identity index
16581  * before attempting any UPDATE or DELETE on the table. (If we
16582  * changed the table's pg_class row above, then a relcache inval
16583  * is already queued due to that; but we might not have.)
16584  */
16586  }
16587  heap_freetuple(pg_index_tuple);
16588  }
16589 
16590  table_close(pg_index, RowExclusiveLock);
16591 }
16592 
16593 /*
16594  * ALTER TABLE <name> REPLICA IDENTITY ...
16595  */
16596 static void
16598 {
16599  Oid indexOid;
16600  Relation indexRel;
16601  int key;
16602 
16603  if (stmt->identity_type == REPLICA_IDENTITY_DEFAULT)
16604  {
16605  relation_mark_replica_identity(rel, stmt->identity_type, InvalidOid, true);
16606  return;
16607  }
16608  else if (stmt->identity_type == REPLICA_IDENTITY_FULL)
16609  {
16610  relation_mark_replica_identity(rel, stmt->identity_type, InvalidOid, true);
16611  return;
16612  }
16613  else if (stmt->identity_type == REPLICA_IDENTITY_NOTHING)
16614  {
16615  relation_mark_replica_identity(rel, stmt->identity_type, InvalidOid, true);
16616  return;
16617  }
16618  else if (stmt->identity_type == REPLICA_IDENTITY_INDEX)
16619  {
16620  /* fallthrough */ ;
16621  }
16622  else
16623  elog(ERROR, "unexpected identity type %u", stmt->identity_type);
16624 
16625  /* Check that the index exists */
16626  indexOid = get_relname_relid(stmt->name, rel->rd_rel->relnamespace);
16627  if (!OidIsValid(indexOid))
16628  ereport(ERROR,
16629  (errcode(ERRCODE_UNDEFINED_OBJECT),
16630  errmsg("index \"%s\" for table \"%s\" does not exist",
16631  stmt->name, RelationGetRelationName(rel))));
16632 
16633  indexRel = index_open(indexOid, ShareLock);
16634 
16635  /* Check that the index is on the relation we're altering. */
16636  if (indexRel->rd_index == NULL ||
16637  indexRel->rd_index->indrelid != RelationGetRelid(rel))
16638  ereport(ERROR,
16639  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
16640  errmsg("\"%s\" is not an index for table \"%s\"",
16641  RelationGetRelationName(indexRel),
16642  RelationGetRelationName(rel))));
16643  /* The AM must support uniqueness, and the index must in fact be unique. */
16644  if (!indexRel->rd_indam->amcanunique ||
16645  !indexRel->rd_index->indisunique)
16646  ereport(ERROR,
16647  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
16648  errmsg("cannot use non-unique index \"%s\" as replica identity",
16649  RelationGetRelationName(indexRel))));
16650  /* Deferred indexes are not guaranteed to be always unique. */
16651  if (!indexRel->rd_index->indimmediate)
16652  ereport(ERROR,
16653  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
16654  errmsg("cannot use non-immediate index \"%s\" as replica identity",
16655  RelationGetRelationName(indexRel))));
16656  /* Expression indexes aren't supported. */
16657  if (RelationGetIndexExpressions(indexRel) != NIL)
16658  ereport(ERROR,
16659  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
16660  errmsg("cannot use expression index \"%s\" as replica identity",
16661  RelationGetRelationName(indexRel))));
16662  /* Predicate indexes aren't supported. */
16663  if (RelationGetIndexPredicate(indexRel) != NIL)
16664  ereport(ERROR,
16665  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
16666  errmsg("cannot use partial index \"%s\" as replica identity",
16667  RelationGetRelationName(indexRel))));
16668 
16669  /* Check index for nullable columns. */
16670  for (key = 0; key < IndexRelationGetNumberOfKeyAttributes(indexRel); key++)
16671  {
16672  int16 attno = indexRel->rd_index->indkey.values[key];
16673  Form_pg_attribute attr;
16674 
16675  /*
16676  * Reject any other system columns. (Going forward, we'll disallow
16677  * indexes containing such columns in the first place, but they might
16678  * exist in older branches.)
16679  */
16680  if (attno <= 0)
16681  ereport(ERROR,
16682  (errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
16683  errmsg("index \"%s\" cannot be used as replica identity because column %d is a system column",
16684  RelationGetRelationName(indexRel), attno)));
16685 
16686  attr = TupleDescAttr(rel->rd_att, attno - 1);
16687  if (!attr->attnotnull)
16688  ereport(ERROR,
16689  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
16690  errmsg("index \"%s\" cannot be used as replica identity because column \"%s\" is nullable",
16691  RelationGetRelationName(indexRel),
16692  NameStr(attr->attname))));
16693  }
16694 
16695  /* This index is suitable for use as a replica identity. Mark it. */
16696  relation_mark_replica_identity(rel, stmt->identity_type, indexOid, true);
16697 
16698  index_close(indexRel, NoLock);
16699 }
16700 
16701 /*
16702  * ALTER TABLE ENABLE/DISABLE ROW LEVEL SECURITY
16703  */
16704 static void
16706 {
16707  Relation pg_class;
16708  Oid relid;
16709  HeapTuple tuple;
16710 
16711  relid = RelationGetRelid(rel);
16712 
16713  /* Pull the record for this relation and update it */
16714  pg_class = table_open(RelationRelationId, RowExclusiveLock);
16715 
16716  tuple = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
16717 
16718  if (!HeapTupleIsValid(tuple))
16719  elog(ERROR, "cache lookup failed for relation %u", relid);
16720 
16721  ((Form_pg_class) GETSTRUCT(tuple))->relrowsecurity = rls;
16722  CatalogTupleUpdate(pg_class, &tuple->t_self, tuple);
16723 
16724  InvokeObjectPostAlterHook(RelationRelationId,
16725  RelationGetRelid(rel), 0);
16726 
16727  table_close(pg_class, RowExclusiveLock);
16728  heap_freetuple(tuple);
16729 }
16730 
16731 /*
16732  * ALTER TABLE FORCE/NO FORCE ROW LEVEL SECURITY
16733  */
16734 static void
16736 {
16737  Relation pg_class;
16738  Oid relid;
16739  HeapTuple tuple;
16740 
16741  relid = RelationGetRelid(rel);
16742 
16743  pg_class = table_open(RelationRelationId, RowExclusiveLock);
16744 
16745  tuple = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
16746 
16747  if (!HeapTupleIsValid(tuple))
16748  elog(ERROR, "cache lookup failed for relation %u", relid);
16749 
16750  ((Form_pg_class) GETSTRUCT(tuple))->relforcerowsecurity = force_rls;
16751  CatalogTupleUpdate(pg_class, &tuple->t_self, tuple);
16752 
16753  InvokeObjectPostAlterHook(RelationRelationId,
16754  RelationGetRelid(rel), 0);
16755 
16756  table_close(pg_class, RowExclusiveLock);
16757  heap_freetuple(tuple);
16758 }
16759 
16760 /*
16761  * ALTER FOREIGN TABLE <name> OPTIONS (...)
16762  */
16763 static void
16765 {
16766  Relation ftrel;
16767  ForeignServer *server;
16768  ForeignDataWrapper *fdw;
16769  HeapTuple tuple;
16770  bool isnull;
16771  Datum repl_val[Natts_pg_foreign_table];
16772  bool repl_null[Natts_pg_foreign_table];
16773  bool repl_repl[Natts_pg_foreign_table];
16774  Datum datum;
16775  Form_pg_foreign_table tableform;
16776 
16777  if (options == NIL)
16778  return;
16779 
16780  ftrel = table_open(ForeignTableRelationId, RowExclusiveLock);
16781 
16782  tuple = SearchSysCacheCopy1(FOREIGNTABLEREL,
16783  ObjectIdGetDatum(rel->rd_id));
16784  if (!HeapTupleIsValid(tuple))
16785  ereport(ERROR,
16786  (errcode(ERRCODE_UNDEFINED_OBJECT),
16787  errmsg("foreign table \"%s\" does not exist",
16788  RelationGetRelationName(rel))));
16789  tableform = (Form_pg_foreign_table) GETSTRUCT(tuple);
16790  server = GetForeignServer(tableform->ftserver);
16791  fdw = GetForeignDataWrapper(server->fdwid);
16792 
16793  memset(repl_val, 0, sizeof(repl_val));
16794  memset(repl_null, false, sizeof(repl_null));
16795  memset(repl_repl, false, sizeof(repl_repl));
16796 
16797  /* Extract the current options */
16798  datum = SysCacheGetAttr(FOREIGNTABLEREL,
16799  tuple,
16800  Anum_pg_foreign_table_ftoptions,
16801  &isnull);
16802  if (isnull)
16803  datum = PointerGetDatum(NULL);
16804 
16805  /* Transform the options */
16806  datum = transformGenericOptions(ForeignTableRelationId,
16807  datum,
16808  options,
16809  fdw->fdwvalidator);
16810 
16811  if (PointerIsValid(DatumGetPointer(datum)))
16812  repl_val[Anum_pg_foreign_table_ftoptions - 1] = datum;
16813  else
16814  repl_null[Anum_pg_foreign_table_ftoptions - 1] = true;
16815 
16816  repl_repl[Anum_pg_foreign_table_ftoptions - 1] = true;
16817 
16818  /* Everything looks good - update the tuple */
16819 
16820  tuple = heap_modify_tuple(tuple, RelationGetDescr(ftrel),
16821  repl_val, repl_null, repl_repl);
16822 
16823  CatalogTupleUpdate(ftrel, &tuple->t_self, tuple);
16824 
16825  /*
16826  * Invalidate relcache so that all sessions will refresh any cached plans
16827  * that might depend on the old options.
16828  */
16830 
16831  InvokeObjectPostAlterHook(ForeignTableRelationId,
16832  RelationGetRelid(rel), 0);
16833 
16834  table_close(ftrel, RowExclusiveLock);
16835 
16836  heap_freetuple(tuple);
16837 }
16838 
16839 /*
16840  * ALTER TABLE ALTER COLUMN SET COMPRESSION
16841  *
16842  * Return value is the address of the modified column
16843  */
16844 static ObjectAddress
16846  const char *column,
16847  Node *newValue,
16848  LOCKMODE lockmode)
16849 {
16850  Relation attrel;
16851  HeapTuple tuple;
16852  Form_pg_attribute atttableform;
16854  char *compression;
16855  char cmethod;
16856  ObjectAddress address;
16857 
16858  compression = strVal(newValue);
16859 
16860  attrel = table_open(AttributeRelationId, RowExclusiveLock);
16861 
16862  /* copy the cache entry so we can scribble on it below */
16863  tuple = SearchSysCacheCopyAttName(RelationGetRelid(rel), column);
16864  if (!HeapTupleIsValid(tuple))
16865  ereport(ERROR,
16866  (errcode(ERRCODE_UNDEFINED_COLUMN),
16867  errmsg("column \"%s\" of relation \"%s\" does not exist",
16868  column, RelationGetRelationName(rel))));
16869 
16870  /* prevent them from altering a system attribute */
16871  atttableform = (Form_pg_attribute) GETSTRUCT(tuple);
16872  attnum = atttableform->attnum;
16873  if (attnum <= 0)
16874  ereport(ERROR,
16875  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
16876  errmsg("cannot alter system column \"%s\"", column)));
16877 
16878  /*
16879  * Check that column type is compressible, then get the attribute
16880  * compression method code
16881  */
16882  cmethod = GetAttributeCompression(atttableform->atttypid, compression);
16883 
16884  /* update pg_attribute entry */
16885  atttableform->attcompression = cmethod;
16886  CatalogTupleUpdate(attrel, &tuple->t_self, tuple);
16887 
16888  InvokeObjectPostAlterHook(RelationRelationId,
16889  RelationGetRelid(rel),
16890  attnum);
16891 
16892  /*
16893  * Apply the change to indexes as well (only for simple index columns,
16894  * matching behavior of index.c ConstructTupleDescriptor()).
16895  */
16896  SetIndexStorageProperties(rel, attrel, attnum,
16897  false, 0,
16898  true, cmethod,
16899  lockmode);
16900 
16901  heap_freetuple(tuple);
16902 
16903  table_close(attrel, RowExclusiveLock);
16904 
16905  /* make changes visible */
16907 
16908  ObjectAddressSubSet(address, RelationRelationId,
16909  RelationGetRelid(rel), attnum);
16910  return address;
16911 }
16912 
16913 
16914 /*
16915  * Preparation phase for SET LOGGED/UNLOGGED
16916  *
16917  * This verifies that we're not trying to change a temp table. Also,
16918  * existing foreign key constraints are checked to avoid ending up with
16919  * permanent tables referencing unlogged tables.
16920  *
16921  * Return value is false if the operation is a no-op (in which case the
16922  * checks are skipped), otherwise true.
16923  */
16924 static bool
16926 {
16927  Relation pg_constraint;
16928  HeapTuple tuple;
16929  SysScanDesc scan;
16930  ScanKeyData skey[1];
16931 
16932  /*
16933  * Disallow changing status for a temp table. Also verify whether we can
16934  * get away with doing nothing; in such cases we don't need to run the
16935  * checks below, either.
16936  */
16937  switch (rel->rd_rel->relpersistence)
16938  {
16939  case RELPERSISTENCE_TEMP:
16940  ereport(ERROR,
16941  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
16942  errmsg("cannot change logged status of table \"%s\" because it is temporary",
16944  errtable(rel)));
16945  break;
16946  case RELPERSISTENCE_PERMANENT:
16947  if (toLogged)
16948  /* nothing to do */
16949  return false;
16950  break;
16951  case RELPERSISTENCE_UNLOGGED:
16952  if (!toLogged)
16953  /* nothing to do */
16954  return false;
16955  break;
16956  }
16957 
16958  /*
16959  * Check that the table is not part of any publication when changing to
16960  * UNLOGGED, as UNLOGGED tables can't be published.
16961  */
16962  if (!toLogged &&
16964  ereport(ERROR,
16965  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
16966  errmsg("cannot change table \"%s\" to unlogged because it is part of a publication",
16968  errdetail("Unlogged relations cannot be replicated.")));
16969 
16970  /*
16971  * Check existing foreign key constraints to preserve the invariant that
16972  * permanent tables cannot reference unlogged ones. Self-referencing
16973  * foreign keys can safely be ignored.
16974  */
16975  pg_constraint = table_open(ConstraintRelationId, AccessShareLock);
16976 
16977  /*
16978  * Scan conrelid if changing to permanent, else confrelid. This also
16979  * determines whether a useful index exists.
16980  */
16981  ScanKeyInit(&skey[0],
16982  toLogged ? Anum_pg_constraint_conrelid :
16983  Anum_pg_constraint_confrelid,
16984  BTEqualStrategyNumber, F_OIDEQ,
16986  scan = systable_beginscan(pg_constraint,
16987  toLogged ? ConstraintRelidTypidNameIndexId : InvalidOid,
16988  true, NULL, 1, skey);
16989 
16990  while (HeapTupleIsValid(tuple = systable_getnext(scan)))
16991  {
16993 
16994  if (con->contype == CONSTRAINT_FOREIGN)
16995  {
16996  Oid foreignrelid;
16997  Relation foreignrel;
16998 
16999  /* the opposite end of what we used as scankey */
17000  foreignrelid = toLogged ? con->confrelid : con->conrelid;
17001 
17002  /* ignore if self-referencing */
17003  if (RelationGetRelid(rel) == foreignrelid)
17004  continue;
17005 
17006  foreignrel = relation_open(foreignrelid, AccessShareLock);
17007 
17008  if (toLogged)
17009  {
17010  if (!RelationIsPermanent(foreignrel))
17011  ereport(ERROR,
17012  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
17013  errmsg("could not change table \"%s\" to logged because it references unlogged table \"%s\"",
17015  RelationGetRelationName(foreignrel)),
17016  errtableconstraint(rel, NameStr(con->conname))));
17017  }
17018  else
17019  {
17020  if (RelationIsPermanent(foreignrel))
17021  ereport(ERROR,
17022  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
17023  errmsg("could not change table \"%s\" to unlogged because it references logged table \"%s\"",
17025  RelationGetRelationName(foreignrel)),
17026  errtableconstraint(rel, NameStr(con->conname))));
17027  }
17028 
17029  relation_close(foreignrel, AccessShareLock);
17030  }
17031  }
17032 
17033  systable_endscan(scan);
17034 
17035  table_close(pg_constraint, AccessShareLock);
17036 
17037  return true;
17038 }
17039 
17040 /*
17041  * Execute ALTER TABLE SET SCHEMA
17042  */
17045 {
17046  Relation rel;
17047  Oid relid;
17048  Oid oldNspOid;
17049  Oid nspOid;
17050  RangeVar *newrv;
17051  ObjectAddresses *objsMoved;
17052  ObjectAddress myself;
17053 
17055  stmt->missing_ok ? RVR_MISSING_OK : 0,
17057  (void *) stmt);
17058 
17059  if (!OidIsValid(relid))
17060  {
17061  ereport(NOTICE,
17062  (errmsg("relation \"%s\" does not exist, skipping",
17063  stmt->relation->relname)));
17064  return InvalidObjectAddress;
17065  }
17066 
17067  rel = relation_open(relid, NoLock);
17068 
17069  oldNspOid = RelationGetNamespace(rel);
17070 
17071  /* If it's an owned sequence, disallow moving it by itself. */
17072  if (rel->rd_rel->relkind == RELKIND_SEQUENCE)
17073  {
17074  Oid tableId;
17075  int32 colId;
17076 
17077  if (sequenceIsOwned(relid, DEPENDENCY_AUTO, &tableId, &colId) ||
17078  sequenceIsOwned(relid, DEPENDENCY_INTERNAL, &tableId, &colId))
17079  ereport(ERROR,
17080  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
17081  errmsg("cannot move an owned sequence into another schema"),
17082  errdetail("Sequence \"%s\" is linked to table \"%s\".",
17084  get_rel_name(tableId))));
17085  }
17086 
17087  /* Get and lock schema OID and check its permissions. */
17088  newrv = makeRangeVar(stmt->newschema, RelationGetRelationName(rel), -1);
17089  nspOid = RangeVarGetAndCheckCreationNamespace(newrv, NoLock, NULL);
17090 
17091  /* common checks on switching namespaces */
17092  CheckSetNamespace(oldNspOid, nspOid);
17093 
17094  objsMoved = new_object_addresses();
17095  AlterTableNamespaceInternal(rel, oldNspOid, nspOid, objsMoved);
17096  free_object_addresses(objsMoved);
17097 
17098  ObjectAddressSet(myself, RelationRelationId, relid);
17099 
17100  if (oldschema)
17101  *oldschema = oldNspOid;
17102 
17103  /* close rel, but keep lock until commit */
17104  relation_close(rel, NoLock);
17105 
17106  return myself;
17107 }
17108 
17109 /*
17110  * The guts of relocating a table or materialized view to another namespace:
17111  * besides moving the relation itself, its dependent objects are relocated to
17112  * the new schema.
17113  */
17114 void
17116  ObjectAddresses *objsMoved)
17117 {
17118  Relation classRel;
17119 
17120  Assert(objsMoved != NULL);
17121 
17122  /* OK, modify the pg_class row and pg_depend entry */
17123  classRel = table_open(RelationRelationId, RowExclusiveLock);
17124 
17125  AlterRelationNamespaceInternal(classRel, RelationGetRelid(rel), oldNspOid,
17126  nspOid, true, objsMoved);
17127 
17128  /* Fix the table's row type too, if it has one */
17129  if (OidIsValid(rel->rd_rel->reltype))
17130  AlterTypeNamespaceInternal(rel->rd_rel->reltype, nspOid,
17131  false, /* isImplicitArray */
17132  false, /* ignoreDependent */
17133  false, /* errorOnTableType */
17134  objsMoved);
17135 
17136  /* Fix other dependent stuff */
17137  AlterIndexNamespaces(classRel, rel, oldNspOid, nspOid, objsMoved);
17138  AlterSeqNamespaces(classRel, rel, oldNspOid, nspOid,
17139  objsMoved, AccessExclusiveLock);
17140  AlterConstraintNamespaces(RelationGetRelid(rel), oldNspOid, nspOid,
17141  false, objsMoved);
17142 
17143  table_close(classRel, RowExclusiveLock);
17144 }
17145 
17146 /*
17147  * The guts of relocating a relation to another namespace: fix the pg_class
17148  * entry, and the pg_depend entry if any. Caller must already have
17149  * opened and write-locked pg_class.
17150  */
17151 void
17153  Oid oldNspOid, Oid newNspOid,
17154  bool hasDependEntry,
17155  ObjectAddresses *objsMoved)
17156 {
17157  HeapTuple classTup;
17158  Form_pg_class classForm;
17159  ObjectAddress thisobj;
17160  bool already_done = false;
17161 
17162  classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relOid));
17163  if (!HeapTupleIsValid(classTup))
17164  elog(ERROR, "cache lookup failed for relation %u", relOid);
17165  classForm = (Form_pg_class) GETSTRUCT(classTup);
17166 
17167  Assert(classForm->relnamespace == oldNspOid);
17168 
17169  thisobj.classId = RelationRelationId;
17170  thisobj.objectId = relOid;
17171  thisobj.objectSubId = 0;
17172 
17173  /*
17174  * If the object has already been moved, don't move it again. If it's
17175  * already in the right place, don't move it, but still fire the object
17176  * access hook.
17177  */
17178  already_done = object_address_present(&thisobj, objsMoved);
17179  if (!already_done && oldNspOid != newNspOid)
17180  {
17181  /* check for duplicate name (more friendly than unique-index failure) */
17182  if (get_relname_relid(NameStr(classForm->relname),
17183  newNspOid) != InvalidOid)
17184  ereport(ERROR,
17185  (errcode(ERRCODE_DUPLICATE_TABLE),
17186  errmsg("relation \"%s\" already exists in schema \"%s\"",
17187  NameStr(classForm->relname),
17188  get_namespace_name(newNspOid))));
17189 
17190  /* classTup is a copy, so OK to scribble on */
17191  classForm->relnamespace = newNspOid;
17192 
17193  CatalogTupleUpdate(classRel, &classTup->t_self, classTup);
17194 
17195  /* Update dependency on schema if caller said so */
17196  if (hasDependEntry &&
17197  changeDependencyFor(RelationRelationId,
17198  relOid,
17199  NamespaceRelationId,
17200  oldNspOid,
17201  newNspOid) != 1)
17202  elog(ERROR, "could not change schema dependency for relation \"%s\"",
17203  NameStr(classForm->relname));
17204  }
17205  if (!already_done)
17206  {
17207  add_exact_object_address(&thisobj, objsMoved);
17208 
17209  InvokeObjectPostAlterHook(RelationRelationId, relOid, 0);
17210  }
17211 
17212  heap_freetuple(classTup);
17213 }
17214 
17215 /*
17216  * Move all indexes for the specified relation to another namespace.
17217  *
17218  * Note: we assume adequate permission checking was done by the caller,
17219  * and that the caller has a suitable lock on the owning relation.
17220  */
17221 static void
17223  Oid oldNspOid, Oid newNspOid, ObjectAddresses *objsMoved)
17224 {
17225  List *indexList;
17226  ListCell *l;
17227 
17228  indexList = RelationGetIndexList(rel);
17229 
17230  foreach(l, indexList)
17231  {
17232  Oid indexOid = lfirst_oid(l);
17233  ObjectAddress thisobj;
17234 
17235  thisobj.classId = RelationRelationId;
17236  thisobj.objectId = indexOid;
17237  thisobj.objectSubId = 0;
17238 
17239  /*
17240  * Note: currently, the index will not have its own dependency on the
17241  * namespace, so we don't need to do changeDependencyFor(). There's no
17242  * row type in pg_type, either.
17243  *
17244  * XXX this objsMoved test may be pointless -- surely we have a single
17245  * dependency link from a relation to each index?
17246  */
17247  if (!object_address_present(&thisobj, objsMoved))
17248  {
17249  AlterRelationNamespaceInternal(classRel, indexOid,
17250  oldNspOid, newNspOid,
17251  false, objsMoved);
17252  add_exact_object_address(&thisobj, objsMoved);
17253  }
17254  }
17255 
17256  list_free(indexList);
17257 }
17258 
17259 /*
17260  * Move all identity and SERIAL-column sequences of the specified relation to another
17261  * namespace.
17262  *
17263  * Note: we assume adequate permission checking was done by the caller,
17264  * and that the caller has a suitable lock on the owning relation.
17265  */
17266 static void
17268  Oid oldNspOid, Oid newNspOid, ObjectAddresses *objsMoved,
17269  LOCKMODE lockmode)
17270 {
17271  Relation depRel;
17272  SysScanDesc scan;
17273  ScanKeyData key[2];
17274  HeapTuple tup;
17275 
17276  /*
17277  * SERIAL sequences are those having an auto dependency on one of the
17278  * table's columns (we don't care *which* column, exactly).
17279  */
17280  depRel = table_open(DependRelationId, AccessShareLock);
17281 
17282  ScanKeyInit(&key[0],
17283  Anum_pg_depend_refclassid,
17284  BTEqualStrategyNumber, F_OIDEQ,
17285  ObjectIdGetDatum(RelationRelationId));
17286  ScanKeyInit(&key[1],
17287  Anum_pg_depend_refobjid,
17288  BTEqualStrategyNumber, F_OIDEQ,
17290  /* we leave refobjsubid unspecified */
17291 
17292  scan = systable_beginscan(depRel, DependReferenceIndexId, true,
17293  NULL, 2, key);
17294 
17295  while (HeapTupleIsValid(tup = systable_getnext(scan)))
17296  {
17297  Form_pg_depend depForm = (Form_pg_depend) GETSTRUCT(tup);
17298  Relation seqRel;
17299 
17300  /* skip dependencies other than auto dependencies on columns */
17301  if (depForm->refobjsubid == 0 ||
17302  depForm->classid != RelationRelationId ||
17303  depForm->objsubid != 0 ||
17304  !(depForm->deptype == DEPENDENCY_AUTO || depForm->deptype == DEPENDENCY_INTERNAL))
17305  continue;
17306 
17307  /* Use relation_open just in case it's an index */
17308  seqRel = relation_open(depForm->objid, lockmode);
17309 
17310  /* skip non-sequence relations */
17311  if (RelationGetForm(seqRel)->relkind != RELKIND_SEQUENCE)
17312  {
17313  /* No need to keep the lock */
17314  relation_close(seqRel, lockmode);
17315  continue;
17316  }
17317 
17318  /* Fix the pg_class and pg_depend entries */
17319  AlterRelationNamespaceInternal(classRel, depForm->objid,
17320  oldNspOid, newNspOid,
17321  true, objsMoved);
17322 
17323  /*
17324  * Sequences used to have entries in pg_type, but no longer do. If we
17325  * ever re-instate that, we'll need to move the pg_type entry to the
17326  * new namespace, too (using AlterTypeNamespaceInternal).
17327  */
17328  Assert(RelationGetForm(seqRel)->reltype == InvalidOid);
17329 
17330  /* Now we can close it. Keep the lock till end of transaction. */
17331  relation_close(seqRel, NoLock);
17332  }
17333 
17334  systable_endscan(scan);
17335 
17337 }
17338 
17339 
17340 /*
17341  * This code supports
17342  * CREATE TEMP TABLE ... ON COMMIT { DROP | PRESERVE ROWS | DELETE ROWS }
17343  *
17344  * Because we only support this for TEMP tables, it's sufficient to remember
17345  * the state in a backend-local data structure.
17346  */
17347 
17348 /*
17349  * Register a newly-created relation's ON COMMIT action.
17350  */
17351 void
17353 {
17354  OnCommitItem *oc;
17355  MemoryContext oldcxt;
17356 
17357  /*
17358  * We needn't bother registering the relation unless there is an ON COMMIT
17359  * action we need to take.
17360  */
17362  return;
17363 
17365 
17366  oc = (OnCommitItem *) palloc(sizeof(OnCommitItem));
17367  oc->relid = relid;
17368  oc->oncommit = action;
17371 
17372  /*
17373  * We use lcons() here so that ON COMMIT actions are processed in reverse
17374  * order of registration. That might not be essential but it seems
17375  * reasonable.
17376  */
17377  on_commits = lcons(oc, on_commits);
17378 
17379  MemoryContextSwitchTo(oldcxt);
17380 }
17381 
17382 /*
17383  * Unregister any ON COMMIT action when a relation is deleted.
17384  *
17385  * Actually, we only mark the OnCommitItem entry as to be deleted after commit.
17386  */
17387 void
17389 {
17390  ListCell *l;
17391 
17392  foreach(l, on_commits)
17393  {
17394  OnCommitItem *oc = (OnCommitItem *) lfirst(l);
17395 
17396  if (oc->relid == relid)
17397  {
17399  break;
17400  }
17401  }
17402 }
17403 
17404 /*
17405  * Perform ON COMMIT actions.
17406  *
17407  * This is invoked just before actually committing, since it's possible
17408  * to encounter errors.
17409  */
17410 void
17412 {
17413  ListCell *l;
17414  List *oids_to_truncate = NIL;
17415  List *oids_to_drop = NIL;
17416 
17417  foreach(l, on_commits)
17418  {
17419  OnCommitItem *oc = (OnCommitItem *) lfirst(l);
17420 
17421  /* Ignore entry if already dropped in this xact */
17423  continue;
17424 
17425  switch (oc->oncommit)
17426  {
17427  case ONCOMMIT_NOOP:
17429  /* Do nothing (there shouldn't be such entries, actually) */
17430  break;
17431  case ONCOMMIT_DELETE_ROWS:
17432 
17433  /*
17434  * If this transaction hasn't accessed any temporary
17435  * relations, we can skip truncating ON COMMIT DELETE ROWS
17436  * tables, as they must still be empty.
17437  */
17439  oids_to_truncate = lappend_oid(oids_to_truncate, oc->relid);
17440  break;
17441  case ONCOMMIT_DROP:
17442  oids_to_drop = lappend_oid(oids_to_drop, oc->relid);
17443  break;
17444  }
17445  }
17446 
17447  /*
17448  * Truncate relations before dropping so that all dependencies between
17449  * relations are removed after they are worked on. Doing it like this
17450  * might be a waste as it is possible that a relation being truncated will
17451  * be dropped anyway due to its parent being dropped, but this makes the
17452  * code more robust because of not having to re-check that the relation
17453  * exists at truncation time.
17454  */
17455  if (oids_to_truncate != NIL)
17456  heap_truncate(oids_to_truncate);
17457 
17458  if (oids_to_drop != NIL)
17459  {
17460  ObjectAddresses *targetObjects = new_object_addresses();
17461 
17462  foreach(l, oids_to_drop)
17463  {
17464  ObjectAddress object;
17465 
17466  object.classId = RelationRelationId;
17467  object.objectId = lfirst_oid(l);
17468  object.objectSubId = 0;
17469 
17470  Assert(!object_address_present(&object, targetObjects));
17471 
17472  add_exact_object_address(&object, targetObjects);
17473  }
17474 
17475  /*
17476  * Object deletion might involve toast table access (to clean up
17477  * toasted catalog entries), so ensure we have a valid snapshot.
17478  */
17480 
17481  /*
17482  * Since this is an automatic drop, rather than one directly initiated
17483  * by the user, we pass the PERFORM_DELETION_INTERNAL flag.
17484  */
17485  performMultipleDeletions(targetObjects, DROP_CASCADE,
17487 
17489 
17490 #ifdef USE_ASSERT_CHECKING
17491 
17492  /*
17493  * Note that table deletion will call remove_on_commit_action, so the
17494  * entry should get marked as deleted.
17495  */
17496  foreach(l, on_commits)
17497  {
17498  OnCommitItem *oc = (OnCommitItem *) lfirst(l);
17499 
17500  if (oc->oncommit != ONCOMMIT_DROP)
17501  continue;
17502 
17504  }
17505 #endif
17506  }
17507 }
17508 
17509 /*
17510  * Post-commit or post-abort cleanup for ON COMMIT management.
17511  *
17512  * All we do here is remove no-longer-needed OnCommitItem entries.
17513  *
17514  * During commit, remove entries that were deleted during this transaction;
17515  * during abort, remove those created during this transaction.
17516  */
17517 void
17519 {
17520  ListCell *cur_item;
17521 
17522  foreach(cur_item, on_commits)
17523  {
17524  OnCommitItem *oc = (OnCommitItem *) lfirst(cur_item);
17525 
17526  if (isCommit ? oc->deleting_subid != InvalidSubTransactionId :
17528  {
17529  /* cur_item must be removed */
17531  pfree(oc);
17532  }
17533  else
17534  {
17535  /* cur_item must be preserved */
17538  }
17539  }
17540 }
17541 
17542 /*
17543  * Post-subcommit or post-subabort cleanup for ON COMMIT management.
17544  *
17545  * During subabort, we can immediately remove entries created during this
17546  * subtransaction. During subcommit, just relabel entries marked during
17547  * this subtransaction as being the parent's responsibility.
17548  */
17549 void
17551  SubTransactionId parentSubid)
17552 {
17553  ListCell *cur_item;
17554 
17555  foreach(cur_item, on_commits)
17556  {
17557  OnCommitItem *oc = (OnCommitItem *) lfirst(cur_item);
17558 
17559  if (!isCommit && oc->creating_subid == mySubid)
17560  {
17561  /* cur_item must be removed */
17563  pfree(oc);
17564  }
17565  else
17566  {
17567  /* cur_item must be preserved */
17568  if (oc->creating_subid == mySubid)
17569  oc->creating_subid = parentSubid;
17570  if (oc->deleting_subid == mySubid)
17571  oc->deleting_subid = isCommit ? parentSubid : InvalidSubTransactionId;
17572  }
17573  }
17574 }
17575 
17576 /*
17577  * This is intended as a callback for RangeVarGetRelidExtended(). It allows
17578  * the relation to be locked only if (1) it's a plain or partitioned table,
17579  * materialized view, or TOAST table and (2) the current user is the owner (or
17580  * the superuser) or has been granted MAINTAIN. This meets the
17581  * permission-checking needs of CLUSTER, REINDEX TABLE, and REFRESH
17582  * MATERIALIZED VIEW; we expose it here so that it can be used by all.
17583  */
17584 void
17586  Oid relId, Oid oldRelId, void *arg)
17587 {
17588  char relkind;
17589  AclResult aclresult;
17590 
17591  /* Nothing to do if the relation was not found. */
17592  if (!OidIsValid(relId))
17593  return;
17594 
17595  /*
17596  * If the relation does exist, check whether it's an index. But note that
17597  * the relation might have been dropped between the time we did the name
17598  * lookup and now. In that case, there's nothing to do.
17599  */
17600  relkind = get_rel_relkind(relId);
17601  if (!relkind)
17602  return;
17603  if (relkind != RELKIND_RELATION && relkind != RELKIND_TOASTVALUE &&
17604  relkind != RELKIND_MATVIEW && relkind != RELKIND_PARTITIONED_TABLE)
17605  ereport(ERROR,
17606  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
17607  errmsg("\"%s\" is not a table or materialized view", relation->relname)));
17608 
17609  /* Check permissions */
17610  aclresult = pg_class_aclcheck(relId, GetUserId(), ACL_MAINTAIN);
17611  if (aclresult != ACLCHECK_OK)
17612  aclcheck_error(aclresult,
17614  relation->relname);
17615 }
17616 
17617 /*
17618  * Callback to RangeVarGetRelidExtended() for TRUNCATE processing.
17619  */
17620 static void
17622  Oid relId, Oid oldRelId, void *arg)
17623 {
17624  HeapTuple tuple;
17625 
17626  /* Nothing to do if the relation was not found. */
17627  if (!OidIsValid(relId))
17628  return;
17629 
17630  tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relId));
17631  if (!HeapTupleIsValid(tuple)) /* should not happen */
17632  elog(ERROR, "cache lookup failed for relation %u", relId);
17633 
17634  truncate_check_rel(relId, (Form_pg_class) GETSTRUCT(tuple));
17635  truncate_check_perms(relId, (Form_pg_class) GETSTRUCT(tuple));
17636 
17637  ReleaseSysCache(tuple);
17638 }
17639 
17640 /*
17641  * Callback for RangeVarGetRelidExtended(). Checks that the current user is
17642  * the owner of the relation, or superuser.
17643  */
17644 void
17646  Oid relId, Oid oldRelId, void *arg)
17647 {
17648  HeapTuple tuple;
17649 
17650  /* Nothing to do if the relation was not found. */
17651  if (!OidIsValid(relId))
17652  return;
17653 
17654  tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relId));
17655  if (!HeapTupleIsValid(tuple)) /* should not happen */
17656  elog(ERROR, "cache lookup failed for relation %u", relId);
17657 
17658  if (!object_ownercheck(RelationRelationId, relId, GetUserId()))
17660  relation->relname);
17661 
17662  if (!allowSystemTableMods &&
17663  IsSystemClass(relId, (Form_pg_class) GETSTRUCT(tuple)))
17664  ereport(ERROR,
17665  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
17666  errmsg("permission denied: \"%s\" is a system catalog",
17667  relation->relname)));
17668 
17669  ReleaseSysCache(tuple);
17670 }
17671 
17672 /*
17673  * Common RangeVarGetRelid callback for rename, set schema, and alter table
17674  * processing.
17675  */
17676 static void
17678  void *arg)
17679 {
17680  Node *stmt = (Node *) arg;
17681  ObjectType reltype;
17682  HeapTuple tuple;
17683  Form_pg_class classform;
17684  AclResult aclresult;
17685  char relkind;
17686 
17687  tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
17688  if (!HeapTupleIsValid(tuple))
17689  return; /* concurrently dropped */
17690  classform = (Form_pg_class) GETSTRUCT(tuple);
17691  relkind = classform->relkind;
17692 
17693  /* Must own relation. */
17694  if (!object_ownercheck(RelationRelationId, relid, GetUserId()))
17696 
17697  /* No system table modifications unless explicitly allowed. */
17698  if (!allowSystemTableMods && IsSystemClass(relid, classform))
17699  ereport(ERROR,
17700  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
17701  errmsg("permission denied: \"%s\" is a system catalog",
17702  rv->relname)));
17703 
17704  /*
17705  * Extract the specified relation type from the statement parse tree.
17706  *
17707  * Also, for ALTER .. RENAME, check permissions: the user must (still)
17708  * have CREATE rights on the containing namespace.
17709  */
17710  if (IsA(stmt, RenameStmt))
17711  {
17712  aclresult = object_aclcheck(NamespaceRelationId, classform->relnamespace,
17713  GetUserId(), ACL_CREATE);
17714  if (aclresult != ACLCHECK_OK)
17715  aclcheck_error(aclresult, OBJECT_SCHEMA,
17716  get_namespace_name(classform->relnamespace));
17717  reltype = ((RenameStmt *) stmt)->renameType;
17718  }
17719  else if (IsA(stmt, AlterObjectSchemaStmt))
17720  reltype = ((AlterObjectSchemaStmt *) stmt)->objectType;
17721 
17722  else if (IsA(stmt, AlterTableStmt))
17723  reltype = ((AlterTableStmt *) stmt)->objtype;
17724  else
17725  {
17726  elog(ERROR, "unrecognized node type: %d", (int) nodeTag(stmt));
17727  reltype = OBJECT_TABLE; /* placate compiler */
17728  }
17729 
17730  /*
17731  * For compatibility with prior releases, we allow ALTER TABLE to be used
17732  * with most other types of relations (but not composite types). We allow
17733  * similar flexibility for ALTER INDEX in the case of RENAME, but not
17734  * otherwise. Otherwise, the user must select the correct form of the
17735  * command for the relation at issue.
17736  */
17737  if (reltype == OBJECT_SEQUENCE && relkind != RELKIND_SEQUENCE)
17738  ereport(ERROR,
17739  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
17740  errmsg("\"%s\" is not a sequence", rv->relname)));
17741 
17742  if (reltype == OBJECT_VIEW && relkind != RELKIND_VIEW)
17743  ereport(ERROR,
17744  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
17745  errmsg("\"%s\" is not a view", rv->relname)));
17746 
17747  if (reltype == OBJECT_MATVIEW && relkind != RELKIND_MATVIEW)
17748  ereport(ERROR,
17749  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
17750  errmsg("\"%s\" is not a materialized view", rv->relname)));
17751 
17752  if (reltype == OBJECT_FOREIGN_TABLE && relkind != RELKIND_FOREIGN_TABLE)
17753  ereport(ERROR,
17754  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
17755  errmsg("\"%s\" is not a foreign table", rv->relname)));
17756 
17757  if (reltype == OBJECT_TYPE && relkind != RELKIND_COMPOSITE_TYPE)
17758  ereport(ERROR,
17759  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
17760  errmsg("\"%s\" is not a composite type", rv->relname)));
17761 
17762  if (reltype == OBJECT_INDEX && relkind != RELKIND_INDEX &&
17763  relkind != RELKIND_PARTITIONED_INDEX
17764  && !IsA(stmt, RenameStmt))
17765  ereport(ERROR,
17766  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
17767  errmsg("\"%s\" is not an index", rv->relname)));
17768 
17769  /*
17770  * Don't allow ALTER TABLE on composite types. We want people to use ALTER
17771  * TYPE for that.
17772  */
17773  if (reltype != OBJECT_TYPE && relkind == RELKIND_COMPOSITE_TYPE)
17774  ereport(ERROR,
17775  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
17776  errmsg("\"%s\" is a composite type", rv->relname),
17777  /* translator: %s is an SQL ALTER command */
17778  errhint("Use %s instead.",
17779  "ALTER TYPE")));
17780 
17781  /*
17782  * Don't allow ALTER TABLE .. SET SCHEMA on relations that can't be moved
17783  * to a different schema, such as indexes and TOAST tables.
17784  */
17786  {
17787  if (relkind == RELKIND_INDEX || relkind == RELKIND_PARTITIONED_INDEX)
17788  ereport(ERROR,
17789  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
17790  errmsg("cannot change schema of index \"%s\"",
17791  rv->relname),
17792  errhint("Change the schema of the table instead.")));
17793  else if (relkind == RELKIND_COMPOSITE_TYPE)
17794  ereport(ERROR,
17795  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
17796  errmsg("cannot change schema of composite type \"%s\"",
17797  rv->relname),
17798  /* translator: %s is an SQL ALTER command */
17799  errhint("Use %s instead.",
17800  "ALTER TYPE")));
17801  else if (relkind == RELKIND_TOASTVALUE)
17802  ereport(ERROR,
17803  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
17804  errmsg("cannot change schema of TOAST table \"%s\"",
17805  rv->relname),
17806  errhint("Change the schema of the table instead.")));
17807  }
17808 
17809  ReleaseSysCache(tuple);
17810 }
17811 
17812 /*
17813  * Transform any expressions present in the partition key
17814  *
17815  * Returns a transformed PartitionSpec.
17816  */
17817 static PartitionSpec *
17819 {
17820  PartitionSpec *newspec;
17821  ParseState *pstate;
17822  ParseNamespaceItem *nsitem;
17823  ListCell *l;
17824 
17825  newspec = makeNode(PartitionSpec);
17826 
17827  newspec->strategy = partspec->strategy;
17828  newspec->partParams = NIL;
17829  newspec->location = partspec->location;
17830 
17831  /* Check valid number of columns for strategy */
17832  if (partspec->strategy == PARTITION_STRATEGY_LIST &&
17833  list_length(partspec->partParams) != 1)
17834  ereport(ERROR,
17835  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
17836  errmsg("cannot use \"list\" partition strategy with more than one column")));
17837 
17838  /*
17839  * Create a dummy ParseState and insert the target relation as its sole
17840  * rangetable entry. We need a ParseState for transformExpr.
17841  */
17842  pstate = make_parsestate(NULL);
17843  nsitem = addRangeTableEntryForRelation(pstate, rel, AccessShareLock,
17844  NULL, false, true);
17845  addNSItemToQuery(pstate, nsitem, true, true, true);
17846 
17847  /* take care of any partition expressions */
17848  foreach(l, partspec->partParams)
17849  {
17851 
17852  if (pelem->expr)
17853  {
17854  /* Copy, to avoid scribbling on the input */
17855  pelem = copyObject(pelem);
17856 
17857  /* Now do parse transformation of the expression */
17858  pelem->expr = transformExpr(pstate, pelem->expr,
17860 
17861  /* we have to fix its collations too */
17862  assign_expr_collations(pstate, pelem->expr);
17863  }
17864 
17865  newspec->partParams = lappend(newspec->partParams, pelem);
17866  }
17867 
17868  return newspec;
17869 }
17870 
17871 /*
17872  * Compute per-partition-column information from a list of PartitionElems.
17873  * Expressions in the PartitionElems must be parse-analyzed already.
17874  */
17875 static void
17876 ComputePartitionAttrs(ParseState *pstate, Relation rel, List *partParams, AttrNumber *partattrs,
17877  List **partexprs, Oid *partopclass, Oid *partcollation,
17878  PartitionStrategy strategy)
17879 {
17880  int attn;
17881  ListCell *lc;
17882  Oid am_oid;
17883 
17884  attn = 0;
17885  foreach(lc, partParams)
17886  {
17887  PartitionElem *pelem = lfirst_node(PartitionElem, lc);
17888  Oid atttype;
17889  Oid attcollation;
17890 
17891  if (pelem->name != NULL)
17892  {
17893  /* Simple attribute reference */
17894  HeapTuple atttuple;
17895  Form_pg_attribute attform;
17896 
17897  atttuple = SearchSysCacheAttName(RelationGetRelid(rel),
17898  pelem->name);
17899  if (!HeapTupleIsValid(atttuple))
17900  ereport(ERROR,
17901  (errcode(ERRCODE_UNDEFINED_COLUMN),
17902  errmsg("column \"%s\" named in partition key does not exist",
17903  pelem->name),
17904  parser_errposition(pstate, pelem->location)));
17905  attform = (Form_pg_attribute) GETSTRUCT(atttuple);
17906 
17907  if (attform->attnum <= 0)
17908  ereport(ERROR,
17909  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
17910  errmsg("cannot use system column \"%s\" in partition key",
17911  pelem->name),
17912  parser_errposition(pstate, pelem->location)));
17913 
17914  /*
17915  * Generated columns cannot work: They are computed after BEFORE
17916  * triggers, but partition routing is done before all triggers.
17917  */
17918  if (attform->attgenerated)
17919  ereport(ERROR,
17920  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
17921  errmsg("cannot use generated column in partition key"),
17922  errdetail("Column \"%s\" is a generated column.",
17923  pelem->name),
17924  parser_errposition(pstate, pelem->location)));
17925 
17926  partattrs[attn] = attform->attnum;
17927  atttype = attform->atttypid;
17928  attcollation = attform->attcollation;
17929  ReleaseSysCache(atttuple);
17930  }
17931  else
17932  {
17933  /* Expression */
17934  Node *expr = pelem->expr;
17935  char partattname[16];
17936 
17937  Assert(expr != NULL);
17938  atttype = exprType(expr);
17939  attcollation = exprCollation(expr);
17940 
17941  /*
17942  * The expression must be of a storable type (e.g., not RECORD).
17943  * The test is the same as for whether a table column is of a safe
17944  * type (which is why we needn't check for the non-expression
17945  * case).
17946  */
17947  snprintf(partattname, sizeof(partattname), "%d", attn + 1);
17948  CheckAttributeType(partattname,
17949  atttype, attcollation,
17951 
17952  /*
17953  * Strip any top-level COLLATE clause. This ensures that we treat
17954  * "x COLLATE y" and "(x COLLATE y)" alike.
17955  */
17956  while (IsA(expr, CollateExpr))
17957  expr = (Node *) ((CollateExpr *) expr)->arg;
17958 
17959  if (IsA(expr, Var) &&
17960  ((Var *) expr)->varattno > 0)
17961  {
17962  /*
17963  * User wrote "(column)" or "(column COLLATE something)".
17964  * Treat it like simple attribute anyway.
17965  */
17966  partattrs[attn] = ((Var *) expr)->varattno;
17967  }
17968  else
17969  {
17970  Bitmapset *expr_attrs = NULL;
17971  int i;
17972 
17973  partattrs[attn] = 0; /* marks the column as expression */
17974  *partexprs = lappend(*partexprs, expr);
17975 
17976  /*
17977  * transformPartitionSpec() should have already rejected
17978  * subqueries, aggregates, window functions, and SRFs, based
17979  * on the EXPR_KIND_ for partition expressions.
17980  */
17981 
17982  /*
17983  * Cannot allow system column references, since that would
17984  * make partition routing impossible: their values won't be
17985  * known yet when we need to do that.
17986  */
17987  pull_varattnos(expr, 1, &expr_attrs);
17988  for (i = FirstLowInvalidHeapAttributeNumber; i < 0; i++)
17989  {
17991  expr_attrs))
17992  ereport(ERROR,
17993  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
17994  errmsg("partition key expressions cannot contain system column references")));
17995  }
17996 
17997  /*
17998  * Generated columns cannot work: They are computed after
17999  * BEFORE triggers, but partition routing is done before all
18000  * triggers.
18001  */
18002  i = -1;
18003  while ((i = bms_next_member(expr_attrs, i)) >= 0)
18004  {
18006 
18007  if (attno > 0 &&
18008  TupleDescAttr(RelationGetDescr(rel), attno - 1)->attgenerated)
18009  ereport(ERROR,
18010  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
18011  errmsg("cannot use generated column in partition key"),
18012  errdetail("Column \"%s\" is a generated column.",
18013  get_attname(RelationGetRelid(rel), attno, false)),
18014  parser_errposition(pstate, pelem->location)));
18015  }
18016 
18017  /*
18018  * Preprocess the expression before checking for mutability.
18019  * This is essential for the reasons described in
18020  * contain_mutable_functions_after_planning. However, we call
18021  * expression_planner for ourselves rather than using that
18022  * function, because if constant-folding reduces the
18023  * expression to a constant, we'd like to know that so we can
18024  * complain below.
18025  *
18026  * Like contain_mutable_functions_after_planning, assume that
18027  * expression_planner won't scribble on its input, so this
18028  * won't affect the partexprs entry we saved above.
18029  */
18030  expr = (Node *) expression_planner((Expr *) expr);
18031 
18032  /*
18033  * Partition expressions cannot contain mutable functions,
18034  * because a given row must always map to the same partition
18035  * as long as there is no change in the partition boundary
18036  * structure.
18037  */
18038  if (contain_mutable_functions(expr))
18039  ereport(ERROR,
18040  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
18041  errmsg("functions in partition key expression must be marked IMMUTABLE")));
18042 
18043  /*
18044  * While it is not exactly *wrong* for a partition expression
18045  * to be a constant, it seems better to reject such keys.
18046  */
18047  if (IsA(expr, Const))
18048  ereport(ERROR,
18049  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
18050  errmsg("cannot use constant expression as partition key")));
18051  }
18052  }
18053 
18054  /*
18055  * Apply collation override if any
18056  */
18057  if (pelem->collation)
18058  attcollation = get_collation_oid(pelem->collation, false);
18059 
18060  /*
18061  * Check we have a collation iff it's a collatable type. The only
18062  * expected failures here are (1) COLLATE applied to a noncollatable
18063  * type, or (2) partition expression had an unresolved collation. But
18064  * we might as well code this to be a complete consistency check.
18065  */
18066  if (type_is_collatable(atttype))
18067  {
18068  if (!OidIsValid(attcollation))
18069  ereport(ERROR,
18070  (errcode(ERRCODE_INDETERMINATE_COLLATION),
18071  errmsg("could not determine which collation to use for partition expression"),
18072  errhint("Use the COLLATE clause to set the collation explicitly.")));
18073  }
18074  else
18075  {
18076  if (OidIsValid(attcollation))
18077  ereport(ERROR,
18078  (errcode(ERRCODE_DATATYPE_MISMATCH),
18079  errmsg("collations are not supported by type %s",
18080  format_type_be(atttype))));
18081  }
18082 
18083  partcollation[attn] = attcollation;
18084 
18085  /*
18086  * Identify the appropriate operator class. For list and range
18087  * partitioning, we use a btree operator class; hash partitioning uses
18088  * a hash operator class.
18089  */
18090  if (strategy == PARTITION_STRATEGY_HASH)
18091  am_oid = HASH_AM_OID;
18092  else
18093  am_oid = BTREE_AM_OID;
18094 
18095  if (!pelem->opclass)
18096  {
18097  partopclass[attn] = GetDefaultOpClass(atttype, am_oid);
18098 
18099  if (!OidIsValid(partopclass[attn]))
18100  {
18101  if (strategy == PARTITION_STRATEGY_HASH)
18102  ereport(ERROR,
18103  (errcode(ERRCODE_UNDEFINED_OBJECT),
18104  errmsg("data type %s has no default operator class for access method \"%s\"",
18105  format_type_be(atttype), "hash"),
18106  errhint("You must specify a hash operator class or define a default hash operator class for the data type.")));
18107  else
18108  ereport(ERROR,
18109  (errcode(ERRCODE_UNDEFINED_OBJECT),
18110  errmsg("data type %s has no default operator class for access method \"%s\"",
18111  format_type_be(atttype), "btree"),
18112  errhint("You must specify a btree operator class or define a default btree operator class for the data type.")));
18113  }
18114  }
18115  else
18116  partopclass[attn] = ResolveOpClass(pelem->opclass,
18117  atttype,
18118  am_oid == HASH_AM_OID ? "hash" : "btree",
18119  am_oid);
18120 
18121  attn++;
18122  }
18123 }
18124 
18125 /*
18126  * PartConstraintImpliedByRelConstraint
18127  * Do scanrel's existing constraints imply the partition constraint?
18128  *
18129  * "Existing constraints" include its check constraints and column-level
18130  * not-null constraints. partConstraint describes the partition constraint,
18131  * in implicit-AND form.
18132  */
18133 bool
18135  List *partConstraint)
18136 {
18137  List *existConstraint = NIL;
18138  TupleConstr *constr = RelationGetDescr(scanrel)->constr;
18139  int i;
18140 
18141  if (constr && constr->has_not_null)
18142  {
18143  int natts = scanrel->rd_att->natts;
18144 
18145  for (i = 1; i <= natts; i++)
18146  {
18147  Form_pg_attribute att = TupleDescAttr(scanrel->rd_att, i - 1);
18148 
18149  if (att->attnotnull && !att->attisdropped)
18150  {
18151  NullTest *ntest = makeNode(NullTest);
18152 
18153  ntest->arg = (Expr *) makeVar(1,
18154  i,
18155  att->atttypid,
18156  att->atttypmod,
18157  att->attcollation,
18158  0);
18159  ntest->nulltesttype = IS_NOT_NULL;
18160 
18161  /*
18162  * argisrow=false is correct even for a composite column,
18163  * because attnotnull does not represent a SQL-spec IS NOT
18164  * NULL test in such a case, just IS DISTINCT FROM NULL.
18165  */
18166  ntest->argisrow = false;
18167  ntest->location = -1;
18168  existConstraint = lappend(existConstraint, ntest);
18169  }
18170  }
18171  }
18172 
18173  return ConstraintImpliedByRelConstraint(scanrel, partConstraint, existConstraint);
18174 }
18175 
18176 /*
18177  * ConstraintImpliedByRelConstraint
18178  * Do scanrel's existing constraints imply the given constraint?
18179  *
18180  * testConstraint is the constraint to validate. provenConstraint is a
18181  * caller-provided list of conditions which this function may assume
18182  * to be true. Both provenConstraint and testConstraint must be in
18183  * implicit-AND form, must only contain immutable clauses, and must
18184  * contain only Vars with varno = 1.
18185  */
18186 bool
18187 ConstraintImpliedByRelConstraint(Relation scanrel, List *testConstraint, List *provenConstraint)
18188 {
18189  List *existConstraint = list_copy(provenConstraint);
18190  TupleConstr *constr = RelationGetDescr(scanrel)->constr;
18191  int num_check,
18192  i;
18193 
18194  num_check = (constr != NULL) ? constr->num_check : 0;
18195  for (i = 0; i < num_check; i++)
18196  {
18197  Node *cexpr;
18198 
18199  /*
18200  * If this constraint hasn't been fully validated yet, we must ignore
18201  * it here.
18202  */
18203  if (!constr->check[i].ccvalid)
18204  continue;
18205 
18206  cexpr = stringToNode(constr->check[i].ccbin);
18207 
18208  /*
18209  * Run each expression through const-simplification and
18210  * canonicalization. It is necessary, because we will be comparing it
18211  * to similarly-processed partition constraint expressions, and may
18212  * fail to detect valid matches without this.
18213  */
18214  cexpr = eval_const_expressions(NULL, cexpr);
18215  cexpr = (Node *) canonicalize_qual((Expr *) cexpr, true);
18216 
18217  existConstraint = list_concat(existConstraint,
18218  make_ands_implicit((Expr *) cexpr));
18219  }
18220 
18221  /*
18222  * Try to make the proof. Since we are comparing CHECK constraints, we
18223  * need to use weak implication, i.e., we assume existConstraint is
18224  * not-false and try to prove the same for testConstraint.
18225  *
18226  * Note that predicate_implied_by assumes its first argument is known
18227  * immutable. That should always be true for both NOT NULL and partition
18228  * constraints, so we don't test it here.
18229  */
18230  return predicate_implied_by(testConstraint, existConstraint, true);
18231 }
18232 
18233 /*
18234  * QueuePartitionConstraintValidation
18235  *
18236  * Add an entry to wqueue to have the given partition constraint validated by
18237  * Phase 3, for the given relation, and all its children.
18238  *
18239  * We first verify whether the given constraint is implied by pre-existing
18240  * relation constraints; if it is, there's no need to scan the table to
18241  * validate, so don't queue in that case.
18242  */
18243 static void
18245  List *partConstraint,
18246  bool validate_default)
18247 {
18248  /*
18249  * Based on the table's existing constraints, determine whether or not we
18250  * may skip scanning the table.
18251  */
18252  if (PartConstraintImpliedByRelConstraint(scanrel, partConstraint))
18253  {
18254  if (!validate_default)
18255  ereport(DEBUG1,
18256  (errmsg_internal("partition constraint for table \"%s\" is implied by existing constraints",
18257  RelationGetRelationName(scanrel))));
18258  else
18259  ereport(DEBUG1,
18260  (errmsg_internal("updated partition constraint for default partition \"%s\" is implied by existing constraints",
18261  RelationGetRelationName(scanrel))));
18262  return;
18263  }
18264 
18265  /*
18266  * Constraints proved insufficient. For plain relations, queue a
18267  * validation item now; for partitioned tables, recurse to process each
18268  * partition.
18269  */
18270  if (scanrel->rd_rel->relkind == RELKIND_RELATION)
18271  {
18272  AlteredTableInfo *tab;
18273 
18274  /* Grab a work queue entry. */
18275  tab = ATGetQueueEntry(wqueue, scanrel);
18276  Assert(tab->partition_constraint == NULL);
18277  tab->partition_constraint = (Expr *) linitial(partConstraint);
18278  tab->validate_default = validate_default;
18279  }
18280  else if (scanrel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
18281  {
18282  PartitionDesc partdesc = RelationGetPartitionDesc(scanrel, true);
18283  int i;
18284 
18285  for (i = 0; i < partdesc->nparts; i++)
18286  {
18287  Relation part_rel;
18288  List *thisPartConstraint;
18289 
18290  /*
18291  * This is the minimum lock we need to prevent deadlocks.
18292  */
18293  part_rel = table_open(partdesc->oids[i], AccessExclusiveLock);
18294 
18295  /*
18296  * Adjust the constraint for scanrel so that it matches this
18297  * partition's attribute numbers.
18298  */
18299  thisPartConstraint =
18300  map_partition_varattnos(partConstraint, 1,
18301  part_rel, scanrel);
18302 
18303  QueuePartitionConstraintValidation(wqueue, part_rel,
18304  thisPartConstraint,
18305  validate_default);
18306  table_close(part_rel, NoLock); /* keep lock till commit */
18307  }
18308  }
18309 }
18310 
18311 /*
18312  * attachPartitionTable: attach a new partition to the partitioned table
18313  *
18314  * wqueue: the ALTER TABLE work queue; can be NULL when not running as part
18315  * of an ALTER TABLE sequence.
18316  * rel: partitioned relation;
18317  * attachrel: relation of attached partition;
18318  * bound: bounds of attached relation.
18319  */
18320 static void
18322 {
18323  /* OK to create inheritance. Rest of the checks performed there */
18324  CreateInheritance(attachrel, rel, true);
18325 
18326  /* Update the pg_class entry. */
18327  StorePartitionBound(attachrel, rel, bound);
18328 
18329  /* Ensure there exists a correct set of indexes in the partition. */
18330  AttachPartitionEnsureIndexes(wqueue, rel, attachrel);
18331 
18332  /* and triggers */
18333  CloneRowTriggersToPartition(rel, attachrel);
18334 
18335  /*
18336  * Clone foreign key constraints. Callee is responsible for setting up
18337  * for phase 3 constraint verification.
18338  */
18339  CloneForeignKeyConstraints(wqueue, rel, attachrel);
18340 }
18341 
18342 /*
18343  * ALTER TABLE <name> ATTACH PARTITION <partition-name> FOR VALUES
18344  *
18345  * Return the address of the newly attached partition.
18346  */
18347 static ObjectAddress
18350 {
18351  Relation attachrel,
18352  catalog;
18353  List *attachrel_children;
18354  List *partConstraint;
18355  SysScanDesc scan;
18356  ScanKeyData skey;
18357  AttrNumber attno;
18358  int natts;
18359  TupleDesc tupleDesc;
18360  ObjectAddress address;
18361  const char *trigger_name;
18362  Oid defaultPartOid;
18363  List *partBoundConstraint;
18364  ParseState *pstate = make_parsestate(NULL);
18365 
18366  pstate->p_sourcetext = context->queryString;
18367 
18368  /*
18369  * We must lock the default partition if one exists, because attaching a
18370  * new partition will change its partition constraint.
18371  */
18372  defaultPartOid =
18374  if (OidIsValid(defaultPartOid))
18375  LockRelationOid(defaultPartOid, AccessExclusiveLock);
18376 
18377  attachrel = table_openrv(cmd->name, AccessExclusiveLock);
18378 
18379  /*
18380  * XXX I think it'd be a good idea to grab locks on all tables referenced
18381  * by FKs at this point also.
18382  */
18383 
18384  /*
18385  * Must be owner of both parent and source table -- parent was checked by
18386  * ATSimplePermissions call in ATPrepCmd
18387  */
18389 
18390  /* A partition can only have one parent */
18391  if (attachrel->rd_rel->relispartition)
18392  ereport(ERROR,
18393  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
18394  errmsg("\"%s\" is already a partition",
18395  RelationGetRelationName(attachrel))));
18396 
18397  if (OidIsValid(attachrel->rd_rel->reloftype))
18398  ereport(ERROR,
18399  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
18400  errmsg("cannot attach a typed table as partition")));
18401 
18402  /*
18403  * Table being attached should not already be part of inheritance; either
18404  * as a child table...
18405  */
18406  catalog = table_open(InheritsRelationId, AccessShareLock);
18407  ScanKeyInit(&skey,
18408  Anum_pg_inherits_inhrelid,
18409  BTEqualStrategyNumber, F_OIDEQ,
18410  ObjectIdGetDatum(RelationGetRelid(attachrel)));
18411  scan = systable_beginscan(catalog, InheritsRelidSeqnoIndexId, true,
18412  NULL, 1, &skey);
18414  ereport(ERROR,
18415  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
18416  errmsg("cannot attach inheritance child as partition")));
18417  systable_endscan(scan);
18418 
18419  /* ...or as a parent table (except the case when it is partitioned) */
18420  ScanKeyInit(&skey,
18421  Anum_pg_inherits_inhparent,
18422  BTEqualStrategyNumber, F_OIDEQ,
18423  ObjectIdGetDatum(RelationGetRelid(attachrel)));
18424  scan = systable_beginscan(catalog, InheritsParentIndexId, true, NULL,
18425  1, &skey);
18426  if (HeapTupleIsValid(systable_getnext(scan)) &&
18427  attachrel->rd_rel->relkind == RELKIND_RELATION)
18428  ereport(ERROR,
18429  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
18430  errmsg("cannot attach inheritance parent as partition")));
18431  systable_endscan(scan);
18432  table_close(catalog, AccessShareLock);
18433 
18434  /*
18435  * Prevent circularity by seeing if rel is a partition of attachrel. (In
18436  * particular, this disallows making a rel a partition of itself.)
18437  *
18438  * We do that by checking if rel is a member of the list of attachrel's
18439  * partitions provided the latter is partitioned at all. We want to avoid
18440  * having to construct this list again, so we request the strongest lock
18441  * on all partitions. We need the strongest lock, because we may decide
18442  * to scan them if we find out that the table being attached (or its leaf
18443  * partitions) may contain rows that violate the partition constraint. If
18444  * the table has a constraint that would prevent such rows, which by
18445  * definition is present in all the partitions, we need not scan the
18446  * table, nor its partitions. But we cannot risk a deadlock by taking a
18447  * weaker lock now and the stronger one only when needed.
18448  */
18449  attachrel_children = find_all_inheritors(RelationGetRelid(attachrel),
18450  AccessExclusiveLock, NULL);
18451  if (list_member_oid(attachrel_children, RelationGetRelid(rel)))
18452  ereport(ERROR,
18453  (errcode(ERRCODE_DUPLICATE_TABLE),
18454  errmsg("circular inheritance not allowed"),
18455  errdetail("\"%s\" is already a child of \"%s\".",
18457  RelationGetRelationName(attachrel))));
18458 
18459  /* If the parent is permanent, so must be all of its partitions. */
18460  if (rel->rd_rel->relpersistence != RELPERSISTENCE_TEMP &&
18461  attachrel->rd_rel->relpersistence == RELPERSISTENCE_TEMP)
18462  ereport(ERROR,
18463  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
18464  errmsg("cannot attach a temporary relation as partition of permanent relation \"%s\"",
18465  RelationGetRelationName(rel))));
18466 
18467  /* Temp parent cannot have a partition that is itself not a temp */
18468  if (rel->rd_rel->relpersistence == RELPERSISTENCE_TEMP &&
18469  attachrel->rd_rel->relpersistence != RELPERSISTENCE_TEMP)
18470  ereport(ERROR,
18471  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
18472  errmsg("cannot attach a permanent relation as partition of temporary relation \"%s\"",
18473  RelationGetRelationName(rel))));
18474 
18475  /* If the parent is temp, it must belong to this session */
18476  if (rel->rd_rel->relpersistence == RELPERSISTENCE_TEMP &&
18477  !rel->rd_islocaltemp)
18478  ereport(ERROR,
18479  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
18480  errmsg("cannot attach as partition of temporary relation of another session")));
18481 
18482  /* Ditto for the partition */
18483  if (attachrel->rd_rel->relpersistence == RELPERSISTENCE_TEMP &&
18484  !attachrel->rd_islocaltemp)
18485  ereport(ERROR,
18486  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
18487  errmsg("cannot attach temporary relation of another session as partition")));
18488 
18489  /*
18490  * Check if attachrel has any identity columns or any columns that aren't
18491  * in the parent.
18492  */
18493  tupleDesc = RelationGetDescr(attachrel);
18494  natts = tupleDesc->natts;
18495  for (attno = 1; attno <= natts; attno++)
18496  {
18497  Form_pg_attribute attribute = TupleDescAttr(tupleDesc, attno - 1);
18498  char *attributeName = NameStr(attribute->attname);
18499 
18500  /* Ignore dropped */
18501  if (attribute->attisdropped)
18502  continue;
18503 
18504  if (attribute->attidentity)
18505  ereport(ERROR,
18506  errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
18507  errmsg("table \"%s\" being attached contains an identity column \"%s\"",
18508  RelationGetRelationName(attachrel), attributeName),
18509  errdetail("The new partition may not contain an identity column."));
18510 
18511  /* Try to find the column in parent (matching on column name) */
18512  if (!SearchSysCacheExists2(ATTNAME,
18514  CStringGetDatum(attributeName)))
18515  ereport(ERROR,
18516  (errcode(ERRCODE_DATATYPE_MISMATCH),
18517  errmsg("table \"%s\" contains column \"%s\" not found in parent \"%s\"",
18518  RelationGetRelationName(attachrel), attributeName,
18520  errdetail("The new partition may contain only the columns present in parent.")));
18521  }
18522 
18523  /*
18524  * If child_rel has row-level triggers with transition tables, we
18525  * currently don't allow it to become a partition. See also prohibitions
18526  * in ATExecAddInherit() and CreateTrigger().
18527  */
18528  trigger_name = FindTriggerIncompatibleWithInheritance(attachrel->trigdesc);
18529  if (trigger_name != NULL)
18530  ereport(ERROR,
18531  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
18532  errmsg("trigger \"%s\" prevents table \"%s\" from becoming a partition",
18533  trigger_name, RelationGetRelationName(attachrel)),
18534  errdetail("ROW triggers with transition tables are not supported on partitions.")));
18535 
18536  /*
18537  * Check that the new partition's bound is valid and does not overlap any
18538  * of existing partitions of the parent - note that it does not return on
18539  * error.
18540  */
18542  cmd->bound, pstate);
18543 
18544  /* Attach a new partition to the partitioned table. */
18545  attachPartitionTable(wqueue, rel, attachrel, cmd->bound);
18546 
18547  /*
18548  * Generate partition constraint from the partition bound specification.
18549  * If the parent itself is a partition, make sure to include its
18550  * constraint as well.
18551  */
18552  partBoundConstraint = get_qual_from_partbound(rel, cmd->bound);
18553  partConstraint = list_concat(partBoundConstraint,
18555 
18556  /* Skip validation if there are no constraints to validate. */
18557  if (partConstraint)
18558  {
18559  /*
18560  * Run the partition quals through const-simplification similar to
18561  * check constraints. We skip canonicalize_qual, though, because
18562  * partition quals should be in canonical form already.
18563  */
18564  partConstraint =
18565  (List *) eval_const_expressions(NULL,
18566  (Node *) partConstraint);
18567 
18568  /* XXX this sure looks wrong */
18569  partConstraint = list_make1(make_ands_explicit(partConstraint));
18570 
18571  /*
18572  * Adjust the generated constraint to match this partition's attribute
18573  * numbers.
18574  */
18575  partConstraint = map_partition_varattnos(partConstraint, 1, attachrel,
18576  rel);
18577 
18578  /* Validate partition constraints against the table being attached. */
18579  QueuePartitionConstraintValidation(wqueue, attachrel, partConstraint,
18580  false);
18581  }
18582 
18583  /*
18584  * If we're attaching a partition other than the default partition and a
18585  * default one exists, then that partition's partition constraint changes,
18586  * so add an entry to the work queue to validate it, too. (We must not do
18587  * this when the partition being attached is the default one; we already
18588  * did it above!)
18589  */
18590  if (OidIsValid(defaultPartOid))
18591  {
18592  Relation defaultrel;
18593  List *defPartConstraint;
18594 
18595  Assert(!cmd->bound->is_default);
18596 
18597  /* we already hold a lock on the default partition */
18598  defaultrel = table_open(defaultPartOid, NoLock);
18599  defPartConstraint =
18600  get_proposed_default_constraint(partBoundConstraint);
18601 
18602  /*
18603  * Map the Vars in the constraint expression from rel's attnos to
18604  * defaultrel's.
18605  */
18606  defPartConstraint =
18607  map_partition_varattnos(defPartConstraint,
18608  1, defaultrel, rel);
18609  QueuePartitionConstraintValidation(wqueue, defaultrel,
18610  defPartConstraint, true);
18611 
18612  /* keep our lock until commit. */
18613  table_close(defaultrel, NoLock);
18614  }
18615 
18616  ObjectAddressSet(address, RelationRelationId, RelationGetRelid(attachrel));
18617 
18618  /*
18619  * If the partition we just attached is partitioned itself, invalidate
18620  * relcache for all descendent partitions too to ensure that their
18621  * rd_partcheck expression trees are rebuilt; partitions already locked at
18622  * the beginning of this function.
18623  */
18624  if (attachrel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
18625  {
18626  ListCell *l;
18627 
18628  foreach(l, attachrel_children)
18629  {
18631  }
18632  }
18633 
18634  /* keep our lock until commit */
18635  table_close(attachrel, NoLock);
18636 
18637  return address;
18638 }
18639 
18640 /*
18641  * AttachPartitionEnsureIndexes
18642  * subroutine for ATExecAttachPartition to create/match indexes
18643  *
18644  * Enforce the indexing rule for partitioned tables during ALTER TABLE / ATTACH
18645  * PARTITION: every partition must have an index attached to each index on the
18646  * partitioned table.
18647  */
18648 static void
18650 {
18651  List *idxes;
18652  List *attachRelIdxs;
18653  Relation *attachrelIdxRels;
18654  IndexInfo **attachInfos;
18655  ListCell *cell;
18656  MemoryContext cxt;
18657  MemoryContext oldcxt;
18658 
18660  "AttachPartitionEnsureIndexes",
18662  oldcxt = MemoryContextSwitchTo(cxt);
18663 
18664  idxes = RelationGetIndexList(rel);
18665  attachRelIdxs = RelationGetIndexList(attachrel);
18666  attachrelIdxRels = palloc(sizeof(Relation) * list_length(attachRelIdxs));
18667  attachInfos = palloc(sizeof(IndexInfo *) * list_length(attachRelIdxs));
18668 
18669  /* Build arrays of all existing indexes and their IndexInfos */
18670  foreach_oid(cldIdxId, attachRelIdxs)
18671  {
18672  int i = foreach_current_index(cldIdxId);
18673 
18674  attachrelIdxRels[i] = index_open(cldIdxId, AccessShareLock);
18675  attachInfos[i] = BuildIndexInfo(attachrelIdxRels[i]);
18676  }
18677 
18678  /*
18679  * If we're attaching a foreign table, we must fail if any of the indexes
18680  * is a constraint index; otherwise, there's nothing to do here. Do this
18681  * before starting work, to avoid wasting the effort of building a few
18682  * non-unique indexes before coming across a unique one.
18683  */
18684  if (attachrel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
18685  {
18686  foreach(cell, idxes)
18687  {
18688  Oid idx = lfirst_oid(cell);
18690 
18691  if (idxRel->rd_index->indisunique ||
18692  idxRel->rd_index->indisprimary)
18693  ereport(ERROR,
18694  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
18695  errmsg("cannot attach foreign table \"%s\" as partition of partitioned table \"%s\"",
18696  RelationGetRelationName(attachrel),
18698  errdetail("Partitioned table \"%s\" contains unique indexes.",
18699  RelationGetRelationName(rel))));
18700  index_close(idxRel, AccessShareLock);
18701  }
18702 
18703  goto out;
18704  }
18705 
18706  /*
18707  * For each index on the partitioned table, find a matching one in the
18708  * partition-to-be; if one is not found, create one.
18709  */
18710  foreach(cell, idxes)
18711  {
18712  Oid idx = lfirst_oid(cell);
18714  IndexInfo *info;
18715  AttrMap *attmap;
18716  bool found = false;
18717  Oid constraintOid;
18718 
18719  /*
18720  * Ignore indexes in the partitioned table other than partitioned
18721  * indexes.
18722  */
18723  if (idxRel->rd_rel->relkind != RELKIND_PARTITIONED_INDEX)
18724  {
18725  index_close(idxRel, AccessShareLock);
18726  continue;
18727  }
18728 
18729  /* construct an indexinfo to compare existing indexes against */
18730  info = BuildIndexInfo(idxRel);
18731  attmap = build_attrmap_by_name(RelationGetDescr(attachrel),
18732  RelationGetDescr(rel),
18733  false);
18734  constraintOid = get_relation_idx_constraint_oid(RelationGetRelid(rel), idx);
18735 
18736  /*
18737  * Scan the list of existing indexes in the partition-to-be, and mark
18738  * the first matching, valid, unattached one we find, if any, as
18739  * partition of the parent index. If we find one, we're done.
18740  */
18741  for (int i = 0; i < list_length(attachRelIdxs); i++)
18742  {
18743  Oid cldIdxId = RelationGetRelid(attachrelIdxRels[i]);
18744  Oid cldConstrOid = InvalidOid;
18745 
18746  /* does this index have a parent? if so, can't use it */
18747  if (attachrelIdxRels[i]->rd_rel->relispartition)
18748  continue;
18749 
18750  /* If this index is invalid, can't use it */
18751  if (!attachrelIdxRels[i]->rd_index->indisvalid)
18752  continue;
18753 
18754  if (CompareIndexInfo(attachInfos[i], info,
18755  attachrelIdxRels[i]->rd_indcollation,
18756  idxRel->rd_indcollation,
18757  attachrelIdxRels[i]->rd_opfamily,
18758  idxRel->rd_opfamily,
18759  attmap))
18760  {
18761  /*
18762  * If this index is being created in the parent because of a
18763  * constraint, then the child needs to have a constraint also,
18764  * so look for one. If there is no such constraint, this
18765  * index is no good, so keep looking.
18766  */
18767  if (OidIsValid(constraintOid))
18768  {
18769  cldConstrOid =
18771  cldIdxId);
18772  /* no dice */
18773  if (!OidIsValid(cldConstrOid))
18774  continue;
18775 
18776  /* Ensure they're both the same type of constraint */
18777  if (get_constraint_type(constraintOid) !=
18778  get_constraint_type(cldConstrOid))
18779  continue;
18780  }
18781 
18782  /* bingo. */
18783  IndexSetParentIndex(attachrelIdxRels[i], idx);
18784  if (OidIsValid(constraintOid))
18785  ConstraintSetParentConstraint(cldConstrOid, constraintOid,
18786  RelationGetRelid(attachrel));
18787  found = true;
18788 
18790  break;
18791  }
18792  }
18793 
18794  /*
18795  * If no suitable index was found in the partition-to-be, create one
18796  * now.
18797  */
18798  if (!found)
18799  {
18800  IndexStmt *stmt;
18801  Oid conOid;
18802 
18804  idxRel, attmap,
18805  &conOid);
18807  RelationGetRelid(idxRel),
18808  conOid,
18809  -1,
18810  true, false, false, false, false);
18811  }
18812 
18813  index_close(idxRel, AccessShareLock);
18814  }
18815 
18816 out:
18817  /* Clean up. */
18818  for (int i = 0; i < list_length(attachRelIdxs); i++)
18819  index_close(attachrelIdxRels[i], AccessShareLock);
18820  MemoryContextSwitchTo(oldcxt);
18821  MemoryContextDelete(cxt);
18822 }
18823 
18824 /*
18825  * CloneRowTriggersToPartition
18826  * subroutine for ATExecAttachPartition/DefineRelation to create row
18827  * triggers on partitions
18828  */
18829 static void
18831 {
18832  Relation pg_trigger;
18833  ScanKeyData key;
18834  SysScanDesc scan;
18835  HeapTuple tuple;
18836  MemoryContext perTupCxt;
18837 
18838  ScanKeyInit(&key, Anum_pg_trigger_tgrelid, BTEqualStrategyNumber,
18839  F_OIDEQ, ObjectIdGetDatum(RelationGetRelid(parent)));
18840  pg_trigger = table_open(TriggerRelationId, RowExclusiveLock);
18841  scan = systable_beginscan(pg_trigger, TriggerRelidNameIndexId,
18842  true, NULL, 1, &key);
18843 
18845  "clone trig", ALLOCSET_SMALL_SIZES);
18846 
18847  while (HeapTupleIsValid(tuple = systable_getnext(scan)))
18848  {
18849  Form_pg_trigger trigForm = (Form_pg_trigger) GETSTRUCT(tuple);
18850  CreateTrigStmt *trigStmt;
18851  Node *qual = NULL;
18852  Datum value;
18853  bool isnull;
18854  List *cols = NIL;
18855  List *trigargs = NIL;
18856  MemoryContext oldcxt;
18857 
18858  /*
18859  * Ignore statement-level triggers; those are not cloned.
18860  */
18861  if (!TRIGGER_FOR_ROW(trigForm->tgtype))
18862  continue;
18863 
18864  /*
18865  * Don't clone internal triggers, because the constraint cloning code
18866  * will.
18867  */
18868  if (trigForm->tgisinternal)
18869  continue;
18870 
18871  /*
18872  * Complain if we find an unexpected trigger type.
18873  */
18874  if (!TRIGGER_FOR_BEFORE(trigForm->tgtype) &&
18875  !TRIGGER_FOR_AFTER(trigForm->tgtype))
18876  elog(ERROR, "unexpected trigger \"%s\" found",
18877  NameStr(trigForm->tgname));
18878 
18879  /* Use short-lived context for CREATE TRIGGER */
18880  oldcxt = MemoryContextSwitchTo(perTupCxt);
18881 
18882  /*
18883  * If there is a WHEN clause, generate a 'cooked' version of it that's
18884  * appropriate for the partition.
18885  */
18886  value = heap_getattr(tuple, Anum_pg_trigger_tgqual,
18887  RelationGetDescr(pg_trigger), &isnull);
18888  if (!isnull)
18889  {
18891  qual = (Node *) map_partition_varattnos((List *) qual, PRS2_OLD_VARNO,
18892  partition, parent);
18893  qual = (Node *) map_partition_varattnos((List *) qual, PRS2_NEW_VARNO,
18894  partition, parent);
18895  }
18896 
18897  /*
18898  * If there is a column list, transform it to a list of column names.
18899  * Note we don't need to map this list in any way ...
18900  */
18901  if (trigForm->tgattr.dim1 > 0)
18902  {
18903  int i;
18904 
18905  for (i = 0; i < trigForm->tgattr.dim1; i++)
18906  {
18907  Form_pg_attribute col;
18908 
18909  col = TupleDescAttr(parent->rd_att,
18910  trigForm->tgattr.values[i] - 1);
18911  cols = lappend(cols,
18912  makeString(pstrdup(NameStr(col->attname))));
18913  }
18914  }
18915 
18916  /* Reconstruct trigger arguments list. */
18917  if (trigForm->tgnargs > 0)
18918  {
18919  char *p;
18920 
18921  value = heap_getattr(tuple, Anum_pg_trigger_tgargs,
18922  RelationGetDescr(pg_trigger), &isnull);
18923  if (isnull)
18924  elog(ERROR, "tgargs is null for trigger \"%s\" in partition \"%s\"",
18925  NameStr(trigForm->tgname), RelationGetRelationName(partition));
18926 
18927  p = (char *) VARDATA_ANY(DatumGetByteaPP(value));
18928 
18929  for (int i = 0; i < trigForm->tgnargs; i++)
18930  {
18931  trigargs = lappend(trigargs, makeString(pstrdup(p)));
18932  p += strlen(p) + 1;
18933  }
18934  }
18935 
18936  trigStmt = makeNode(CreateTrigStmt);
18937  trigStmt->replace = false;
18938  trigStmt->isconstraint = OidIsValid(trigForm->tgconstraint);
18939  trigStmt->trigname = NameStr(trigForm->tgname);
18940  trigStmt->relation = NULL;
18941  trigStmt->funcname = NULL; /* passed separately */
18942  trigStmt->args = trigargs;
18943  trigStmt->row = true;
18944  trigStmt->timing = trigForm->tgtype & TRIGGER_TYPE_TIMING_MASK;
18945  trigStmt->events = trigForm->tgtype & TRIGGER_TYPE_EVENT_MASK;
18946  trigStmt->columns = cols;
18947  trigStmt->whenClause = NULL; /* passed separately */
18948  trigStmt->transitionRels = NIL; /* not supported at present */
18949  trigStmt->deferrable = trigForm->tgdeferrable;
18950  trigStmt->initdeferred = trigForm->tginitdeferred;
18951  trigStmt->constrrel = NULL; /* passed separately */
18952 
18953  CreateTriggerFiringOn(trigStmt, NULL, RelationGetRelid(partition),
18954  trigForm->tgconstrrelid, InvalidOid, InvalidOid,
18955  trigForm->tgfoid, trigForm->oid, qual,
18956  false, true, trigForm->tgenabled);
18957 
18958  MemoryContextSwitchTo(oldcxt);
18959  MemoryContextReset(perTupCxt);
18960  }
18961 
18962  MemoryContextDelete(perTupCxt);
18963 
18964  systable_endscan(scan);
18965  table_close(pg_trigger, RowExclusiveLock);
18966 }
18967 
18968 /*
18969  * ALTER TABLE DETACH PARTITION
18970  *
18971  * Return the address of the relation that is no longer a partition of rel.
18972  *
18973  * If concurrent mode is requested, we run in two transactions. A side-
18974  * effect is that this command cannot run in a multi-part ALTER TABLE.
18975  * Currently, that's enforced by the grammar.
18976  *
18977  * The strategy for concurrency is to first modify the partition's
18978  * pg_inherit catalog row to make it visible to everyone that the
18979  * partition is detached, lock the partition against writes, and commit
18980  * the transaction; anyone who requests the partition descriptor from
18981  * that point onwards has to ignore such a partition. In a second
18982  * transaction, we wait until all transactions that could have seen the
18983  * partition as attached are gone, then we remove the rest of partition
18984  * metadata (pg_inherits and pg_class.relpartbounds).
18985  */
18986 static ObjectAddress
18988  RangeVar *name, bool concurrent)
18989 {
18990  Relation partRel;
18991  ObjectAddress address;
18992  Oid defaultPartOid;
18993 
18994  /*
18995  * We must lock the default partition, because detaching this partition
18996  * will change its partition constraint.
18997  */
18998  defaultPartOid =
19000  if (OidIsValid(defaultPartOid))
19001  {
19002  /*
19003  * Concurrent detaching when a default partition exists is not
19004  * supported. The main problem is that the default partition
19005  * constraint would change. And there's a definitional problem: what
19006  * should happen to the tuples that are being inserted that belong to
19007  * the partition being detached? Putting them on the partition being
19008  * detached would be wrong, since they'd become "lost" after the
19009  * detaching completes but we cannot put them in the default partition
19010  * either until we alter its partition constraint.
19011  *
19012  * I think we could solve this problem if we effected the constraint
19013  * change before committing the first transaction. But the lock would
19014  * have to remain AEL and it would cause concurrent query planning to
19015  * be blocked, so changing it that way would be even worse.
19016  */
19017  if (concurrent)
19018  ereport(ERROR,
19019  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
19020  errmsg("cannot detach partitions concurrently when a default partition exists")));
19021  LockRelationOid(defaultPartOid, AccessExclusiveLock);
19022  }
19023 
19024  /*
19025  * In concurrent mode, the partition is locked with share-update-exclusive
19026  * in the first transaction. This allows concurrent transactions to be
19027  * doing DML to the partition.
19028  */
19029  partRel = table_openrv(name, concurrent ? ShareUpdateExclusiveLock :
19031 
19032  /*
19033  * Check inheritance conditions and either delete the pg_inherits row (in
19034  * non-concurrent mode) or just set the inhdetachpending flag.
19035  */
19036  if (!concurrent)
19037  RemoveInheritance(partRel, rel, false);
19038  else
19039  MarkInheritDetached(partRel, rel);
19040 
19041  /*
19042  * Ensure that foreign keys still hold after this detach. This keeps
19043  * locks on the referencing tables, which prevents concurrent transactions
19044  * from adding rows that we wouldn't see. For this to work in concurrent
19045  * mode, it is critical that the partition appears as no longer attached
19046  * for the RI queries as soon as the first transaction commits.
19047  */
19049 
19050  /*
19051  * Concurrent mode has to work harder; first we add a new constraint to
19052  * the partition that matches the partition constraint. Then we close our
19053  * existing transaction, and in a new one wait for all processes to catch
19054  * up on the catalog updates we've done so far; at that point we can
19055  * complete the operation.
19056  */
19057  if (concurrent)
19058  {
19059  Oid partrelid,
19060  parentrelid;
19061  LOCKTAG tag;
19062  char *parentrelname;
19063  char *partrelname;
19064 
19065  /*
19066  * Add a new constraint to the partition being detached, which
19067  * supplants the partition constraint (unless there is one already).
19068  */
19069  DetachAddConstraintIfNeeded(wqueue, partRel);
19070 
19071  /*
19072  * We're almost done now; the only traces that remain are the
19073  * pg_inherits tuple and the partition's relpartbounds. Before we can
19074  * remove those, we need to wait until all transactions that know that
19075  * this is a partition are gone.
19076  */
19077 
19078  /*
19079  * Remember relation OIDs to re-acquire them later; and relation names
19080  * too, for error messages if something is dropped in between.
19081  */
19082  partrelid = RelationGetRelid(partRel);
19083  parentrelid = RelationGetRelid(rel);
19084  parentrelname = MemoryContextStrdup(PortalContext,
19086  partrelname = MemoryContextStrdup(PortalContext,
19087  RelationGetRelationName(partRel));
19088 
19089  /* Invalidate relcache entries for the parent -- must be before close */
19091 
19092  table_close(partRel, NoLock);
19093  table_close(rel, NoLock);
19094  tab->rel = NULL;
19095 
19096  /* Make updated catalog entry visible */
19099 
19101 
19102  /*
19103  * Now wait. This ensures that all queries that were planned
19104  * including the partition are finished before we remove the rest of
19105  * catalog entries. We don't need or indeed want to acquire this
19106  * lock, though -- that would block later queries.
19107  *
19108  * We don't need to concern ourselves with waiting for a lock on the
19109  * partition itself, since we will acquire AccessExclusiveLock below.
19110  */
19111  SET_LOCKTAG_RELATION(tag, MyDatabaseId, parentrelid);
19113 
19114  /*
19115  * Now acquire locks in both relations again. Note they may have been
19116  * removed in the meantime, so care is required.
19117  */
19118  rel = try_relation_open(parentrelid, ShareUpdateExclusiveLock);
19119  partRel = try_relation_open(partrelid, AccessExclusiveLock);
19120 
19121  /* If the relations aren't there, something bad happened; bail out */
19122  if (rel == NULL)
19123  {
19124  if (partRel != NULL) /* shouldn't happen */
19125  elog(WARNING, "dangling partition \"%s\" remains, can't fix",
19126  partrelname);
19127  ereport(ERROR,
19128  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
19129  errmsg("partitioned table \"%s\" was removed concurrently",
19130  parentrelname)));
19131  }
19132  if (partRel == NULL)
19133  ereport(ERROR,
19134  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
19135  errmsg("partition \"%s\" was removed concurrently", partrelname)));
19136 
19137  tab->rel = rel;
19138  }
19139 
19140  /* Do the final part of detaching */
19141  DetachPartitionFinalize(rel, partRel, concurrent, defaultPartOid);
19142 
19143  ObjectAddressSet(address, RelationRelationId, RelationGetRelid(partRel));
19144 
19145  /* keep our lock until commit */
19146  table_close(partRel, NoLock);
19147 
19148  return address;
19149 }
19150 
19151 /*
19152  * Second part of ALTER TABLE .. DETACH.
19153  *
19154  * This is separate so that it can be run independently when the second
19155  * transaction of the concurrent algorithm fails (crash or abort).
19156  */
19157 static void
19158 DetachPartitionFinalize(Relation rel, Relation partRel, bool concurrent,
19159  Oid defaultPartOid)
19160 {
19161  Relation classRel;
19162  List *fks;
19163  ListCell *cell;
19164  List *indexes;
19165  Datum new_val[Natts_pg_class];
19166  bool new_null[Natts_pg_class],
19167  new_repl[Natts_pg_class];
19168  HeapTuple tuple,
19169  newtuple;
19170  Relation trigrel = NULL;
19171 
19172  if (concurrent)
19173  {
19174  /*
19175  * We can remove the pg_inherits row now. (In the non-concurrent case,
19176  * this was already done).
19177  */
19178  RemoveInheritance(partRel, rel, true);
19179  }
19180 
19181  /* Drop any triggers that were cloned on creation/attach. */
19183 
19184  /*
19185  * Detach any foreign keys that are inherited. This includes creating
19186  * additional action triggers.
19187  */
19188  fks = copyObject(RelationGetFKeyList(partRel));
19189  if (fks != NIL)
19190  trigrel = table_open(TriggerRelationId, RowExclusiveLock);
19191  foreach(cell, fks)
19192  {
19193  ForeignKeyCacheInfo *fk = lfirst(cell);
19194  HeapTuple contup;
19195  Form_pg_constraint conform;
19196  Constraint *fkconstraint;
19197  Oid insertTriggerOid,
19198  updateTriggerOid;
19199 
19200  contup = SearchSysCache1(CONSTROID, ObjectIdGetDatum(fk->conoid));
19201  if (!HeapTupleIsValid(contup))
19202  elog(ERROR, "cache lookup failed for constraint %u", fk->conoid);
19203  conform = (Form_pg_constraint) GETSTRUCT(contup);
19204 
19205  /* consider only the inherited foreign keys */
19206  if (conform->contype != CONSTRAINT_FOREIGN ||
19207  !OidIsValid(conform->conparentid))
19208  {
19209  ReleaseSysCache(contup);
19210  continue;
19211  }
19212 
19213  /* unset conparentid and adjust conislocal, coninhcount, etc. */
19215 
19216  /*
19217  * Also, look up the partition's "check" triggers corresponding to the
19218  * constraint being detached and detach them from the parent triggers.
19219  */
19221  fk->conoid, fk->confrelid, fk->conrelid,
19222  &insertTriggerOid, &updateTriggerOid);
19223  Assert(OidIsValid(insertTriggerOid));
19224  TriggerSetParentTrigger(trigrel, insertTriggerOid, InvalidOid,
19225  RelationGetRelid(partRel));
19226  Assert(OidIsValid(updateTriggerOid));
19227  TriggerSetParentTrigger(trigrel, updateTriggerOid, InvalidOid,
19228  RelationGetRelid(partRel));
19229 
19230  /*
19231  * Make the action triggers on the referenced relation. When this was
19232  * a partition the action triggers pointed to the parent rel (they
19233  * still do), but now we need separate ones of our own.
19234  */
19235  fkconstraint = makeNode(Constraint);
19236  fkconstraint->contype = CONSTRAINT_FOREIGN;
19237  fkconstraint->conname = pstrdup(NameStr(conform->conname));
19238  fkconstraint->deferrable = conform->condeferrable;
19239  fkconstraint->initdeferred = conform->condeferred;
19240  fkconstraint->location = -1;
19241  fkconstraint->pktable = NULL;
19242  fkconstraint->fk_attrs = NIL;
19243  fkconstraint->pk_attrs = NIL;
19244  fkconstraint->fk_matchtype = conform->confmatchtype;
19245  fkconstraint->fk_upd_action = conform->confupdtype;
19246  fkconstraint->fk_del_action = conform->confdeltype;
19247  fkconstraint->fk_del_set_cols = NIL;
19248  fkconstraint->old_conpfeqop = NIL;
19249  fkconstraint->old_pktable_oid = InvalidOid;
19250  fkconstraint->skip_validation = false;
19251  fkconstraint->initially_valid = true;
19252 
19253  createForeignKeyActionTriggers(partRel, conform->confrelid,
19254  fkconstraint, fk->conoid,
19255  conform->conindid,
19257  NULL, NULL);
19258 
19259  ReleaseSysCache(contup);
19260  }
19261  list_free_deep(fks);
19262  if (trigrel)
19263  table_close(trigrel, RowExclusiveLock);
19264 
19265  /*
19266  * Any sub-constraints that are in the referenced-side of a larger
19267  * constraint have to be removed. This partition is no longer part of the
19268  * key space of the constraint.
19269  */
19270  foreach(cell, GetParentedForeignKeyRefs(partRel))
19271  {
19272  Oid constrOid = lfirst_oid(cell);
19273  ObjectAddress constraint;
19274 
19276  deleteDependencyRecordsForClass(ConstraintRelationId,
19277  constrOid,
19278  ConstraintRelationId,
19281 
19282  ObjectAddressSet(constraint, ConstraintRelationId, constrOid);
19283  performDeletion(&constraint, DROP_RESTRICT, 0);
19284  }
19285 
19286  /* Now we can detach indexes */
19287  indexes = RelationGetIndexList(partRel);
19288  foreach(cell, indexes)
19289  {
19290  Oid idxid = lfirst_oid(cell);
19291  Oid parentidx;
19292  Relation idx;
19293  Oid constrOid;
19294  Oid parentConstrOid;
19295 
19296  if (!has_superclass(idxid))
19297  continue;
19298 
19299  parentidx = get_partition_parent(idxid, false);
19300  Assert((IndexGetRelation(parentidx, false) == RelationGetRelid(rel)));
19301 
19304 
19305  /*
19306  * If there's a constraint associated with the index, detach it too.
19307  * Careful: it is possible for a constraint index in a partition to be
19308  * the child of a non-constraint index, so verify whether the parent
19309  * index does actually have a constraint.
19310  */
19312  idxid);
19313  parentConstrOid = get_relation_idx_constraint_oid(RelationGetRelid(rel),
19314  parentidx);
19315  if (OidIsValid(parentConstrOid) && OidIsValid(constrOid))
19317 
19319  }
19320 
19321  /* Update pg_class tuple */
19322  classRel = table_open(RelationRelationId, RowExclusiveLock);
19323  tuple = SearchSysCacheCopy1(RELOID,
19325  if (!HeapTupleIsValid(tuple))
19326  elog(ERROR, "cache lookup failed for relation %u",
19327  RelationGetRelid(partRel));
19328  Assert(((Form_pg_class) GETSTRUCT(tuple))->relispartition);
19329 
19330  /* Clear relpartbound and reset relispartition */
19331  memset(new_val, 0, sizeof(new_val));
19332  memset(new_null, false, sizeof(new_null));
19333  memset(new_repl, false, sizeof(new_repl));
19334  new_val[Anum_pg_class_relpartbound - 1] = (Datum) 0;
19335  new_null[Anum_pg_class_relpartbound - 1] = true;
19336  new_repl[Anum_pg_class_relpartbound - 1] = true;
19337  newtuple = heap_modify_tuple(tuple, RelationGetDescr(classRel),
19338  new_val, new_null, new_repl);
19339 
19340  ((Form_pg_class) GETSTRUCT(newtuple))->relispartition = false;
19341  CatalogTupleUpdate(classRel, &newtuple->t_self, newtuple);
19342  heap_freetuple(newtuple);
19343  table_close(classRel, RowExclusiveLock);
19344 
19345  /*
19346  * Drop identity property from all identity columns of partition.
19347  */
19348  for (int attno = 0; attno < RelationGetNumberOfAttributes(partRel); attno++)
19349  {
19350  Form_pg_attribute attr = TupleDescAttr(partRel->rd_att, attno);
19351 
19352  if (!attr->attisdropped && attr->attidentity)
19353  ATExecDropIdentity(partRel, NameStr(attr->attname), false,
19354  AccessExclusiveLock, true, true);
19355  }
19356 
19357  if (OidIsValid(defaultPartOid))
19358  {
19359  /*
19360  * If the relation being detached is the default partition itself,
19361  * remove it from the parent's pg_partitioned_table entry.
19362  *
19363  * If not, we must invalidate default partition's relcache entry, as
19364  * in StorePartitionBound: its partition constraint depends on every
19365  * other partition's partition constraint.
19366  */
19367  if (RelationGetRelid(partRel) == defaultPartOid)
19369  else
19370  CacheInvalidateRelcacheByRelid(defaultPartOid);
19371  }
19372 
19373  /*
19374  * Invalidate the parent's relcache so that the partition is no longer
19375  * included in its partition descriptor.
19376  */
19378 
19379  /*
19380  * If the partition we just detached is partitioned itself, invalidate
19381  * relcache for all descendent partitions too to ensure that their
19382  * rd_partcheck expression trees are rebuilt; must lock partitions before
19383  * doing so, using the same lockmode as what partRel has been locked with
19384  * by the caller.
19385  */
19386  if (partRel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
19387  {
19388  List *children;
19389 
19390  children = find_all_inheritors(RelationGetRelid(partRel),
19391  AccessExclusiveLock, NULL);
19392  foreach(cell, children)
19393  {
19395  }
19396  }
19397 }
19398 
19399 /*
19400  * ALTER TABLE ... DETACH PARTITION ... FINALIZE
19401  *
19402  * To use when a DETACH PARTITION command previously did not run to
19403  * completion; this completes the detaching process.
19404  */
19405 static ObjectAddress
19407 {
19408  Relation partRel;
19409  ObjectAddress address;
19410  Snapshot snap = GetActiveSnapshot();
19411 
19413 
19414  /*
19415  * Wait until existing snapshots are gone. This is important if the
19416  * second transaction of DETACH PARTITION CONCURRENTLY is canceled: the
19417  * user could immediately run DETACH FINALIZE without actually waiting for
19418  * existing transactions. We must not complete the detach action until
19419  * all such queries are complete (otherwise we would present them with an
19420  * inconsistent view of catalogs).
19421  */
19422  WaitForOlderSnapshots(snap->xmin, false);
19423 
19424  DetachPartitionFinalize(rel, partRel, true, InvalidOid);
19425 
19426  ObjectAddressSet(address, RelationRelationId, RelationGetRelid(partRel));
19427 
19428  table_close(partRel, NoLock);
19429 
19430  return address;
19431 }
19432 
19433 /*
19434  * DetachAddConstraintIfNeeded
19435  * Subroutine for ATExecDetachPartition. Create a constraint that
19436  * takes the place of the partition constraint, but avoid creating
19437  * a dupe if an constraint already exists which implies the needed
19438  * constraint.
19439  */
19440 static void
19442 {
19443  List *constraintExpr;
19444 
19445  constraintExpr = RelationGetPartitionQual(partRel);
19446  constraintExpr = (List *) eval_const_expressions(NULL, (Node *) constraintExpr);
19447 
19448  /*
19449  * Avoid adding a new constraint if the needed constraint is implied by an
19450  * existing constraint
19451  */
19452  if (!PartConstraintImpliedByRelConstraint(partRel, constraintExpr))
19453  {
19454  AlteredTableInfo *tab;
19455  Constraint *n;
19456 
19457  tab = ATGetQueueEntry(wqueue, partRel);
19458 
19459  /* Add constraint on partition, equivalent to the partition constraint */
19460  n = makeNode(Constraint);
19461  n->contype = CONSTR_CHECK;
19462  n->conname = NULL;
19463  n->location = -1;
19464  n->is_no_inherit = false;
19465  n->raw_expr = NULL;
19466  n->cooked_expr = nodeToString(make_ands_explicit(constraintExpr));
19467  n->initially_valid = true;
19468  n->skip_validation = true;
19469  /* It's a re-add, since it nominally already exists */
19470  ATAddCheckConstraint(wqueue, tab, partRel, n,
19471  true, false, true, ShareUpdateExclusiveLock);
19472  }
19473 }
19474 
19475 /*
19476  * DropClonedTriggersFromPartition
19477  * subroutine for ATExecDetachPartition to remove any triggers that were
19478  * cloned to the partition when it was created-as-partition or attached.
19479  * This undoes what CloneRowTriggersToPartition did.
19480  */
19481 static void
19483 {
19484  ScanKeyData skey;
19485  SysScanDesc scan;
19486  HeapTuple trigtup;
19487  Relation tgrel;
19488  ObjectAddresses *objects;
19489 
19490  objects = new_object_addresses();
19491 
19492  /*
19493  * Scan pg_trigger to search for all triggers on this rel.
19494  */
19495  ScanKeyInit(&skey, Anum_pg_trigger_tgrelid, BTEqualStrategyNumber,
19496  F_OIDEQ, ObjectIdGetDatum(partitionId));
19497  tgrel = table_open(TriggerRelationId, RowExclusiveLock);
19498  scan = systable_beginscan(tgrel, TriggerRelidNameIndexId,
19499  true, NULL, 1, &skey);
19500  while (HeapTupleIsValid(trigtup = systable_getnext(scan)))
19501  {
19502  Form_pg_trigger pg_trigger = (Form_pg_trigger) GETSTRUCT(trigtup);
19503  ObjectAddress trig;
19504 
19505  /* Ignore triggers that weren't cloned */
19506  if (!OidIsValid(pg_trigger->tgparentid))
19507  continue;
19508 
19509  /*
19510  * Ignore internal triggers that are implementation objects of foreign
19511  * keys, because these will be detached when the foreign keys
19512  * themselves are.
19513  */
19514  if (OidIsValid(pg_trigger->tgconstrrelid))
19515  continue;
19516 
19517  /*
19518  * This is ugly, but necessary: remove the dependency markings on the
19519  * trigger so that it can be removed.
19520  */
19521  deleteDependencyRecordsForClass(TriggerRelationId, pg_trigger->oid,
19522  TriggerRelationId,
19524  deleteDependencyRecordsForClass(TriggerRelationId, pg_trigger->oid,
19525  RelationRelationId,
19527 
19528  /* remember this trigger to remove it below */
19529  ObjectAddressSet(trig, TriggerRelationId, pg_trigger->oid);
19530  add_exact_object_address(&trig, objects);
19531  }
19532 
19533  /* make the dependency removal visible to the deletion below */
19536 
19537  /* done */
19538  free_object_addresses(objects);
19539  systable_endscan(scan);
19540  table_close(tgrel, RowExclusiveLock);
19541 }
19542 
19543 /*
19544  * Before acquiring lock on an index, acquire the same lock on the owning
19545  * table.
19546  */
19548 {
19552 };
19553 
19554 static void
19555 RangeVarCallbackForAttachIndex(const RangeVar *rv, Oid relOid, Oid oldRelOid,
19556  void *arg)
19557 {
19559  Form_pg_class classform;
19560  HeapTuple tuple;
19561 
19562  state = (struct AttachIndexCallbackState *) arg;
19563 
19564  if (!state->lockedParentTbl)
19565  {
19566  LockRelationOid(state->parentTblOid, AccessShareLock);
19567  state->lockedParentTbl = true;
19568  }
19569 
19570  /*
19571  * If we previously locked some other heap, and the name we're looking up
19572  * no longer refers to an index on that relation, release the now-useless
19573  * lock. XXX maybe we should do *after* we verify whether the index does
19574  * not actually belong to the same relation ...
19575  */
19576  if (relOid != oldRelOid && OidIsValid(state->partitionOid))
19577  {
19578  UnlockRelationOid(state->partitionOid, AccessShareLock);
19579  state->partitionOid = InvalidOid;
19580  }
19581 
19582  /* Didn't find a relation, so no need for locking or permission checks. */
19583  if (!OidIsValid(relOid))
19584  return;
19585 
19586  tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relOid));
19587  if (!HeapTupleIsValid(tuple))
19588  return; /* concurrently dropped, so nothing to do */
19589  classform = (Form_pg_class) GETSTRUCT(tuple);
19590  if (classform->relkind != RELKIND_PARTITIONED_INDEX &&
19591  classform->relkind != RELKIND_INDEX)
19592  ereport(ERROR,
19593  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
19594  errmsg("\"%s\" is not an index", rv->relname)));
19595  ReleaseSysCache(tuple);
19596 
19597  /*
19598  * Since we need only examine the heap's tupledesc, an access share lock
19599  * on it (preventing any DDL) is sufficient.
19600  */
19601  state->partitionOid = IndexGetRelation(relOid, false);
19602  LockRelationOid(state->partitionOid, AccessShareLock);
19603 }
19604 
19605 /*
19606  * ALTER INDEX i1 ATTACH PARTITION i2
19607  */
19608 static ObjectAddress
19610 {
19611  Relation partIdx;
19612  Relation partTbl;
19613  Relation parentTbl;
19614  ObjectAddress address;
19615  Oid partIdxId;
19616  Oid currParent;
19618 
19619  /*
19620  * We need to obtain lock on the index 'name' to modify it, but we also
19621  * need to read its owning table's tuple descriptor -- so we need to lock
19622  * both. To avoid deadlocks, obtain lock on the table before doing so on
19623  * the index. Furthermore, we need to examine the parent table of the
19624  * partition, so lock that one too.
19625  */
19626  state.partitionOid = InvalidOid;
19627  state.parentTblOid = parentIdx->rd_index->indrelid;
19628  state.lockedParentTbl = false;
19629  partIdxId =
19632  (void *) &state);
19633  /* Not there? */
19634  if (!OidIsValid(partIdxId))
19635  ereport(ERROR,
19636  (errcode(ERRCODE_UNDEFINED_OBJECT),
19637  errmsg("index \"%s\" does not exist", name->relname)));
19638 
19639  /* no deadlock risk: RangeVarGetRelidExtended already acquired the lock */
19640  partIdx = relation_open(partIdxId, AccessExclusiveLock);
19641 
19642  /* we already hold locks on both tables, so this is safe: */
19643  parentTbl = relation_open(parentIdx->rd_index->indrelid, AccessShareLock);
19644  partTbl = relation_open(partIdx->rd_index->indrelid, NoLock);
19645 
19646  ObjectAddressSet(address, RelationRelationId, RelationGetRelid(partIdx));
19647 
19648  /* Silently do nothing if already in the right state */
19649  currParent = partIdx->rd_rel->relispartition ?
19650  get_partition_parent(partIdxId, false) : InvalidOid;
19651  if (currParent != RelationGetRelid(parentIdx))
19652  {
19653  IndexInfo *childInfo;
19654  IndexInfo *parentInfo;
19655  AttrMap *attmap;
19656  bool found;
19657  int i;
19658  PartitionDesc partDesc;
19659  Oid constraintOid,
19660  cldConstrId = InvalidOid;
19661 
19662  /*
19663  * If this partition already has an index attached, refuse the
19664  * operation.
19665  */
19666  refuseDupeIndexAttach(parentIdx, partIdx, partTbl);
19667 
19668  if (OidIsValid(currParent))
19669  ereport(ERROR,
19670  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
19671  errmsg("cannot attach index \"%s\" as a partition of index \"%s\"",
19672  RelationGetRelationName(partIdx),
19673  RelationGetRelationName(parentIdx)),
19674  errdetail("Index \"%s\" is already attached to another index.",
19675  RelationGetRelationName(partIdx))));
19676 
19677  /* Make sure it indexes a partition of the other index's table */
19678  partDesc = RelationGetPartitionDesc(parentTbl, true);
19679  found = false;
19680  for (i = 0; i < partDesc->nparts; i++)
19681  {
19682  if (partDesc->oids[i] == state.partitionOid)
19683  {
19684  found = true;
19685  break;
19686  }
19687  }
19688  if (!found)
19689  ereport(ERROR,
19690  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
19691  errmsg("cannot attach index \"%s\" as a partition of index \"%s\"",
19692  RelationGetRelationName(partIdx),
19693  RelationGetRelationName(parentIdx)),
19694  errdetail("Index \"%s\" is not an index on any partition of table \"%s\".",
19695  RelationGetRelationName(partIdx),
19696  RelationGetRelationName(parentTbl))));
19697 
19698  /* Ensure the indexes are compatible */
19699  childInfo = BuildIndexInfo(partIdx);
19700  parentInfo = BuildIndexInfo(parentIdx);
19701  attmap = build_attrmap_by_name(RelationGetDescr(partTbl),
19702  RelationGetDescr(parentTbl),
19703  false);
19704  if (!CompareIndexInfo(childInfo, parentInfo,
19705  partIdx->rd_indcollation,
19706  parentIdx->rd_indcollation,
19707  partIdx->rd_opfamily,
19708  parentIdx->rd_opfamily,
19709  attmap))
19710  ereport(ERROR,
19711  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
19712  errmsg("cannot attach index \"%s\" as a partition of index \"%s\"",
19713  RelationGetRelationName(partIdx),
19714  RelationGetRelationName(parentIdx)),
19715  errdetail("The index definitions do not match.")));
19716 
19717  /*
19718  * If there is a constraint in the parent, make sure there is one in
19719  * the child too.
19720  */
19721  constraintOid = get_relation_idx_constraint_oid(RelationGetRelid(parentTbl),
19722  RelationGetRelid(parentIdx));
19723 
19724  if (OidIsValid(constraintOid))
19725  {
19726  cldConstrId = get_relation_idx_constraint_oid(RelationGetRelid(partTbl),
19727  partIdxId);
19728  if (!OidIsValid(cldConstrId))
19729  ereport(ERROR,
19730  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
19731  errmsg("cannot attach index \"%s\" as a partition of index \"%s\"",
19732  RelationGetRelationName(partIdx),
19733  RelationGetRelationName(parentIdx)),
19734  errdetail("The index \"%s\" belongs to a constraint in table \"%s\" but no constraint exists for index \"%s\".",
19735  RelationGetRelationName(parentIdx),
19736  RelationGetRelationName(parentTbl),
19737  RelationGetRelationName(partIdx))));
19738  }
19739 
19740  /* All good -- do it */
19741  IndexSetParentIndex(partIdx, RelationGetRelid(parentIdx));
19742  if (OidIsValid(constraintOid))
19743  ConstraintSetParentConstraint(cldConstrId, constraintOid,
19744  RelationGetRelid(partTbl));
19745 
19746  free_attrmap(attmap);
19747 
19748  validatePartitionedIndex(parentIdx, parentTbl);
19749  }
19750 
19751  relation_close(parentTbl, AccessShareLock);
19752  /* keep these locks till commit */
19753  relation_close(partTbl, NoLock);
19754  relation_close(partIdx, NoLock);
19755 
19756  return address;
19757 }
19758 
19759 /*
19760  * Verify whether the given partition already contains an index attached
19761  * to the given partitioned index. If so, raise an error.
19762  */
19763 static void
19764 refuseDupeIndexAttach(Relation parentIdx, Relation partIdx, Relation partitionTbl)
19765 {
19766  Oid existingIdx;
19767 
19768  existingIdx = index_get_partition(partitionTbl,
19769  RelationGetRelid(parentIdx));
19770  if (OidIsValid(existingIdx))
19771  ereport(ERROR,
19772  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
19773  errmsg("cannot attach index \"%s\" as a partition of index \"%s\"",
19774  RelationGetRelationName(partIdx),
19775  RelationGetRelationName(parentIdx)),
19776  errdetail("Another index is already attached for partition \"%s\".",
19777  RelationGetRelationName(partitionTbl))));
19778 }
19779 
19780 /*
19781  * Verify whether the set of attached partition indexes to a parent index on
19782  * a partitioned table is complete. If it is, mark the parent index valid.
19783  *
19784  * This should be called each time a partition index is attached.
19785  */
19786 static void
19788 {
19789  Relation inheritsRel;
19790  SysScanDesc scan;
19791  ScanKeyData key;
19792  int tuples = 0;
19793  HeapTuple inhTup;
19794  bool updated = false;
19795 
19796  Assert(partedIdx->rd_rel->relkind == RELKIND_PARTITIONED_INDEX);
19797 
19798  /*
19799  * Scan pg_inherits for this parent index. Count each valid index we find
19800  * (verifying the pg_index entry for each), and if we reach the total
19801  * amount we expect, we can mark this parent index as valid.
19802  */
19803  inheritsRel = table_open(InheritsRelationId, AccessShareLock);
19804  ScanKeyInit(&key, Anum_pg_inherits_inhparent,
19805  BTEqualStrategyNumber, F_OIDEQ,
19806  ObjectIdGetDatum(RelationGetRelid(partedIdx)));
19807  scan = systable_beginscan(inheritsRel, InheritsParentIndexId, true,
19808  NULL, 1, &key);
19809  while ((inhTup = systable_getnext(scan)) != NULL)
19810  {
19811  Form_pg_inherits inhForm = (Form_pg_inherits) GETSTRUCT(inhTup);
19812  HeapTuple indTup;
19813  Form_pg_index indexForm;
19814 
19815  indTup = SearchSysCache1(INDEXRELID,
19816  ObjectIdGetDatum(inhForm->inhrelid));
19817  if (!HeapTupleIsValid(indTup))
19818  elog(ERROR, "cache lookup failed for index %u", inhForm->inhrelid);
19819  indexForm = (Form_pg_index) GETSTRUCT(indTup);
19820  if (indexForm->indisvalid)
19821  tuples += 1;
19822  ReleaseSysCache(indTup);
19823  }
19824 
19825  /* Done with pg_inherits */
19826  systable_endscan(scan);
19827  table_close(inheritsRel, AccessShareLock);
19828 
19829  /*
19830  * If we found as many inherited indexes as the partitioned table has
19831  * partitions, we're good; update pg_index to set indisvalid.
19832  */
19833  if (tuples == RelationGetPartitionDesc(partedTbl, true)->nparts)
19834  {
19835  Relation idxRel;
19836  HeapTuple indTup;
19837  Form_pg_index indexForm;
19838 
19839  idxRel = table_open(IndexRelationId, RowExclusiveLock);
19840  indTup = SearchSysCacheCopy1(INDEXRELID,
19841  ObjectIdGetDatum(RelationGetRelid(partedIdx)));
19842  if (!HeapTupleIsValid(indTup))
19843  elog(ERROR, "cache lookup failed for index %u",
19844  RelationGetRelid(partedIdx));
19845  indexForm = (Form_pg_index) GETSTRUCT(indTup);
19846 
19847  indexForm->indisvalid = true;
19848  updated = true;
19849 
19850  CatalogTupleUpdate(idxRel, &indTup->t_self, indTup);
19851 
19852  table_close(idxRel, RowExclusiveLock);
19853  heap_freetuple(indTup);
19854  }
19855 
19856  /*
19857  * If this index is in turn a partition of a larger index, validating it
19858  * might cause the parent to become valid also. Try that.
19859  */
19860  if (updated && partedIdx->rd_rel->relispartition)
19861  {
19862  Oid parentIdxId,
19863  parentTblId;
19864  Relation parentIdx,
19865  parentTbl;
19866 
19867  /* make sure we see the validation we just did */
19869 
19870  parentIdxId = get_partition_parent(RelationGetRelid(partedIdx), false);
19871  parentTblId = get_partition_parent(RelationGetRelid(partedTbl), false);
19872  parentIdx = relation_open(parentIdxId, AccessExclusiveLock);
19873  parentTbl = relation_open(parentTblId, AccessExclusiveLock);
19874  Assert(!parentIdx->rd_index->indisvalid);
19875 
19876  validatePartitionedIndex(parentIdx, parentTbl);
19877 
19878  relation_close(parentIdx, AccessExclusiveLock);
19879  relation_close(parentTbl, AccessExclusiveLock);
19880  }
19881 }
19882 
19883 /*
19884  * Return an OID list of constraints that reference the given relation
19885  * that are marked as having a parent constraints.
19886  */
19887 static List *
19889 {
19890  Relation pg_constraint;
19891  HeapTuple tuple;
19892  SysScanDesc scan;
19893  ScanKeyData key[2];
19894  List *constraints = NIL;
19895 
19896  /*
19897  * If no indexes, or no columns are referenceable by FKs, we can avoid the
19898  * scan.
19899  */
19900  if (RelationGetIndexList(partition) == NIL ||
19903  return NIL;
19904 
19905  /* Search for constraints referencing this table */
19906  pg_constraint = table_open(ConstraintRelationId, AccessShareLock);
19907  ScanKeyInit(&key[0],
19908  Anum_pg_constraint_confrelid, BTEqualStrategyNumber,
19909  F_OIDEQ, ObjectIdGetDatum(RelationGetRelid(partition)));
19910  ScanKeyInit(&key[1],
19911  Anum_pg_constraint_contype, BTEqualStrategyNumber,
19912  F_CHAREQ, CharGetDatum(CONSTRAINT_FOREIGN));
19913 
19914  /* XXX This is a seqscan, as we don't have a usable index */
19915  scan = systable_beginscan(pg_constraint, InvalidOid, true, NULL, 2, key);
19916  while ((tuple = systable_getnext(scan)) != NULL)
19917  {
19918  Form_pg_constraint constrForm = (Form_pg_constraint) GETSTRUCT(tuple);
19919 
19920  /*
19921  * We only need to process constraints that are part of larger ones.
19922  */
19923  if (!OidIsValid(constrForm->conparentid))
19924  continue;
19925 
19926  constraints = lappend_oid(constraints, constrForm->oid);
19927  }
19928 
19929  systable_endscan(scan);
19930  table_close(pg_constraint, AccessShareLock);
19931 
19932  return constraints;
19933 }
19934 
19935 /*
19936  * During DETACH PARTITION, verify that any foreign keys pointing to the
19937  * partitioned table would not become invalid. An error is raised if any
19938  * referenced values exist.
19939  */
19940 static void
19942 {
19943  List *constraints;
19944  ListCell *cell;
19945 
19946  constraints = GetParentedForeignKeyRefs(partition);
19947 
19948  foreach(cell, constraints)
19949  {
19950  Oid constrOid = lfirst_oid(cell);
19951  HeapTuple tuple;
19952  Form_pg_constraint constrForm;
19953  Relation rel;
19954  Trigger trig = {0};
19955 
19956  tuple = SearchSysCache1(CONSTROID, ObjectIdGetDatum(constrOid));
19957  if (!HeapTupleIsValid(tuple))
19958  elog(ERROR, "cache lookup failed for constraint %u", constrOid);
19959  constrForm = (Form_pg_constraint) GETSTRUCT(tuple);
19960 
19961  Assert(OidIsValid(constrForm->conparentid));
19962  Assert(constrForm->confrelid == RelationGetRelid(partition));
19963 
19964  /* prevent data changes into the referencing table until commit */
19965  rel = table_open(constrForm->conrelid, ShareLock);
19966 
19967  trig.tgoid = InvalidOid;
19968  trig.tgname = NameStr(constrForm->conname);
19970  trig.tgisinternal = true;
19971  trig.tgconstrrelid = RelationGetRelid(partition);
19972  trig.tgconstrindid = constrForm->conindid;
19973  trig.tgconstraint = constrForm->oid;
19974  trig.tgdeferrable = false;
19975  trig.tginitdeferred = false;
19976  /* we needn't fill in remaining fields */
19977 
19978  RI_PartitionRemove_Check(&trig, rel, partition);
19979 
19980  ReleaseSysCache(tuple);
19981 
19982  table_close(rel, NoLock);
19983  }
19984 }
19985 
19986 /*
19987  * resolve column compression specification to compression method.
19988  */
19989 static char
19990 GetAttributeCompression(Oid atttypid, const char *compression)
19991 {
19992  char cmethod;
19993 
19994  if (compression == NULL || strcmp(compression, "default") == 0)
19995  return InvalidCompressionMethod;
19996 
19997  /*
19998  * To specify a nondefault method, the column data type must be toastable.
19999  * Note this says nothing about whether the column's attstorage setting
20000  * permits compression; we intentionally allow attstorage and
20001  * attcompression to be independent. But with a non-toastable type,
20002  * attstorage could not be set to a value that would permit compression.
20003  *
20004  * We don't actually need to enforce this, since nothing bad would happen
20005  * if attcompression were non-default; it would never be consulted. But
20006  * it seems more user-friendly to complain about a certainly-useless
20007  * attempt to set the property.
20008  */
20009  if (!TypeIsToastable(atttypid))
20010  ereport(ERROR,
20011  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
20012  errmsg("column data type %s does not support compression",
20013  format_type_be(atttypid))));
20014 
20015  cmethod = CompressionNameToMethod(compression);
20016  if (!CompressionMethodIsValid(cmethod))
20017  ereport(ERROR,
20018  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
20019  errmsg("invalid compression method \"%s\"", compression)));
20020 
20021  return cmethod;
20022 }
20023 
20024 /*
20025  * resolve column storage specification
20026  */
20027 static char
20028 GetAttributeStorage(Oid atttypid, const char *storagemode)
20029 {
20030  char cstorage = 0;
20031 
20032  if (pg_strcasecmp(storagemode, "plain") == 0)
20033  cstorage = TYPSTORAGE_PLAIN;
20034  else if (pg_strcasecmp(storagemode, "external") == 0)
20035  cstorage = TYPSTORAGE_EXTERNAL;
20036  else if (pg_strcasecmp(storagemode, "extended") == 0)
20037  cstorage = TYPSTORAGE_EXTENDED;
20038  else if (pg_strcasecmp(storagemode, "main") == 0)
20039  cstorage = TYPSTORAGE_MAIN;
20040  else if (pg_strcasecmp(storagemode, "default") == 0)
20041  cstorage = get_typstorage(atttypid);
20042  else
20043  ereport(ERROR,
20044  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
20045  errmsg("invalid storage type \"%s\"",
20046  storagemode)));
20047 
20048  /*
20049  * safety check: do not allow toasted storage modes unless column datatype
20050  * is TOAST-aware.
20051  */
20052  if (!(cstorage == TYPSTORAGE_PLAIN || TypeIsToastable(atttypid)))
20053  ereport(ERROR,
20054  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
20055  errmsg("column data type %s can only have storage PLAIN",
20056  format_type_be(atttypid))));
20057 
20058  return cstorage;
20059 }
20060 
20061 /*
20062  * Struct with context of new partition for inserting rows from split partition
20063  */
20065 {
20066  ExprState *partqualstate; /* expression for checking slot for partition
20067  * (NULL for DEFAULT partition) */
20068  BulkInsertState bistate; /* state of bulk inserts for partition */
20069  TupleTableSlot *dstslot; /* slot for inserting row into partition */
20070  Relation partRel; /* relation for partition */
20072 
20073 
20074 /*
20075  * createSplitPartitionContext: create context for partition and fill it
20076  */
20077 static SplitPartitionContext *
20079 {
20081 
20083  pc->partRel = partRel;
20084 
20085  /*
20086  * Prepare a BulkInsertState for table_tuple_insert. The FSM is empty, so
20087  * don't bother using it.
20088  */
20089  pc->bistate = GetBulkInsertState();
20090 
20091  /* Create tuple slot for new partition. */
20095 
20096  return pc;
20097 }
20098 
20099 /*
20100  * deleteSplitPartitionContext: delete context for partition
20101  */
20102 static void
20104 {
20107 
20108  table_finish_bulk_insert(pc->partRel, ti_options);
20109 
20110  pfree(pc);
20111 }
20112 
20113 /*
20114  * moveSplitTableRows: scan split partition (splitRel) of partitioned table
20115  * (rel) and move rows into new partitions.
20116  *
20117  * New partitions description:
20118  * partlist: list of pointers to SinglePartitionSpec structures.
20119  * newPartRels: list of Relations.
20120  * defaultPartOid: oid of DEFAULT partition, for table rel.
20121  */
20122 static void
20123 moveSplitTableRows(Relation rel, Relation splitRel, List *partlist, List *newPartRels, Oid defaultPartOid)
20124 {
20125  /* The FSM is empty, so don't bother using it. */
20126  int ti_options = TABLE_INSERT_SKIP_FSM;
20127  CommandId mycid;
20128  EState *estate;
20129  ListCell *listptr,
20130  *listptr2;
20131  TupleTableSlot *srcslot;
20132  ExprContext *econtext;
20133  TableScanDesc scan;
20134  Snapshot snapshot;
20135  MemoryContext oldCxt;
20136  List *partContexts = NIL;
20137  TupleConversionMap *tuple_map;
20138  SplitPartitionContext *defaultPartCtx = NULL,
20139  *pc;
20140  bool isOldDefaultPart = false;
20141 
20142  mycid = GetCurrentCommandId(true);
20143 
20144  estate = CreateExecutorState();
20145 
20146  forboth(listptr, partlist, listptr2, newPartRels)
20147  {
20148  SinglePartitionSpec *sps = (SinglePartitionSpec *) lfirst(listptr);
20149 
20150  pc = createSplitPartitionContext((Relation) lfirst(listptr2));
20151 
20152  if (sps->bound->is_default)
20153  {
20154  /* We should not create constraint for detached DEFAULT partition. */
20155  defaultPartCtx = pc;
20156  }
20157  else
20158  {
20159  List *partConstraint;
20160 
20161  /* Build expression execution states for partition check quals. */
20162  partConstraint = get_qual_from_partbound(rel, sps->bound);
20163  partConstraint =
20164  (List *) eval_const_expressions(NULL,
20165  (Node *) partConstraint);
20166  /* Make boolean expression for ExecCheck(). */
20167  partConstraint = list_make1(make_ands_explicit(partConstraint));
20168 
20169  /*
20170  * Map the vars in the constraint expression from rel's attnos to
20171  * splitRel's.
20172  */
20173  partConstraint = map_partition_varattnos(partConstraint,
20174  1, splitRel, rel);
20175 
20176  pc->partqualstate =
20177  ExecPrepareExpr((Expr *) linitial(partConstraint), estate);
20178  Assert(pc->partqualstate != NULL);
20179  }
20180 
20181  /* Store partition context into list. */
20182  partContexts = lappend(partContexts, pc);
20183  }
20184 
20185  /*
20186  * Create partition context for DEFAULT partition. We can insert values
20187  * into this partition in case spaces with values between new partitions.
20188  */
20189  if (!defaultPartCtx && OidIsValid(defaultPartOid))
20190  {
20191  /* Indicate that we allocate context for old DEFAULT partition */
20192  isOldDefaultPart = true;
20193  defaultPartCtx = createSplitPartitionContext(table_open(defaultPartOid, AccessExclusiveLock));
20194  }
20195 
20196  econtext = GetPerTupleExprContext(estate);
20197 
20198  /* Create necessary tuple slot. */
20199  srcslot = MakeSingleTupleTableSlot(RelationGetDescr(splitRel),
20200  table_slot_callbacks(splitRel));
20201 
20202  /*
20203  * Map computing for moving attributes of split partition to new partition
20204  * (for first new partition, but other new partitions can use the same
20205  * map).
20206  */
20207  pc = (SplitPartitionContext *) lfirst(list_head(partContexts));
20208  tuple_map = convert_tuples_by_name(RelationGetDescr(splitRel),
20209  RelationGetDescr(pc->partRel));
20210 
20211  /* Scan through the rows. */
20212  snapshot = RegisterSnapshot(GetLatestSnapshot());
20213  scan = table_beginscan(splitRel, snapshot, 0, NULL);
20214 
20215  /*
20216  * Switch to per-tuple memory context and reset it for each tuple
20217  * produced, so we don't leak memory.
20218  */
20220 
20221  while (table_scan_getnextslot(scan, ForwardScanDirection, srcslot))
20222  {
20223  bool found = false;
20224  TupleTableSlot *insertslot;
20225 
20226  /* Extract data from old tuple. */
20227  slot_getallattrs(srcslot);
20228 
20229  econtext->ecxt_scantuple = srcslot;
20230 
20231  /* Search partition for current slot srcslot. */
20232  foreach(listptr, partContexts)
20233  {
20234  pc = (SplitPartitionContext *) lfirst(listptr);
20235 
20236  if (pc->partqualstate /* skip DEFAULT partition */ &&
20237  ExecCheck(pc->partqualstate, econtext))
20238  {
20239  found = true;
20240  break;
20241  }
20242  ResetExprContext(econtext);
20243  }
20244  if (!found)
20245  {
20246  /* Use DEFAULT partition if it exists. */
20247  if (defaultPartCtx)
20248  pc = defaultPartCtx;
20249  else
20250  ereport(ERROR,
20251  (errcode(ERRCODE_CHECK_VIOLATION),
20252  errmsg("can not find partition for split partition row"),
20253  errtable(splitRel)));
20254  }
20255 
20256  if (tuple_map)
20257  {
20258  /* Need to use map to copy attributes. */
20259  insertslot = execute_attr_map_slot(tuple_map->attrMap, srcslot, pc->dstslot);
20260  }
20261  else
20262  {
20263  /* Copy attributes directly. */
20264  insertslot = pc->dstslot;
20265 
20266  ExecClearTuple(insertslot);
20267 
20268  memcpy(insertslot->tts_values, srcslot->tts_values,
20269  sizeof(Datum) * srcslot->tts_nvalid);
20270  memcpy(insertslot->tts_isnull, srcslot->tts_isnull,
20271  sizeof(bool) * srcslot->tts_nvalid);
20272 
20273  ExecStoreVirtualTuple(insertslot);
20274  }
20275 
20276  /* Write the tuple out to the new relation. */
20277  table_tuple_insert(pc->partRel, insertslot, mycid,
20278  ti_options, pc->bistate);
20279 
20280  ResetExprContext(econtext);
20281 
20283  }
20284 
20285  MemoryContextSwitchTo(oldCxt);
20286 
20287  table_endscan(scan);
20288  UnregisterSnapshot(snapshot);
20289 
20290  if (tuple_map)
20291  free_conversion_map(tuple_map);
20292 
20294 
20295  FreeExecutorState(estate);
20296 
20297  foreach(listptr, partContexts)
20298  deleteSplitPartitionContext((SplitPartitionContext *) lfirst(listptr), ti_options);
20299 
20300  /* Need to close table and free buffers for DEFAULT partition. */
20301  if (isOldDefaultPart)
20302  {
20303  Relation defaultPartRel = defaultPartCtx->partRel;
20304 
20305  deleteSplitPartitionContext(defaultPartCtx, ti_options);
20306  /* Keep the lock until commit. */
20307  table_close(defaultPartRel, NoLock);
20308  }
20309 }
20310 
20311 /*
20312  * createPartitionTable: create table for a new partition with given name
20313  * (newPartName) like table (modelRel)
20314  *
20315  * Emulates command: CREATE [TEMP] TABLE <newPartName> (LIKE <modelRel's name>
20316  * INCLUDING ALL EXCLUDING INDEXES EXCLUDING IDENTITY EXCLUDING STATISTICS)
20317  *
20318  * Also, this function sets the new partition access method same as parent
20319  * table access methods (similarly to CREATE TABLE ... PARTITION OF). It
20320  * checks that parent and child tables have compatible persistence.
20321  *
20322  * Function returns the created relation (locked in AccessExclusiveLock mode).
20323  */
20324 static Relation
20325 createPartitionTable(RangeVar *newPartName, Relation modelRel,
20327 {
20328  CreateStmt *createStmt;
20329  TableLikeClause *tlc;
20330  PlannedStmt *wrapper;
20331  Relation newRel;
20332 
20333  /* If existing rel is temp, it must belong to this session */
20334  if (modelRel->rd_rel->relpersistence == RELPERSISTENCE_TEMP &&
20335  !modelRel->rd_islocaltemp)
20336  ereport(ERROR,
20337  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
20338  errmsg("cannot create as partition of temporary relation of another session")));
20339 
20340  /* New partition should have the same persistence as modelRel */
20341  newPartName->relpersistence = modelRel->rd_rel->relpersistence;
20342 
20343  createStmt = makeNode(CreateStmt);
20344  createStmt->relation = newPartName;
20345  createStmt->tableElts = NIL;
20346  createStmt->inhRelations = NIL;
20347  createStmt->constraints = NIL;
20348  createStmt->options = NIL;
20349  createStmt->oncommit = ONCOMMIT_NOOP;
20350  createStmt->tablespacename = get_tablespace_name(modelRel->rd_rel->reltablespace);
20351  createStmt->if_not_exists = false;
20352  createStmt->accessMethod = get_am_name(modelRel->rd_rel->relam);
20353 
20354  tlc = makeNode(TableLikeClause);
20356  RelationGetRelationName(modelRel), -1);
20357 
20358  /*
20359  * Indexes will be inherited on "attach new partitions" stage, after data
20360  * moving. We also don't copy the extended statistics for consistency
20361  * with CREATE TABLE PARTITION OF.
20362  */
20365  tlc->relationOid = InvalidOid;
20366  createStmt->tableElts = lappend(createStmt->tableElts, tlc);
20367 
20368  /* Need to make a wrapper PlannedStmt. */
20369  wrapper = makeNode(PlannedStmt);
20370  wrapper->commandType = CMD_UTILITY;
20371  wrapper->canSetTag = false;
20372  wrapper->utilityStmt = (Node *) createStmt;
20373  wrapper->stmt_location = context->pstmt->stmt_location;
20374  wrapper->stmt_len = context->pstmt->stmt_len;
20375 
20376  ProcessUtility(wrapper,
20377  context->queryString,
20378  false,
20380  NULL,
20381  NULL,
20382  None_Receiver,
20383  NULL);
20384 
20385  /*
20386  * Open the new partition with no lock, because we already have
20387  * AccessExclusiveLock placed there after creation.
20388  */
20389  newRel = table_openrv(newPartName, NoLock);
20390 
20391  /*
20392  * We intended to create the partition with the same persistence as the
20393  * parent table, but we still need to recheck because that might be
20394  * affected by the search_path. If the parent is permanent, so must be
20395  * all of its partitions.
20396  */
20397  if (modelRel->rd_rel->relpersistence != RELPERSISTENCE_TEMP &&
20398  newRel->rd_rel->relpersistence == RELPERSISTENCE_TEMP)
20399  ereport(ERROR,
20400  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
20401  errmsg("cannot create a temporary relation as partition of permanent relation \"%s\"",
20402  RelationGetRelationName(modelRel))));
20403 
20404  /* Permanent rels cannot be partitions belonging to temporary parent */
20405  if (newRel->rd_rel->relpersistence != RELPERSISTENCE_TEMP &&
20406  modelRel->rd_rel->relpersistence == RELPERSISTENCE_TEMP)
20407  ereport(ERROR,
20408  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
20409  errmsg("cannot create a permanent relation as partition of temporary relation \"%s\"",
20410  RelationGetRelationName(modelRel))));
20411 
20412  return newRel;
20413 }
20414 
20415 /*
20416  * ALTER TABLE <name> SPLIT PARTITION <partition-name> INTO <partition-list>
20417  */
20418 static void
20421 {
20422  Relation splitRel;
20423  Oid splitRelOid;
20424  char relname[NAMEDATALEN];
20425  Oid namespaceId;
20426  ListCell *listptr,
20427  *listptr2;
20428  bool isSameName = false;
20429  char tmpRelName[NAMEDATALEN];
20430  List *newPartRels = NIL;
20431  ObjectAddress object;
20432  Oid defaultPartOid;
20433 
20434  defaultPartOid = get_default_oid_from_partdesc(RelationGetPartitionDesc(rel, true));
20435 
20436  /*
20437  * We are going to detach and remove this partition: need to use exclusive
20438  * lock for preventing DML-queries to the partition.
20439  */
20440  splitRel = table_openrv(cmd->name, AccessExclusiveLock);
20441 
20442  splitRelOid = RelationGetRelid(splitRel);
20443 
20444  /* Check descriptions of new partitions. */
20445  foreach(listptr, cmd->partlist)
20446  {
20447  Oid existing_relid;
20448  SinglePartitionSpec *sps = (SinglePartitionSpec *) lfirst(listptr);
20449 
20451 
20452  /*
20453  * Look up the namespace in which we are supposed to create the
20454  * partition, check we have permission to create there, lock it
20455  * against concurrent drop, and mark stmt->relation as
20456  * RELPERSISTENCE_TEMP if a temporary namespace is selected.
20457  */
20458  sps->name->relpersistence = rel->rd_rel->relpersistence;
20459  namespaceId =
20461 
20462  /*
20463  * This would fail later on anyway if the relation already exists. But
20464  * by catching it here we can emit a nicer error message.
20465  */
20466  existing_relid = get_relname_relid(relname, namespaceId);
20467  if (existing_relid == splitRelOid && !isSameName)
20468  /* One new partition can have the same name as split partition. */
20469  isSameName = true;
20470  else if (existing_relid != InvalidOid)
20471  ereport(ERROR,
20472  (errcode(ERRCODE_DUPLICATE_TABLE),
20473  errmsg("relation \"%s\" already exists", relname)));
20474  }
20475 
20476  /* Detach split partition. */
20477  RemoveInheritance(splitRel, rel, false);
20478  /* Do the final part of detaching. */
20479  DetachPartitionFinalize(rel, splitRel, false, defaultPartOid);
20480 
20481  /*
20482  * If new partition has the same name as split partition then we should
20483  * rename split partition for reusing name.
20484  */
20485  if (isSameName)
20486  {
20487  /*
20488  * We must bump the command counter to make the split partition tuple
20489  * visible for renaming.
20490  */
20492  /* Rename partition. */
20493  sprintf(tmpRelName, "split-%u-%X-tmp", RelationGetRelid(rel), MyProcPid);
20494  RenameRelationInternal(splitRelOid, tmpRelName, false, false);
20495 
20496  /*
20497  * We must bump the command counter to make the split partition tuple
20498  * visible after renaming.
20499  */
20501  }
20502 
20503  /* Create new partitions (like split partition), without indexes. */
20504  foreach(listptr, cmd->partlist)
20505  {
20506  SinglePartitionSpec *sps = (SinglePartitionSpec *) lfirst(listptr);
20507  Relation newPartRel;
20508 
20509  newPartRel = createPartitionTable(sps->name, rel, context);
20510  newPartRels = lappend(newPartRels, newPartRel);
20511  }
20512 
20513  /* Copy data from split partition to new partitions. */
20514  moveSplitTableRows(rel, splitRel, cmd->partlist, newPartRels, defaultPartOid);
20515  /* Keep the lock until commit. */
20516  table_close(splitRel, NoLock);
20517 
20518  /* Attach new partitions to partitioned table. */
20519  forboth(listptr, cmd->partlist, listptr2, newPartRels)
20520  {
20521  SinglePartitionSpec *sps = (SinglePartitionSpec *) lfirst(listptr);
20522  Relation newPartRel = (Relation) lfirst(listptr2);
20523 
20524  /*
20525  * wqueue = NULL: verification for each cloned constraint is not
20526  * needed.
20527  */
20528  attachPartitionTable(NULL, rel, newPartRel, sps->bound);
20529  /* Keep the lock until commit. */
20530  table_close(newPartRel, NoLock);
20531  }
20532 
20533  /* Drop split partition. */
20534  object.classId = RelationRelationId;
20535  object.objectId = splitRelOid;
20536  object.objectSubId = 0;
20537  /* Probably DROP_CASCADE is not needed. */
20538  performDeletion(&object, DROP_RESTRICT, 0);
20539 }
20540 
20541 /*
20542  * moveMergedTablesRows: scan partitions to be merged (mergingPartitionsList)
20543  * of the partitioned table (rel) and move rows into the new partition
20544  * (newPartRel).
20545  */
20546 static void
20547 moveMergedTablesRows(Relation rel, List *mergingPartitionsList,
20548  Relation newPartRel)
20549 {
20550  CommandId mycid;
20551 
20552  /* The FSM is empty, so don't bother using it. */
20553  int ti_options = TABLE_INSERT_SKIP_FSM;
20554  ListCell *listptr;
20555  BulkInsertState bistate; /* state of bulk inserts for partition */
20556  TupleTableSlot *dstslot;
20557 
20558  mycid = GetCurrentCommandId(true);
20559 
20560  /* Prepare a BulkInsertState for table_tuple_insert. */
20561  bistate = GetBulkInsertState();
20562 
20563  /* Create necessary tuple slot. */
20564  dstslot = MakeSingleTupleTableSlot(RelationGetDescr(newPartRel),
20565  table_slot_callbacks(newPartRel));
20566  ExecStoreAllNullTuple(dstslot);
20567 
20568  foreach(listptr, mergingPartitionsList)
20569  {
20570  Relation mergingPartition = (Relation) lfirst(listptr);
20571  TupleTableSlot *srcslot;
20572  TupleConversionMap *tuple_map;
20573  TableScanDesc scan;
20574  Snapshot snapshot;
20575 
20576  /* Create tuple slot for new partition. */
20577  srcslot = MakeSingleTupleTableSlot(RelationGetDescr(mergingPartition),
20578  table_slot_callbacks(mergingPartition));
20579 
20580  /*
20581  * Map computing for moving attributes of merged partition to new
20582  * partition.
20583  */
20584  tuple_map = convert_tuples_by_name(RelationGetDescr(mergingPartition),
20585  RelationGetDescr(newPartRel));
20586 
20587  /* Scan through the rows. */
20588  snapshot = RegisterSnapshot(GetLatestSnapshot());
20589  scan = table_beginscan(mergingPartition, snapshot, 0, NULL);
20590 
20591  while (table_scan_getnextslot(scan, ForwardScanDirection, srcslot))
20592  {
20593  TupleTableSlot *insertslot;
20594 
20595  /* Extract data from old tuple. */
20596  slot_getallattrs(srcslot);
20597 
20598  if (tuple_map)
20599  {
20600  /* Need to use map to copy attributes. */
20601  insertslot = execute_attr_map_slot(tuple_map->attrMap, srcslot, dstslot);
20602  }
20603  else
20604  {
20605  /* Copy attributes directly. */
20606  insertslot = dstslot;
20607 
20608  ExecClearTuple(insertslot);
20609 
20610  memcpy(insertslot->tts_values, srcslot->tts_values,
20611  sizeof(Datum) * srcslot->tts_nvalid);
20612  memcpy(insertslot->tts_isnull, srcslot->tts_isnull,
20613  sizeof(bool) * srcslot->tts_nvalid);
20614 
20615  ExecStoreVirtualTuple(insertslot);
20616  }
20617 
20618  /* Write the tuple out to the new relation. */
20619  table_tuple_insert(newPartRel, insertslot, mycid,
20620  ti_options, bistate);
20621 
20623  }
20624 
20625  table_endscan(scan);
20626  UnregisterSnapshot(snapshot);
20627 
20628  if (tuple_map)
20629  free_conversion_map(tuple_map);
20630 
20632  }
20633 
20635  FreeBulkInsertState(bistate);
20636 
20637  table_finish_bulk_insert(newPartRel, ti_options);
20638 }
20639 
20640 /*
20641  * ALTER TABLE <name> MERGE PARTITIONS <partition-list> INTO <partition-name>
20642  */
20643 static void
20646 {
20647  Relation newPartRel;
20648  ListCell *listptr;
20649  List *mergingPartitionsList = NIL;
20650  Oid defaultPartOid;
20651  Oid namespaceId;
20652  Oid existingRelid;
20653 
20654  /*
20655  * Lock all merged partitions, check them and create list with partitions
20656  * contexts.
20657  */
20658  foreach(listptr, cmd->partlist)
20659  {
20660  RangeVar *name = (RangeVar *) lfirst(listptr);
20661  Relation mergingPartition;
20662 
20663  /*
20664  * We are going to detach and remove this partition: need to use
20665  * exclusive lock for preventing DML-queries to the partition.
20666  */
20667  mergingPartition = table_openrv(name, AccessExclusiveLock);
20668 
20669  /* Store a next merging partition into the list. */
20670  mergingPartitionsList = lappend(mergingPartitionsList,
20671  mergingPartition);
20672  }
20673 
20674  /*
20675  * Look up the namespace in which we are supposed to create the partition,
20676  * check we have permission to create there, lock it against concurrent
20677  * drop, and mark stmt->relation as RELPERSISTENCE_TEMP if a temporary
20678  * namespace is selected.
20679  */
20680  cmd->name->relpersistence = rel->rd_rel->relpersistence;
20681  namespaceId =
20683 
20684  /*
20685  * Check if this name is already taken. This helps us to detect the
20686  * situation when one of the merging partitions has the same name as the
20687  * new partition. Otherwise, this would fail later on anyway but catching
20688  * this here allows us to emit a nicer error message.
20689  */
20690  existingRelid = get_relname_relid(cmd->name->relname, namespaceId);
20691 
20692  if (OidIsValid(existingRelid))
20693  {
20694  Relation sameNamePartition = NULL;
20695 
20696  foreach_ptr(RelationData, mergingPartition, mergingPartitionsList)
20697  {
20698  if (RelationGetRelid(mergingPartition) == existingRelid)
20699  {
20700  sameNamePartition = mergingPartition;
20701  break;
20702  }
20703  }
20704 
20705  if (sameNamePartition)
20706  {
20707  /*
20708  * The new partition has the same name as one of merging
20709  * partitions.
20710  */
20711  char tmpRelName[NAMEDATALEN];
20712 
20713  /* Generate temporary name. */
20714  sprintf(tmpRelName, "merge-%u-%X-tmp", RelationGetRelid(rel), MyProcPid);
20715 
20716  /*
20717  * Rename the existing partition with a temporary name, leaving it
20718  * free for the new partition. We don't need to care about this
20719  * in the future because we're going to eventually drop the
20720  * existing partition anyway.
20721  */
20722  RenameRelationInternal(RelationGetRelid(sameNamePartition),
20723  tmpRelName, false, false);
20724 
20725  /*
20726  * We must bump the command counter to make the new partition
20727  * tuple visible for rename.
20728  */
20730  }
20731  else
20732  {
20733  ereport(ERROR,
20734  (errcode(ERRCODE_DUPLICATE_TABLE),
20735  errmsg("relation \"%s\" already exists", cmd->name->relname)));
20736  }
20737  }
20738 
20739  /* Detach all merged partitions. */
20740  defaultPartOid =
20742  foreach(listptr, mergingPartitionsList)
20743  {
20744  Relation mergingPartition = (Relation) lfirst(listptr);
20745 
20746  /* Remove the pg_inherits row first. */
20747  RemoveInheritance(mergingPartition, rel, false);
20748  /* Do the final part of detaching. */
20749  DetachPartitionFinalize(rel, mergingPartition, false, defaultPartOid);
20750  }
20751 
20752  /* Create table for new partition, use partitioned table as model. */
20753  newPartRel = createPartitionTable(cmd->name, rel, context);
20754 
20755  /* Copy data from merged partitions to new partition. */
20756  moveMergedTablesRows(rel, mergingPartitionsList, newPartRel);
20757 
20758  /* Drop the current partitions before attaching the new one. */
20759  foreach(listptr, mergingPartitionsList)
20760  {
20761  ObjectAddress object;
20762  Relation mergingPartition = (Relation) lfirst(listptr);
20763 
20764  /* Get relation id before table_close() call. */
20765  object.objectId = RelationGetRelid(mergingPartition);
20766  object.classId = RelationRelationId;
20767  object.objectSubId = 0;
20768 
20769  /* Keep the lock until commit. */
20770  table_close(mergingPartition, NoLock);
20771 
20772  performDeletion(&object, DROP_RESTRICT, 0);
20773  }
20774  list_free(mergingPartitionsList);
20775 
20776  /*
20777  * Attach a new partition to the partitioned table. wqueue = NULL:
20778  * verification for each cloned constraint is not needed.
20779  */
20780  attachPartitionTable(NULL, rel, newPartRel, cmd->bound);
20781 
20782  /* Keep the lock until commit. */
20783  table_close(newPartRel, NoLock);
20784 }
Datum idx(PG_FUNCTION_ARGS)
Definition: _int_op.c:259
Acl * aclnewowner(const Acl *old_acl, Oid oldOwnerId, Oid newOwnerId)
Definition: acl.c:1102
void check_can_set_role(Oid member, Oid role)
Definition: acl.c:5191
Oid get_rolespec_oid(const RoleSpec *role, bool missing_ok)
Definition: acl.c:5454
AclResult
Definition: acl.h:182
@ ACLCHECK_OK
Definition: acl.h:183
@ ACLCHECK_NOT_OWNER
Definition: acl.h:185
#define DatumGetAclP(X)
Definition: acl.h:120
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:2700
AclResult pg_attribute_aclcheck(Oid table_oid, AttrNumber attnum, Oid roleid, AclMode mode)
Definition: aclchk.c:3920
AclResult object_aclcheck(Oid classid, Oid objectid, Oid roleid, AclMode mode)
Definition: aclchk.c:3888
bool object_ownercheck(Oid classid, Oid objectid, Oid roleid)
Definition: aclchk.c:4142
void aclcheck_error_type(AclResult aclerr, Oid typeOid)
Definition: aclchk.c:3019
AclResult pg_class_aclcheck(Oid table_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4091
Oid get_table_am_oid(const char *amname, bool missing_ok)
Definition: amcmds.c:173
char * get_am_name(Oid amOid)
Definition: amcmds.c:192
#define ARR_NDIM(a)
Definition: array.h:290
#define ARR_DATA_PTR(a)
Definition: array.h:322
#define DatumGetArrayTypeP(X)
Definition: array.h:261
#define ARR_ELEMTYPE(a)
Definition: array.h:292
#define ARR_DIMS(a)
Definition: array.h:294
#define ARR_HASNULL(a)
Definition: array.h:291
ArrayType * construct_array(Datum *elems, int nelems, Oid elmtype, int elmlen, bool elmbyval, char elmalign)
Definition: arrayfuncs.c:3361
Datum array_get_element(Datum arraydatum, int nSubscripts, int *indx, int arraytyplen, int elmlen, bool elmbyval, char elmalign, bool *isNull)
Definition: arrayfuncs.c:1820
void free_attrmap(AttrMap *map)
Definition: attmap.c:56
AttrMap * make_attrmap(int maplen)
Definition: attmap.c:40
AttrMap * build_attrmap_by_name_if_req(TupleDesc indesc, TupleDesc outdesc, bool missing_ok)
Definition: attmap.c:263
AttrMap * build_attrmap_by_name(TupleDesc indesc, TupleDesc outdesc, bool missing_ok)
Definition: attmap.c:177
int16 AttrNumber
Definition: attnum.h:21
#define InvalidAttrNumber
Definition: attnum.h:23
char * get_tablespace_name(Oid spc_oid)
Definition: tablespace.c:1472
Oid get_tablespace_oid(const char *tablespacename, bool missing_ok)
Definition: tablespace.c:1426
Oid GetDefaultTablespace(char relpersistence, bool partitioned)
Definition: tablespace.c:1143
List * roleSpecsToIds(List *memberNames)
Definition: user.c:1652
List * raw_parser(const char *str, RawParseMode mode)
Definition: parser.c:42
bool TimestampTimestampTzRequiresRewrite(void)
Definition: timestamp.c:6274
int bms_next_member(const Bitmapset *a, int prevbit)
Definition: bitmapset.c:1306
bool bms_is_member(int x, const Bitmapset *a)
Definition: bitmapset.c:510
Bitmapset * bms_make_singleton(int x)
Definition: bitmapset.c:216
#define bms_is_empty(a)
Definition: bitmapset.h:118
void FlushRelationBuffers(Relation rel)
Definition: bufmgr.c:4504
#define TextDatumGetCString(d)
Definition: builtins.h:98
#define NameStr(name)
Definition: c.h:746
uint16 bits16
Definition: c.h:514
signed short int16
Definition: c.h:493
uint32 SubTransactionId
Definition: c.h:656
signed int int32
Definition: c.h:494
#define gettext_noop(x)
Definition: c.h:1196
#define InvalidSubTransactionId
Definition: c.h:658
#define Assert(condition)
Definition: c.h:858
#define PointerIsValid(pointer)
Definition: c.h:763
#define MemSet(start, val, len)
Definition: c.h:1020
uint32 CommandId
Definition: c.h:666
#define PG_INT16_MAX
Definition: c.h:586
#define OidIsValid(objectId)
Definition: c.h:775
bool IsToastNamespace(Oid namespaceId)
Definition: catalog.c:221
bool IsSystemRelation(Relation relation)
Definition: catalog.c:73
RelFileNumber GetNewRelFileNumber(Oid reltablespace, Relation pg_class, char relpersistence)
Definition: catalog.c:521
bool IsCatalogNamespace(Oid namespaceId)
Definition: catalog.c:203
bool IsSystemClass(Oid relid, Form_pg_class reltuple)
Definition: catalog.c:85
bool contain_mutable_functions(Node *clause)
Definition: clauses.c:370
Node * eval_const_expressions(PlannerInfo *root, Node *node)
Definition: clauses.c:2254
void check_index_is_clusterable(Relation OldHeap, Oid indexOid, LOCKMODE lockmode)
Definition: cluster.c:500
void finish_heap_swap(Oid OIDOldHeap, Oid OIDNewHeap, bool is_system_catalog, bool swap_toast_by_content, bool check_constraints, bool is_internal, TransactionId frozenXid, MultiXactId cutoffMulti, char newrelpersistence)
Definition: cluster.c:1438
Oid make_new_heap(Oid OIDOldHeap, Oid NewTableSpace, Oid NewAccessMethod, char relpersistence, LOCKMODE lockmode)
Definition: cluster.c:688
void mark_index_clustered(Relation rel, Oid indexOid, bool is_internal)
Definition: cluster.c:560
Oid collid
void ResetSequence(Oid seq_relid)
Definition: sequence.c:262
void SequenceChangePersistence(Oid relid, char newrelpersistence)
Definition: sequence.c:541
char * GetComment(Oid oid, Oid classoid, int32 subid)
Definition: comment.c:410
ObjectAddress CommentObject(CommentStmt *stmt)
Definition: comment.c:40
int32 defGetInt32(DefElem *def)
Definition: define.c:162
void performMultipleDeletions(const ObjectAddresses *objects, DropBehavior behavior, int flags)
Definition: dependency.c:332
void performDeletion(const ObjectAddress *object, DropBehavior behavior, int flags)
Definition: dependency.c:273
bool object_address_present(const ObjectAddress *object, const ObjectAddresses *addrs)
Definition: dependency.c:2593
ObjectAddresses * new_object_addresses(void)
Definition: dependency.c:2487
void add_exact_object_address(const ObjectAddress *object, ObjectAddresses *addrs)
Definition: dependency.c:2533
void free_object_addresses(ObjectAddresses *addrs)
Definition: dependency.c:2773
#define PERFORM_DELETION_CONCURRENTLY
Definition: dependency.h:93
DependencyType
Definition: dependency.h:32
@ DEPENDENCY_AUTO
Definition: dependency.h:34
@ DEPENDENCY_INTERNAL
Definition: dependency.h:35
@ DEPENDENCY_PARTITION_PRI
Definition: dependency.h:36
@ DEPENDENCY_PARTITION_SEC
Definition: dependency.h:37
@ DEPENDENCY_NORMAL
Definition: dependency.h:33
#define PERFORM_DELETION_QUIETLY
Definition: dependency.h:94
#define PERFORM_DELETION_INTERNAL
Definition: dependency.h:92
DestReceiver * None_Receiver
Definition: dest.c:96
void hash_destroy(HTAB *hashp)
Definition: dynahash.c:865
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:955
HTAB * hash_create(const char *tabname, long nelem, const HASHCTL *info, int flags)
Definition: dynahash.c:352
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1395
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1385
int errmsg_internal(const char *fmt,...)
Definition: elog.c:1157
int errdetail(const char *fmt,...)
Definition: elog.c:1203
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 _(x)
Definition: elog.c:90
#define PG_TRY(...)
Definition: elog.h:370
#define WARNING
Definition: elog.h:36
#define PG_END_TRY(...)
Definition: elog.h:395
#define DEBUG1
Definition: elog.h:30
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:224
#define NOTICE
Definition: elog.h:35
#define PG_FINALLY(...)
Definition: elog.h:387
#define ereport(elevel,...)
Definition: elog.h:149
bool equal(const void *a, const void *b)
Definition: equalfuncs.c:223
void EventTriggerAlterTableStart(Node *parsetree)
void EventTriggerTableRewrite(Node *parsetree, Oid tableOid, int reason)
void EventTriggerAlterTableRelid(Oid objectId)
void EventTriggerAlterTableEnd(void)
void EventTriggerCollectAlterTableSubcmd(Node *subcmd, ObjectAddress address)
#define AT_REWRITE_ALTER_PERSISTENCE
Definition: event_trigger.h:34
#define AT_REWRITE_DEFAULT_VAL
Definition: event_trigger.h:35
#define AT_REWRITE_ACCESS_METHOD
Definition: event_trigger.h:37
#define AT_REWRITE_COLUMN_REWRITE
Definition: event_trigger.h:36
ExprState * ExecPrepareExpr(Expr *node, EState *estate)
Definition: execExpr.c:739
bool ExecCheck(ExprState *state, ExprContext *econtext)
Definition: execExpr.c:846
ExprState * ExecInitExpr(Expr *node, PlanState *parent)
Definition: execExpr.c:134
void InitResultRelInfo(ResultRelInfo *resultRelInfo, Relation resultRelationDesc, Index resultRelationIndex, ResultRelInfo *partition_root_rri, int instrument_options)
Definition: execMain.c:1199
TupleTableSlot * ExecStoreVirtualTuple(TupleTableSlot *slot)
Definition: execTuples.c:1639
void ExecDropSingleTupleTableSlot(TupleTableSlot *slot)
Definition: execTuples.c:1341
TupleTableSlot * ExecStoreAllNullTuple(TupleTableSlot *slot)
Definition: execTuples.c:1663
HeapTuple ExecFetchSlotHeapTuple(TupleTableSlot *slot, bool materialize, bool *shouldFree)
Definition: execTuples.c:1731
TupleTableSlot * MakeSingleTupleTableSlot(TupleDesc tupdesc, const TupleTableSlotOps *tts_ops)
Definition: execTuples.c:1325
EState * CreateExecutorState(void)
Definition: execUtils.c:88
void FreeExecutorState(EState *estate)
Definition: execUtils.c:189
struct ResultRelInfo ResultRelInfo
#define GetPerTupleExprContext(estate)
Definition: executor.h:550
#define ResetExprContext(econtext)
Definition: executor.h:544
#define GetPerTupleMemoryContext(estate)
Definition: executor.h:555
static Datum ExecEvalExpr(ExprState *state, ExprContext *econtext, bool *isNull)
Definition: executor.h:333
#define palloc0_object(type)
Definition: fe_memutils.h:63
#define DirectFunctionCall2(func, arg1, arg2)
Definition: fmgr.h:644
#define DatumGetByteaPP(X)
Definition: fmgr.h:291
#define SizeForFunctionCallInfo(nargs)
Definition: fmgr.h:102
#define LOCAL_FCINFO(name, nargs)
Definition: fmgr.h:110
ForeignDataWrapper * GetForeignDataWrapper(Oid fdwid)
Definition: foreign.c:36
ForeignServer * GetForeignServer(Oid serverid)
Definition: foreign.c:110
Oid GetForeignServerIdByRelId(Oid relid)
Definition: foreign.c:345
FdwRoutine * GetFdwRoutineByServerId(Oid serverid)
Definition: foreign.c:367
Datum transformGenericOptions(Oid catalogId, Datum oldOptions, List *options, Oid fdwvalidator)
Definition: foreigncmds.c:110
char * format_type_with_typemod(Oid type_oid, int32 typemod)
Definition: format_type.c:362
char * format_type_be(Oid type_oid)
Definition: format_type.c:343
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:596
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:503
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:384
bool IsBinaryUpgrade
Definition: globals.c:119
int MyProcPid
Definition: globals.c:46
bool allowSystemTableMods
Definition: globals.c:128
Oid MyDatabaseTableSpace
Definition: globals.c:94
Oid MyDatabaseId
Definition: globals.c:92
#define newval
for(;;)
void RelationClearMissing(Relation rel)
Definition: heap.c:1945
void StorePartitionKey(Relation rel, char strategy, int16 partnatts, AttrNumber *partattrs, List *partexprs, Oid *partopclass, Oid *partcollation)
Definition: heap.c:3325
List * heap_truncate_find_FKs(List *relationIds)
Definition: heap.c:3198
void RemoveStatistics(Oid relid, AttrNumber attnum)
Definition: heap.c:2923
Oid heap_create_with_catalog(const char *relname, Oid relnamespace, Oid reltablespace, Oid relid, Oid reltypeid, Oid reloftypeid, Oid ownerid, Oid accessmtd, TupleDesc tupdesc, List *cooked_constraints, char relkind, char relpersistence, bool shared_relation, bool mapped_relation, OnCommitAction oncommit, Datum reloptions, bool use_user_acl, bool allow_system_table_mods, bool is_internal, Oid relrewrite, ObjectAddress *typaddress)
Definition: heap.c:1105
void heap_truncate(List *relids)
Definition: heap.c:3018
void CheckAttributeType(const char *attname, Oid atttypid, Oid attcollation, List *containing_rowtypes, int flags)
Definition: heap.c:548
void heap_truncate_check_FKs(List *relations, bool tempTables)
Definition: heap.c:3103
void StorePartitionBound(Relation rel, Relation parent, PartitionBoundSpec *bound)
Definition: heap.c:3481
void InsertPgAttributeTuples(Relation pg_attribute_rel, TupleDesc tupdesc, Oid new_rel_oid, const FormExtraData_pg_attribute tupdesc_extra[], CatalogIndexState indstate)
Definition: heap.c:702
void heap_truncate_one_rel(Relation rel)
Definition: heap.c:3059
List * AddRelationNewConstraints(Relation rel, List *newColDefaults, List *newConstraints, bool allow_merge, bool is_local, bool is_internal, const char *queryString)
Definition: heap.c:2258
#define CHKATYPE_IS_PARTKEY
Definition: heap.h:25
HeapTuple heap_getnext(TableScanDesc sscan, ScanDirection direction)
Definition: heapam.c:1252
BulkInsertState GetBulkInsertState(void)
Definition: heapam.c:1927
void FreeBulkInsertState(BulkInsertState bistate)
Definition: heapam.c:1944
#define XLOG_HEAP_TRUNCATE
Definition: heapam_xlog.h:35
#define XLH_TRUNCATE_RESTART_SEQS
Definition: heapam_xlog.h:126
#define SizeOfHeapTruncate
Definition: heapam_xlog.h:141
#define XLH_TRUNCATE_CASCADE
Definition: heapam_xlog.h:125
HeapTuple heap_modify_tuple(HeapTuple tuple, TupleDesc tupleDesc, const Datum *replValues, const bool *replIsnull, const bool *doReplace)
Definition: heaptuple.c:1209
HeapTuple heap_copytuple(HeapTuple tuple)
Definition: heaptuple.c:776
bool heap_attisnull(HeapTuple tup, int attnum, TupleDesc tupleDesc)
Definition: heaptuple.c:455
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1434
@ HASH_ENTER
Definition: hsearch.h:114
#define HASH_CONTEXT
Definition: hsearch.h:102
#define HASH_ELEM
Definition: hsearch.h:95
#define HASH_BLOBS
Definition: hsearch.h:97
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
static Datum heap_getattr(HeapTuple tup, int attnum, TupleDesc tupleDesc, bool *isnull)
Definition: htup_details.h:792
#define GETSTRUCT(TUP)
Definition: htup_details.h:653
#define MaxHeapAttributeNumber
Definition: htup_details.h:48
#define stmt
Definition: indent_codes.h:59
Oid IndexGetRelation(Oid indexId, bool missing_ok)
Definition: index.c:3524
bool CompareIndexInfo(const IndexInfo *info1, const IndexInfo *info2, const Oid *collations1, const Oid *collations2, const Oid *opfamilies1, const Oid *opfamilies2, const AttrMap *attmap)
Definition: index.c:2511
bool reindex_relation(const ReindexStmt *stmt, Oid relid, int flags, const ReindexParams *params)
Definition: index.c:3889
void index_check_primary_key(Relation heapRel, const IndexInfo *indexInfo, bool is_alter_table, const IndexStmt *stmt)
Definition: index.c:201
ObjectAddress index_constraint_create(Relation heapRelation, Oid indexRelationId, Oid parentConstraintId, const IndexInfo *indexInfo, const char *constraintName, char constraintType, bits16 constr_flags, bool allow_system_table_mods, bool is_internal)
Definition: index.c:1881
IndexInfo * BuildIndexInfo(Relation index)
Definition: index.c:2404
#define REINDEX_REL_PROCESS_TOAST
Definition: index.h:158
#define INDEX_CONSTR_CREATE_UPDATE_INDEX
Definition: index.h:94
#define INDEX_CONSTR_CREATE_REMOVE_OLD_DEPS
Definition: index.h:95
#define INDEX_CONSTR_CREATE_DEFERRABLE
Definition: index.h:92
#define INDEX_CONSTR_CREATE_MARK_AS_PRIMARY
Definition: index.h:91
#define INDEX_CONSTR_CREATE_INIT_DEFERRED
Definition: index.h:93
void index_close(Relation relation, LOCKMODE lockmode)
Definition: indexam.c:177
Relation index_open(Oid relationId, LOCKMODE lockmode)
Definition: indexam.c:133
bool CheckIndexCompatible(Oid oldId, const char *accessMethodName, const List *attributeList, const List *exclusionOpNames)
Definition: indexcmds.c:174
ObjectAddress DefineIndex(Oid tableId, IndexStmt *stmt, Oid indexRelationId, Oid parentIndexId, Oid parentConstraintId, int total_parts, bool is_alter_table, bool check_rights, bool check_not_in_use, bool skip_build, bool quiet)
Definition: indexcmds.c:531
void IndexSetParentIndex(Relation partitionIdx, Oid parentOid)
Definition: indexcmds.c:4280
Oid GetDefaultOpClass(Oid type_id, Oid am_id)
Definition: indexcmds.c:2304
void WaitForOlderSnapshots(TransactionId limitXmin, bool progress)
Definition: indexcmds.c:424
Oid ResolveOpClass(const List *opclass, Oid attrType, const char *accessMethodName, Oid accessMethodId)
Definition: indexcmds.c:2219
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:313
void CatalogTupleDelete(Relation heapRel, ItemPointer tid)
Definition: indexing.c:365
long val
Definition: informix.c:670
static struct @155 value
void AcceptInvalidationMessages(void)
Definition: inval.c:806
void CacheInvalidateRelcache(Relation relation)
Definition: inval.c:1360
void CacheInvalidateRelcacheByRelid(Oid relid)
Definition: inval.c:1419
void CacheInvalidateRelcacheByTuple(HeapTuple classTuple)
Definition: inval.c:1396
int b
Definition: isn.c:70
int a
Definition: isn.c:69
int j
Definition: isn.c:74
int i
Definition: isn.c:73
if(TABLE==NULL||TABLE_index==NULL)
Definition: isn.c:77
List * list_difference_ptr(const List *list1, const List *list2)
Definition: list.c:1263
List * lappend(List *list, void *datum)
Definition: list.c:339
List * lappend_int(List *list, int datum)
Definition: list.c:357
List * lappend_oid(List *list, Oid datum)
Definition: list.c:375
List * list_copy(const List *oldlist)
Definition: list.c:1573
List * list_delete_nth_cell(List *list, int n)
Definition: list.c:767
void list_free(List *list)
Definition: list.c:1546
bool list_member_oid(const List *list, Oid datum)
Definition: list.c:722
List * list_concat(List *list1, const List *list2)
Definition: list.c:561
List * lcons(void *datum, List *list)
Definition: list.c:495
List * list_append_unique_oid(List *list, Oid datum)
Definition: list.c:1380
void list_free_deep(List *list)
Definition: list.c:1560
bool ConditionalLockRelationOid(Oid relid, LOCKMODE lockmode)
Definition: lmgr.c:151
void UnlockRelationOid(Oid relid, LOCKMODE lockmode)
Definition: lmgr.c:227
void WaitForLockersMultiple(List *locktags, LOCKMODE lockmode, bool progress)
Definition: lmgr.c:897
void LockRelationOid(Oid relid, LOCKMODE lockmode)
Definition: lmgr.c:108
bool CheckRelationOidLockedByMe(Oid relid, LOCKMODE lockmode, bool orstronger)
Definition: lmgr.c:347
#define SET_LOCKTAG_RELATION(locktag, dboid, reloid)
Definition: lock.h:181
int LOCKMODE
Definition: lockdefs.h:26
#define NoLock
Definition: lockdefs.h:34
#define AccessExclusiveLock
Definition: lockdefs.h:43
#define ShareRowExclusiveLock
Definition: lockdefs.h:41
#define AccessShareLock
Definition: lockdefs.h:36
#define ShareUpdateExclusiveLock
Definition: lockdefs.h:39
#define RowShareLock
Definition: lockdefs.h:37
#define ShareLock
Definition: lockdefs.h:40
#define RowExclusiveLock
Definition: lockdefs.h:38
AttrNumber get_attnum(Oid relid, const char *attname)
Definition: lsyscache.c:858
Oid get_constraint_index(Oid conoid)
Definition: lsyscache.c:1113
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3366
char get_typstorage(Oid typid)
Definition: lsyscache.c:2419
bool get_index_isreplident(Oid index_oid)
Definition: lsyscache.c:3555
char get_rel_relkind(Oid relid)
Definition: lsyscache.c:2003
Oid get_typcollation(Oid typid)
Definition: lsyscache.c:3056
char * get_rel_name(Oid relid)
Definition: lsyscache.c:1928
bool get_index_isclustered(Oid index_oid)
Definition: lsyscache.c:3601
Oid get_opfamily_member(Oid opfamily, Oid lefttype, Oid righttype, int16 strategy)
Definition: lsyscache.c:166
char * get_collation_name(Oid colloid)
Definition: lsyscache.c:1035
char * get_constraint_name(Oid conoid)
Definition: lsyscache.c:1081
Oid get_rel_relam(Oid relid)
Definition: lsyscache.c:2100
bool type_is_collatable(Oid typid)
Definition: lsyscache.c:3081
Oid get_rel_tablespace(Oid relid)
Definition: lsyscache.c:2054
Oid get_typ_typrelid(Oid typid)
Definition: lsyscache.c:2731
Oid getBaseTypeAndTypmod(Oid typid, int32 *typmod)
Definition: lsyscache.c:2538
Oid getBaseType(Oid typid)
Definition: lsyscache.c:2521
char get_constraint_type(Oid conoid)
Definition: lsyscache.c:1143
Oid get_relname_relid(const char *relname, Oid relnamespace)
Definition: lsyscache.c:1885
char * get_attname(Oid relid, AttrNumber attnum, bool missing_ok)
Definition: lsyscache.c:827
#define TypeIsToastable(typid)
Definition: lsyscache.h:213
List * make_ands_implicit(Expr *clause)
Definition: makefuncs.c:737
TypeName * makeTypeNameFromNameList(List *names)
Definition: makefuncs.c:458
Const * makeNullConst(Oid consttype, int32 consttypmod, Oid constcollid)
Definition: makefuncs.c:339
RangeVar * makeRangeVar(char *schemaname, char *relname, int location)
Definition: makefuncs.c:424
ColumnDef * makeColumnDef(const char *colname, Oid typeOid, int32 typmod, Oid collOid)
Definition: makefuncs.c:492
Var * makeVar(int varno, AttrNumber varattno, Oid vartype, int32 vartypmod, Oid varcollid, Index varlevelsup)
Definition: makefuncs.c:66
Expr * make_ands_explicit(List *andclauses)
Definition: makefuncs.c:726
void MemoryContextReset(MemoryContext context)
Definition: mcxt.c:383
char * pstrdup(const char *in)
Definition: mcxt.c:1696
void pfree(void *pointer)
Definition: mcxt.c:1521
void * palloc0(Size size)
Definition: mcxt.c:1347
MemoryContext CurrentMemoryContext
Definition: mcxt.c:143
char * MemoryContextStrdup(MemoryContext context, const char *string)
Definition: mcxt.c:1683
MemoryContext CacheMemoryContext
Definition: mcxt.c:152
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:454
void * palloc(Size size)
Definition: mcxt.c:1317
MemoryContext PortalContext
Definition: mcxt.c:158
#define AllocSetContextCreate
Definition: memutils.h:129
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:160
#define ALLOCSET_SMALL_SIZES
Definition: memutils.h:170
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:122
bool InSecurityRestrictedOperation(void)
Definition: miscinit.c:662
Oid GetUserId(void)
Definition: miscinit.c:514
MultiXactId ReadNextMultiXactId(void)
Definition: multixact.c:770
void namestrcpy(Name name, const char *str)
Definition: name.c:233
Oid RangeVarGetAndCheckCreationNamespace(RangeVar *relation, LOCKMODE lockmode, Oid *existing_relation_id)
Definition: namespace.c:724
bool isAnyTempNamespace(Oid namespaceId)
Definition: namespace.c:3672
Oid get_collation_oid(List *collname, bool missing_ok)
Definition: namespace.c:3956
void CheckSetNamespace(Oid oldNspOid, Oid nspOid)
Definition: namespace.c:3444
RangeVar * makeRangeVarFromNameList(const List *names)
Definition: namespace.c:3539
Oid LookupNamespaceNoError(const char *nspname)
Definition: namespace.c:3340
Oid RangeVarGetRelidExtended(const RangeVar *relation, LOCKMODE lockmode, uint32 flags, RangeVarGetRelidCallback callback, void *callback_arg)
Definition: namespace.c:426
@ RVR_MISSING_OK
Definition: namespace.h:72
#define RangeVarGetRelid(relation, lockmode, missing_ok)
Definition: namespace.h:80
Oid exprType(const Node *expr)
Definition: nodeFuncs.c:42
Oid exprCollation(const Node *expr)
Definition: nodeFuncs.c:816
Node * strip_implicit_coercions(Node *node)
Definition: nodeFuncs.c:700
#define IsA(nodeptr, _type_)
Definition: nodes.h:158
#define copyObject(obj)
Definition: nodes.h:224
#define nodeTag(nodeptr)
Definition: nodes.h:133
@ CMD_UTILITY
Definition: nodes.h:270
#define makeNode(_type_)
Definition: nodes.h:155
#define castNode(_type_, nodeptr)
Definition: nodes.h:176
#define InvokeObjectPostCreateHook(classId, objectId, subId)
Definition: objectaccess.h:173
#define InvokeObjectTruncateHook(objectId)
Definition: objectaccess.h:191
#define InvokeObjectPostAlterHook(classId, objectId, subId)
Definition: objectaccess.h:197
#define InvokeObjectPostAlterHookArg(classId, objectId, subId, auxiliaryId, is_internal)
Definition: objectaccess.h:200
ObjectType get_relkind_objtype(char relkind)
char * getObjectDescription(const ObjectAddress *object, bool missing_ok)
const ObjectAddress InvalidObjectAddress
#define ObjectAddressSet(addr, class_id, object_id)
Definition: objectaddress.h:40
#define ObjectAddressSubSet(addr, class_id, object_id, object_sub_id)
Definition: objectaddress.h:33
char * nodeToString(const void *obj)
Definition: outfuncs.c:791
Node * coerce_to_target_type(ParseState *pstate, Node *expr, Oid exprtype, Oid targettype, int32 targettypmod, CoercionContext ccontext, CoercionForm cformat, int location)
Definition: parse_coerce.c:78
CoercionPathType find_coercion_pathway(Oid targetTypeId, Oid sourceTypeId, CoercionContext ccontext, Oid *funcid)
bool can_coerce_type(int nargs, const Oid *input_typeids, const Oid *target_typeids, CoercionContext ccontext)
Definition: parse_coerce.c:556
CoercionPathType
Definition: parse_coerce.h:25
@ COERCION_PATH_NONE
Definition: parse_coerce.h:26
@ COERCION_PATH_RELABELTYPE
Definition: parse_coerce.h:28
void assign_expr_collations(ParseState *pstate, Node *expr)
Node * transformExpr(ParseState *pstate, Node *expr, ParseExprKind exprKind)
Definition: parse_expr.c:120
int parser_errposition(ParseState *pstate, int location)
Definition: parse_node.c:106
ParseState * make_parsestate(ParseState *parentParseState)
Definition: parse_node.c:39
@ EXPR_KIND_PARTITION_EXPRESSION
Definition: parse_node.h:80
ParseNamespaceItem * addRangeTableEntryForRelation(ParseState *pstate, Relation rel, int lockmode, Alias *alias, bool inh, bool inFromCl)
const NameData * attnumAttName(Relation rd, int attid)
void addNSItemToQuery(ParseState *pstate, ParseNamespaceItem *nsitem, bool addToJoinList, bool addToRelNameSpace, bool addToVarNameSpace)
Oid attnumTypeId(Relation rd, int attid)
void typenameTypeIdAndMod(ParseState *pstate, const TypeName *typeName, Oid *typeid_p, int32 *typmod_p)
Definition: parse_type.c:310
Type typenameType(ParseState *pstate, const TypeName *typeName, int32 *typmod_p)
Definition: parse_type.c:264
Oid GetColumnDefCollation(ParseState *pstate, const ColumnDef *coldef, Oid typeOid)
Definition: parse_type.c:540
Oid typenameTypeId(ParseState *pstate, const TypeName *typeName)
Definition: parse_type.c:291
IndexStmt * generateClonedIndexStmt(RangeVar *heapRel, Relation source_idx, const AttrMap *attmap, Oid *constraintOid)
CreateStatsStmt * transformStatsStmt(Oid relid, CreateStatsStmt *stmt, const char *queryString)
AlterTableStmt * transformAlterTableStmt(Oid relid, AlterTableStmt *stmt, const char *queryString, List **beforeStmts, List **afterStmts)
IndexStmt * transformIndexStmt(Oid relid, IndexStmt *stmt, const char *queryString)
PartitionBoundSpec * transformPartitionBound(ParseState *pstate, Relation parent, PartitionBoundSpec *spec)
#define FKCONSTR_ACTION_RESTRICT
Definition: parsenodes.h:2723
#define ACL_MAINTAIN
Definition: parsenodes.h:90
#define ACL_USAGE
Definition: parsenodes.h:84
#define FKCONSTR_ACTION_SETDEFAULT
Definition: parsenodes.h:2726
PartitionStrategy
Definition: parsenodes.h:871
@ PARTITION_STRATEGY_HASH
Definition: parsenodes.h:874
@ PARTITION_STRATEGY_LIST
Definition: parsenodes.h:872
ConstrType
Definition: parsenodes.h:2703
@ CONSTR_FOREIGN
Definition: parsenodes.h:2714
@ CONSTR_UNIQUE
Definition: parsenodes.h:2712
@ CONSTR_DEFAULT
Definition: parsenodes.h:2707
@ CONSTR_CHECK
Definition: parsenodes.h:2710
@ CONSTR_EXCLUSION
Definition: parsenodes.h:2713
@ CONSTR_PRIMARY
Definition: parsenodes.h:2711
DropBehavior
Definition: parsenodes.h:2333
@ DROP_CASCADE
Definition: parsenodes.h:2335
@ DROP_RESTRICT
Definition: parsenodes.h:2334
ObjectType
Definition: parsenodes.h:2260
@ OBJECT_MATVIEW
Definition: parsenodes.h:2284
@ OBJECT_SCHEMA
Definition: parsenodes.h:2297
@ OBJECT_FOREIGN_TABLE
Definition: parsenodes.h:2279
@ OBJECT_TABLESPACE
Definition: parsenodes.h:2303
@ OBJECT_INDEX
Definition: parsenodes.h:2281
@ OBJECT_SEQUENCE
Definition: parsenodes.h:2298
@ OBJECT_TABLE
Definition: parsenodes.h:2302
@ OBJECT_VIEW
Definition: parsenodes.h:2312
@ OBJECT_TYPE
Definition: parsenodes.h:2310
@ OBJECT_TABCONSTRAINT
Definition: parsenodes.h:2301
@ OBJECT_DOMCONSTRAINT
Definition: parsenodes.h:2274
AlterTableType
Definition: parsenodes.h:2352
@ AT_AddIndexConstraint
Definition: parsenodes.h:2375
@ AT_MergePartitions
Definition: parsenodes.h:2417
@ AT_DropOf
Definition: parsenodes.h:2406
@ AT_CheckNotNull
Definition: parsenodes.h:2361
@ AT_SetOptions
Definition: parsenodes.h:2363
@ AT_DropIdentity
Definition: parsenodes.h:2420
@ AT_DisableTrigUser
Definition: parsenodes.h:2398
@ AT_DropNotNull
Definition: parsenodes.h:2357
@ AT_AddOf
Definition: parsenodes.h:2405
@ AT_ResetOptions
Definition: parsenodes.h:2364
@ AT_ReplicaIdentity
Definition: parsenodes.h:2407
@ AT_ReplaceRelOptions
Definition: parsenodes.h:2390
@ AT_EnableRowSecurity
Definition: parsenodes.h:2408
@ AT_AddColumnToView
Definition: parsenodes.h:2354
@ AT_ResetRelOptions
Definition: parsenodes.h:2389
@ AT_EnableReplicaTrig
Definition: parsenodes.h:2393
@ AT_DropOids
Definition: parsenodes.h:2385
@ AT_SetIdentity
Definition: parsenodes.h:2419
@ AT_ReAddStatistics
Definition: parsenodes.h:2421
@ AT_SetUnLogged
Definition: parsenodes.h:2384
@ AT_DisableTrig
Definition: parsenodes.h:2394
@ AT_SetCompression
Definition: parsenodes.h:2366
@ AT_DropExpression
Definition: parsenodes.h:2360
@ AT_AddIndex
Definition: parsenodes.h:2368
@ AT_EnableReplicaRule
Definition: parsenodes.h:2401
@ AT_ReAddIndex
Definition: parsenodes.h:2369
@ AT_DropConstraint
Definition: parsenodes.h:2376
@ AT_SetNotNull
Definition: parsenodes.h:2358
@ AT_ClusterOn
Definition: parsenodes.h:2381
@ AT_AddIdentity
Definition: parsenodes.h:2418
@ AT_ForceRowSecurity
Definition: parsenodes.h:2410
@ AT_EnableAlwaysRule
Definition: parsenodes.h:2400
@ AT_SetAccessMethod
Definition: parsenodes.h:2386
@ AT_AlterColumnType
Definition: parsenodes.h:2378
@ AT_DetachPartitionFinalize
Definition: parsenodes.h:2415
@ AT_AddInherit
Definition: parsenodes.h:2403
@ AT_ReAddDomainConstraint
Definition: parsenodes.h:2372
@ AT_EnableTrig
Definition: parsenodes.h:2391
@ AT_DropColumn
Definition: parsenodes.h:2367
@ AT_ReAddComment
Definition: parsenodes.h:2377
@ AT_AlterColumnGenericOptions
Definition: parsenodes.h:2379
@ AT_DisableTrigAll
Definition: parsenodes.h:2396
@ AT_EnableRule
Definition: parsenodes.h:2399
@ AT_NoForceRowSecurity
Definition: parsenodes.h:2411
@ AT_DetachPartition
Definition: parsenodes.h:2414
@ AT_SetStatistics
Definition: parsenodes.h:2362
@ AT_AttachPartition
Definition: parsenodes.h:2413
@ AT_AddConstraint
Definition: parsenodes.h:2370
@ AT_DropInherit
Definition: parsenodes.h:2404
@ AT_EnableAlwaysTrig
Definition: parsenodes.h:2392
@ AT_SetLogged
Definition: parsenodes.h:2383
@ AT_SetStorage
Definition: parsenodes.h:2365
@ AT_DisableRule
Definition: parsenodes.h:2402
@ AT_DisableRowSecurity
Definition: parsenodes.h:2409
@ AT_SetRelOptions
Definition: parsenodes.h:2388
@ AT_ChangeOwner
Definition: parsenodes.h:2380
@ AT_EnableTrigUser
Definition: parsenodes.h:2397
@ AT_SetExpression
Definition: parsenodes.h:2359
@ AT_ReAddConstraint
Definition: parsenodes.h:2371
@ AT_SetTableSpace
Definition: parsenodes.h:2387
@ AT_GenericOptions
Definition: parsenodes.h:2412
@ AT_ColumnDefault
Definition: parsenodes.h:2355
@ AT_CookedColumnDefault
Definition: parsenodes.h:2356
@ AT_AlterConstraint
Definition: parsenodes.h:2373
@ AT_EnableTrigAll
Definition: parsenodes.h:2395
@ AT_SplitPartition
Definition: parsenodes.h:2416
@ AT_DropCluster
Definition: parsenodes.h:2382
@ AT_ValidateConstraint
Definition: parsenodes.h:2374
@ AT_AddColumn
Definition: parsenodes.h:2353
#define ACL_REFERENCES
Definition: parsenodes.h:81
#define FKCONSTR_ACTION_CASCADE
Definition: parsenodes.h:2724
#define ACL_TRUNCATE
Definition: parsenodes.h:80
#define ACL_CREATE
Definition: parsenodes.h:85
#define FKCONSTR_ACTION_SETNULL
Definition: parsenodes.h:2725
@ CREATE_TABLE_LIKE_IDENTITY
Definition: parsenodes.h:766
@ CREATE_TABLE_LIKE_ALL
Definition: parsenodes.h:770
@ CREATE_TABLE_LIKE_INDEXES
Definition: parsenodes.h:767
@ CREATE_TABLE_LIKE_STATISTICS
Definition: parsenodes.h:768
#define FKCONSTR_ACTION_NOACTION
Definition: parsenodes.h:2722
@ RAW_PARSE_DEFAULT
Definition: parser.h:39
List * SystemFuncName(char *name)
void check_new_partition_bound(char *relname, Relation parent, PartitionBoundSpec *spec, ParseState *pstate)
Definition: partbounds.c:2896
List * get_qual_from_partbound(Relation parent, PartitionBoundSpec *spec)
Definition: partbounds.c:249
void check_default_partition_contents(Relation parent, Relation default_rel, PartitionBoundSpec *new_spec)
Definition: partbounds.c:3252
List * RelationGetPartitionQual(Relation rel)
Definition: partcache.c:277
PartitionDesc RelationGetPartitionDesc(Relation rel, bool omit_detached)
Definition: partdesc.c:71
Oid get_default_oid_from_partdesc(PartitionDesc partdesc)
Definition: partdesc.c:487
bool has_partition_attrs(Relation rel, Bitmapset *attnums, bool *used_in_expr)
Definition: partition.c:255
List * map_partition_varattnos(List *expr, int fromrel_varno, Relation to_rel, Relation from_rel)
Definition: partition.c:222
List * get_proposed_default_constraint(List *new_part_constraints)
Definition: partition.c:370
void update_default_partition_oid(Oid parentId, Oid defaultPartId)
Definition: partition.c:340
Oid index_get_partition(Relation partition, Oid indexId)
Definition: partition.c:176
Oid get_partition_parent(Oid relid, bool even_if_detached)
Definition: partition.c:53
Oid GetAttrDefaultOid(Oid relid, AttrNumber attnum)
Definition: pg_attrdef.c:339
Oid StoreAttrDefault(Relation rel, AttrNumber attnum, Node *expr, bool is_internal, bool add_column_mode)
Definition: pg_attrdef.c:46
ObjectAddress GetAttrDefaultColumnAddress(Oid attrdefoid)
Definition: pg_attrdef.c:381
void RemoveAttrDefault(Oid relid, AttrNumber attnum, DropBehavior behavior, bool complain, bool internal)
Definition: pg_attrdef.c:213
NameData attname
Definition: pg_attribute.h:41
int16 attnum
Definition: pg_attribute.h:74
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:209
bool attnotnull
Definition: pg_attribute.h:130
void * arg
int errdetail_relkind_not_supported(char relkind)
Definition: pg_class.c:24
NameData relname
Definition: pg_class.h:38
FormData_pg_class * Form_pg_class
Definition: pg_class.h:153
#define PARTITION_MAX_KEYS
#define INDEX_MAX_KEYS
#define NAMEDATALEN
char * ChooseConstraintName(const char *name1, const char *name2, const char *label, Oid namespaceid, List *others)
bool ConstraintNameIsUsed(ConstraintCategory conCat, Oid objId, const char *conname)
void RenameConstraintById(Oid conId, const char *newname)
Oid get_relation_idx_constraint_oid(Oid relationId, Oid indexId)
void ConstraintSetParentConstraint(Oid childConstrId, Oid parentConstrId, Oid childTableId)
void DeconstructFkConstraintRow(HeapTuple tuple, int *numfks, AttrNumber *conkey, AttrNumber *confkey, Oid *pf_eq_oprs, Oid *pp_eq_oprs, Oid *ff_eq_oprs, int *num_fk_del_set_cols, AttrNumber *fk_del_set_cols)
void AlterConstraintNamespaces(Oid ownerId, Oid oldNspId, Oid newNspId, bool isType, ObjectAddresses *objsMoved)
Oid CreateConstraintEntry(const char *constraintName, Oid constraintNamespace, char constraintType, bool isDeferrable, bool isDeferred, bool isValidated, Oid parentConstrId, Oid relId, const int16 *constraintKey, int constraintNKeys, int constraintNTotalKeys, Oid domainId, Oid indexRelId, Oid foreignRelId, const int16 *foreignKey, const Oid *pfEqOp, const Oid *ppEqOp, const Oid *ffEqOp, int foreignNKeys, char foreignUpdateType, char foreignDeleteType, const int16 *fkDeleteSetCols, int numFkDeleteSetCols, char foreignMatchType, const Oid *exclOp, Node *conExpr, const char *conBin, bool conIsLocal, int conInhCount, bool conNoInherit, bool is_internal)
Definition: pg_constraint.c:48
Oid get_relation_constraint_oid(Oid relid, const char *conname, bool missing_ok)
Oid get_domain_constraint_oid(Oid typid, const char *conname, bool missing_ok)
FormData_pg_constraint * Form_pg_constraint
@ CONSTRAINT_RELATION
void recordDependencyOn(const ObjectAddress *depender, const ObjectAddress *referenced, DependencyType behavior)
Definition: pg_depend.c:46
long changeDependencyFor(Oid classId, Oid objectId, Oid refClassId, Oid oldRefObjectId, Oid newRefObjectId)
Definition: pg_depend.c:458
long deleteDependencyRecordsForClass(Oid classId, Oid objectId, Oid refclassId, char deptype)
Definition: pg_depend.c:352
long deleteDependencyRecordsFor(Oid classId, Oid objectId, bool skipExtensionDeps)
Definition: pg_depend.c:302
Oid getIdentitySequence(Relation rel, AttrNumber attnum, bool missing_ok)
Definition: pg_depend.c:946
Oid get_index_constraint(Oid indexId)
Definition: pg_depend.c:989
List * getOwnedSequences(Oid relid)
Definition: pg_depend.c:937
bool sequenceIsOwned(Oid seqId, char deptype, Oid *tableId, int32 *colId)
Definition: pg_depend.c:829
FormData_pg_depend * Form_pg_depend
Definition: pg_depend.h:72
FormData_pg_foreign_table * Form_pg_foreign_table
FormData_pg_index * Form_pg_index
Definition: pg_index.h:70
bool DeleteInheritsTuple(Oid inhrelid, Oid inhparent, bool expect_detach_pending, const char *childname)
Definition: pg_inherits.c:552
List * find_all_inheritors(Oid parentrelId, LOCKMODE lockmode, List **numparents)
Definition: pg_inherits.c:255
void StoreSingleInheritance(Oid relationId, Oid parentOid, int32 seqNumber)
Definition: pg_inherits.c:508
List * find_inheritance_children(Oid parentrelId, LOCKMODE lockmode)
Definition: pg_inherits.c:58
bool has_superclass(Oid relationId)
Definition: pg_inherits.c:377
bool PartitionHasPendingDetach(Oid partoid)
Definition: pg_inherits.c:620
FormData_pg_inherits * Form_pg_inherits
Definition: pg_inherits.h:45
#define lfirst(lc)
Definition: pg_list.h:172
#define lfirst_node(type, lc)
Definition: pg_list.h:176
static int list_length(const List *l)
Definition: pg_list.h:152
#define NIL
Definition: pg_list.h:68
#define forboth(cell1, list1, cell2, list2)
Definition: pg_list.h:518
#define foreach_current_index(var_or_cell)
Definition: pg_list.h:403
#define lfirst_int(lc)
Definition: pg_list.h:173
#define foreach_delete_current(lst, var_or_cell)
Definition: pg_list.h:391
#define list_make1_oid(x1)
Definition: pg_list.h:242
#define list_make1(x1)
Definition: pg_list.h:212
#define foreach_ptr(type, var, lst)
Definition: pg_list.h:469
static ListCell * list_head(const List *l)
Definition: pg_list.h:128
#define for_each_from(cell, lst, N)
Definition: pg_list.h:414
#define linitial(l)
Definition: pg_list.h:178
#define list_make3(x1, x2, x3)
Definition: pg_list.h:216
static void * list_nth(const List *list, int n)
Definition: pg_list.h:299
#define foreach_oid(var, lst)
Definition: pg_list.h:471
#define list_nth_node(type, list, n)
Definition: pg_list.h:327
static ListCell * lnext(const List *l, const ListCell *c)
Definition: pg_list.h:343
#define linitial_oid(l)
Definition: pg_list.h:180
#define lfirst_oid(lc)
Definition: pg_list.h:174
#define list_make2(x1, x2)
Definition: pg_list.h:214
FormData_pg_opclass * Form_pg_opclass
Definition: pg_opclass.h:83
List * GetRelationPublications(Oid relid)
void changeDependencyOnOwner(Oid classId, Oid objectId, Oid newOwnerId)
Definition: pg_shdepend.c:316
void changeDependencyOnTablespace(Oid classId, Oid objectId, Oid newTablespaceId)
Definition: pg_shdepend.c:391
static char * buf
Definition: pg_test_fsync.c:73
FormData_pg_trigger * Form_pg_trigger
Definition: pg_trigger.h:80
void RenameTypeInternal(Oid typeOid, const char *newTypeName, Oid typeNamespace)
Definition: pg_type.c:765
FormData_pg_type * Form_pg_type
Definition: pg_type.h:261
#define ERRCODE_UNDEFINED_TABLE
Definition: pgbench.c:78
void pgstat_count_truncate(Relation rel)
Expr * expression_planner(Expr *expr)
Definition: planner.c:6580
int pg_strcasecmp(const char *s1, const char *s2)
Definition: pgstrcasecmp.c:36
#define sprintf
Definition: port.h:240
#define snprintf
Definition: port.h:238
size_t strlcpy(char *dst, const char *src, size_t siz)
Definition: strlcpy.c:45
void check_stack_depth(void)
Definition: postgres.c:3530
static Datum PointerGetDatum(const void *X)
Definition: postgres.h:322
uintptr_t Datum
Definition: postgres.h:64
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:252
static Pointer DatumGetPointer(Datum X)
Definition: postgres.h:312
static Datum CStringGetDatum(const char *X)
Definition: postgres.h:350
static Datum Int32GetDatum(int32 X)
Definition: postgres.h:212
static Datum CharGetDatum(char X)
Definition: postgres.h:122
#define InvalidOid
Definition: postgres_ext.h:36
unsigned int Oid
Definition: postgres_ext.h:31
void CheckTableForSerializableConflictIn(Relation relation)
Definition: predicate.c:4404
void TransferPredicateLocksToHeapRelation(Relation relation)
Definition: predicate.c:3108
bool predicate_implied_by(List *predicate_list, List *clause_list, bool weak)
Definition: predtest.c:152
Expr * canonicalize_qual(Expr *qual, bool is_check)
Definition: prepqual.c:293
char * c
#define PRS2_OLD_VARNO
Definition: primnodes.h:244
#define PRS2_NEW_VARNO
Definition: primnodes.h:245
OnCommitAction
Definition: primnodes.h:56
@ ONCOMMIT_DELETE_ROWS
Definition: primnodes.h:59
@ ONCOMMIT_NOOP
Definition: primnodes.h:57
@ ONCOMMIT_PRESERVE_ROWS
Definition: primnodes.h:58
@ ONCOMMIT_DROP
Definition: primnodes.h:60
@ COERCE_IMPLICIT_CAST
Definition: primnodes.h:736
@ IS_NOT_NULL
Definition: primnodes.h:1948
@ COERCION_ASSIGNMENT
Definition: primnodes.h:715
@ COERCION_IMPLICIT
Definition: primnodes.h:714
tree context
Definition: radixtree.h:1835
MemoryContextSwitchTo(old_ctx)
void * stringToNode(const char *str)
Definition: read.c:90
#define RelationGetForm(relation)
Definition: rel.h:499
#define RelationGetRelid(relation)
Definition: rel.h:505
#define RelationIsLogicallyLogged(relation)
Definition: rel.h:701
#define RelationIsUsedAsCatalogTable(relation)
Definition: rel.h:386
static SMgrRelation RelationGetSmgr(Relation rel)
Definition: rel.h:567
#define RelationGetDescr(relation)
Definition: rel.h:531
#define RelationIsMapped(relation)
Definition: rel.h:554
#define RelationGetNumberOfAttributes(relation)
Definition: rel.h:511
#define RelationGetRelationName(relation)
Definition: rel.h:539
#define RELATION_IS_OTHER_TEMP(relation)
Definition: rel.h:658
#define RelationGetNamespace(relation)
Definition: rel.h:546
#define IndexRelationGetNumberOfKeyAttributes(relation)
Definition: rel.h:524
#define RelationIsPermanent(relation)
Definition: rel.h:617
List * RelationGetIndexList(Relation relation)
Definition: relcache.c:4801
int errtableconstraint(Relation rel, const char *conname)
Definition: relcache.c:6006
int errtablecol(Relation rel, int attnum)
Definition: relcache.c:5969
List * RelationGetIndexPredicate(Relation relation)
Definition: relcache.c:5151
Bitmapset * RelationGetIndexAttrBitmap(Relation relation, IndexAttrBitmapKind attrKind)
Definition: relcache.c:5244
List * RelationGetFKeyList(Relation relation)
Definition: relcache.c:4692
void RelationSetNewRelfilenumber(Relation relation, char persistence)
Definition: relcache.c:3767
void RelationAssumeNewRelfilelocator(Relation relation)
Definition: relcache.c:3966
int errtable(Relation rel)
Definition: relcache.c:5952
List * RelationGetIndexExpressions(Relation relation)
Definition: relcache.c:5038
struct RelationData * Relation
Definition: relcache.h:27
@ INDEX_ATTR_BITMAP_KEY
Definition: relcache.h:61
bytea * index_reloptions(amoptions_function amoptions, Datum reloptions, bool validate)
Definition: reloptions.c:2054
List * untransformRelOptions(Datum options)
Definition: reloptions.c:1331
Datum transformRelOptions(Datum oldOptions, List *defList, const char *namspace, char *validnsps[], bool acceptOidsOff, bool isReset)
Definition: reloptions.c:1156
bytea * heap_reloptions(char relkind, Datum reloptions, bool validate)
Definition: reloptions.c:2019
bytea * view_reloptions(Datum reloptions, bool validate)
Definition: reloptions.c:1998
bytea * partitioned_table_reloptions(Datum reloptions, bool validate)
Definition: reloptions.c:1984
LOCKMODE AlterTableGetRelOptionsLockLevel(List *defList)
Definition: reloptions.c:2108
bytea * attribute_reloptions(Datum reloptions, bool validate)
Definition: reloptions.c:2069
#define HEAP_RELOPT_NAMESPACES
Definition: reloptions.h:61
Oid RelFileNumber
Definition: relpath.h:25
ForkNumber
Definition: relpath.h:48
@ MAIN_FORKNUM
Definition: relpath.h:50
@ INIT_FORKNUM
Definition: relpath.h:53
#define MAX_FORKNUM
Definition: relpath.h:62
#define RelFileNumberIsValid(relnumber)
Definition: relpath.h:27
void EnableDisableRule(Relation rel, const char *rulename, char fires_when)
#define RULE_FIRES_ON_ORIGIN
Definition: rewriteDefine.h:21
#define RULE_FIRES_ON_REPLICA
Definition: rewriteDefine.h:23
#define RULE_FIRES_ALWAYS
Definition: rewriteDefine.h:22
#define RULE_DISABLED
Definition: rewriteDefine.h:24
const char * view_query_is_auto_updatable(Query *viewquery, bool check_cols)
Query * get_view_query(Relation view)
Node * build_column_default(Relation rel, int attrno)
Node * map_variable_attnos(Node *node, int target_varno, int sublevels_up, const AttrMap *attno_map, Oid to_rowtype, bool *found_whole_row)
Datum RI_FKey_check_ins(PG_FUNCTION_ARGS)
Definition: ri_triggers.c:424
bool RI_Initial_Check(Trigger *trigger, Relation fk_rel, Relation pk_rel)
Definition: ri_triggers.c:1359
void RI_PartitionRemove_Check(Trigger *trigger, Relation fk_rel, Relation pk_rel)
Definition: ri_triggers.c:1654
int RI_FKey_trigger_type(Oid tgfoid)
Definition: ri_triggers.c:3001
char * pg_get_constraintdef_command(Oid constraintId)
Definition: ruleutils.c:2168
const char * quote_identifier(const char *ident)
Definition: ruleutils.c:12596
char * pg_get_statisticsobjdef_string(Oid statextid)
Definition: ruleutils.c:1611
Datum pg_get_expr(PG_FUNCTION_ARGS)
Definition: ruleutils.c:2628
char * pg_get_indexdef_string(Oid indexrelid)
Definition: ruleutils.c:1209
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
@ ForwardScanDirection
Definition: sdir.h:28
void smgrcreate(SMgrRelation reln, ForkNumber forknum, bool isRedo)
Definition: smgr.c:411
void smgrclose(SMgrRelation reln)
Definition: smgr.c:320
bool smgrexists(SMgrRelation reln, ForkNumber forknum)
Definition: smgr.c:398
TransactionId RecentXmin
Definition: snapmgr.c:99
Snapshot GetTransactionSnapshot(void)
Definition: snapmgr.c:216
Snapshot GetLatestSnapshot(void)
Definition: snapmgr.c:291
void UnregisterSnapshot(Snapshot snapshot)
Definition: snapmgr.c:836
void PushActiveSnapshot(Snapshot snapshot)
Definition: snapmgr.c:648
Snapshot RegisterSnapshot(Snapshot snapshot)
Definition: snapmgr.c:794
void PopActiveSnapshot(void)
Definition: snapmgr.c:743
Snapshot GetActiveSnapshot(void)
Definition: snapmgr.c:770
void relation_close(Relation relation, LOCKMODE lockmode)
Definition: relation.c:205
Relation try_relation_open(Oid relationId, LOCKMODE lockmode)
Definition: relation.c:88
Relation relation_open(Oid relationId, LOCKMODE lockmode)
Definition: relation.c:47
ObjectAddress CreateStatistics(CreateStatsStmt *stmt)
Definition: statscmds.c:62
Oid StatisticsGetRelation(Oid statId, bool missing_ok)
Definition: statscmds.c:898
void RelationPreserveStorage(RelFileLocator rlocator, bool atCommit)
Definition: storage.c:251
void RelationCopyStorage(SMgrRelation src, SMgrRelation dst, ForkNumber forkNum, char relpersistence)
Definition: storage.c:452
SMgrRelation RelationCreateStorage(RelFileLocator rlocator, char relpersistence, bool register_delete)
Definition: storage.c:121
void log_smgrcreate(const RelFileLocator *rlocator, ForkNumber forkNum)
Definition: storage.c:186
void RelationDropStorage(Relation rel)
Definition: storage.c:206
#define BTEqualStrategyNumber
Definition: stratnum.h:31
#define ERRCODE_DUPLICATE_OBJECT
Definition: streamutil.c:32
RoleSpec * newowner
Definition: parsenodes.h:2439
DropBehavior behavior
Definition: parsenodes.h:2442
AlterTableType subtype
Definition: parsenodes.h:2434
RangeVar * relation
Definition: parsenodes.h:2345
ObjectType objtype
Definition: parsenodes.h:2347
List * constraints
Definition: tablecmds.c:185
bool verify_new_notnull
Definition: tablecmds.c:188
List * changedConstraintDefs
Definition: tablecmds.c:201
Expr * partition_constraint
Definition: tablecmds.c:196
char newrelpersistence
Definition: tablecmds.c:195
List * changedStatisticsDefs
Definition: tablecmds.c:207
bool chgAccessMethod
Definition: tablecmds.c:190
List * afterStmts
Definition: tablecmds.c:187
char * clusterOnIndex
Definition: tablecmds.c:205
char * replicaIdentityIndex
Definition: tablecmds.c:204
List * changedStatisticsOids
Definition: tablecmds.c:206
List * changedIndexDefs
Definition: tablecmds.c:203
List * changedIndexOids
Definition: tablecmds.c:202
List * changedConstraintOids
Definition: tablecmds.c:200
bool validate_default
Definition: tablecmds.c:198
List * subcmds[AT_NUM_PASSES]
Definition: tablecmds.c:183
TupleDesc oldDesc
Definition: tablecmds.c:171
Relation rel
Definition: tablecmds.c:180
Definition: attmap.h:35
AttrNumber * attnums
Definition: attmap.h:36
bool is_not_null
Definition: parsenodes.h:731
char identity
Definition: parsenodes.h:737
RangeVar * identitySequence
Definition: parsenodes.h:738
List * constraints
Definition: parsenodes.h:743
Node * cooked_default
Definition: parsenodes.h:736
char * storage_name
Definition: parsenodes.h:734
int inhcount
Definition: parsenodes.h:729
char * colname
Definition: parsenodes.h:726
TypeName * typeName
Definition: parsenodes.h:727
char generated
Definition: parsenodes.h:740
bool is_from_type
Definition: parsenodes.h:732
Node * raw_default
Definition: parsenodes.h:735
char storage
Definition: parsenodes.h:733
bool is_local
Definition: parsenodes.h:730
char * compression
Definition: parsenodes.h:728
char * comment
Definition: parsenodes.h:3262
ObjectType objtype
Definition: parsenodes.h:3260
Node * object
Definition: parsenodes.h:3261
char * ccname
Definition: tupdesc.h:30
bool ccvalid
Definition: tupdesc.h:32
char * ccbin
Definition: tupdesc.h:31
bool initdeferred
Definition: parsenodes.h:2739
ParseLoc location
Definition: parsenodes.h:2777
bool reset_default_tblspc
Definition: parsenodes.h:2760
List * pk_attrs
Definition: parsenodes.h:2768
List * fk_del_set_cols
Definition: parsenodes.h:2772
ConstrType contype
Definition: parsenodes.h:2736
Oid old_pktable_oid
Definition: parsenodes.h:2774
bool is_no_inherit
Definition: parsenodes.h:2742
char fk_upd_action
Definition: parsenodes.h:2770
List * old_conpfeqop
Definition: parsenodes.h:2773
char fk_matchtype
Definition: parsenodes.h:2769
char * cooked_expr
Definition: parsenodes.h:2745
bool initially_valid
Definition: parsenodes.h:2741
bool skip_validation
Definition: parsenodes.h:2740
bool deferrable
Definition: parsenodes.h:2738
Node * raw_expr
Definition: parsenodes.h:2743
char * conname
Definition: parsenodes.h:2737
RangeVar * pktable
Definition: parsenodes.h:2766
char fk_del_action
Definition: parsenodes.h:2771
List * fk_attrs
Definition: parsenodes.h:2767
Oid conoid
Definition: heap.h:38
char * name
Definition: heap.h:39
AttrNumber attnum
Definition: heap.h:40
bool skip_validation
Definition: heap.h:42
bool is_no_inherit
Definition: heap.h:45
int inhcount
Definition: heap.h:44
bool is_local
Definition: heap.h:43
ConstrType contype
Definition: heap.h:37
Node * expr
Definition: heap.h:41
List * tableElts
Definition: parsenodes.h:2657
OnCommitAction oncommit
Definition: parsenodes.h:2665
List * options
Definition: parsenodes.h:2664
bool if_not_exists
Definition: parsenodes.h:2668
List * inhRelations
Definition: parsenodes.h:2658
RangeVar * relation
Definition: parsenodes.h:2656
char * tablespacename
Definition: parsenodes.h:2666
char * accessMethod
Definition: parsenodes.h:2667
List * constraints
Definition: parsenodes.h:2663
Node * whenClause
Definition: parsenodes.h:3021
List * transitionRels
Definition: parsenodes.h:3023
RangeVar * constrrel
Definition: parsenodes.h:3027
RangeVar * relation
Definition: parsenodes.h:3012
char * defname
Definition: parsenodes.h:815
bool missing_ok
Definition: parsenodes.h:3237
List * objects
Definition: parsenodes.h:3234
ObjectType removeType
Definition: parsenodes.h:3235
bool concurrent
Definition: parsenodes.h:3238
DropBehavior behavior
Definition: parsenodes.h:3236
List * es_opened_result_relations
Definition: execnodes.h:645
TupleTableSlot * ecxt_scantuple
Definition: execnodes.h:255
ExecForeignTruncate_function ExecForeignTruncate
Definition: fdwapi.h:263
Oid funcid
Definition: primnodes.h:750
List * args
Definition: primnodes.h:768
Size keysize
Definition: hsearch.h:75
Size entrysize
Definition: hsearch.h:76
MemoryContext hcxt
Definition: hsearch.h:86
Definition: dynahash.c:220
ItemPointerData t_self
Definition: htup.h:65
amoptions_function amoptions
Definition: amapi.h:275
bool amcanunique
Definition: amapi.h:230
bool ii_Unique
Definition: execnodes.h:197
bool reset_default_tblspc
Definition: parsenodes.h:3381
char * idxname
Definition: parsenodes.h:3356
char * idxcomment
Definition: parsenodes.h:3366
Definition: lock.h:165
Definition: pg_list.h:54
AttrNumber attnum
Definition: tablecmds.c:233
bool is_generated
Definition: tablecmds.c:236
ExprState * exprstate
Definition: tablecmds.c:235
char * name
Definition: tablecmds.c:214
ConstrType contype
Definition: tablecmds.c:215
Node * qual
Definition: tablecmds.c:219
ExprState * qualstate
Definition: tablecmds.c:220
Definition: nodes.h:129
NullTestType nulltesttype
Definition: primnodes.h:1955
ParseLoc location
Definition: primnodes.h:1958
Expr * arg
Definition: primnodes.h:1954
SubTransactionId creating_subid
Definition: tablecmds.c:125
SubTransactionId deleting_subid
Definition: tablecmds.c:126
OnCommitAction oncommit
Definition: tablecmds.c:116
const char * p_sourcetext
Definition: parse_node.h:193
PartitionBoundSpec * bound
Definition: parsenodes.h:958
List * partlist
Definition: parsenodes.h:959
RangeVar * name
Definition: parsenodes.h:957
List * collation
Definition: parsenodes.h:865
ParseLoc location
Definition: parsenodes.h:867
List * opclass
Definition: parsenodes.h:866
List * partParams
Definition: parsenodes.h:886
ParseLoc location
Definition: parsenodes.h:887
PartitionStrategy strategy
Definition: parsenodes.h:885
bool canSetTag
Definition: plannodes.h:60
ParseLoc stmt_len
Definition: plannodes.h:99
ParseLoc stmt_location
Definition: plannodes.h:98
CmdType commandType
Definition: plannodes.h:52
Node * utilityStmt
Definition: plannodes.h:95
char * relname
Definition: primnodes.h:82
bool inh
Definition: primnodes.h:85
char relpersistence
Definition: primnodes.h:88
char * schemaname
Definition: primnodes.h:79
Node * raw_default
Definition: heap.h:30
AttrNumber attnum
Definition: heap.h:29
char generated
Definition: heap.h:32
bool missingMode
Definition: heap.h:31
Node * stmt
Definition: parsenodes.h:2025
RelFileNumber relNumber
struct IndexAmRoutine * rd_indam
Definition: rel.h:206
SubTransactionId rd_firstRelfilelocatorSubid
Definition: rel.h:106
int rd_refcnt
Definition: rel.h:59
TriggerDesc * trigdesc
Definition: rel.h:117
bool rd_islocaltemp
Definition: rel.h:61
TupleDesc rd_att
Definition: rel.h:112
Form_pg_index rd_index
Definition: rel.h:192
bool rd_isnailed
Definition: rel.h:62
Oid rd_id
Definition: rel.h:113
SubTransactionId rd_newRelfilelocatorSubid
Definition: rel.h:104
SubTransactionId rd_createSubid
Definition: rel.h:103
RelFileLocator rd_locator
Definition: rel.h:57
Oid * rd_opfamily
Definition: rel.h:207
Oid * rd_indcollation
Definition: rel.h:217
Form_pg_class rd_rel
Definition: rel.h:111
Relation ri_RelationDesc
Definition: execnodes.h:456
PartitionBoundSpec * bound
Definition: parsenodes.h:948
TransactionId xmin
Definition: snapshot.h:157
TupleTableSlot * dstslot
Definition: tablecmds.c:20069
BulkInsertState bistate
Definition: tablecmds.c:20068
ExprState * partqualstate
Definition: tablecmds.c:20066
RangeVar * relation
Definition: parsenodes.h:754
NodeTag type
Definition: trigger.h:33
Relation tg_relation
Definition: trigger.h:35
TriggerEvent tg_event
Definition: trigger.h:34
TupleTableSlot * tg_trigslot
Definition: trigger.h:39
Trigger * tg_trigger
Definition: trigger.h:38
HeapTuple tg_trigtuple
Definition: trigger.h:36
char tgenabled
Definition: reltrigger.h:30
Oid tgoid
Definition: reltrigger.h:25
Oid tgconstrindid
Definition: reltrigger.h:34
Oid tgconstraint
Definition: reltrigger.h:35
Oid tgconstrrelid
Definition: reltrigger.h:33
char * tgname
Definition: reltrigger.h:27
bool tgdeferrable
Definition: reltrigger.h:36
bool tginitdeferred
Definition: reltrigger.h:37
bool tgisinternal
Definition: reltrigger.h:31
bool has_not_null
Definition: tupdesc.h:44
ConstrCheck * check
Definition: tupdesc.h:40
uint16 num_check
Definition: tupdesc.h:43
AttrMap * attrMap
Definition: tupconvert.h:28
TupleConstr * constr
Definition: tupdesc.h:85
Oid tts_tableOid
Definition: tuptable.h:130
AttrNumber tts_nvalid
Definition: tuptable.h:120
bool * tts_isnull
Definition: tuptable.h:127
Datum * tts_values
Definition: tuptable.h:125
bool setof
Definition: parsenodes.h:270
List * arrayBounds
Definition: parsenodes.h:274
Definition: primnodes.h:248
const char * skipping_msg
Definition: tablecmds.c:247
int nonexistent_code
Definition: tablecmds.c:245
const char * nonexistent_msg
Definition: tablecmds.c:246
const char * drophint_msg
Definition: tablecmds.c:249
const char * nota_msg
Definition: tablecmds.c:248
Definition: type.h:95
Definition: c.h:726
Oid values[FLEXIBLE_ARRAY_MEMBER]
Definition: c.h:733
Definition: regguts.h:323
bool superuser(void)
Definition: superuser.c:46
#define FirstLowInvalidHeapAttributeNumber
Definition: sysattr.h:27
HeapTuple SearchSysCacheCopyAttName(Oid relid, const char *attname)
Definition: syscache.c:382
HeapTuple SearchSysCacheCopyAttNum(Oid relid, int16 attnum)
Definition: syscache.c:445
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:266
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:218
HeapTuple SearchSysCacheAttNum(Oid relid, int16 attnum)
Definition: syscache.c:422
Datum SysCacheGetAttr(int cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition: syscache.c:479
bool SearchSysCacheExistsAttName(Oid relid, const char *attname)
Definition: syscache.c:401
HeapTuple SearchSysCache2(int cacheId, Datum key1, Datum key2)
Definition: syscache.c:229
HeapTuple SearchSysCacheAttName(Oid relid, const char *attname)
Definition: syscache.c:359
Datum SysCacheGetAttrNotNull(int cacheId, HeapTuple tup, AttrNumber attributeNumber)
Definition: syscache.c:510
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:86
#define SearchSysCacheExists2(cacheId, key1, key2)
Definition: syscache.h:97
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:126
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:40
Relation table_openrv(const RangeVar *relation, LOCKMODE lockmode)
Definition: table.c:83
const TupleTableSlotOps * table_slot_callbacks(Relation relation)
Definition: tableam.c:58
TableScanDesc table_beginscan_catalog(Relation relation, int nkeys, struct ScanKeyData *key)
Definition: tableam.c:112
char * default_table_access_method
Definition: tableam.c:48
TupleTableSlot * table_slot_create(Relation relation, List **reglist)
Definition: tableam.c:91
static TableScanDesc table_beginscan(Relation rel, Snapshot snapshot, int nkeys, struct ScanKeyData *key)
Definition: tableam.h:908
static void table_endscan(TableScanDesc scan)
Definition: tableam.h:1019
#define TABLE_INSERT_SKIP_FSM
Definition: tableam.h:260
static void table_finish_bulk_insert(Relation rel, int options)
Definition: tableam.h:1595
static void table_tuple_insert(Relation rel, TupleTableSlot *slot, CommandId cid, int options, struct BulkInsertStateData *bistate)
Definition: tableam.h:1402
static void table_relation_copy_data(Relation rel, const RelFileLocator *newrlocator)
Definition: tableam.h:1651
static bool table_scan_getnextslot(TableScanDesc sscan, ScanDirection direction, TupleTableSlot *slot)
Definition: tableam.h:1055
static AttrNumber renameatt_internal(Oid myrelid, const char *oldattname, const char *newattname, bool recurse, bool recursing, int expected_parents, DropBehavior behavior)
Definition: tablecmds.c:3678
void ResetRelRewrite(Oid myrelid)
Definition: tablecmds.c:4191
static void MergeAttributesIntoExisting(Relation child_rel, Relation parent_rel, bool ispartition)
Definition: tablecmds.c:15733
static ObjectAddress ATExecSetNotNull(AlteredTableInfo *tab, Relation rel, const char *colName, LOCKMODE lockmode)
Definition: tablecmds.c:7735
static void MarkInheritDetached(Relation child_rel, Relation parent_rel)
Definition: tablecmds.c:16020
static ObjectAddress ATExecAlterColumnGenericOptions(Relation rel, const char *colName, List *options, LOCKMODE lockmode)
Definition: tablecmds.c:14197
static void ATRewriteCatalogs(List **wqueue, LOCKMODE lockmode, AlterTableUtilityContext *context)
Definition: tablecmds.c:5139
static ObjectAddress ATExecAddInherit(Relation child_rel, RangeVar *parent, LOCKMODE lockmode)
Definition: tablecmds.c:15498
ObjectAddress RenameRelation(RenameStmt *stmt)
Definition: tablecmds.c:4037
static AlteredTableInfo * ATGetQueueEntry(List **wqueue, Relation rel)
Definition: tablecmds.c:6361
static void ATExecDropOf(Relation rel, LOCKMODE lockmode)
Definition: tablecmds.c:16465
static ColumnDef * MergeInheritedAttribute(List *inh_columns, int exist_attno, const ColumnDef *newdef)
Definition: tablecmds.c:3248
#define ATT_TABLE
Definition: tablecmds.c:325
static bool ConstraintImpliedByRelConstraint(Relation scanrel, List *testConstraint, List *provenConstraint)
Definition: tablecmds.c:18187
static const char * storage_name(char c)
Definition: tablecmds.c:2360
static ObjectAddress ATExecDropExpression(Relation rel, const char *colName, bool missing_ok, LOCKMODE lockmode)
Definition: tablecmds.c:8494
void AtEOSubXact_on_commit_actions(bool isCommit, SubTransactionId mySubid, SubTransactionId parentSubid)
Definition: tablecmds.c:17550
static void add_column_datatype_dependency(Oid relid, int32 attnum, Oid typid)
Definition: tablecmds.c:7466
static ObjectAddress ATExecColumnDefault(Relation rel, const char *colName, Node *newDefault, LOCKMODE lockmode)
Definition: tablecmds.c:7883
static void ATPostAlterTypeParse(Oid oldId, Oid oldRelId, Oid refRelId, char *cmd, List **wqueue, LOCKMODE lockmode, bool rewrite)
Definition: tablecmds.c:13869
static void ATExecSetTableSpace(Oid tableOid, Oid newTableSpace, LOCKMODE lockmode)
Definition: tablecmds.c:15090
static void drop_parent_dependency(Oid relid, Oid refclassid, Oid refobjid, DependencyType deptype)
Definition: tablecmds.c:16271
static void RemoveInheritance(Relation child_rel, Relation parent_rel, bool expect_detached)
Definition: tablecmds.c:16103
#define AT_NUM_PASSES
Definition: tablecmds.c:164
void PreCommit_on_commit_actions(void)
Definition: tablecmds.c:17411
static int transformFkeyGetPrimaryKey(Relation pkrel, Oid *indexOid, List **attnamelist, int16 *attnums, Oid *atttypids, Oid *opclasses)
Definition: tablecmds.c:11817
struct SplitPartitionContext SplitPartitionContext
static void ATExecDropConstraint(Relation rel, const char *constrName, DropBehavior behavior, bool recurse, bool recursing, bool missing_ok, LOCKMODE lockmode)
Definition: tablecmds.c:12428
static ObjectAddress ATExecDropIdentity(Relation rel, const char *colName, bool missing_ok, LOCKMODE lockmode, bool recurse, bool recursing)
Definition: tablecmds.c:8221
static char GetAttributeCompression(Oid atttypid, const char *compression)
Definition: tablecmds.c:19990
static ObjectAddress ATExecDropNotNull(Relation rel, const char *colName, LOCKMODE lockmode)
Definition: tablecmds.c:7531
static int findAttrByName(const char *attributeName, const List *columns)
Definition: tablecmds.c:3447
static void RememberIndexForRebuilding(Oid indoid, AlteredTableInfo *tab)
Definition: tablecmds.c:13621
static bool ATColumnChangeRequiresRewrite(Node *expr, AttrNumber varattno)
Definition: tablecmds.c:12960
static char * ChooseForeignKeyConstraintNameAddition(List *colnames)
Definition: tablecmds.c:9403
static ObjectAddress ATExecValidateConstraint(List **wqueue, Relation rel, char *constrName, bool recurse, bool recursing, LOCKMODE lockmode)
Definition: tablecmds.c:11576
void AlterTable(AlterTableStmt *stmt, LOCKMODE lockmode, AlterTableUtilityContext *context)
Definition: tablecmds.c:4362
static void RememberStatisticsForRebuilding(Oid stxoid, AlteredTableInfo *tab)
Definition: tablecmds.c:13672
static CoercionPathType findFkeyCast(Oid targetTypeId, Oid sourceTypeId, Oid *funcid)
Definition: tablecmds.c:12055
static void add_column_collation_dependency(Oid relid, int32 attnum, Oid collid)
Definition: tablecmds.c:7484
#define ATT_SEQUENCE
Definition: tablecmds.c:332
void RemoveRelations(DropStmt *drop)
Definition: tablecmds.c:1437
static void ATPrepSetTableSpace(AlteredTableInfo *tab, Relation rel, const char *tablespacename, LOCKMODE lockmode)
Definition: tablecmds.c:14857
static void ATTypedTableRecursion(List **wqueue, Relation rel, AlterTableCmd *cmd, LOCKMODE lockmode, AlterTableUtilityContext *context)
Definition: tablecmds.c:6694
static void RememberReplicaIdentityForRebuilding(Oid indoid, AlteredTableInfo *tab)
Definition: tablecmds.c:13550
static List * MergeAttributes(List *columns, const List *supers, char relpersistence, bool is_partition, List **supconstr)
Definition: tablecmds.c:2439
static List * GetParentedForeignKeyRefs(Relation partition)
Definition: tablecmds.c:19888
void AlterRelationNamespaceInternal(Relation classRel, Oid relOid, Oid oldNspOid, Oid newNspOid, bool hasDependEntry, ObjectAddresses *objsMoved)
Definition: tablecmds.c:17152
static ObjectAddress ATExecAddConstraint(List **wqueue, AlteredTableInfo *tab, Relation rel, Constraint *newConstraint, bool recurse, bool is_readd, LOCKMODE lockmode)
Definition: tablecmds.c:9330
ObjectAddress renameatt(RenameStmt *stmt)
Definition: tablecmds.c:3843
void ATExecChangeOwner(Oid relationOid, Oid newOwnerId, bool recursing, LOCKMODE lockmode)
Definition: tablecmds.c:14314
static void RangeVarCallbackForAlterRelation(const RangeVar *rv, Oid relid, Oid oldrelid, void *arg)
Definition: tablecmds.c:17677
static void CheckAlterTableIsSafe(Relation rel)
Definition: tablecmds.c:4277
static void DropErrorMsgWrongType(const char *relname, char wrongkind, char rightkind)
Definition: tablecmds.c:1410
LOCKMODE AlterTableGetLockLevel(List *cmds)
Definition: tablecmds.c:4436
static int transformColumnNameList(Oid relId, List *colList, int16 *attnums, Oid *atttypids)
Definition: tablecmds.c:11765
static void validateForeignKeyConstraint(char *conname, Relation rel, Relation pkrel, Oid pkindOid, Oid constraintOid)
Definition: tablecmds.c:12113
struct ForeignTruncateInfo ForeignTruncateInfo
static ObjectAddress ATExecDetachPartition(List **wqueue, AlteredTableInfo *tab, Relation rel, RangeVar *name, bool concurrent)
Definition: tablecmds.c:18987
static bool ATExecAlterConstrRecurse(Constraint *cmdcon, Relation conrel, Relation tgrel, Relation rel, HeapTuple contuple, List **otherrelids, LOCKMODE lockmode)
Definition: tablecmds.c:11425
static void AlterSeqNamespaces(Relation classRel, Relation rel, Oid oldNspOid, Oid newNspOid, ObjectAddresses *objsMoved, LOCKMODE lockmode)
Definition: tablecmds.c:17267
static void RangeVarCallbackForRenameAttribute(const RangeVar *rv, Oid relid, Oid oldrelid, void *arg)
Definition: tablecmds.c:3823
TupleDesc BuildDescForRelation(const List *columns)
Definition: tablecmds.c:1281
static void attachPartitionTable(List **wqueue, Relation rel, Relation attachrel, PartitionBoundSpec *bound)
Definition: tablecmds.c:18321
static void ATExecForceNoForceRowSecurity(Relation rel, bool force_rls)
Definition: tablecmds.c:16735
void AtEOXact_on_commit_actions(bool isCommit)
Definition: tablecmds.c:17518
static void checkFkeyPermissions(Relation rel, int16 *attnums, int natts)
Definition: tablecmds.c:12084
struct OnCommitItem OnCommitItem
void CheckTableNotInUse(Relation rel, const char *stmt)
Definition: tablecmds.c:4244
static void moveSplitTableRows(Relation rel, Relation splitRel, List *partlist, List *newPartRels, Oid defaultPartOid)
Definition: tablecmds.c:20123
static void ATExecEnableDisableTrigger(Relation rel, const char *trigname, char fires_when, bool skip_system, bool recurse, LOCKMODE lockmode)
Definition: tablecmds.c:15441
static void createForeignKeyActionTriggers(Relation rel, Oid refRelOid, Constraint *fkconstraint, Oid constraintOid, Oid indexOid, Oid parentDelTrigger, Oid parentUpdTrigger, Oid *deleteTrigOid, Oid *updateTrigOid)
Definition: tablecmds.c:12273
static void renameatt_check(Oid myrelid, Form_pg_class classform, bool recursing)
Definition: tablecmds.c:3629
static void RangeVarCallbackForAttachIndex(const RangeVar *rv, Oid relOid, Oid oldRelOid, void *arg)
Definition: tablecmds.c:19555
static void ATCheckPartitionsNotInUse(Relation rel, LOCKMODE lockmode)
Definition: tablecmds.c:6664
static void truncate_check_activity(Relation rel)
Definition: tablecmds.c:2337
static void validatePartitionedIndex(Relation partedIdx, Relation partedTbl)
Definition: tablecmds.c:19787
static ObjectAddress ATAddForeignKeyConstraint(List **wqueue, AlteredTableInfo *tab, Relation rel, Constraint *fkconstraint, bool recurse, bool recursing, LOCKMODE lockmode)
Definition: tablecmds.c:9582
static void TryReuseIndex(Oid oldId, IndexStmt *stmt)
Definition: tablecmds.c:14129
static void GetForeignKeyCheckTriggers(Relation trigrel, Oid conoid, Oid confrelid, Oid conrelid, Oid *insertTriggerOid, Oid *updateTriggerOid)
Definition: tablecmds.c:11221
static void ATPrepSetNotNull(List **wqueue, Relation rel, AlterTableCmd *cmd, bool recurse, bool recursing, LOCKMODE lockmode, AlterTableUtilityContext *context)
Definition: tablecmds.c:7666
static void RememberClusterOnForRebuilding(Oid indoid, AlteredTableInfo *tab)
Definition: tablecmds.c:13565
static ObjectAddress ATExecSetOptions(Relation rel, const char *colName, Node *options, bool isReset, LOCKMODE lockmode)
Definition: tablecmds.c:8720
static ObjectAddress ATExecDropColumn(List **wqueue, Relation rel, const char *colName, DropBehavior behavior, bool recurse, bool recursing, bool missing_ok, LOCKMODE lockmode, ObjectAddresses *addrs)
Definition: tablecmds.c:8953
static void CloneFkReferencing(List **wqueue, Relation parentRel, Relation partRel)
Definition: tablecmds.c:10749
static void ATPrepDropNotNull(Relation rel, bool recurse, bool recursing)
Definition: tablecmds.c:7507
static void SetIndexStorageProperties(Relation rel, Relation attrelation, AttrNumber attnum, bool setstorage, char newstorage, bool setcompression, char newcompression, LOCKMODE lockmode)
Definition: tablecmds.c:8799
static void ATController(AlterTableStmt *parsetree, Relation rel, List *cmds, bool recurse, LOCKMODE lockmode, AlterTableUtilityContext *context)
Definition: tablecmds.c:4715
bool CheckRelationTableSpaceMove(Relation rel, Oid newTableSpaceId)
Definition: tablecmds.c:3530
static void ATExecSetRowSecurity(Relation rel, bool rls)
Definition: tablecmds.c:16705
static void ATExecCheckNotNull(AlteredTableInfo *tab, Relation rel, const char *colName, LOCKMODE lockmode)
Definition: tablecmds.c:7817
static Oid transformFkeyCheckAttrs(Relation pkrel, int numattrs, int16 *attnums, Oid *opclasses)
Definition: tablecmds.c:11916
void find_composite_type_dependencies(Oid typeOid, Relation origRelation, const char *origTypeName)
Definition: tablecmds.c:6739
static void truncate_check_perms(Oid relid, Form_pg_class reltuple)
Definition: tablecmds.c:2319
static void truncate_check_rel(Oid relid, Form_pg_class reltuple)
Definition: tablecmds.c:2271
#define ATT_INDEX
Definition: tablecmds.c:328
static void change_owner_recurse_to_sequences(Oid relationOid, Oid newOwnerId, LOCKMODE lockmode)
Definition: tablecmds.c:14620
static void StoreCatalogInheritance1(Oid relationId, Oid parentOid, int32 seqNumber, Relation inhRelation, bool child_is_partition)
Definition: tablecmds.c:3402
static void RememberAllDependentForRebuilding(AlteredTableInfo *tab, AlterTableType subtype, Relation rel, AttrNumber attnum, const char *colName)
Definition: tablecmds.c:13324
static void ATPrepDropExpression(Relation rel, AlterTableCmd *cmd, bool recurse, bool recursing, LOCKMODE lockmode)
Definition: tablecmds.c:8448
static ObjectAddress ATExecCookedColumnDefault(Relation rel, AttrNumber attnum, Node *newDefault)
Definition: tablecmds.c:7969
static void moveMergedTablesRows(Relation rel, List *mergingPartitionsList, Relation newPartRel)
Definition: tablecmds.c:20547
static ObjectAddress rename_constraint_internal(Oid myrelid, Oid mytypid, const char *oldconname, const char *newconname, bool recurse, bool recursing, int expected_parents)
Definition: tablecmds.c:3881
static void DropErrorMsgNonExistent(RangeVar *rel, char rightkind, bool missing_ok)
Definition: tablecmds.c:1362
static void ATPostAlterTypeCleanup(List **wqueue, AlteredTableInfo *tab, LOCKMODE lockmode)
Definition: tablecmds.c:13701
static bool tryAttachPartitionForeignKey(ForeignKeyCacheInfo *fk, Oid partRelid, Oid parentConstrOid, int numfks, AttrNumber *mapped_conkey, AttrNumber *confkey, Oid *conpfeqop, Oid parentInsTrigger, Oid parentUpdTrigger, Relation trigrel)
Definition: tablecmds.c:11017
static void ATExecMergePartitions(List **wqueue, AlteredTableInfo *tab, Relation rel, PartitionCmd *cmd, AlterTableUtilityContext *context)
Definition: tablecmds.c:20644
static AlterTableCmd * ATParseTransformCmd(List **wqueue, AlteredTableInfo *tab, Relation rel, AlterTableCmd *cmd, bool recurse, LOCKMODE lockmode, AlterTablePass cur_pass, AlterTableUtilityContext *context)
Definition: tablecmds.c:5564
void AlterTableNamespaceInternal(Relation rel, Oid oldNspOid, Oid nspOid, ObjectAddresses *objsMoved)
Definition: tablecmds.c:17115
static void CloneFkReferenced(Relation parentRel, Relation partitionRel)
Definition: tablecmds.c:10544
static void MergeConstraintsIntoExisting(Relation child_rel, Relation parent_rel)
Definition: tablecmds.c:15853
static void ATPrepDropColumn(List **wqueue, Relation rel, bool recurse, bool recursing, AlterTableCmd *cmd, LOCKMODE lockmode, AlterTableUtilityContext *context)
Definition: tablecmds.c:8925
void SetRelationHasSubclass(Oid relationId, bool relhassubclass)
Definition: tablecmds.c:3484
static void MergeChildAttribute(List *inh_columns, int exist_attno, int newcol_attno, const ColumnDef *newdef)
Definition: tablecmds.c:3087
static void ATSimplePermissions(AlterTableType cmdtype, Relation rel, int allowed_targets)
Definition: tablecmds.c:6544
static List * MergeCheckConstraint(List *constraints, const char *name, Node *expr)
Definition: tablecmds.c:3021
static void ATExecSetRelOptions(Relation rel, List *defList, AlterTableType operation, LOCKMODE lockmode)
Definition: tablecmds.c:14887
static ObjectAddress ATExecSetIdentity(Relation rel, const char *colName, Node *def, LOCKMODE lockmode, bool recurse, bool recursing)
Definition: tablecmds.c:8104
ObjectAddress AlterTableNamespace(AlterObjectSchemaStmt *stmt, Oid *oldschema)
Definition: tablecmds.c:17044
static void RememberConstraintForRebuilding(Oid conoid, AlteredTableInfo *tab)
Definition: tablecmds.c:13581
void ExecuteTruncate(TruncateStmt *stmt)
Definition: tablecmds.c:1760
static bool ATPrepChangePersistence(Relation rel, bool toLogged)
Definition: tablecmds.c:16925
static void relation_mark_replica_identity(Relation rel, char ri_type, Oid indexOid, bool is_internal)
Definition: tablecmds.c:16509
#define ATT_FOREIGN_TABLE
Definition: tablecmds.c:330
static ObjectAddress ATExecAlterConstraint(Relation rel, AlterTableCmd *cmd, bool recurse, bool recursing, LOCKMODE lockmode)
Definition: tablecmds.c:11287
static void ATPrepAddColumn(List **wqueue, Relation rel, bool recurse, bool recursing, bool is_view, AlterTableCmd *cmd, LOCKMODE lockmode, AlterTableUtilityContext *context)
Definition: tablecmds.c:6996
static void ComputePartitionAttrs(ParseState *pstate, Relation rel, List *partParams, AttrNumber *partattrs, List **partexprs, Oid *partopclass, Oid *partcollation, PartitionStrategy strategy)
Definition: tablecmds.c:17876
static void CloneRowTriggersToPartition(Relation parent, Relation partition)
Definition: tablecmds.c:18830
static void AttachPartitionEnsureIndexes(List **wqueue, Relation rel, Relation attachrel)
Definition: tablecmds.c:18649
static void StoreCatalogInheritance(Oid relationId, List *supers, bool child_is_partition)
Definition: tablecmds.c:3358
static ObjectAddress ATAddCheckConstraint(List **wqueue, AlteredTableInfo *tab, Relation rel, Constraint *constr, bool recurse, bool recursing, bool is_readd, LOCKMODE lockmode)
Definition: tablecmds.c:9445
static void ATExecGenericOptions(Relation rel, List *options)
Definition: tablecmds.c:16764
static void TryReuseForeignKey(Oid oldId, Constraint *con)
Definition: tablecmds.c:14157
struct AlteredTableInfo AlteredTableInfo
static void validateFkOnDeleteSetColumns(int numfks, const int16 *fkattnums, int numfksetcols, const int16 *fksetcolsattnums, List *fksetcols)
Definition: tablecmds.c:10007
Oid AlterTableLookupRelation(AlterTableStmt *stmt, LOCKMODE lockmode)
Definition: tablecmds.c:4303
struct NewConstraint NewConstraint
static ObjectAddress ATExecSetStatistics(Relation rel, const char *colName, int16 colNum, Node *newValue, LOCKMODE lockmode)
Definition: tablecmds.c:8585
static void ATSimpleRecursion(List **wqueue, Relation rel, AlterTableCmd *cmd, bool recurse, LOCKMODE lockmode, AlterTableUtilityContext *context)
Definition: tablecmds.c:6619
static void DetachPartitionFinalize(Relation rel, Relation partRel, bool concurrent, Oid defaultPartOid)
Definition: tablecmds.c:19158
static Relation createPartitionTable(RangeVar *newPartName, Relation modelRel, AlterTableUtilityContext *context)
Definition: tablecmds.c:20325
static void RebuildConstraintComment(AlteredTableInfo *tab, AlterTablePass pass, Oid objid, Relation rel, List *domname, const char *conname)
Definition: tablecmds.c:14085
static void CloneForeignKeyConstraints(List **wqueue, Relation parentRel, Relation partitionRel)
Definition: tablecmds.c:10513
static bool check_for_column_name_collision(Relation rel, const char *colname, bool if_not_exists)
Definition: tablecmds.c:7413
static ObjectAddress ATExecAddColumn(List **wqueue, AlteredTableInfo *tab, Relation rel, AlterTableCmd **cmd, bool recurse, bool recursing, LOCKMODE lockmode, AlterTablePass cur_pass, AlterTableUtilityContext *context)
Definition: tablecmds.c:7020
AlterTablePass
Definition: tablecmds.c:147
@ AT_PASS_ADD_CONSTR
Definition: tablecmds.c:156
@ AT_PASS_ADD_OTHERCONSTR
Definition: tablecmds.c:160
@ AT_PASS_OLD_CONSTR
Definition: tablecmds.c:154
@ AT_PASS_ADD_COL
Definition: tablecmds.c:151
@ AT_PASS_OLD_INDEX
Definition: tablecmds.c:153
@ AT_PASS_ALTER_TYPE
Definition: tablecmds.c:150
@ AT_PASS_ADD_INDEXCONSTR
Definition: tablecmds.c:158
@ AT_PASS_DROP
Definition: tablecmds.c:149
@ AT_PASS_MISC
Definition: tablecmds.c:161
@ AT_PASS_COL_ATTRS
Definition: tablecmds.c:157
@ AT_PASS_SET_EXPRESSION
Definition: tablecmds.c:152
@ AT_PASS_ADD_INDEX
Definition: tablecmds.c:159
@ AT_PASS_UNSET
Definition: tablecmds.c:148
static ObjectAddress ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel, AlterTableCmd *cmd, LOCKMODE lockmode)
Definition: tablecmds.c:13007
void SetRelationTableSpace(Relation rel, Oid newTableSpaceId, RelFileNumber newRelFilenumber)
Definition: tablecmds.c:3587
void remove_on_commit_action(Oid relid)
Definition: tablecmds.c:17388
static void DetachAddConstraintIfNeeded(List **wqueue, Relation partRel)
Definition: tablecmds.c:19441
static void ATExecDropCluster(Relation rel, LOCKMODE lockmode)
Definition: tablecmds.c:14721
#define ATT_PARTITIONED_INDEX
Definition: tablecmds.c:331
static void CreateInheritance(Relation child_rel, Relation parent_rel, bool ispartition)
Definition: tablecmds.c:15610
static void addFkRecurseReferencing(List **wqueue, Constraint *fkconstraint, Relation rel, Relation pkrel, Oid indexOid, Oid parentConstr, int numfks, int16 *pkattnum, int16 *fkattnum, Oid *pfeqoperators, Oid *ppeqoperators, Oid *ffeqoperators, int numfkdelsetcols, int16 *fkdelsetcols, bool old_check_ok, LOCKMODE lockmode, Oid parentInsTrigger, Oid parentUpdTrigger)
Definition: tablecmds.c:10289
static const struct dropmsgstrings dropmsgstringarray[]
Definition: tablecmds.c:252
static ObjectAddress ATExecSetExpression(AlteredTableInfo *tab, Relation rel, const char *colName, Node *newExpr, LOCKMODE lockmode)
Definition: tablecmds.c:8335
ObjectAddress DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId, ObjectAddress *typaddress, const char *queryString)
Definition: tablecmds.c:686
static Oid CreateFKCheckTrigger(Oid myRelOid, Oid refRelOid, Constraint *fkconstraint, Oid constraintOid, Oid indexOid, Oid parentTrigOid, bool on_insert)
Definition: tablecmds.c:12210
static SplitPartitionContext * createSplitPartitionContext(Relation partRel)
Definition: tablecmds.c:20078
static void DropClonedTriggersFromPartition(Oid partitionId)
Definition: tablecmds.c:19482
static void QueuePartitionConstraintValidation(List **wqueue, Relation scanrel, List *partConstraint, bool validate_default)
Definition: tablecmds.c:18244
static ObjectAddress ATExecAddOf(Relation rel, const TypeName *ofTypename, LOCKMODE lockmode)
Definition: tablecmds.c:16323
static void RangeVarCallbackForDropRelation(const RangeVar *rel, Oid relOid, Oid oldRelOid, void *arg)
Definition: tablecmds.c:1601
void AlterTableInternal(Oid relid, List *cmds, bool recurse)
Definition: tablecmds.c:4391
static void GetForeignKeyActionTriggers(Relation trigrel, Oid conoid, Oid confrelid, Oid conrelid, Oid *deleteTriggerOid, Oid *updateTriggerOid)
Definition: tablecmds.c:11160
void check_of_type(HeapTuple typetuple)
Definition: tablecmds.c:6946
static ObjectAddress ATExecDropInherit(Relation rel, RangeVar *parent, LOCKMODE lockmode)
Definition: tablecmds.c:15978
static void ATDetachCheckNoForeignKeyRefs(Relation partition)
Definition: tablecmds.c:19941
static ObjectAddress ATExecAddIndexConstraint(AlteredTableInfo *tab, Relation rel, IndexStmt *stmt, LOCKMODE lockmode)
Definition: tablecmds.c:9238
#define ATT_VIEW
Definition: tablecmds.c:326
static void AlterIndexNamespaces(Relation classRel, Relation rel, Oid oldNspOid, Oid newNspOid, ObjectAddresses *objsMoved)
Definition: tablecmds.c:17222
static char * decompile_conbin(HeapTuple contup, TupleDesc tupdesc)
Definition: tablecmds.c:15679
static void ATExecCmd(List **wqueue, AlteredTableInfo *tab, AlterTableCmd *cmd, LOCKMODE lockmode, AlterTablePass cur_pass, AlterTableUtilityContext *context)
Definition: tablecmds.c:5213
static void ATExecReplicaIdentity(Relation rel, ReplicaIdentityStmt *stmt, LOCKMODE lockmode)
Definition: tablecmds.c:16597
static void createForeignKeyCheckTriggers(Oid myRelOid, Oid refRelOid, Constraint *fkconstraint, Oid constraintOid, Oid indexOid, Oid parentInsTrigger, Oid parentUpdTrigger, Oid *insertTrigOid, Oid *updateTrigOid)
Definition: tablecmds.c:12408
static void ATPrepAddInherit(Relation child_rel)
Definition: tablecmds.c:15476
static ObjectAddress ATExecDetachPartitionFinalize(Relation rel, RangeVar *name)
Definition: tablecmds.c:19406
static ObjectAddress ATExecSetStorage(Relation rel, const char *colName, Node *newValue, LOCKMODE lockmode)
Definition: tablecmds.c:8862
static ObjectAddress ATExecAttachPartition(List **wqueue, Relation rel, PartitionCmd *cmd, AlterTableUtilityContext *context)
Definition: tablecmds.c:18348
static List * find_typed_table_dependencies(Oid typeOid, const char *typeName, DropBehavior behavior)
Definition: tablecmds.c:6897
Oid AlterTableMoveAll(AlterTableMoveAllStmt *stmt)
Definition: tablecmds.c:15222
static ObjectAddress ATExecAddIdentity(Relation rel, const char *colName, Node *def, LOCKMODE lockmode, bool recurse, bool recursing)
Definition: tablecmds.c:7998
static void ATExecSetAccessMethodNoStorage(Relation rel, Oid newAccessMethodId)
Definition: tablecmds.c:14767
static ObjectAddress ATExecAddIndex(AlteredTableInfo *tab, Relation rel, IndexStmt *stmt, bool is_rebuild, LOCKMODE lockmode)
Definition: tablecmds.c:9154
static ObjectAddress ATExecSetCompression(Relation rel, const char *column, Node *newValue, LOCKMODE lockmode)
Definition: tablecmds.c:16845
static PartitionSpec * transformPartitionSpec(Relation rel, PartitionSpec *partspec)
Definition: tablecmds.c:17818
static void ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd, bool recurse, bool recursing, LOCKMODE lockmode, AlterTableUtilityContext *context)
Definition: tablecmds.c:4750
static void ATRewriteTable(AlteredTableInfo *tab, Oid OIDNewHeap, LOCKMODE lockmode)
Definition: tablecmds.c:5985
static void index_copy_data(Relation rel, RelFileLocator newrlocator)
Definition: tablecmds.c:15384
void RenameRelationInternal(Oid myrelid, const char *newrelname, bool is_internal, bool is_index)
Definition: tablecmds.c:4101
static void ATExecSetTableSpaceNoStorage(Relation rel, Oid newTableSpace)
Definition: tablecmds.c:15183
static void ATPrepAlterColumnType(List **wqueue, AlteredTableInfo *tab, Relation rel, bool recurse, bool recursing, AlterTableCmd *cmd, LOCKMODE lockmode, AlterTableUtilityContext *context)
Definition: tablecmds.c:12679
static void deleteSplitPartitionContext(SplitPartitionContext *pc, int ti_options)
Definition: tablecmds.c:20103
static void change_owner_fix_column_acls(Oid relationOid, Oid oldOwnerId, Oid newOwnerId)
Definition: tablecmds.c:14555
#define ATT_COMPOSITE_TYPE
Definition: tablecmds.c:329
static ObjectAddress ATExecAttachPartitionIdx(List **wqueue, Relation parentIdx, RangeVar *name)
Definition: tablecmds.c:19609
bool PartConstraintImpliedByRelConstraint(Relation scanrel, List *partConstraint)
Definition: tablecmds.c:18134
void RangeVarCallbackMaintainsTable(const RangeVar *relation, Oid relId, Oid oldRelId, void *arg)
Definition: tablecmds.c:17585
static void ATExecSplitPartition(List **wqueue, AlteredTableInfo *tab, Relation rel, PartitionCmd *cmd, AlterTableUtilityContext *context)
Definition: tablecmds.c:20419
static const char * alter_table_type_to_string(AlterTableType cmdtype)
Definition: tablecmds.c:6395
static ObjectAddress addFkRecurseReferenced(List **wqueue, Constraint *fkconstraint, Relation rel, Relation pkrel, Oid indexOid, Oid parentConstr, int numfks, int16 *pkattnum, int16 *fkattnum, Oid *pfeqoperators, Oid *ppeqoperators, Oid *ffeqoperators, int numfkdelsetcols, int16 *fkdelsetcols, bool old_check_ok, Oid parentDelTrigger, Oid parentUpdTrigger)
Definition: tablecmds.c:10069
static List * on_commits
Definition: tablecmds.c:129
static bool constraints_equivalent(HeapTuple a, HeapTuple b, TupleDesc tupleDesc)
Definition: tablecmds.c:15704
static ObjectAddress ATExecAddStatistics(AlteredTableInfo *tab, Relation rel, CreateStatsStmt *stmt, bool is_rebuild, LOCKMODE lockmode)
Definition: tablecmds.c:9217
ObjectAddress RenameConstraint(RenameStmt *stmt)
Definition: tablecmds.c:3987
static void ATRewriteTables(AlterTableStmt *parsetree, List **wqueue, LOCKMODE lockmode, AlterTableUtilityContext *context)
Definition: tablecmds.c:5699
void register_on_commit_action(Oid relid, OnCommitAction action)
Definition: tablecmds.c:17352
static void RangeVarCallbackForTruncate(const RangeVar *relation, Oid relId, Oid oldRelId, void *arg)
Definition: tablecmds.c:17621
static ObjectAddress ATExecClusterOn(Relation rel, const char *indexName, LOCKMODE lockmode)
Definition: tablecmds.c:14689
static char GetAttributeStorage(Oid atttypid, const char *storagemode)
Definition: tablecmds.c:20028
void RangeVarCallbackOwnsRelation(const RangeVar *relation, Oid relId, Oid oldRelId, void *arg)
Definition: tablecmds.c:17645
#define ATT_MATVIEW
Definition: tablecmds.c:327
#define child_dependency_type(child_is_partition)
Definition: tablecmds.c:353
static void refuseDupeIndexAttach(Relation parentIdx, Relation partIdx, Relation partitionTbl)
Definition: tablecmds.c:19764
void ExecuteTruncateGuts(List *explicit_rels, List *relids, List *relids_logged, DropBehavior behavior, bool restart_seqs, bool run_as_table_owner)
Definition: tablecmds.c:1884
static void ATExecEnableDisableRule(Relation rel, const char *rulename, char fires_when, LOCKMODE lockmode)
Definition: tablecmds.c:15459
struct NewColumnValue NewColumnValue
static void ATPrepSetAccessMethod(AlteredTableInfo *tab, Relation rel, const char *amname)
Definition: tablecmds.c:14733
static bool NotNullImpliedByRelConstraints(Relation rel, Form_pg_attribute attr)
Definition: tablecmds.c:7846
const char * GetCompressionMethodName(char method)
char CompressionNameToMethod(const char *compression)
#define CompressionMethodIsValid(cm)
#define InvalidCompressionMethod
void AlterTableCreateToastTable(Oid relOid, Datum reloptions, LOCKMODE lockmode)
Definition: toasting.c:57
void ExecBSTruncateTriggers(EState *estate, ResultRelInfo *relinfo)
Definition: trigger.c:3222
void EnableDisableTrigger(Relation rel, const char *tgname, Oid tgparent, char fires_when, bool skip_system, bool recurse, LOCKMODE lockmode)
Definition: trigger.c:1721
void ExecASTruncateTriggers(EState *estate, ResultRelInfo *relinfo)
Definition: trigger.c:3269
const char * FindTriggerIncompatibleWithInheritance(TriggerDesc *trigdesc)
Definition: trigger.c:2272
ObjectAddress CreateTrigger(CreateTrigStmt *stmt, const char *queryString, Oid relOid, Oid refRelOid, Oid constraintOid, Oid indexOid, Oid funcoid, Oid parentTriggerOid, Node *whenClause, bool isInternal, bool in_partition)
Definition: trigger.c:158
void TriggerSetParentTrigger(Relation trigRel, Oid childTrigId, Oid parentTrigId, Oid childTableId)
Definition: trigger.c:1215
ObjectAddress CreateTriggerFiringOn(CreateTrigStmt *stmt, const char *queryString, Oid relOid, Oid refRelOid, Oid constraintOid, Oid indexOid, Oid funcoid, Oid parentTriggerOid, Node *whenClause, bool isInternal, bool in_partition, char trigger_fires_when)
Definition: trigger.c:175
bool AfterTriggerPendingOnRel(Oid relid)
Definition: trigger.c:5976
void AfterTriggerEndQuery(EState *estate)
Definition: trigger.c:5040
void AfterTriggerBeginQuery(void)
Definition: trigger.c:5020
#define RI_TRIGGER_FK
Definition: trigger.h:283
#define TRIGGER_FIRES_ON_ORIGIN
Definition: trigger.h:149
#define TRIGGER_DISABLED
Definition: trigger.h:152
#define TRIGGER_FIRES_ON_REPLICA
Definition: trigger.h:151
#define TRIGGER_EVENT_ROW
Definition: trigger.h:98
#define TRIGGER_FIRES_ALWAYS
Definition: trigger.h:150
#define TRIGGER_EVENT_INSERT
Definition: trigger.h:92
#define RI_TRIGGER_PK
Definition: trigger.h:282
TupleTableSlot * execute_attr_map_slot(AttrMap *attrMap, TupleTableSlot *in_slot, TupleTableSlot *out_slot)
Definition: tupconvert.c:192
void free_conversion_map(TupleConversionMap *map)
Definition: tupconvert.c:299
TupleConversionMap * convert_tuples_by_name(TupleDesc indesc, TupleDesc outdesc)
Definition: tupconvert.c:102
TupleDesc CreateTupleDescCopyConstr(TupleDesc tupdesc)
Definition: tupdesc.c:173
TupleDesc CreateTemplateTupleDesc(int natts)
Definition: tupdesc.c:67
Node * TupleDescGetDefault(TupleDesc tupdesc, AttrNumber attnum)
Definition: tupdesc.c:899
void TupleDescInitEntryCollation(TupleDesc desc, AttrNumber attributeNumber, Oid collationid)
Definition: tupdesc.c:833
void TupleDescInitEntry(TupleDesc desc, AttrNumber attributeNumber, const char *attributeName, Oid oidtypeid, int32 typmod, int attdim)
Definition: tupdesc.c:651
#define ReleaseTupleDesc(tupdesc)
Definition: tupdesc.h:122
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92
static TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: tuptable.h:454
static void slot_getallattrs(TupleTableSlot *slot)
Definition: tuptable.h:368
static bool slot_attisnull(TupleTableSlot *slot, int attnum)
Definition: tuptable.h:381
TupleDesc lookup_rowtype_tupdesc(Oid type_id, int32 typmod)
Definition: typcache.c:1833
bool DomainHasConstraints(Oid type_id)
Definition: typcache.c:1400
void AlterTypeOwnerInternal(Oid typeOid, Oid newOwnerId)
Definition: typecmds.c:3987
ObjectAddress AlterDomainAddConstraint(List *names, Node *newConstraint, ObjectAddress *constrAddr)
Definition: typecmds.c:2897
void checkDomainOwner(HeapTuple tup)
Definition: typecmds.c:3490
Oid AlterTypeNamespaceInternal(Oid typeOid, Oid nspOid, bool isImplicitArray, bool ignoreDependent, bool errorOnTableType, ObjectAddresses *objsMoved)
Definition: typecmds.c:4156
void SwitchToUntrustedUser(Oid userid, UserContext *context)
Definition: usercontext.c:33
void RestoreUserContext(UserContext *context)
Definition: usercontext.c:87
void ProcessUtility(PlannedStmt *pstmt, const char *queryString, bool readOnlyTree, ProcessUtilityContext context, ParamListInfo params, QueryEnvironment *queryEnv, DestReceiver *dest, QueryCompletion *qc)
Definition: utility.c:499
void ProcessUtilityForAlterTable(Node *stmt, AlterTableUtilityContext *context)
Definition: utility.c:1956
@ PROCESS_UTILITY_SUBCOMMAND
Definition: utility.h:26
#define MAX_STATISTICS_TARGET
Definition: vacuum.h:305
String * makeString(char *str)
Definition: value.c:63
#define intVal(v)
Definition: value.h:79
#define strVal(v)
Definition: value.h:82
void pull_varattnos(Node *node, Index varno, Bitmapset **varattnos)
Definition: var.c:291
#define VARDATA_ANY(PTR)
Definition: varatt.h:324
const char * name
SubTransactionId GetCurrentSubTransactionId(void)
Definition: xact.c:789
void CommandCounterIncrement(void)
Definition: xact.c:1098
void StartTransactionCommand(void)
Definition: xact.c:3033
void CommitTransactionCommand(void)
Definition: xact.c:3131
int MyXactFlags
Definition: xact.c:134
CommandId GetCurrentCommandId(bool used)
Definition: xact.c:827
#define XACT_FLAGS_ACCESSEDTEMPNAMESPACE
Definition: xact.h:102
#define XLogLogicalInfoActive()
Definition: xlog.h:126
#define XLOG_INCLUDE_ORIGIN
Definition: xlog.h:154
void XLogRegisterData(char *data, uint32 len)
Definition: xloginsert.c:364
XLogRecPtr XLogInsert(RmgrId rmid, uint8 info)
Definition: xloginsert.c:474
void XLogSetRecordFlags(uint8 flags)
Definition: xloginsert.c:456
void XLogBeginInsert(void)
Definition: xloginsert.c:149