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/gist.h"
20 #include "access/heapam.h"
21 #include "access/heapam_xlog.h"
22 #include "access/multixact.h"
23 #include "access/reloptions.h"
24 #include "access/relscan.h"
25 #include "access/sysattr.h"
26 #include "access/tableam.h"
28 #include "access/xact.h"
29 #include "access/xlog.h"
30 #include "access/xloginsert.h"
31 #include "catalog/catalog.h"
32 #include "catalog/heap.h"
33 #include "catalog/index.h"
34 #include "catalog/namespace.h"
35 #include "catalog/objectaccess.h"
36 #include "catalog/partition.h"
37 #include "catalog/pg_am.h"
38 #include "catalog/pg_attrdef.h"
39 #include "catalog/pg_collation.h"
40 #include "catalog/pg_constraint.h"
41 #include "catalog/pg_depend.h"
43 #include "catalog/pg_inherits.h"
44 #include "catalog/pg_largeobject.h"
45 #include "catalog/pg_namespace.h"
46 #include "catalog/pg_opclass.h"
47 #include "catalog/pg_policy.h"
48 #include "catalog/pg_rewrite.h"
50 #include "catalog/pg_tablespace.h"
51 #include "catalog/pg_trigger.h"
52 #include "catalog/pg_type.h"
53 #include "catalog/storage.h"
54 #include "catalog/storage_xlog.h"
55 #include "catalog/toasting.h"
56 #include "commands/cluster.h"
57 #include "commands/comment.h"
58 #include "commands/defrem.h"
59 #include "commands/event_trigger.h"
60 #include "commands/sequence.h"
61 #include "commands/tablecmds.h"
62 #include "commands/tablespace.h"
63 #include "commands/trigger.h"
64 #include "commands/typecmds.h"
65 #include "commands/user.h"
66 #include "commands/vacuum.h"
67 #include "executor/executor.h"
68 #include "foreign/fdwapi.h"
69 #include "foreign/foreign.h"
70 #include "miscadmin.h"
71 #include "nodes/makefuncs.h"
72 #include "nodes/nodeFuncs.h"
73 #include "nodes/parsenodes.h"
74 #include "optimizer/optimizer.h"
75 #include "parser/parse_coerce.h"
76 #include "parser/parse_collate.h"
77 #include "parser/parse_expr.h"
78 #include "parser/parse_relation.h"
79 #include "parser/parse_type.h"
80 #include "parser/parse_utilcmd.h"
81 #include "parser/parser.h"
83 #include "partitioning/partdesc.h"
84 #include "pgstat.h"
85 #include "rewrite/rewriteDefine.h"
86 #include "rewrite/rewriteHandler.h"
87 #include "rewrite/rewriteManip.h"
88 #include "storage/bufmgr.h"
89 #include "storage/lmgr.h"
90 #include "storage/lock.h"
91 #include "storage/predicate.h"
92 #include "storage/smgr.h"
93 #include "tcop/utility.h"
94 #include "utils/acl.h"
95 #include "utils/builtins.h"
96 #include "utils/fmgroids.h"
97 #include "utils/inval.h"
98 #include "utils/lsyscache.h"
99 #include "utils/memutils.h"
100 #include "utils/partcache.h"
101 #include "utils/relcache.h"
102 #include "utils/ruleutils.h"
103 #include "utils/snapmgr.h"
104 #include "utils/syscache.h"
105 #include "utils/timestamp.h"
106 #include "utils/typcache.h"
107 #include "utils/usercontext.h"
108 
109 /*
110  * ON COMMIT action list
111  */
112 typedef struct OnCommitItem
113 {
114  Oid relid; /* relid of relation */
115  OnCommitAction oncommit; /* what to do at end of xact */
116 
117  /*
118  * If this entry was created during the current transaction,
119  * creating_subid is the ID of the creating subxact; if created in a prior
120  * transaction, creating_subid is zero. If deleted during the current
121  * transaction, deleting_subid is the ID of the deleting subxact; if no
122  * deletion request is pending, deleting_subid is zero.
123  */
127 
128 static List *on_commits = NIL;
129 
130 
131 /*
132  * State information for ALTER TABLE
133  *
134  * The pending-work queue for an ALTER TABLE is a List of AlteredTableInfo
135  * structs, one for each table modified by the operation (the named table
136  * plus any child tables that are affected). We save lists of subcommands
137  * to apply to this table (possibly modified by parse transformation steps);
138  * these lists will be executed in Phase 2. If a Phase 3 step is needed,
139  * necessary information is stored in the constraints and newvals lists.
140  *
141  * Phase 2 is divided into multiple passes; subcommands are executed in
142  * a pass determined by subcommand type.
143  */
144 
145 typedef enum AlterTablePass
146 {
147  AT_PASS_UNSET = -1, /* UNSET will cause ERROR */
148  AT_PASS_DROP, /* DROP (all flavors) */
149  AT_PASS_ALTER_TYPE, /* ALTER COLUMN TYPE */
150  AT_PASS_ADD_COL, /* ADD COLUMN */
151  AT_PASS_SET_EXPRESSION, /* ALTER SET EXPRESSION */
152  AT_PASS_OLD_COL_ATTRS, /* re-install attnotnull */
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  bool conwithperiod; /* Whether the new FOREIGN KEY uses PERIOD */
219  Oid conid; /* OID of pg_constraint entry, if FOREIGN */
220  Node *qual; /* Check expr or CONSTR_FOREIGN Constraint */
221  ExprState *qualstate; /* Execution state for CHECK expr */
223 
224 /*
225  * Struct describing one new column value that needs to be computed during
226  * Phase 3 copy (this could be either a new column with a non-null default, or
227  * a column that we're changing the type of). Columns without such an entry
228  * are just copied from the old table during ATRewriteTable. Note that the
229  * expr is an expression over *old* table values, except when is_generated
230  * is true; then it is an expression over columns of the *new* tuple.
231  */
232 typedef struct NewColumnValue
233 {
234  AttrNumber attnum; /* which column */
235  Expr *expr; /* expression to compute */
236  ExprState *exprstate; /* execution state */
237  bool is_generated; /* is it a GENERATED expression? */
239 
240 /*
241  * Error-reporting support for RemoveRelations
242  */
244 {
245  char kind;
247  const char *nonexistent_msg;
248  const char *skipping_msg;
249  const char *nota_msg;
250  const char *drophint_msg;
251 };
252 
253 static const struct dropmsgstrings dropmsgstringarray[] = {
254  {RELKIND_RELATION,
256  gettext_noop("table \"%s\" does not exist"),
257  gettext_noop("table \"%s\" does not exist, skipping"),
258  gettext_noop("\"%s\" is not a table"),
259  gettext_noop("Use DROP TABLE to remove a table.")},
260  {RELKIND_SEQUENCE,
262  gettext_noop("sequence \"%s\" does not exist"),
263  gettext_noop("sequence \"%s\" does not exist, skipping"),
264  gettext_noop("\"%s\" is not a sequence"),
265  gettext_noop("Use DROP SEQUENCE to remove a sequence.")},
266  {RELKIND_VIEW,
268  gettext_noop("view \"%s\" does not exist"),
269  gettext_noop("view \"%s\" does not exist, skipping"),
270  gettext_noop("\"%s\" is not a view"),
271  gettext_noop("Use DROP VIEW to remove a view.")},
272  {RELKIND_MATVIEW,
274  gettext_noop("materialized view \"%s\" does not exist"),
275  gettext_noop("materialized view \"%s\" does not exist, skipping"),
276  gettext_noop("\"%s\" is not a materialized view"),
277  gettext_noop("Use DROP MATERIALIZED VIEW to remove a materialized view.")},
278  {RELKIND_INDEX,
279  ERRCODE_UNDEFINED_OBJECT,
280  gettext_noop("index \"%s\" does not exist"),
281  gettext_noop("index \"%s\" does not exist, skipping"),
282  gettext_noop("\"%s\" is not an index"),
283  gettext_noop("Use DROP INDEX to remove an index.")},
284  {RELKIND_COMPOSITE_TYPE,
285  ERRCODE_UNDEFINED_OBJECT,
286  gettext_noop("type \"%s\" does not exist"),
287  gettext_noop("type \"%s\" does not exist, skipping"),
288  gettext_noop("\"%s\" is not a type"),
289  gettext_noop("Use DROP TYPE to remove a type.")},
290  {RELKIND_FOREIGN_TABLE,
291  ERRCODE_UNDEFINED_OBJECT,
292  gettext_noop("foreign table \"%s\" does not exist"),
293  gettext_noop("foreign table \"%s\" does not exist, skipping"),
294  gettext_noop("\"%s\" is not a foreign table"),
295  gettext_noop("Use DROP FOREIGN TABLE to remove a foreign table.")},
296  {RELKIND_PARTITIONED_TABLE,
298  gettext_noop("table \"%s\" does not exist"),
299  gettext_noop("table \"%s\" does not exist, skipping"),
300  gettext_noop("\"%s\" is not a table"),
301  gettext_noop("Use DROP TABLE to remove a table.")},
302  {RELKIND_PARTITIONED_INDEX,
303  ERRCODE_UNDEFINED_OBJECT,
304  gettext_noop("index \"%s\" does not exist"),
305  gettext_noop("index \"%s\" does not exist, skipping"),
306  gettext_noop("\"%s\" is not an index"),
307  gettext_noop("Use DROP INDEX to remove an index.")},
308  {'\0', 0, NULL, NULL, NULL, NULL}
309 };
310 
311 /* communication between RemoveRelations and RangeVarCallbackForDropRelation */
313 {
314  /* These fields are set by RemoveRelations: */
317  /* These fields are state to track which subsidiary locks are held: */
320  /* These fields are passed back by RangeVarCallbackForDropRelation: */
323 };
324 
325 /* Alter table target-type flags for ATSimplePermissions */
326 #define ATT_TABLE 0x0001
327 #define ATT_VIEW 0x0002
328 #define ATT_MATVIEW 0x0004
329 #define ATT_INDEX 0x0008
330 #define ATT_COMPOSITE_TYPE 0x0010
331 #define ATT_FOREIGN_TABLE 0x0020
332 #define ATT_PARTITIONED_INDEX 0x0040
333 #define ATT_SEQUENCE 0x0080
334 
335 /*
336  * ForeignTruncateInfo
337  *
338  * Information related to truncation of foreign tables. This is used for
339  * the elements in a hash table. It uses the server OID as lookup key,
340  * and includes a per-server list of all foreign tables involved in the
341  * truncation.
342  */
343 typedef struct ForeignTruncateInfo
344 {
348 
349 /*
350  * Partition tables are expected to be dropped when the parent partitioned
351  * table gets dropped. Hence for partitioning we use AUTO dependency.
352  * Otherwise, for regular inheritance use NORMAL dependency.
353  */
354 #define child_dependency_type(child_is_partition) \
355  ((child_is_partition) ? DEPENDENCY_AUTO : DEPENDENCY_NORMAL)
356 
357 static void truncate_check_rel(Oid relid, Form_pg_class reltuple);
358 static void truncate_check_perms(Oid relid, Form_pg_class reltuple);
359 static void truncate_check_activity(Relation rel);
360 static void RangeVarCallbackForTruncate(const RangeVar *relation,
361  Oid relId, Oid oldRelId, void *arg);
362 static List *MergeAttributes(List *columns, const List *supers, char relpersistence,
363  bool is_partition, List **supconstr,
364  List **supnotnulls);
365 static List *MergeCheckConstraint(List *constraints, const char *name, Node *expr);
366 static void MergeChildAttribute(List *inh_columns, int exist_attno, int newcol_attno, const ColumnDef *newdef);
367 static ColumnDef *MergeInheritedAttribute(List *inh_columns, int exist_attno, const ColumnDef *newdef);
368 static void MergeAttributesIntoExisting(Relation child_rel, Relation parent_rel, bool ispartition);
369 static void MergeConstraintsIntoExisting(Relation child_rel, Relation parent_rel);
370 static void StoreCatalogInheritance(Oid relationId, List *supers,
371  bool child_is_partition);
372 static void StoreCatalogInheritance1(Oid relationId, Oid parentOid,
373  int32 seqNumber, Relation inhRelation,
374  bool child_is_partition);
375 static int findAttrByName(const char *attributeName, const List *columns);
376 static void AlterIndexNamespaces(Relation classRel, Relation rel,
377  Oid oldNspOid, Oid newNspOid, ObjectAddresses *objsMoved);
378 static void AlterSeqNamespaces(Relation classRel, Relation rel,
379  Oid oldNspOid, Oid newNspOid, ObjectAddresses *objsMoved,
380  LOCKMODE lockmode);
382  bool recurse, bool recursing, LOCKMODE lockmode);
383 static bool ATExecAlterConstrRecurse(Constraint *cmdcon, Relation conrel, Relation tgrel,
384  Relation rel, HeapTuple contuple, List **otherrelids,
385  LOCKMODE lockmode);
387  Relation rel, char *constrName,
388  bool recurse, bool recursing, LOCKMODE lockmode);
389 static int transformColumnNameList(Oid relId, List *colList,
390  int16 *attnums, Oid *atttypids);
391 static int transformFkeyGetPrimaryKey(Relation pkrel, Oid *indexOid,
392  List **attnamelist,
393  int16 *attnums, Oid *atttypids,
394  Oid *opclasses, bool *pk_has_without_overlaps);
396  int numattrs, int16 *attnums,
397  bool with_period, Oid *opclasses,
398  bool *pk_has_without_overlaps);
399 static void checkFkeyPermissions(Relation rel, int16 *attnums, int natts);
400 static CoercionPathType findFkeyCast(Oid targetTypeId, Oid sourceTypeId,
401  Oid *funcid);
402 static void validateForeignKeyConstraint(char *conname,
403  Relation rel, Relation pkrel,
404  Oid pkindOid, Oid constraintOid, bool hasperiod);
405 static void ATController(AlterTableStmt *parsetree,
406  Relation rel, List *cmds, bool recurse, LOCKMODE lockmode,
408 static void ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd,
409  bool recurse, bool recursing, LOCKMODE lockmode,
411 static void ATRewriteCatalogs(List **wqueue, LOCKMODE lockmode,
413 static void ATExecCmd(List **wqueue, AlteredTableInfo *tab,
414  AlterTableCmd *cmd, LOCKMODE lockmode, AlterTablePass cur_pass,
417  Relation rel, AlterTableCmd *cmd,
418  bool recurse, LOCKMODE lockmode,
419  AlterTablePass cur_pass,
421 static void ATRewriteTables(AlterTableStmt *parsetree,
422  List **wqueue, LOCKMODE lockmode,
424 static void ATRewriteTable(AlteredTableInfo *tab, Oid OIDNewHeap, LOCKMODE lockmode);
425 static AlteredTableInfo *ATGetQueueEntry(List **wqueue, Relation rel);
426 static void ATSimplePermissions(AlterTableType cmdtype, Relation rel, int allowed_targets);
427 static void ATSimpleRecursion(List **wqueue, Relation rel,
428  AlterTableCmd *cmd, bool recurse, LOCKMODE lockmode,
430 static void ATCheckPartitionsNotInUse(Relation rel, LOCKMODE lockmode);
431 static void ATTypedTableRecursion(List **wqueue, Relation rel, AlterTableCmd *cmd,
432  LOCKMODE lockmode,
434 static List *find_typed_table_dependencies(Oid typeOid, const char *typeName,
435  DropBehavior behavior);
436 static void ATPrepAddColumn(List **wqueue, Relation rel, bool recurse, bool recursing,
437  bool is_view, AlterTableCmd *cmd, LOCKMODE lockmode,
439 static ObjectAddress ATExecAddColumn(List **wqueue, AlteredTableInfo *tab,
440  Relation rel, AlterTableCmd **cmd,
441  bool recurse, bool recursing,
442  LOCKMODE lockmode, AlterTablePass cur_pass,
444 static bool check_for_column_name_collision(Relation rel, const char *colname,
445  bool if_not_exists);
446 static void add_column_datatype_dependency(Oid relid, int32 attnum, Oid typid);
448 static ObjectAddress ATExecDropNotNull(Relation rel, const char *colName, bool recurse,
449  LOCKMODE lockmode);
450 static bool set_attnotnull(List **wqueue, Relation rel,
451  AttrNumber attnum, bool recurse, LOCKMODE lockmode);
452 static ObjectAddress ATExecSetNotNull(List **wqueue, Relation rel,
453  char *constrname, char *colName,
454  bool recurse, bool recursing,
455  List **readyRels, LOCKMODE lockmode);
456 static ObjectAddress ATExecSetAttNotNull(List **wqueue, Relation rel,
457  const char *colName, LOCKMODE lockmode);
459 static bool ConstraintImpliedByRelConstraint(Relation scanrel,
460  List *testConstraint, List *provenConstraint);
461 static ObjectAddress ATExecColumnDefault(Relation rel, const char *colName,
462  Node *newDefault, LOCKMODE lockmode);
464  Node *newDefault);
465 static ObjectAddress ATExecAddIdentity(Relation rel, const char *colName,
466  Node *def, LOCKMODE lockmode, bool recurse, bool recursing);
467 static ObjectAddress ATExecSetIdentity(Relation rel, const char *colName,
468  Node *def, LOCKMODE lockmode, bool recurse, bool recursing);
469 static ObjectAddress ATExecDropIdentity(Relation rel, const char *colName, bool missing_ok, LOCKMODE lockmode,
470  bool recurse, bool recursing);
471 static ObjectAddress ATExecSetExpression(AlteredTableInfo *tab, Relation rel, const char *colName,
472  Node *newExpr, LOCKMODE lockmode);
473 static void ATPrepDropExpression(Relation rel, AlterTableCmd *cmd, bool recurse, bool recursing, LOCKMODE lockmode);
474 static ObjectAddress ATExecDropExpression(Relation rel, const char *colName, bool missing_ok, LOCKMODE lockmode);
475 static ObjectAddress ATExecSetStatistics(Relation rel, const char *colName, int16 colNum,
476  Node *newValue, LOCKMODE lockmode);
477 static ObjectAddress ATExecSetOptions(Relation rel, const char *colName,
478  Node *options, bool isReset, LOCKMODE lockmode);
479 static ObjectAddress ATExecSetStorage(Relation rel, const char *colName,
480  Node *newValue, LOCKMODE lockmode);
481 static void ATPrepDropColumn(List **wqueue, Relation rel, bool recurse, bool recursing,
482  AlterTableCmd *cmd, LOCKMODE lockmode,
484 static ObjectAddress ATExecDropColumn(List **wqueue, Relation rel, const char *colName,
485  DropBehavior behavior,
486  bool recurse, bool recursing,
487  bool missing_ok, LOCKMODE lockmode,
488  ObjectAddresses *addrs);
489 static void ATPrepAddPrimaryKey(List **wqueue, Relation rel, AlterTableCmd *cmd,
492  IndexStmt *stmt, bool is_rebuild, LOCKMODE lockmode);
494  CreateStatsStmt *stmt, bool is_rebuild, LOCKMODE lockmode);
495 static ObjectAddress ATExecAddConstraint(List **wqueue,
496  AlteredTableInfo *tab, Relation rel,
497  Constraint *newConstraint, bool recurse, bool is_readd,
498  LOCKMODE lockmode);
499 static char *ChooseForeignKeyConstraintNameAddition(List *colnames);
501  IndexStmt *stmt, LOCKMODE lockmode);
503  AlteredTableInfo *tab, Relation rel,
504  Constraint *constr,
505  bool recurse, bool recursing, bool is_readd,
506  LOCKMODE lockmode);
508  Relation rel, Constraint *fkconstraint,
509  bool recurse, bool recursing,
510  LOCKMODE lockmode);
511 static ObjectAddress addFkRecurseReferenced(List **wqueue, Constraint *fkconstraint,
512  Relation rel, Relation pkrel, Oid indexOid, Oid parentConstr,
513  int numfks, int16 *pkattnum, int16 *fkattnum,
514  Oid *pfeqoperators, Oid *ppeqoperators, Oid *ffeqoperators,
515  int numfkdelsetcols, int16 *fkdelsetcols,
516  bool old_check_ok,
517  Oid parentDelTrigger, Oid parentUpdTrigger,
518  bool with_period);
519 static void validateFkOnDeleteSetColumns(int numfks, const int16 *fkattnums,
520  int numfksetcols, const int16 *fksetcolsattnums,
521  List *fksetcols);
522 static void addFkRecurseReferencing(List **wqueue, Constraint *fkconstraint,
523  Relation rel, Relation pkrel, Oid indexOid, Oid parentConstr,
524  int numfks, int16 *pkattnum, int16 *fkattnum,
525  Oid *pfeqoperators, Oid *ppeqoperators, Oid *ffeqoperators,
526  int numfkdelsetcols, int16 *fkdelsetcols,
527  bool old_check_ok, LOCKMODE lockmode,
528  Oid parentInsTrigger, Oid parentUpdTrigger,
529  bool with_period);
530 
531 static void CloneForeignKeyConstraints(List **wqueue, Relation parentRel,
532  Relation partitionRel);
533 static void CloneFkReferenced(Relation parentRel, Relation partitionRel);
534 static void CloneFkReferencing(List **wqueue, Relation parentRel,
535  Relation partRel);
536 static void createForeignKeyCheckTriggers(Oid myRelOid, Oid refRelOid,
537  Constraint *fkconstraint, Oid constraintOid,
538  Oid indexOid,
539  Oid parentInsTrigger, Oid parentUpdTrigger,
540  Oid *insertTrigOid, Oid *updateTrigOid);
541 static void createForeignKeyActionTriggers(Relation rel, Oid refRelOid,
542  Constraint *fkconstraint, Oid constraintOid,
543  Oid indexOid,
544  Oid parentDelTrigger, Oid parentUpdTrigger,
545  Oid *deleteTrigOid, Oid *updateTrigOid);
547  Oid partRelid,
548  Oid parentConstrOid, int numfks,
549  AttrNumber *mapped_conkey, AttrNumber *confkey,
550  Oid *conpfeqop,
551  Oid parentInsTrigger,
552  Oid parentUpdTrigger,
553  Relation trigrel);
554 static void GetForeignKeyActionTriggers(Relation trigrel,
555  Oid conoid, Oid confrelid, Oid conrelid,
556  Oid *deleteTriggerOid,
557  Oid *updateTriggerOid);
558 static void GetForeignKeyCheckTriggers(Relation trigrel,
559  Oid conoid, Oid confrelid, Oid conrelid,
560  Oid *insertTriggerOid,
561  Oid *updateTriggerOid);
562 static void ATExecDropConstraint(Relation rel, const char *constrName,
563  DropBehavior behavior, bool recurse,
564  bool missing_ok, LOCKMODE lockmode);
566  HeapTuple constraintTup, DropBehavior behavior,
567  bool recurse, bool recursing,
568  bool missing_ok, List **readyRels,
569  LOCKMODE lockmode);
570 static void ATPrepAlterColumnType(List **wqueue,
571  AlteredTableInfo *tab, Relation rel,
572  bool recurse, bool recursing,
573  AlterTableCmd *cmd, LOCKMODE lockmode,
575 static bool ATColumnChangeRequiresRewrite(Node *expr, AttrNumber varattno);
577  AlterTableCmd *cmd, LOCKMODE lockmode);
579  Relation rel, AttrNumber attnum, const char *colName);
580 static void RememberConstraintForRebuilding(Oid conoid, AlteredTableInfo *tab);
581 static void RememberIndexForRebuilding(Oid indoid, AlteredTableInfo *tab);
582 static void RememberStatisticsForRebuilding(Oid stxoid, AlteredTableInfo *tab);
583 static void ATPostAlterTypeCleanup(List **wqueue, AlteredTableInfo *tab,
584  LOCKMODE lockmode);
585 static void ATPostAlterTypeParse(Oid oldId, Oid oldRelId, Oid refRelId,
586  char *cmd, List **wqueue, LOCKMODE lockmode,
587  bool rewrite);
589  Oid objid, Relation rel, List *domname,
590  const char *conname);
591 static void TryReuseIndex(Oid oldId, IndexStmt *stmt);
592 static void TryReuseForeignKey(Oid oldId, Constraint *con);
593 static ObjectAddress ATExecAlterColumnGenericOptions(Relation rel, const char *colName,
594  List *options, LOCKMODE lockmode);
595 static void change_owner_fix_column_acls(Oid relationOid,
596  Oid oldOwnerId, Oid newOwnerId);
597 static void change_owner_recurse_to_sequences(Oid relationOid,
598  Oid newOwnerId, LOCKMODE lockmode);
599 static ObjectAddress ATExecClusterOn(Relation rel, const char *indexName,
600  LOCKMODE lockmode);
601 static void ATExecDropCluster(Relation rel, LOCKMODE lockmode);
602 static void ATPrepSetAccessMethod(AlteredTableInfo *tab, Relation rel, const char *amname);
603 static void ATExecSetAccessMethodNoStorage(Relation rel, Oid newAccessMethod);
604 static bool ATPrepChangePersistence(Relation rel, bool toLogged);
605 static void ATPrepSetTableSpace(AlteredTableInfo *tab, Relation rel,
606  const char *tablespacename, LOCKMODE lockmode);
607 static void ATExecSetTableSpace(Oid tableOid, Oid newTableSpace, LOCKMODE lockmode);
608 static void ATExecSetTableSpaceNoStorage(Relation rel, Oid newTableSpace);
609 static void ATExecSetRelOptions(Relation rel, List *defList,
610  AlterTableType operation,
611  LOCKMODE lockmode);
612 static void ATExecEnableDisableTrigger(Relation rel, const char *trigname,
613  char fires_when, bool skip_system, bool recurse,
614  LOCKMODE lockmode);
615 static void ATExecEnableDisableRule(Relation rel, const char *rulename,
616  char fires_when, LOCKMODE lockmode);
617 static void ATPrepAddInherit(Relation child_rel);
618 static ObjectAddress ATExecAddInherit(Relation child_rel, RangeVar *parent, LOCKMODE lockmode);
619 static ObjectAddress ATExecDropInherit(Relation rel, RangeVar *parent, LOCKMODE lockmode);
620 static void drop_parent_dependency(Oid relid, Oid refclassid, Oid refobjid,
621  DependencyType deptype);
622 static ObjectAddress ATExecAddOf(Relation rel, const TypeName *ofTypename, LOCKMODE lockmode);
623 static void ATExecDropOf(Relation rel, LOCKMODE lockmode);
624 static void ATExecReplicaIdentity(Relation rel, ReplicaIdentityStmt *stmt, LOCKMODE lockmode);
625 static void ATExecGenericOptions(Relation rel, List *options);
626 static void ATExecSetRowSecurity(Relation rel, bool rls);
627 static void ATExecForceNoForceRowSecurity(Relation rel, bool force_rls);
629  const char *column, Node *newValue, LOCKMODE lockmode);
630 
631 static void index_copy_data(Relation rel, RelFileLocator newrlocator);
632 static const char *storage_name(char c);
633 
634 static void RangeVarCallbackForDropRelation(const RangeVar *rel, Oid relOid,
635  Oid oldRelOid, void *arg);
636 static void RangeVarCallbackForAlterRelation(const RangeVar *rv, Oid relid,
637  Oid oldrelid, void *arg);
639 static void ComputePartitionAttrs(ParseState *pstate, Relation rel, List *partParams, AttrNumber *partattrs,
640  List **partexprs, Oid *partopclass, Oid *partcollation,
641  PartitionStrategy strategy);
642 static void CreateInheritance(Relation child_rel, Relation parent_rel, bool ispartition);
643 static void RemoveInheritance(Relation child_rel, Relation parent_rel,
644  bool expect_detached);
645 static void ATInheritAdjustNotNulls(Relation parent_rel, Relation child_rel,
646  int inhcount);
647 static ObjectAddress ATExecAttachPartition(List **wqueue, Relation rel,
648  PartitionCmd *cmd,
650 static void AttachPartitionEnsureIndexes(List **wqueue, Relation rel, Relation attachrel);
651 static void QueuePartitionConstraintValidation(List **wqueue, Relation scanrel,
652  List *partConstraint,
653  bool validate_default);
654 static void CloneRowTriggersToPartition(Relation parent, Relation partition);
655 static void DetachAddConstraintIfNeeded(List **wqueue, Relation partRel);
656 static void DropClonedTriggersFromPartition(Oid partitionId);
658  Relation rel, RangeVar *name,
659  bool concurrent);
660 static void DetachPartitionFinalize(Relation rel, Relation partRel,
661  bool concurrent, Oid defaultPartOid);
663 static ObjectAddress ATExecAttachPartitionIdx(List **wqueue, Relation parentIdx,
664  RangeVar *name);
665 static void validatePartitionedIndex(Relation partedIdx, Relation partedTbl);
666 static void refuseDupeIndexAttach(Relation parentIdx, Relation partIdx,
667  Relation partitionTbl);
668 static void verifyPartitionIndexNotNull(IndexInfo *iinfo, Relation partIdx);
669 static List *GetParentedForeignKeyRefs(Relation partition);
670 static void ATDetachCheckNoForeignKeyRefs(Relation partition);
671 static char GetAttributeCompression(Oid atttypid, const char *compression);
672 static char GetAttributeStorage(Oid atttypid, const char *storagemode);
673 
674 static void ATExecSplitPartition(List **wqueue, AlteredTableInfo *tab,
675  Relation rel, PartitionCmd *cmd,
677 static void ATExecMergePartitions(List **wqueue, AlteredTableInfo *tab, Relation rel,
679 
680 /* ----------------------------------------------------------------
681  * DefineRelation
682  * Creates a new relation.
683  *
684  * stmt carries parsetree information from an ordinary CREATE TABLE statement.
685  * The other arguments are used to extend the behavior for other cases:
686  * relkind: relkind to assign to the new relation
687  * ownerId: if not InvalidOid, use this as the new relation's owner.
688  * typaddress: if not null, it's set to the pg_type entry's address.
689  * queryString: for error reporting
690  *
691  * Note that permissions checks are done against current user regardless of
692  * ownerId. A nonzero ownerId is used when someone is creating a relation
693  * "on behalf of" someone else, so we still want to see that the current user
694  * has permissions to do it.
695  *
696  * If successful, returns the address of the new relation.
697  * ----------------------------------------------------------------
698  */
700 DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId,
701  ObjectAddress *typaddress, const char *queryString)
702 {
703  char relname[NAMEDATALEN];
704  Oid namespaceId;
705  Oid relationId;
706  Oid tablespaceId;
707  Relation rel;
709  List *inheritOids;
710  List *old_constraints;
711  List *old_notnulls;
712  List *rawDefaults;
713  List *cookedDefaults;
714  List *nncols;
715  Datum reloptions;
716  ListCell *listptr;
718  bool partitioned;
719  static char *validnsps[] = HEAP_RELOPT_NAMESPACES;
720  Oid ofTypeId;
721  ObjectAddress address;
722  LOCKMODE parentLockmode;
723  Oid accessMethodId = InvalidOid;
724 
725  /*
726  * Truncate relname to appropriate length (probably a waste of time, as
727  * parser should have done this already).
728  */
729  strlcpy(relname, stmt->relation->relname, NAMEDATALEN);
730 
731  /*
732  * Check consistency of arguments
733  */
734  if (stmt->oncommit != ONCOMMIT_NOOP
735  && stmt->relation->relpersistence != RELPERSISTENCE_TEMP)
736  ereport(ERROR,
737  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
738  errmsg("ON COMMIT can only be used on temporary tables")));
739 
740  if (stmt->partspec != NULL)
741  {
742  if (relkind != RELKIND_RELATION)
743  elog(ERROR, "unexpected relkind: %d", (int) relkind);
744 
745  relkind = RELKIND_PARTITIONED_TABLE;
746  partitioned = true;
747  }
748  else
749  partitioned = false;
750 
751  /*
752  * Look up the namespace in which we are supposed to create the relation,
753  * check we have permission to create there, lock it against concurrent
754  * drop, and mark stmt->relation as RELPERSISTENCE_TEMP if a temporary
755  * namespace is selected.
756  */
757  namespaceId =
759 
760  /*
761  * Security check: disallow creating temp tables from security-restricted
762  * code. This is needed because calling code might not expect untrusted
763  * tables to appear in pg_temp at the front of its search path.
764  */
765  if (stmt->relation->relpersistence == RELPERSISTENCE_TEMP
767  ereport(ERROR,
768  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
769  errmsg("cannot create temporary table within security-restricted operation")));
770 
771  /*
772  * Determine the lockmode to use when scanning parents. A self-exclusive
773  * lock is needed here.
774  *
775  * For regular inheritance, if two backends attempt to add children to the
776  * same parent simultaneously, and that parent has no pre-existing
777  * children, then both will attempt to update the parent's relhassubclass
778  * field, leading to a "tuple concurrently updated" error. Also, this
779  * interlocks against a concurrent ANALYZE on the parent table, which
780  * might otherwise be attempting to clear the parent's relhassubclass
781  * field, if its previous children were recently dropped.
782  *
783  * If the child table is a partition, then we instead grab an exclusive
784  * lock on the parent because its partition descriptor will be changed by
785  * addition of the new partition.
786  */
787  parentLockmode = (stmt->partbound != NULL ? AccessExclusiveLock :
789 
790  /* Determine the list of OIDs of the parents. */
791  inheritOids = NIL;
792  foreach(listptr, stmt->inhRelations)
793  {
794  RangeVar *rv = (RangeVar *) lfirst(listptr);
795  Oid parentOid;
796 
797  parentOid = RangeVarGetRelid(rv, parentLockmode, false);
798 
799  /*
800  * Reject duplications in the list of parents.
801  */
802  if (list_member_oid(inheritOids, parentOid))
803  ereport(ERROR,
804  (errcode(ERRCODE_DUPLICATE_TABLE),
805  errmsg("relation \"%s\" would be inherited from more than once",
806  get_rel_name(parentOid))));
807 
808  inheritOids = lappend_oid(inheritOids, parentOid);
809  }
810 
811  /*
812  * Select tablespace to use: an explicitly indicated one, or (in the case
813  * of a partitioned table) the parent's, if it has one.
814  */
815  if (stmt->tablespacename)
816  {
817  tablespaceId = get_tablespace_oid(stmt->tablespacename, false);
818 
819  if (partitioned && tablespaceId == MyDatabaseTableSpace)
820  ereport(ERROR,
821  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
822  errmsg("cannot specify default tablespace for partitioned relations")));
823  }
824  else if (stmt->partbound)
825  {
826  Assert(list_length(inheritOids) == 1);
827  tablespaceId = get_rel_tablespace(linitial_oid(inheritOids));
828  }
829  else
830  tablespaceId = InvalidOid;
831 
832  /* still nothing? use the default */
833  if (!OidIsValid(tablespaceId))
834  tablespaceId = GetDefaultTablespace(stmt->relation->relpersistence,
835  partitioned);
836 
837  /* Check permissions except when using database's default */
838  if (OidIsValid(tablespaceId) && tablespaceId != MyDatabaseTableSpace)
839  {
840  AclResult aclresult;
841 
842  aclresult = object_aclcheck(TableSpaceRelationId, tablespaceId, GetUserId(),
843  ACL_CREATE);
844  if (aclresult != ACLCHECK_OK)
846  get_tablespace_name(tablespaceId));
847  }
848 
849  /* In all cases disallow placing user relations in pg_global */
850  if (tablespaceId == GLOBALTABLESPACE_OID)
851  ereport(ERROR,
852  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
853  errmsg("only shared relations can be placed in pg_global tablespace")));
854 
855  /* Identify user ID that will own the table */
856  if (!OidIsValid(ownerId))
857  ownerId = GetUserId();
858 
859  /*
860  * Parse and validate reloptions, if any.
861  */
862  reloptions = transformRelOptions((Datum) 0, stmt->options, NULL, validnsps,
863  true, false);
864 
865  switch (relkind)
866  {
867  case RELKIND_VIEW:
868  (void) view_reloptions(reloptions, true);
869  break;
870  case RELKIND_PARTITIONED_TABLE:
871  (void) partitioned_table_reloptions(reloptions, true);
872  break;
873  default:
874  (void) heap_reloptions(relkind, reloptions, true);
875  }
876 
877  if (stmt->ofTypename)
878  {
879  AclResult aclresult;
880 
881  ofTypeId = typenameTypeId(NULL, stmt->ofTypename);
882 
883  aclresult = object_aclcheck(TypeRelationId, ofTypeId, GetUserId(), ACL_USAGE);
884  if (aclresult != ACLCHECK_OK)
885  aclcheck_error_type(aclresult, ofTypeId);
886  }
887  else
888  ofTypeId = InvalidOid;
889 
890  /*
891  * Look up inheritance ancestors and generate relation schema, including
892  * inherited attributes. (Note that stmt->tableElts is destructively
893  * modified by MergeAttributes.)
894  */
895  stmt->tableElts =
896  MergeAttributes(stmt->tableElts, inheritOids,
897  stmt->relation->relpersistence,
898  stmt->partbound != NULL,
899  &old_constraints, &old_notnulls);
900 
901  /*
902  * Create a tuple descriptor from the relation schema. Note that this
903  * deals with column names, types, and in-descriptor NOT NULL flags, but
904  * not default values, NOT NULL or CHECK constraints; we handle those
905  * below.
906  */
907  descriptor = BuildDescForRelation(stmt->tableElts);
908 
909  /*
910  * Find columns with default values and prepare for insertion of the
911  * defaults. Pre-cooked (that is, inherited) defaults go into a list of
912  * CookedConstraint structs that we'll pass to heap_create_with_catalog,
913  * while raw defaults go into a list of RawColumnDefault structs that will
914  * be processed by AddRelationNewConstraints. (We can't deal with raw
915  * expressions until we can do transformExpr.)
916  *
917  * We can set the atthasdef flags now in the tuple descriptor; this just
918  * saves StoreAttrDefault from having to do an immediate update of the
919  * pg_attribute rows.
920  */
921  rawDefaults = NIL;
922  cookedDefaults = NIL;
923  attnum = 0;
924 
925  foreach(listptr, stmt->tableElts)
926  {
927  ColumnDef *colDef = lfirst(listptr);
928  Form_pg_attribute attr;
929 
930  attnum++;
931  attr = TupleDescAttr(descriptor, attnum - 1);
932 
933  if (colDef->raw_default != NULL)
934  {
935  RawColumnDefault *rawEnt;
936 
937  Assert(colDef->cooked_default == NULL);
938 
939  rawEnt = (RawColumnDefault *) palloc(sizeof(RawColumnDefault));
940  rawEnt->attnum = attnum;
941  rawEnt->raw_default = colDef->raw_default;
942  rawEnt->missingMode = false;
943  rawEnt->generated = colDef->generated;
944  rawDefaults = lappend(rawDefaults, rawEnt);
945  attr->atthasdef = true;
946  }
947  else if (colDef->cooked_default != NULL)
948  {
949  CookedConstraint *cooked;
950 
951  cooked = (CookedConstraint *) palloc(sizeof(CookedConstraint));
952  cooked->contype = CONSTR_DEFAULT;
953  cooked->conoid = InvalidOid; /* until created */
954  cooked->name = NULL;
955  cooked->attnum = attnum;
956  cooked->expr = colDef->cooked_default;
957  cooked->skip_validation = false;
958  cooked->is_local = true; /* not used for defaults */
959  cooked->inhcount = 0; /* ditto */
960  cooked->is_no_inherit = false;
961  cookedDefaults = lappend(cookedDefaults, cooked);
962  attr->atthasdef = true;
963  }
964  }
965 
966  /*
967  * For relations with table AM and partitioned tables, select access
968  * method to use: an explicitly indicated one, or (in the case of a
969  * partitioned table) the parent's, if it has one.
970  */
971  if (stmt->accessMethod != NULL)
972  {
973  Assert(RELKIND_HAS_TABLE_AM(relkind) || relkind == RELKIND_PARTITIONED_TABLE);
974  accessMethodId = get_table_am_oid(stmt->accessMethod, false);
975  }
976  else if (RELKIND_HAS_TABLE_AM(relkind) || relkind == RELKIND_PARTITIONED_TABLE)
977  {
978  if (stmt->partbound)
979  {
980  Assert(list_length(inheritOids) == 1);
981  accessMethodId = get_rel_relam(linitial_oid(inheritOids));
982  }
983 
984  if (RELKIND_HAS_TABLE_AM(relkind) && !OidIsValid(accessMethodId))
985  accessMethodId = get_table_am_oid(default_table_access_method, false);
986  }
987 
988  /*
989  * Create the relation. Inherited defaults and constraints are passed in
990  * for immediate handling --- since they don't need parsing, they can be
991  * stored immediately.
992  */
993  relationId = heap_create_with_catalog(relname,
994  namespaceId,
995  tablespaceId,
996  InvalidOid,
997  InvalidOid,
998  ofTypeId,
999  ownerId,
1000  accessMethodId,
1001  descriptor,
1002  list_concat(cookedDefaults,
1003  old_constraints),
1004  relkind,
1005  stmt->relation->relpersistence,
1006  false,
1007  false,
1008  stmt->oncommit,
1009  reloptions,
1010  true,
1012  false,
1013  InvalidOid,
1014  typaddress);
1015 
1016  /*
1017  * We must bump the command counter to make the newly-created relation
1018  * tuple visible for opening.
1019  */
1021 
1022  /*
1023  * Open the new relation and acquire exclusive lock on it. This isn't
1024  * really necessary for locking out other backends (since they can't see
1025  * the new rel anyway until we commit), but it keeps the lock manager from
1026  * complaining about deadlock risks.
1027  */
1028  rel = relation_open(relationId, AccessExclusiveLock);
1029 
1030  /*
1031  * Now add any newly specified column default and generation expressions
1032  * to the new relation. These are passed to us in the form of raw
1033  * parsetrees; we need to transform them to executable expression trees
1034  * before they can be added. The most convenient way to do that is to
1035  * apply the parser's transformExpr routine, but transformExpr doesn't
1036  * work unless we have a pre-existing relation. So, the transformation has
1037  * to be postponed to this final step of CREATE TABLE.
1038  *
1039  * This needs to be before processing the partitioning clauses because
1040  * those could refer to generated columns.
1041  */
1042  if (rawDefaults)
1043  AddRelationNewConstraints(rel, rawDefaults, NIL,
1044  true, true, false, queryString);
1045 
1046  /*
1047  * Make column generation expressions visible for use by partitioning.
1048  */
1050 
1051  /* Process and store partition bound, if any. */
1052  if (stmt->partbound)
1053  {
1054  PartitionBoundSpec *bound;
1055  ParseState *pstate;
1056  Oid parentId = linitial_oid(inheritOids),
1057  defaultPartOid;
1058  Relation parent,
1059  defaultRel = NULL;
1060  ParseNamespaceItem *nsitem;
1061 
1062  /* Already have strong enough lock on the parent */
1063  parent = table_open(parentId, NoLock);
1064 
1065  /*
1066  * We are going to try to validate the partition bound specification
1067  * against the partition key of parentRel, so it better have one.
1068  */
1069  if (parent->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
1070  ereport(ERROR,
1071  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1072  errmsg("\"%s\" is not partitioned",
1073  RelationGetRelationName(parent))));
1074 
1075  /*
1076  * The partition constraint of the default partition depends on the
1077  * partition bounds of every other partition. It is possible that
1078  * another backend might be about to execute a query on the default
1079  * partition table, and that the query relies on previously cached
1080  * default partition constraints. We must therefore take a table lock
1081  * strong enough to prevent all queries on the default partition from
1082  * proceeding until we commit and send out a shared-cache-inval notice
1083  * that will make them update their index lists.
1084  *
1085  * Order of locking: The relation being added won't be visible to
1086  * other backends until it is committed, hence here in
1087  * DefineRelation() the order of locking the default partition and the
1088  * relation being added does not matter. But at all other places we
1089  * need to lock the default relation before we lock the relation being
1090  * added or removed i.e. we should take the lock in same order at all
1091  * the places such that lock parent, lock default partition and then
1092  * lock the partition so as to avoid a deadlock.
1093  */
1094  defaultPartOid =
1096  true));
1097  if (OidIsValid(defaultPartOid))
1098  defaultRel = table_open(defaultPartOid, AccessExclusiveLock);
1099 
1100  /* Transform the bound values */
1101  pstate = make_parsestate(NULL);
1102  pstate->p_sourcetext = queryString;
1103 
1104  /*
1105  * Add an nsitem containing this relation, so that transformExpr
1106  * called on partition bound expressions is able to report errors
1107  * using a proper context.
1108  */
1109  nsitem = addRangeTableEntryForRelation(pstate, rel, AccessShareLock,
1110  NULL, false, false);
1111  addNSItemToQuery(pstate, nsitem, false, true, true);
1112 
1113  bound = transformPartitionBound(pstate, parent, stmt->partbound);
1114 
1115  /*
1116  * Check first that the new partition's bound is valid and does not
1117  * overlap with any of existing partitions of the parent.
1118  */
1119  check_new_partition_bound(relname, parent, bound, pstate);
1120 
1121  /*
1122  * If the default partition exists, its partition constraints will
1123  * change after the addition of this new partition such that it won't
1124  * allow any row that qualifies for this new partition. So, check that
1125  * the existing data in the default partition satisfies the constraint
1126  * as it will exist after adding this partition.
1127  */
1128  if (OidIsValid(defaultPartOid))
1129  {
1130  check_default_partition_contents(parent, defaultRel, bound);
1131  /* Keep the lock until commit. */
1132  table_close(defaultRel, NoLock);
1133  }
1134 
1135  /* Update the pg_class entry. */
1136  StorePartitionBound(rel, parent, bound);
1137 
1138  table_close(parent, NoLock);
1139  }
1140 
1141  /* Store inheritance information for new rel. */
1142  StoreCatalogInheritance(relationId, inheritOids, stmt->partbound != NULL);
1143 
1144  /*
1145  * Process the partitioning specification (if any) and store the partition
1146  * key information into the catalog.
1147  */
1148  if (partitioned)
1149  {
1150  ParseState *pstate;
1151  int partnatts;
1152  AttrNumber partattrs[PARTITION_MAX_KEYS];
1153  Oid partopclass[PARTITION_MAX_KEYS];
1154  Oid partcollation[PARTITION_MAX_KEYS];
1155  List *partexprs = NIL;
1156 
1157  pstate = make_parsestate(NULL);
1158  pstate->p_sourcetext = queryString;
1159 
1160  partnatts = list_length(stmt->partspec->partParams);
1161 
1162  /* Protect fixed-size arrays here and in executor */
1163  if (partnatts > PARTITION_MAX_KEYS)
1164  ereport(ERROR,
1165  (errcode(ERRCODE_TOO_MANY_COLUMNS),
1166  errmsg("cannot partition using more than %d columns",
1167  PARTITION_MAX_KEYS)));
1168 
1169  /*
1170  * We need to transform the raw parsetrees corresponding to partition
1171  * expressions into executable expression trees. Like column defaults
1172  * and CHECK constraints, we could not have done the transformation
1173  * earlier.
1174  */
1175  stmt->partspec = transformPartitionSpec(rel, stmt->partspec);
1176 
1177  ComputePartitionAttrs(pstate, rel, stmt->partspec->partParams,
1178  partattrs, &partexprs, partopclass,
1179  partcollation, stmt->partspec->strategy);
1180 
1181  StorePartitionKey(rel, stmt->partspec->strategy, partnatts, partattrs,
1182  partexprs,
1183  partopclass, partcollation);
1184 
1185  /* make it all visible */
1187  }
1188 
1189  /*
1190  * If we're creating a partition, create now all the indexes, triggers,
1191  * FKs defined in the parent.
1192  *
1193  * We can't do it earlier, because DefineIndex wants to know the partition
1194  * key which we just stored.
1195  */
1196  if (stmt->partbound)
1197  {
1198  Oid parentId = linitial_oid(inheritOids);
1199  Relation parent;
1200  List *idxlist;
1201  ListCell *cell;
1202 
1203  /* Already have strong enough lock on the parent */
1204  parent = table_open(parentId, NoLock);
1205  idxlist = RelationGetIndexList(parent);
1206 
1207  /*
1208  * For each index in the parent table, create one in the partition
1209  */
1210  foreach(cell, idxlist)
1211  {
1212  Relation idxRel = index_open(lfirst_oid(cell), AccessShareLock);
1213  AttrMap *attmap;
1214  IndexStmt *idxstmt;
1215  Oid constraintOid;
1216 
1217  if (rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
1218  {
1219  if (idxRel->rd_index->indisunique)
1220  ereport(ERROR,
1221  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1222  errmsg("cannot create foreign partition of partitioned table \"%s\"",
1223  RelationGetRelationName(parent)),
1224  errdetail("Table \"%s\" contains indexes that are unique.",
1225  RelationGetRelationName(parent))));
1226  else
1227  {
1228  index_close(idxRel, AccessShareLock);
1229  continue;
1230  }
1231  }
1232 
1234  RelationGetDescr(parent),
1235  false);
1236  idxstmt =
1237  generateClonedIndexStmt(NULL, idxRel,
1238  attmap, &constraintOid);
1240  idxstmt,
1241  InvalidOid,
1242  RelationGetRelid(idxRel),
1243  constraintOid,
1244  -1,
1245  false, false, false, false, false);
1246 
1247  index_close(idxRel, AccessShareLock);
1248  }
1249 
1250  list_free(idxlist);
1251 
1252  /*
1253  * If there are any row-level triggers, clone them to the new
1254  * partition.
1255  */
1256  if (parent->trigdesc != NULL)
1257  CloneRowTriggersToPartition(parent, rel);
1258 
1259  /*
1260  * And foreign keys too. Note that because we're freshly creating the
1261  * table, there is no need to verify these new constraints.
1262  */
1263  CloneForeignKeyConstraints(NULL, parent, rel);
1264 
1265  table_close(parent, NoLock);
1266  }
1267 
1268  /*
1269  * Now add any newly specified CHECK constraints to the new relation. Same
1270  * as for defaults above, but these need to come after partitioning is set
1271  * up.
1272  */
1273  if (stmt->constraints)
1274  AddRelationNewConstraints(rel, NIL, stmt->constraints,
1275  true, true, false, queryString);
1276 
1277  /*
1278  * Finally, merge the not-null constraints that are declared directly with
1279  * those that come from parent relations (making sure to count inheritance
1280  * appropriately for each), create them, and set the attnotnull flag on
1281  * columns that don't yet have it.
1282  */
1283  nncols = AddRelationNotNullConstraints(rel, stmt->nnconstraints,
1284  old_notnulls);
1285  foreach(listptr, nncols)
1286  set_attnotnull(NULL, rel, lfirst_int(listptr), false, NoLock);
1287 
1288  ObjectAddressSet(address, RelationRelationId, relationId);
1289 
1290  /*
1291  * Clean up. We keep lock on new relation (although it shouldn't be
1292  * visible to anyone else anyway, until commit).
1293  */
1294  relation_close(rel, NoLock);
1295 
1296  return address;
1297 }
1298 
1299 /*
1300  * BuildDescForRelation
1301  *
1302  * Given a list of ColumnDef nodes, build a TupleDesc.
1303  *
1304  * Note: tdtypeid will need to be filled in later on.
1305  */
1306 TupleDesc
1308 {
1309  int natts;
1311  ListCell *l;
1312  TupleDesc desc;
1313  bool has_not_null;
1314  char *attname;
1315  Oid atttypid;
1316  int32 atttypmod;
1317  Oid attcollation;
1318  int attdim;
1319 
1320  /*
1321  * allocate a new tuple descriptor
1322  */
1323  natts = list_length(columns);
1324  desc = CreateTemplateTupleDesc(natts);
1325  has_not_null = false;
1326 
1327  attnum = 0;
1328 
1329  foreach(l, columns)
1330  {
1331  ColumnDef *entry = lfirst(l);
1332  AclResult aclresult;
1333  Form_pg_attribute att;
1334 
1335  /*
1336  * for each entry in the list, get the name and type information from
1337  * the list and have TupleDescInitEntry fill in the attribute
1338  * information we need.
1339  */
1340  attnum++;
1341 
1342  attname = entry->colname;
1343  typenameTypeIdAndMod(NULL, entry->typeName, &atttypid, &atttypmod);
1344 
1345  aclresult = object_aclcheck(TypeRelationId, atttypid, GetUserId(), ACL_USAGE);
1346  if (aclresult != ACLCHECK_OK)
1347  aclcheck_error_type(aclresult, atttypid);
1348 
1349  attcollation = GetColumnDefCollation(NULL, entry, atttypid);
1350  attdim = list_length(entry->typeName->arrayBounds);
1351  if (attdim > PG_INT16_MAX)
1352  ereport(ERROR,
1353  errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
1354  errmsg("too many array dimensions"));
1355 
1356  if (entry->typeName->setof)
1357  ereport(ERROR,
1358  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
1359  errmsg("column \"%s\" cannot be declared SETOF",
1360  attname)));
1361 
1363  atttypid, atttypmod, attdim);
1364  att = TupleDescAttr(desc, attnum - 1);
1365 
1366  /* Override TupleDescInitEntry's settings as requested */
1367  TupleDescInitEntryCollation(desc, attnum, attcollation);
1368 
1369  /* Fill in additional stuff not handled by TupleDescInitEntry */
1370  att->attnotnull = entry->is_not_null;
1371  has_not_null |= entry->is_not_null;
1372  att->attislocal = entry->is_local;
1373  att->attinhcount = entry->inhcount;
1374  att->attidentity = entry->identity;
1375  att->attgenerated = entry->generated;
1376  att->attcompression = GetAttributeCompression(att->atttypid, entry->compression);
1377  if (entry->storage)
1378  att->attstorage = entry->storage;
1379  else if (entry->storage_name)
1380  att->attstorage = GetAttributeStorage(att->atttypid, entry->storage_name);
1381  }
1382 
1383  if (has_not_null)
1384  {
1385  TupleConstr *constr = (TupleConstr *) palloc0(sizeof(TupleConstr));
1386 
1387  constr->has_not_null = true;
1388  constr->has_generated_stored = false;
1389  constr->defval = NULL;
1390  constr->missing = NULL;
1391  constr->num_defval = 0;
1392  constr->check = NULL;
1393  constr->num_check = 0;
1394  desc->constr = constr;
1395  }
1396  else
1397  {
1398  desc->constr = NULL;
1399  }
1400 
1401  return desc;
1402 }
1403 
1404 /*
1405  * Emit the right error or warning message for a "DROP" command issued on a
1406  * non-existent relation
1407  */
1408 static void
1409 DropErrorMsgNonExistent(RangeVar *rel, char rightkind, bool missing_ok)
1410 {
1411  const struct dropmsgstrings *rentry;
1412 
1413  if (rel->schemaname != NULL &&
1415  {
1416  if (!missing_ok)
1417  {
1418  ereport(ERROR,
1419  (errcode(ERRCODE_UNDEFINED_SCHEMA),
1420  errmsg("schema \"%s\" does not exist", rel->schemaname)));
1421  }
1422  else
1423  {
1424  ereport(NOTICE,
1425  (errmsg("schema \"%s\" does not exist, skipping",
1426  rel->schemaname)));
1427  }
1428  return;
1429  }
1430 
1431  for (rentry = dropmsgstringarray; rentry->kind != '\0'; rentry++)
1432  {
1433  if (rentry->kind == rightkind)
1434  {
1435  if (!missing_ok)
1436  {
1437  ereport(ERROR,
1438  (errcode(rentry->nonexistent_code),
1439  errmsg(rentry->nonexistent_msg, rel->relname)));
1440  }
1441  else
1442  {
1443  ereport(NOTICE, (errmsg(rentry->skipping_msg, rel->relname)));
1444  break;
1445  }
1446  }
1447  }
1448 
1449  Assert(rentry->kind != '\0'); /* Should be impossible */
1450 }
1451 
1452 /*
1453  * Emit the right error message for a "DROP" command issued on a
1454  * relation of the wrong type
1455  */
1456 static void
1457 DropErrorMsgWrongType(const char *relname, char wrongkind, char rightkind)
1458 {
1459  const struct dropmsgstrings *rentry;
1460  const struct dropmsgstrings *wentry;
1461 
1462  for (rentry = dropmsgstringarray; rentry->kind != '\0'; rentry++)
1463  if (rentry->kind == rightkind)
1464  break;
1465  Assert(rentry->kind != '\0');
1466 
1467  for (wentry = dropmsgstringarray; wentry->kind != '\0'; wentry++)
1468  if (wentry->kind == wrongkind)
1469  break;
1470  /* wrongkind could be something we don't have in our table... */
1471 
1472  ereport(ERROR,
1473  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1474  errmsg(rentry->nota_msg, relname),
1475  (wentry->kind != '\0') ? errhint("%s", _(wentry->drophint_msg)) : 0));
1476 }
1477 
1478 /*
1479  * RemoveRelations
1480  * Implements DROP TABLE, DROP INDEX, DROP SEQUENCE, DROP VIEW,
1481  * DROP MATERIALIZED VIEW, DROP FOREIGN TABLE
1482  */
1483 void
1485 {
1486  ObjectAddresses *objects;
1487  char relkind;
1488  ListCell *cell;
1489  int flags = 0;
1490  LOCKMODE lockmode = AccessExclusiveLock;
1491 
1492  /* DROP CONCURRENTLY uses a weaker lock, and has some restrictions */
1493  if (drop->concurrent)
1494  {
1495  /*
1496  * Note that for temporary relations this lock may get upgraded later
1497  * on, but as no other session can access a temporary relation, this
1498  * is actually fine.
1499  */
1500  lockmode = ShareUpdateExclusiveLock;
1501  Assert(drop->removeType == OBJECT_INDEX);
1502  if (list_length(drop->objects) != 1)
1503  ereport(ERROR,
1504  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1505  errmsg("DROP INDEX CONCURRENTLY does not support dropping multiple objects")));
1506  if (drop->behavior == DROP_CASCADE)
1507  ereport(ERROR,
1508  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1509  errmsg("DROP INDEX CONCURRENTLY does not support CASCADE")));
1510  }
1511 
1512  /*
1513  * First we identify all the relations, then we delete them in a single
1514  * performMultipleDeletions() call. This is to avoid unwanted DROP
1515  * RESTRICT errors if one of the relations depends on another.
1516  */
1517 
1518  /* Determine required relkind */
1519  switch (drop->removeType)
1520  {
1521  case OBJECT_TABLE:
1522  relkind = RELKIND_RELATION;
1523  break;
1524 
1525  case OBJECT_INDEX:
1526  relkind = RELKIND_INDEX;
1527  break;
1528 
1529  case OBJECT_SEQUENCE:
1530  relkind = RELKIND_SEQUENCE;
1531  break;
1532 
1533  case OBJECT_VIEW:
1534  relkind = RELKIND_VIEW;
1535  break;
1536 
1537  case OBJECT_MATVIEW:
1538  relkind = RELKIND_MATVIEW;
1539  break;
1540 
1541  case OBJECT_FOREIGN_TABLE:
1542  relkind = RELKIND_FOREIGN_TABLE;
1543  break;
1544 
1545  default:
1546  elog(ERROR, "unrecognized drop object type: %d",
1547  (int) drop->removeType);
1548  relkind = 0; /* keep compiler quiet */
1549  break;
1550  }
1551 
1552  /* Lock and validate each relation; build a list of object addresses */
1553  objects = new_object_addresses();
1554 
1555  foreach(cell, drop->objects)
1556  {
1557  RangeVar *rel = makeRangeVarFromNameList((List *) lfirst(cell));
1558  Oid relOid;
1559  ObjectAddress obj;
1561 
1562  /*
1563  * These next few steps are a great deal like relation_openrv, but we
1564  * don't bother building a relcache entry since we don't need it.
1565  *
1566  * Check for shared-cache-inval messages before trying to access the
1567  * relation. This is needed to cover the case where the name
1568  * identifies a rel that has been dropped and recreated since the
1569  * start of our transaction: if we don't flush the old syscache entry,
1570  * then we'll latch onto that entry and suffer an error later.
1571  */
1573 
1574  /* Look up the appropriate relation using namespace search. */
1575  state.expected_relkind = relkind;
1576  state.heap_lockmode = drop->concurrent ?
1578  /* We must initialize these fields to show that no locks are held: */
1579  state.heapOid = InvalidOid;
1580  state.partParentOid = InvalidOid;
1581 
1582  relOid = RangeVarGetRelidExtended(rel, lockmode, RVR_MISSING_OK,
1584  (void *) &state);
1585 
1586  /* Not there? */
1587  if (!OidIsValid(relOid))
1588  {
1589  DropErrorMsgNonExistent(rel, relkind, drop->missing_ok);
1590  continue;
1591  }
1592 
1593  /*
1594  * Decide if concurrent mode needs to be used here or not. The
1595  * callback retrieved the rel's persistence for us.
1596  */
1597  if (drop->concurrent &&
1598  state.actual_relpersistence != RELPERSISTENCE_TEMP)
1599  {
1600  Assert(list_length(drop->objects) == 1 &&
1601  drop->removeType == OBJECT_INDEX);
1603  }
1604 
1605  /*
1606  * Concurrent index drop cannot be used with partitioned indexes,
1607  * either.
1608  */
1609  if ((flags & PERFORM_DELETION_CONCURRENTLY) != 0 &&
1610  state.actual_relkind == RELKIND_PARTITIONED_INDEX)
1611  ereport(ERROR,
1612  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1613  errmsg("cannot drop partitioned index \"%s\" concurrently",
1614  rel->relname)));
1615 
1616  /*
1617  * If we're told to drop a partitioned index, we must acquire lock on
1618  * all the children of its parent partitioned table before proceeding.
1619  * Otherwise we'd try to lock the child index partitions before their
1620  * tables, leading to potential deadlock against other sessions that
1621  * will lock those objects in the other order.
1622  */
1623  if (state.actual_relkind == RELKIND_PARTITIONED_INDEX)
1624  (void) find_all_inheritors(state.heapOid,
1625  state.heap_lockmode,
1626  NULL);
1627 
1628  /* OK, we're ready to delete this one */
1629  obj.classId = RelationRelationId;
1630  obj.objectId = relOid;
1631  obj.objectSubId = 0;
1632 
1633  add_exact_object_address(&obj, objects);
1634  }
1635 
1636  performMultipleDeletions(objects, drop->behavior, flags);
1637 
1638  free_object_addresses(objects);
1639 }
1640 
1641 /*
1642  * Before acquiring a table lock, check whether we have sufficient rights.
1643  * In the case of DROP INDEX, also try to lock the table before the index.
1644  * Also, if the table to be dropped is a partition, we try to lock the parent
1645  * first.
1646  */
1647 static void
1648 RangeVarCallbackForDropRelation(const RangeVar *rel, Oid relOid, Oid oldRelOid,
1649  void *arg)
1650 {
1651  HeapTuple tuple;
1653  char expected_relkind;
1654  bool is_partition;
1655  Form_pg_class classform;
1657  bool invalid_system_index = false;
1658 
1659  state = (struct DropRelationCallbackState *) arg;
1660  heap_lockmode = state->heap_lockmode;
1661 
1662  /*
1663  * If we previously locked some other index's heap, and the name we're
1664  * looking up no longer refers to that relation, release the now-useless
1665  * lock.
1666  */
1667  if (relOid != oldRelOid && OidIsValid(state->heapOid))
1668  {
1670  state->heapOid = InvalidOid;
1671  }
1672 
1673  /*
1674  * Similarly, if we previously locked some other partition's heap, and the
1675  * name we're looking up no longer refers to that relation, release the
1676  * now-useless lock.
1677  */
1678  if (relOid != oldRelOid && OidIsValid(state->partParentOid))
1679  {
1680  UnlockRelationOid(state->partParentOid, AccessExclusiveLock);
1681  state->partParentOid = InvalidOid;
1682  }
1683 
1684  /* Didn't find a relation, so no need for locking or permission checks. */
1685  if (!OidIsValid(relOid))
1686  return;
1687 
1688  tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relOid));
1689  if (!HeapTupleIsValid(tuple))
1690  return; /* concurrently dropped, so nothing to do */
1691  classform = (Form_pg_class) GETSTRUCT(tuple);
1692  is_partition = classform->relispartition;
1693 
1694  /* Pass back some data to save lookups in RemoveRelations */
1695  state->actual_relkind = classform->relkind;
1696  state->actual_relpersistence = classform->relpersistence;
1697 
1698  /*
1699  * Both RELKIND_RELATION and RELKIND_PARTITIONED_TABLE are OBJECT_TABLE,
1700  * but RemoveRelations() can only pass one relkind for a given relation.
1701  * It chooses RELKIND_RELATION for both regular and partitioned tables.
1702  * That means we must be careful before giving the wrong type error when
1703  * the relation is RELKIND_PARTITIONED_TABLE. An equivalent problem
1704  * exists with indexes.
1705  */
1706  if (classform->relkind == RELKIND_PARTITIONED_TABLE)
1707  expected_relkind = RELKIND_RELATION;
1708  else if (classform->relkind == RELKIND_PARTITIONED_INDEX)
1709  expected_relkind = RELKIND_INDEX;
1710  else
1711  expected_relkind = classform->relkind;
1712 
1713  if (state->expected_relkind != expected_relkind)
1714  DropErrorMsgWrongType(rel->relname, classform->relkind,
1715  state->expected_relkind);
1716 
1717  /* Allow DROP to either table owner or schema owner */
1718  if (!object_ownercheck(RelationRelationId, relOid, GetUserId()) &&
1719  !object_ownercheck(NamespaceRelationId, classform->relnamespace, GetUserId()))
1721  get_relkind_objtype(classform->relkind),
1722  rel->relname);
1723 
1724  /*
1725  * Check the case of a system index that might have been invalidated by a
1726  * failed concurrent process and allow its drop. For the time being, this
1727  * only concerns indexes of toast relations that became invalid during a
1728  * REINDEX CONCURRENTLY process.
1729  */
1730  if (IsSystemClass(relOid, classform) && classform->relkind == RELKIND_INDEX)
1731  {
1732  HeapTuple locTuple;
1733  Form_pg_index indexform;
1734  bool indisvalid;
1735 
1736  locTuple = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(relOid));
1737  if (!HeapTupleIsValid(locTuple))
1738  {
1739  ReleaseSysCache(tuple);
1740  return;
1741  }
1742 
1743  indexform = (Form_pg_index) GETSTRUCT(locTuple);
1744  indisvalid = indexform->indisvalid;
1745  ReleaseSysCache(locTuple);
1746 
1747  /* Mark object as being an invalid index of system catalogs */
1748  if (!indisvalid)
1749  invalid_system_index = true;
1750  }
1751 
1752  /* In the case of an invalid index, it is fine to bypass this check */
1753  if (!invalid_system_index && !allowSystemTableMods && IsSystemClass(relOid, classform))
1754  ereport(ERROR,
1755  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1756  errmsg("permission denied: \"%s\" is a system catalog",
1757  rel->relname)));
1758 
1759  ReleaseSysCache(tuple);
1760 
1761  /*
1762  * In DROP INDEX, attempt to acquire lock on the parent table before
1763  * locking the index. index_drop() will need this anyway, and since
1764  * regular queries lock tables before their indexes, we risk deadlock if
1765  * we do it the other way around. No error if we don't find a pg_index
1766  * entry, though --- the relation may have been dropped. Note that this
1767  * code will execute for either plain or partitioned indexes.
1768  */
1769  if (expected_relkind == RELKIND_INDEX &&
1770  relOid != oldRelOid)
1771  {
1772  state->heapOid = IndexGetRelation(relOid, true);
1773  if (OidIsValid(state->heapOid))
1774  LockRelationOid(state->heapOid, heap_lockmode);
1775  }
1776 
1777  /*
1778  * Similarly, if the relation is a partition, we must acquire lock on its
1779  * parent before locking the partition. That's because queries lock the
1780  * parent before its partitions, so we risk deadlock if we do it the other
1781  * way around.
1782  */
1783  if (is_partition && relOid != oldRelOid)
1784  {
1785  state->partParentOid = get_partition_parent(relOid, true);
1786  if (OidIsValid(state->partParentOid))
1787  LockRelationOid(state->partParentOid, AccessExclusiveLock);
1788  }
1789 }
1790 
1791 /*
1792  * ExecuteTruncate
1793  * Executes a TRUNCATE command.
1794  *
1795  * This is a multi-relation truncate. We first open and grab exclusive
1796  * lock on all relations involved, checking permissions and otherwise
1797  * verifying that the relation is OK for truncation. Note that if relations
1798  * are foreign tables, at this stage, we have not yet checked that their
1799  * foreign data in external data sources are OK for truncation. These are
1800  * checked when foreign data are actually truncated later. In CASCADE mode,
1801  * relations having FK references to the targeted relations are automatically
1802  * added to the group; in RESTRICT mode, we check that all FK references are
1803  * internal to the group that's being truncated. Finally all the relations
1804  * are truncated and reindexed.
1805  */
1806 void
1808 {
1809  List *rels = NIL;
1810  List *relids = NIL;
1811  List *relids_logged = NIL;
1812  ListCell *cell;
1813 
1814  /*
1815  * Open, exclusive-lock, and check all the explicitly-specified relations
1816  */
1817  foreach(cell, stmt->relations)
1818  {
1819  RangeVar *rv = lfirst(cell);
1820  Relation rel;
1821  bool recurse = rv->inh;
1822  Oid myrelid;
1823  LOCKMODE lockmode = AccessExclusiveLock;
1824 
1825  myrelid = RangeVarGetRelidExtended(rv, lockmode,
1827  NULL);
1828 
1829  /* don't throw error for "TRUNCATE foo, foo" */
1830  if (list_member_oid(relids, myrelid))
1831  continue;
1832 
1833  /* open the relation, we already hold a lock on it */
1834  rel = table_open(myrelid, NoLock);
1835 
1836  /*
1837  * RangeVarGetRelidExtended() has done most checks with its callback,
1838  * but other checks with the now-opened Relation remain.
1839  */
1841 
1842  rels = lappend(rels, rel);
1843  relids = lappend_oid(relids, myrelid);
1844 
1845  /* Log this relation only if needed for logical decoding */
1846  if (RelationIsLogicallyLogged(rel))
1847  relids_logged = lappend_oid(relids_logged, myrelid);
1848 
1849  if (recurse)
1850  {
1851  ListCell *child;
1852  List *children;
1853 
1854  children = find_all_inheritors(myrelid, lockmode, NULL);
1855 
1856  foreach(child, children)
1857  {
1858  Oid childrelid = lfirst_oid(child);
1859 
1860  if (list_member_oid(relids, childrelid))
1861  continue;
1862 
1863  /* find_all_inheritors already got lock */
1864  rel = table_open(childrelid, NoLock);
1865 
1866  /*
1867  * It is possible that the parent table has children that are
1868  * temp tables of other backends. We cannot safely access
1869  * such tables (because of buffering issues), and the best
1870  * thing to do is to silently ignore them. Note that this
1871  * check is the same as one of the checks done in
1872  * truncate_check_activity() called below, still it is kept
1873  * here for simplicity.
1874  */
1875  if (RELATION_IS_OTHER_TEMP(rel))
1876  {
1877  table_close(rel, lockmode);
1878  continue;
1879  }
1880 
1881  /*
1882  * Inherited TRUNCATE commands perform access permission
1883  * checks on the parent table only. So we skip checking the
1884  * children's permissions and don't call
1885  * truncate_check_perms() here.
1886  */
1889 
1890  rels = lappend(rels, rel);
1891  relids = lappend_oid(relids, childrelid);
1892 
1893  /* Log this relation only if needed for logical decoding */
1894  if (RelationIsLogicallyLogged(rel))
1895  relids_logged = lappend_oid(relids_logged, childrelid);
1896  }
1897  }
1898  else if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
1899  ereport(ERROR,
1900  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1901  errmsg("cannot truncate only a partitioned table"),
1902  errhint("Do not specify the ONLY keyword, or use TRUNCATE ONLY on the partitions directly.")));
1903  }
1904 
1905  ExecuteTruncateGuts(rels, relids, relids_logged,
1906  stmt->behavior, stmt->restart_seqs, false);
1907 
1908  /* And close the rels */
1909  foreach(cell, rels)
1910  {
1911  Relation rel = (Relation) lfirst(cell);
1912 
1913  table_close(rel, NoLock);
1914  }
1915 }
1916 
1917 /*
1918  * ExecuteTruncateGuts
1919  *
1920  * Internal implementation of TRUNCATE. This is called by the actual TRUNCATE
1921  * command (see above) as well as replication subscribers that execute a
1922  * replicated TRUNCATE action.
1923  *
1924  * explicit_rels is the list of Relations to truncate that the command
1925  * specified. relids is the list of Oids corresponding to explicit_rels.
1926  * relids_logged is the list of Oids (a subset of relids) that require
1927  * WAL-logging. This is all a bit redundant, but the existing callers have
1928  * this information handy in this form.
1929  */
1930 void
1931 ExecuteTruncateGuts(List *explicit_rels,
1932  List *relids,
1933  List *relids_logged,
1934  DropBehavior behavior, bool restart_seqs,
1935  bool run_as_table_owner)
1936 {
1937  List *rels;
1938  List *seq_relids = NIL;
1939  HTAB *ft_htab = NULL;
1940  EState *estate;
1941  ResultRelInfo *resultRelInfos;
1942  ResultRelInfo *resultRelInfo;
1943  SubTransactionId mySubid;
1944  ListCell *cell;
1945  Oid *logrelids;
1946 
1947  /*
1948  * Check the explicitly-specified relations.
1949  *
1950  * In CASCADE mode, suck in all referencing relations as well. This
1951  * requires multiple iterations to find indirectly-dependent relations. At
1952  * each phase, we need to exclusive-lock new rels before looking for their
1953  * dependencies, else we might miss something. Also, we check each rel as
1954  * soon as we open it, to avoid a faux pas such as holding lock for a long
1955  * time on a rel we have no permissions for.
1956  */
1957  rels = list_copy(explicit_rels);
1958  if (behavior == DROP_CASCADE)
1959  {
1960  for (;;)
1961  {
1962  List *newrelids;
1963 
1964  newrelids = heap_truncate_find_FKs(relids);
1965  if (newrelids == NIL)
1966  break; /* nothing else to add */
1967 
1968  foreach(cell, newrelids)
1969  {
1970  Oid relid = lfirst_oid(cell);
1971  Relation rel;
1972 
1973  rel = table_open(relid, AccessExclusiveLock);
1974  ereport(NOTICE,
1975  (errmsg("truncate cascades to table \"%s\"",
1976  RelationGetRelationName(rel))));
1977  truncate_check_rel(relid, rel->rd_rel);
1978  truncate_check_perms(relid, rel->rd_rel);
1980  rels = lappend(rels, rel);
1981  relids = lappend_oid(relids, relid);
1982 
1983  /* Log this relation only if needed for logical decoding */
1984  if (RelationIsLogicallyLogged(rel))
1985  relids_logged = lappend_oid(relids_logged, relid);
1986  }
1987  }
1988  }
1989 
1990  /*
1991  * Check foreign key references. In CASCADE mode, this should be
1992  * unnecessary since we just pulled in all the references; but as a
1993  * cross-check, do it anyway if in an Assert-enabled build.
1994  */
1995 #ifdef USE_ASSERT_CHECKING
1996  heap_truncate_check_FKs(rels, false);
1997 #else
1998  if (behavior == DROP_RESTRICT)
1999  heap_truncate_check_FKs(rels, false);
2000 #endif
2001 
2002  /*
2003  * If we are asked to restart sequences, find all the sequences, lock them
2004  * (we need AccessExclusiveLock for ResetSequence), and check permissions.
2005  * We want to do this early since it's pointless to do all the truncation
2006  * work only to fail on sequence permissions.
2007  */
2008  if (restart_seqs)
2009  {
2010  foreach(cell, rels)
2011  {
2012  Relation rel = (Relation) lfirst(cell);
2013  List *seqlist = getOwnedSequences(RelationGetRelid(rel));
2014  ListCell *seqcell;
2015 
2016  foreach(seqcell, seqlist)
2017  {
2018  Oid seq_relid = lfirst_oid(seqcell);
2019  Relation seq_rel;
2020 
2021  seq_rel = relation_open(seq_relid, AccessExclusiveLock);
2022 
2023  /* This check must match AlterSequence! */
2024  if (!object_ownercheck(RelationRelationId, seq_relid, GetUserId()))
2026  RelationGetRelationName(seq_rel));
2027 
2028  seq_relids = lappend_oid(seq_relids, seq_relid);
2029 
2030  relation_close(seq_rel, NoLock);
2031  }
2032  }
2033  }
2034 
2035  /* Prepare to catch AFTER triggers. */
2037 
2038  /*
2039  * To fire triggers, we'll need an EState as well as a ResultRelInfo for
2040  * each relation. We don't need to call ExecOpenIndices, though.
2041  *
2042  * We put the ResultRelInfos in the es_opened_result_relations list, even
2043  * though we don't have a range table and don't populate the
2044  * es_result_relations array. That's a bit bogus, but it's enough to make
2045  * ExecGetTriggerResultRel() find them.
2046  */
2047  estate = CreateExecutorState();
2048  resultRelInfos = (ResultRelInfo *)
2049  palloc(list_length(rels) * sizeof(ResultRelInfo));
2050  resultRelInfo = resultRelInfos;
2051  foreach(cell, rels)
2052  {
2053  Relation rel = (Relation) lfirst(cell);
2054 
2055  InitResultRelInfo(resultRelInfo,
2056  rel,
2057  0, /* dummy rangetable index */
2058  NULL,
2059  0);
2060  estate->es_opened_result_relations =
2061  lappend(estate->es_opened_result_relations, resultRelInfo);
2062  resultRelInfo++;
2063  }
2064 
2065  /*
2066  * Process all BEFORE STATEMENT TRUNCATE triggers before we begin
2067  * truncating (this is because one of them might throw an error). Also, if
2068  * we were to allow them to prevent statement execution, that would need
2069  * to be handled here.
2070  */
2071  resultRelInfo = resultRelInfos;
2072  foreach(cell, rels)
2073  {
2074  UserContext ucxt;
2075 
2076  if (run_as_table_owner)
2077  SwitchToUntrustedUser(resultRelInfo->ri_RelationDesc->rd_rel->relowner,
2078  &ucxt);
2079  ExecBSTruncateTriggers(estate, resultRelInfo);
2080  if (run_as_table_owner)
2081  RestoreUserContext(&ucxt);
2082  resultRelInfo++;
2083  }
2084 
2085  /*
2086  * OK, truncate each table.
2087  */
2088  mySubid = GetCurrentSubTransactionId();
2089 
2090  foreach(cell, rels)
2091  {
2092  Relation rel = (Relation) lfirst(cell);
2093 
2094  /* Skip partitioned tables as there is nothing to do */
2095  if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
2096  continue;
2097 
2098  /*
2099  * Build the lists of foreign tables belonging to each foreign server
2100  * and pass each list to the foreign data wrapper's callback function,
2101  * so that each server can truncate its all foreign tables in bulk.
2102  * Each list is saved as a single entry in a hash table that uses the
2103  * server OID as lookup key.
2104  */
2105  if (rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
2106  {
2108  bool found;
2109  ForeignTruncateInfo *ft_info;
2110 
2111  /* First time through, initialize hashtable for foreign tables */
2112  if (!ft_htab)
2113  {
2114  HASHCTL hctl;
2115 
2116  memset(&hctl, 0, sizeof(HASHCTL));
2117  hctl.keysize = sizeof(Oid);
2118  hctl.entrysize = sizeof(ForeignTruncateInfo);
2119  hctl.hcxt = CurrentMemoryContext;
2120 
2121  ft_htab = hash_create("TRUNCATE for Foreign Tables",
2122  32, /* start small and extend */
2123  &hctl,
2125  }
2126 
2127  /* Find or create cached entry for the foreign table */
2128  ft_info = hash_search(ft_htab, &serverid, HASH_ENTER, &found);
2129  if (!found)
2130  ft_info->rels = NIL;
2131 
2132  /*
2133  * Save the foreign table in the entry of the server that the
2134  * foreign table belongs to.
2135  */
2136  ft_info->rels = lappend(ft_info->rels, rel);
2137  continue;
2138  }
2139 
2140  /*
2141  * Normally, we need a transaction-safe truncation here. However, if
2142  * the table was either created in the current (sub)transaction or has
2143  * a new relfilenumber in the current (sub)transaction, then we can
2144  * just truncate it in-place, because a rollback would cause the whole
2145  * table or the current physical file to be thrown away anyway.
2146  */
2147  if (rel->rd_createSubid == mySubid ||
2148  rel->rd_newRelfilelocatorSubid == mySubid)
2149  {
2150  /* Immediate, non-rollbackable truncation is OK */
2151  heap_truncate_one_rel(rel);
2152  }
2153  else
2154  {
2155  Oid heap_relid;
2156  Oid toast_relid;
2157  ReindexParams reindex_params = {0};
2158 
2159  /*
2160  * This effectively deletes all rows in the table, and may be done
2161  * in a serializable transaction. In that case we must record a
2162  * rw-conflict in to this transaction from each transaction
2163  * holding a predicate lock on the table.
2164  */
2166 
2167  /*
2168  * Need the full transaction-safe pushups.
2169  *
2170  * Create a new empty storage file for the relation, and assign it
2171  * as the relfilenumber value. The old storage file is scheduled
2172  * for deletion at commit.
2173  */
2174  RelationSetNewRelfilenumber(rel, rel->rd_rel->relpersistence);
2175 
2176  heap_relid = RelationGetRelid(rel);
2177 
2178  /*
2179  * The same for the toast table, if any.
2180  */
2181  toast_relid = rel->rd_rel->reltoastrelid;
2182  if (OidIsValid(toast_relid))
2183  {
2184  Relation toastrel = relation_open(toast_relid,
2186 
2187  RelationSetNewRelfilenumber(toastrel,
2188  toastrel->rd_rel->relpersistence);
2189  table_close(toastrel, NoLock);
2190  }
2191 
2192  /*
2193  * Reconstruct the indexes to match, and we're done.
2194  */
2195  reindex_relation(NULL, heap_relid, REINDEX_REL_PROCESS_TOAST,
2196  &reindex_params);
2197  }
2198 
2199  pgstat_count_truncate(rel);
2200  }
2201 
2202  /* Now go through the hash table, and truncate foreign tables */
2203  if (ft_htab)
2204  {
2205  ForeignTruncateInfo *ft_info;
2206  HASH_SEQ_STATUS seq;
2207 
2208  hash_seq_init(&seq, ft_htab);
2209 
2210  PG_TRY();
2211  {
2212  while ((ft_info = hash_seq_search(&seq)) != NULL)
2213  {
2214  FdwRoutine *routine = GetFdwRoutineByServerId(ft_info->serverid);
2215 
2216  /* truncate_check_rel() has checked that already */
2217  Assert(routine->ExecForeignTruncate != NULL);
2218 
2219  routine->ExecForeignTruncate(ft_info->rels,
2220  behavior,
2221  restart_seqs);
2222  }
2223  }
2224  PG_FINALLY();
2225  {
2226  hash_destroy(ft_htab);
2227  }
2228  PG_END_TRY();
2229  }
2230 
2231  /*
2232  * Restart owned sequences if we were asked to.
2233  */
2234  foreach(cell, seq_relids)
2235  {
2236  Oid seq_relid = lfirst_oid(cell);
2237 
2238  ResetSequence(seq_relid);
2239  }
2240 
2241  /*
2242  * Write a WAL record to allow this set of actions to be logically
2243  * decoded.
2244  *
2245  * Assemble an array of relids so we can write a single WAL record for the
2246  * whole action.
2247  */
2248  if (relids_logged != NIL)
2249  {
2250  xl_heap_truncate xlrec;
2251  int i = 0;
2252 
2253  /* should only get here if wal_level >= logical */
2255 
2256  logrelids = palloc(list_length(relids_logged) * sizeof(Oid));
2257  foreach(cell, relids_logged)
2258  logrelids[i++] = lfirst_oid(cell);
2259 
2260  xlrec.dbId = MyDatabaseId;
2261  xlrec.nrelids = list_length(relids_logged);
2262  xlrec.flags = 0;
2263  if (behavior == DROP_CASCADE)
2264  xlrec.flags |= XLH_TRUNCATE_CASCADE;
2265  if (restart_seqs)
2267 
2268  XLogBeginInsert();
2269  XLogRegisterData((char *) &xlrec, SizeOfHeapTruncate);
2270  XLogRegisterData((char *) logrelids, list_length(relids_logged) * sizeof(Oid));
2271 
2273 
2274  (void) XLogInsert(RM_HEAP_ID, XLOG_HEAP_TRUNCATE);
2275  }
2276 
2277  /*
2278  * Process all AFTER STATEMENT TRUNCATE triggers.
2279  */
2280  resultRelInfo = resultRelInfos;
2281  foreach(cell, rels)
2282  {
2283  UserContext ucxt;
2284 
2285  if (run_as_table_owner)
2286  SwitchToUntrustedUser(resultRelInfo->ri_RelationDesc->rd_rel->relowner,
2287  &ucxt);
2288  ExecASTruncateTriggers(estate, resultRelInfo);
2289  if (run_as_table_owner)
2290  RestoreUserContext(&ucxt);
2291  resultRelInfo++;
2292  }
2293 
2294  /* Handle queued AFTER triggers */
2295  AfterTriggerEndQuery(estate);
2296 
2297  /* We can clean up the EState now */
2298  FreeExecutorState(estate);
2299 
2300  /*
2301  * Close any rels opened by CASCADE (can't do this while EState still
2302  * holds refs)
2303  */
2304  rels = list_difference_ptr(rels, explicit_rels);
2305  foreach(cell, rels)
2306  {
2307  Relation rel = (Relation) lfirst(cell);
2308 
2309  table_close(rel, NoLock);
2310  }
2311 }
2312 
2313 /*
2314  * Check that a given relation is safe to truncate. Subroutine for
2315  * ExecuteTruncate() and RangeVarCallbackForTruncate().
2316  */
2317 static void
2319 {
2320  char *relname = NameStr(reltuple->relname);
2321 
2322  /*
2323  * Only allow truncate on regular tables, foreign tables using foreign
2324  * data wrappers supporting TRUNCATE and partitioned tables (although, the
2325  * latter are only being included here for the following checks; no
2326  * physical truncation will occur in their case.).
2327  */
2328  if (reltuple->relkind == RELKIND_FOREIGN_TABLE)
2329  {
2330  Oid serverid = GetForeignServerIdByRelId(relid);
2331  FdwRoutine *fdwroutine = GetFdwRoutineByServerId(serverid);
2332 
2333  if (!fdwroutine->ExecForeignTruncate)
2334  ereport(ERROR,
2335  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2336  errmsg("cannot truncate foreign table \"%s\"",
2337  relname)));
2338  }
2339  else if (reltuple->relkind != RELKIND_RELATION &&
2340  reltuple->relkind != RELKIND_PARTITIONED_TABLE)
2341  ereport(ERROR,
2342  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2343  errmsg("\"%s\" is not a table", relname)));
2344 
2345  /*
2346  * Most system catalogs can't be truncated at all, or at least not unless
2347  * allow_system_table_mods=on. As an exception, however, we allow
2348  * pg_largeobject to be truncated as part of pg_upgrade, because we need
2349  * to change its relfilenode to match the old cluster, and allowing a
2350  * TRUNCATE command to be executed is the easiest way of doing that.
2351  */
2352  if (!allowSystemTableMods && IsSystemClass(relid, reltuple)
2353  && (!IsBinaryUpgrade || relid != LargeObjectRelationId))
2354  ereport(ERROR,
2355  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
2356  errmsg("permission denied: \"%s\" is a system catalog",
2357  relname)));
2358 
2359  InvokeObjectTruncateHook(relid);
2360 }
2361 
2362 /*
2363  * Check that current user has the permission to truncate given relation.
2364  */
2365 static void
2367 {
2368  char *relname = NameStr(reltuple->relname);
2369  AclResult aclresult;
2370 
2371  /* Permissions checks */
2372  aclresult = pg_class_aclcheck(relid, GetUserId(), ACL_TRUNCATE);
2373  if (aclresult != ACLCHECK_OK)
2374  aclcheck_error(aclresult, get_relkind_objtype(reltuple->relkind),
2375  relname);
2376 }
2377 
2378 /*
2379  * Set of extra sanity checks to check if a given relation is safe to
2380  * truncate. This is split with truncate_check_rel() as
2381  * RangeVarCallbackForTruncate() cannot open a Relation yet.
2382  */
2383 static void
2385 {
2386  /*
2387  * Don't allow truncate on temp tables of other backends ... their local
2388  * buffer manager is not going to cope.
2389  */
2390  if (RELATION_IS_OTHER_TEMP(rel))
2391  ereport(ERROR,
2392  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2393  errmsg("cannot truncate temporary tables of other sessions")));
2394 
2395  /*
2396  * Also check for active uses of the relation in the current transaction,
2397  * including open scans and pending AFTER trigger events.
2398  */
2399  CheckTableNotInUse(rel, "TRUNCATE");
2400 }
2401 
2402 /*
2403  * storage_name
2404  * returns the name corresponding to a typstorage/attstorage enum value
2405  */
2406 static const char *
2408 {
2409  switch (c)
2410  {
2411  case TYPSTORAGE_PLAIN:
2412  return "PLAIN";
2413  case TYPSTORAGE_EXTERNAL:
2414  return "EXTERNAL";
2415  case TYPSTORAGE_EXTENDED:
2416  return "EXTENDED";
2417  case TYPSTORAGE_MAIN:
2418  return "MAIN";
2419  default:
2420  return "???";
2421  }
2422 }
2423 
2424 /*----------
2425  * MergeAttributes
2426  * Returns new schema given initial schema and superclasses.
2427  *
2428  * Input arguments:
2429  * 'columns' is the column/attribute definition for the table. (It's a list
2430  * of ColumnDef's.) It is destructively changed.
2431  * 'supers' is a list of OIDs of parent relations, already locked by caller.
2432  * 'relpersistence' is the persistence type of the table.
2433  * 'is_partition' tells if the table is a partition.
2434  *
2435  * Output arguments:
2436  * 'supconstr' receives a list of constraints belonging to the parents,
2437  * updated as necessary to be valid for the child.
2438  * 'supnotnulls' receives a list of CookedConstraints that corresponds to
2439  * constraints coming from inheritance parents.
2440  *
2441  * Return value:
2442  * Completed schema list.
2443  *
2444  * Notes:
2445  * The order in which the attributes are inherited is very important.
2446  * Intuitively, the inherited attributes should come first. If a table
2447  * inherits from multiple parents, the order of those attributes are
2448  * according to the order of the parents specified in CREATE TABLE.
2449  *
2450  * Here's an example:
2451  *
2452  * create table person (name text, age int4, location point);
2453  * create table emp (salary int4, manager text) inherits(person);
2454  * create table student (gpa float8) inherits (person);
2455  * create table stud_emp (percent int4) inherits (emp, student);
2456  *
2457  * The order of the attributes of stud_emp is:
2458  *
2459  * person {1:name, 2:age, 3:location}
2460  * / \
2461  * {6:gpa} student emp {4:salary, 5:manager}
2462  * \ /
2463  * stud_emp {7:percent}
2464  *
2465  * If the same attribute name appears multiple times, then it appears
2466  * in the result table in the proper location for its first appearance.
2467  *
2468  * Constraints (including not-null constraints) for the child table
2469  * are the union of all relevant constraints, from both the child schema
2470  * and parent tables. In addition, in legacy inheritance, each column that
2471  * appears in a primary key in any of the parents also gets a NOT NULL
2472  * constraint (partitioning doesn't need this, because the PK itself gets
2473  * inherited.)
2474  *
2475  * The default value for a child column is defined as:
2476  * (1) If the child schema specifies a default, that value is used.
2477  * (2) If neither the child nor any parent specifies a default, then
2478  * the column will not have a default.
2479  * (3) If conflicting defaults are inherited from different parents
2480  * (and not overridden by the child), an error is raised.
2481  * (4) Otherwise the inherited default is used.
2482  *
2483  * Note that the default-value infrastructure is used for generated
2484  * columns' expressions too, so most of the preceding paragraph applies
2485  * to generation expressions too. We insist that a child column be
2486  * generated if and only if its parent(s) are, but it need not have
2487  * the same generation expression.
2488  *----------
2489  */
2490 static List *
2491 MergeAttributes(List *columns, const List *supers, char relpersistence,
2492  bool is_partition, List **supconstr, List **supnotnulls)
2493 {
2494  List *inh_columns = NIL;
2495  List *constraints = NIL;
2496  List *nnconstraints = NIL;
2497  bool have_bogus_defaults = false;
2498  int child_attno;
2499  static Node bogus_marker = {0}; /* marks conflicting defaults */
2500  List *saved_columns = NIL;
2501  ListCell *lc;
2502 
2503  /*
2504  * Check for and reject tables with too many columns. We perform this
2505  * check relatively early for two reasons: (a) we don't run the risk of
2506  * overflowing an AttrNumber in subsequent code (b) an O(n^2) algorithm is
2507  * okay if we're processing <= 1600 columns, but could take minutes to
2508  * execute if the user attempts to create a table with hundreds of
2509  * thousands of columns.
2510  *
2511  * Note that we also need to check that we do not exceed this figure after
2512  * including columns from inherited relations.
2513  */
2514  if (list_length(columns) > MaxHeapAttributeNumber)
2515  ereport(ERROR,
2516  (errcode(ERRCODE_TOO_MANY_COLUMNS),
2517  errmsg("tables can have at most %d columns",
2519 
2520  /*
2521  * Check for duplicate names in the explicit list of attributes.
2522  *
2523  * Although we might consider merging such entries in the same way that we
2524  * handle name conflicts for inherited attributes, it seems to make more
2525  * sense to assume such conflicts are errors.
2526  *
2527  * We don't use foreach() here because we have two nested loops over the
2528  * columns list, with possible element deletions in the inner one. If we
2529  * used foreach_delete_current() it could only fix up the state of one of
2530  * the loops, so it seems cleaner to use looping over list indexes for
2531  * both loops. Note that any deletion will happen beyond where the outer
2532  * loop is, so its index never needs adjustment.
2533  */
2534  for (int coldefpos = 0; coldefpos < list_length(columns); coldefpos++)
2535  {
2536  ColumnDef *coldef = list_nth_node(ColumnDef, columns, coldefpos);
2537 
2538  if (!is_partition && coldef->typeName == NULL)
2539  {
2540  /*
2541  * Typed table column option that does not belong to a column from
2542  * the type. This works because the columns from the type come
2543  * first in the list. (We omit this check for partition column
2544  * lists; those are processed separately below.)
2545  */
2546  ereport(ERROR,
2547  (errcode(ERRCODE_UNDEFINED_COLUMN),
2548  errmsg("column \"%s\" does not exist",
2549  coldef->colname)));
2550  }
2551 
2552  /* restpos scans all entries beyond coldef; incr is in loop body */
2553  for (int restpos = coldefpos + 1; restpos < list_length(columns);)
2554  {
2555  ColumnDef *restdef = list_nth_node(ColumnDef, columns, restpos);
2556 
2557  if (strcmp(coldef->colname, restdef->colname) == 0)
2558  {
2559  if (coldef->is_from_type)
2560  {
2561  /*
2562  * merge the column options into the column from the type
2563  */
2564  coldef->is_not_null = restdef->is_not_null;
2565  coldef->raw_default = restdef->raw_default;
2566  coldef->cooked_default = restdef->cooked_default;
2567  coldef->constraints = restdef->constraints;
2568  coldef->is_from_type = false;
2569  columns = list_delete_nth_cell(columns, restpos);
2570  }
2571  else
2572  ereport(ERROR,
2573  (errcode(ERRCODE_DUPLICATE_COLUMN),
2574  errmsg("column \"%s\" specified more than once",
2575  coldef->colname)));
2576  }
2577  else
2578  restpos++;
2579  }
2580  }
2581 
2582  /*
2583  * In case of a partition, there are no new column definitions, only dummy
2584  * ColumnDefs created for column constraints. Set them aside for now and
2585  * process them at the end.
2586  */
2587  if (is_partition)
2588  {
2589  saved_columns = columns;
2590  columns = NIL;
2591  }
2592 
2593  /*
2594  * Scan the parents left-to-right, and merge their attributes to form a
2595  * list of inherited columns (inh_columns).
2596  */
2597  child_attno = 0;
2598  foreach(lc, supers)
2599  {
2600  Oid parent = lfirst_oid(lc);
2601  Relation relation;
2602  TupleDesc tupleDesc;
2603  TupleConstr *constr;
2604  AttrMap *newattmap;
2605  List *inherited_defaults;
2606  List *cols_with_defaults;
2607  List *nnconstrs;
2608  ListCell *lc1;
2609  ListCell *lc2;
2610  Bitmapset *pkattrs;
2611  Bitmapset *nncols = NULL;
2612 
2613  /* caller already got lock */
2614  relation = table_open(parent, NoLock);
2615 
2616  /*
2617  * Check for active uses of the parent partitioned table in the
2618  * current transaction, such as being used in some manner by an
2619  * enclosing command.
2620  */
2621  if (is_partition)
2622  CheckTableNotInUse(relation, "CREATE TABLE .. PARTITION OF");
2623 
2624  /*
2625  * We do not allow partitioned tables and partitions to participate in
2626  * regular inheritance.
2627  */
2628  if (relation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE && !is_partition)
2629  ereport(ERROR,
2630  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2631  errmsg("cannot inherit from partitioned table \"%s\"",
2632  RelationGetRelationName(relation))));
2633  if (relation->rd_rel->relispartition && !is_partition)
2634  ereport(ERROR,
2635  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2636  errmsg("cannot inherit from partition \"%s\"",
2637  RelationGetRelationName(relation))));
2638 
2639  if (relation->rd_rel->relkind != RELKIND_RELATION &&
2640  relation->rd_rel->relkind != RELKIND_FOREIGN_TABLE &&
2641  relation->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
2642  ereport(ERROR,
2643  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2644  errmsg("inherited relation \"%s\" is not a table or foreign table",
2645  RelationGetRelationName(relation))));
2646 
2647  /*
2648  * If the parent is permanent, so must be all of its partitions. Note
2649  * that inheritance allows that case.
2650  */
2651  if (is_partition &&
2652  relation->rd_rel->relpersistence != RELPERSISTENCE_TEMP &&
2653  relpersistence == RELPERSISTENCE_TEMP)
2654  ereport(ERROR,
2655  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2656  errmsg("cannot create a temporary relation as partition of permanent relation \"%s\"",
2657  RelationGetRelationName(relation))));
2658 
2659  /* Permanent rels cannot inherit from temporary ones */
2660  if (relpersistence != RELPERSISTENCE_TEMP &&
2661  relation->rd_rel->relpersistence == RELPERSISTENCE_TEMP)
2662  ereport(ERROR,
2663  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2664  errmsg(!is_partition
2665  ? "cannot inherit from temporary relation \"%s\""
2666  : "cannot create a permanent relation as partition of temporary relation \"%s\"",
2667  RelationGetRelationName(relation))));
2668 
2669  /* If existing rel is temp, it must belong to this session */
2670  if (relation->rd_rel->relpersistence == RELPERSISTENCE_TEMP &&
2671  !relation->rd_islocaltemp)
2672  ereport(ERROR,
2673  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2674  errmsg(!is_partition
2675  ? "cannot inherit from temporary relation of another session"
2676  : "cannot create as partition of temporary relation of another session")));
2677 
2678  /*
2679  * We should have an UNDER permission flag for this, but for now,
2680  * demand that creator of a child table own the parent.
2681  */
2682  if (!object_ownercheck(RelationRelationId, RelationGetRelid(relation), GetUserId()))
2684  RelationGetRelationName(relation));
2685 
2686  tupleDesc = RelationGetDescr(relation);
2687  constr = tupleDesc->constr;
2688 
2689  /*
2690  * newattmap->attnums[] will contain the child-table attribute numbers
2691  * for the attributes of this parent table. (They are not the same
2692  * for parents after the first one, nor if we have dropped columns.)
2693  */
2694  newattmap = make_attrmap(tupleDesc->natts);
2695 
2696  /* We can't process inherited defaults until newattmap is complete. */
2697  inherited_defaults = cols_with_defaults = NIL;
2698 
2699  /*
2700  * All columns that are part of the parent's primary key need to be
2701  * NOT NULL; if partition just the attnotnull bit, otherwise a full
2702  * constraint (if they don't have one already). Also, we request
2703  * attnotnull on columns that have a not-null constraint that's not
2704  * marked NO INHERIT.
2705  */
2706  pkattrs = RelationGetIndexAttrBitmap(relation,
2708  nnconstrs = RelationGetNotNullConstraints(RelationGetRelid(relation), true);
2709  foreach(lc1, nnconstrs)
2710  nncols = bms_add_member(nncols,
2711  ((CookedConstraint *) lfirst(lc1))->attnum);
2712 
2713  for (AttrNumber parent_attno = 1; parent_attno <= tupleDesc->natts;
2714  parent_attno++)
2715  {
2716  Form_pg_attribute attribute = TupleDescAttr(tupleDesc,
2717  parent_attno - 1);
2718  char *attributeName = NameStr(attribute->attname);
2719  int exist_attno;
2720  ColumnDef *newdef;
2721  ColumnDef *mergeddef;
2722 
2723  /*
2724  * Ignore dropped columns in the parent.
2725  */
2726  if (attribute->attisdropped)
2727  continue; /* leave newattmap->attnums entry as zero */
2728 
2729  /*
2730  * Create new column definition
2731  */
2732  newdef = makeColumnDef(attributeName, attribute->atttypid,
2733  attribute->atttypmod, attribute->attcollation);
2734  newdef->storage = attribute->attstorage;
2735  newdef->generated = attribute->attgenerated;
2736  if (CompressionMethodIsValid(attribute->attcompression))
2737  newdef->compression =
2738  pstrdup(GetCompressionMethodName(attribute->attcompression));
2739 
2740  /*
2741  * Regular inheritance children are independent enough not to
2742  * inherit identity columns. But partitions are integral part of
2743  * a partitioned table and inherit identity column.
2744  */
2745  if (is_partition)
2746  newdef->identity = attribute->attidentity;
2747 
2748  /*
2749  * Does it match some previously considered column from another
2750  * parent?
2751  */
2752  exist_attno = findAttrByName(attributeName, inh_columns);
2753  if (exist_attno > 0)
2754  {
2755  /*
2756  * Yes, try to merge the two column definitions.
2757  */
2758  mergeddef = MergeInheritedAttribute(inh_columns, exist_attno, newdef);
2759 
2760  newattmap->attnums[parent_attno - 1] = exist_attno;
2761 
2762  /*
2763  * Partitions have only one parent, so conflict should never
2764  * occur.
2765  */
2766  Assert(!is_partition);
2767  }
2768  else
2769  {
2770  /*
2771  * No, create a new inherited column
2772  */
2773  newdef->inhcount = 1;
2774  newdef->is_local = false;
2775  inh_columns = lappend(inh_columns, newdef);
2776 
2777  newattmap->attnums[parent_attno - 1] = ++child_attno;
2778 
2779  mergeddef = newdef;
2780  }
2781 
2782  /*
2783  * mark attnotnull if parent has it and it's not NO INHERIT
2784  */
2785  if (bms_is_member(parent_attno, nncols) ||
2787  pkattrs))
2788  mergeddef->is_not_null = true;
2789 
2790  /*
2791  * In regular inheritance, columns in the parent's primary key get
2792  * an extra not-null constraint. Partitioning doesn't need this,
2793  * because the PK itself is going to be cloned to the partition.
2794  */
2795  if (!is_partition &&
2796  bms_is_member(parent_attno -
2798  pkattrs))
2799  {
2800  CookedConstraint *nn;
2801 
2802  nn = palloc(sizeof(CookedConstraint));
2803  nn->contype = CONSTR_NOTNULL;
2804  nn->conoid = InvalidOid;
2805  nn->name = NULL;
2806  nn->attnum = newattmap->attnums[parent_attno - 1];
2807  nn->expr = NULL;
2808  nn->skip_validation = false;
2809  nn->is_local = false;
2810  nn->inhcount = 1;
2811  nn->is_no_inherit = false;
2812 
2813  nnconstraints = lappend(nnconstraints, nn);
2814  }
2815 
2816  /*
2817  * Locate default/generation expression if any
2818  */
2819  if (attribute->atthasdef)
2820  {
2821  Node *this_default;
2822 
2823  this_default = TupleDescGetDefault(tupleDesc, parent_attno);
2824  if (this_default == NULL)
2825  elog(ERROR, "default expression not found for attribute %d of relation \"%s\"",
2826  parent_attno, RelationGetRelationName(relation));
2827 
2828  /*
2829  * If it's a GENERATED default, it might contain Vars that
2830  * need to be mapped to the inherited column(s)' new numbers.
2831  * We can't do that till newattmap is ready, so just remember
2832  * all the inherited default expressions for the moment.
2833  */
2834  inherited_defaults = lappend(inherited_defaults, this_default);
2835  cols_with_defaults = lappend(cols_with_defaults, mergeddef);
2836  }
2837  }
2838 
2839  /*
2840  * Now process any inherited default expressions, adjusting attnos
2841  * using the completed newattmap map.
2842  */
2843  forboth(lc1, inherited_defaults, lc2, cols_with_defaults)
2844  {
2845  Node *this_default = (Node *) lfirst(lc1);
2846  ColumnDef *def = (ColumnDef *) lfirst(lc2);
2847  bool found_whole_row;
2848 
2849  /* Adjust Vars to match new table's column numbering */
2850  this_default = map_variable_attnos(this_default,
2851  1, 0,
2852  newattmap,
2853  InvalidOid, &found_whole_row);
2854 
2855  /*
2856  * For the moment we have to reject whole-row variables. We could
2857  * convert them, if we knew the new table's rowtype OID, but that
2858  * hasn't been assigned yet. (A variable could only appear in a
2859  * generation expression, so the error message is correct.)
2860  */
2861  if (found_whole_row)
2862  ereport(ERROR,
2863  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2864  errmsg("cannot convert whole-row table reference"),
2865  errdetail("Generation expression for column \"%s\" contains a whole-row reference to table \"%s\".",
2866  def->colname,
2867  RelationGetRelationName(relation))));
2868 
2869  /*
2870  * If we already had a default from some prior parent, check to
2871  * see if they are the same. If so, no problem; if not, mark the
2872  * column as having a bogus default. Below, we will complain if
2873  * the bogus default isn't overridden by the child columns.
2874  */
2875  Assert(def->raw_default == NULL);
2876  if (def->cooked_default == NULL)
2877  def->cooked_default = this_default;
2878  else if (!equal(def->cooked_default, this_default))
2879  {
2880  def->cooked_default = &bogus_marker;
2881  have_bogus_defaults = true;
2882  }
2883  }
2884 
2885  /*
2886  * Now copy the CHECK constraints of this parent, adjusting attnos
2887  * using the completed newattmap map. Identically named constraints
2888  * are merged if possible, else we throw error.
2889  */
2890  if (constr && constr->num_check > 0)
2891  {
2892  ConstrCheck *check = constr->check;
2893 
2894  for (int i = 0; i < constr->num_check; i++)
2895  {
2896  char *name = check[i].ccname;
2897  Node *expr;
2898  bool found_whole_row;
2899 
2900  /* ignore if the constraint is non-inheritable */
2901  if (check[i].ccnoinherit)
2902  continue;
2903 
2904  /* Adjust Vars to match new table's column numbering */
2905  expr = map_variable_attnos(stringToNode(check[i].ccbin),
2906  1, 0,
2907  newattmap,
2908  InvalidOid, &found_whole_row);
2909 
2910  /*
2911  * For the moment we have to reject whole-row variables. We
2912  * could convert them, if we knew the new table's rowtype OID,
2913  * but that hasn't been assigned yet.
2914  */
2915  if (found_whole_row)
2916  ereport(ERROR,
2917  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2918  errmsg("cannot convert whole-row table reference"),
2919  errdetail("Constraint \"%s\" contains a whole-row reference to table \"%s\".",
2920  name,
2921  RelationGetRelationName(relation))));
2922 
2923  constraints = MergeCheckConstraint(constraints, name, expr);
2924  }
2925  }
2926 
2927  /*
2928  * Also copy the not-null constraints from this parent. The
2929  * attnotnull markings were already installed above.
2930  */
2931  foreach(lc1, nnconstrs)
2932  {
2933  CookedConstraint *nn = lfirst(lc1);
2934 
2935  Assert(nn->contype == CONSTR_NOTNULL);
2936 
2937  nn->attnum = newattmap->attnums[nn->attnum - 1];
2938  nn->is_local = false;
2939  nn->inhcount = 1;
2940 
2941  nnconstraints = lappend(nnconstraints, nn);
2942  }
2943 
2944  free_attrmap(newattmap);
2945 
2946  /*
2947  * Close the parent rel, but keep our lock on it until xact commit.
2948  * That will prevent someone else from deleting or ALTERing the parent
2949  * before the child is committed.
2950  */
2951  table_close(relation, NoLock);
2952  }
2953 
2954  /*
2955  * If we had no inherited attributes, the result columns are just the
2956  * explicitly declared columns. Otherwise, we need to merge the declared
2957  * columns into the inherited column list. Although, we never have any
2958  * explicitly declared columns if the table is a partition.
2959  */
2960  if (inh_columns != NIL)
2961  {
2962  int newcol_attno = 0;
2963 
2964  foreach(lc, columns)
2965  {
2966  ColumnDef *newdef = lfirst_node(ColumnDef, lc);
2967  char *attributeName = newdef->colname;
2968  int exist_attno;
2969 
2970  /*
2971  * Partitions have only one parent and have no column definitions
2972  * of their own, so conflict should never occur.
2973  */
2974  Assert(!is_partition);
2975 
2976  newcol_attno++;
2977 
2978  /*
2979  * Does it match some inherited column?
2980  */
2981  exist_attno = findAttrByName(attributeName, inh_columns);
2982  if (exist_attno > 0)
2983  {
2984  /*
2985  * Yes, try to merge the two column definitions.
2986  */
2987  MergeChildAttribute(inh_columns, exist_attno, newcol_attno, newdef);
2988  }
2989  else
2990  {
2991  /*
2992  * No, attach new column unchanged to result columns.
2993  */
2994  inh_columns = lappend(inh_columns, newdef);
2995  }
2996  }
2997 
2998  columns = inh_columns;
2999 
3000  /*
3001  * Check that we haven't exceeded the legal # of columns after merging
3002  * in inherited columns.
3003  */
3004  if (list_length(columns) > MaxHeapAttributeNumber)
3005  ereport(ERROR,
3006  (errcode(ERRCODE_TOO_MANY_COLUMNS),
3007  errmsg("tables can have at most %d columns",
3009  }
3010 
3011  /*
3012  * Now that we have the column definition list for a partition, we can
3013  * check whether the columns referenced in the column constraint specs
3014  * actually exist. Also, merge column defaults.
3015  */
3016  if (is_partition)
3017  {
3018  foreach(lc, saved_columns)
3019  {
3020  ColumnDef *restdef = lfirst(lc);
3021  bool found = false;
3022  ListCell *l;
3023 
3024  foreach(l, columns)
3025  {
3026  ColumnDef *coldef = lfirst(l);
3027 
3028  if (strcmp(coldef->colname, restdef->colname) == 0)
3029  {
3030  found = true;
3031 
3032  /*
3033  * Check for conflicts related to generated columns.
3034  *
3035  * Same rules as above: generated-ness has to match the
3036  * parent, but the contents of the generation expression
3037  * can be different.
3038  */
3039  if (coldef->generated)
3040  {
3041  if (restdef->raw_default && !restdef->generated)
3042  ereport(ERROR,
3043  (errcode(ERRCODE_INVALID_COLUMN_DEFINITION),
3044  errmsg("column \"%s\" inherits from generated column but specifies default",
3045  restdef->colname)));
3046  if (restdef->identity)
3047  ereport(ERROR,
3048  (errcode(ERRCODE_INVALID_COLUMN_DEFINITION),
3049  errmsg("column \"%s\" inherits from generated column but specifies identity",
3050  restdef->colname)));
3051  }
3052  else
3053  {
3054  if (restdef->generated)
3055  ereport(ERROR,
3056  (errcode(ERRCODE_INVALID_COLUMN_DEFINITION),
3057  errmsg("child column \"%s\" specifies generation expression",
3058  restdef->colname),
3059  errhint("A child table column cannot be generated unless its parent column is.")));
3060  }
3061 
3062  /*
3063  * Override the parent's default value for this column
3064  * (coldef->cooked_default) with the partition's local
3065  * definition (restdef->raw_default), if there's one. It
3066  * should be physically impossible to get a cooked default
3067  * in the local definition or a raw default in the
3068  * inherited definition, but make sure they're nulls, for
3069  * future-proofing.
3070  */
3071  Assert(restdef->cooked_default == NULL);
3072  Assert(coldef->raw_default == NULL);
3073  if (restdef->raw_default)
3074  {
3075  coldef->raw_default = restdef->raw_default;
3076  coldef->cooked_default = NULL;
3077  }
3078  }
3079  }
3080 
3081  /* complain for constraints on columns not in parent */
3082  if (!found)
3083  ereport(ERROR,
3084  (errcode(ERRCODE_UNDEFINED_COLUMN),
3085  errmsg("column \"%s\" does not exist",
3086  restdef->colname)));
3087  }
3088  }
3089 
3090  /*
3091  * If we found any conflicting parent default values, check to make sure
3092  * they were overridden by the child.
3093  */
3094  if (have_bogus_defaults)
3095  {
3096  foreach(lc, columns)
3097  {
3098  ColumnDef *def = lfirst(lc);
3099 
3100  if (def->cooked_default == &bogus_marker)
3101  {
3102  if (def->generated)
3103  ereport(ERROR,
3104  (errcode(ERRCODE_INVALID_COLUMN_DEFINITION),
3105  errmsg("column \"%s\" inherits conflicting generation expressions",
3106  def->colname),
3107  errhint("To resolve the conflict, specify a generation expression explicitly.")));
3108  else
3109  ereport(ERROR,
3110  (errcode(ERRCODE_INVALID_COLUMN_DEFINITION),
3111  errmsg("column \"%s\" inherits conflicting default values",
3112  def->colname),
3113  errhint("To resolve the conflict, specify a default explicitly.")));
3114  }
3115  }
3116  }
3117 
3118  *supconstr = constraints;
3119  *supnotnulls = nnconstraints;
3120 
3121  return columns;
3122 }
3123 
3124 
3125 /*
3126  * MergeCheckConstraint
3127  * Try to merge an inherited CHECK constraint with previous ones
3128  *
3129  * If we inherit identically-named constraints from multiple parents, we must
3130  * merge them, or throw an error if they don't have identical definitions.
3131  *
3132  * constraints is a list of CookedConstraint structs for previous constraints.
3133  *
3134  * If the new constraint matches an existing one, then the existing
3135  * constraint's inheritance count is updated. If there is a conflict (same
3136  * name but different expression), throw an error. If the constraint neither
3137  * matches nor conflicts with an existing one, a new constraint is appended to
3138  * the list.
3139  */
3140 static List *
3141 MergeCheckConstraint(List *constraints, const char *name, Node *expr)
3142 {
3143  ListCell *lc;
3144  CookedConstraint *newcon;
3145 
3146  foreach(lc, constraints)
3147  {
3148  CookedConstraint *ccon = (CookedConstraint *) lfirst(lc);
3149 
3150  Assert(ccon->contype == CONSTR_CHECK);
3151 
3152  /* Non-matching names never conflict */
3153  if (strcmp(ccon->name, name) != 0)
3154  continue;
3155 
3156  if (equal(expr, ccon->expr))
3157  {
3158  /* OK to merge constraint with existing */
3159  ccon->inhcount++;
3160  if (ccon->inhcount < 0)
3161  ereport(ERROR,
3162  errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
3163  errmsg("too many inheritance parents"));
3164  return constraints;
3165  }
3166 
3167  ereport(ERROR,
3169  errmsg("check constraint name \"%s\" appears multiple times but with different expressions",
3170  name)));
3171  }
3172 
3173  /*
3174  * Constraint couldn't be merged with an existing one and also didn't
3175  * conflict with an existing one, so add it as a new one to the list.
3176  */
3177  newcon = palloc0_object(CookedConstraint);
3178  newcon->contype = CONSTR_CHECK;
3179  newcon->name = pstrdup(name);
3180  newcon->expr = expr;
3181  newcon->inhcount = 1;
3182  return lappend(constraints, newcon);
3183 }
3184 
3185 /*
3186  * MergeChildAttribute
3187  * Merge given child attribute definition into given inherited attribute.
3188  *
3189  * Input arguments:
3190  * 'inh_columns' is the list of inherited ColumnDefs.
3191  * 'exist_attno' is the number of the inherited attribute in inh_columns
3192  * 'newcol_attno' is the attribute number in child table's schema definition
3193  * 'newdef' is the column/attribute definition from the child table.
3194  *
3195  * The ColumnDef in 'inh_columns' list is modified. The child attribute's
3196  * ColumnDef remains unchanged.
3197  *
3198  * Notes:
3199  * - The attribute is merged according to the rules laid out in the prologue
3200  * of MergeAttributes().
3201  * - If matching inherited attribute exists but the child attribute can not be
3202  * merged into it, the function throws respective errors.
3203  * - A partition can not have its own column definitions. Hence this function
3204  * is applicable only to a regular inheritance child.
3205  */
3206 static void
3207 MergeChildAttribute(List *inh_columns, int exist_attno, int newcol_attno, const ColumnDef *newdef)
3208 {
3209  char *attributeName = newdef->colname;
3210  ColumnDef *inhdef;
3211  Oid inhtypeid,
3212  newtypeid;
3213  int32 inhtypmod,
3214  newtypmod;
3215  Oid inhcollid,
3216  newcollid;
3217 
3218  if (exist_attno == newcol_attno)
3219  ereport(NOTICE,
3220  (errmsg("merging column \"%s\" with inherited definition",
3221  attributeName)));
3222  else
3223  ereport(NOTICE,
3224  (errmsg("moving and merging column \"%s\" with inherited definition", attributeName),
3225  errdetail("User-specified column moved to the position of the inherited column.")));
3226 
3227  inhdef = list_nth_node(ColumnDef, inh_columns, exist_attno - 1);
3228 
3229  /*
3230  * Must have the same type and typmod
3231  */
3232  typenameTypeIdAndMod(NULL, inhdef->typeName, &inhtypeid, &inhtypmod);
3233  typenameTypeIdAndMod(NULL, newdef->typeName, &newtypeid, &newtypmod);
3234  if (inhtypeid != newtypeid || inhtypmod != newtypmod)
3235  ereport(ERROR,
3236  (errcode(ERRCODE_DATATYPE_MISMATCH),
3237  errmsg("column \"%s\" has a type conflict",
3238  attributeName),
3239  errdetail("%s versus %s",
3240  format_type_with_typemod(inhtypeid, inhtypmod),
3241  format_type_with_typemod(newtypeid, newtypmod))));
3242 
3243  /*
3244  * Must have the same collation
3245  */
3246  inhcollid = GetColumnDefCollation(NULL, inhdef, inhtypeid);
3247  newcollid = GetColumnDefCollation(NULL, newdef, newtypeid);
3248  if (inhcollid != newcollid)
3249  ereport(ERROR,
3250  (errcode(ERRCODE_COLLATION_MISMATCH),
3251  errmsg("column \"%s\" has a collation conflict",
3252  attributeName),
3253  errdetail("\"%s\" versus \"%s\"",
3254  get_collation_name(inhcollid),
3255  get_collation_name(newcollid))));
3256 
3257  /*
3258  * Identity is never inherited by a regular inheritance child. Pick
3259  * child's identity definition if there's one.
3260  */
3261  inhdef->identity = newdef->identity;
3262 
3263  /*
3264  * Copy storage parameter
3265  */
3266  if (inhdef->storage == 0)
3267  inhdef->storage = newdef->storage;
3268  else if (newdef->storage != 0 && inhdef->storage != newdef->storage)
3269  ereport(ERROR,
3270  (errcode(ERRCODE_DATATYPE_MISMATCH),
3271  errmsg("column \"%s\" has a storage parameter conflict",
3272  attributeName),
3273  errdetail("%s versus %s",
3274  storage_name(inhdef->storage),
3275  storage_name(newdef->storage))));
3276 
3277  /*
3278  * Copy compression parameter
3279  */
3280  if (inhdef->compression == NULL)
3281  inhdef->compression = newdef->compression;
3282  else if (newdef->compression != NULL)
3283  {
3284  if (strcmp(inhdef->compression, newdef->compression) != 0)
3285  ereport(ERROR,
3286  (errcode(ERRCODE_DATATYPE_MISMATCH),
3287  errmsg("column \"%s\" has a compression method conflict",
3288  attributeName),
3289  errdetail("%s versus %s", inhdef->compression, newdef->compression)));
3290  }
3291 
3292  /*
3293  * Merge of not-null constraints = OR 'em together
3294  */
3295  inhdef->is_not_null |= newdef->is_not_null;
3296 
3297  /*
3298  * Check for conflicts related to generated columns.
3299  *
3300  * If the parent column is generated, the child column will be made a
3301  * generated column if it isn't already. If it is a generated column,
3302  * we'll take its generation expression in preference to the parent's. We
3303  * must check that the child column doesn't specify a default value or
3304  * identity, which matches the rules for a single column in
3305  * parse_utilcmd.c.
3306  *
3307  * Conversely, if the parent column is not generated, the child column
3308  * can't be either. (We used to allow that, but it results in being able
3309  * to override the generation expression via UPDATEs through the parent.)
3310  */
3311  if (inhdef->generated)
3312  {
3313  if (newdef->raw_default && !newdef->generated)
3314  ereport(ERROR,
3315  (errcode(ERRCODE_INVALID_COLUMN_DEFINITION),
3316  errmsg("column \"%s\" inherits from generated column but specifies default",
3317  inhdef->colname)));
3318  if (newdef->identity)
3319  ereport(ERROR,
3320  (errcode(ERRCODE_INVALID_COLUMN_DEFINITION),
3321  errmsg("column \"%s\" inherits from generated column but specifies identity",
3322  inhdef->colname)));
3323  }
3324  else
3325  {
3326  if (newdef->generated)
3327  ereport(ERROR,
3328  (errcode(ERRCODE_INVALID_COLUMN_DEFINITION),
3329  errmsg("child column \"%s\" specifies generation expression",
3330  inhdef->colname),
3331  errhint("A child table column cannot be generated unless its parent column is.")));
3332  }
3333 
3334  /*
3335  * If new def has a default, override previous default
3336  */
3337  if (newdef->raw_default != NULL)
3338  {
3339  inhdef->raw_default = newdef->raw_default;
3340  inhdef->cooked_default = newdef->cooked_default;
3341  }
3342 
3343  /* Mark the column as locally defined */
3344  inhdef->is_local = true;
3345 }
3346 
3347 /*
3348  * MergeInheritedAttribute
3349  * Merge given parent attribute definition into specified attribute
3350  * inherited from the previous parents.
3351  *
3352  * Input arguments:
3353  * 'inh_columns' is the list of previously inherited ColumnDefs.
3354  * 'exist_attno' is the number the existing matching attribute in inh_columns.
3355  * 'newdef' is the new parent column/attribute definition to be merged.
3356  *
3357  * The matching ColumnDef in 'inh_columns' list is modified and returned.
3358  *
3359  * Notes:
3360  * - The attribute is merged according to the rules laid out in the prologue
3361  * of MergeAttributes().
3362  * - If matching inherited attribute exists but the new attribute can not be
3363  * merged into it, the function throws respective errors.
3364  * - A partition inherits from only a single parent. Hence this function is
3365  * applicable only to a regular inheritance.
3366  */
3367 static ColumnDef *
3369  int exist_attno,
3370  const ColumnDef *newdef)
3371 {
3372  char *attributeName = newdef->colname;
3373  ColumnDef *prevdef;
3374  Oid prevtypeid,
3375  newtypeid;
3376  int32 prevtypmod,
3377  newtypmod;
3378  Oid prevcollid,
3379  newcollid;
3380 
3381  ereport(NOTICE,
3382  (errmsg("merging multiple inherited definitions of column \"%s\"",
3383  attributeName)));
3384  prevdef = list_nth_node(ColumnDef, inh_columns, exist_attno - 1);
3385 
3386  /*
3387  * Must have the same type and typmod
3388  */
3389  typenameTypeIdAndMod(NULL, prevdef->typeName, &prevtypeid, &prevtypmod);
3390  typenameTypeIdAndMod(NULL, newdef->typeName, &newtypeid, &newtypmod);
3391  if (prevtypeid != newtypeid || prevtypmod != newtypmod)
3392  ereport(ERROR,
3393  (errcode(ERRCODE_DATATYPE_MISMATCH),
3394  errmsg("inherited column \"%s\" has a type conflict",
3395  attributeName),
3396  errdetail("%s versus %s",
3397  format_type_with_typemod(prevtypeid, prevtypmod),
3398  format_type_with_typemod(newtypeid, newtypmod))));
3399 
3400  /*
3401  * Must have the same collation
3402  */
3403  prevcollid = GetColumnDefCollation(NULL, prevdef, prevtypeid);
3404  newcollid = GetColumnDefCollation(NULL, newdef, newtypeid);
3405  if (prevcollid != newcollid)
3406  ereport(ERROR,
3407  (errcode(ERRCODE_COLLATION_MISMATCH),
3408  errmsg("inherited column \"%s\" has a collation conflict",
3409  attributeName),
3410  errdetail("\"%s\" versus \"%s\"",
3411  get_collation_name(prevcollid),
3412  get_collation_name(newcollid))));
3413 
3414  /*
3415  * Copy/check storage parameter
3416  */
3417  if (prevdef->storage == 0)
3418  prevdef->storage = newdef->storage;
3419  else if (prevdef->storage != newdef->storage)
3420  ereport(ERROR,
3421  (errcode(ERRCODE_DATATYPE_MISMATCH),
3422  errmsg("inherited column \"%s\" has a storage parameter conflict",
3423  attributeName),
3424  errdetail("%s versus %s",
3425  storage_name(prevdef->storage),
3426  storage_name(newdef->storage))));
3427 
3428  /*
3429  * Copy/check compression parameter
3430  */
3431  if (prevdef->compression == NULL)
3432  prevdef->compression = newdef->compression;
3433  else if (strcmp(prevdef->compression, newdef->compression) != 0)
3434  ereport(ERROR,
3435  (errcode(ERRCODE_DATATYPE_MISMATCH),
3436  errmsg("column \"%s\" has a compression method conflict",
3437  attributeName),
3438  errdetail("%s versus %s", prevdef->compression, newdef->compression)));
3439 
3440  /*
3441  * Check for GENERATED conflicts
3442  */
3443  if (prevdef->generated != newdef->generated)
3444  ereport(ERROR,
3445  (errcode(ERRCODE_DATATYPE_MISMATCH),
3446  errmsg("inherited column \"%s\" has a generation conflict",
3447  attributeName)));
3448 
3449  /*
3450  * Default and other constraints are handled by the caller.
3451  */
3452 
3453  prevdef->inhcount++;
3454  if (prevdef->inhcount < 0)
3455  ereport(ERROR,
3456  errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
3457  errmsg("too many inheritance parents"));
3458 
3459  return prevdef;
3460 }
3461 
3462 /*
3463  * StoreCatalogInheritance
3464  * Updates the system catalogs with proper inheritance information.
3465  *
3466  * supers is a list of the OIDs of the new relation's direct ancestors.
3467  */
3468 static void
3469 StoreCatalogInheritance(Oid relationId, List *supers,
3470  bool child_is_partition)
3471 {
3472  Relation relation;
3473  int32 seqNumber;
3474  ListCell *entry;
3475 
3476  /*
3477  * sanity checks
3478  */
3479  Assert(OidIsValid(relationId));
3480 
3481  if (supers == NIL)
3482  return;
3483 
3484  /*
3485  * Store INHERITS information in pg_inherits using direct ancestors only.
3486  * Also enter dependencies on the direct ancestors, and make sure they are
3487  * marked with relhassubclass = true.
3488  *
3489  * (Once upon a time, both direct and indirect ancestors were found here
3490  * and then entered into pg_ipl. Since that catalog doesn't exist
3491  * anymore, there's no need to look for indirect ancestors.)
3492  */
3493  relation = table_open(InheritsRelationId, RowExclusiveLock);
3494 
3495  seqNumber = 1;
3496  foreach(entry, supers)
3497  {
3498  Oid parentOid = lfirst_oid(entry);
3499 
3500  StoreCatalogInheritance1(relationId, parentOid, seqNumber, relation,
3501  child_is_partition);
3502  seqNumber++;
3503  }
3504 
3505  table_close(relation, RowExclusiveLock);
3506 }
3507 
3508 /*
3509  * Make catalog entries showing relationId as being an inheritance child
3510  * of parentOid. inhRelation is the already-opened pg_inherits catalog.
3511  */
3512 static void
3513 StoreCatalogInheritance1(Oid relationId, Oid parentOid,
3514  int32 seqNumber, Relation inhRelation,
3515  bool child_is_partition)
3516 {
3517  ObjectAddress childobject,
3518  parentobject;
3519 
3520  /* store the pg_inherits row */
3521  StoreSingleInheritance(relationId, parentOid, seqNumber);
3522 
3523  /*
3524  * Store a dependency too
3525  */
3526  parentobject.classId = RelationRelationId;
3527  parentobject.objectId = parentOid;
3528  parentobject.objectSubId = 0;
3529  childobject.classId = RelationRelationId;
3530  childobject.objectId = relationId;
3531  childobject.objectSubId = 0;
3532 
3533  recordDependencyOn(&childobject, &parentobject,
3534  child_dependency_type(child_is_partition));
3535 
3536  /*
3537  * Post creation hook of this inheritance. Since object_access_hook
3538  * doesn't take multiple object identifiers, we relay oid of parent
3539  * relation using auxiliary_id argument.
3540  */
3541  InvokeObjectPostAlterHookArg(InheritsRelationId,
3542  relationId, 0,
3543  parentOid, false);
3544 
3545  /*
3546  * Mark the parent as having subclasses.
3547  */
3548  SetRelationHasSubclass(parentOid, true);
3549 }
3550 
3551 /*
3552  * Look for an existing column entry with the given name.
3553  *
3554  * Returns the index (starting with 1) if attribute already exists in columns,
3555  * 0 if it doesn't.
3556  */
3557 static int
3558 findAttrByName(const char *attributeName, const List *columns)
3559 {
3560  ListCell *lc;
3561  int i = 1;
3562 
3563  foreach(lc, columns)
3564  {
3565  if (strcmp(attributeName, lfirst_node(ColumnDef, lc)->colname) == 0)
3566  return i;
3567 
3568  i++;
3569  }
3570  return 0;
3571 }
3572 
3573 
3574 /*
3575  * SetRelationHasSubclass
3576  * Set the value of the relation's relhassubclass field in pg_class.
3577  *
3578  * NOTE: caller must be holding an appropriate lock on the relation.
3579  * ShareUpdateExclusiveLock is sufficient.
3580  *
3581  * NOTE: an important side-effect of this operation is that an SI invalidation
3582  * message is sent out to all backends --- including me --- causing plans
3583  * referencing the relation to be rebuilt with the new list of children.
3584  * This must happen even if we find that no change is needed in the pg_class
3585  * row.
3586  */
3587 void
3588 SetRelationHasSubclass(Oid relationId, bool relhassubclass)
3589 {
3590  Relation relationRelation;
3591  HeapTuple tuple;
3592  Form_pg_class classtuple;
3593 
3594  /*
3595  * Fetch a modifiable copy of the tuple, modify it, update pg_class.
3596  */
3597  relationRelation = table_open(RelationRelationId, RowExclusiveLock);
3598  tuple = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relationId));
3599  if (!HeapTupleIsValid(tuple))
3600  elog(ERROR, "cache lookup failed for relation %u", relationId);
3601  classtuple = (Form_pg_class) GETSTRUCT(tuple);
3602 
3603  if (classtuple->relhassubclass != relhassubclass)
3604  {
3605  classtuple->relhassubclass = relhassubclass;
3606  CatalogTupleUpdate(relationRelation, &tuple->t_self, tuple);
3607  }
3608  else
3609  {
3610  /* no need to change tuple, but force relcache rebuild anyway */
3612  }
3613 
3614  heap_freetuple(tuple);
3615  table_close(relationRelation, RowExclusiveLock);
3616 }
3617 
3618 /*
3619  * CheckRelationTableSpaceMove
3620  * Check if relation can be moved to new tablespace.
3621  *
3622  * NOTE: The caller must hold AccessExclusiveLock on the relation.
3623  *
3624  * Returns true if the relation can be moved to the new tablespace; raises
3625  * an error if it is not possible to do the move; returns false if the move
3626  * would have no effect.
3627  */
3628 bool
3630 {
3631  Oid oldTableSpaceId;
3632 
3633  /*
3634  * No work if no change in tablespace. Note that MyDatabaseTableSpace is
3635  * stored as 0.
3636  */
3637  oldTableSpaceId = rel->rd_rel->reltablespace;
3638  if (newTableSpaceId == oldTableSpaceId ||
3639  (newTableSpaceId == MyDatabaseTableSpace && oldTableSpaceId == 0))
3640  return false;
3641 
3642  /*
3643  * We cannot support moving mapped relations into different tablespaces.
3644  * (In particular this eliminates all shared catalogs.)
3645  */
3646  if (RelationIsMapped(rel))
3647  ereport(ERROR,
3648  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3649  errmsg("cannot move system relation \"%s\"",
3650  RelationGetRelationName(rel))));
3651 
3652  /* Cannot move a non-shared relation into pg_global */
3653  if (newTableSpaceId == GLOBALTABLESPACE_OID)
3654  ereport(ERROR,
3655  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
3656  errmsg("only shared relations can be placed in pg_global tablespace")));
3657 
3658  /*
3659  * Do not allow moving temp tables of other backends ... their local
3660  * buffer manager is not going to cope.
3661  */
3662  if (RELATION_IS_OTHER_TEMP(rel))
3663  ereport(ERROR,
3664  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3665  errmsg("cannot move temporary tables of other sessions")));
3666 
3667  return true;
3668 }
3669 
3670 /*
3671  * SetRelationTableSpace
3672  * Set new reltablespace and relfilenumber in pg_class entry.
3673  *
3674  * newTableSpaceId is the new tablespace for the relation, and
3675  * newRelFilenumber its new filenumber. If newRelFilenumber is
3676  * InvalidRelFileNumber, this field is not updated.
3677  *
3678  * NOTE: The caller must hold AccessExclusiveLock on the relation.
3679  *
3680  * The caller of this routine had better check if a relation can be
3681  * moved to this new tablespace by calling CheckRelationTableSpaceMove()
3682  * first, and is responsible for making the change visible with
3683  * CommandCounterIncrement().
3684  */
3685 void
3687  Oid newTableSpaceId,
3688  RelFileNumber newRelFilenumber)
3689 {
3690  Relation pg_class;
3691  HeapTuple tuple;
3692  Form_pg_class rd_rel;
3693  Oid reloid = RelationGetRelid(rel);
3694 
3695  Assert(CheckRelationTableSpaceMove(rel, newTableSpaceId));
3696 
3697  /* Get a modifiable copy of the relation's pg_class row. */
3698  pg_class = table_open(RelationRelationId, RowExclusiveLock);
3699 
3700  tuple = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(reloid));
3701  if (!HeapTupleIsValid(tuple))
3702  elog(ERROR, "cache lookup failed for relation %u", reloid);
3703  rd_rel = (Form_pg_class) GETSTRUCT(tuple);
3704 
3705  /* Update the pg_class row. */
3706  rd_rel->reltablespace = (newTableSpaceId == MyDatabaseTableSpace) ?
3707  InvalidOid : newTableSpaceId;
3708  if (RelFileNumberIsValid(newRelFilenumber))
3709  rd_rel->relfilenode = newRelFilenumber;
3710  CatalogTupleUpdate(pg_class, &tuple->t_self, tuple);
3711 
3712  /*
3713  * Record dependency on tablespace. This is only required for relations
3714  * that have no physical storage.
3715  */
3716  if (!RELKIND_HAS_STORAGE(rel->rd_rel->relkind))
3717  changeDependencyOnTablespace(RelationRelationId, reloid,
3718  rd_rel->reltablespace);
3719 
3720  heap_freetuple(tuple);
3721  table_close(pg_class, RowExclusiveLock);
3722 }
3723 
3724 /*
3725  * renameatt_check - basic sanity checks before attribute rename
3726  */
3727 static void
3728 renameatt_check(Oid myrelid, Form_pg_class classform, bool recursing)
3729 {
3730  char relkind = classform->relkind;
3731 
3732  if (classform->reloftype && !recursing)
3733  ereport(ERROR,
3734  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3735  errmsg("cannot rename column of typed table")));
3736 
3737  /*
3738  * Renaming the columns of sequences or toast tables doesn't actually
3739  * break anything from the system's point of view, since internal
3740  * references are by attnum. But it doesn't seem right to allow users to
3741  * change names that are hardcoded into the system, hence the following
3742  * restriction.
3743  */
3744  if (relkind != RELKIND_RELATION &&
3745  relkind != RELKIND_VIEW &&
3746  relkind != RELKIND_MATVIEW &&
3747  relkind != RELKIND_COMPOSITE_TYPE &&
3748  relkind != RELKIND_INDEX &&
3749  relkind != RELKIND_PARTITIONED_INDEX &&
3750  relkind != RELKIND_FOREIGN_TABLE &&
3751  relkind != RELKIND_PARTITIONED_TABLE)
3752  ereport(ERROR,
3753  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3754  errmsg("cannot rename columns of relation \"%s\"",
3755  NameStr(classform->relname)),
3757 
3758  /*
3759  * permissions checking. only the owner of a class can change its schema.
3760  */
3761  if (!object_ownercheck(RelationRelationId, myrelid, GetUserId()))
3763  NameStr(classform->relname));
3764  if (!allowSystemTableMods && IsSystemClass(myrelid, classform))
3765  ereport(ERROR,
3766  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
3767  errmsg("permission denied: \"%s\" is a system catalog",
3768  NameStr(classform->relname))));
3769 }
3770 
3771 /*
3772  * renameatt_internal - workhorse for renameatt
3773  *
3774  * Return value is the attribute number in the 'myrelid' relation.
3775  */
3776 static AttrNumber
3778  const char *oldattname,
3779  const char *newattname,
3780  bool recurse,
3781  bool recursing,
3782  int expected_parents,
3783  DropBehavior behavior)
3784 {
3785  Relation targetrelation;
3786  Relation attrelation;
3787  HeapTuple atttup;
3788  Form_pg_attribute attform;
3790 
3791  /*
3792  * Grab an exclusive lock on the target table, which we will NOT release
3793  * until end of transaction.
3794  */
3795  targetrelation = relation_open(myrelid, AccessExclusiveLock);
3796  renameatt_check(myrelid, RelationGetForm(targetrelation), recursing);
3797 
3798  /*
3799  * if the 'recurse' flag is set then we are supposed to rename this
3800  * attribute in all classes that inherit from 'relname' (as well as in
3801  * 'relname').
3802  *
3803  * any permissions or problems with duplicate attributes will cause the
3804  * whole transaction to abort, which is what we want -- all or nothing.
3805  */
3806  if (recurse)
3807  {
3808  List *child_oids,
3809  *child_numparents;
3810  ListCell *lo,
3811  *li;
3812 
3813  /*
3814  * we need the number of parents for each child so that the recursive
3815  * calls to renameatt() can determine whether there are any parents
3816  * outside the inheritance hierarchy being processed.
3817  */
3818  child_oids = find_all_inheritors(myrelid, AccessExclusiveLock,
3819  &child_numparents);
3820 
3821  /*
3822  * find_all_inheritors does the recursive search of the inheritance
3823  * hierarchy, so all we have to do is process all of the relids in the
3824  * list that it returns.
3825  */
3826  forboth(lo, child_oids, li, child_numparents)
3827  {
3828  Oid childrelid = lfirst_oid(lo);
3829  int numparents = lfirst_int(li);
3830 
3831  if (childrelid == myrelid)
3832  continue;
3833  /* note we need not recurse again */
3834  renameatt_internal(childrelid, oldattname, newattname, false, true, numparents, behavior);
3835  }
3836  }
3837  else
3838  {
3839  /*
3840  * If we are told not to recurse, there had better not be any child
3841  * tables; else the rename would put them out of step.
3842  *
3843  * expected_parents will only be 0 if we are not already recursing.
3844  */
3845  if (expected_parents == 0 &&
3846  find_inheritance_children(myrelid, NoLock) != NIL)
3847  ereport(ERROR,
3848  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
3849  errmsg("inherited column \"%s\" must be renamed in child tables too",
3850  oldattname)));
3851  }
3852 
3853  /* rename attributes in typed tables of composite type */
3854  if (targetrelation->rd_rel->relkind == RELKIND_COMPOSITE_TYPE)
3855  {
3856  List *child_oids;
3857  ListCell *lo;
3858 
3859  child_oids = find_typed_table_dependencies(targetrelation->rd_rel->reltype,
3860  RelationGetRelationName(targetrelation),
3861  behavior);
3862 
3863  foreach(lo, child_oids)
3864  renameatt_internal(lfirst_oid(lo), oldattname, newattname, true, true, 0, behavior);
3865  }
3866 
3867  attrelation = table_open(AttributeRelationId, RowExclusiveLock);
3868 
3869  atttup = SearchSysCacheCopyAttName(myrelid, oldattname);
3870  if (!HeapTupleIsValid(atttup))
3871  ereport(ERROR,
3872  (errcode(ERRCODE_UNDEFINED_COLUMN),
3873  errmsg("column \"%s\" does not exist",
3874  oldattname)));
3875  attform = (Form_pg_attribute) GETSTRUCT(atttup);
3876 
3877  attnum = attform->attnum;
3878  if (attnum <= 0)
3879  ereport(ERROR,
3880  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3881  errmsg("cannot rename system column \"%s\"",
3882  oldattname)));
3883 
3884  /*
3885  * if the attribute is inherited, forbid the renaming. if this is a
3886  * top-level call to renameatt(), then expected_parents will be 0, so the
3887  * effect of this code will be to prohibit the renaming if the attribute
3888  * is inherited at all. if this is a recursive call to renameatt(),
3889  * expected_parents will be the number of parents the current relation has
3890  * within the inheritance hierarchy being processed, so we'll prohibit the
3891  * renaming only if there are additional parents from elsewhere.
3892  */
3893  if (attform->attinhcount > expected_parents)
3894  ereport(ERROR,
3895  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
3896  errmsg("cannot rename inherited column \"%s\"",
3897  oldattname)));
3898 
3899  /* new name should not already exist */
3900  (void) check_for_column_name_collision(targetrelation, newattname, false);
3901 
3902  /* apply the update */
3903  namestrcpy(&(attform->attname), newattname);
3904 
3905  CatalogTupleUpdate(attrelation, &atttup->t_self, atttup);
3906 
3907  InvokeObjectPostAlterHook(RelationRelationId, myrelid, attnum);
3908 
3909  heap_freetuple(atttup);
3910 
3911  table_close(attrelation, RowExclusiveLock);
3912 
3913  relation_close(targetrelation, NoLock); /* close rel but keep lock */
3914 
3915  return attnum;
3916 }
3917 
3918 /*
3919  * Perform permissions and integrity checks before acquiring a relation lock.
3920  */
3921 static void
3923  void *arg)
3924 {
3925  HeapTuple tuple;
3926  Form_pg_class form;
3927 
3928  tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
3929  if (!HeapTupleIsValid(tuple))
3930  return; /* concurrently dropped */
3931  form = (Form_pg_class) GETSTRUCT(tuple);
3932  renameatt_check(relid, form, false);
3933  ReleaseSysCache(tuple);
3934 }
3935 
3936 /*
3937  * renameatt - changes the name of an attribute in a relation
3938  *
3939  * The returned ObjectAddress is that of the renamed column.
3940  */
3943 {
3944  Oid relid;
3946  ObjectAddress address;
3947 
3948  /* lock level taken here should match renameatt_internal */
3950  stmt->missing_ok ? RVR_MISSING_OK : 0,
3952  NULL);
3953 
3954  if (!OidIsValid(relid))
3955  {
3956  ereport(NOTICE,
3957  (errmsg("relation \"%s\" does not exist, skipping",
3958  stmt->relation->relname)));
3959  return InvalidObjectAddress;
3960  }
3961 
3962  attnum =
3963  renameatt_internal(relid,
3964  stmt->subname, /* old att name */
3965  stmt->newname, /* new att name */
3966  stmt->relation->inh, /* recursive? */
3967  false, /* recursing? */
3968  0, /* expected inhcount */
3969  stmt->behavior);
3970 
3971  ObjectAddressSubSet(address, RelationRelationId, relid, attnum);
3972 
3973  return address;
3974 }
3975 
3976 /*
3977  * same logic as renameatt_internal
3978  */
3979 static ObjectAddress
3981  Oid mytypid,
3982  const char *oldconname,
3983  const char *newconname,
3984  bool recurse,
3985  bool recursing,
3986  int expected_parents)
3987 {
3988  Relation targetrelation = NULL;
3989  Oid constraintOid;
3990  HeapTuple tuple;
3991  Form_pg_constraint con;
3992  ObjectAddress address;
3993 
3994  Assert(!myrelid || !mytypid);
3995 
3996  if (mytypid)
3997  {
3998  constraintOid = get_domain_constraint_oid(mytypid, oldconname, false);
3999  }
4000  else
4001  {
4002  targetrelation = relation_open(myrelid, AccessExclusiveLock);
4003 
4004  /*
4005  * don't tell it whether we're recursing; we allow changing typed
4006  * tables here
4007  */
4008  renameatt_check(myrelid, RelationGetForm(targetrelation), false);
4009 
4010  constraintOid = get_relation_constraint_oid(myrelid, oldconname, false);
4011  }
4012 
4013  tuple = SearchSysCache1(CONSTROID, ObjectIdGetDatum(constraintOid));
4014  if (!HeapTupleIsValid(tuple))
4015  elog(ERROR, "cache lookup failed for constraint %u",
4016  constraintOid);
4017  con = (Form_pg_constraint) GETSTRUCT(tuple);
4018 
4019  if (myrelid &&
4020  (con->contype == CONSTRAINT_CHECK ||
4021  con->contype == CONSTRAINT_NOTNULL) &&
4022  !con->connoinherit)
4023  {
4024  if (recurse)
4025  {
4026  List *child_oids,
4027  *child_numparents;
4028  ListCell *lo,
4029  *li;
4030 
4031  child_oids = find_all_inheritors(myrelid, AccessExclusiveLock,
4032  &child_numparents);
4033 
4034  forboth(lo, child_oids, li, child_numparents)
4035  {
4036  Oid childrelid = lfirst_oid(lo);
4037  int numparents = lfirst_int(li);
4038 
4039  if (childrelid == myrelid)
4040  continue;
4041 
4042  rename_constraint_internal(childrelid, InvalidOid, oldconname, newconname, false, true, numparents);
4043  }
4044  }
4045  else
4046  {
4047  if (expected_parents == 0 &&
4048  find_inheritance_children(myrelid, NoLock) != NIL)
4049  ereport(ERROR,
4050  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
4051  errmsg("inherited constraint \"%s\" must be renamed in child tables too",
4052  oldconname)));
4053  }
4054 
4055  if (con->coninhcount > expected_parents)
4056  ereport(ERROR,
4057  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
4058  errmsg("cannot rename inherited constraint \"%s\"",
4059  oldconname)));
4060  }
4061 
4062  if (con->conindid
4063  && (con->contype == CONSTRAINT_PRIMARY
4064  || con->contype == CONSTRAINT_UNIQUE
4065  || con->contype == CONSTRAINT_EXCLUSION))
4066  /* rename the index; this renames the constraint as well */
4067  RenameRelationInternal(con->conindid, newconname, false, true);
4068  else
4069  RenameConstraintById(constraintOid, newconname);
4070 
4071  ObjectAddressSet(address, ConstraintRelationId, constraintOid);
4072 
4073  ReleaseSysCache(tuple);
4074 
4075  if (targetrelation)
4076  {
4077  /*
4078  * Invalidate relcache so as others can see the new constraint name.
4079  */
4080  CacheInvalidateRelcache(targetrelation);
4081 
4082  relation_close(targetrelation, NoLock); /* close rel but keep lock */
4083  }
4084 
4085  return address;
4086 }
4087 
4090 {
4091  Oid relid = InvalidOid;
4092  Oid typid = InvalidOid;
4093 
4094  if (stmt->renameType == OBJECT_DOMCONSTRAINT)
4095  {
4096  Relation rel;
4097  HeapTuple tup;
4098 
4099  typid = typenameTypeId(NULL, makeTypeNameFromNameList(castNode(List, stmt->object)));
4100  rel = table_open(TypeRelationId, RowExclusiveLock);
4101  tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
4102  if (!HeapTupleIsValid(tup))
4103  elog(ERROR, "cache lookup failed for type %u", typid);
4104  checkDomainOwner(tup);
4105  ReleaseSysCache(tup);
4106  table_close(rel, NoLock);
4107  }
4108  else
4109  {
4110  /* lock level taken here should match rename_constraint_internal */
4112  stmt->missing_ok ? RVR_MISSING_OK : 0,
4114  NULL);
4115  if (!OidIsValid(relid))
4116  {
4117  ereport(NOTICE,
4118  (errmsg("relation \"%s\" does not exist, skipping",
4119  stmt->relation->relname)));
4120  return InvalidObjectAddress;
4121  }
4122  }
4123 
4124  return
4125  rename_constraint_internal(relid, typid,
4126  stmt->subname,
4127  stmt->newname,
4128  (stmt->relation &&
4129  stmt->relation->inh), /* recursive? */
4130  false, /* recursing? */
4131  0 /* expected inhcount */ );
4132 }
4133 
4134 /*
4135  * Execute ALTER TABLE/INDEX/SEQUENCE/VIEW/MATERIALIZED VIEW/FOREIGN TABLE
4136  * RENAME
4137  */
4140 {
4141  bool is_index_stmt = stmt->renameType == OBJECT_INDEX;
4142  Oid relid;
4143  ObjectAddress address;
4144 
4145  /*
4146  * Grab an exclusive lock on the target table, index, sequence, view,
4147  * materialized view, or foreign table, which we will NOT release until
4148  * end of transaction.
4149  *
4150  * Lock level used here should match RenameRelationInternal, to avoid lock
4151  * escalation. However, because ALTER INDEX can be used with any relation
4152  * type, we mustn't believe without verification.
4153  */
4154  for (;;)
4155  {
4156  LOCKMODE lockmode;
4157  char relkind;
4158  bool obj_is_index;
4159 
4160  lockmode = is_index_stmt ? ShareUpdateExclusiveLock : AccessExclusiveLock;
4161 
4162  relid = RangeVarGetRelidExtended(stmt->relation, lockmode,
4163  stmt->missing_ok ? RVR_MISSING_OK : 0,
4165  (void *) stmt);
4166 
4167  if (!OidIsValid(relid))
4168  {
4169  ereport(NOTICE,
4170  (errmsg("relation \"%s\" does not exist, skipping",
4171  stmt->relation->relname)));
4172  return InvalidObjectAddress;
4173  }
4174 
4175  /*
4176  * We allow mismatched statement and object types (e.g., ALTER INDEX
4177  * to rename a table), but we might've used the wrong lock level. If
4178  * that happens, retry with the correct lock level. We don't bother
4179  * if we already acquired AccessExclusiveLock with an index, however.
4180  */
4181  relkind = get_rel_relkind(relid);
4182  obj_is_index = (relkind == RELKIND_INDEX ||
4183  relkind == RELKIND_PARTITIONED_INDEX);
4184  if (obj_is_index || is_index_stmt == obj_is_index)
4185  break;
4186 
4187  UnlockRelationOid(relid, lockmode);
4188  is_index_stmt = obj_is_index;
4189  }
4190 
4191  /* Do the work */
4192  RenameRelationInternal(relid, stmt->newname, false, is_index_stmt);
4193 
4194  ObjectAddressSet(address, RelationRelationId, relid);
4195 
4196  return address;
4197 }
4198 
4199 /*
4200  * RenameRelationInternal - change the name of a relation
4201  */
4202 void
4203 RenameRelationInternal(Oid myrelid, const char *newrelname, bool is_internal, bool is_index)
4204 {
4205  Relation targetrelation;
4206  Relation relrelation; /* for RELATION relation */
4207  HeapTuple reltup;
4208  Form_pg_class relform;
4209  Oid namespaceId;
4210 
4211  /*
4212  * Grab a lock on the target relation, which we will NOT release until end
4213  * of transaction. We need at least a self-exclusive lock so that
4214  * concurrent DDL doesn't overwrite the rename if they start updating
4215  * while still seeing the old version. The lock also guards against
4216  * triggering relcache reloads in concurrent sessions, which might not
4217  * handle this information changing under them. For indexes, we can use a
4218  * reduced lock level because RelationReloadIndexInfo() handles indexes
4219  * specially.
4220  */
4221  targetrelation = relation_open(myrelid, is_index ? ShareUpdateExclusiveLock : AccessExclusiveLock);
4222  namespaceId = RelationGetNamespace(targetrelation);
4223 
4224  /*
4225  * Find relation's pg_class tuple, and make sure newrelname isn't in use.
4226  */
4227  relrelation = table_open(RelationRelationId, RowExclusiveLock);
4228 
4229  reltup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(myrelid));
4230  if (!HeapTupleIsValid(reltup)) /* shouldn't happen */
4231  elog(ERROR, "cache lookup failed for relation %u", myrelid);
4232  relform = (Form_pg_class) GETSTRUCT(reltup);
4233 
4234  if (get_relname_relid(newrelname, namespaceId) != InvalidOid)
4235  ereport(ERROR,
4236  (errcode(ERRCODE_DUPLICATE_TABLE),
4237  errmsg("relation \"%s\" already exists",
4238  newrelname)));
4239 
4240  /*
4241  * RenameRelation is careful not to believe the caller's idea of the
4242  * relation kind being handled. We don't have to worry about this, but
4243  * let's not be totally oblivious to it. We can process an index as
4244  * not-an-index, but not the other way around.
4245  */
4246  Assert(!is_index ||
4247  is_index == (targetrelation->rd_rel->relkind == RELKIND_INDEX ||
4248  targetrelation->rd_rel->relkind == RELKIND_PARTITIONED_INDEX));
4249 
4250  /*
4251  * Update pg_class tuple with new relname. (Scribbling on reltup is OK
4252  * because it's a copy...)
4253  */
4254  namestrcpy(&(relform->relname), newrelname);
4255 
4256  CatalogTupleUpdate(relrelation, &reltup->t_self, reltup);
4257 
4258  InvokeObjectPostAlterHookArg(RelationRelationId, myrelid, 0,
4259  InvalidOid, is_internal);
4260 
4261  heap_freetuple(reltup);
4262  table_close(relrelation, RowExclusiveLock);
4263 
4264  /*
4265  * Also rename the associated type, if any.
4266  */
4267  if (OidIsValid(targetrelation->rd_rel->reltype))
4268  RenameTypeInternal(targetrelation->rd_rel->reltype,
4269  newrelname, namespaceId);
4270 
4271  /*
4272  * Also rename the associated constraint, if any.
4273  */
4274  if (targetrelation->rd_rel->relkind == RELKIND_INDEX ||
4275  targetrelation->rd_rel->relkind == RELKIND_PARTITIONED_INDEX)
4276  {
4277  Oid constraintId = get_index_constraint(myrelid);
4278 
4279  if (OidIsValid(constraintId))
4280  RenameConstraintById(constraintId, newrelname);
4281  }
4282 
4283  /*
4284  * Close rel, but keep lock!
4285  */
4286  relation_close(targetrelation, NoLock);
4287 }
4288 
4289 /*
4290  * ResetRelRewrite - reset relrewrite
4291  */
4292 void
4294 {
4295  Relation relrelation; /* for RELATION relation */
4296  HeapTuple reltup;
4297  Form_pg_class relform;
4298 
4299  /*
4300  * Find relation's pg_class tuple.
4301  */
4302  relrelation = table_open(RelationRelationId, RowExclusiveLock);
4303 
4304  reltup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(myrelid));
4305  if (!HeapTupleIsValid(reltup)) /* shouldn't happen */
4306  elog(ERROR, "cache lookup failed for relation %u", myrelid);
4307  relform = (Form_pg_class) GETSTRUCT(reltup);
4308 
4309  /*
4310  * Update pg_class tuple.
4311  */
4312  relform->relrewrite = InvalidOid;
4313 
4314  CatalogTupleUpdate(relrelation, &reltup->t_self, reltup);
4315 
4316  heap_freetuple(reltup);
4317  table_close(relrelation, RowExclusiveLock);
4318 }
4319 
4320 /*
4321  * Disallow ALTER TABLE (and similar commands) when the current backend has
4322  * any open reference to the target table besides the one just acquired by
4323  * the calling command; this implies there's an open cursor or active plan.
4324  * We need this check because our lock doesn't protect us against stomping
4325  * on our own foot, only other people's feet!
4326  *
4327  * For ALTER TABLE, the only case known to cause serious trouble is ALTER
4328  * COLUMN TYPE, and some changes are obviously pretty benign, so this could
4329  * possibly be relaxed to only error out for certain types of alterations.
4330  * But the use-case for allowing any of these things is not obvious, so we
4331  * won't work hard at it for now.
4332  *
4333  * We also reject these commands if there are any pending AFTER trigger events
4334  * for the rel. This is certainly necessary for the rewriting variants of
4335  * ALTER TABLE, because they don't preserve tuple TIDs and so the pending
4336  * events would try to fetch the wrong tuples. It might be overly cautious
4337  * in other cases, but again it seems better to err on the side of paranoia.
4338  *
4339  * REINDEX calls this with "rel" referencing the index to be rebuilt; here
4340  * we are worried about active indexscans on the index. The trigger-event
4341  * check can be skipped, since we are doing no damage to the parent table.
4342  *
4343  * The statement name (eg, "ALTER TABLE") is passed for use in error messages.
4344  */
4345 void
4347 {
4348  int expected_refcnt;
4349 
4350  expected_refcnt = rel->rd_isnailed ? 2 : 1;
4351  if (rel->rd_refcnt != expected_refcnt)
4352  ereport(ERROR,
4353  (errcode(ERRCODE_OBJECT_IN_USE),
4354  /* translator: first %s is a SQL command, eg ALTER TABLE */
4355  errmsg("cannot %s \"%s\" because it is being used by active queries in this session",
4356  stmt, RelationGetRelationName(rel))));
4357 
4358  if (rel->rd_rel->relkind != RELKIND_INDEX &&
4359  rel->rd_rel->relkind != RELKIND_PARTITIONED_INDEX &&
4361  ereport(ERROR,
4362  (errcode(ERRCODE_OBJECT_IN_USE),
4363  /* translator: first %s is a SQL command, eg ALTER TABLE */
4364  errmsg("cannot %s \"%s\" because it has pending trigger events",
4365  stmt, RelationGetRelationName(rel))));
4366 }
4367 
4368 /*
4369  * AlterTableLookupRelation
4370  * Look up, and lock, the OID for the relation named by an alter table
4371  * statement.
4372  */
4373 Oid
4375 {
4376  return RangeVarGetRelidExtended(stmt->relation, lockmode,
4377  stmt->missing_ok ? RVR_MISSING_OK : 0,
4379  (void *) stmt);
4380 }
4381 
4382 /*
4383  * AlterTable
4384  * Execute ALTER TABLE, which can be a list of subcommands
4385  *
4386  * ALTER TABLE is performed in three phases:
4387  * 1. Examine subcommands and perform pre-transformation checking.
4388  * 2. Validate and transform subcommands, and update system catalogs.
4389  * 3. Scan table(s) to check new constraints, and optionally recopy
4390  * the data into new table(s).
4391  * Phase 3 is not performed unless one or more of the subcommands requires
4392  * it. The intention of this design is to allow multiple independent
4393  * updates of the table schema to be performed with only one pass over the
4394  * data.
4395  *
4396  * ATPrepCmd performs phase 1. A "work queue" entry is created for
4397  * each table to be affected (there may be multiple affected tables if the
4398  * commands traverse a table inheritance hierarchy). Also we do preliminary
4399  * validation of the subcommands. Because earlier subcommands may change
4400  * the catalog state seen by later commands, there are limits to what can
4401  * be done in this phase. Generally, this phase acquires table locks,
4402  * checks permissions and relkind, and recurses to find child tables.
4403  *
4404  * ATRewriteCatalogs performs phase 2 for each affected table.
4405  * Certain subcommands need to be performed before others to avoid
4406  * unnecessary conflicts; for example, DROP COLUMN should come before
4407  * ADD COLUMN. Therefore phase 1 divides the subcommands into multiple
4408  * lists, one for each logical "pass" of phase 2.
4409  *
4410  * ATRewriteTables performs phase 3 for those tables that need it.
4411  *
4412  * For most subcommand types, phases 2 and 3 do no explicit recursion,
4413  * since phase 1 already does it. However, for certain subcommand types
4414  * it is only possible to determine how to recurse at phase 2 time; for
4415  * those cases, phase 1 sets the cmd->recurse flag.
4416  *
4417  * Thanks to the magic of MVCC, an error anywhere along the way rolls back
4418  * the whole operation; we don't have to do anything special to clean up.
4419  *
4420  * The caller must lock the relation, with an appropriate lock level
4421  * for the subcommands requested, using AlterTableGetLockLevel(stmt->cmds)
4422  * or higher. We pass the lock level down
4423  * so that we can apply it recursively to inherited tables. Note that the
4424  * lock level we want as we recurse might well be higher than required for
4425  * that specific subcommand. So we pass down the overall lock requirement,
4426  * rather than reassess it at lower levels.
4427  *
4428  * The caller also provides a "context" which is to be passed back to
4429  * utility.c when we need to execute a subcommand such as CREATE INDEX.
4430  * Some of the fields therein, such as the relid, are used here as well.
4431  */
4432 void
4435 {
4436  Relation rel;
4437 
4438  /* Caller is required to provide an adequate lock. */
4439  rel = relation_open(context->relid, NoLock);
4440 
4441  CheckTableNotInUse(rel, "ALTER TABLE");
4442 
4443  ATController(stmt, rel, stmt->cmds, stmt->relation->inh, lockmode, context);
4444 }
4445 
4446 /*
4447  * AlterTableInternal
4448  *
4449  * ALTER TABLE with target specified by OID
4450  *
4451  * We do not reject if the relation is already open, because it's quite
4452  * likely that one or more layers of caller have it open. That means it
4453  * is unsafe to use this entry point for alterations that could break
4454  * existing query plans. On the assumption it's not used for such, we
4455  * don't have to reject pending AFTER triggers, either.
4456  *
4457  * Also, since we don't have an AlterTableUtilityContext, this cannot be
4458  * used for any subcommand types that require parse transformation or
4459  * could generate subcommands that have to be passed to ProcessUtility.
4460  */
4461 void
4462 AlterTableInternal(Oid relid, List *cmds, bool recurse)
4463 {
4464  Relation rel;
4465  LOCKMODE lockmode = AlterTableGetLockLevel(cmds);
4466 
4467  rel = relation_open(relid, lockmode);
4468 
4470 
4471  ATController(NULL, rel, cmds, recurse, lockmode, NULL);
4472 }
4473 
4474 /*
4475  * AlterTableGetLockLevel
4476  *
4477  * Sets the overall lock level required for the supplied list of subcommands.
4478  * Policy for doing this set according to needs of AlterTable(), see
4479  * comments there for overall explanation.
4480  *
4481  * Function is called before and after parsing, so it must give same
4482  * answer each time it is called. Some subcommands are transformed
4483  * into other subcommand types, so the transform must never be made to a
4484  * lower lock level than previously assigned. All transforms are noted below.
4485  *
4486  * Since this is called before we lock the table we cannot use table metadata
4487  * to influence the type of lock we acquire.
4488  *
4489  * There should be no lockmodes hardcoded into the subcommand functions. All
4490  * lockmode decisions for ALTER TABLE are made here only. The one exception is
4491  * ALTER TABLE RENAME which is treated as a different statement type T_RenameStmt
4492  * and does not travel through this section of code and cannot be combined with
4493  * any of the subcommands given here.
4494  *
4495  * Note that Hot Standby only knows about AccessExclusiveLocks on the primary
4496  * so any changes that might affect SELECTs running on standbys need to use
4497  * AccessExclusiveLocks even if you think a lesser lock would do, unless you
4498  * have a solution for that also.
4499  *
4500  * Also note that pg_dump uses only an AccessShareLock, meaning that anything
4501  * that takes a lock less than AccessExclusiveLock can change object definitions
4502  * while pg_dump is running. Be careful to check that the appropriate data is
4503  * derived by pg_dump using an MVCC snapshot, rather than syscache lookups,
4504  * otherwise we might end up with an inconsistent dump that can't restore.
4505  */
4506 LOCKMODE
4508 {
4509  /*
4510  * This only works if we read catalog tables using MVCC snapshots.
4511  */
4512  ListCell *lcmd;
4514 
4515  foreach(lcmd, cmds)
4516  {
4517  AlterTableCmd *cmd = (AlterTableCmd *) lfirst(lcmd);
4518  LOCKMODE cmd_lockmode = AccessExclusiveLock; /* default for compiler */
4519 
4520  switch (cmd->subtype)
4521  {
4522  /*
4523  * These subcommands rewrite the heap, so require full locks.
4524  */
4525  case AT_AddColumn: /* may rewrite heap, in some cases and visible
4526  * to SELECT */
4527  case AT_SetAccessMethod: /* must rewrite heap */
4528  case AT_SetTableSpace: /* must rewrite heap */
4529  case AT_AlterColumnType: /* must rewrite heap */
4530  cmd_lockmode = AccessExclusiveLock;
4531  break;
4532 
4533  /*
4534  * These subcommands may require addition of toast tables. If
4535  * we add a toast table to a table currently being scanned, we
4536  * might miss data added to the new toast table by concurrent
4537  * insert transactions.
4538  */
4539  case AT_SetStorage: /* may add toast tables, see
4540  * ATRewriteCatalogs() */
4541  cmd_lockmode = AccessExclusiveLock;
4542  break;
4543 
4544  /*
4545  * Removing constraints can affect SELECTs that have been
4546  * optimized assuming the constraint holds true. See also
4547  * CloneFkReferenced.
4548  */
4549  case AT_DropConstraint: /* as DROP INDEX */
4550  case AT_DropNotNull: /* may change some SQL plans */
4551  cmd_lockmode = AccessExclusiveLock;
4552  break;
4553 
4554  /*
4555  * Subcommands that may be visible to concurrent SELECTs
4556  */
4557  case AT_DropColumn: /* change visible to SELECT */
4558  case AT_AddColumnToView: /* CREATE VIEW */
4559  case AT_DropOids: /* used to equiv to DropColumn */
4560  case AT_EnableAlwaysRule: /* may change SELECT rules */
4561  case AT_EnableReplicaRule: /* may change SELECT rules */
4562  case AT_EnableRule: /* may change SELECT rules */
4563  case AT_DisableRule: /* may change SELECT rules */
4564  cmd_lockmode = AccessExclusiveLock;
4565  break;
4566 
4567  /*
4568  * Changing owner may remove implicit SELECT privileges
4569  */
4570  case AT_ChangeOwner: /* change visible to SELECT */
4571  cmd_lockmode = AccessExclusiveLock;
4572  break;
4573 
4574  /*
4575  * Changing foreign table options may affect optimization.
4576  */
4577  case AT_GenericOptions:
4579  cmd_lockmode = AccessExclusiveLock;
4580  break;
4581 
4582  /*
4583  * These subcommands affect write operations only.
4584  */
4585  case AT_EnableTrig:
4586  case AT_EnableAlwaysTrig:
4587  case AT_EnableReplicaTrig:
4588  case AT_EnableTrigAll:
4589  case AT_EnableTrigUser:
4590  case AT_DisableTrig:
4591  case AT_DisableTrigAll:
4592  case AT_DisableTrigUser:
4593  cmd_lockmode = ShareRowExclusiveLock;
4594  break;
4595 
4596  /*
4597  * These subcommands affect write operations only. XXX
4598  * Theoretically, these could be ShareRowExclusiveLock.
4599  */
4600  case AT_ColumnDefault:
4602  case AT_AlterConstraint:
4603  case AT_AddIndex: /* from ADD CONSTRAINT */
4604  case AT_AddIndexConstraint:
4605  case AT_ReplicaIdentity:
4606  case AT_SetNotNull:
4607  case AT_SetAttNotNull:
4608  case AT_EnableRowSecurity:
4609  case AT_DisableRowSecurity:
4610  case AT_ForceRowSecurity:
4611  case AT_NoForceRowSecurity:
4612  case AT_AddIdentity:
4613  case AT_DropIdentity:
4614  case AT_SetIdentity:
4615  case AT_SetExpression:
4616  case AT_DropExpression:
4617  case AT_SetCompression:
4618  cmd_lockmode = AccessExclusiveLock;
4619  break;
4620 
4621  case AT_AddConstraint:
4622  case AT_ReAddConstraint: /* becomes AT_AddConstraint */
4623  case AT_ReAddDomainConstraint: /* becomes AT_AddConstraint */
4624  if (IsA(cmd->def, Constraint))
4625  {
4626  Constraint *con = (Constraint *) cmd->def;
4627 
4628  switch (con->contype)
4629  {
4630  case CONSTR_EXCLUSION:
4631  case CONSTR_PRIMARY:
4632  case CONSTR_UNIQUE:
4633 
4634  /*
4635  * Cases essentially the same as CREATE INDEX. We
4636  * could reduce the lock strength to ShareLock if
4637  * we can work out how to allow concurrent catalog
4638  * updates. XXX Might be set down to
4639  * ShareRowExclusiveLock but requires further
4640  * analysis.
4641  */
4642  cmd_lockmode = AccessExclusiveLock;
4643  break;
4644  case CONSTR_FOREIGN:
4645 
4646  /*
4647  * We add triggers to both tables when we add a
4648  * Foreign Key, so the lock level must be at least
4649  * as strong as CREATE TRIGGER.
4650  */
4651  cmd_lockmode = ShareRowExclusiveLock;
4652  break;
4653 
4654  default:
4655  cmd_lockmode = AccessExclusiveLock;
4656  }
4657  }
4658  break;
4659 
4660  /*
4661  * These subcommands affect inheritance behaviour. Queries
4662  * started before us will continue to see the old inheritance
4663  * behaviour, while queries started after we commit will see
4664  * new behaviour. No need to prevent reads or writes to the
4665  * subtable while we hook it up though. Changing the TupDesc
4666  * may be a problem, so keep highest lock.
4667  */
4668  case AT_AddInherit:
4669  case AT_DropInherit:
4670  cmd_lockmode = AccessExclusiveLock;
4671  break;
4672 
4673  /*
4674  * These subcommands affect implicit row type conversion. They
4675  * have affects similar to CREATE/DROP CAST on queries. don't
4676  * provide for invalidating parse trees as a result of such
4677  * changes, so we keep these at AccessExclusiveLock.
4678  */
4679  case AT_AddOf:
4680  case AT_DropOf:
4681  cmd_lockmode = AccessExclusiveLock;
4682  break;
4683 
4684  /*
4685  * Only used by CREATE OR REPLACE VIEW which must conflict
4686  * with an SELECTs currently using the view.
4687  */
4688  case AT_ReplaceRelOptions:
4689  cmd_lockmode = AccessExclusiveLock;
4690  break;
4691 
4692  /*
4693  * These subcommands affect general strategies for performance
4694  * and maintenance, though don't change the semantic results
4695  * from normal data reads and writes. Delaying an ALTER TABLE
4696  * behind currently active writes only delays the point where
4697  * the new strategy begins to take effect, so there is no
4698  * benefit in waiting. In this case the minimum restriction
4699  * applies: we don't currently allow concurrent catalog
4700  * updates.
4701  */
4702  case AT_SetStatistics: /* Uses MVCC in getTableAttrs() */
4703  case AT_ClusterOn: /* Uses MVCC in getIndexes() */
4704  case AT_DropCluster: /* Uses MVCC in getIndexes() */
4705  case AT_SetOptions: /* Uses MVCC in getTableAttrs() */
4706  case AT_ResetOptions: /* Uses MVCC in getTableAttrs() */
4707  cmd_lockmode = ShareUpdateExclusiveLock;
4708  break;
4709 
4710  case AT_SetLogged:
4711  case AT_SetUnLogged:
4712  cmd_lockmode = AccessExclusiveLock;
4713  break;
4714 
4715  case AT_ValidateConstraint: /* Uses MVCC in getConstraints() */
4716  cmd_lockmode = ShareUpdateExclusiveLock;
4717  break;
4718 
4719  /*
4720  * Rel options are more complex than first appears. Options
4721  * are set here for tables, views and indexes; for historical
4722  * reasons these can all be used with ALTER TABLE, so we can't
4723  * decide between them using the basic grammar.
4724  */
4725  case AT_SetRelOptions: /* Uses MVCC in getIndexes() and
4726  * getTables() */
4727  case AT_ResetRelOptions: /* Uses MVCC in getIndexes() and
4728  * getTables() */
4729  cmd_lockmode = AlterTableGetRelOptionsLockLevel((List *) cmd->def);
4730  break;
4731 
4732  case AT_AttachPartition:
4733  cmd_lockmode = ShareUpdateExclusiveLock;
4734  break;
4735 
4736  case AT_DetachPartition:
4737  if (((PartitionCmd *) cmd->def)->concurrent)
4738  cmd_lockmode = ShareUpdateExclusiveLock;
4739  else
4740  cmd_lockmode = AccessExclusiveLock;
4741  break;
4742 
4744  cmd_lockmode = ShareUpdateExclusiveLock;
4745  break;
4746 
4747  case AT_SplitPartition:
4748  cmd_lockmode = AccessExclusiveLock;
4749  break;
4750 
4751  case AT_MergePartitions:
4752  cmd_lockmode = AccessExclusiveLock;
4753  break;
4754 
4755  default: /* oops */
4756  elog(ERROR, "unrecognized alter table type: %d",
4757  (int) cmd->subtype);
4758  break;
4759  }
4760 
4761  /*
4762  * Take the greatest lockmode from any subcommand
4763  */
4764  if (cmd_lockmode > lockmode)
4765  lockmode = cmd_lockmode;
4766  }
4767 
4768  return lockmode;
4769 }
4770 
4771 /*
4772  * ATController provides top level control over the phases.
4773  *
4774  * parsetree is passed in to allow it to be passed to event triggers
4775  * when requested.
4776  */
4777 static void
4779  Relation rel, List *cmds, bool recurse, LOCKMODE lockmode,
4781 {
4782  List *wqueue = NIL;
4783  ListCell *lcmd;
4784 
4785  /* Phase 1: preliminary examination of commands, create work queue */
4786  foreach(lcmd, cmds)
4787  {
4788  AlterTableCmd *cmd = (AlterTableCmd *) lfirst(lcmd);
4789 
4790  ATPrepCmd(&wqueue, rel, cmd, recurse, false, lockmode, context);
4791  }
4792 
4793  /* Close the relation, but keep lock until commit */
4794  relation_close(rel, NoLock);
4795 
4796  /* Phase 2: update system catalogs */
4797  ATRewriteCatalogs(&wqueue, lockmode, context);
4798 
4799  /* Phase 3: scan/rewrite tables as needed, and run afterStmts */
4800  ATRewriteTables(parsetree, &wqueue, lockmode, context);
4801 }
4802 
4803 /*
4804  * ATPrepCmd
4805  *
4806  * Traffic cop for ALTER TABLE Phase 1 operations, including simple
4807  * recursion and permission checks.
4808  *
4809  * Caller must have acquired appropriate lock type on relation already.
4810  * This lock should be held until commit.
4811  */
4812 static void
4813 ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd,
4814  bool recurse, bool recursing, LOCKMODE lockmode,
4816 {
4817  AlteredTableInfo *tab;
4819 
4820  /* Find or create work queue entry for this table */
4821  tab = ATGetQueueEntry(wqueue, rel);
4822 
4823  /*
4824  * Disallow any ALTER TABLE other than ALTER TABLE DETACH FINALIZE on
4825  * partitions that are pending detach.
4826  */
4827  if (rel->rd_rel->relispartition &&
4830  ereport(ERROR,
4831  errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
4832  errmsg("cannot alter partition \"%s\" with an incomplete detach",
4834  errhint("Use ALTER TABLE ... DETACH PARTITION ... FINALIZE to complete the pending detach operation."));
4835 
4836  /*
4837  * Copy the original subcommand for each table, so we can scribble on it.
4838  * This avoids conflicts when different child tables need to make
4839  * different parse transformations (for example, the same column may have
4840  * different column numbers in different children).
4841  */
4842  cmd = copyObject(cmd);
4843 
4844  /*
4845  * Do permissions and relkind checking, recursion to child tables if
4846  * needed, and any additional phase-1 processing needed. (But beware of
4847  * adding any processing that looks at table details that another
4848  * subcommand could change. In some cases we reject multiple subcommands
4849  * that could try to change the same state in contrary ways.)
4850  */
4851  switch (cmd->subtype)
4852  {
4853  case AT_AddColumn: /* ADD COLUMN */
4854  ATSimplePermissions(cmd->subtype, rel,
4856  ATPrepAddColumn(wqueue, rel, recurse, recursing, false, cmd,
4857  lockmode, context);
4858  /* Recursion occurs during execution phase */
4859  pass = AT_PASS_ADD_COL;
4860  break;
4861  case AT_AddColumnToView: /* add column via CREATE OR REPLACE VIEW */
4862  ATSimplePermissions(cmd->subtype, rel, ATT_VIEW);
4863  ATPrepAddColumn(wqueue, rel, recurse, recursing, true, cmd,
4864  lockmode, context);
4865  /* Recursion occurs during execution phase */
4866  pass = AT_PASS_ADD_COL;
4867  break;
4868  case AT_ColumnDefault: /* ALTER COLUMN DEFAULT */
4869 
4870  /*
4871  * We allow defaults on views so that INSERT into a view can have
4872  * default-ish behavior. This works because the rewriter
4873  * substitutes default values into INSERTs before it expands
4874  * rules.
4875  */
4877  ATSimpleRecursion(wqueue, rel, cmd, recurse, lockmode, context);
4878  /* No command-specific prep needed */
4879  pass = cmd->def ? AT_PASS_ADD_OTHERCONSTR : AT_PASS_DROP;
4880  break;
4881  case AT_CookedColumnDefault: /* add a pre-cooked default */
4882  /* This is currently used only in CREATE TABLE */
4883  /* (so the permission check really isn't necessary) */
4885  /* This command never recurses */
4886  pass = AT_PASS_ADD_OTHERCONSTR;
4887  break;
4888  case AT_AddIdentity:
4890  /* Set up recursion for phase 2; no other prep needed */
4891  if (recurse)
4892  cmd->recurse = true;
4893  pass = AT_PASS_ADD_OTHERCONSTR;
4894  break;
4895  case AT_SetIdentity:
4897  /* Set up recursion for phase 2; no other prep needed */
4898  if (recurse)
4899  cmd->recurse = true;
4900  /* This should run after AddIdentity, so do it in MISC pass */
4901  pass = AT_PASS_MISC;
4902  break;
4903  case AT_DropIdentity:
4905  /* Set up recursion for phase 2; no other prep needed */
4906  if (recurse)
4907  cmd->recurse = true;
4908  pass = AT_PASS_DROP;
4909  break;
4910  case AT_DropNotNull: /* ALTER COLUMN DROP NOT NULL */
4912  /* Set up recursion for phase 2; no other prep needed */
4913  if (recurse)
4914  cmd->recurse = true;
4915  pass = AT_PASS_DROP;
4916  break;
4917  case AT_SetNotNull: /* ALTER COLUMN SET NOT NULL */
4919  /* Set up recursion for phase 2; no other prep needed */
4920  if (recurse)
4921  cmd->recurse = true;
4922  pass = AT_PASS_COL_ATTRS;
4923  break;
4924  case AT_SetAttNotNull: /* set pg_attribute.attnotnull without adding
4925  * a constraint */
4927  /* Need command-specific recursion decision */
4928  ATSimpleRecursion(wqueue, rel, cmd, recurse, lockmode, context);
4929  pass = AT_PASS_COL_ATTRS;
4930  break;
4931  case AT_SetExpression: /* ALTER COLUMN SET EXPRESSION */
4933  ATSimpleRecursion(wqueue, rel, cmd, recurse, lockmode, context);
4934  pass = AT_PASS_SET_EXPRESSION;
4935  break;
4936  case AT_DropExpression: /* ALTER COLUMN DROP EXPRESSION */
4938  ATSimpleRecursion(wqueue, rel, cmd, recurse, lockmode, context);
4939  ATPrepDropExpression(rel, cmd, recurse, recursing, lockmode);
4940  pass = AT_PASS_DROP;
4941  break;
4942  case AT_SetStatistics: /* ALTER COLUMN SET STATISTICS */
4944  ATSimpleRecursion(wqueue, rel, cmd, recurse, lockmode, context);
4945  /* No command-specific prep needed */
4946  pass = AT_PASS_MISC;
4947  break;
4948  case AT_SetOptions: /* ALTER COLUMN SET ( options ) */
4949  case AT_ResetOptions: /* ALTER COLUMN RESET ( options ) */
4951  /* This command never recurses */
4952  pass = AT_PASS_MISC;
4953  break;
4954  case AT_SetStorage: /* ALTER COLUMN SET STORAGE */
4956  ATSimpleRecursion(wqueue, rel, cmd, recurse, lockmode, context);
4957  /* No command-specific prep needed */
4958  pass = AT_PASS_MISC;
4959  break;
4960  case AT_SetCompression: /* ALTER COLUMN SET COMPRESSION */
4962  /* This command never recurses */
4963  /* No command-specific prep needed */
4964  pass = AT_PASS_MISC;
4965  break;
4966  case AT_DropColumn: /* DROP COLUMN */
4967  ATSimplePermissions(cmd->subtype, rel,
4969  ATPrepDropColumn(wqueue, rel, recurse, recursing, cmd,
4970  lockmode, context);
4971  /* Recursion occurs during execution phase */
4972  pass = AT_PASS_DROP;
4973  break;
4974  case AT_AddIndex: /* ADD INDEX */
4976  /* This command never recurses */
4977  /* No command-specific prep needed */
4978  pass = AT_PASS_ADD_INDEX;
4979  break;
4980  case AT_AddConstraint: /* ADD CONSTRAINT */
4982  /* Recursion occurs during execution phase */
4983  /* No command-specific prep needed except saving recurse flag */
4984  if (recurse)
4985  cmd->recurse = true;
4986  pass = AT_PASS_ADD_CONSTR;
4987  break;
4988  case AT_AddIndexConstraint: /* ADD CONSTRAINT USING INDEX */
4990  /* This command never recurses */
4991  /* No command-specific prep needed */
4992  pass = AT_PASS_ADD_INDEXCONSTR;
4993  break;
4994  case AT_DropConstraint: /* DROP CONSTRAINT */
4996  ATCheckPartitionsNotInUse(rel, lockmode);
4997  /* Other recursion occurs during execution phase */
4998  /* No command-specific prep needed except saving recurse flag */
4999  if (recurse)
5000  cmd->recurse = true;
5001  pass = AT_PASS_DROP;
5002  break;
5003  case AT_AlterColumnType: /* ALTER COLUMN TYPE */
5004  ATSimplePermissions(cmd->subtype, rel,
5006  /* See comments for ATPrepAlterColumnType */
5007  cmd = ATParseTransformCmd(wqueue, tab, rel, cmd, recurse, lockmode,
5009  Assert(cmd != NULL);
5010  /* Performs own recursion */
5011  ATPrepAlterColumnType(wqueue, tab, rel, recurse, recursing, cmd,
5012  lockmode, context);
5013  pass = AT_PASS_ALTER_TYPE;
5014  break;
5017  /* This command never recurses */
5018  /* No command-specific prep needed */
5019  pass = AT_PASS_MISC;
5020  break;
5021  case AT_ChangeOwner: /* ALTER OWNER */
5022  /* This command never recurses */
5023  /* No command-specific prep needed */
5024  pass = AT_PASS_MISC;
5025  break;
5026  case AT_ClusterOn: /* CLUSTER ON */
5027  case AT_DropCluster: /* SET WITHOUT CLUSTER */
5029  /* These commands never recurse */
5030  /* No command-specific prep needed */
5031  pass = AT_PASS_MISC;
5032  break;
5033  case AT_SetLogged: /* SET LOGGED */
5035  if (tab->chgPersistence)
5036  ereport(ERROR,
5037  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
5038  errmsg("cannot change persistence setting twice")));
5039  tab->chgPersistence = ATPrepChangePersistence(rel, true);
5040  /* force rewrite if necessary; see comment in ATRewriteTables */
5041  if (tab->chgPersistence)
5042  {
5044  tab->newrelpersistence = RELPERSISTENCE_PERMANENT;
5045  }
5046  pass = AT_PASS_MISC;
5047  break;
5048  case AT_SetUnLogged: /* SET UNLOGGED */
5050  if (tab->chgPersistence)
5051  ereport(ERROR,
5052  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
5053  errmsg("cannot change persistence setting twice")));
5054  tab->chgPersistence = ATPrepChangePersistence(rel, false);
5055  /* force rewrite if necessary; see comment in ATRewriteTables */
5056  if (tab->chgPersistence)
5057  {
5059  tab->newrelpersistence = RELPERSISTENCE_UNLOGGED;
5060  }
5061  pass = AT_PASS_MISC;
5062  break;
5063  case AT_DropOids: /* SET WITHOUT OIDS */
5065  pass = AT_PASS_DROP;
5066  break;
5067  case AT_SetAccessMethod: /* SET ACCESS METHOD */
5069 
5070  /* check if another access method change was already requested */
5071  if (tab->chgAccessMethod)
5072  ereport(ERROR,
5073  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
5074  errmsg("cannot have multiple SET ACCESS METHOD subcommands")));
5075 
5076  ATPrepSetAccessMethod(tab, rel, cmd->name);
5077  pass = AT_PASS_MISC; /* does not matter; no work in Phase 2 */
5078  break;
5079  case AT_SetTableSpace: /* SET TABLESPACE */
5082  /* This command never recurses */
5083  ATPrepSetTableSpace(tab, rel, cmd->name, lockmode);
5084  pass = AT_PASS_MISC; /* doesn't actually matter */
5085  break;
5086  case AT_SetRelOptions: /* SET (...) */
5087  case AT_ResetRelOptions: /* RESET (...) */
5088  case AT_ReplaceRelOptions: /* reset them all, then set just these */
5090  /* This command never recurses */
5091  /* No command-specific prep needed */
5092  pass = AT_PASS_MISC;
5093  break;
5094  case AT_AddInherit: /* INHERIT */
5096  /* This command never recurses */
5097  ATPrepAddInherit(rel);
5098  pass = AT_PASS_MISC;
5099  break;
5100  case AT_DropInherit: /* NO INHERIT */
5102  /* This command never recurses */
5103  /* No command-specific prep needed */
5104  pass = AT_PASS_MISC;
5105  break;
5106  case AT_AlterConstraint: /* ALTER CONSTRAINT */
5108  /* Recursion occurs during execution phase */
5109  pass = AT_PASS_MISC;
5110  break;
5111  case AT_ValidateConstraint: /* VALIDATE CONSTRAINT */
5113  /* Recursion occurs during execution phase */
5114  /* No command-specific prep needed except saving recurse flag */
5115  if (recurse)
5116  cmd->recurse = true;
5117  pass = AT_PASS_MISC;
5118  break;
5119  case AT_ReplicaIdentity: /* REPLICA IDENTITY ... */
5121  pass = AT_PASS_MISC;
5122  /* This command never recurses */
5123  /* No command-specific prep needed */
5124  break;
5125  case AT_EnableTrig: /* ENABLE TRIGGER variants */
5126  case AT_EnableAlwaysTrig:
5127  case AT_EnableReplicaTrig:
5128  case AT_EnableTrigAll:
5129  case AT_EnableTrigUser:
5130  case AT_DisableTrig: /* DISABLE TRIGGER variants */
5131  case AT_DisableTrigAll:
5132  case AT_DisableTrigUser:
5134  /* Set up recursion for phase 2; no other prep needed */
5135  if (recurse)
5136  cmd->recurse = true;
5137  pass = AT_PASS_MISC;
5138  break;
5139  case AT_EnableRule: /* ENABLE/DISABLE RULE variants */
5140  case AT_EnableAlwaysRule:
5141  case AT_EnableReplicaRule:
5142  case AT_DisableRule:
5143  case AT_AddOf: /* OF */
5144  case AT_DropOf: /* NOT OF */
5145  case AT_EnableRowSecurity:
5146  case AT_DisableRowSecurity:
5147  case AT_ForceRowSecurity:
5148  case AT_NoForceRowSecurity:
5150  /* These commands never recurse */
5151  /* No command-specific prep needed */
5152  pass = AT_PASS_MISC;
5153  break;
5154  case AT_GenericOptions:
5156  /* No command-specific prep needed */
5157  pass = AT_PASS_MISC;
5158  break;
5159  case AT_AttachPartition:
5161  /* No command-specific prep needed */
5162  pass = AT_PASS_MISC;
5163  break;
5164  case AT_DetachPartition:
5166  /* No command-specific prep needed */
5167  pass = AT_PASS_MISC;
5168  break;
5171  /* No command-specific prep needed */
5172  pass = AT_PASS_MISC;
5173  break;
5174  case AT_SplitPartition:
5176  /* No command-specific prep needed */
5177  pass = AT_PASS_MISC;
5178  break;
5179  case AT_MergePartitions:
5181  /* No command-specific prep needed */
5182  pass = AT_PASS_MISC;
5183  break;
5184  default: /* oops */
5185  elog(ERROR, "unrecognized alter table type: %d",
5186  (int) cmd->subtype);
5187  pass = AT_PASS_UNSET; /* keep compiler quiet */
5188  break;
5189  }
5190  Assert(pass > AT_PASS_UNSET);
5191 
5192  /* Add the subcommand to the appropriate list for phase 2 */
5193  tab->subcmds[pass] = lappend(tab->subcmds[pass], cmd);
5194 }
5195 
5196 /*
5197  * ATRewriteCatalogs
5198  *
5199  * Traffic cop for ALTER TABLE Phase 2 operations. Subcommands are
5200  * dispatched in a "safe" execution order (designed to avoid unnecessary
5201  * conflicts).
5202  */
5203 static void
5204 ATRewriteCatalogs(List **wqueue, LOCKMODE lockmode,
5206 {
5207  ListCell *ltab;
5208 
5209  /*
5210  * We process all the tables "in parallel", one pass at a time. This is
5211  * needed because we may have to propagate work from one table to another
5212  * (specifically, ALTER TYPE on a foreign key's PK has to dispatch the
5213  * re-adding of the foreign key constraint to the other table). Work can
5214  * only be propagated into later passes, however.
5215  */
5216  for (AlterTablePass pass = 0; pass < AT_NUM_PASSES; pass++)
5217  {
5218  /* Go through each table that needs to be processed */
5219  foreach(ltab, *wqueue)
5220  {
5221  AlteredTableInfo *tab = (AlteredTableInfo *) lfirst(ltab);
5222  List *subcmds = tab->subcmds[pass];
5223  ListCell *lcmd;
5224 
5225  if (subcmds == NIL)
5226  continue;
5227 
5228  /*
5229  * Open the relation and store it in tab. This allows subroutines
5230  * close and reopen, if necessary. Appropriate lock was obtained
5231  * by phase 1, needn't get it again.
5232  */
5233  tab->rel = relation_open(tab->relid, NoLock);
5234 
5235  foreach(lcmd, subcmds)
5236  ATExecCmd(wqueue, tab,
5237  lfirst_node(AlterTableCmd, lcmd),
5238  lockmode, pass, context);
5239 
5240  /*
5241  * After the ALTER TYPE or SET EXPRESSION pass, do cleanup work
5242  * (this is not done in ATExecAlterColumnType since it should be
5243  * done only once if multiple columns of a table are altered).
5244  */
5245  if (pass == AT_PASS_ALTER_TYPE || pass == AT_PASS_SET_EXPRESSION)
5246  ATPostAlterTypeCleanup(wqueue, tab, lockmode);
5247 
5248  if (tab->rel)
5249  {
5250  relation_close(tab->rel, NoLock);
5251  tab->rel = NULL;
5252  }
5253  }
5254  }
5255 
5256  /* Check to see if a toast table must be added. */
5257  foreach(ltab, *wqueue)
5258  {
5259  AlteredTableInfo *tab = (AlteredTableInfo *) lfirst(ltab);
5260 
5261  /*
5262  * If the table is source table of ATTACH PARTITION command, we did
5263  * not modify anything about it that will change its toasting
5264  * requirement, so no need to check.
5265  */
5266  if (((tab->relkind == RELKIND_RELATION ||
5267  tab->relkind == RELKIND_PARTITIONED_TABLE) &&
5268  tab->partition_constraint == NULL) ||
5269  tab->relkind == RELKIND_MATVIEW)
5270  AlterTableCreateToastTable(tab->relid, (Datum) 0, lockmode);
5271  }
5272 }
5273 
5274 /*
5275  * ATExecCmd: dispatch a subcommand to appropriate execution routine
5276  */
5277 static void
5279  AlterTableCmd *cmd, LOCKMODE lockmode, AlterTablePass cur_pass,
5281 {
5283  Relation rel = tab->rel;
5284 
5285  switch (cmd->subtype)
5286  {
5287  case AT_AddColumn: /* ADD COLUMN */
5288  case AT_AddColumnToView: /* add column via CREATE OR REPLACE VIEW */
5289  address = ATExecAddColumn(wqueue, tab, rel, &cmd,
5290  cmd->recurse, false,
5291  lockmode, cur_pass, context);
5292  break;
5293  case AT_ColumnDefault: /* ALTER COLUMN DEFAULT */
5294  address = ATExecColumnDefault(rel, cmd->name, cmd->def, lockmode);
5295  break;
5296  case AT_CookedColumnDefault: /* add a pre-cooked default */
5297  address = ATExecCookedColumnDefault(rel, cmd->num, cmd->def);
5298  break;
5299  case AT_AddIdentity:
5300  cmd = ATParseTransformCmd(wqueue, tab, rel, cmd, false, lockmode,
5301  cur_pass, context);
5302  Assert(cmd != NULL);
5303  address = ATExecAddIdentity(rel, cmd->name, cmd->def, lockmode, cmd->recurse, false);
5304  break;
5305  case AT_SetIdentity:
5306  cmd = ATParseTransformCmd(wqueue, tab, rel, cmd, false, lockmode,
5307  cur_pass, context);
5308  Assert(cmd != NULL);
5309  address = ATExecSetIdentity(rel, cmd->name, cmd->def, lockmode, cmd->recurse, false);
5310  break;
5311  case AT_DropIdentity:
5312  address = ATExecDropIdentity(rel, cmd->name, cmd->missing_ok, lockmode, cmd->recurse, false);
5313  break;
5314  case AT_DropNotNull: /* ALTER COLUMN DROP NOT NULL */
5315  address = ATExecDropNotNull(rel, cmd->name, cmd->recurse, lockmode);
5316  break;
5317  case AT_SetNotNull: /* ALTER COLUMN SET NOT NULL */
5318  address = ATExecSetNotNull(wqueue, rel, NULL, cmd->name,
5319  cmd->recurse, false, NULL, lockmode);
5320  break;
5321  case AT_SetAttNotNull: /* set pg_attribute.attnotnull */
5322  address = ATExecSetAttNotNull(wqueue, rel, cmd->name, lockmode);
5323  break;
5324  case AT_SetExpression:
5325  address = ATExecSetExpression(tab, rel, cmd->name, cmd->def, lockmode);
5326  break;
5327  case AT_DropExpression:
5328  address = ATExecDropExpression(rel, cmd->name, cmd->missing_ok, lockmode);
5329  break;
5330  case AT_SetStatistics: /* ALTER COLUMN SET STATISTICS */
5331  address = ATExecSetStatistics(rel, cmd->name, cmd->num, cmd->def, lockmode);
5332  break;
5333  case AT_SetOptions: /* ALTER COLUMN SET ( options ) */
5334  address = ATExecSetOptions(rel, cmd->name, cmd->def, false, lockmode);
5335  break;
5336  case AT_ResetOptions: /* ALTER COLUMN RESET ( options ) */
5337  address = ATExecSetOptions(rel, cmd->name, cmd->def, true, lockmode);
5338  break;
5339  case AT_SetStorage: /* ALTER COLUMN SET STORAGE */
5340  address = ATExecSetStorage(rel, cmd->name, cmd->def, lockmode);
5341  break;
5342  case AT_SetCompression: /* ALTER COLUMN SET COMPRESSION */
5343  address = ATExecSetCompression(rel, cmd->name, cmd->def,
5344  lockmode);
5345  break;
5346  case AT_DropColumn: /* DROP COLUMN */
5347  address = ATExecDropColumn(wqueue, rel, cmd->name,
5348  cmd->behavior, cmd->recurse, false,
5349  cmd->missing_ok, lockmode,
5350  NULL);
5351  break;
5352  case AT_AddIndex: /* ADD INDEX */
5353  address = ATExecAddIndex(tab, rel, (IndexStmt *) cmd->def, false,
5354  lockmode);
5355  break;
5356  case AT_ReAddIndex: /* ADD INDEX */
5357  address = ATExecAddIndex(tab, rel, (IndexStmt *) cmd->def, true,
5358  lockmode);
5359  break;
5360  case AT_ReAddStatistics: /* ADD STATISTICS */
5361  address = ATExecAddStatistics(tab, rel, (CreateStatsStmt *) cmd->def,
5362  true, lockmode);
5363  break;
5364  case AT_AddConstraint: /* ADD CONSTRAINT */
5365  /* Transform the command only during initial examination */
5366  if (cur_pass == AT_PASS_ADD_CONSTR)
5367  cmd = ATParseTransformCmd(wqueue, tab, rel, cmd,
5368  cmd->recurse, lockmode,
5369  cur_pass, context);
5370  /* Depending on constraint type, might be no more work to do now */
5371  if (cmd != NULL)
5372  address =
5373  ATExecAddConstraint(wqueue, tab, rel,
5374  (Constraint *) cmd->def,
5375  cmd->recurse, false, lockmode);
5376  break;
5377  case AT_ReAddConstraint: /* Re-add pre-existing check constraint */
5378  address =
5379  ATExecAddConstraint(wqueue, tab, rel, (Constraint *) cmd->def,
5380  true, true, lockmode);
5381  break;
5382  case AT_ReAddDomainConstraint: /* Re-add pre-existing domain check
5383  * constraint */
5384  address =
5385  AlterDomainAddConstraint(((AlterDomainStmt *) cmd->def)->typeName,
5386  ((AlterDomainStmt *) cmd->def)->def,
5387  NULL);
5388  break;
5389  case AT_ReAddComment: /* Re-add existing comment */
5390  address = CommentObject((CommentStmt *) cmd->def);
5391  break;
5392  case AT_AddIndexConstraint: /* ADD CONSTRAINT USING INDEX */
5393  address = ATExecAddIndexConstraint(tab, rel, (IndexStmt *) cmd->def,
5394  lockmode);
5395  break;
5396  case AT_AlterConstraint: /* ALTER CONSTRAINT */
5397  address = ATExecAlterConstraint(rel, cmd, false, false, lockmode);
5398  break;
5399  case AT_ValidateConstraint: /* VALIDATE CONSTRAINT */
5400  address = ATExecValidateConstraint(wqueue, rel, cmd->name, cmd->recurse,
5401  false, lockmode);
5402  break;
5403  case AT_DropConstraint: /* DROP CONSTRAINT */
5404  ATExecDropConstraint(rel, cmd->name, cmd->behavior,
5405  cmd->recurse,
5406  cmd->missing_ok, lockmode);
5407  break;
5408  case AT_AlterColumnType: /* ALTER COLUMN TYPE */
5409  /* parse transformation was done earlier */
5410  address = ATExecAlterColumnType(tab, rel, cmd, lockmode);
5411  break;
5412  case AT_AlterColumnGenericOptions: /* ALTER COLUMN OPTIONS */
5413  address =
5415  (List *) cmd->def, lockmode);
5416  break;
5417  case AT_ChangeOwner: /* ALTER OWNER */
5419  get_rolespec_oid(cmd->newowner, false),
5420  false, lockmode);
5421  break;
5422  case AT_ClusterOn: /* CLUSTER ON */
5423  address = ATExecClusterOn(rel, cmd->name, lockmode);
5424  break;
5425  case AT_DropCluster: /* SET WITHOUT CLUSTER */
5426  ATExecDropCluster(rel, lockmode);
5427  break;
5428  case AT_SetLogged: /* SET LOGGED */
5429  case AT_SetUnLogged: /* SET UNLOGGED */
5430  break;
5431  case AT_DropOids: /* SET WITHOUT OIDS */
5432  /* nothing to do here, oid columns don't exist anymore */
5433  break;
5434  case AT_SetAccessMethod: /* SET ACCESS METHOD */
5435 
5436  /*
5437  * Only do this for partitioned tables, for which this is just a
5438  * catalog change. Tables with storage are handled by Phase 3.
5439  */
5440  if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE &&
5441  tab->chgAccessMethod)
5443  break;
5444  case AT_SetTableSpace: /* SET TABLESPACE */
5445 
5446  /*
5447  * Only do this for partitioned tables and indexes, for which this
5448  * is just a catalog change. Other relation types which have
5449  * storage are handled by Phase 3.
5450  */
5451  if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE ||
5452  rel->rd_rel->relkind == RELKIND_PARTITIONED_INDEX)
5454 
5455  break;
5456  case AT_SetRelOptions: /* SET (...) */
5457  case AT_ResetRelOptions: /* RESET (...) */
5458  case AT_ReplaceRelOptions: /* replace entire option list */
5459  ATExecSetRelOptions(rel, (List *) cmd->def, cmd->subtype, lockmode);
5460  break;
5461  case AT_EnableTrig: /* ENABLE TRIGGER name */
5462  ATExecEnableDisableTrigger(rel, cmd->name,
5463  TRIGGER_FIRES_ON_ORIGIN, false,
5464  cmd->recurse,
5465  lockmode);
5466  break;
5467  case AT_EnableAlwaysTrig: /* ENABLE ALWAYS TRIGGER name */
5468  ATExecEnableDisableTrigger(rel, cmd->name,
5469  TRIGGER_FIRES_ALWAYS, false,
5470  cmd->recurse,
5471  lockmode);
5472  break;
5473  case AT_EnableReplicaTrig: /* ENABLE REPLICA TRIGGER name */
5474  ATExecEnableDisableTrigger(rel, cmd->name,
5475  TRIGGER_FIRES_ON_REPLICA, false,
5476  cmd->recurse,
5477  lockmode);
5478  break;
5479  case AT_DisableTrig: /* DISABLE TRIGGER name */
5480  ATExecEnableDisableTrigger(rel, cmd->name,
5481  TRIGGER_DISABLED, false,
5482  cmd->recurse,
5483  lockmode);
5484  break;
5485  case AT_EnableTrigAll: /* ENABLE TRIGGER ALL */
5486  ATExecEnableDisableTrigger(rel, NULL,
5487  TRIGGER_FIRES_ON_ORIGIN, false,
5488  cmd->recurse,
5489  lockmode);
5490  break;
5491  case AT_DisableTrigAll: /* DISABLE TRIGGER ALL */
5492  ATExecEnableDisableTrigger(rel, NULL,
5493  TRIGGER_DISABLED, false,
5494  cmd->recurse,
5495  lockmode);
5496  break;
5497  case AT_EnableTrigUser: /* ENABLE TRIGGER USER */
5498  ATExecEnableDisableTrigger(rel, NULL,
5500  cmd->recurse,
5501  lockmode);
5502  break;
5503  case AT_DisableTrigUser: /* DISABLE TRIGGER USER */
5504  ATExecEnableDisableTrigger(rel, NULL,
5505  TRIGGER_DISABLED, true,
5506  cmd->recurse,
5507  lockmode);
5508  break;
5509 
5510  case AT_EnableRule: /* ENABLE RULE name */
5511  ATExecEnableDisableRule(rel, cmd->name,
5512  RULE_FIRES_ON_ORIGIN, lockmode);
5513  break;
5514  case AT_EnableAlwaysRule: /* ENABLE ALWAYS RULE name */
5515  ATExecEnableDisableRule(rel, cmd->name,
5516  RULE_FIRES_ALWAYS, lockmode);
5517  break;
5518  case AT_EnableReplicaRule: /* ENABLE REPLICA RULE name */
5519  ATExecEnableDisableRule(rel, cmd->name,
5520  RULE_FIRES_ON_REPLICA, lockmode);
5521  break;
5522  case AT_DisableRule: /* DISABLE RULE name */
5523  ATExecEnableDisableRule(rel, cmd->name,
5524  RULE_DISABLED, lockmode);
5525  break;
5526 
5527  case AT_AddInherit:
5528  address = ATExecAddInherit(rel, (RangeVar *) cmd->def, lockmode);
5529  break;
5530  case AT_DropInherit:
5531  address = ATExecDropInherit(rel, (RangeVar *) cmd->def, lockmode);
5532  break;
5533  case AT_AddOf:
5534  address = ATExecAddOf(rel, (TypeName *) cmd->def, lockmode);
5535  break;
5536  case AT_DropOf:
5537  ATExecDropOf(rel, lockmode);
5538  break;
5539  case AT_ReplicaIdentity:
5540  ATExecReplicaIdentity(rel, (ReplicaIdentityStmt *) cmd->def, lockmode);
5541  break;
5542  case AT_EnableRowSecurity:
5543  ATExecSetRowSecurity(rel, true);
5544  break;
5545  case AT_DisableRowSecurity:
5546  ATExecSetRowSecurity(rel, false);
5547  break;
5548  case AT_ForceRowSecurity:
5549  ATExecForceNoForceRowSecurity(rel, true);
5550  break;
5551  case AT_NoForceRowSecurity:
5552  ATExecForceNoForceRowSecurity(rel, false);
5553  break;
5554  case AT_GenericOptions:
5555  ATExecGenericOptions(rel, (List *) cmd->def);
5556  break;
5557  case AT_AttachPartition:
5558  cmd = ATParseTransformCmd(wqueue, tab, rel, cmd, false, lockmode,
5559  cur_pass, context);
5560  Assert(cmd != NULL);
5561  if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
5562  address = ATExecAttachPartition(wqueue, rel, (PartitionCmd *) cmd->def,
5563  context);
5564  else
5565  address = ATExecAttachPartitionIdx(wqueue, rel,
5566  ((PartitionCmd *) cmd->def)->name);
5567  break;
5568  case AT_DetachPartition:
5569  cmd = ATParseTransformCmd(wqueue, tab, rel, cmd, false, lockmode,
5570  cur_pass, context);
5571  Assert(cmd != NULL);
5572  /* ATPrepCmd ensures it must be a table */
5573  Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
5574  address = ATExecDetachPartition(wqueue, tab, rel,
5575  ((PartitionCmd *) cmd->def)->name,
5576  ((PartitionCmd *) cmd->def)->concurrent);
5577  break;
5579  address = ATExecDetachPartitionFinalize(rel, ((PartitionCmd *) cmd->def)->name);
5580  break;
5581  case AT_SplitPartition:
5582  cmd = ATParseTransformCmd(wqueue, tab, rel, cmd, false, lockmode,
5583  cur_pass, context);
5584  Assert(cmd != NULL);
5585  Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
5586  ATExecSplitPartition(wqueue, tab, rel, (PartitionCmd *) cmd->def,
5587  context);
5588  break;
5589  case AT_MergePartitions:
5590  cmd = ATParseTransformCmd(wqueue, tab, rel, cmd, false, lockmode,
5591  cur_pass, context);
5592  Assert(cmd != NULL);
5593  Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
5594  ATExecMergePartitions(wqueue, tab, rel, (PartitionCmd *) cmd->def,
5595  context);
5596  break;
5597  default: /* oops */
5598  elog(ERROR, "unrecognized alter table type: %d",
5599  (int) cmd->subtype);
5600  break;
5601  }
5602 
5603  /*
5604  * Report the subcommand to interested event triggers.
5605  */
5606  if (cmd)
5607  EventTriggerCollectAlterTableSubcmd((Node *) cmd, address);
5608 
5609  /*
5610  * Bump the command counter to ensure the next subcommand in the sequence
5611  * can see the changes so far
5612  */
5614 }
5615 
5616 /*
5617  * ATParseTransformCmd: perform parse transformation for one subcommand
5618  *
5619  * Returns the transformed subcommand tree, if there is one, else NULL.
5620  *
5621  * The parser may hand back additional AlterTableCmd(s) and/or other
5622  * utility statements, either before or after the original subcommand.
5623  * Other AlterTableCmds are scheduled into the appropriate slot of the
5624  * AlteredTableInfo (they had better be for later passes than the current one).
5625  * Utility statements that are supposed to happen before the AlterTableCmd
5626  * are executed immediately. Those that are supposed to happen afterwards
5627  * are added to the tab->afterStmts list to be done at the very end.
5628  */
5629 static AlterTableCmd *
5631  AlterTableCmd *cmd, bool recurse, LOCKMODE lockmode,
5633 {
5634  AlterTableCmd *newcmd = NULL;
5636  List *beforeStmts;
5637  List *afterStmts;
5638  ListCell *lc;
5639 
5640  /* Gin up an AlterTableStmt with just this subcommand and this table */
5641  atstmt->relation =
5644  -1);
5645  atstmt->relation->inh = recurse;
5646  atstmt->cmds = list_make1(cmd);
5647  atstmt->objtype = OBJECT_TABLE; /* needn't be picky here */
5648  atstmt->missing_ok = false;
5649 
5650  /* Transform the AlterTableStmt */
5652  atstmt,
5653  context->queryString,
5654  &beforeStmts,
5655  &afterStmts);
5656 
5657  /* Execute any statements that should happen before these subcommand(s) */
5658  foreach(lc, beforeStmts)
5659  {
5660  Node *stmt = (Node *) lfirst(lc);
5661 
5664  }
5665 
5666  /* Examine the transformed subcommands and schedule them appropriately */
5667  foreach(lc, atstmt->cmds)
5668  {
5670  AlterTablePass pass;
5671 
5672  /*
5673  * This switch need only cover the subcommand types that can be added
5674  * by parse_utilcmd.c; otherwise, we'll use the default strategy of
5675  * executing the subcommand immediately, as a substitute for the
5676  * original subcommand. (Note, however, that this does cause
5677  * AT_AddConstraint subcommands to be rescheduled into later passes,
5678  * which is important for index and foreign key constraints.)
5679  *
5680  * We assume we needn't do any phase-1 checks for added subcommands.
5681  */
5682  switch (cmd2->subtype)
5683  {
5684  case AT_SetAttNotNull:
5685  ATSimpleRecursion(wqueue, rel, cmd2, recurse, lockmode, context);
5686  pass = AT_PASS_COL_ATTRS;
5687  break;
5688  case AT_AddIndex:
5689 
5690  /*
5691  * A primary key on an inheritance parent needs supporting NOT
5692  * NULL constraint on its children; enqueue commands to create
5693  * those or mark them inherited if they already exist.
5694  */
5695  ATPrepAddPrimaryKey(wqueue, rel, cmd2, lockmode, context);
5696  pass = AT_PASS_ADD_INDEX;
5697  break;
5698  case AT_AddIndexConstraint:
5699  /* as above */
5700  ATPrepAddPrimaryKey(wqueue, rel, cmd2, lockmode, context);
5701  pass = AT_PASS_ADD_INDEXCONSTR;
5702  break;
5703  case AT_AddConstraint:
5704  /* Recursion occurs during execution phase */
5705  if (recurse)
5706  cmd2->recurse = true;
5707  switch (castNode(Constraint, cmd2->def)->contype)
5708  {
5709  case CONSTR_PRIMARY:
5710  case CONSTR_UNIQUE:
5711  case CONSTR_EXCLUSION:
5712  pass = AT_PASS_ADD_INDEXCONSTR;
5713  break;
5714  default:
5715  pass = AT_PASS_ADD_OTHERCONSTR;
5716  break;
5717  }
5718  break;
5720  /* This command never recurses */
5721  /* No command-specific prep needed */
5722  pass = AT_PASS_MISC;
5723  break;
5724  default:
5725  pass = cur_pass;
5726  break;
5727  }
5728 
5729  if (pass < cur_pass)
5730  {
5731  /* Cannot schedule into a pass we already finished */
5732  elog(ERROR, "ALTER TABLE scheduling failure: too late for pass %d",
5733  pass);
5734  }
5735  else if (pass > cur_pass)
5736  {
5737  /* OK, queue it up for later */
5738  tab->subcmds[pass] = lappend(tab->subcmds[pass], cmd2);
5739  }
5740  else
5741  {
5742  /*
5743  * We should see at most one subcommand for the current pass,
5744  * which is the transformed version of the original subcommand.
5745  */
5746  if (newcmd == NULL && cmd->subtype == cmd2->subtype)
5747  {
5748  /* Found the transformed version of our subcommand */
5749  newcmd = cmd2;
5750  }
5751  else
5752  elog(ERROR, "ALTER TABLE scheduling failure: bogus item for pass %d",
5753  pass);
5754  }
5755  }
5756 
5757  /* Queue up any after-statements to happen at the end */
5758  tab->afterStmts = list_concat(tab->afterStmts, afterStmts);
5759 
5760  return newcmd;
5761 }
5762 
5763 /*
5764  * ATRewriteTables: ALTER TABLE phase 3
5765  */
5766 static void
5767 ATRewriteTables(AlterTableStmt *parsetree, List **wqueue, LOCKMODE lockmode,
5769 {
5770  ListCell *ltab;
5771 
5772  /* Go through each table that needs to be checked or rewritten */
5773  foreach(ltab, *wqueue)
5774  {
5775  AlteredTableInfo *tab = (AlteredTableInfo *) lfirst(ltab);
5776 
5777  /* Relations without storage may be ignored here */
5778  if (!RELKIND_HAS_STORAGE(tab->relkind))
5779  continue;
5780 
5781  /*
5782  * If we change column data types, the operation has to be propagated
5783  * to tables that use this table's rowtype as a column type.
5784  * tab->newvals will also be non-NULL in the case where we're adding a
5785  * column with a default. We choose to forbid that case as well,
5786  * since composite types might eventually support defaults.
5787  *
5788  * (Eventually we'll probably need to check for composite type
5789  * dependencies even when we're just scanning the table without a
5790  * rewrite, but at the moment a composite type does not enforce any
5791  * constraints, so it's not necessary/appropriate to enforce them just
5792  * during ALTER.)
5793  */
5794  if (tab->newvals != NIL || tab->rewrite > 0)
5795  {
5796  Relation rel;
5797 
5798  rel = table_open(tab->relid, NoLock);
5799  find_composite_type_dependencies(rel->rd_rel->reltype, rel, NULL);
5800  table_close(rel, NoLock);
5801  }
5802 
5803  /*
5804  * We only need to rewrite the table if at least one column needs to
5805  * be recomputed, or we are changing its persistence or access method.
5806  *
5807  * There are two reasons for requiring a rewrite when changing
5808  * persistence: on one hand, we need to ensure that the buffers
5809  * belonging to each of the two relations are marked with or without
5810  * BM_PERMANENT properly. On the other hand, since rewriting creates
5811  * and assigns a new relfilenumber, we automatically create or drop an
5812  * init fork for the relation as appropriate.
5813  */
5814  if (tab->rewrite > 0 && tab->relkind != RELKIND_SEQUENCE)
5815  {
5816  /* Build a temporary relation and copy data */
5817  Relation OldHeap;
5818  Oid OIDNewHeap;
5819  Oid NewAccessMethod;
5820  Oid NewTableSpace;
5821  char persistence;
5822 
5823  OldHeap = table_open(tab->relid, NoLock);
5824 
5825  /*
5826  * We don't support rewriting of system catalogs; there are too
5827  * many corner cases and too little benefit. In particular this
5828  * is certainly not going to work for mapped catalogs.
5829  */
5830  if (IsSystemRelation(OldHeap))
5831  ereport(ERROR,
5832  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
5833  errmsg("cannot rewrite system relation \"%s\"",
5834  RelationGetRelationName(OldHeap))));
5835 
5836  if (RelationIsUsedAsCatalogTable(OldHeap))
5837  ereport(ERROR,
5838  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
5839  errmsg("cannot rewrite table \"%s\" used as a catalog table",
5840  RelationGetRelationName(OldHeap))));
5841 
5842  /*
5843  * Don't allow rewrite on temp tables of other backends ... their
5844  * local buffer manager is not going to cope.
5845  */
5846  if (RELATION_IS_OTHER_TEMP(OldHeap))
5847  ereport(ERROR,
5848  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
5849  errmsg("cannot rewrite temporary tables of other sessions")));
5850 
5851  /*
5852  * Select destination tablespace (same as original unless user
5853  * requested a change)
5854  */
5855  if (tab->newTableSpace)
5856  NewTableSpace = tab->newTableSpace;
5857  else
5858  NewTableSpace = OldHeap->rd_rel->reltablespace;
5859 
5860  /*
5861  * Select destination access method (same as original unless user
5862  * requested a change)
5863  */
5864  if (tab->chgAccessMethod)
5865  NewAccessMethod = tab->newAccessMethod;
5866  else
5867  NewAccessMethod = OldHeap->rd_rel->relam;
5868 
5869  /*
5870  * Select persistence of transient table (same as original unless
5871  * user requested a change)
5872  */
5873  persistence = tab->chgPersistence ?
5874  tab->newrelpersistence : OldHeap->rd_rel->relpersistence;
5875 
5876  table_close(OldHeap, NoLock);
5877 
5878  /*
5879  * Fire off an Event Trigger now, before actually rewriting the
5880  * table.
5881  *
5882  * We don't support Event Trigger for nested commands anywhere,
5883  * here included, and parsetree is given NULL when coming from
5884  * AlterTableInternal.
5885  *
5886  * And fire it only once.
5887  */
5888  if (parsetree)
5889  EventTriggerTableRewrite((Node *) parsetree,
5890  tab->relid,
5891  tab->rewrite);
5892 
5893  /*
5894  * Create transient table that will receive the modified data.
5895  *
5896  * Ensure it is marked correctly as logged or unlogged. We have
5897  * to do this here so that buffers for the new relfilenumber will
5898  * have the right persistence set, and at the same time ensure
5899  * that the original filenumbers's buffers will get read in with
5900  * the correct setting (i.e. the original one). Otherwise a
5901  * rollback after the rewrite would possibly result with buffers
5902  * for the original filenumbers having the wrong persistence
5903  * setting.
5904  *
5905  * NB: This relies on swap_relation_files() also swapping the
5906  * persistence. That wouldn't work for pg_class, but that can't be
5907  * unlogged anyway.
5908  */
5909  OIDNewHeap = make_new_heap(tab->relid, NewTableSpace, NewAccessMethod,
5910  persistence, lockmode);
5911 
5912  /*
5913  * Copy the heap data into the new table with the desired
5914  * modifications, and test the current data within the table
5915  * against new constraints generated by ALTER TABLE commands.
5916  */
5917  ATRewriteTable(tab, OIDNewHeap, lockmode);
5918 
5919  /*
5920  * Swap the physical files of the old and new heaps, then rebuild
5921  * indexes and discard the old heap. We can use RecentXmin for
5922  * the table's new relfrozenxid because we rewrote all the tuples
5923  * in ATRewriteTable, so no older Xid remains in the table. Also,
5924  * we never try to swap toast tables by content, since we have no
5925  * interest in letting this code work on system catalogs.
5926  */
5927  finish_heap_swap(tab->relid, OIDNewHeap,
5928  false, false, true,
5929  !OidIsValid(tab->newTableSpace),
5930  RecentXmin,
5932  persistence);
5933 
5934  InvokeObjectPostAlterHook(RelationRelationId, tab->relid, 0);
5935  }
5936  else if (tab->rewrite > 0 && tab->relkind == RELKIND_SEQUENCE)
5937  {
5938  if (tab->chgPersistence)
5940  }
5941  else
5942  {
5943  /*
5944  * If required, test the current data within the table against new
5945  * constraints generated by ALTER TABLE commands, but don't
5946  * rebuild data.
5947  */
5948  if (tab->constraints != NIL || tab->verify_new_notnull ||
5949  tab->partition_constraint != NULL)
5950  ATRewriteTable(tab, InvalidOid, lockmode);
5951 
5952  /*
5953  * If we had SET TABLESPACE but no reason to reconstruct tuples,
5954  * just do a block-by-block copy.
5955  */
5956  if (tab->newTableSpace)
5957  ATExecSetTableSpace(tab->relid, tab->newTableSpace, lockmode);
5958  }
5959 
5960  /*
5961  * Also change persistence of owned sequences, so that it matches the
5962  * table persistence.
5963  */
5964  if (tab->chgPersistence)
5965  {
5966  List *seqlist = getOwnedSequences(tab->relid);
5967  ListCell *lc;
5968 
5969  foreach(lc, seqlist)
5970  {
5971  Oid seq_relid = lfirst_oid(lc);
5972 
5974  }
5975  }
5976  }
5977 
5978  /*
5979  * Foreign key constraints are checked in a final pass, since (a) it's
5980  * generally best to examine each one separately, and (b) it's at least
5981  * theoretically possible that we have changed both relations of the
5982  * foreign key, and we'd better have finished both rewrites before we try
5983  * to read the tables.
5984  */
5985  foreach(ltab, *wqueue)
5986  {
5987  AlteredTableInfo *tab = (AlteredTableInfo *) lfirst(ltab);
5988  Relation rel = NULL;
5989  ListCell *lcon;
5990 
5991  /* Relations without storage may be ignored here too */
5992  if (!RELKIND_HAS_STORAGE(tab->relkind))
5993  continue;
5994 
5995  foreach(lcon, tab->constraints)
5996  {
5997  NewConstraint *con = lfirst(lcon);
5998 
5999  if (con->contype == CONSTR_FOREIGN)
6000  {
6001  Constraint *fkconstraint = (Constraint *) con->qual;
6002  Relation refrel;
6003 
6004  if (rel == NULL)
6005  {
6006  /* Long since locked, no need for another */
6007  rel = table_open(tab->relid, NoLock);
6008  }
6009 
6010  refrel = table_open(con->refrelid, RowShareLock);
6011 
6012  validateForeignKeyConstraint(fkconstraint->conname, rel, refrel,
6013  con->refindid,
6014  con->conid,
6015  con->conwithperiod);
6016 
6017  /*
6018  * No need to mark the constraint row as validated, we did
6019  * that when we inserted the row earlier.
6020  */
6021 
6022  table_close(refrel, NoLock);
6023  }
6024  }
6025 
6026  if (rel)
6027  table_close(rel, NoLock);
6028  }
6029 
6030  /* Finally, run any afterStmts that were queued up */
6031  foreach(ltab, *wqueue)
6032  {
6033  AlteredTableInfo *tab = (AlteredTableInfo *) lfirst(ltab);
6034  ListCell *lc;
6035 
6036  foreach(lc, tab->afterStmts)
6037  {
6038  Node *stmt = (Node *) lfirst(lc);
6039 
6042  }
6043  }
6044 }
6045 
6046 /*
6047  * ATRewriteTable: scan or rewrite one table
6048  *
6049  * OIDNewHeap is InvalidOid if we don't need to rewrite
6050  */
6051 static void
6052 ATRewriteTable(AlteredTableInfo *tab, Oid OIDNewHeap, LOCKMODE lockmode)
6053 {
6054  Relation oldrel;
6055  Relation newrel;
6056  TupleDesc oldTupDesc;
6057  TupleDesc newTupDesc;
6058  bool needscan = false;
6059  List *notnull_attrs;
6060  int i;
6061  ListCell *l;
6062  EState *estate;
6063  CommandId mycid;
6064  BulkInsertState bistate;
6065  int ti_options;
6066  ExprState *partqualstate = NULL;
6067 
6068  /*
6069  * Open the relation(s). We have surely already locked the existing
6070  * table.
6071  */
6072  oldrel = table_open(tab->relid, NoLock);
6073  oldTupDesc = tab->oldDesc;
6074  newTupDesc = RelationGetDescr(oldrel); /* includes all mods */
6075 
6076  if (OidIsValid(OIDNewHeap))
6077  newrel = table_open(OIDNewHeap, lockmode);
6078  else
6079  newrel = NULL;
6080 
6081  /*
6082  * Prepare a BulkInsertState and options for table_tuple_insert. The FSM
6083  * is empty, so don't bother using it.
6084  */
6085  if (newrel)
6086  {
6087  mycid = GetCurrentCommandId(true);
6088  bistate = GetBulkInsertState();
6089  ti_options = TABLE_INSERT_SKIP_FSM;
6090  }
6091  else
6092  {
6093  /* keep compiler quiet about using these uninitialized */
6094  mycid = 0;
6095  bistate = NULL;
6096  ti_options = 0;
6097  }
6098 
6099  /*
6100  * Generate the constraint and default execution states
6101  */
6102 
6103  estate = CreateExecutorState();
6104 
6105  /* Build the needed expression execution states */
6106  foreach(l, tab->constraints)
6107  {
6108  NewConstraint *con = lfirst(l);
6109 
6110  switch (con->contype)
6111  {
6112  case CONSTR_CHECK:
6113  needscan = true;
6114  con->qualstate = ExecPrepareExpr((Expr *) con->qual, estate);
6115  break;
6116  case CONSTR_FOREIGN:
6117  /* Nothing to do here */
6118  break;
6119  default:
6120  elog(ERROR, "unrecognized constraint type: %d",
6121  (int) con->contype);
6122  }
6123  }
6124 
6125  /* Build expression execution states for partition check quals */
6126  if (tab->partition_constraint)
6127  {
6128  needscan = true;
6129  partqualstate = ExecPrepareExpr(tab->partition_constraint, estate);
6130  }
6131 
6132  foreach(l, tab->newvals)
6133  {
6134  NewColumnValue *ex = lfirst(l);
6135 
6136  /* expr already planned */
6137  ex->exprstate = ExecInitExpr((Expr *) ex->expr, NULL);
6138  }
6139 
6140  notnull_attrs = NIL;
6141  if (newrel || tab->verify_new_notnull)
6142  {
6143  /*
6144  * If we are rebuilding the tuples OR if we added any new but not
6145  * verified not-null constraints, check all not-null constraints. This
6146  * is a bit of overkill but it minimizes risk of bugs, and
6147  * heap_attisnull is a pretty cheap test anyway.
6148  */
6149  for (i = 0; i < newTupDesc->natts; i++)
6150  {
6151  Form_pg_attribute attr = TupleDescAttr(newTupDesc, i);
6152 
6153  if (attr->attnotnull && !attr->attisdropped)
6154  notnull_attrs = lappend_int(notnull_attrs, i);
6155  }
6156  if (notnull_attrs)
6157  needscan = true;
6158  }
6159 
6160  if (newrel || needscan)
6161  {
6162  ExprContext *econtext;
6163  TupleTableSlot *oldslot;
6164  TupleTableSlot *newslot;
6165  TableScanDesc scan;
6166  MemoryContext oldCxt;
6167  List *dropped_attrs = NIL;
6168  ListCell *lc;
6169  Snapshot snapshot;
6170 
6171  if (newrel)
6172  ereport(DEBUG1,
6173  (errmsg_internal("rewriting table \"%s\"",
6174  RelationGetRelationName(oldrel))));
6175  else
6176  ereport(DEBUG1,
6177  (errmsg_internal("verifying table \"%s\"",
6178  RelationGetRelationName(oldrel))));
6179 
6180  if (newrel)
6181  {
6182  /*
6183  * All predicate locks on the tuples or pages are about to be made
6184  * invalid, because we move tuples around. Promote them to
6185  * relation locks.
6186  */
6188  }
6189 
6190  econtext = GetPerTupleExprContext(estate);
6191 
6192  /*
6193  * Create necessary tuple slots. When rewriting, two slots are needed,
6194  * otherwise one suffices. In the case where one slot suffices, we
6195  * need to use the new tuple descriptor, otherwise some constraints
6196  * can't be evaluated. Note that even when the tuple layout is the
6197  * same and no rewrite is required, the tupDescs might not be
6198  * (consider ADD COLUMN without a default).
6199  */
6200  if (tab->rewrite)
6201  {
6202  Assert(newrel != NULL);
6203  oldslot = MakeSingleTupleTableSlot(oldTupDesc,
6204  table_slot_callbacks(oldrel));
6205  newslot = MakeSingleTupleTableSlot(newTupDesc,
6206  table_slot_callbacks(newrel));
6207 
6208  /*
6209  * Set all columns in the new slot to NULL initially, to ensure
6210  * columns added as part of the rewrite are initialized to NULL.
6211  * That is necessary as tab->newvals will not contain an
6212  * expression for columns with a NULL default, e.g. when adding a
6213  * column without a default together with a column with a default
6214  * requiring an actual rewrite.
6215  */
6216  ExecStoreAllNullTuple(newslot);
6217  }
6218  else
6219  {
6220  oldslot = MakeSingleTupleTableSlot(newTupDesc,
6221  table_slot_callbacks(oldrel));
6222  newslot = NULL;
6223  }
6224 
6225  /*
6226  * Any attributes that are dropped according to the new tuple
6227  * descriptor can be set to NULL. We precompute the list of dropped
6228  * attributes to avoid needing to do so in the per-tuple loop.
6229  */
6230  for (i = 0; i < newTupDesc->natts; i++)
6231  {
6232  if (TupleDescAttr(newTupDesc, i)->attisdropped)
6233  dropped_attrs = lappend_int(dropped_attrs, i);
6234  }
6235 
6236  /*
6237  * Scan through the rows, generating a new row if needed and then
6238  * checking all the constraints.
6239  */
6240  snapshot = RegisterSnapshot(GetLatestSnapshot());
6241  scan = table_beginscan(oldrel, snapshot, 0, NULL);
6242 
6243  /*
6244  * Switch to per-tuple memory context and reset it for each tuple
6245  * produced, so we don't leak memory.
6246  */
6248 
6249  while (table_scan_getnextslot(scan, ForwardScanDirection, oldslot))
6250  {
6251  TupleTableSlot *insertslot;
6252 
6253  if (tab->rewrite > 0)
6254  {
6255  /* Extract data from old tuple */
6256  slot_getallattrs(oldslot);
6257  ExecClearTuple(newslot);
6258 
6259  /* copy attributes */
6260  memcpy(newslot->tts_values, oldslot->tts_values,
6261  sizeof(Datum) * oldslot->tts_nvalid);
6262  memcpy(newslot->tts_isnull, oldslot->tts_isnull,
6263  sizeof(bool) * oldslot->tts_nvalid);
6264 
6265  /* Set dropped attributes to null in new tuple */
6266  foreach(lc, dropped_attrs)
6267  newslot->tts_isnull[lfirst_int(lc)] = true;
6268 
6269  /*
6270  * Constraints and GENERATED expressions might reference the
6271  * tableoid column, so fill tts_tableOid with the desired
6272  * value. (We must do this each time, because it gets
6273  * overwritten with newrel's OID during storing.)
6274  */
6275  newslot->tts_tableOid = RelationGetRelid(oldrel);
6276 
6277  /*
6278  * Process supplied expressions to replace selected columns.
6279  *
6280  * First, evaluate expressions whose inputs come from the old
6281  * tuple.
6282  */
6283  econtext->ecxt_scantuple = oldslot;
6284 
6285  foreach(l, tab->newvals)
6286  {
6287  NewColumnValue *ex = lfirst(l);
6288 
6289  if (ex->is_generated)
6290  continue;
6291 
6292  newslot->tts_values[ex->attnum - 1]
6293  = ExecEvalExpr(ex->exprstate,
6294  econtext,
6295  &newslot->tts_isnull[ex->attnum - 1]);
6296  }
6297 
6298  ExecStoreVirtualTuple(newslot);
6299 
6300  /*
6301  * Now, evaluate any expressions whose inputs come from the
6302  * new tuple. We assume these columns won't reference each
6303  * other, so that there's no ordering dependency.
6304  */
6305  econtext->ecxt_scantuple = newslot;
6306 
6307  foreach(l, tab->newvals)
6308  {
6309  NewColumnValue *ex = lfirst(l);
6310 
6311  if (!ex->is_generated)
6312  continue;
6313 
6314  newslot->tts_values[ex->attnum - 1]
6315  = ExecEvalExpr(ex->exprstate,
6316  econtext,
6317  &newslot->tts_isnull[ex->attnum - 1]);
6318  }
6319 
6320  insertslot = newslot;
6321  }
6322  else
6323  {
6324  /*
6325  * If there's no rewrite, old and new table are guaranteed to
6326  * have the same AM, so we can just use the old slot to verify
6327  * new constraints etc.
6328  */
6329  insertslot = oldslot;
6330  }
6331 
6332  /* Now check any constraints on the possibly-changed tuple */
6333  econtext->ecxt_scantuple = insertslot;
6334 
6335  foreach(l, notnull_attrs)
6336  {
6337  int attn = lfirst_int(l);
6338 
6339  if (slot_attisnull(insertslot, attn + 1))
6340  {
6341  Form_pg_attribute attr = TupleDescAttr(newTupDesc, attn);
6342 
6343  ereport(ERROR,
6344  (errcode(ERRCODE_NOT_NULL_VIOLATION),
6345  errmsg("column \"%s\" of relation \"%s\" contains null values",
6346  NameStr(attr->attname),
6347  RelationGetRelationName(oldrel)),
6348  errtablecol(oldrel, attn + 1)));
6349  }
6350  }
6351 
6352  foreach(l, tab->constraints)
6353  {
6354  NewConstraint *con = lfirst(l);
6355 
6356  switch (con->contype)
6357  {
6358  case CONSTR_CHECK:
6359  if (!ExecCheck(con->qualstate, econtext))
6360  ereport(ERROR,
6361  (errcode(ERRCODE_CHECK_VIOLATION),
6362  errmsg("check constraint \"%s\" of relation \"%s\" is violated by some row",
6363  con->name,
6364  RelationGetRelationName(oldrel)),
6365  errtableconstraint(oldrel, con->name)));
6366  break;
6367  case CONSTR_NOTNULL:
6368  case CONSTR_FOREIGN:
6369  /* Nothing to do here */
6370  break;
6371  default:
6372  elog(ERROR, "unrecognized constraint type: %d",
6373  (int) con->contype);
6374  }
6375  }
6376 
6377  if (partqualstate && !ExecCheck(partqualstate, econtext))
6378  {
6379  if (tab->validate_default)
6380  ereport(ERROR,
6381  (errcode(ERRCODE_CHECK_VIOLATION),
6382  errmsg("updated partition constraint for default partition \"%s\" would be violated by some row",
6383  RelationGetRelationName(oldrel)),
6384  errtable(oldrel)));
6385  else
6386  ereport(ERROR,
6387  (errcode(ERRCODE_CHECK_VIOLATION),
6388  errmsg("partition constraint of relation \"%s\" is violated by some row",
6389  RelationGetRelationName(oldrel)),
6390  errtable(oldrel)));
6391  }
6392 
6393  /* Write the tuple out to the new relation */
6394  if (newrel)
6395  table_tuple_insert(newrel, insertslot, mycid,
6396  ti_options, bistate);
6397 
6398  ResetExprContext(econtext);
6399 
6401  }
6402 
6403  MemoryContextSwitchTo(oldCxt);
6404  table_endscan(scan);
6405  UnregisterSnapshot(snapshot);
6406 
6408  if (newslot)
6410  }
6411 
6412  FreeExecutorState(estate);
6413 
6414  table_close(oldrel, NoLock);
6415  if (newrel)
6416  {
6417  FreeBulkInsertState(bistate);
6418 
6419  table_finish_bulk_insert(newrel, ti_options);
6420 
6421  table_close(newrel, NoLock);
6422  }
6423 }
6424 
6425 /*
6426  * ATGetQueueEntry: find or create an entry in the ALTER TABLE work queue
6427  */
6428 static AlteredTableInfo *
6430 {
6431  Oid relid = RelationGetRelid(rel);
6432  AlteredTableInfo *tab;
6433  ListCell *ltab;
6434 
6435  foreach(ltab, *wqueue)
6436  {
6437  tab = (AlteredTableInfo *) lfirst(ltab);
6438  if (tab->relid == relid)
6439  return tab;
6440  }
6441 
6442  /*
6443  * Not there, so add it. Note that we make a copy of the relation's
6444  * existing descriptor before anything interesting can happen to it.
6445  */
6446  tab = (AlteredTableInfo *) palloc0(sizeof(AlteredTableInfo));
6447  tab->relid = relid;
6448  tab->rel = NULL; /* set later */
6449  tab->relkind = rel->rd_rel->relkind;
6451  tab->newAccessMethod = InvalidOid;
6452  tab->chgAccessMethod = false;
6453  tab->newTableSpace = InvalidOid;
6454  tab->newrelpersistence = RELPERSISTENCE_PERMANENT;
6455  tab->chgPersistence = false;
6456 
6457  *wqueue = lappend(*wqueue, tab);
6458 
6459  return tab;
6460 }
6461 
6462 static const char *
6464 {
6465  switch (cmdtype)
6466  {
6467  case AT_AddColumn:
6468  case AT_AddColumnToView:
6469  return "ADD COLUMN";
6470  case AT_ColumnDefault:
6472  return "ALTER COLUMN ... SET DEFAULT";
6473  case AT_DropNotNull:
6474  return "ALTER COLUMN ... DROP NOT NULL";
6475  case AT_SetNotNull:
6476  return "ALTER COLUMN ... SET NOT NULL";
6477  case AT_SetAttNotNull:
6478  return NULL; /* not real grammar */
6479  case AT_SetExpression:
6480  return "ALTER COLUMN ... SET EXPRESSION";
6481  case AT_DropExpression:
6482  return "ALTER COLUMN ... DROP EXPRESSION";
6483  case AT_SetStatistics:
6484  return "ALTER COLUMN ... SET STATISTICS";
6485  case AT_SetOptions:
6486  return "ALTER COLUMN ... SET";
6487  case AT_ResetOptions:
6488  return "ALTER COLUMN ... RESET";
6489  case AT_SetStorage:
6490  return "ALTER COLUMN ... SET STORAGE";
6491  case AT_SetCompression:
6492  return "ALTER COLUMN ... SET COMPRESSION";
6493  case AT_DropColumn:
6494  return "DROP COLUMN";
6495  case AT_AddIndex:
6496  case AT_ReAddIndex:
6497  return NULL; /* not real grammar */
6498  case AT_AddConstraint:
6499  case AT_ReAddConstraint:
6501  case AT_AddIndexConstraint:
6502  return "ADD CONSTRAINT";
6503  case AT_AlterConstraint:
6504  return "ALTER CONSTRAINT";
6505  case AT_ValidateConstraint:
6506  return "VALIDATE CONSTRAINT";
6507  case AT_DropConstraint:
6508  return "DROP CONSTRAINT";
6509  case AT_ReAddComment:
6510  return NULL; /* not real grammar */
6511  case AT_AlterColumnType:
6512  return "ALTER COLUMN ... SET DATA TYPE";
6514  return "ALTER COLUMN ... OPTIONS";
6515  case AT_ChangeOwner:
6516  return "OWNER TO";
6517  case AT_ClusterOn:
6518  return "CLUSTER ON";
6519  case AT_DropCluster:
6520  return "SET WITHOUT CLUSTER";
6521  case AT_SetAccessMethod:
6522  return "SET ACCESS METHOD";
6523  case AT_SetLogged:
6524  return "SET LOGGED";
6525  case AT_SetUnLogged:
6526  return "SET UNLOGGED";
6527  case AT_DropOids:
6528  return "SET WITHOUT OIDS";
6529  case AT_SetTableSpace:
6530  return "SET TABLESPACE";
6531  case AT_SetRelOptions:
6532  return "SET";
6533  case AT_ResetRelOptions:
6534  return "RESET";
6535  case AT_ReplaceRelOptions:
6536  return NULL; /* not real grammar */
6537  case AT_EnableTrig:
6538  return "ENABLE TRIGGER";
6539  case AT_EnableAlwaysTrig:
6540  return "ENABLE ALWAYS TRIGGER";
6541  case AT_EnableReplicaTrig:
6542  return "ENABLE REPLICA TRIGGER";
6543  case AT_DisableTrig:
6544  return "DISABLE TRIGGER";
6545  case AT_EnableTrigAll:
6546  return "ENABLE TRIGGER ALL";
6547  case AT_DisableTrigAll:
6548  return "DISABLE TRIGGER ALL";
6549  case AT_EnableTrigUser:
6550  return "ENABLE TRIGGER USER";
6551  case AT_DisableTrigUser:
6552  return "DISABLE TRIGGER USER";
6553  case AT_EnableRule:
6554  return "ENABLE RULE";
6555  case AT_EnableAlwaysRule:
6556  return "ENABLE ALWAYS RULE";
6557  case AT_EnableReplicaRule:
6558  return "ENABLE REPLICA RULE";
6559  case AT_DisableRule:
6560  return "DISABLE RULE";
6561  case AT_AddInherit:
6562  return "INHERIT";
6563  case AT_DropInherit:
6564  return "NO INHERIT";
6565  case AT_AddOf:
6566  return "OF";
6567  case AT_DropOf:
6568  return "NOT OF";
6569  case AT_ReplicaIdentity:
6570  return "REPLICA IDENTITY";
6571  case AT_EnableRowSecurity:
6572  return "ENABLE ROW SECURITY";
6573  case AT_DisableRowSecurity:
6574  return "DISABLE ROW SECURITY";
6575  case AT_ForceRowSecurity:
6576  return "FORCE ROW SECURITY";
6577  case AT_NoForceRowSecurity:
6578  return "NO FORCE ROW SECURITY";
6579  case AT_GenericOptions:
6580  return "OPTIONS";
6581  case AT_AttachPartition:
6582  return "ATTACH PARTITION";
6583  case AT_DetachPartition:
6584  return "DETACH PARTITION";
6586  return "DETACH PARTITION ... FINALIZE";
6587  case AT_SplitPartition:
6588  return "SPLIT PARTITION";
6589  case AT_MergePartitions:
6590  return "MERGE PARTITIONS";
6591  case AT_AddIdentity:
6592  return "ALTER COLUMN ... ADD IDENTITY";
6593  case AT_SetIdentity:
6594  return "ALTER COLUMN ... SET";
6595  case AT_DropIdentity:
6596  return "ALTER COLUMN ... DROP IDENTITY";
6597  case AT_ReAddStatistics:
6598  return NULL; /* not real grammar */
6599  }
6600 
6601  return NULL;
6602 }
6603 
6604 /*
6605  * ATSimplePermissions
6606  *
6607  * - Ensure that it is a relation (or possibly a view)
6608  * - Ensure this user is the owner
6609  * - Ensure that it is not a system table
6610  */
6611 static void
6612 ATSimplePermissions(AlterTableType cmdtype, Relation rel, int allowed_targets)
6613 {
6614  int actual_target;
6615 
6616  switch (rel->rd_rel->relkind)
6617  {
6618  case RELKIND_RELATION:
6619  case RELKIND_PARTITIONED_TABLE:
6620  actual_target = ATT_TABLE;
6621  break;
6622  case RELKIND_VIEW:
6623  actual_target = ATT_VIEW;
6624  break;
6625  case RELKIND_MATVIEW:
6626  actual_target = ATT_MATVIEW;
6627  break;
6628  case RELKIND_INDEX:
6629  actual_target = ATT_INDEX;
6630  break;
6631  case RELKIND_PARTITIONED_INDEX:
6632  actual_target = ATT_PARTITIONED_INDEX;
6633  break;
6634  case RELKIND_COMPOSITE_TYPE:
6635  actual_target = ATT_COMPOSITE_TYPE;
6636  break;
6637  case RELKIND_FOREIGN_TABLE:
6638  actual_target = ATT_FOREIGN_TABLE;
6639  break;
6640  case RELKIND_SEQUENCE:
6641  actual_target = ATT_SEQUENCE;
6642  break;
6643  default:
6644  actual_target = 0;
6645  break;
6646  }
6647 
6648  /* Wrong target type? */
6649  if ((actual_target & allowed_targets) == 0)
6650  {
6651  const char *action_str = alter_table_type_to_string(cmdtype);
6652 
6653  if (action_str)
6654  ereport(ERROR,
6655  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
6656  /* translator: %s is a group of some SQL keywords */
6657  errmsg("ALTER action %s cannot be performed on relation \"%s\"",
6658  action_str, RelationGetRelationName(rel)),
6659  errdetail_relkind_not_supported(rel->rd_rel->relkind)));
6660  else
6661  /* internal error? */
6662  elog(ERROR, "invalid ALTER action attempted on relation \"%s\"",
6664  }
6665 
6666  /* Permissions checks */
6667  if (!object_ownercheck(RelationRelationId, RelationGetRelid(rel), GetUserId()))
6670 
6672  ereport(ERROR,
6673  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
6674  errmsg("permission denied: \"%s\" is a system catalog",
6675  RelationGetRelationName(rel))));
6676 }
6677 
6678 /*
6679  * ATSimpleRecursion
6680  *
6681  * Simple table recursion sufficient for most ALTER TABLE operations.
6682  * All direct and indirect children are processed in an unspecified order.
6683  * Note that if a child inherits from the original table via multiple
6684  * inheritance paths, it will be visited just once.
6685  */
6686 static void
6688  AlterTableCmd *cmd, bool recurse, LOCKMODE lockmode,
6690 {
6691  /*
6692  * Propagate to children, if desired and if there are (or might be) any
6693  * children.
6694  */
6695  if (recurse && rel->rd_rel->relhassubclass)
6696  {
6697  Oid relid = RelationGetRelid(rel);
6698  ListCell *child;
6699  List *children;
6700 
6701  children = find_all_inheritors(relid, lockmode, NULL);
6702 
6703  /*
6704  * find_all_inheritors does the recursive search of the inheritance
6705  * hierarchy, so all we have to do is process all of the relids in the
6706  * list that it returns.
6707  */
6708  foreach(child, children)
6709  {
6710  Oid childrelid = lfirst_oid(child);
6711  Relation childrel;
6712 
6713  if (childrelid == relid)
6714  continue;
6715  /* find_all_inheritors already got lock */
6716  childrel = relation_open(childrelid, NoLock);
6717  CheckTableNotInUse(childrel, "ALTER TABLE");
6718  ATPrepCmd(wqueue, childrel, cmd, false, true, lockmode, context);
6719  relation_close(childrel, NoLock);
6720  }
6721  }
6722 }
6723 
6724 /*
6725  * Obtain list of partitions of the given table, locking them all at the given
6726  * lockmode and ensuring that they all pass CheckTableNotInUse.
6727  *
6728  * This function is a no-op if the given relation is not a partitioned table;
6729  * in particular, nothing is done if it's a legacy inheritance parent.
6730  */
6731 static void
6733 {
6734  if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
6735  {
6736  List *inh;
6737  ListCell *cell;
6738 
6739  inh = find_all_inheritors(RelationGetRelid(rel), lockmode, NULL);
6740  /* first element is the parent rel; must ignore it */
6741  for_each_from(cell, inh, 1)
6742  {
6743  Relation childrel;
6744 
6745  /* find_all_inheritors already got lock */
6746  childrel = table_open(lfirst_oid(cell), NoLock);
6747  CheckTableNotInUse(childrel, "ALTER TABLE");
6748  table_close(childrel, NoLock);
6749  }
6750  list_free(inh);
6751  }
6752 }
6753 
6754 /*
6755  * ATTypedTableRecursion
6756  *
6757  * Propagate ALTER TYPE operations to the typed tables of that type.
6758  * Also check the RESTRICT/CASCADE behavior. Given CASCADE, also permit
6759  * recursion to inheritance children of the typed tables.
6760  */
6761 static void
6764 {
6765  ListCell *child;
6766  List *children;
6767 
6768  Assert(rel->rd_rel->relkind == RELKIND_COMPOSITE_TYPE);
6769 
6770  children = find_typed_table_dependencies(rel->rd_rel->reltype,
6772  cmd->behavior);
6773 
6774  foreach(child, children)
6775  {
6776  Oid childrelid = lfirst_oid(child);
6777  Relation childrel;
6778 
6779  childrel = relation_open(childrelid, lockmode);
6780  CheckTableNotInUse(childrel, "ALTER TABLE");
6781  ATPrepCmd(wqueue, childrel, cmd, true, true, lockmode, context);
6782  relation_close(childrel, NoLock);
6783  }
6784 }
6785 
6786 
6787 /*
6788  * find_composite_type_dependencies
6789  *
6790  * Check to see if the type "typeOid" is being used as a column in some table
6791  * (possibly nested several levels deep in composite types, arrays, etc!).
6792  * Eventually, we'd like to propagate the check or rewrite operation
6793  * into such tables, but for now, just error out if we find any.
6794  *
6795  * Caller should provide either the associated relation of a rowtype,
6796  * or a type name (not both) for use in the error message, if any.
6797  *
6798  * Note that "typeOid" is not necessarily a composite type; it could also be
6799  * another container type such as an array or range, or a domain over one of
6800  * these things. The name of this function is therefore somewhat historical,
6801  * but it's not worth changing.
6802  *
6803  * We assume that functions and views depending on the type are not reasons
6804  * to reject the ALTER. (How safe is this really?)
6805  */
6806 void
6808  const char *origTypeName)
6809 {
6810  Relation depRel;
6811  ScanKeyData key[2];
6812  SysScanDesc depScan;
6813  HeapTuple depTup;
6814 
6815  /* since this function recurses, it could be driven to stack overflow */
6817 
6818  /*
6819  * We scan pg_depend to find those things that depend on the given type.
6820  * (We assume we can ignore refobjsubid for a type.)
6821  */
6822  depRel = table_open(DependRelationId, AccessShareLock);
6823 
6824  ScanKeyInit(&key[0],
6825  Anum_pg_depend_refclassid,
6826  BTEqualStrategyNumber, F_OIDEQ,
6827  ObjectIdGetDatum(TypeRelationId));
6828  ScanKeyInit(&key[1],
6829  Anum_pg_depend_refobjid,
6830  BTEqualStrategyNumber, F_OIDEQ,
6831  ObjectIdGetDatum(typeOid));
6832 
6833  depScan = systable_beginscan(depRel, DependReferenceIndexId, true,
6834  NULL, 2, key);
6835 
6836  while (HeapTupleIsValid(depTup = systable_getnext(depScan)))
6837  {
6838  Form_pg_depend pg_depend = (Form_pg_depend) GETSTRUCT(depTup);
6839  Relation rel;
6840  TupleDesc tupleDesc;
6841  Form_pg_attribute att;
6842 
6843  /* Check for directly dependent types */
6844  if (pg_depend->classid == TypeRelationId)
6845  {
6846  /*
6847  * This must be an array, domain, or range containing the given
6848  * type, so recursively check for uses of this type. Note that
6849  * any error message will mention the original type not the
6850  * container; this is intentional.
6851  */
6852  find_composite_type_dependencies(pg_depend->objid,
6853  origRelation, origTypeName);
6854  continue;
6855  }
6856 
6857  /* Else, ignore dependees that aren't relations */
6858  if (pg_depend->classid != RelationRelationId)
6859  continue;
6860 
6861  rel = relation_open(pg_depend->objid, AccessShareLock);
6862  tupleDesc = RelationGetDescr(rel);
6863 
6864  /*
6865  * If objsubid identifies a specific column, refer to that in error
6866  * messages. Otherwise, search to see if there's a user column of the
6867  * type. (We assume system columns are never of interesting types.)
6868  * The search is needed because an index containing an expression
6869  * column of the target type will just be recorded as a whole-relation
6870  * dependency. If we do not find a column of the type, the dependency
6871  * must indicate that the type is transiently referenced in an index
6872  * expression but not stored on disk, which we assume is OK, just as
6873  * we do for references in views. (It could also be that the target
6874  * type is embedded in some container type that is stored in an index
6875  * column, but the previous recursion should catch such cases.)
6876  */
6877  if (pg_depend->objsubid > 0 && pg_depend->objsubid <= tupleDesc->natts)
6878  att = TupleDescAttr(tupleDesc, pg_depend->objsubid - 1);
6879  else
6880  {
6881  att = NULL;
6882  for (int attno = 1; attno <= tupleDesc->natts; attno++)
6883  {
6884  att = TupleDescAttr(tupleDesc, attno - 1);
6885  if (att->atttypid == typeOid && !att->attisdropped)
6886  break;
6887  att = NULL;
6888  }
6889  if (att == NULL)
6890  {
6891  /* No such column, so assume OK */
6893  continue;
6894  }
6895  }
6896 
6897  /*
6898  * We definitely should reject if the relation has storage. If it's
6899  * partitioned, then perhaps we don't have to reject: if there are
6900  * partitions then we'll fail when we find one, else there is no
6901  * stored data to worry about. However, it's possible that the type
6902  * change would affect conclusions about whether the type is sortable
6903  * or hashable and thus (if it's a partitioning column) break the
6904  * partitioning rule. For now, reject for partitioned rels too.
6905  */
6906  if (RELKIND_HAS_STORAGE(rel->rd_rel->relkind) ||
6907  RELKIND_HAS_PARTITIONS(rel->rd_rel->relkind))
6908  {
6909  if (origTypeName)
6910  ereport(ERROR,
6911  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
6912  errmsg("cannot alter type \"%s\" because column \"%s.%s\" uses it",
6913  origTypeName,
6915  NameStr(att->attname))));
6916  else if (origRelation->rd_rel->relkind == RELKIND_COMPOSITE_TYPE)
6917  ereport(ERROR,
6918  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
6919  errmsg("cannot alter type \"%s\" because column \"%s.%s\" uses it",
6920  RelationGetRelationName(origRelation),
6922  NameStr(att->attname))));
6923  else if (origRelation->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
6924  ereport(ERROR,
6925  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
6926  errmsg("cannot alter foreign table \"%s\" because column \"%s.%s\" uses its row type",
6927  RelationGetRelationName(origRelation),
6929  NameStr(att->attname))));
6930  else
6931  ereport(ERROR,
6932  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
6933  errmsg("cannot alter table \"%s\" because column \"%s.%s\" uses its row type",
6934  RelationGetRelationName(origRelation),
6936  NameStr(att->attname))));
6937  }
6938  else if (OidIsValid(rel->rd_rel->reltype))
6939  {
6940  /*
6941  * A view or composite type itself isn't a problem, but we must
6942  * recursively check for indirect dependencies via its rowtype.
6943  */
6945  origRelation, origTypeName);
6946  }
6947 
6949  }
6950 
6951  systable_endscan(depScan);
6952 
6954 }
6955 
6956 
6957 /*
6958  * find_typed_table_dependencies
6959  *
6960  * Check to see if a composite type is being used as the type of a
6961  * typed table. Abort if any are found and behavior is RESTRICT.
6962  * Else return the list of tables.
6963  */
6964 static List *
6965 find_typed_table_dependencies(Oid typeOid, const char *typeName, DropBehavior behavior)
6966 {
6967  Relation classRel;
6968  ScanKeyData key[1];
6969  TableScanDesc scan;
6970  HeapTuple tuple;
6971  List *result = NIL;
6972 
6973  classRel = table_open(RelationRelationId, AccessShareLock);
6974 
6975  ScanKeyInit(&key[0],
6976  Anum_pg_class_reloftype,
6977  BTEqualStrategyNumber, F_OIDEQ,
6978  ObjectIdGetDatum(typeOid));
6979 
6980  scan = table_beginscan_catalog(classRel, 1, key);
6981 
6982  while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
6983  {
6984  Form_pg_class classform = (Form_pg_class) GETSTRUCT(tuple);
6985 
6986  if (behavior == DROP_RESTRICT)
6987  ereport(ERROR,
6988  (errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
6989  errmsg("cannot alter type \"%s\" because it is the type of a typed table",
6990  typeName),
6991  errhint("Use ALTER ... CASCADE to alter the typed tables too.")));
6992  else
6993  result = lappend_oid(result, classform->oid);
6994  }
6995 
6996  table_endscan(scan);
6997  table_close(classRel, AccessShareLock);
6998 
6999  return result;
7000 }
7001 
7002 
7003 /*
7004  * check_of_type
7005  *
7006  * Check whether a type is suitable for CREATE TABLE OF/ALTER TABLE OF. If it
7007  * isn't suitable, throw an error. Currently, we require that the type
7008  * originated with CREATE TYPE AS. We could support any row type, but doing so
7009  * would require handling a number of extra corner cases in the DDL commands.
7010  * (Also, allowing domain-over-composite would open up a can of worms about
7011  * whether and how the domain's constraints should apply to derived tables.)
7012  */
7013 void
7015 {
7016  Form_pg_type typ = (Form_pg_type) GETSTRUCT(typetuple);
7017  bool typeOk = false;
7018 
7019  if (typ->typtype == TYPTYPE_COMPOSITE)
7020  {
7021  Relation typeRelation;
7022 
7023  Assert(OidIsValid(typ->typrelid));
7024  typeRelation = relation_open(typ->typrelid, AccessShareLock);
7025  typeOk = (typeRelation->rd_rel->relkind == RELKIND_COMPOSITE_TYPE);
7026 
7027  /*
7028  * Close the parent rel, but keep our AccessShareLock on it until xact
7029  * commit. That will prevent someone else from deleting or ALTERing
7030  * the type before the typed table creation/conversion commits.
7031  */
7032  relation_close(typeRelation, NoLock);
7033  }
7034  if (!typeOk)
7035  ereport(ERROR,
7036  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
7037  errmsg("type %s is not a composite type",
7038  format_type_be(typ->oid))));
7039 }
7040 
7041 
7042 /*
7043  * ALTER TABLE ADD COLUMN
7044  *
7045  * Adds an additional attribute to a relation making the assumption that
7046  * CHECK, NOT NULL, and FOREIGN KEY constraints will be removed from the
7047  * AT_AddColumn AlterTableCmd by parse_utilcmd.c and added as independent
7048  * AlterTableCmd's.
7049  *
7050  * ADD COLUMN cannot use the normal ALTER TABLE recursion mechanism, because we
7051  * have to decide at runtime whether to recurse or not depending on whether we
7052  * actually add a column or merely merge with an existing column. (We can't
7053  * check this in a static pre-pass because it won't handle multiple inheritance
7054  * situations correctly.)
7055  */
7056 static void
7057 ATPrepAddColumn(List **wqueue, Relation rel, bool recurse, bool recursing,
7058  bool is_view, AlterTableCmd *cmd, LOCKMODE lockmode,
7060 {
7061  if (rel->rd_rel->reloftype && !recursing)
7062  ereport(ERROR,
7063  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
7064  errmsg("cannot add column to typed table")));
7065 
7066  if (rel->rd_rel->relkind == RELKIND_COMPOSITE_TYPE)
7067  ATTypedTableRecursion(wqueue, rel, cmd, lockmode, context);
7068 
7069  if (recurse && !is_view)
7070  cmd->recurse = true;
7071 }
7072 
7073 /*
7074  * Add a column to a table. The return value is the address of the
7075  * new column in the parent relation.
7076  *
7077  * cmd is pass-by-ref so that we can replace it with the parse-transformed
7078  * copy (but that happens only after we check for IF NOT EXISTS).
7079  */
7080 static ObjectAddress
7082  AlterTableCmd **cmd, bool recurse, bool recursing,
7083  LOCKMODE lockmode, AlterTablePass cur_pass,
7085 {
7086  Oid myrelid = RelationGetRelid(rel);
7087  ColumnDef *colDef = castNode(ColumnDef, (*cmd)->def);
7088  bool if_not_exists = (*cmd)->missing_ok;
7089  Relation pgclass,
7090  attrdesc;
7091  HeapTuple reltup;
7092  Form_pg_attribute attribute;
7093  int newattnum;
7094  char relkind;
7095  Expr *defval;
7096  List *children;
7097  ListCell *child;
7098  AlterTableCmd *childcmd;
7099  ObjectAddress address;
7100  TupleDesc tupdesc;
7101 
7102  /* since this function recurses, it could be driven to stack overflow */
7104 
7105  /* At top level, permission check was done in ATPrepCmd, else do it */
7106  if (recursing)
7107  ATSimplePermissions((*cmd)->subtype, rel, ATT_TABLE | ATT_FOREIGN_TABLE);
7108 
7109  if (rel->rd_rel->relispartition && !recursing)
7110  ereport(ERROR,
7111  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
7112  errmsg("cannot add column to a partition")));
7113 
7114  attrdesc = table_open(AttributeRelationId, RowExclusiveLock);
7115 
7116  /*
7117  * Are we adding the column to a recursion child? If so, check whether to
7118  * merge with an existing definition for the column. If we do merge, we
7119  * must not recurse. Children will already have the column, and recursing
7120  * into them would mess up attinhcount.
7121  */
7122  if (colDef->inhcount > 0)
7123  {
7124  HeapTuple tuple;
7125 
7126  /* Does child already have a column by this name? */
7127  tuple = SearchSysCacheCopyAttName(myrelid, colDef->colname);
7128  if (HeapTupleIsValid(tuple))
7129  {
7130  Form_pg_attribute childatt = (Form_pg_attribute) GETSTRUCT(tuple);
7131  Oid ctypeId;
7132  int32 ctypmod;
7133  Oid ccollid;
7134 
7135  /* Child column must match on type, typmod, and collation */
7136  typenameTypeIdAndMod(NULL, colDef->typeName, &ctypeId, &ctypmod);
7137  if (ctypeId != childatt->atttypid ||
7138  ctypmod != childatt->atttypmod)
7139  ereport(ERROR,
7140  (errcode(ERRCODE_DATATYPE_MISMATCH),
7141  errmsg("child table \"%s\" has different type for column \"%s\"",
7142  RelationGetRelationName(rel), colDef->colname)));
7143  ccollid = GetColumnDefCollation(NULL, colDef, ctypeId);
7144  if (ccollid != childatt->attcollation)
7145  ereport(ERROR,
7146  (errcode(ERRCODE_COLLATION_MISMATCH),
7147  errmsg("child table \"%s\" has different collation for column \"%s\"",
7148  RelationGetRelationName(rel), colDef->colname),
7149  errdetail("\"%s\" versus \"%s\"",
7150  get_collation_name(ccollid),
7151  get_collation_name(childatt->attcollation))));
7152 
7153  /* Bump the existing child att's inhcount */
7154  childatt->attinhcount++;
7155  if (childatt->attinhcount < 0)
7156  ereport(ERROR,
7157  errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
7158  errmsg("too many inheritance parents"));
7159  CatalogTupleUpdate(attrdesc, &tuple->t_self, tuple);
7160 
7161  heap_freetuple(tuple);
7162 
7163  /* Inform the user about the merge */
7164  ereport(NOTICE,
7165  (errmsg("merging definition of column \"%s\" for child \"%s\"",
7166  colDef->colname, RelationGetRelationName(rel))));
7167 
7168  table_close(attrdesc, RowExclusiveLock);
7169 
7170  /* Make the child column change visible */
7172 
7173  return InvalidObjectAddress;
7174  }
7175  }
7176 
7177  /* skip if the name already exists and if_not_exists is true */
7178  if (!check_for_column_name_collision(rel, colDef->colname, if_not_exists))
7179  {
7180  table_close(attrdesc, RowExclusiveLock);
7181  return InvalidObjectAddress;
7182  }
7183 
7184  /*
7185  * Okay, we need to add the column, so go ahead and do parse
7186  * transformation. This can result in queueing up, or even immediately
7187  * executing, subsidiary operations (such as creation of unique indexes);
7188  * so we mustn't do it until we have made the if_not_exists check.
7189  *
7190  * When recursing, the command was already transformed and we needn't do
7191  * so again. Also, if context isn't given we can't transform. (That
7192  * currently happens only for AT_AddColumnToView; we expect that view.c
7193  * passed us a ColumnDef that doesn't need work.)
7194  */
7195  if (context != NULL && !recursing)
7196  {
7197  *cmd = ATParseTransformCmd(wqueue, tab, rel, *cmd, recurse, lockmode,
7198  cur_pass, context);
7199  Assert(*cmd != NULL);
7200  colDef = castNode(ColumnDef, (*cmd)->def);
7201  }
7202 
7203  /*
7204  * Regular inheritance children are independent enough not to inherit the
7205  * identity column from parent hence cannot recursively add identity
7206  * column if the table has inheritance children.
7207  *
7208  * Partitions, on the other hand, are integral part of a partitioned table
7209  * and inherit identity column. Hence propagate identity column down the
7210  * partition hierarchy.
7211  */
7212  if (colDef->identity &&
7213  recurse &&
7214  rel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE &&
7215  find_inheritance_children(myrelid, NoLock) != NIL)
7216  ereport(ERROR,
7217  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
7218  errmsg("cannot recursively add identity column to table that has child tables")));
7219 
7220  pgclass = table_open(RelationRelationId, RowExclusiveLock);
7221 
7222  reltup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(myrelid));
7223  if (!HeapTupleIsValid(reltup))
7224  elog(ERROR, "cache lookup failed for relation %u", myrelid);
7225  relkind = ((Form_pg_class) GETSTRUCT(reltup))->relkind;
7226 
7227  /* Determine the new attribute's number */
7228  newattnum = ((Form_pg_class) GETSTRUCT(reltup))->relnatts + 1;
7229  if (newattnum > MaxHeapAttributeNumber)
7230  ereport(ERROR,
7231  (errcode(ERRCODE_TOO_MANY_COLUMNS),
7232  errmsg("tables can have at most %d columns",
7234 
7235  /*
7236  * Construct new attribute's pg_attribute entry.
7237  */
7238  tupdesc = BuildDescForRelation(list_make1(colDef));
7239 
7240  attribute = TupleDescAttr(tupdesc, 0);
7241 
7242  /* Fix up attribute number */
7243  attribute->attnum = newattnum;
7244 
7245  /* make sure datatype is legal for a column */
7246  CheckAttributeType(NameStr(attribute->attname), attribute->atttypid, attribute->attcollation,
7247  list_make1_oid(rel->rd_rel->reltype),
7248  0);
7249 
7250  InsertPgAttributeTuples(attrdesc, tupdesc, myrelid, NULL, NULL);
7251 
7252  table_close(attrdesc, RowExclusiveLock);
7253 
7254  /*
7255  * Update pg_class tuple as appropriate
7256  */
7257  ((Form_pg_class) GETSTRUCT(reltup))->relnatts = newattnum;
7258 
7259  CatalogTupleUpdate(pgclass, &reltup->t_self, reltup);
7260 
7261  heap_freetuple(reltup);
7262 
7263  /* Post creation hook for new attribute */
7264  InvokeObjectPostCreateHook(RelationRelationId, myrelid, newattnum);
7265 
7266  table_close(pgclass, RowExclusiveLock);
7267 
7268  /* Make the attribute's catalog entry visible */
7270 
7271  /*
7272  * Store the DEFAULT, if any, in the catalogs
7273  */
7274  if (colDef->raw_default)
7275  {
7276  RawColumnDefault *rawEnt;
7277 
7278  rawEnt = (RawColumnDefault *) palloc(sizeof(RawColumnDefault));
7279  rawEnt->attnum = attribute->attnum;
7280  rawEnt->raw_default = copyObject(colDef->raw_default);
7281 
7282  /*
7283  * Attempt to skip a complete table rewrite by storing the specified
7284  * DEFAULT value outside of the heap. This may be disabled inside
7285  * AddRelationNewConstraints if the optimization cannot be applied.
7286  */
7287  rawEnt->missingMode = (!colDef->generated);
7288 
7289  rawEnt->generated = colDef->generated;
7290 
7291  /*
7292  * This function is intended for CREATE TABLE, so it processes a
7293  * _list_ of defaults, but we just do one.
7294  */
7296  false, true, false, NULL);
7297 
7298  /* Make the additional catalog changes visible */
7300 
7301  /*
7302  * Did the request for a missing value work? If not we'll have to do a
7303  * rewrite
7304  */
7305  if (!rawEnt->missingMode)
7307  }
7308 
7309  /*
7310  * Tell Phase 3 to fill in the default expression, if there is one.
7311  *
7312  * If there is no default, Phase 3 doesn't have to do anything, because
7313  * that effectively means that the default is NULL. The heap tuple access
7314  * routines always check for attnum > # of attributes in tuple, and return
7315  * NULL if so, so without any modification of the tuple data we will get
7316  * the effect of NULL values in the new column.
7317  *
7318  * An exception occurs when the new column is of a domain type: the domain
7319  * might have a not-null constraint, or a check constraint that indirectly
7320  * rejects nulls. If there are any domain constraints then we construct
7321  * an explicit NULL default value that will be passed through
7322  * CoerceToDomain processing. (This is a tad inefficient, since it causes
7323  * rewriting the table which we really don't have to do, but the present
7324  * design of domain processing doesn't offer any simple way of checking
7325  * the constraints more directly.)
7326  *
7327  * Note: we use build_column_default, and not just the cooked default
7328  * returned by AddRelationNewConstraints, so that the right thing happens
7329  * when a datatype's default applies.
7330  *
7331  * Note: it might seem that this should happen at the end of Phase 2, so
7332  * that the effects of subsequent subcommands can be taken into account.
7333  * It's intentional that we do it now, though. The new column should be
7334  * filled according to what is said in the ADD COLUMN subcommand, so that
7335  * the effects are the same as if this subcommand had been run by itself
7336  * and the later subcommands had been issued in new ALTER TABLE commands.
7337  *
7338  * We can skip this entirely for relations without storage, since Phase 3
7339  * is certainly not going to touch them. System attributes don't have
7340  * interesting defaults, either.
7341  */
7342  if (RELKIND_HAS_STORAGE(relkind))
7343  {
7344  /*
7345  * For an identity column, we can't use build_column_default(),
7346  * because the sequence ownership isn't set yet. So do it manually.
7347  */
7348  if (colDef->identity)
7349  {
7351 
7352  nve->seqid = RangeVarGetRelid(colDef->identitySequence, NoLock, false);
7353  nve->typeId = attribute->atttypid;
7354 
7355  defval = (Expr *) nve;
7356 
7357  /* must do a rewrite for identity columns */
7359  }
7360  else
7361  defval = (Expr *) build_column_default(rel, attribute->attnum);
7362 
7363  if (!defval && DomainHasConstraints(attribute->atttypid))
7364  {
7365  Oid baseTypeId;
7366  int32 baseTypeMod;
7367  Oid baseTypeColl;
7368 
7369  baseTypeMod = attribute->atttypmod;
7370  baseTypeId = getBaseTypeAndTypmod(attribute->atttypid, &baseTypeMod);
7371  baseTypeColl = get_typcollation(baseTypeId);
7372  defval = (Expr *) makeNullConst(baseTypeId, baseTypeMod, baseTypeColl);
7373  defval = (Expr *) coerce_to_target_type(NULL,
7374  (Node *) defval,
7375  baseTypeId,
7376  attribute->atttypid,
7377  attribute->atttypmod,
7380  -1);
7381  if (defval == NULL) /* should not happen */
7382  elog(ERROR, "failed to coerce base type to domain");
7383  }
7384 
7385  if (defval)
7386  {
7388 
7390  newval->attnum = attribute->attnum;
7391  newval->expr = expression_planner(defval);
7392  newval->is_generated = (colDef->generated != '\0');
7393 
7394  tab->newvals = lappend(tab->newvals, newval);
7395  }
7396 
7397  if (DomainHasConstraints(attribute->atttypid))
7399 
7400  if (!TupleDescAttr(rel->rd_att, attribute->attnum - 1)->atthasmissing)
7401  {
7402  /*
7403  * If the new column is NOT NULL, and there is no missing value,
7404  * tell Phase 3 it needs to check for NULLs.
7405  */
7406  tab->verify_new_notnull |= colDef->is_not_null;
7407  }
7408  }
7409 
7410  /*
7411  * Add needed dependency entries for the new column.
7412  */
7413  add_column_datatype_dependency(myrelid, newattnum, attribute->atttypid);
7414  add_column_collation_dependency(myrelid, newattnum, attribute->attcollation);
7415 
7416  /*
7417  * Propagate to children as appropriate. Unlike most other ALTER
7418  * routines, we have to do this one level of recursion at a time; we can't
7419  * use find_all_inheritors to do it in one pass.
7420  */
7421  children =
7423 
7424  /*
7425  * If we are told not to recurse, there had better not be any child
7426  * tables; else the addition would put them out of step.
7427  */
7428  if (children && !recurse)
7429  ereport(ERROR,
7430  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
7431  errmsg("column must be added to child tables too")));
7432 
7433  /* Children should see column as singly inherited */
7434  if (!recursing)
7435  {
7436  childcmd = copyObject(*cmd);
7437  colDef = castNode(ColumnDef, childcmd->def);
7438  colDef->inhcount = 1;
7439  colDef->is_local = false;
7440  }
7441  else
7442  childcmd = *cmd; /* no need to copy again */
7443 
7444  foreach(child, children)
7445  {
7446  Oid childrelid = lfirst_oid(child);
7447  Relation childrel;
7448  AlteredTableInfo *childtab;
7449 
7450  /* find_inheritance_children already got lock */
7451  childrel = table_open(childrelid, NoLock);
7452  CheckTableNotInUse(childrel, "ALTER TABLE");
7453 
7454  /* Find or create work queue entry for this table */
7455  childtab = ATGetQueueEntry(wqueue, childrel);
7456 
7457  /* Recurse to child; return value is ignored */
7458  ATExecAddColumn(wqueue, childtab, childrel,
7459  &childcmd, recurse, true,
7460  lockmode, cur_pass, context);
7461 
7462  table_close(childrel, NoLock);
7463  }
7464 
7465  ObjectAddressSubSet(address, RelationRelationId, myrelid, newattnum);
7466  return address;
7467 }
7468 
7469 /*
7470  * If a new or renamed column will collide with the name of an existing
7471  * column and if_not_exists is false then error out, else do nothing.
7472  */
7473 static bool
7475  bool if_not_exists)
7476 {
7477  HeapTuple attTuple;
7478  int attnum;
7479 
7480  /*
7481  * this test is deliberately not attisdropped-aware, since if one tries to
7482  * add a column matching a dropped column name, it's gonna fail anyway.
7483  */
7484  attTuple = SearchSysCache2(ATTNAME,
7486  PointerGetDatum(colname));
7487  if (!HeapTupleIsValid(attTuple))
7488  return true;
7489 
7490  attnum = ((Form_pg_attribute) GETSTRUCT(attTuple))->attnum;
7491  ReleaseSysCache(attTuple);
7492 
7493  /*
7494  * We throw a different error message for conflicts with system column
7495  * names, since they are normally not shown and the user might otherwise
7496  * be confused about the reason for the conflict.
7497  */
7498  if (attnum <= 0)
7499  ereport(ERROR,
7500  (errcode(ERRCODE_DUPLICATE_COLUMN),
7501  errmsg("column name \"%s\" conflicts with a system column name",
7502  colname)));
7503  else
7504  {
7505  if (if_not_exists)
7506  {
7507  ereport(NOTICE,
7508  (errcode(ERRCODE_DUPLICATE_COLUMN),
7509  errmsg("column \"%s\" of relation \"%s\" already exists, skipping",
7510  colname, RelationGetRelationName(rel))));
7511  return false;
7512  }
7513 
7514  ereport(ERROR,
7515  (errcode(ERRCODE_DUPLICATE_COLUMN),
7516  errmsg("column \"%s\" of relation \"%s\" already exists",
7517  colname, RelationGetRelationName(rel))));
7518  }
7519 
7520  return true;
7521 }
7522 
7523 /*
7524  * Install a column's dependency on its datatype.
7525  */
7526 static void
7528 {
7529  ObjectAddress myself,
7530  referenced;
7531 
7532  myself.classId = RelationRelationId;
7533  myself.objectId = relid;
7534  myself.objectSubId = attnum;
7535  referenced.classId = TypeRelationId;
7536  referenced.objectId = typid;
7537  referenced.objectSubId = 0;
7538  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
7539 }
7540 
7541 /*
7542  * Install a column's dependency on its collation.
7543  */
7544 static void
7546 {
7547  ObjectAddress myself,
7548  referenced;
7549 
7550  /* We know the default collation is pinned, so don't bother recording it */
7551  if (OidIsValid(collid) && collid != DEFAULT_COLLATION_OID)
7552  {
7553  myself.classId = RelationRelationId;
7554  myself.objectId = relid;
7555  myself.objectSubId = attnum;
7556  referenced.classId = CollationRelationId;
7557  referenced.objectId = collid;
7558  referenced.objectSubId = 0;
7559  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
7560  }
7561 }
7562 
7563 /*
7564  * ALTER TABLE ALTER COLUMN DROP NOT NULL
7565  *
7566  * Return the address of the modified column. If the column was already
7567  * nullable, InvalidObjectAddress is returned.
7568  */
7569 static ObjectAddress
7570 ATExecDropNotNull(Relation rel, const char *colName, bool recurse,
7571  LOCKMODE lockmode)
7572 {
7573  HeapTuple tuple;
7574  HeapTuple conTup;
7575  Form_pg_attribute attTup;
7577  Relation attr_rel;
7578  ObjectAddress address;
7579  List *readyRels;
7580 
7581  /*
7582  * lookup the attribute
7583  */
7584  attr_rel = table_open(AttributeRelationId, RowExclusiveLock);
7585 
7586  tuple = SearchSysCacheCopyAttName(RelationGetRelid(rel), colName);
7587  if (!HeapTupleIsValid(tuple))
7588  ereport(ERROR,
7589  (errcode(ERRCODE_UNDEFINED_COLUMN),
7590  errmsg("column \"%s\" of relation \"%s\" does not exist",
7591  colName, RelationGetRelationName(rel))));
7592  attTup = (Form_pg_attribute) GETSTRUCT(tuple);
7593  attnum = attTup->attnum;
7594  ObjectAddressSubSet(address, RelationRelationId,
7595  RelationGetRelid(rel), attnum);
7596 
7597  /* If the column is already nullable there's nothing to do. */
7598  if (!attTup->attnotnull)
7599  {
7600  table_close(attr_rel, RowExclusiveLock);
7601  return InvalidObjectAddress;
7602  }
7603 
7604  /* Prevent them from altering a system attribute */
7605  if (attnum <= 0)
7606  ereport(ERROR,
7607  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
7608  errmsg("cannot alter system column \"%s\"",
7609  colName)));
7610 
7611  if (attTup->attidentity)
7612  ereport(ERROR,
7613  (errcode(ERRCODE_SYNTAX_ERROR),
7614  errmsg("column \"%s\" of relation \"%s\" is an identity column",
7615  colName, RelationGetRelationName(rel))));
7616 
7617  /*
7618  * It's not OK to remove a constraint only for the parent and leave it in
7619  * the children, so disallow that.
7620  */
7621  if (!recurse)
7622  {
7623  if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
7624  {
7625  PartitionDesc partdesc;
7626 
7627  partdesc = RelationGetPartitionDesc(rel, true);
7628 
7629  if (partdesc->nparts > 0)
7630  ereport(ERROR,
7631  errcode(ERRCODE_INVALID_TABLE_DEFINITION),
7632  errmsg("cannot remove constraint from only the partitioned table when partitions exist"),
7633  errhint("Do not specify the ONLY keyword."));
7634  }
7635  else if (rel->rd_rel->relhassubclass &&
7637  {
7638  ereport(ERROR,
7639  errcode(ERRCODE_INVALID_TABLE_DEFINITION),
7640  errmsg("not-null constraint on column \"%s\" must be removed in child tables too",
7641  colName),
7642  errhint("Do not specify the ONLY keyword."));
7643  }
7644  }
7645 
7646  /*
7647  * If rel is partition, shouldn't drop NOT NULL if parent has the same.
7648  */
7649  if (rel->rd_rel->relispartition)
7650  {
7651  Oid parentId = get_partition_parent(RelationGetRelid(rel), false);
7652  Relation parent = table_open(parentId, AccessShareLock);
7653  TupleDesc tupDesc = RelationGetDescr(parent);
7654  AttrNumber parent_attnum;
7655 
7656  parent_attnum = get_attnum(parentId, colName);
7657  if (TupleDescAttr(tupDesc, parent_attnum - 1)->attnotnull)
7658  ereport(ERROR,
7659  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
7660  errmsg("column \"%s\" is marked NOT NULL in parent table",
7661  colName)));
7662  table_close(parent, AccessShareLock);
7663  }
7664 
7665  /*
7666  * Find the constraint that makes this column NOT NULL, and drop it if we
7667  * see one. dropconstraint_internal() will do necessary consistency
7668  * checking. If there isn't one, there are two possibilities: either the
7669  * column is marked attnotnull because it's part of the primary key, and
7670  * then we just throw an appropriate error; or it's a leftover marking
7671  * that we can remove. However, before doing the latter, to avoid
7672  * breaking consistency any further, prevent this if the column is part of
7673  * the replica identity.
7674  */
7675  conTup = findNotNullConstraint(RelationGetRelid(rel), colName);
7676  if (conTup == NULL)
7677  {
7678  Bitmapset *pkcols;
7679  Bitmapset *ircols;
7680 
7681  /*
7682  * If the column is in a primary key, throw a specific error message.
7683  */
7686  pkcols))
7687  ereport(ERROR,
7688  errcode(ERRCODE_INVALID_TABLE_DEFINITION),
7689  errmsg("column \"%s\" is in a primary key", colName));
7690 
7691  /* Also throw an error if the column is in the replica identity */
7694  ereport(ERROR,
7695  errcode(ERRCODE_INVALID_TABLE_DEFINITION),
7696  errmsg("column \"%s\" is in index used as replica identity",
7697  get_attname(RelationGetRelid(rel), attnum, false)));
7698 
7699  /* Otherwise, just remove the attnotnull marking and do nothing else. */
7700  attTup->attnotnull = false;
7701  CatalogTupleUpdate(attr_rel, &tuple->t_self, tuple);
7702  }
7703  else
7704  {
7705  /* The normal case: we have a pg_constraint row, remove it */
7706  readyRels = NIL;
7707  dropconstraint_internal(rel, conTup, DROP_RESTRICT, recurse, false,
7708  false, &readyRels, lockmode);
7709 
7710  heap_freetuple(conTup);
7711  }
7712 
7713  InvokeObjectPostAlterHook(RelationRelationId,
7714  RelationGetRelid(rel), attnum);
7715 
7716  table_close(attr_rel, RowExclusiveLock);
7717 
7718  return address;
7719 }
7720 
7721 /*
7722  * Helper to set pg_attribute.attnotnull if it isn't set, and to tell phase 3
7723  * to verify it; recurses to apply the same to children.
7724  *
7725  * When called to alter an existing table, 'wqueue' must be given so that we can
7726  * queue a check that existing tuples pass the constraint. When called from
7727  * table creation, 'wqueue' should be passed as NULL.
7728  *
7729  * Returns true if the flag was set in any table, otherwise false.
7730  */
7731 static bool
7732 set_attnotnull(List **wqueue, Relation rel, AttrNumber attnum, bool recurse,
7733  LOCKMODE lockmode)
7734 {
7735  HeapTuple tuple;
7736  Form_pg_attribute attForm;
7737  bool retval = false;
7738 
7739  /* Guard against stack overflow due to overly deep inheritance tree. */
7741 
7743  if (!HeapTupleIsValid(tuple))
7744  elog(ERROR, "cache lookup failed for attribute %d of relation %u",
7745  attnum, RelationGetRelid(rel));
7746  attForm = (Form_pg_attribute) GETSTRUCT(tuple);
7747  if (!attForm->attnotnull)
7748  {
7749  Relation attr_rel;
7750 
7751  attr_rel = table_open(AttributeRelationId, RowExclusiveLock);
7752 
7753  attForm->attnotnull = true;
7754  CatalogTupleUpdate(attr_rel, &tuple->t_self, tuple);
7755 
7756  table_close(attr_rel, RowExclusiveLock);
7757 
7758  /*
7759  * And set up for existing values to be checked, unless another
7760  * constraint already proves this.
7761  */
7762  if (wqueue && !NotNullImpliedByRelConstraints(rel, attForm))
7763  {
7764  AlteredTableInfo *tab;
7765 
7766  tab = ATGetQueueEntry(wqueue, rel);
7767  tab->verify_new_notnull = true;
7768  }
7769 
7770  retval = true;
7771  }
7772 
7773  if (recurse)
7774  {
7775  List *children;
7776  ListCell *lc;
7777 
7778  /* Make above update visible, for multiple inheritance cases */
7779  if (retval)
7781 
7782  children = find_inheritance_children(RelationGetRelid(rel), lockmode);
7783  foreach(lc, children)
7784  {
7785  Oid childrelid = lfirst_oid(lc);
7786  Relation childrel;
7787  AttrNumber childattno;
7788 
7789  /* find_inheritance_children already got lock */
7790  childrel = table_open(childrelid, NoLock);
7791  CheckTableNotInUse(childrel, "ALTER TABLE");
7792 
7793  childattno = get_attnum(RelationGetRelid(childrel),
7795  false));
7796  retval |= set_attnotnull(wqueue, childrel, childattno,
7797  recurse, lockmode);
7798  table_close(childrel, NoLock);
7799  }
7800  }
7801 
7802  return retval;
7803 }
7804 
7805 /*
7806  * ALTER TABLE ALTER COLUMN SET NOT NULL
7807  *
7808  * Add a not-null constraint to a single table and its children. Returns
7809  * the address of the constraint added to the parent relation, if one gets
7810  * added, or InvalidObjectAddress otherwise.
7811  *
7812  * We must recurse to child tables during execution, rather than using
7813  * ALTER TABLE's normal prep-time recursion.
7814  */
7815 static ObjectAddress
7816 ATExecSetNotNull(List **wqueue, Relation rel, char *conName, char *colName,
7817  bool recurse, bool recursing, List **readyRels,
7818  LOCKMODE lockmode)
7819 {
7820  HeapTuple tuple;
7821  Relation constr_rel;
7822  ScanKeyData skey;
7823  SysScanDesc conscan;
7825  ObjectAddress address;
7826  Constraint *constraint;
7827  CookedConstraint *ccon;
7828  List *cooked;
7829  bool is_no_inherit = false;
7830  List *ready = NIL;
7831 
7832  /* Guard against stack overflow due to overly deep inheritance tree. */
7834 
7835  /*
7836  * In cases of multiple inheritance, we might visit the same child more
7837  * than once. In the topmost call, set up a list that we fill with all
7838  * visited relations, to skip those.
7839  */
7840  if (readyRels == NULL)
7841  {
7842  Assert(!recursing);
7843  readyRels = &ready;
7844  }
7845  if (list_member_oid(*readyRels, RelationGetRelid(rel)))
7846  return InvalidObjectAddress;
7847  *readyRels = lappend_oid(*readyRels, RelationGetRelid(rel));
7848 
7849  /* At top level, permission check was done in ATPrepCmd, else do it */
7850  if (recursing)
7851  {
7853  Assert(conName != NULL);
7854  }
7855 
7856  attnum = get_attnum(RelationGetRelid(rel), colName);
7857  if (attnum == InvalidAttrNumber)
7858  ereport(ERROR,
7859  (errcode(ERRCODE_UNDEFINED_COLUMN),
7860  errmsg("column \"%s\" of relation \"%s\" does not exist",
7861  colName, RelationGetRelationName(rel))));
7862 
7863  /* Prevent them from altering a system attribute */
7864  if (attnum <= 0)
7865  ereport(ERROR,
7866  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
7867  errmsg("cannot alter system column \"%s\"",
7868  colName)));
7869 
7870  /* See if there's already a constraint */
7871  constr_rel = table_open(ConstraintRelationId, RowExclusiveLock);
7872  ScanKeyInit(&skey,
7873  Anum_pg_constraint_conrelid,
7874  BTEqualStrategyNumber, F_OIDEQ,
7876  conscan = systable_beginscan(constr_rel, ConstraintRelidTypidNameIndexId, true,
7877  NULL, 1, &skey);
7878 
7879  while (HeapTupleIsValid(tuple = systable_getnext(conscan)))
7880  {
7881  Form_pg_constraint conForm = (Form_pg_constraint) GETSTRUCT(tuple);
7882  bool changed = false;
7883  HeapTuple copytup;
7884 
7885  if (conForm->contype != CONSTRAINT_NOTNULL)
7886  continue;
7887 
7888  if (extractNotNullColumn(tuple) != attnum)
7889  continue;
7890 
7891  copytup = heap_copytuple(tuple);
7892  conForm = (Form_pg_constraint) GETSTRUCT(copytup);
7893 
7894  /*
7895  * If we find an appropriate constraint, we're almost done, but just
7896  * need to change some properties on it: if we're recursing, increment
7897  * coninhcount; if not, set conislocal if not already set.
7898  */
7899  if (recursing)
7900  {
7901  conForm->coninhcount++;
7902  changed = true;
7903  }
7904  else if (!conForm->conislocal)
7905  {
7906  conForm->conislocal = true;
7907  changed = true;
7908  }
7909 
7910  if (changed)
7911  {
7912  CatalogTupleUpdate(constr_rel, &copytup->t_self, copytup);
7913  ObjectAddressSet(address, ConstraintRelationId, conForm->oid);
7914  }
7915 
7916  systable_endscan(conscan);
7917  table_close(constr_rel, RowExclusiveLock);
7918 
7919  if (changed)
7920  return address;
7921  else
7922  return InvalidObjectAddress;
7923  }
7924 
7925  systable_endscan(conscan);
7926  table_close(constr_rel, RowExclusiveLock);
7927 
7928  /*
7929  * If we're asked not to recurse, and children exist, raise an error for
7930  * partitioned tables. For inheritance, we act as if NO INHERIT had been
7931  * specified.
7932  */
7933  if (!recurse &&
7935  NoLock) != NIL)
7936  {
7937  if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
7938  ereport(ERROR,
7939  errcode(ERRCODE_INVALID_TABLE_DEFINITION),
7940  errmsg("constraint must be added to child tables too"),
7941  errhint("Do not specify the ONLY keyword."));
7942  else
7943  is_no_inherit = true;
7944  }
7945 
7946  /*
7947  * No constraint exists; we must add one. First determine a name to use,
7948  * if we haven't already.
7949  */
7950  if (!recursing)
7951  {
7952  Assert(conName == NULL);
7954  colName, "not_null",
7955  RelationGetNamespace(rel),
7956  NIL);
7957  }
7958  constraint = makeNode(Constraint);
7959  constraint->contype = CONSTR_NOTNULL;
7960  constraint->conname = conName;
7961  constraint->deferrable = false;
7962  constraint->initdeferred = false;
7963  constraint->location = -1;
7964  constraint->keys = list_make1(makeString(colName));
7965  constraint->is_no_inherit = is_no_inherit;
7966  constraint->inhcount = recursing ? 1 : 0;
7967  constraint->skip_validation = false;
7968  constraint->initially_valid = true;
7969 
7970  /* and do it */
7971  cooked = AddRelationNewConstraints(rel, NIL, list_make1(constraint),
7972  false, !recursing, false, NULL);
7973  ccon = linitial(cooked);
7974  ObjectAddressSet(address, ConstraintRelationId, ccon->conoid);
7975 
7976  InvokeObjectPostAlterHook(RelationRelationId,
7977  RelationGetRelid(rel), attnum);
7978 
7979  /*
7980  * Mark pg_attribute.attnotnull for the column. Tell that function not to
7981  * recurse, because we're going to do it here.
7982  */
7983  set_attnotnull(wqueue, rel, attnum, false, lockmode);
7984 
7985  /*
7986  * Recurse to propagate the constraint to children that don't have one.
7987  */
7988  if (recurse)
7989  {
7990  List *children;
7991  ListCell *lc;
7992 
7994  lockmode);
7995 
7996  foreach(lc, children)
7997  {
7998  Relation childrel;
7999 
8000  childrel = table_open(lfirst_oid(lc), NoLock);
8001 
8002  ATExecSetNotNull(wqueue, childrel,
8003  conName, colName, recurse, true,
8004  readyRels, lockmode);
8005 
8006  table_close(childrel, NoLock);
8007  }
8008  }
8009 
8010  return address;
8011 }
8012 
8013 /*
8014  * ALTER TABLE ALTER COLUMN SET ATTNOTNULL
8015  *
8016  * This doesn't exist in the grammar; it's used when creating a
8017  * primary key and the column is not already marked attnotnull.
8018  */
8019 static ObjectAddress
8021  const char *colName, LOCKMODE lockmode)
8022 {
8025 
8026  attnum = get_attnum(RelationGetRelid(rel), colName);
8027  if (attnum == InvalidAttrNumber)
8028  ereport(ERROR,
8029  errcode(ERRCODE_UNDEFINED_COLUMN),
8030  errmsg("column \"%s\" of relation \"%s\" does not exist",
8031  colName, RelationGetRelationName(rel)));
8032 
8033  /*
8034  * Make the change, if necessary, and only if so report the column as
8035  * changed
8036  */
8037  if (set_attnotnull(wqueue, rel, attnum, false, lockmode))
8038  ObjectAddressSubSet(address, RelationRelationId,
8039  RelationGetRelid(rel), attnum);
8040 
8041  return address;
8042 }
8043 
8044 /*
8045  * NotNullImpliedByRelConstraints
8046  * Does rel's existing constraints imply NOT NULL for the given attribute?
8047  */
8048 static bool
8050 {
8051  NullTest *nnulltest = makeNode(NullTest);
8052 
8053  nnulltest->arg = (Expr *) makeVar(1,
8054  attr->attnum,
8055  attr->atttypid,
8056  attr->atttypmod,
8057  attr->attcollation,
8058  0);
8059  nnulltest->nulltesttype = IS_NOT_NULL;
8060 
8061  /*
8062  * argisrow = false is correct even for a composite column, because
8063  * attnotnull does not represent a SQL-spec IS NOT NULL test in such a
8064  * case, just IS DISTINCT FROM NULL.
8065  */
8066  nnulltest->argisrow = false;
8067  nnulltest->location = -1;
8068 
8069  if (ConstraintImpliedByRelConstraint(rel, list_make1(nnulltest), NIL))
8070  {
8071  ereport(DEBUG1,
8072  (errmsg_internal("existing constraints on column \"%s.%s\" are sufficient to prove that it does not contain nulls",
8073  RelationGetRelationName(rel), NameStr(attr->attname))));
8074  return true;
8075  }
8076 
8077  return false;
8078 }
8079 
8080 /*
8081  * ALTER TABLE ALTER COLUMN SET/DROP DEFAULT
8082  *
8083  * Return the address of the affected column.
8084  */
8085 static ObjectAddress
8086 ATExecColumnDefault(Relation rel, const char *colName,
8087  Node *newDefault, LOCKMODE lockmode)
8088 {
8089  TupleDesc tupdesc = RelationGetDescr(rel);
8091  ObjectAddress address;
8092 
8093  /*
8094  * get the number of the attribute
8095  */
8096  attnum = get_attnum(RelationGetRelid(rel), colName);
8097  if (attnum == InvalidAttrNumber)
8098  ereport(ERROR,
8099  (errcode(ERRCODE_UNDEFINED_COLUMN),
8100  errmsg("column \"%s\" of relation \"%s\" does not exist",
8101  colName, RelationGetRelationName(rel))));
8102 
8103  /* Prevent them from altering a system attribute */
8104  if (attnum <= 0)
8105  ereport(ERROR,
8106  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
8107  errmsg("cannot alter system column \"%s\"",
8108  colName)));
8109 
8110  if (TupleDescAttr(tupdesc, attnum - 1)->attidentity)
8111  ereport(ERROR,
8112  (errcode(ERRCODE_SYNTAX_ERROR),
8113  errmsg("column \"%s\" of relation \"%s\" is an identity column",
8114  colName, RelationGetRelationName(rel)),
8115  /* translator: %s is an SQL ALTER command */
8116  newDefault ? 0 : errhint("Use %s instead.",
8117  "ALTER TABLE ... ALTER COLUMN ... DROP IDENTITY")));
8118 
8119  if (TupleDescAttr(tupdesc, attnum - 1)->attgenerated)
8120  ereport(ERROR,
8121  (errcode(ERRCODE_SYNTAX_ERROR),
8122  errmsg("column \"%s\" of relation \"%s\" is a generated column",
8123  colName, RelationGetRelationName(rel)),
8124  newDefault ?
8125  /* translator: %s is an SQL ALTER command */
8126  errhint("Use %s instead.", "ALTER TABLE ... ALTER COLUMN ... SET EXPRESSION") :
8127  (TupleDescAttr(tupdesc, attnum - 1)->attgenerated == ATTRIBUTE_GENERATED_STORED ?
8128  errhint("Use %s instead.", "ALTER TABLE ... ALTER COLUMN ... DROP EXPRESSION") : 0)));
8129 
8130  /*
8131  * Remove any old default for the column. We use RESTRICT here for
8132  * safety, but at present we do not expect anything to depend on the
8133  * default.
8134  *
8135  * We treat removing the existing default as an internal operation when it
8136  * is preparatory to adding a new default, but as a user-initiated
8137  * operation when the user asked for a drop.
8138  */
8140  newDefault != NULL);
8141 
8142  if (newDefault)
8143  {
8144  /* SET DEFAULT */
8145  RawColumnDefault *rawEnt;
8146 
8147  rawEnt = (RawColumnDefault *) palloc(sizeof(RawColumnDefault));
8148  rawEnt->attnum = attnum;
8149  rawEnt->raw_default = newDefault;
8150  rawEnt->missingMode = false;
8151  rawEnt->generated = '\0';
8152 
8153  /*
8154  * This function is intended for CREATE TABLE, so it processes a
8155  * _list_ of defaults, but we just do one.
8156  */
8158  false, true, false, NULL);
8159  }
8160 
8161  ObjectAddressSubSet(address, RelationRelationId,
8162  RelationGetRelid(rel), attnum);
8163  return address;
8164 }
8165 
8166 /*
8167  * Add a pre-cooked default expression.
8168  *
8169  * Return the address of the affected column.
8170  */
8171 static ObjectAddress
8173  Node *newDefault)
8174 {
8175  ObjectAddress address;
8176 
8177  /* We assume no checking is required */
8178 
8179  /*
8180  * Remove any old default for the column. We use RESTRICT here for
8181  * safety, but at present we do not expect anything to depend on the
8182  * default. (In ordinary cases, there could not be a default in place
8183  * anyway, but it's possible when combining LIKE with inheritance.)
8184  */
8186  true);
8187 
8188  (void) StoreAttrDefault(rel, attnum, newDefault, true, false);
8189 
8190  ObjectAddressSubSet(address, RelationRelationId,
8191  RelationGetRelid(rel), attnum);
8192  return address;
8193 }
8194 
8195 /*
8196  * ALTER TABLE ALTER COLUMN ADD IDENTITY
8197  *
8198  * Return the address of the affected column.
8199  */
8200 static ObjectAddress
8201 ATExecAddIdentity(Relation rel, const char *colName,
8202  Node *def, LOCKMODE lockmode, bool recurse, bool recursing)
8203 {
8204  Relation attrelation;
8205  HeapTuple tuple;
8206  Form_pg_attribute attTup;
8208  ObjectAddress address;
8209  ColumnDef *cdef = castNode(ColumnDef, def);
8210  bool ispartitioned;
8211 
8212  ispartitioned = (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
8213  if (ispartitioned && !recurse)
8214  ereport(ERROR,
8215  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
8216  errmsg("cannot add identity to a column of only the partitioned table"),
8217  errhint("Do not specify the ONLY keyword.")));
8218 
8219  if (rel->rd_rel->relispartition && !recursing)
8220  ereport(ERROR,
8221  errcode(ERRCODE_INVALID_TABLE_DEFINITION),
8222  errmsg("cannot add identity to a column of a partition"));
8223 
8224  attrelation = table_open(AttributeRelationId, RowExclusiveLock);
8225 
8226  tuple = SearchSysCacheCopyAttName(RelationGetRelid(rel), colName);
8227  if (!HeapTupleIsValid(tuple))
8228  ereport(ERROR,
8229  (errcode(ERRCODE_UNDEFINED_COLUMN),
8230  errmsg("column \"%s\" of relation \"%s\" does not exist",
8231  colName, RelationGetRelationName(rel))));
8232  attTup = (Form_pg_attribute) GETSTRUCT(tuple);
8233  attnum = attTup->attnum;
8234 
8235  /* Can't alter a system attribute */
8236  if (attnum <= 0)
8237  ereport(ERROR,
8238  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
8239  errmsg("cannot alter system column \"%s\"",
8240  colName)));
8241 
8242  /*
8243  * Creating a column as identity implies NOT NULL, so adding the identity
8244  * to an existing column that is not NOT NULL would create a state that
8245  * cannot be reproduced without contortions.
8246  */
8247  if (!attTup->attnotnull)
8248  ereport(ERROR,
8249  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
8250  errmsg("column \"%s\" of relation \"%s\" must be declared NOT NULL before identity can be added",
8251  colName, RelationGetRelationName(rel))));
8252 
8253  if (attTup->attidentity)
8254  ereport(ERROR,
8255  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
8256  errmsg("column \"%s\" of relation \"%s\" is already an identity column",
8257  colName, RelationGetRelationName(rel))));
8258 
8259  if (attTup->atthasdef)
8260  ereport(ERROR,
8261  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
8262  errmsg("column \"%s\" of relation \"%s\" already has a default value",
8263  colName, RelationGetRelationName(rel))));
8264 
8265  attTup->attidentity = cdef->identity;
8266  CatalogTupleUpdate(attrelation, &tuple->t_self, tuple);
8267 
8268  InvokeObjectPostAlterHook(RelationRelationId,
8269  RelationGetRelid(rel),
8270  attTup->attnum);
8271  ObjectAddressSubSet(address, RelationRelationId,
8272  RelationGetRelid(rel), attnum);
8273  heap_freetuple(tuple);
8274 
8275  table_close(attrelation, RowExclusiveLock);
8276 
8277  /*
8278  * Recurse to propagate the identity column to partitions. Identity is
8279  * not inherited in regular inheritance children.
8280  */
8281  if (recurse && ispartitioned)
8282  {
8283  List *children;
8284  ListCell *lc;
8285 
8286  children = find_inheritance_children(RelationGetRelid(rel), lockmode);
8287 
8288  foreach(lc, children)
8289  {
8290  Relation childrel;
8291 
8292  childrel = table_open(lfirst_oid(lc), NoLock);
8293  ATExecAddIdentity(childrel, colName, def, lockmode, recurse, true);
8294  table_close(childrel, NoLock);
8295  }
8296  }
8297 
8298  return address;
8299 }
8300 
8301 /*
8302  * ALTER TABLE ALTER COLUMN SET { GENERATED or sequence options }
8303  *
8304  * Return the address of the affected column.
8305  */
8306 static ObjectAddress
8307 ATExecSetIdentity(Relation rel, const char *colName, Node *def,
8308  LOCKMODE lockmode, bool recurse, bool recursing)
8309 {
8310  ListCell *option;
8311  DefElem *generatedEl = NULL;
8312  HeapTuple tuple;
8313  Form_pg_attribute attTup;
8315  Relation attrelation;
8316  ObjectAddress address;
8317  bool ispartitioned;
8318 
8319  ispartitioned = (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
8320  if (ispartitioned && !recurse)
8321  ereport(ERROR,
8322  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
8323  errmsg("cannot change identity column of only the partitioned table"),
8324  errhint("Do not specify the ONLY keyword.")));
8325 
8326  if (rel->rd_rel->relispartition && !recursing)
8327  ereport(ERROR,
8328  errcode(ERRCODE_INVALID_TABLE_DEFINITION),
8329  errmsg("cannot change identity column of a partition"));
8330 
8331  foreach(option, castNode(List, def))
8332  {
8333  DefElem *defel = lfirst_node(DefElem, option);
8334 
8335  if (strcmp(defel->defname, "generated") == 0)
8336  {
8337  if (generatedEl)
8338  ereport(ERROR,
8339  (errcode(ERRCODE_SYNTAX_ERROR),
8340  errmsg("conflicting or redundant options")));
8341  generatedEl = defel;
8342  }
8343  else
8344  elog(ERROR, "option \"%s\" not recognized",
8345  defel->defname);
8346  }
8347 
8348  /*
8349  * Even if there is nothing to change here, we run all the checks. There
8350  * will be a subsequent ALTER SEQUENCE that relies on everything being
8351  * there.
8352  */
8353 
8354  attrelation = table_open(AttributeRelationId, RowExclusiveLock);
8355  tuple = SearchSysCacheCopyAttName(RelationGetRelid(rel), colName);
8356  if (!HeapTupleIsValid(tuple))
8357  ereport(ERROR,
8358  (errcode(ERRCODE_UNDEFINED_COLUMN),
8359  errmsg("column \"%s\" of relation \"%s\" does not exist",
8360  colName, RelationGetRelationName(rel))));
8361 
8362  attTup = (Form_pg_attribute) GETSTRUCT(tuple);
8363  attnum = attTup->attnum;
8364 
8365  if (attnum <= 0)
8366  ereport(ERROR,
8367  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
8368  errmsg("cannot alter system column \"%s\"",
8369  colName)));
8370 
8371  if (!attTup->attidentity)
8372  ereport(ERROR,
8373  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
8374  errmsg("column \"%s\" of relation \"%s\" is not an identity column",
8375  colName, RelationGetRelationName(rel))));
8376 
8377  if (generatedEl)
8378  {
8379  attTup->attidentity = defGetInt32(generatedEl);
8380  CatalogTupleUpdate(attrelation, &tuple->t_self, tuple);
8381 
8382  InvokeObjectPostAlterHook(RelationRelationId,
8383  RelationGetRelid(rel),
8384  attTup->attnum);
8385  ObjectAddressSubSet(address, RelationRelationId,
8386  RelationGetRelid(rel), attnum);
8387  }
8388  else
8389  address = InvalidObjectAddress;
8390 
8391  heap_freetuple(tuple);
8392  table_close(attrelation, RowExclusiveLock);
8393 
8394  /*
8395  * Recurse to propagate the identity change to partitions. Identity is not
8396  * inherited in regular inheritance children.
8397  */
8398  if (generatedEl && recurse && ispartitioned)
8399  {
8400  List *children;
8401  ListCell *lc;
8402 
8403  children = find_inheritance_children(RelationGetRelid(rel), lockmode);
8404 
8405  foreach(lc, children)
8406  {
8407  Relation childrel;
8408 
8409  childrel = table_open(lfirst_oid(lc), NoLock);
8410  ATExecSetIdentity(childrel, colName, def, lockmode, recurse, true);
8411  table_close(childrel, NoLock);
8412  }
8413  }
8414 
8415  return address;
8416 }
8417 
8418 /*
8419  * ALTER TABLE ALTER COLUMN DROP IDENTITY
8420  *
8421  * Return the address of the affected column.
8422  */
8423 static ObjectAddress
8424 ATExecDropIdentity(Relation rel, const char *colName, bool missing_ok, LOCKMODE lockmode,
8425  bool recurse, bool recursing)
8426 {
8427  HeapTuple tuple;
8428  Form_pg_attribute attTup;
8430  Relation attrelation;
8431  ObjectAddress address;
8432  Oid seqid;
8433  ObjectAddress seqaddress;
8434  bool ispartitioned;
8435 
8436  ispartitioned = (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
8437  if (ispartitioned && !recurse)
8438  ereport(ERROR,
8439  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
8440  errmsg("cannot drop identity from a column of only the partitioned table"),
8441  errhint("Do not specify the ONLY keyword.")));
8442 
8443  if (rel->rd_rel->relispartition && !recursing)
8444  ereport(ERROR,
8445  errcode(ERRCODE_INVALID_TABLE_DEFINITION),
8446  errmsg("cannot drop identity from a column of a partition"));
8447 
8448  attrelation = table_open(AttributeRelationId, RowExclusiveLock);
8449  tuple = SearchSysCacheCopyAttName(RelationGetRelid(rel), colName);
8450  if (!HeapTupleIsValid(tuple))
8451  ereport(ERROR,
8452  (errcode(ERRCODE_UNDEFINED_COLUMN),
8453  errmsg("column \"%s\" of relation \"%s\" does not exist",
8454  colName, RelationGetRelationName(rel))));
8455 
8456  attTup = (Form_pg_attribute) GETSTRUCT(tuple);
8457  attnum = attTup->attnum;
8458 
8459  if (attnum <= 0)
8460  ereport(ERROR,
8461  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
8462  errmsg("cannot alter system column \"%s\"",
8463  colName)));
8464 
8465  if (!attTup->attidentity)
8466  {
8467  if (!missing_ok)
8468  ereport(ERROR,
8469  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
8470  errmsg("column \"%s\" of relation \"%s\" is not an identity column",
8471  colName, RelationGetRelationName(rel))));
8472  else
8473  {
8474  ereport(NOTICE,
8475  (errmsg("column \"%s\" of relation \"%s\" is not an identity column, skipping",
8476  colName, RelationGetRelationName(rel))));
8477  heap_freetuple(tuple);
8478  table_close(attrelation, RowExclusiveLock);
8479  return InvalidObjectAddress;
8480  }
8481  }
8482 
8483  attTup->attidentity = '\0';
8484  CatalogTupleUpdate(attrelation, &tuple->t_self, tuple);
8485 
8486  InvokeObjectPostAlterHook(RelationRelationId,
8487  RelationGetRelid(rel),
8488  attTup->attnum);
8489  ObjectAddressSubSet(address, RelationRelationId,
8490  RelationGetRelid(rel), attnum);
8491  heap_freetuple(tuple);
8492 
8493  table_close(attrelation, RowExclusiveLock);
8494 
8495  /*
8496  * Recurse to drop the identity from column in partitions. Identity is
8497  * not inherited in regular inheritance children so ignore them.
8498  */
8499  if (recurse && ispartitioned)
8500  {
8501  List *children;
8502  ListCell *lc;
8503 
8504  children = find_inheritance_children(RelationGetRelid(rel), lockmode);
8505 
8506  foreach(lc, children)
8507  {
8508  Relation childrel;
8509 
8510  childrel = table_open(lfirst_oid(lc), NoLock);
8511  ATExecDropIdentity(childrel, colName, false, lockmode, recurse, true);
8512  table_close(childrel, NoLock);
8513  }
8514  }
8515 
8516  if (!recursing)
8517  {
8518  /* drop the internal sequence */
8519  seqid = getIdentitySequence(RelationGetRelid(rel), attnum, false);
8520  deleteDependencyRecordsForClass(RelationRelationId, seqid,
8521  RelationRelationId, DEPENDENCY_INTERNAL);
8523  seqaddress.classId = RelationRelationId;
8524  seqaddress.objectId = seqid;
8525  seqaddress.objectSubId = 0;
8527  }
8528 
8529  return address;
8530 }
8531 
8532 /*
8533  * ALTER TABLE ALTER COLUMN SET EXPRESSION
8534  *
8535  * Return the address of the affected column.
8536  */
8537 static ObjectAddress
8538 ATExecSetExpression(AlteredTableInfo *tab, Relation rel, const char *colName,
8539  Node *newExpr, LOCKMODE lockmode)
8540 {
8541  HeapTuple tuple;
8542  Form_pg_attribute attTup;
8544  Oid attrdefoid;
8545  ObjectAddress address;
8546  Expr *defval;
8548  RawColumnDefault *rawEnt;
8549 
8550  tuple = SearchSysCacheAttName(RelationGetRelid(rel), colName);
8551  if (!HeapTupleIsValid(tuple))
8552  ereport(ERROR,
8553  (errcode(ERRCODE_UNDEFINED_COLUMN),
8554  errmsg("column \"%s\" of relation \"%s\" does not exist",
8555  colName, RelationGetRelationName(rel))));
8556 
8557  attTup = (Form_pg_attribute) GETSTRUCT(tuple);
8558  attnum = attTup->attnum;
8559 
8560  if (attnum <= 0)
8561  ereport(ERROR,
8562  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
8563  errmsg("cannot alter system column \"%s\"",
8564  colName)));
8565 
8566  if (attTup->attgenerated != ATTRIBUTE_GENERATED_STORED)
8567  ereport(ERROR,
8568  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
8569  errmsg("column \"%s\" of relation \"%s\" is not a generated column",
8570  colName, RelationGetRelationName(rel))));
8571  ReleaseSysCache(tuple);
8572 
8573  /*
8574  * Clear all the missing values if we're rewriting the table, since this
8575  * renders them pointless.
8576  */
8577  RelationClearMissing(rel);
8578 
8579  /* make sure we don't conflict with later attribute modifications */
8581 
8582  /*
8583  * Find everything that depends on the column (constraints, indexes, etc),
8584  * and record enough information to let us recreate the objects after
8585  * rewrite.
8586  */
8588 
8589  /*
8590  * Drop the dependency records of the GENERATED expression, in particular
8591  * its INTERNAL dependency on the column, which would otherwise cause
8592  * dependency.c to refuse to perform the deletion.
8593  */
8594  attrdefoid = GetAttrDefaultOid(RelationGetRelid(rel), attnum);
8595  if (!OidIsValid(attrdefoid))
8596  elog(ERROR, "could not find attrdef tuple for relation %u attnum %d",
8597  RelationGetRelid(rel), attnum);
8598  (void) deleteDependencyRecordsFor(AttrDefaultRelationId, attrdefoid, false);
8599 
8600  /* Make above changes visible */
8602 
8603  /*
8604  * Get rid of the GENERATED expression itself. We use RESTRICT here for
8605  * safety, but at present we do not expect anything to depend on the
8606  * expression.
8607  */
8609  false, false);
8610 
8611  /* Prepare to store the new expression, in the catalogs */
8612  rawEnt = (RawColumnDefault *) palloc(sizeof(RawColumnDefault));
8613  rawEnt->attnum = attnum;
8614  rawEnt->raw_default = newExpr;
8615  rawEnt->missingMode = false;
8616  rawEnt->generated = ATTRIBUTE_GENERATED_STORED;
8617 
8618  /* Store the generated expression */
8620  false, true, false, NULL);
8621 
8622  /* Make above new expression visible */
8624 
8625  /* Prepare for table rewrite */
8626  defval = (Expr *) build_column_default(rel, attnum);
8627 
8629  newval->attnum = attnum;
8630  newval->expr = expression_planner(defval);
8631  newval->is_generated = true;
8632 
8633  tab->newvals = lappend(tab->newvals, newval);
8635 
8636  /* Drop any pg_statistic entry for the column */
8638 
8639  InvokeObjectPostAlterHook(RelationRelationId,
8640  RelationGetRelid(rel), attnum);
8641 
8642  ObjectAddressSubSet(address, RelationRelationId,
8643  RelationGetRelid(rel), attnum);
8644  return address;
8645 }
8646 
8647 /*
8648  * ALTER TABLE ALTER COLUMN DROP EXPRESSION
8649  */
8650 static void
8651 ATPrepDropExpression(Relation rel, AlterTableCmd *cmd, bool recurse, bool recursing, LOCKMODE lockmode)
8652 {
8653  /*
8654  * Reject ONLY if there are child tables. We could implement this, but it
8655  * is a bit complicated. GENERATED clauses must be attached to the column
8656  * definition and cannot be added later like DEFAULT, so if a child table
8657  * has a generation expression that the parent does not have, the child
8658  * column will necessarily be an attislocal column. So to implement ONLY
8659  * here, we'd need extra code to update attislocal of the direct child
8660  * tables, somewhat similar to how DROP COLUMN does it, so that the
8661  * resulting state can be properly dumped and restored.
8662  */
8663  if (!recurse &&
8665  ereport(ERROR,
8666  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
8667  errmsg("ALTER TABLE / DROP EXPRESSION must be applied to child tables too")));
8668 
8669  /*
8670  * Cannot drop generation expression from inherited columns.
8671  */
8672  if (!recursing)
8673  {
8674  HeapTuple tuple;
8675  Form_pg_attribute attTup;
8676 
8677  tuple = SearchSysCacheCopyAttName(RelationGetRelid(rel), cmd->name);
8678  if (!HeapTupleIsValid(tuple))
8679  ereport(ERROR,
8680  (errcode(ERRCODE_UNDEFINED_COLUMN),
8681  errmsg("column \"%s\" of relation \"%s\" does not exist",
8682  cmd->name, RelationGetRelationName(rel))));
8683 
8684  attTup = (Form_pg_attribute) GETSTRUCT(tuple);
8685 
8686  if (attTup->attinhcount > 0)
8687  ereport(ERROR,
8688  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
8689  errmsg("cannot drop generation expression from inherited column")));
8690  }
8691 }
8692 
8693 /*
8694  * Return the address of the affected column.
8695  */
8696 static ObjectAddress
8697 ATExecDropExpression(Relation rel, const char *colName, bool missing_ok, LOCKMODE lockmode)
8698 {
8699  HeapTuple tuple;
8700  Form_pg_attribute attTup;
8702  Relation attrelation;
8703  Oid attrdefoid;
8704  ObjectAddress address;
8705 
8706  attrelation = table_open(AttributeRelationId, RowExclusiveLock);
8707  tuple = SearchSysCacheCopyAttName(RelationGetRelid(rel), colName);
8708  if (!HeapTupleIsValid(tuple))
8709  ereport(ERROR,
8710  (errcode(ERRCODE_UNDEFINED_COLUMN),
8711  errmsg("column \"%s\" of relation \"%s\" does not exist",
8712  colName, RelationGetRelationName(rel))));
8713 
8714  attTup = (Form_pg_attribute) GETSTRUCT(tuple);
8715  attnum = attTup->attnum;
8716 
8717  if (attnum <= 0)
8718  ereport(ERROR,
8719  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
8720  errmsg("cannot alter system column \"%s\"",
8721  colName)));
8722 
8723  if (attTup->attgenerated != ATTRIBUTE_GENERATED_STORED)
8724  {
8725  if (!missing_ok)
8726  ereport(ERROR,
8727  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
8728  errmsg("column \"%s\" of relation \"%s\" is not a stored generated column",
8729  colName, RelationGetRelationName(rel))));
8730  else
8731  {
8732  ereport(NOTICE,
8733  (errmsg("column \"%s\" of relation \"%s\" is not a stored generated column, skipping",
8734  colName, RelationGetRelationName(rel))));
8735  heap_freetuple(tuple);
8736  table_close(attrelation, RowExclusiveLock);
8737  return InvalidObjectAddress;
8738  }
8739  }
8740 
8741  /*
8742  * Mark the column as no longer generated. (The atthasdef flag needs to
8743  * get cleared too, but RemoveAttrDefault will handle that.)
8744  */
8745  attTup->attgenerated = '\0';
8746  CatalogTupleUpdate(attrelation, &tuple->t_self, tuple);
8747 
8748  InvokeObjectPostAlterHook(RelationRelationId,
8749  RelationGetRelid(rel),
8750  attnum);
8751  heap_freetuple(tuple);
8752 
8753  table_close(attrelation, RowExclusiveLock);
8754 
8755  /*
8756  * Drop the dependency records of the GENERATED expression, in particular
8757  * its INTERNAL dependency on the column, which would otherwise cause
8758  * dependency.c to refuse to perform the deletion.
8759  */
8760  attrdefoid = GetAttrDefaultOid(RelationGetRelid(rel), attnum);
8761  if (!OidIsValid(attrdefoid))
8762  elog(ERROR, "could not find attrdef tuple for relation %u attnum %d",
8763  RelationGetRelid(rel), attnum);
8764  (void) deleteDependencyRecordsFor(AttrDefaultRelationId, attrdefoid, false);
8765 
8766  /* Make above changes visible */
8768 
8769  /*
8770  * Get rid of the GENERATED expression itself. We use RESTRICT here for
8771  * safety, but at present we do not expect anything to depend on the
8772  * default.
8773  */
8775  false, false);
8776 
8777  ObjectAddressSubSet(address, RelationRelationId,
8778  RelationGetRelid(rel), attnum);
8779  return address;
8780 }
8781 
8782 /*
8783  * ALTER TABLE ALTER COLUMN SET STATISTICS
8784  *
8785  * Return value is the address of the modified column
8786  */
8787 static ObjectAddress
8788 ATExecSetStatistics(Relation rel, const char *colName, int16 colNum, Node *newValue, LOCKMODE lockmode)
8789 {
8790  int newtarget = 0;
8791  bool newtarget_default;
8792  Relation attrelation;
8793  HeapTuple tuple,
8794  newtuple;
8795  Form_pg_attribute attrtuple;
8797  ObjectAddress address;
8798  Datum repl_val[Natts_pg_attribute];
8799  bool repl_null[Natts_pg_attribute];
8800  bool repl_repl[Natts_pg_attribute];
8801 
8802  /*
8803  * We allow referencing columns by numbers only for indexes, since table
8804  * column numbers could contain gaps if columns are later dropped.
8805  */
8806  if (rel->rd_rel->relkind != RELKIND_INDEX &&
8807  rel->rd_rel->relkind != RELKIND_PARTITIONED_INDEX &&
8808  !colName)
8809  ereport(ERROR,
8810  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
8811  errmsg("cannot refer to non-index column by number")));
8812 
8813  /* -1 was used in previous versions for the default setting */
8814  if (newValue && intVal(newValue) != -1)
8815  {
8816  newtarget = intVal(newValue);
8817  newtarget_default = false;
8818  }
8819  else
8820  newtarget_default = true;
8821 
8822  if (!newtarget_default)
8823  {
8824  /*
8825  * Limit target to a sane range
8826  */
8827  if (newtarget < 0)
8828  {
8829  ereport(ERROR,
8830  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
8831  errmsg("statistics target %d is too low",
8832  newtarget)));
8833  }
8834  else if (newtarget > MAX_STATISTICS_TARGET)
8835  {
8836  newtarget = MAX_STATISTICS_TARGET;
8837  ereport(WARNING,
8838  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
8839  errmsg("lowering statistics target to %d",
8840  newtarget)));
8841  }
8842  }
8843 
8844  attrelation = table_open(AttributeRelationId, RowExclusiveLock);
8845 
8846  if (colName)
8847  {
8848  tuple = SearchSysCacheAttName(RelationGetRelid(rel), colName);
8849 
8850  if (!HeapTupleIsValid(tuple))
8851  ereport(ERROR,
8852  (errcode(ERRCODE_UNDEFINED_COLUMN),
8853  errmsg("column \"%s\" of relation \"%s\" does not exist",
8854  colName, RelationGetRelationName(rel))));
8855  }
8856  else
8857  {
8858  tuple = SearchSysCacheAttNum(RelationGetRelid(rel), colNum);
8859 
8860  if (!HeapTupleIsValid(tuple))
8861  ereport(ERROR,
8862  (errcode(ERRCODE_UNDEFINED_COLUMN),
8863  errmsg("column number %d of relation \"%s\" does not exist",
8864  colNum, RelationGetRelationName(rel))));
8865  }
8866 
8867  attrtuple = (Form_pg_attribute) GETSTRUCT(tuple);
8868 
8869  attnum = attrtuple->attnum;
8870  if (attnum <= 0)
8871  ereport(ERROR,
8872  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
8873  errmsg("cannot alter system column \"%s\"",
8874  colName)));
8875 
8876  if (rel->rd_rel->relkind == RELKIND_INDEX ||
8877  rel->rd_rel->relkind == RELKIND_PARTITIONED_INDEX)
8878  {
8879  if (attnum > rel->rd_index->indnkeyatts)
8880  ereport(ERROR,
8881  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
8882  errmsg("cannot alter statistics on included column \"%s\" of index \"%s\"",
8883  NameStr(attrtuple->attname), RelationGetRelationName(rel))));
8884  else if (rel->rd_index->indkey.values[attnum - 1] != 0)
8885  ereport(ERROR,
8886  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
8887  errmsg("cannot alter statistics on non-expression column \"%s\" of index \"%s\"",
8888  NameStr(attrtuple->attname), RelationGetRelationName(rel)),
8889  errhint("Alter statistics on table column instead.")));
8890  }
8891 
8892  /* Build new tuple. */
8893  memset(repl_null, false, sizeof(repl_null));
8894  memset(repl_repl, false, sizeof(repl_repl));
8895  if (!newtarget_default)
8896  repl_val[Anum_pg_attribute_attstattarget - 1] = newtarget;
8897  else
8898  repl_null[Anum_pg_attribute_attstattarget - 1] = true;
8899  repl_repl[Anum_pg_attribute_attstattarget - 1] = true;
8900  newtuple = heap_modify_tuple(tuple, RelationGetDescr(attrelation),
8901  repl_val, repl_null, repl_repl);
8902  CatalogTupleUpdate(attrelation, &tuple->t_self, newtuple);
8903 
8904  InvokeObjectPostAlterHook(RelationRelationId,
8905  RelationGetRelid(rel),
8906  attrtuple->attnum);
8907  ObjectAddressSubSet(address, RelationRelationId,
8908  RelationGetRelid(rel), attnum);
8909 
8910  heap_freetuple(newtuple);
8911 
8912  ReleaseSysCache(tuple);
8913 
8914  table_close(attrelation, RowExclusiveLock);
8915 
8916  return address;
8917 }
8918 
8919 /*
8920  * Return value is the address of the modified column
8921  */
8922 static ObjectAddress
8923 ATExecSetOptions(Relation rel, const char *colName, Node *options,
8924  bool isReset, LOCKMODE lockmode)
8925 {
8926  Relation attrelation;
8927  HeapTuple tuple,
8928  newtuple;
8929  Form_pg_attribute attrtuple;
8931  Datum datum,
8932  newOptions;
8933  bool isnull;
8934  ObjectAddress address;
8935  Datum repl_val[Natts_pg_attribute];
8936  bool repl_null[Natts_pg_attribute];
8937  bool repl_repl[Natts_pg_attribute];
8938 
8939  attrelation = table_open(AttributeRelationId, RowExclusiveLock);
8940 
8941  tuple = SearchSysCacheAttName(RelationGetRelid(rel), colName);
8942 
8943  if (!HeapTupleIsValid(tuple))
8944  ereport(ERROR,
8945  (errcode(ERRCODE_UNDEFINED_COLUMN),
8946  errmsg("column \"%s\" of relation \"%s\" does not exist",
8947  colName, RelationGetRelationName(rel))));
8948  attrtuple = (Form_pg_attribute) GETSTRUCT(tuple);
8949 
8950  attnum = attrtuple->attnum;
8951  if (attnum <= 0)
8952  ereport(ERROR,
8953  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
8954  errmsg("cannot alter system column \"%s\"",
8955  colName)));
8956 
8957  /* Generate new proposed attoptions (text array) */
8958  datum = SysCacheGetAttr(ATTNAME, tuple, Anum_pg_attribute_attoptions,
8959  &isnull);
8960  newOptions = transformRelOptions(isnull ? (Datum) 0 : datum,
8961  castNode(List, options), NULL, NULL,
8962  false, isReset);
8963  /* Validate new options */
8964  (void) attribute_reloptions(newOptions, true);
8965 
8966  /* Build new tuple. */
8967  memset(repl_null, false, sizeof(repl_null));
8968  memset(repl_repl, false, sizeof(repl_repl));
8969  if (newOptions != (Datum) 0)
8970  repl_val[Anum_pg_attribute_attoptions - 1] = newOptions;
8971  else
8972  repl_null[Anum_pg_attribute_attoptions - 1] = true;
8973  repl_repl[Anum_pg_attribute_attoptions - 1] = true;
8974  newtuple = heap_modify_tuple(tuple, RelationGetDescr(attrelation),
8975  repl_val, repl_null, repl_repl);
8976 
8977  /* Update system catalog. */
8978  CatalogTupleUpdate(attrelation, &newtuple->t_self, newtuple);
8979 
8980  InvokeObjectPostAlterHook(RelationRelationId,
8981  RelationGetRelid(rel),
8982  attrtuple->attnum);
8983  ObjectAddressSubSet(address, RelationRelationId,
8984  RelationGetRelid(rel), attnum);
8985 
8986  heap_freetuple(newtuple);
8987 
8988  ReleaseSysCache(tuple);
8989 
8990  table_close(attrelation, RowExclusiveLock);
8991 
8992  return address;
8993 }
8994 
8995 /*
8996  * Helper function for ATExecSetStorage and ATExecSetCompression
8997  *
8998  * Set the attstorage and/or attcompression fields for index columns
8999  * associated with the specified table column.
9000  */
9001 static void
9004  bool setstorage, char newstorage,
9005  bool setcompression, char newcompression,
9006  LOCKMODE lockmode)
9007 {
9008  ListCell *lc;
9009 
9010  foreach(lc, RelationGetIndexList(rel))
9011  {
9012  Oid indexoid = lfirst_oid(lc);
9013  Relation indrel;
9014  AttrNumber indattnum = 0;
9015  HeapTuple tuple;
9016 
9017  indrel = index_open(indexoid, lockmode);
9018 
9019  for (int i = 0; i < indrel->rd_index->indnatts; i++)
9020  {
9021  if (indrel->rd_index->indkey.values[i] == attnum)
9022  {
9023  indattnum = i + 1;
9024  break;
9025  }
9026  }
9027 
9028  if (indattnum == 0)
9029  {
9030  index_close(indrel, lockmode);
9031  continue;
9032  }
9033 
9034  tuple = SearchSysCacheCopyAttNum(RelationGetRelid(indrel), indattnum);
9035 
9036  if (HeapTupleIsValid(tuple))
9037  {
9038  Form_pg_attribute attrtuple = (Form_pg_attribute) GETSTRUCT(tuple);
9039 
9040  if (setstorage)
9041  attrtuple->attstorage = newstorage;
9042 
9043  if (setcompression)
9044  attrtuple->attcompression = newcompression;
9045 
9046  CatalogTupleUpdate(attrelation, &tuple->t_self, tuple);
9047 
9048  InvokeObjectPostAlterHook(RelationRelationId,
9049  RelationGetRelid(rel),
9050  attrtuple->attnum);
9051 
9052  heap_freetuple(tuple);
9053  }
9054 
9055  index_close(indrel, lockmode);
9056  }
9057 }
9058 
9059 /*
9060  * ALTER TABLE ALTER COLUMN SET STORAGE
9061  *
9062  * Return value is the address of the modified column
9063  */
9064 static ObjectAddress
9065 ATExecSetStorage(Relation rel, const char *colName, Node *newValue, LOCKMODE lockmode)
9066 {
9067  Relation attrelation;
9068  HeapTuple tuple;
9069  Form_pg_attribute attrtuple;
9071  ObjectAddress address;
9072 
9073  attrelation = table_open(AttributeRelationId, RowExclusiveLock);
9074 
9075  tuple = SearchSysCacheCopyAttName(RelationGetRelid(rel), colName);
9076 
9077  if (!HeapTupleIsValid(tuple))
9078  ereport(ERROR,
9079  (errcode(ERRCODE_UNDEFINED_COLUMN),
9080  errmsg("column \"%s\" of relation \"%s\" does not exist",
9081  colName, RelationGetRelationName(rel))));
9082  attrtuple = (Form_pg_attribute) GETSTRUCT(tuple);
9083 
9084  attnum = attrtuple->attnum;
9085  if (attnum <= 0)
9086  ereport(ERROR,
9087  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
9088  errmsg("cannot alter system column \"%s\"",
9089  colName)));
9090 
9091  attrtuple->attstorage = GetAttributeStorage(attrtuple->atttypid, strVal(newValue));
9092 
9093  CatalogTupleUpdate(attrelation, &tuple->t_self, tuple);
9094 
9095  InvokeObjectPostAlterHook(RelationRelationId,
9096  RelationGetRelid(rel),
9097  attrtuple->attnum);
9098 
9099  /*
9100  * Apply the change to indexes as well (only for simple index columns,
9101  * matching behavior of index.c ConstructTupleDescriptor()).
9102  */
9103  SetIndexStorageProperties(rel, attrelation, attnum,
9104  true, attrtuple->attstorage,
9105  false, 0,
9106  lockmode);
9107 
9108  heap_freetuple(tuple);
9109 
9110  table_close(attrelation, RowExclusiveLock);
9111 
9112  ObjectAddressSubSet(address, RelationRelationId,
9113  RelationGetRelid(rel), attnum);
9114  return address;
9115 }
9116 
9117 
9118 /*
9119  * ALTER TABLE DROP COLUMN
9120  *
9121  * DROP COLUMN cannot use the normal ALTER TABLE recursion mechanism,
9122  * because we have to decide at runtime whether to recurse or not depending
9123  * on whether attinhcount goes to zero or not. (We can't check this in a
9124  * static pre-pass because it won't handle multiple inheritance situations
9125  * correctly.)
9126  */
9127 static void
9128 ATPrepDropColumn(List **wqueue, Relation rel, bool recurse, bool recursing,
9129  AlterTableCmd *cmd, LOCKMODE lockmode,
9131 {
9132  if (rel->rd_rel->reloftype && !recursing)
9133  ereport(ERROR,
9134  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
9135  errmsg("cannot drop column from typed table")));
9136 
9137  if (rel->rd_rel->relkind == RELKIND_COMPOSITE_TYPE)
9138  ATTypedTableRecursion(wqueue, rel, cmd, lockmode, context);
9139 
9140  if (recurse)
9141  cmd->recurse = true;
9142 }
9143 
9144 /*
9145  * Drops column 'colName' from relation 'rel' and returns the address of the
9146  * dropped column. The column is also dropped (or marked as no longer
9147  * inherited from relation) from the relation's inheritance children, if any.
9148  *
9149  * In the recursive invocations for inheritance child relations, instead of
9150  * dropping the column directly (if to be dropped at all), its object address
9151  * is added to 'addrs', which must be non-NULL in such invocations. All
9152  * columns are dropped at the same time after all the children have been
9153  * checked recursively.
9154  */
9155 static ObjectAddress
9156 ATExecDropColumn(List **wqueue, Relation rel, const char *colName,
9157  DropBehavior behavior,
9158  bool recurse, bool recursing,
9159  bool missing_ok, LOCKMODE lockmode,
9160  ObjectAddresses *addrs)
9161 {
9162  HeapTuple tuple;
9163  Form_pg_attribute targetatt;
9165  List *children;
9166  ObjectAddress object;
9167  bool is_expr;
9168 
9169  /* At top level, permission check was done in ATPrepCmd, else do it */
9170  if (recursing)
9172 
9173  /* Initialize addrs on the first invocation */
9174  Assert(!recursing || addrs != NULL);
9175 
9176  /* since this function recurses, it could be driven to stack overflow */
9178 
9179  if (!recursing)
9180  addrs = new_object_addresses();
9181 
9182  /*
9183  * get the number of the attribute
9184  */
9185  tuple = SearchSysCacheAttName(RelationGetRelid(rel), colName);
9186  if (!HeapTupleIsValid(tuple))
9187  {
9188  if (!missing_ok)
9189  {
9190  ereport(ERROR,
9191  (errcode(ERRCODE_UNDEFINED_COLUMN),
9192  errmsg("column \"%s\" of relation \"%s\" does not exist",
9193  colName, RelationGetRelationName(rel))));
9194  }
9195  else
9196  {
9197  ereport(NOTICE,
9198  (errmsg("column \"%s\" of relation \"%s\" does not exist, skipping",
9199  colName, RelationGetRelationName(rel))));
9200  return InvalidObjectAddress;
9201  }
9202  }
9203  targetatt = (Form_pg_attribute) GETSTRUCT(tuple);
9204 
9205  attnum = targetatt->attnum;
9206 
9207  /* Can't drop a system attribute */
9208  if (attnum <= 0)
9209  ereport(ERROR,
9210  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
9211  errmsg("cannot drop system column \"%s\"",
9212  colName)));
9213 
9214  /*
9215  * Don't drop inherited columns, unless recursing (presumably from a drop
9216  * of the parent column)
9217  */
9218  if (targetatt->attinhcount > 0 && !recursing)
9219  ereport(ERROR,
9220  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
9221  errmsg("cannot drop inherited column \"%s\"",
9222  colName)));
9223 
9224  /*
9225  * Don't drop columns used in the partition key, either. (If we let this
9226  * go through, the key column's dependencies would cause a cascaded drop
9227  * of the whole table, which is surely not what the user expected.)
9228  */
9229  if (has_partition_attrs(rel,
9231  &is_expr))
9232  ereport(ERROR,
9233  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
9234  errmsg("cannot drop column \"%s\" because it is part of the partition key of relation \"%s\"",
9235  colName, RelationGetRelationName(rel))));
9236 
9237  ReleaseSysCache(tuple);
9238 
9239  /*
9240  * Propagate to children as appropriate. Unlike most other ALTER
9241  * routines, we have to do this one level of recursion at a time; we can't
9242  * use find_all_inheritors to do it in one pass.
9243  */
9244  children =
9246 
9247  if (children)
9248  {
9249  Relation attr_rel;
9250  ListCell *child;
9251 
9252  /*
9253  * In case of a partitioned table, the column must be dropped from the
9254  * partitions as well.
9255  */
9256  if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE && !recurse)
9257  ereport(ERROR,
9258  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
9259  errmsg("cannot drop column from only the partitioned table when partitions exist"),
9260  errhint("Do not specify the ONLY keyword.")));
9261 
9262  attr_rel = table_open(AttributeRelationId, RowExclusiveLock);
9263  foreach(child, children)
9264  {
9265  Oid childrelid = lfirst_oid(child);
9266  Relation childrel;
9267  Form_pg_attribute childatt;
9268 
9269  /* find_inheritance_children already got lock */
9270  childrel = table_open(childrelid, NoLock);
9271  CheckTableNotInUse(childrel, "ALTER TABLE");
9272 
9273  tuple = SearchSysCacheCopyAttName(childrelid, colName);
9274  if (!HeapTupleIsValid(tuple)) /* shouldn't happen */
9275  elog(ERROR, "cache lookup failed for attribute \"%s\" of relation %u",
9276  colName, childrelid);
9277  childatt = (Form_pg_attribute) GETSTRUCT(tuple);
9278 
9279  if (childatt->attinhcount <= 0) /* shouldn't happen */
9280  elog(ERROR, "relation %u has non-inherited attribute \"%s\"",
9281  childrelid, colName);
9282 
9283  if (recurse)
9284  {
9285  /*
9286  * If the child column has other definition sources, just
9287  * decrement its inheritance count; if not, recurse to delete
9288  * it.
9289  */
9290  if (childatt->attinhcount == 1 && !childatt->attislocal)
9291  {
9292  /* Time to delete this child column, too */
9293  ATExecDropColumn(wqueue, childrel, colName,
9294  behavior, true, true,
9295  false, lockmode, addrs);
9296  }
9297  else
9298  {
9299  /* Child column must survive my deletion */
9300  childatt->attinhcount--;
9301 
9302  CatalogTupleUpdate(attr_rel, &tuple->t_self, tuple);
9303 
9304  /* Make update visible */
9306  }
9307  }
9308  else
9309  {
9310  /*
9311  * If we were told to drop ONLY in this table (no recursion),
9312  * we need to mark the inheritors' attributes as locally
9313  * defined rather than inherited.
9314  */
9315  childatt->attinhcount--;
9316  childatt->attislocal = true;
9317 
9318  CatalogTupleUpdate(attr_rel, &tuple->t_self, tuple);
9319 
9320  /* Make update visible */
9322  }
9323 
9324  heap_freetuple(tuple);
9325 
9326  table_close(childrel, NoLock);
9327  }
9328  table_close(attr_rel, RowExclusiveLock);
9329  }
9330 
9331  /* Add object to delete */
9332  object.classId = RelationRelationId;
9333  object.objectId = RelationGetRelid(rel);
9334  object.objectSubId = attnum;
9335  add_exact_object_address(&object, addrs);
9336 
9337  if (!recursing)
9338  {
9339  /* Recursion has ended, drop everything that was collected */
9340  performMultipleDeletions(addrs, behavior, 0);
9341  free_object_addresses(addrs);
9342  }
9343 
9344  return object;
9345 }
9346 
9347 /*
9348  * Prepare to add a primary key on an inheritance parent, by adding NOT NULL
9349  * constraint on its children.
9350  */
9351 static void
9354 {
9355  List *children;
9356  List *newconstrs = NIL;
9357  IndexStmt *indexstmt;
9358 
9359  /* No work if not creating a primary key */
9360  if (!IsA(cmd->def, IndexStmt))
9361  return;
9362  indexstmt = castNode(IndexStmt, cmd->def);
9363  if (!indexstmt->primary)
9364  return;
9365 
9366  /* No work if no legacy inheritance children are present */
9367  if (rel->rd_rel->relkind != RELKIND_RELATION ||
9368  !rel->rd_rel->relhassubclass)
9369  return;
9370 
9371  /*
9372  * Acquire locks all the way down the hierarchy. The recursion to lower
9373  * levels occurs at execution time as necessary, so we don't need to do it
9374  * here, and we don't need the returned list either.
9375  */
9376  (void) find_all_inheritors(RelationGetRelid(rel), lockmode, NULL);
9377 
9378  /*
9379  * Construct the list of constraints that we need to add to each child
9380  * relation.
9381  */
9382  foreach_node(IndexElem, elem, indexstmt->indexParams)
9383  {
9384  Constraint *nnconstr;
9385 
9386  Assert(elem->expr == NULL);
9387 
9388  nnconstr = makeNode(Constraint);
9389  nnconstr->contype = CONSTR_NOTNULL;
9390  nnconstr->conname = NULL; /* XXX use PK name? */
9391  nnconstr->inhcount = 1;
9392  nnconstr->deferrable = false;
9393  nnconstr->initdeferred = false;
9394  nnconstr->location = -1;
9395  nnconstr->keys = list_make1(makeString(elem->name));
9396  nnconstr->skip_validation = false;
9397  nnconstr->initially_valid = true;
9398 
9399  newconstrs = lappend(newconstrs, nnconstr);
9400  }
9401 
9402  /* Finally, add AT subcommands to add each constraint to each child. */
9404  foreach_oid(childrelid, children)
9405  {
9406  Relation childrel = table_open(childrelid, NoLock);
9408  ListCell *lc2;
9409 
9410  newcmd->subtype = AT_AddConstraint;
9411  newcmd->recurse = true;
9412 
9413  foreach(lc2, newconstrs)
9414  {
9415  /* ATPrepCmd copies newcmd, so we can scribble on it here */
9416  newcmd->def = lfirst(lc2);
9417 
9418  ATPrepCmd(wqueue, childrel, newcmd,
9419  true, false, lockmode, context);
9420  }
9421 
9422  table_close(childrel, NoLock);
9423  }
9424 }
9425 
9426 /*
9427  * ALTER TABLE ADD INDEX
9428  *
9429  * There is no such command in the grammar, but parse_utilcmd.c converts
9430  * UNIQUE and PRIMARY KEY constraints into AT_AddIndex subcommands. This lets
9431  * us schedule creation of the index at the appropriate time during ALTER.
9432  *
9433  * Return value is the address of the new index.
9434  */
9435 static ObjectAddress
9437  IndexStmt *stmt, bool is_rebuild, LOCKMODE lockmode)
9438 {
9439  bool check_rights;
9440  bool skip_build;
9441  bool quiet;
9442  ObjectAddress address;
9443 
9444  Assert(IsA(stmt, IndexStmt));
9445  Assert(!stmt->concurrent);
9446 
9447  /* The IndexStmt has already been through transformIndexStmt */
9448  Assert(stmt->transformed);
9449 
9450  /* suppress schema rights check when rebuilding existing index */
9451  check_rights = !is_rebuild;
9452  /* skip index build if phase 3 will do it or we're reusing an old one */
9453  skip_build = tab->rewrite > 0 || RelFileNumberIsValid(stmt->oldNumber);
9454  /* suppress notices when rebuilding existing index */
9455  quiet = is_rebuild;
9456 
9457  address = DefineIndex(RelationGetRelid(rel),
9458  stmt,
9459  InvalidOid, /* no predefined OID */
9460  InvalidOid, /* no parent index */
9461  InvalidOid, /* no parent constraint */
9462  -1, /* total_parts unknown */
9463  true, /* is_alter_table */
9464  check_rights,
9465  false, /* check_not_in_use - we did it already */
9466  skip_build,
9467  quiet);
9468 
9469  /*
9470  * If TryReuseIndex() stashed a relfilenumber for us, we used it for the
9471  * new index instead of building from scratch. Restore associated fields.
9472  * This may store InvalidSubTransactionId in both fields, in which case
9473  * relcache.c will assume it can rebuild the relcache entry. Hence, do
9474  * this after the CCI that made catalog rows visible to any rebuild. The
9475  * DROP of the old edition of this index will have scheduled the storage
9476  * for deletion at commit, so cancel that pending deletion.
9477  */
9478  if (RelFileNumberIsValid(stmt->oldNumber))
9479  {
9480  Relation irel = index_open(address.objectId, NoLock);
9481 
9482  irel->rd_createSubid = stmt->oldCreateSubid;
9483  irel->rd_firstRelfilelocatorSubid = stmt->oldFirstRelfilelocatorSubid;
9484  RelationPreserveStorage(irel->rd_locator, true);
9485  index_close(irel, NoLock);
9486  }
9487 
9488  return address;
9489 }
9490 
9491 /*
9492  * ALTER TABLE ADD STATISTICS
9493  *
9494  * This is no such command in the grammar, but we use this internally to add
9495  * AT_ReAddStatistics subcommands to rebuild extended statistics after a table
9496  * column type change.
9497  */
9498 static ObjectAddress
9500  CreateStatsStmt *stmt, bool is_rebuild, LOCKMODE lockmode)
9501 {
9502  ObjectAddress address;
9503 
9505 
9506  /* The CreateStatsStmt has already been through transformStatsStmt */
9507  Assert(stmt->transformed);
9508 
9509  address = CreateStatistics(stmt);
9510 
9511  return address;
9512 }
9513 
9514 /*
9515  * ALTER TABLE ADD CONSTRAINT USING INDEX
9516  *
9517  * Returns the address of the new constraint.
9518  */
9519 static ObjectAddress
9521  IndexStmt *stmt, LOCKMODE lockmode)
9522 {
9523  Oid index_oid = stmt->indexOid;
9524  Relation indexRel;
9525  char *indexName;
9526  IndexInfo *indexInfo;
9527  char *constraintName;
9528  char constraintType;
9529  ObjectAddress address;
9530  bits16 flags;
9531 
9532  Assert(IsA(stmt, IndexStmt));
9533  Assert(OidIsValid(index_oid));
9534  Assert(stmt->isconstraint);
9535 
9536  /*
9537  * Doing this on partitioned tables is not a simple feature to implement,
9538  * so let's punt for now.
9539  */
9540  if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
9541  ereport(ERROR,
9542  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
9543  errmsg("ALTER TABLE / ADD CONSTRAINT USING INDEX is not supported on partitioned tables")));
9544 
9545  indexRel = index_open(index_oid, AccessShareLock);
9546 
9547  indexName = pstrdup(RelationGetRelationName(indexRel));
9548 
9549  indexInfo = BuildIndexInfo(indexRel);
9550 
9551  /* this should have been checked at parse time */
9552  if (!indexInfo->ii_Unique)
9553  elog(ERROR, "index \"%s\" is not unique", indexName);
9554 
9555  /*
9556  * Determine name to assign to constraint. We require a constraint to
9557  * have the same name as the underlying index; therefore, use the index's
9558  * existing name as the default constraint name, and if the user
9559  * explicitly gives some other name for the constraint, rename the index
9560  * to match.
9561  */
9562  constraintName = stmt->idxname;
9563  if (constraintName == NULL)
9564  constraintName = indexName;
9565  else if (strcmp(constraintName, indexName) != 0)
9566  {
9567  ereport(NOTICE,
9568  (errmsg("ALTER TABLE / ADD CONSTRAINT USING INDEX will rename index \"%s\" to \"%s\"",
9569  indexName, constraintName)));
9570  RenameRelationInternal(index_oid, constraintName, false, true);
9571  }
9572 
9573  /* Extra checks needed if making primary key */
9574  if (stmt->primary)
9575  index_check_primary_key(rel, indexInfo, true, stmt);
9576 
9577  /* Note we currently don't support EXCLUSION constraints here */
9578  if (stmt->primary)
9579  constraintType = CONSTRAINT_PRIMARY;
9580  else
9581  constraintType = CONSTRAINT_UNIQUE;
9582 
9583  /* Create the catalog entries for the constraint */
9586  (stmt->initdeferred ? INDEX_CONSTR_CREATE_INIT_DEFERRED : 0) |
9587  (stmt->deferrable ? INDEX_CONSTR_CREATE_DEFERRABLE : 0) |
9588  (stmt->primary ? INDEX_CONSTR_CREATE_MARK_AS_PRIMARY : 0);
9589 
9590  address = index_constraint_create(rel,
9591  index_oid,
9592  InvalidOid,
9593  indexInfo,
9594  constraintName,
9595  constraintType,
9596  flags,
9598  false); /* is_internal */
9599 
9600  index_close(indexRel, NoLock);
9601 
9602  return address;
9603 }
9604 
9605 /*
9606  * ALTER TABLE ADD CONSTRAINT
9607  *
9608  * Return value is the address of the new constraint; if no constraint was
9609  * added, InvalidObjectAddress is returned.
9610  */
9611 static ObjectAddress
9613  Constraint *newConstraint, bool recurse, bool is_readd,
9614  LOCKMODE lockmode)
9615 {
9617 
9618  Assert(IsA(newConstraint, Constraint));
9619 
9620  /*
9621  * Currently, we only expect to see CONSTR_CHECK, CONSTR_NOTNULL and
9622  * CONSTR_FOREIGN nodes arriving here (see the preprocessing done in
9623  * parse_utilcmd.c).
9624  */
9625  switch (newConstraint->contype)
9626  {
9627  case CONSTR_CHECK:
9628  case CONSTR_NOTNULL:
9629  address =
9630  ATAddCheckNNConstraint(wqueue, tab, rel,
9631  newConstraint, recurse, false, is_readd,
9632  lockmode);
9633  break;
9634 
9635  case CONSTR_FOREIGN:
9636 
9637  /*
9638  * Assign or validate constraint name
9639  */
9640  if (newConstraint->conname)
9641  {
9643  RelationGetRelid(rel),
9644  newConstraint->conname))
9645  ereport(ERROR,
9647  errmsg("constraint \"%s\" for relation \"%s\" already exists",
9648  newConstraint->conname,
9649  RelationGetRelationName(rel))));
9650  }
9651  else
9652  newConstraint->conname =
9655  "fkey",
9656  RelationGetNamespace(rel),
9657  NIL);
9658 
9659  address = ATAddForeignKeyConstraint(wqueue, tab, rel,
9660  newConstraint,
9661  recurse, false,
9662  lockmode);
9663  break;
9664 
9665  default:
9666  elog(ERROR, "unrecognized constraint type: %d",
9667  (int) newConstraint->contype);
9668  }
9669 
9670  return address;
9671 }
9672 
9673 /*
9674  * Generate the column-name portion of the constraint name for a new foreign
9675  * key given the list of column names that reference the referenced
9676  * table. This will be passed to ChooseConstraintName along with the parent
9677  * table name and the "fkey" suffix.
9678  *
9679  * We know that less than NAMEDATALEN characters will actually be used, so we
9680  * can truncate the result once we've generated that many.
9681  *
9682  * XXX see also ChooseExtendedStatisticNameAddition and
9683  * ChooseIndexNameAddition.
9684  */
9685 static char *
9687 {
9688  char buf[NAMEDATALEN * 2];
9689  int buflen = 0;
9690  ListCell *lc;
9691 
9692  buf[0] = '\0';
9693  foreach(lc, colnames)
9694  {
9695  const char *name = strVal(lfirst(lc));
9696 
9697  if (buflen > 0)
9698  buf[buflen++] = '_'; /* insert _ between names */
9699 
9700  /*
9701  * At this point we have buflen <= NAMEDATALEN. name should be less
9702  * than NAMEDATALEN already, but use strlcpy for paranoia.
9703  */
9704  strlcpy(buf + buflen, name, NAMEDATALEN);
9705  buflen += strlen(buf + buflen);
9706  if (buflen >= NAMEDATALEN)
9707  break;
9708  }
9709  return pstrdup(buf);
9710 }
9711 
9712 /*
9713  * Add a check or not-null constraint to a single table and its children.
9714  * Returns the address of the constraint added to the parent relation,
9715  * if one gets added, or InvalidObjectAddress otherwise.
9716  *
9717  * Subroutine for ATExecAddConstraint.
9718  *
9719  * We must recurse to child tables during execution, rather than using
9720  * ALTER TABLE's normal prep-time recursion. The reason is that all the
9721  * constraints *must* be given the same name, else they won't be seen as
9722  * related later. If the user didn't explicitly specify a name, then
9723  * AddRelationNewConstraints would normally assign different names to the
9724  * child constraints. To fix that, we must capture the name assigned at
9725  * the parent table and pass that down.
9726  */
9727 static ObjectAddress
9729  Constraint *constr, bool recurse, bool recursing,
9730  bool is_readd, LOCKMODE lockmode)
9731 {
9732  List *newcons;
9733  ListCell *lcon;
9734  List *children;
9735  ListCell *child;
9737 
9738  /* Guard against stack overflow due to overly deep inheritance tree. */
9740 
9741  /* At top level, permission check was done in ATPrepCmd, else do it */
9742  if (recursing)
9744 
9745  /*
9746  * Call AddRelationNewConstraints to do the work, making sure it works on
9747  * a copy of the Constraint so transformExpr can't modify the original. It
9748  * returns a list of cooked constraints.
9749  *
9750  * If the constraint ends up getting merged with a pre-existing one, it's
9751  * omitted from the returned list, which is what we want: we do not need
9752  * to do any validation work. That can only happen at child tables,
9753  * though, since we disallow merging at the top level.
9754  */
9755  newcons = AddRelationNewConstraints(rel, NIL,
9756  list_make1(copyObject(constr)),
9757  recursing || is_readd, /* allow_merge */
9758  !recursing, /* is_local */
9759  is_readd, /* is_internal */
9760  NULL); /* queryString not available
9761  * here */
9762 
9763  /* we don't expect more than one constraint here */
9764  Assert(list_length(newcons) <= 1);
9765 
9766  /* Add each to-be-validated constraint to Phase 3's queue */
9767  foreach(lcon, newcons)
9768  {
9769  CookedConstraint *ccon = (CookedConstraint *) lfirst(lcon);
9770 
9771  if (!ccon->skip_validation && ccon->contype != CONSTR_NOTNULL)
9772  {
9773  NewConstraint *newcon;
9774 
9775  newcon = (NewConstraint *) palloc0(sizeof(NewConstraint));
9776  newcon->name = ccon->name;
9777  newcon->contype = ccon->contype;
9778  newcon->qual = ccon->expr;
9779 
9780  tab->constraints = lappend(tab->constraints, newcon);
9781  }
9782 
9783  /* Save the actually assigned name if it was defaulted */
9784  if (constr->conname == NULL)
9785  constr->conname = ccon->name;
9786 
9787  /*
9788  * If adding a not-null constraint, set the pg_attribute flag and tell
9789  * phase 3 to verify existing rows, if needed.
9790  */
9791  if (constr->contype == CONSTR_NOTNULL)
9792  set_attnotnull(wqueue, rel, ccon->attnum,
9793  !ccon->is_no_inherit, lockmode);
9794 
9795  ObjectAddressSet(address, ConstraintRelationId, ccon->conoid);
9796  }
9797 
9798  /* At this point we must have a locked-down name to use */
9799  Assert(newcons == NIL || constr->conname != NULL);
9800 
9801  /* Advance command counter in case same table is visited multiple times */
9803 
9804  /*
9805  * If the constraint got merged with an existing constraint, we're done.
9806  * We mustn't recurse to child tables in this case, because they've
9807  * already got the constraint, and visiting them again would lead to an
9808  * incorrect value for coninhcount.
9809  */
9810  if (newcons == NIL)
9811  return address;
9812 
9813  /*
9814  * If adding a NO INHERIT constraint, no need to find our children.
9815  */
9816  if (constr->is_no_inherit)
9817  return address;
9818 
9819  /*
9820  * Propagate to children as appropriate. Unlike most other ALTER
9821  * routines, we have to do this one level of recursion at a time; we can't
9822  * use find_all_inheritors to do it in one pass.
9823  */
9824  children =
9826 
9827  /*
9828  * Check if ONLY was specified with ALTER TABLE. If so, allow the
9829  * constraint creation only if there are no children currently. Error out
9830  * otherwise.
9831  */
9832  if (!recurse && children != NIL)
9833  ereport(ERROR,
9834  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
9835  errmsg("constraint must be added to child tables too")));
9836 
9837  /*
9838  * The constraint must appear as inherited in children, so create a
9839  * modified constraint object to use.
9840  */
9841  constr = copyObject(constr);
9842  constr->inhcount = 1;
9843  foreach(child, children)
9844  {
9845  Oid childrelid = lfirst_oid(child);
9846  Relation childrel;
9847  AlteredTableInfo *childtab;
9848 
9849  /* find_inheritance_children already got lock */
9850  childrel = table_open(childrelid, NoLock);
9851  CheckTableNotInUse(childrel, "ALTER TABLE");
9852 
9853  /* Find or create work queue entry for this table */
9854  childtab = ATGetQueueEntry(wqueue, childrel);
9855 
9856  /*
9857  * Recurse to child. XXX if we didn't create a constraint on the
9858  * parent because it already existed, and we do create one on a child,
9859  * should we return that child's constraint ObjectAddress here?
9860  */
9861  ATAddCheckNNConstraint(wqueue, childtab, childrel,
9862  constr, recurse, true, is_readd, lockmode);
9863 
9864  table_close(childrel, NoLock);
9865  }
9866 
9867  return address;
9868 }
9869 
9870 /*
9871  * Add a foreign-key constraint to a single table; return the new constraint's
9872  * address.
9873  *
9874  * Subroutine for ATExecAddConstraint. Must already hold exclusive
9875  * lock on the rel, and have done appropriate validity checks for it.
9876  * We do permissions checks here, however.
9877  *
9878  * When the referenced or referencing tables (or both) are partitioned,
9879  * multiple pg_constraint rows are required -- one for each partitioned table
9880  * and each partition on each side (fortunately, not one for every combination
9881  * thereof). We also need action triggers on each leaf partition on the
9882  * referenced side, and check triggers on each leaf partition on the
9883  * referencing side.
9884  */
9885 static ObjectAddress
9887  Constraint *fkconstraint,
9888  bool recurse, bool recursing, LOCKMODE lockmode)
9889 {
9890  Relation pkrel;
9891  int16 pkattnum[INDEX_MAX_KEYS] = {0};
9892  int16 fkattnum[INDEX_MAX_KEYS] = {0};
9893  Oid pktypoid[INDEX_MAX_KEYS] = {0};
9894  Oid fktypoid[INDEX_MAX_KEYS] = {0};
9895  Oid opclasses[INDEX_MAX_KEYS] = {0};
9896  Oid pfeqoperators[INDEX_MAX_KEYS] = {0};
9897  Oid ppeqoperators[INDEX_MAX_KEYS] = {0};
9898  Oid ffeqoperators[INDEX_MAX_KEYS] = {0};
9899  int16 fkdelsetcols[INDEX_MAX_KEYS] = {0};
9900  bool with_period;
9901  bool pk_has_without_overlaps;
9902  int i;
9903  int numfks,
9904  numpks,
9905  numfkdelsetcols;
9906  Oid indexOid;
9907  bool old_check_ok;
9908  ObjectAddress address;
9909  ListCell *old_pfeqop_item = list_head(fkconstraint->old_conpfeqop);
9910 
9911  /*
9912  * Grab ShareRowExclusiveLock on the pk table, so that someone doesn't
9913  * delete rows out from under us.
9914  */
9915  if (OidIsValid(fkconstraint->old_pktable_oid))
9916  pkrel = table_open(fkconstraint->old_pktable_oid, ShareRowExclusiveLock);
9917  else
9918  pkrel = table_openrv(fkconstraint->pktable, ShareRowExclusiveLock);
9919 
9920  /*
9921  * Validity checks (permission checks wait till we have the column
9922  * numbers)
9923  */
9924  if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
9925  {
9926  if (!recurse)
9927  ereport(ERROR,
9928  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
9929  errmsg("cannot use ONLY for foreign key on partitioned table \"%s\" referencing relation \"%s\"",
9931  RelationGetRelationName(pkrel))));
9932  if (fkconstraint->skip_validation && !fkconstraint->initially_valid)
9933  ereport(ERROR,
9934  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
9935  errmsg("cannot add NOT VALID foreign key on partitioned table \"%s\" referencing relation \"%s\"",
9937  RelationGetRelationName(pkrel)),
9938  errdetail("This feature is not yet supported on partitioned tables.")));
9939  }
9940 
9941  if (pkrel->rd_rel->relkind != RELKIND_RELATION &&
9942  pkrel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
9943  ereport(ERROR,
9944  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
9945  errmsg("referenced relation \"%s\" is not a table",
9946  RelationGetRelationName(pkrel))));
9947 
9948  if (!allowSystemTableMods && IsSystemRelation(pkrel))
9949  ereport(ERROR,
9950  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
9951  errmsg("permission denied: \"%s\" is a system catalog",
9952  RelationGetRelationName(pkrel))));
9953 
9954  /*
9955  * References from permanent or unlogged tables to temp tables, and from
9956  * permanent tables to unlogged tables, are disallowed because the
9957  * referenced data can vanish out from under us. References from temp
9958  * tables to any other table type are also disallowed, because other
9959  * backends might need to run the RI triggers on the perm table, but they
9960  * can't reliably see tuples in the local buffers of other backends.
9961  */
9962  switch (rel->rd_rel->relpersistence)
9963  {
9964  case RELPERSISTENCE_PERMANENT:
9965  if (!RelationIsPermanent(pkrel))
9966  ereport(ERROR,
9967  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
9968  errmsg("constraints on permanent tables may reference only permanent tables")));
9969  break;
9970  case RELPERSISTENCE_UNLOGGED:
9971  if (!RelationIsPermanent(pkrel)
9972  && pkrel->rd_rel->relpersistence != RELPERSISTENCE_UNLOGGED)
9973  ereport(ERROR,
9974  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
9975  errmsg("constraints on unlogged tables may reference only permanent or unlogged tables")));
9976  break;
9977  case RELPERSISTENCE_TEMP:
9978  if (pkrel->rd_rel->relpersistence != RELPERSISTENCE_TEMP)
9979  ereport(ERROR,
9980  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
9981  errmsg("constraints on temporary tables may reference only temporary tables")));
9982  if (!pkrel->rd_islocaltemp || !rel->rd_islocaltemp)
9983  ereport(ERROR,
9984  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
9985  errmsg("constraints on temporary tables must involve temporary tables of this session")));
9986  break;
9987  }
9988 
9989  /*
9990  * Look up the referencing attributes to make sure they exist, and record
9991  * their attnums and type OIDs.
9992  */
9994  fkconstraint->fk_attrs,
9995  fkattnum, fktypoid);
9996  with_period = fkconstraint->fk_with_period || fkconstraint->pk_with_period;
9997  if (with_period && !fkconstraint->fk_with_period)
9998  ereport(ERROR,
9999  errcode(ERRCODE_INVALID_FOREIGN_KEY),
10000  errmsg("foreign key uses PERIOD on the referenced table but not the referencing table"));
10001 
10002  numfkdelsetcols = transformColumnNameList(RelationGetRelid(rel),
10003  fkconstraint->fk_del_set_cols,
10004  fkdelsetcols, NULL);
10005  validateFkOnDeleteSetColumns(numfks, fkattnum,
10006  numfkdelsetcols, fkdelsetcols,
10007  fkconstraint->fk_del_set_cols);
10008 
10009  /*
10010  * If the attribute list for the referenced table was omitted, lookup the
10011  * definition of the primary key and use it. Otherwise, validate the
10012  * supplied attribute list. In either case, discover the index OID and
10013  * index opclasses, and the attnums and type OIDs of the attributes.
10014  */
10015  if (fkconstraint->pk_attrs == NIL)
10016  {
10017  numpks = transformFkeyGetPrimaryKey(pkrel, &indexOid,
10018  &fkconstraint->pk_attrs,
10019  pkattnum, pktypoid,
10020  opclasses, &pk_has_without_overlaps);
10021 
10022  /* If the primary key uses WITHOUT OVERLAPS, the fk must use PERIOD */
10023  if (pk_has_without_overlaps && !fkconstraint->fk_with_period)
10024  ereport(ERROR,
10025  errcode(ERRCODE_INVALID_FOREIGN_KEY),
10026  errmsg("foreign key uses PERIOD on the referenced table but not the referencing table"));
10027  }
10028  else
10029  {
10030  numpks = transformColumnNameList(RelationGetRelid(pkrel),
10031  fkconstraint->pk_attrs,
10032  pkattnum, pktypoid);
10033 
10034  /* Since we got pk_attrs, one should be a period. */
10035  if (with_period && !fkconstraint->pk_with_period)
10036  ereport(ERROR,
10037  errcode(ERRCODE_INVALID_FOREIGN_KEY),
10038  errmsg("foreign key uses PERIOD on the referencing table but not the referenced table"));
10039 
10040  /* Look for an index matching the column list */
10041  indexOid = transformFkeyCheckAttrs(pkrel, numpks, pkattnum,
10042  with_period, opclasses, &pk_has_without_overlaps);
10043  }
10044 
10045  /*
10046  * If the referenced primary key has WITHOUT OVERLAPS, the foreign key
10047  * must use PERIOD.
10048  */
10049  if (pk_has_without_overlaps && !with_period)
10050  ereport(ERROR,
10051  errcode(ERRCODE_INVALID_FOREIGN_KEY),
10052  errmsg("foreign key must use PERIOD when referencing a primary using WITHOUT OVERLAPS"));
10053 
10054  /*
10055  * Now we can check permissions.
10056  */
10057  checkFkeyPermissions(pkrel, pkattnum, numpks);
10058 
10059  /*
10060  * Check some things for generated columns.
10061  */
10062  for (i = 0; i < numfks; i++)
10063  {
10064  char attgenerated = TupleDescAttr(RelationGetDescr(rel), fkattnum[i] - 1)->attgenerated;
10065 
10066  if (attgenerated)
10067  {
10068  /*
10069  * Check restrictions on UPDATE/DELETE actions, per SQL standard
10070  */
10071  if (fkconstraint->fk_upd_action == FKCONSTR_ACTION_SETNULL ||
10072  fkconstraint->fk_upd_action == FKCONSTR_ACTION_SETDEFAULT ||
10073  fkconstraint->fk_upd_action == FKCONSTR_ACTION_CASCADE)
10074  ereport(ERROR,
10075  (errcode(ERRCODE_SYNTAX_ERROR),
10076  errmsg("invalid %s action for foreign key constraint containing generated column",
10077  "ON UPDATE")));
10078  if (fkconstraint->fk_del_action == FKCONSTR_ACTION_SETNULL ||
10079  fkconstraint->fk_del_action == FKCONSTR_ACTION_SETDEFAULT)
10080  ereport(ERROR,
10081  (errcode(ERRCODE_SYNTAX_ERROR),
10082  errmsg("invalid %s action for foreign key constraint containing generated column",
10083  "ON DELETE")));
10084  }
10085  }
10086 
10087  /*
10088  * Some actions are currently unsupported for foreign keys using PERIOD.
10089  */
10090  if (fkconstraint->fk_with_period)
10091  {
10092  if (fkconstraint->fk_upd_action == FKCONSTR_ACTION_CASCADE ||
10093  fkconstraint->fk_upd_action == FKCONSTR_ACTION_SETNULL ||
10094  fkconstraint->fk_upd_action == FKCONSTR_ACTION_SETDEFAULT)
10095  ereport(ERROR,
10096  errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
10097  errmsg("unsupported %s action for foreign key constraint using PERIOD",
10098  "ON UPDATE"));
10099 
10100  if (fkconstraint->fk_del_action == FKCONSTR_ACTION_CASCADE ||
10101  fkconstraint->fk_del_action == FKCONSTR_ACTION_SETNULL ||
10102  fkconstraint->fk_del_action == FKCONSTR_ACTION_SETDEFAULT)
10103  ereport(ERROR,
10104  errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
10105  errmsg("unsupported %s action for foreign key constraint using PERIOD",
10106  "ON DELETE"));
10107  }
10108 
10109  /*
10110  * Look up the equality operators to use in the constraint.
10111  *
10112  * Note that we have to be careful about the difference between the actual
10113  * PK column type and the opclass' declared input type, which might be
10114  * only binary-compatible with it. The declared opcintype is the right
10115  * thing to probe pg_amop with.
10116  */
10117  if (numfks != numpks)
10118  ereport(ERROR,
10119  (errcode(ERRCODE_INVALID_FOREIGN_KEY),
10120  errmsg("number of referencing and referenced columns for foreign key disagree")));
10121 
10122  /*
10123  * On the strength of a previous constraint, we might avoid scanning
10124  * tables to validate this one. See below.
10125  */
10126  old_check_ok = (fkconstraint->old_conpfeqop != NIL);
10127  Assert(!old_check_ok || numfks == list_length(fkconstraint->old_conpfeqop));
10128 
10129  for (i = 0; i < numpks; i++)
10130  {
10131  Oid pktype = pktypoid[i];
10132  Oid fktype = fktypoid[i];
10133  Oid fktyped;
10134  HeapTuple cla_ht;
10135  Form_pg_opclass cla_tup;
10136  Oid amid;
10137  Oid opfamily;
10138  Oid opcintype;
10139  Oid pfeqop;
10140  Oid ppeqop;
10141  Oid ffeqop;
10142  int16 eqstrategy;
10143  Oid pfeqop_right;
10144 
10145  /* We need several fields out of the pg_opclass entry */
10146  cla_ht = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclasses[i]));
10147  if (!HeapTupleIsValid(cla_ht))
10148  elog(ERROR, "cache lookup failed for opclass %u", opclasses[i]);
10149  cla_tup = (Form_pg_opclass) GETSTRUCT(cla_ht);
10150  amid = cla_tup->opcmethod;
10151  opfamily = cla_tup->opcfamily;
10152  opcintype = cla_tup->opcintype;
10153  ReleaseSysCache(cla_ht);
10154 
10155  if (with_period)
10156  {
10157  StrategyNumber rtstrategy;
10158  bool for_overlaps = with_period && i == numpks - 1;
10159 
10160  /*
10161  * GiST indexes are required to support temporal foreign keys
10162  * because they combine equals and overlaps.
10163  */
10164  if (amid != GIST_AM_OID)
10165  elog(ERROR, "only GiST indexes are supported for temporal foreign keys");
10166 
10167  rtstrategy = for_overlaps ? RTOverlapStrategyNumber : RTEqualStrategyNumber;
10168 
10169  /*
10170  * An opclass can use whatever strategy numbers it wants, so we
10171  * ask the opclass what number it actually uses instead of our RT*
10172  * constants.
10173  */
10174  eqstrategy = GistTranslateStratnum(opclasses[i], rtstrategy);
10175  if (eqstrategy == InvalidStrategy)
10176  {
10177  HeapTuple tuple;
10178 
10179  tuple = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclasses[i]));
10180  if (!HeapTupleIsValid(tuple))
10181  elog(ERROR, "cache lookup failed for operator class %u", opclasses[i]);
10182 
10183  ereport(ERROR,
10184  errcode(ERRCODE_UNDEFINED_OBJECT),
10185  for_overlaps
10186  ? errmsg("could not identify an overlaps operator for foreign key")
10187  : errmsg("could not identify an equality operator for foreign key"),
10188  errdetail("Could not translate strategy number %d for operator class \"%s\" for access method \"%s\".",
10189  rtstrategy, NameStr(((Form_pg_opclass) GETSTRUCT(tuple))->opcname), "gist"));
10190  }
10191  }
10192  else
10193  {
10194  /*
10195  * Check it's a btree; currently this can never fail since no
10196  * other index AMs support unique indexes. If we ever did have
10197  * other types of unique indexes, we'd need a way to determine
10198  * which operator strategy number is equality. (We could use
10199  * something like GistTranslateStratnum.)
10200  */
10201  if (amid != BTREE_AM_OID)
10202  elog(ERROR, "only b-tree indexes are supported for foreign keys");
10203  eqstrategy = BTEqualStrategyNumber;
10204  }
10205 
10206  /*
10207  * There had better be a primary equality operator for the index.
10208  * We'll use it for PK = PK comparisons.
10209  */
10210  ppeqop = get_opfamily_member(opfamily, opcintype, opcintype,
10211  eqstrategy);
10212 
10213  if (!OidIsValid(ppeqop))
10214  elog(ERROR, "missing operator %d(%u,%u) in opfamily %u",
10215  eqstrategy, opcintype, opcintype, opfamily);
10216 
10217  /*
10218  * Are there equality operators that take exactly the FK type? Assume
10219  * we should look through any domain here.
10220  */
10221  fktyped = getBaseType(fktype);
10222 
10223  pfeqop = get_opfamily_member(opfamily, opcintype, fktyped,
10224  eqstrategy);
10225  if (OidIsValid(pfeqop))
10226  {
10227  pfeqop_right = fktyped;
10228  ffeqop = get_opfamily_member(opfamily, fktyped, fktyped,
10229  eqstrategy);
10230  }
10231  else
10232  {
10233  /* keep compiler quiet */
10234  pfeqop_right = InvalidOid;
10235  ffeqop = InvalidOid;
10236  }
10237 
10238  if (!(OidIsValid(pfeqop) && OidIsValid(ffeqop)))
10239  {
10240  /*
10241  * Otherwise, look for an implicit cast from the FK type to the
10242  * opcintype, and if found, use the primary equality operator.
10243  * This is a bit tricky because opcintype might be a polymorphic
10244  * type such as ANYARRAY or ANYENUM; so what we have to test is
10245  * whether the two actual column types can be concurrently cast to
10246  * that type. (Otherwise, we'd fail to reject combinations such
10247  * as int[] and point[].)
10248  */
10249  Oid input_typeids[2];
10250  Oid target_typeids[2];
10251 
10252  input_typeids[0] = pktype;
10253  input_typeids[1] = fktype;
10254  target_typeids[0] = opcintype;
10255  target_typeids[1] = opcintype;
10256  if (can_coerce_type(2, input_typeids, target_typeids,
10258  {
10259  pfeqop = ffeqop = ppeqop;
10260  pfeqop_right = opcintype;
10261  }
10262  }
10263 
10264  if (!(OidIsValid(pfeqop) && OidIsValid(ffeqop)))
10265  ereport(ERROR,
10266  (errcode(ERRCODE_DATATYPE_MISMATCH),
10267  errmsg("foreign key constraint \"%s\" cannot be implemented",
10268  fkconstraint->conname),
10269  errdetail("Key columns \"%s\" and \"%s\" "
10270  "are of incompatible types: %s and %s.",
10271  strVal(list_nth(fkconstraint->fk_attrs, i)),
10272  strVal(list_nth(fkconstraint->pk_attrs, i)),
10273  format_type_be(fktype),
10274  format_type_be(pktype))));
10275 
10276  if (old_check_ok)
10277  {
10278  /*
10279  * When a pfeqop changes, revalidate the constraint. We could
10280  * permit intra-opfamily changes, but that adds subtle complexity
10281  * without any concrete benefit for core types. We need not
10282  * assess ppeqop or ffeqop, which RI_Initial_Check() does not use.
10283  */
10284  old_check_ok = (pfeqop == lfirst_oid(old_pfeqop_item));
10285  old_pfeqop_item = lnext(fkconstraint->old_conpfeqop,
10286  old_pfeqop_item);
10287  }
10288  if (old_check_ok)
10289  {
10290  Oid old_fktype;
10291  Oid new_fktype;
10292  CoercionPathType old_pathtype;
10293  CoercionPathType new_pathtype;
10294  Oid old_castfunc;
10295  Oid new_castfunc;
10297  fkattnum[i] - 1);
10298 
10299  /*
10300  * Identify coercion pathways from each of the old and new FK-side
10301  * column types to the right (foreign) operand type of the pfeqop.
10302  * We may assume that pg_constraint.conkey is not changing.
10303  */
10304  old_fktype = attr->atttypid;
10305  new_fktype = fktype;
10306  old_pathtype = findFkeyCast(pfeqop_right, old_fktype,
10307  &old_castfunc);
10308  new_pathtype = findFkeyCast(pfeqop_right, new_fktype,
10309  &new_castfunc);
10310 
10311  /*
10312  * Upon a change to the cast from the FK column to its pfeqop
10313  * operand, revalidate the constraint. For this evaluation, a
10314  * binary coercion cast is equivalent to no cast at all. While
10315  * type implementors should design implicit casts with an eye
10316  * toward consistency of operations like equality, we cannot
10317  * assume here that they have done so.
10318  *
10319  * A function with a polymorphic argument could change behavior
10320  * arbitrarily in response to get_fn_expr_argtype(). Therefore,
10321  * when the cast destination is polymorphic, we only avoid
10322  * revalidation if the input type has not changed at all. Given
10323  * just the core data types and operator classes, this requirement
10324  * prevents no would-be optimizations.
10325  *
10326  * If the cast converts from a base type to a domain thereon, then
10327  * that domain type must be the opcintype of the unique index.
10328  * Necessarily, the primary key column must then be of the domain
10329  * type. Since the constraint was previously valid, all values on
10330  * the foreign side necessarily exist on the primary side and in
10331  * turn conform to the domain. Consequently, we need not treat
10332  * domains specially here.
10333  *
10334  * Since we require that all collations share the same notion of
10335  * equality (which they do, because texteq reduces to bitwise
10336  * equality), we don't compare collation here.
10337  *
10338  * We need not directly consider the PK type. It's necessarily
10339  * binary coercible to the opcintype of the unique index column,
10340  * and ri_triggers.c will only deal with PK datums in terms of
10341  * that opcintype. Changing the opcintype also changes pfeqop.
10342  */
10343  old_check_ok = (new_pathtype == old_pathtype &&
10344  new_castfunc == old_castfunc &&
10345  (!IsPolymorphicType(pfeqop_right) ||
10346  new_fktype == old_fktype));
10347  }
10348 
10349  pfeqoperators[i] = pfeqop;
10350  ppeqoperators[i] = ppeqop;
10351  ffeqoperators[i] = ffeqop;
10352  }
10353 
10354  /*
10355  * For FKs with PERIOD we need additional operators to check whether the
10356  * referencing row's range is contained by the aggregated ranges of the
10357  * referenced row(s). For rangetypes and multirangetypes this is
10358  * fk.periodatt <@ range_agg(pk.periodatt). Those are the only types we
10359  * support for now. FKs will look these up at "runtime", but we should
10360  * make sure the lookup works here, even if we don't use the values.
10361  */
10362  if (with_period)
10363  {
10364  Oid periodoperoid;
10365  Oid aggedperiodoperoid;
10366 
10367  FindFKPeriodOpers(opclasses[numpks - 1], &periodoperoid, &aggedperiodoperoid);
10368  }
10369 
10370  /*
10371  * Create all the constraint and trigger objects, recursing to partitions
10372  * as necessary. First handle the referenced side.
10373  */
10374  address = addFkRecurseReferenced(wqueue, fkconstraint, rel, pkrel,
10375  indexOid,
10376  InvalidOid, /* no parent constraint */
10377  numfks,
10378  pkattnum,
10379  fkattnum,
10380  pfeqoperators,
10381  ppeqoperators,
10382  ffeqoperators,
10383  numfkdelsetcols,
10384  fkdelsetcols,
10385  old_check_ok,
10387  with_period);
10388 
10389  /* Now handle the referencing side. */
10390  addFkRecurseReferencing(wqueue, fkconstraint, rel, pkrel,
10391  indexOid,
10392  address.objectId,
10393  numfks,
10394  pkattnum,
10395  fkattnum,
10396  pfeqoperators,
10397  ppeqoperators,
10398  ffeqoperators,
10399  numfkdelsetcols,
10400  fkdelsetcols,
10401  old_check_ok,
10402  lockmode,
10404  with_period);
10405 
10406  /*
10407  * Done. Close pk table, but keep lock until we've committed.
10408  */
10409  table_close(pkrel, NoLock);
10410 
10411  return address;
10412 }
10413 
10414 /*
10415  * validateFkOnDeleteSetColumns
10416  * Verifies that columns used in ON DELETE SET NULL/DEFAULT (...)
10417  * column lists are valid.
10418  */
10419 void
10420 validateFkOnDeleteSetColumns(int numfks, const int16 *fkattnums,
10421  int numfksetcols, const int16 *fksetcolsattnums,
10422  List *fksetcols)
10423 {
10424  for (int i = 0; i < numfksetcols; i++)
10425  {
10426  int16 setcol_attnum = fksetcolsattnums[i];
10427  bool seen = false;
10428 
10429  for (int j = 0; j < numfks; j++)
10430  {
10431  if (fkattnums[j] == setcol_attnum)
10432  {
10433  seen = true;
10434  break;
10435  }
10436  }
10437 
10438  if (!seen)
10439  {
10440  char *col = strVal(list_nth(fksetcols, i));
10441 
10442  ereport(ERROR,
10443  (errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
10444  errmsg("column \"%s\" referenced in ON DELETE SET action must be part of foreign key", col)));
10445  }
10446  }
10447 }
10448 
10449 /*
10450  * addFkRecurseReferenced
10451  * subroutine for ATAddForeignKeyConstraint; recurses on the referenced
10452  * side of the constraint
10453  *
10454  * Create pg_constraint rows for the referenced side of the constraint,
10455  * referencing the parent of the referencing side; also create action triggers
10456  * on leaf partitions. If the table is partitioned, recurse to handle each
10457  * partition.
10458  *
10459  * wqueue is the ALTER TABLE work queue; can be NULL when not running as part
10460  * of an ALTER TABLE sequence.
10461  * fkconstraint is the constraint being added.
10462  * rel is the root referencing relation.
10463  * pkrel is the referenced relation; might be a partition, if recursing.
10464  * indexOid is the OID of the index (on pkrel) implementing this constraint.
10465  * parentConstr is the OID of a parent constraint; InvalidOid if this is a
10466  * top-level constraint.
10467  * numfks is the number of columns in the foreign key
10468  * pkattnum is the attnum array of referenced attributes.
10469  * fkattnum is the attnum array of referencing attributes.
10470  * numfkdelsetcols is the number of columns in the ON DELETE SET NULL/DEFAULT
10471  * (...) clause
10472  * fkdelsetcols is the attnum array of the columns in the ON DELETE SET
10473  * NULL/DEFAULT clause
10474  * pf/pp/ffeqoperators are OID array of operators between columns.
10475  * old_check_ok signals that this constraint replaces an existing one that
10476  * was already validated (thus this one doesn't need validation).
10477  * parentDelTrigger and parentUpdTrigger, when being recursively called on
10478  * a partition, are the OIDs of the parent action triggers for DELETE and
10479  * UPDATE respectively.
10480  */
10481 static ObjectAddress
10482 addFkRecurseReferenced(List **wqueue, Constraint *fkconstraint, Relation rel,
10483  Relation pkrel, Oid indexOid, Oid parentConstr,
10484  int numfks,
10485  int16 *pkattnum, int16 *fkattnum, Oid *pfeqoperators,
10486  Oid *ppeqoperators, Oid *ffeqoperators,
10487  int numfkdelsetcols, int16 *fkdelsetcols,
10488  bool old_check_ok,
10489  Oid parentDelTrigger, Oid parentUpdTrigger,
10490  bool with_period)
10491 {
10492  ObjectAddress address;
10493  Oid constrOid;
10494  char *conname;
10495  bool conislocal;
10496  int coninhcount;
10497  bool connoinherit;
10498  Oid deleteTriggerOid,
10499  updateTriggerOid;
10500 
10501  /*
10502  * Verify relkind for each referenced partition. At the top level, this
10503  * is redundant with a previous check, but we need it when recursing.
10504  */
10505  if (pkrel->rd_rel->relkind != RELKIND_RELATION &&
10506  pkrel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
10507  ereport(ERROR,
10508  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
10509  errmsg("referenced relation \"%s\" is not a table",
10510  RelationGetRelationName(pkrel))));
10511 
10512  /*
10513  * Caller supplies us with a constraint name; however, it may be used in
10514  * this partition, so come up with a different one in that case.
10515  */
10517  RelationGetRelid(rel),
10518  fkconstraint->conname))
10521  "fkey",
10522  RelationGetNamespace(rel), NIL);
10523  else
10524  conname = fkconstraint->conname;
10525 
10526  if (OidIsValid(parentConstr))
10527  {
10528  conislocal = false;
10529  coninhcount = 1;
10530  connoinherit = false;
10531  }
10532  else
10533  {
10534  conislocal = true;
10535  coninhcount = 0;
10536 
10537  /*
10538  * always inherit for partitioned tables, never for legacy inheritance
10539  */
10540  connoinherit = rel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE;
10541  }
10542 
10543  /*
10544  * Record the FK constraint in pg_constraint.
10545  */
10546  constrOid = CreateConstraintEntry(conname,
10547  RelationGetNamespace(rel),
10548  CONSTRAINT_FOREIGN,
10549  fkconstraint->deferrable,
10550  fkconstraint->initdeferred,
10551  fkconstraint->initially_valid,
10552  parentConstr,
10553  RelationGetRelid(rel),
10554  fkattnum,
10555  numfks,
10556  numfks,
10557  InvalidOid, /* not a domain constraint */
10558  indexOid,
10559  RelationGetRelid(pkrel),
10560  pkattnum,
10561  pfeqoperators,
10562  ppeqoperators,
10563  ffeqoperators,
10564  numfks,
10565  fkconstraint->fk_upd_action,
10566  fkconstraint->fk_del_action,
10567  fkdelsetcols,
10568  numfkdelsetcols,
10569  fkconstraint->fk_matchtype,
10570  NULL, /* no exclusion constraint */
10571  NULL, /* no check constraint */
10572  NULL,
10573  conislocal, /* islocal */
10574  coninhcount, /* inhcount */
10575  connoinherit, /* conNoInherit */
10576  with_period, /* conPeriod */
10577  false); /* is_internal */
10578 
10579  ObjectAddressSet(address, ConstraintRelationId, constrOid);
10580 
10581  /*
10582  * Mark the child constraint as part of the parent constraint; it must not
10583  * be dropped on its own. (This constraint is deleted when the partition
10584  * is detached, but a special check needs to occur that the partition
10585  * contains no referenced values.)
10586  */
10587  if (OidIsValid(parentConstr))
10588  {
10589  ObjectAddress referenced;
10590 
10591  ObjectAddressSet(referenced, ConstraintRelationId, parentConstr);
10592  recordDependencyOn(&address, &referenced, DEPENDENCY_INTERNAL);
10593  }
10594 
10595  /* make new constraint visible, in case we add more */
10597 
10598  /*
10599  * Create the action triggers that enforce the constraint.
10600  */
10602  fkconstraint,
10603  constrOid, indexOid,
10604  parentDelTrigger, parentUpdTrigger,
10605  &deleteTriggerOid, &updateTriggerOid);
10606 
10607  /*
10608  * If the referenced table is partitioned, recurse on ourselves to handle
10609  * each partition. We need one pg_constraint row created for each
10610  * partition in addition to the pg_constraint row for the parent table.
10611  */
10612  if (pkrel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
10613  {
10614  PartitionDesc pd = RelationGetPartitionDesc(pkrel, true);
10615 
10616  for (int i = 0; i < pd->nparts; i++)
10617  {
10618  Relation partRel;
10619  AttrMap *map;
10620  AttrNumber *mapped_pkattnum;
10621  Oid partIndexId;
10622 
10623  partRel = table_open(pd->oids[i], ShareRowExclusiveLock);
10624 
10625  /*
10626  * Map the attribute numbers in the referenced side of the FK
10627  * definition to match the partition's column layout.
10628  */
10630  RelationGetDescr(pkrel),
10631  false);
10632  if (map)
10633  {
10634  mapped_pkattnum = palloc(sizeof(AttrNumber) * numfks);
10635  for (int j = 0; j < numfks; j++)
10636  mapped_pkattnum[j] = map->attnums[pkattnum[j] - 1];
10637  }
10638  else
10639  mapped_pkattnum = pkattnum;
10640 
10641  /* do the deed */
10642  partIndexId = index_get_partition(partRel, indexOid);
10643  if (!OidIsValid(partIndexId))
10644  elog(ERROR, "index for %u not found in partition %s",
10645  indexOid, RelationGetRelationName(partRel));
10646  addFkRecurseReferenced(wqueue, fkconstraint, rel, partRel,
10647  partIndexId, constrOid, numfks,
10648  mapped_pkattnum, fkattnum,
10649  pfeqoperators, ppeqoperators, ffeqoperators,
10650  numfkdelsetcols, fkdelsetcols,
10651  old_check_ok,
10652  deleteTriggerOid, updateTriggerOid,
10653  with_period);
10654 
10655  /* Done -- clean up (but keep the lock) */
10656  table_close(partRel, NoLock);
10657  if (map)
10658  {
10659  pfree(mapped_pkattnum);
10660  free_attrmap(map);
10661  }
10662  }
10663  }
10664 
10665  return address;
10666 }
10667 
10668 /*
10669  * addFkRecurseReferencing
10670  * subroutine for ATAddForeignKeyConstraint and CloneFkReferencing
10671  *
10672  * If the referencing relation is a plain relation, create the necessary check
10673  * triggers that implement the constraint, and set up for Phase 3 constraint
10674  * verification. If the referencing relation is a partitioned table, then
10675  * we create a pg_constraint row for it and recurse on this routine for each
10676  * partition.
10677  *
10678  * We assume that the referenced relation is locked against concurrent
10679  * deletions. If it's a partitioned relation, every partition must be so
10680  * locked.
10681  *
10682  * wqueue is the ALTER TABLE work queue; can be NULL when not running as part
10683  * of an ALTER TABLE sequence.
10684  * fkconstraint is the constraint being added.
10685  * rel is the referencing relation; might be a partition, if recursing.
10686  * pkrel is the root referenced relation.
10687  * indexOid is the OID of the index (on pkrel) implementing this constraint.
10688  * parentConstr is the OID of the parent constraint (there is always one).
10689  * numfks is the number of columns in the foreign key
10690  * pkattnum is the attnum array of referenced attributes.
10691  * fkattnum is the attnum array of referencing attributes.
10692  * pf/pp/ffeqoperators are OID array of operators between columns.
10693  * numfkdelsetcols is the number of columns in the ON DELETE SET NULL/DEFAULT
10694  * (...) clause
10695  * fkdelsetcols is the attnum array of the columns in the ON DELETE SET
10696  * NULL/DEFAULT clause
10697  * old_check_ok signals that this constraint replaces an existing one that
10698  * was already validated (thus this one doesn't need validation).
10699  * lockmode is the lockmode to acquire on partitions when recursing.
10700  * parentInsTrigger and parentUpdTrigger, when being recursively called on
10701  * a partition, are the OIDs of the parent check triggers for INSERT and
10702  * UPDATE respectively.
10703  */
10704 static void
10705 addFkRecurseReferencing(List **wqueue, Constraint *fkconstraint, Relation rel,
10706  Relation pkrel, Oid indexOid, Oid parentConstr,
10707  int numfks, int16 *pkattnum, int16 *fkattnum,
10708  Oid *pfeqoperators, Oid *ppeqoperators, Oid *ffeqoperators,
10709  int numfkdelsetcols, int16 *fkdelsetcols,
10710  bool old_check_ok, LOCKMODE lockmode,
10711  Oid parentInsTrigger, Oid parentUpdTrigger,
10712  bool with_period)
10713 {
10714  Oid insertTriggerOid,
10715  updateTriggerOid;
10716 
10717  Assert(OidIsValid(parentConstr));
10718 
10719  if (rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
10720  ereport(ERROR,
10721  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
10722  errmsg("foreign key constraints are not supported on foreign tables")));
10723 
10724  /*
10725  * Add the check triggers to it and, if necessary, schedule it to be
10726  * checked in Phase 3.
10727  *
10728  * If the relation is partitioned, drill down to do it to its partitions.
10729  */
10731  RelationGetRelid(pkrel),
10732  fkconstraint,
10733  parentConstr,
10734  indexOid,
10735  parentInsTrigger, parentUpdTrigger,
10736  &insertTriggerOid, &updateTriggerOid);
10737 
10738  if (rel->rd_rel->relkind == RELKIND_RELATION)
10739  {
10740  /*
10741  * Tell Phase 3 to check that the constraint is satisfied by existing
10742  * rows. We can skip this during table creation, when requested
10743  * explicitly by specifying NOT VALID in an ADD FOREIGN KEY command,
10744  * and when we're recreating a constraint following a SET DATA TYPE
10745  * operation that did not impugn its validity.
10746  */
10747  if (wqueue && !old_check_ok && !fkconstraint->skip_validation)
10748  {
10749  NewConstraint *newcon;
10750  AlteredTableInfo *tab;
10751 
10752  tab = ATGetQueueEntry(wqueue, rel);
10753 
10754  newcon = (NewConstraint *) palloc0(sizeof(NewConstraint));
10755  newcon->name = get_constraint_name(parentConstr);
10756  newcon->contype = CONSTR_FOREIGN;
10757  newcon->refrelid = RelationGetRelid(pkrel);
10758  newcon->refindid = indexOid;
10759  newcon->conid = parentConstr;
10760  newcon->conwithperiod = fkconstraint->fk_with_period;
10761  newcon->qual = (Node *) fkconstraint;
10762 
10763  tab->constraints = lappend(tab->constraints, newcon);
10764  }
10765  }
10766  else if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
10767  {
10768  PartitionDesc pd = RelationGetPartitionDesc(rel, true);
10769  Relation trigrel;
10770 
10771  /*
10772  * Triggers of the foreign keys will be manipulated a bunch of times
10773  * in the loop below. To avoid repeatedly opening/closing the trigger
10774  * catalog relation, we open it here and pass it to the subroutines
10775  * called below.
10776  */
10777  trigrel = table_open(TriggerRelationId, RowExclusiveLock);
10778 
10779  /*
10780  * Recurse to take appropriate action on each partition; either we
10781  * find an existing constraint to reparent to ours, or we create a new
10782  * one.
10783  */
10784  for (int i = 0; i < pd->nparts; i++)
10785  {
10786  Oid partitionId = pd->oids[i];
10787  Relation partition = table_open(partitionId, lockmode);
10788  List *partFKs;
10789  AttrMap *attmap;
10790  AttrNumber mapped_fkattnum[INDEX_MAX_KEYS];
10791  bool attached;
10792  char *conname;
10793  Oid constrOid;
10794  ObjectAddress address,
10795  referenced;
10796  ListCell *cell;
10797 
10798  CheckTableNotInUse(partition, "ALTER TABLE");
10799 
10800  attmap = build_attrmap_by_name(RelationGetDescr(partition),
10801  RelationGetDescr(rel),
10802  false);
10803  for (int j = 0; j < numfks; j++)
10804  mapped_fkattnum[j] = attmap->attnums[fkattnum[j] - 1];
10805 
10806  /* Check whether an existing constraint can be repurposed */
10807  partFKs = copyObject(RelationGetFKeyList(partition));
10808  attached = false;
10809  foreach(cell, partFKs)
10810  {
10811  ForeignKeyCacheInfo *fk;
10812 
10813  fk = lfirst_node(ForeignKeyCacheInfo, cell);
10815  partitionId,
10816  parentConstr,
10817  numfks,
10818  mapped_fkattnum,
10819  pkattnum,
10820  pfeqoperators,
10821  insertTriggerOid,
10822  updateTriggerOid,
10823  trigrel))
10824  {
10825  attached = true;
10826  break;
10827  }
10828  }
10829  if (attached)
10830  {
10831  table_close(partition, NoLock);
10832  continue;
10833  }
10834 
10835  /*
10836  * No luck finding a good constraint to reuse; create our own.
10837  */
10839  RelationGetRelid(partition),
10840  fkconstraint->conname))
10841  conname = ChooseConstraintName(RelationGetRelationName(partition),
10843  "fkey",
10844  RelationGetNamespace(partition), NIL);
10845  else
10846  conname = fkconstraint->conname;
10847  constrOid =
10848  CreateConstraintEntry(conname,
10849  RelationGetNamespace(partition),
10850  CONSTRAINT_FOREIGN,
10851  fkconstraint->deferrable,
10852  fkconstraint->initdeferred,
10853  fkconstraint->initially_valid,
10854  parentConstr,
10855  partitionId,
10856  mapped_fkattnum,
10857  numfks,
10858  numfks,
10859  InvalidOid,
10860  indexOid,
10861  RelationGetRelid(pkrel),
10862  pkattnum,
10863  pfeqoperators,
10864  ppeqoperators,
10865  ffeqoperators,
10866  numfks,
10867  fkconstraint->fk_upd_action,
10868  fkconstraint->fk_del_action,
10869  fkdelsetcols,
10870  numfkdelsetcols,
10871  fkconstraint->fk_matchtype,
10872  NULL,
10873  NULL,
10874  NULL,
10875  false,
10876  1,
10877  false,
10878  with_period, /* conPeriod */
10879  false);
10880 
10881  /*
10882  * Give this constraint partition-type dependencies on the parent
10883  * constraint as well as the table.
10884  */
10885  ObjectAddressSet(address, ConstraintRelationId, constrOid);
10886  ObjectAddressSet(referenced, ConstraintRelationId, parentConstr);
10887  recordDependencyOn(&address, &referenced, DEPENDENCY_PARTITION_PRI);
10888  ObjectAddressSet(referenced, RelationRelationId, partitionId);
10889  recordDependencyOn(&address, &referenced, DEPENDENCY_PARTITION_SEC);
10890 
10891  /* Make all this visible before recursing */
10893 
10894  /* call ourselves to finalize the creation and we're done */
10895  addFkRecurseReferencing(wqueue, fkconstraint, partition, pkrel,
10896  indexOid,
10897  constrOid,
10898  numfks,
10899  pkattnum,
10900  mapped_fkattnum,
10901  pfeqoperators,
10902  ppeqoperators,
10903  ffeqoperators,
10904  numfkdelsetcols,
10905  fkdelsetcols,
10906  old_check_ok,
10907  lockmode,
10908  insertTriggerOid,
10909  updateTriggerOid,
10910  with_period);
10911 
10912  table_close(partition, NoLock);
10913  }
10914 
10915  table_close(trigrel, RowExclusiveLock);
10916  }
10917 }
10918 
10919 /*
10920  * CloneForeignKeyConstraints
10921  * Clone foreign keys from a partitioned table to a newly acquired
10922  * partition.
10923  *
10924  * partitionRel is a partition of parentRel, so we can be certain that it has
10925  * the same columns with the same datatypes. The columns may be in different
10926  * order, though.
10927  *
10928  * wqueue must be passed to set up phase 3 constraint checking, unless the
10929  * referencing-side partition is known to be empty (such as in CREATE TABLE /
10930  * PARTITION OF).
10931  */
10932 static void
10934  Relation partitionRel)
10935 {
10936  /* This only works for declarative partitioning */
10937  Assert(parentRel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
10938 
10939  /*
10940  * Clone constraints for which the parent is on the referenced side.
10941  */
10942  CloneFkReferenced(parentRel, partitionRel);
10943 
10944  /*
10945  * Now clone constraints where the parent is on the referencing side.
10946  */
10947  CloneFkReferencing(wqueue, parentRel, partitionRel);
10948 }
10949 
10950 /*
10951  * CloneFkReferenced
10952  * Subroutine for CloneForeignKeyConstraints
10953  *
10954  * Find all the FKs that have the parent relation on the referenced side;
10955  * clone those constraints to the given partition. This is to be called
10956  * when the partition is being created or attached.
10957  *
10958  * This ignores self-referencing FKs; those are handled by CloneFkReferencing.
10959  *
10960  * This recurses to partitions, if the relation being attached is partitioned.
10961  * Recursion is done by calling addFkRecurseReferenced.
10962  */
10963 static void
10964 CloneFkReferenced(Relation parentRel, Relation partitionRel)
10965 {
10966  Relation pg_constraint;
10967  AttrMap *attmap;
10968  ListCell *cell;
10969  SysScanDesc scan;
10970  ScanKeyData key[2];
10971  HeapTuple tuple;
10972  List *clone = NIL;
10973  Relation trigrel;
10974 
10975  /*
10976  * Search for any constraints where this partition's parent is in the
10977  * referenced side. However, we must not clone any constraint whose
10978  * parent constraint is also going to be cloned, to avoid duplicates. So
10979  * do it in two steps: first construct the list of constraints to clone,
10980  * then go over that list cloning those whose parents are not in the list.
10981  * (We must not rely on the parent being seen first, since the catalog
10982  * scan could return children first.)
10983  */
10984  pg_constraint = table_open(ConstraintRelationId, RowShareLock);
10985  ScanKeyInit(&key[0],
10986  Anum_pg_constraint_confrelid, BTEqualStrategyNumber,
10987  F_OIDEQ, ObjectIdGetDatum(RelationGetRelid(parentRel)));
10988  ScanKeyInit(&key[1],
10989  Anum_pg_constraint_contype, BTEqualStrategyNumber,
10990  F_CHAREQ, CharGetDatum(CONSTRAINT_FOREIGN));
10991  /* This is a seqscan, as we don't have a usable index ... */
10992  scan = systable_beginscan(pg_constraint, InvalidOid, true,
10993  NULL, 2, key);
10994  while ((tuple = systable_getnext(scan)) != NULL)
10995  {
10996  Form_pg_constraint constrForm = (Form_pg_constraint) GETSTRUCT(tuple);
10997 
10998  clone = lappend_oid(clone, constrForm->oid);
10999  }
11000  systable_endscan(scan);
11001  table_close(pg_constraint, RowShareLock);
11002 
11003  /*
11004  * Triggers of the foreign keys will be manipulated a bunch of times in
11005  * the loop below. To avoid repeatedly opening/closing the trigger
11006  * catalog relation, we open it here and pass it to the subroutines called
11007  * below.
11008  */
11009  trigrel = table_open(TriggerRelationId, RowExclusiveLock);
11010 
11011  attmap = build_attrmap_by_name(RelationGetDescr(partitionRel),
11012  RelationGetDescr(parentRel),
11013  false);
11014  foreach(cell, clone)
11015  {
11016  Oid constrOid = lfirst_oid(cell);
11017  Form_pg_constraint constrForm;
11018  Relation fkRel;
11019  Oid indexOid;
11020  Oid partIndexId;
11021  int numfks;
11022  AttrNumber conkey[INDEX_MAX_KEYS];
11023  AttrNumber mapped_confkey[INDEX_MAX_KEYS];
11024  AttrNumber confkey[INDEX_MAX_KEYS];
11025  Oid conpfeqop[INDEX_MAX_KEYS];
11026  Oid conppeqop[INDEX_MAX_KEYS];
11027  Oid conffeqop[INDEX_MAX_KEYS];
11028  int numfkdelsetcols;
11029  AttrNumber confdelsetcols[INDEX_MAX_KEYS];
11030  Constraint *fkconstraint;
11031  Oid deleteTriggerOid,
11032  updateTriggerOid;
11033 
11034  tuple = SearchSysCache1(CONSTROID, ObjectIdGetDatum(constrOid));
11035  if (!HeapTupleIsValid(tuple))
11036  elog(ERROR, "cache lookup failed for constraint %u", constrOid);
11037  constrForm = (Form_pg_constraint) GETSTRUCT(tuple);
11038 
11039  /*
11040  * As explained above: don't try to clone a constraint for which we're
11041  * going to clone the parent.
11042  */
11043  if (list_member_oid(clone, constrForm->conparentid))
11044  {
11045  ReleaseSysCache(tuple);
11046  continue;
11047  }
11048 
11049  /*
11050  * Don't clone self-referencing foreign keys, which can be in the
11051  * partitioned table or in the partition-to-be.
11052  */
11053  if (constrForm->conrelid == RelationGetRelid(parentRel) ||
11054  constrForm->conrelid == RelationGetRelid(partitionRel))
11055  {
11056  ReleaseSysCache(tuple);
11057  continue;
11058  }
11059 
11060  /*
11061  * Because we're only expanding the key space at the referenced side,
11062  * we don't need to prevent any operation in the referencing table, so
11063  * AccessShareLock suffices (assumes that dropping the constraint
11064  * acquires AEL).
11065  */
11066  fkRel = table_open(constrForm->conrelid, AccessShareLock);
11067 
11068  indexOid = constrForm->conindid;
11070  &numfks,
11071  conkey,
11072  confkey,
11073  conpfeqop,
11074  conppeqop,
11075  conffeqop,
11076  &numfkdelsetcols,
11077  confdelsetcols);
11078 
11079  for (int i = 0; i < numfks; i++)
11080  mapped_confkey[i] = attmap->attnums[confkey[i] - 1];
11081 
11082  fkconstraint = makeNode(Constraint);
11083  fkconstraint->contype = CONSTRAINT_FOREIGN;
11084  fkconstraint->conname = NameStr(constrForm->conname);
11085  fkconstraint->deferrable = constrForm->condeferrable;
11086  fkconstraint->initdeferred = constrForm->condeferred;
11087  fkconstraint->location = -1;
11088  fkconstraint->pktable = NULL;
11089  /* ->fk_attrs determined below */
11090  fkconstraint->pk_attrs = NIL;
11091  fkconstraint->fk_matchtype = constrForm->confmatchtype;
11092  fkconstraint->fk_upd_action = constrForm->confupdtype;
11093  fkconstraint->fk_del_action = constrForm->confdeltype;
11094  fkconstraint->fk_del_set_cols = NIL;
11095  fkconstraint->old_conpfeqop = NIL;
11096  fkconstraint->old_pktable_oid = InvalidOid;
11097  fkconstraint->skip_validation = false;
11098  fkconstraint->initially_valid = true;
11099 
11100  /* set up colnames that are used to generate the constraint name */
11101  for (int i = 0; i < numfks; i++)
11102  {
11103  Form_pg_attribute att;
11104 
11105  att = TupleDescAttr(RelationGetDescr(fkRel),
11106  conkey[i] - 1);
11107  fkconstraint->fk_attrs = lappend(fkconstraint->fk_attrs,
11108  makeString(NameStr(att->attname)));
11109  }
11110 
11111  /*
11112  * Add the new foreign key constraint pointing to the new partition.
11113  * Because this new partition appears in the referenced side of the
11114  * constraint, we don't need to set up for Phase 3 check.
11115  */
11116  partIndexId = index_get_partition(partitionRel, indexOid);
11117  if (!OidIsValid(partIndexId))
11118  elog(ERROR, "index for %u not found in partition %s",
11119  indexOid, RelationGetRelationName(partitionRel));
11120 
11121  /*
11122  * Get the "action" triggers belonging to the constraint to pass as
11123  * parent OIDs for similar triggers that will be created on the
11124  * partition in addFkRecurseReferenced().
11125  */
11126  GetForeignKeyActionTriggers(trigrel, constrOid,
11127  constrForm->confrelid, constrForm->conrelid,
11128  &deleteTriggerOid, &updateTriggerOid);
11129 
11131  fkconstraint,
11132  fkRel,
11133  partitionRel,
11134  partIndexId,
11135  constrOid,
11136  numfks,
11137  mapped_confkey,
11138  conkey,
11139  conpfeqop,
11140  conppeqop,
11141  conffeqop,
11142  numfkdelsetcols,
11143  confdelsetcols,
11144  true,
11145  deleteTriggerOid,
11146  updateTriggerOid,
11147  constrForm->conperiod);
11148 
11149  table_close(fkRel, NoLock);
11150  ReleaseSysCache(tuple);
11151  }
11152 
11153  table_close(trigrel, RowExclusiveLock);
11154 }
11155 
11156 /*
11157  * CloneFkReferencing
11158  * Subroutine for CloneForeignKeyConstraints
11159  *
11160  * For each FK constraint of the parent relation in the given list, find an
11161  * equivalent constraint in its partition relation that can be reparented;
11162  * if one cannot be found, create a new constraint in the partition as its
11163  * child.
11164  *
11165  * If wqueue is given, it is used to set up phase-3 verification for each
11166  * cloned constraint; if omitted, we assume that such verification is not
11167  * needed (example: the partition is being created anew).
11168  */
11169 static void
11170 CloneFkReferencing(List **wqueue, Relation parentRel, Relation partRel)
11171 {
11172  AttrMap *attmap;
11173  List *partFKs;
11174  List *clone = NIL;
11175  ListCell *cell;
11176  Relation trigrel;
11177 
11178  /* obtain a list of constraints that we need to clone */
11179  foreach(cell, RelationGetFKeyList(parentRel))
11180  {
11181  ForeignKeyCacheInfo *fk = lfirst(cell);
11182 
11183  clone = lappend_oid(clone, fk->conoid);
11184  }
11185 
11186  /*
11187  * Silently do nothing if there's nothing to do. In particular, this
11188  * avoids throwing a spurious error for foreign tables.
11189  */
11190  if (clone == NIL)
11191  return;
11192 
11193  if (partRel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
11194  ereport(ERROR,
11195  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
11196  errmsg("foreign key constraints are not supported on foreign tables")));
11197 
11198  /*
11199  * Triggers of the foreign keys will be manipulated a bunch of times in
11200  * the loop below. To avoid repeatedly opening/closing the trigger
11201  * catalog relation, we open it here and pass it to the subroutines called
11202  * below.
11203  */
11204  trigrel = table_open(TriggerRelationId, RowExclusiveLock);
11205 
11206  /*
11207  * The constraint key may differ, if the columns in the partition are
11208  * different. This map is used to convert them.
11209  */
11210  attmap = build_attrmap_by_name(RelationGetDescr(partRel),
11211  RelationGetDescr(parentRel),
11212  false);
11213 
11214  partFKs = copyObject(RelationGetFKeyList(partRel));
11215 
11216  foreach(cell, clone)
11217  {
11218  Oid parentConstrOid = lfirst_oid(cell);
11219  Form_pg_constraint constrForm;
11220  Relation pkrel;
11221  HeapTuple tuple;
11222  int numfks;
11223  AttrNumber conkey[INDEX_MAX_KEYS];
11224  AttrNumber mapped_conkey[INDEX_MAX_KEYS];
11225  AttrNumber confkey[INDEX_MAX_KEYS];
11226  Oid conpfeqop[INDEX_MAX_KEYS];
11227  Oid conppeqop[INDEX_MAX_KEYS];
11228  Oid conffeqop[INDEX_MAX_KEYS];
11229  int numfkdelsetcols;
11230  AttrNumber confdelsetcols[INDEX_MAX_KEYS];
11231  Constraint *fkconstraint;
11232  bool attached;
11233  Oid indexOid;
11234  Oid constrOid;
11235  ObjectAddress address,
11236  referenced;
11237  ListCell *lc;
11238  Oid insertTriggerOid,
11239  updateTriggerOid;
11240  bool with_period;
11241 
11242  tuple = SearchSysCache1(CONSTROID, ObjectIdGetDatum(parentConstrOid));
11243  if (!HeapTupleIsValid(tuple))
11244  elog(ERROR, "cache lookup failed for constraint %u",
11245  parentConstrOid);
11246  constrForm = (Form_pg_constraint) GETSTRUCT(tuple);
11247 
11248  /* Don't clone constraints whose parents are being cloned */
11249  if (list_member_oid(clone, constrForm->conparentid))
11250  {
11251  ReleaseSysCache(tuple);
11252  continue;
11253  }
11254 
11255  /*
11256  * Need to prevent concurrent deletions. If pkrel is a partitioned
11257  * relation, that means to lock all partitions.
11258  */
11259  pkrel = table_open(constrForm->confrelid, ShareRowExclusiveLock);
11260  if (pkrel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
11261  (void) find_all_inheritors(RelationGetRelid(pkrel),
11262  ShareRowExclusiveLock, NULL);
11263 
11264  DeconstructFkConstraintRow(tuple, &numfks, conkey, confkey,
11265  conpfeqop, conppeqop, conffeqop,
11266  &numfkdelsetcols, confdelsetcols);
11267  for (int i = 0; i < numfks; i++)
11268  mapped_conkey[i] = attmap->attnums[conkey[i] - 1];
11269 
11270  /*
11271  * Get the "check" triggers belonging to the constraint to pass as
11272  * parent OIDs for similar triggers that will be created on the
11273  * partition in addFkRecurseReferencing(). They are also passed to
11274  * tryAttachPartitionForeignKey() below to simply assign as parents to
11275  * the partition's existing "check" triggers, that is, if the
11276  * corresponding constraints is deemed attachable to the parent
11277  * constraint.
11278  */
11279  GetForeignKeyCheckTriggers(trigrel, constrForm->oid,
11280  constrForm->confrelid, constrForm->conrelid,
11281  &insertTriggerOid, &updateTriggerOid);
11282 
11283  /*
11284  * Before creating a new constraint, see whether any existing FKs are
11285  * fit for the purpose. If one is, attach the parent constraint to
11286  * it, and don't clone anything. This way we avoid the expensive
11287  * verification step and don't end up with a duplicate FK, and we
11288  * don't need to recurse to partitions for this constraint.
11289  */
11290  attached = false;
11291  foreach(lc, partFKs)
11292  {
11294 
11296  RelationGetRelid(partRel),
11297  parentConstrOid,
11298  numfks,
11299  mapped_conkey,
11300  confkey,
11301  conpfeqop,
11302  insertTriggerOid,
11303  updateTriggerOid,
11304  trigrel))
11305  {
11306  attached = true;
11307  table_close(pkrel, NoLock);
11308  break;
11309  }
11310  }
11311  if (attached)
11312  {
11313  ReleaseSysCache(tuple);
11314  continue;
11315  }
11316 
11317  /* No dice. Set up to create our own constraint */
11318  fkconstraint = makeNode(Constraint);
11319  fkconstraint->contype = CONSTRAINT_FOREIGN;
11320  /* ->conname determined below */
11321  fkconstraint->deferrable = constrForm->condeferrable;
11322  fkconstraint->initdeferred = constrForm->condeferred;
11323  fkconstraint->location = -1;
11324  fkconstraint->pktable = NULL;
11325  /* ->fk_attrs determined below */
11326  fkconstraint->pk_attrs = NIL;
11327  fkconstraint->fk_matchtype = constrForm->confmatchtype;
11328  fkconstraint->fk_upd_action = constrForm->confupdtype;
11329  fkconstraint->fk_del_action = constrForm->confdeltype;
11330  fkconstraint->fk_del_set_cols = NIL;
11331  fkconstraint->old_conpfeqop = NIL;
11332  fkconstraint->old_pktable_oid = InvalidOid;
11333  fkconstraint->skip_validation = false;
11334  fkconstraint->initially_valid = true;
11335  for (int i = 0; i < numfks; i++)
11336  {
11337  Form_pg_attribute att;
11338 
11339  att = TupleDescAttr(RelationGetDescr(partRel),
11340  mapped_conkey[i] - 1);
11341  fkconstraint->fk_attrs = lappend(fkconstraint->fk_attrs,
11342  makeString(NameStr(att->attname)));
11343  }
11345  RelationGetRelid(partRel),
11346  NameStr(constrForm->conname)))
11347  fkconstraint->conname =
11350  "fkey",
11351  RelationGetNamespace(partRel), NIL);
11352  else
11353  fkconstraint->conname = pstrdup(NameStr(constrForm->conname));
11354 
11355  indexOid = constrForm->conindid;
11356  with_period = constrForm->conperiod;
11357  constrOid =
11358  CreateConstraintEntry(fkconstraint->conname,
11359  constrForm->connamespace,
11360  CONSTRAINT_FOREIGN,
11361  fkconstraint->deferrable,
11362  fkconstraint->initdeferred,
11363  constrForm->convalidated,
11364  parentConstrOid,
11365  RelationGetRelid(partRel),
11366  mapped_conkey,
11367  numfks,
11368  numfks,
11369  InvalidOid, /* not a domain constraint */
11370  indexOid,
11371  constrForm->confrelid, /* same foreign rel */
11372  confkey,
11373  conpfeqop,
11374  conppeqop,
11375  conffeqop,
11376  numfks,
11377  fkconstraint->fk_upd_action,
11378  fkconstraint->fk_del_action,
11379  confdelsetcols,
11380  numfkdelsetcols,
11381  fkconstraint->fk_matchtype,
11382  NULL,
11383  NULL,
11384  NULL,
11385  false, /* islocal */
11386  1, /* inhcount */
11387  false, /* conNoInherit */
11388  with_period, /* conPeriod */
11389  true);
11390 
11391  /* Set up partition dependencies for the new constraint */
11392  ObjectAddressSet(address, ConstraintRelationId, constrOid);
11393  ObjectAddressSet(referenced, ConstraintRelationId, parentConstrOid);
11394  recordDependencyOn(&address, &referenced, DEPENDENCY_PARTITION_PRI);
11395  ObjectAddressSet(referenced, RelationRelationId,
11396  RelationGetRelid(partRel));
11397  recordDependencyOn(&address, &referenced, DEPENDENCY_PARTITION_SEC);
11398 
11399  /* Done with the cloned constraint's tuple */
11400  ReleaseSysCache(tuple);
11401 
11402  /* Make all this visible before recursing */
11404 
11405  addFkRecurseReferencing(wqueue,
11406  fkconstraint,
11407  partRel,
11408  pkrel,
11409  indexOid,
11410  constrOid,
11411  numfks,
11412  confkey,
11413  mapped_conkey,
11414  conpfeqop,
11415  conppeqop,
11416  conffeqop,
11417  numfkdelsetcols,
11418  confdelsetcols,
11419  false, /* no old check exists */
11421  insertTriggerOid,
11422  updateTriggerOid,
11423  with_period);
11424  table_close(pkrel, NoLock);
11425  }
11426 
11427  table_close(trigrel, RowExclusiveLock);
11428 }
11429 
11430 /*
11431  * When the parent of a partition receives [the referencing side of] a foreign
11432  * key, we must propagate that foreign key to the partition. However, the
11433  * partition might already have an equivalent foreign key; this routine
11434  * compares the given ForeignKeyCacheInfo (in the partition) to the FK defined
11435  * by the other parameters. If they are equivalent, create the link between
11436  * the two constraints and return true.
11437  *
11438  * If the given FK does not match the one defined by rest of the params,
11439  * return false.
11440  */
11441 static bool
11443  Oid partRelid,
11444  Oid parentConstrOid,
11445  int numfks,
11446  AttrNumber *mapped_conkey,
11447  AttrNumber *confkey,
11448  Oid *conpfeqop,
11449  Oid parentInsTrigger,
11450  Oid parentUpdTrigger,
11451  Relation trigrel)
11452 {
11453  HeapTuple parentConstrTup;
11454  Form_pg_constraint parentConstr;
11455  HeapTuple partcontup;
11456  Form_pg_constraint partConstr;
11457  ScanKeyData key;
11458  SysScanDesc scan;
11459  HeapTuple trigtup;
11460  Oid insertTriggerOid,
11461  updateTriggerOid;
11462 
11463  parentConstrTup = SearchSysCache1(CONSTROID,
11464  ObjectIdGetDatum(parentConstrOid));
11465  if (!HeapTupleIsValid(parentConstrTup))
11466  elog(ERROR, "cache lookup failed for constraint %u", parentConstrOid);
11467  parentConstr = (Form_pg_constraint) GETSTRUCT(parentConstrTup);
11468 
11469  /*
11470  * Do some quick & easy initial checks. If any of these fail, we cannot
11471  * use this constraint.
11472  */
11473  if (fk->confrelid != parentConstr->confrelid || fk->nkeys != numfks)
11474  {
11475  ReleaseSysCache(parentConstrTup);
11476  return false;
11477  }
11478  for (int i = 0; i < numfks; i++)
11479  {
11480  if (fk->conkey[i] != mapped_conkey[i] ||
11481  fk->confkey[i] != confkey[i] ||
11482  fk->conpfeqop[i] != conpfeqop[i])
11483  {
11484  ReleaseSysCache(parentConstrTup);
11485  return false;
11486  }
11487  }
11488 
11489  /*
11490  * Looks good so far; do some more extensive checks. Presumably the check
11491  * for 'convalidated' could be dropped, since we don't really care about
11492  * that, but let's be careful for now.
11493  */
11494  partcontup = SearchSysCache1(CONSTROID,
11495  ObjectIdGetDatum(fk->conoid));
11496  if (!HeapTupleIsValid(partcontup))
11497  elog(ERROR, "cache lookup failed for constraint %u", fk->conoid);
11498  partConstr = (Form_pg_constraint) GETSTRUCT(partcontup);
11499  if (OidIsValid(partConstr->conparentid) ||
11500  !partConstr->convalidated ||
11501  partConstr->condeferrable != parentConstr->condeferrable ||
11502  partConstr->condeferred != parentConstr->condeferred ||
11503  partConstr->confupdtype != parentConstr->confupdtype ||
11504  partConstr->confdeltype != parentConstr->confdeltype ||
11505  partConstr->confmatchtype != parentConstr->confmatchtype)
11506  {
11507  ReleaseSysCache(parentConstrTup);
11508  ReleaseSysCache(partcontup);
11509  return false;
11510  }
11511 
11512  ReleaseSysCache(partcontup);
11513  ReleaseSysCache(parentConstrTup);
11514 
11515  /*
11516  * Looks good! Attach this constraint. The action triggers in the new
11517  * partition become redundant -- the parent table already has equivalent
11518  * ones, and those will be able to reach the partition. Remove the ones
11519  * in the partition. We identify them because they have our constraint
11520  * OID, as well as being on the referenced rel.
11521  */
11522  ScanKeyInit(&key,
11523  Anum_pg_trigger_tgconstraint,
11524  BTEqualStrategyNumber, F_OIDEQ,
11525  ObjectIdGetDatum(fk->conoid));
11526  scan = systable_beginscan(trigrel, TriggerConstraintIndexId, true,
11527  NULL, 1, &key);
11528  while ((trigtup = systable_getnext(scan)) != NULL)
11529  {
11530  Form_pg_trigger trgform = (Form_pg_trigger) GETSTRUCT(trigtup);
11531  ObjectAddress trigger;
11532 
11533  if (trgform->tgconstrrelid != fk->conrelid)
11534  continue;
11535  if (trgform->tgrelid != fk->confrelid)
11536  continue;
11537 
11538  /*
11539  * The constraint is originally set up to contain this trigger as an
11540  * implementation object, so there's a dependency record that links
11541  * the two; however, since the trigger is no longer needed, we remove
11542  * the dependency link in order to be able to drop the trigger while
11543  * keeping the constraint intact.
11544  */
11545  deleteDependencyRecordsFor(TriggerRelationId,
11546  trgform->oid,
11547  false);
11548  /* make dependency deletion visible to performDeletion */
11550  ObjectAddressSet(trigger, TriggerRelationId,
11551  trgform->oid);
11552  performDeletion(&trigger, DROP_RESTRICT, 0);
11553  /* make trigger drop visible, in case the loop iterates */
11555  }
11556 
11557  systable_endscan(scan);
11558 
11559  ConstraintSetParentConstraint(fk->conoid, parentConstrOid, partRelid);
11560 
11561  /*
11562  * Like the constraint, attach partition's "check" triggers to the
11563  * corresponding parent triggers.
11564  */
11566  fk->conoid, fk->confrelid, fk->conrelid,
11567  &insertTriggerOid, &updateTriggerOid);
11568  Assert(OidIsValid(insertTriggerOid) && OidIsValid(parentInsTrigger));
11569  TriggerSetParentTrigger(trigrel, insertTriggerOid, parentInsTrigger,
11570  partRelid);
11571  Assert(OidIsValid(updateTriggerOid) && OidIsValid(parentUpdTrigger));
11572  TriggerSetParentTrigger(trigrel, updateTriggerOid, parentUpdTrigger,
11573  partRelid);
11574 
11576  return true;
11577 }
11578 
11579 /*
11580  * GetForeignKeyActionTriggers
11581  * Returns delete and update "action" triggers of the given relation
11582  * belonging to the given constraint
11583  */
11584 static void
11586  Oid conoid, Oid confrelid, Oid conrelid,
11587  Oid *deleteTriggerOid,
11588  Oid *updateTriggerOid)
11589 {
11590  ScanKeyData key;
11591  SysScanDesc scan;
11592  HeapTuple trigtup;
11593 
11594  *deleteTriggerOid = *updateTriggerOid = InvalidOid;
11595  ScanKeyInit(&key,
11596  Anum_pg_trigger_tgconstraint,
11597  BTEqualStrategyNumber, F_OIDEQ,
11598  ObjectIdGetDatum(conoid));
11599 
11600  scan = systable_beginscan(trigrel, TriggerConstraintIndexId, true,
11601  NULL, 1, &key);
11602  while ((trigtup = systable_getnext(scan)) != NULL)
11603  {
11604  Form_pg_trigger trgform = (Form_pg_trigger) GETSTRUCT(trigtup);
11605 
11606  if (trgform->tgconstrrelid != conrelid)
11607  continue;
11608  if (trgform->tgrelid != confrelid)
11609  continue;
11610  /* Only ever look at "action" triggers on the PK side. */
11611  if (RI_FKey_trigger_type(trgform->tgfoid) != RI_TRIGGER_PK)
11612  continue;
11613  if (TRIGGER_FOR_DELETE(trgform->tgtype))
11614  {
11615  Assert(*deleteTriggerOid == InvalidOid);
11616  *deleteTriggerOid = trgform->oid;
11617  }
11618  else if (TRIGGER_FOR_UPDATE(trgform->tgtype))
11619  {
11620  Assert(*updateTriggerOid == InvalidOid);
11621  *updateTriggerOid = trgform->oid;
11622  }
11623 #ifndef USE_ASSERT_CHECKING
11624  /* In an assert-enabled build, continue looking to find duplicates */
11625  if (OidIsValid(*deleteTriggerOid) && OidIsValid(*updateTriggerOid))
11626  break;
11627 #endif
11628  }
11629 
11630  if (!OidIsValid(*deleteTriggerOid))
11631  elog(ERROR, "could not find ON DELETE action trigger of foreign key constraint %u",
11632  conoid);
11633  if (!OidIsValid(*updateTriggerOid))
11634  elog(ERROR, "could not find ON UPDATE action trigger of foreign key constraint %u",
11635  conoid);
11636 
11637  systable_endscan(scan);
11638 }
11639 
11640 /*
11641  * GetForeignKeyCheckTriggers
11642  * Returns insert and update "check" triggers of the given relation
11643  * belonging to the given constraint
11644  */
11645 static void
11647  Oid conoid, Oid confrelid, Oid conrelid,
11648  Oid *insertTriggerOid,
11649  Oid *updateTriggerOid)
11650 {
11651  ScanKeyData key;
11652  SysScanDesc scan;
11653  HeapTuple trigtup;
11654 
11655  *insertTriggerOid = *updateTriggerOid = InvalidOid;
11656  ScanKeyInit(&key,
11657  Anum_pg_trigger_tgconstraint,
11658  BTEqualStrategyNumber, F_OIDEQ,
11659  ObjectIdGetDatum(conoid));
11660 
11661  scan = systable_beginscan(trigrel, TriggerConstraintIndexId, true,
11662  NULL, 1, &key);
11663  while ((trigtup = systable_getnext(scan)) != NULL)
11664  {
11665  Form_pg_trigger trgform = (Form_pg_trigger) GETSTRUCT(trigtup);
11666 
11667  if (trgform->tgconstrrelid != confrelid)
11668  continue;
11669  if (trgform->tgrelid != conrelid)
11670  continue;
11671  /* Only ever look at "check" triggers on the FK side. */
11672  if (RI_FKey_trigger_type(trgform->tgfoid) != RI_TRIGGER_FK)
11673  continue;
11674  if (TRIGGER_FOR_INSERT(trgform->tgtype))
11675  {
11676  Assert(*insertTriggerOid == InvalidOid);
11677  *insertTriggerOid = trgform->oid;
11678  }
11679  else if (TRIGGER_FOR_UPDATE(trgform->tgtype))
11680  {
11681  Assert(*updateTriggerOid == InvalidOid);
11682  *updateTriggerOid = trgform->oid;
11683  }
11684 #ifndef USE_ASSERT_CHECKING
11685  /* In an assert-enabled build, continue looking to find duplicates. */
11686  if (OidIsValid(*insertTriggerOid) && OidIsValid(*updateTriggerOid))
11687  break;
11688 #endif
11689  }
11690 
11691  if (!OidIsValid(*insertTriggerOid))
11692  elog(ERROR, "could not find ON INSERT check triggers of foreign key constraint %u",
11693  conoid);
11694  if (!OidIsValid(*updateTriggerOid))
11695  elog(ERROR, "could not find ON UPDATE check triggers of foreign key constraint %u",
11696  conoid);
11697 
11698  systable_endscan(scan);
11699 }
11700 
11701 /*
11702  * ALTER TABLE ALTER CONSTRAINT
11703  *
11704  * Update the attributes of a constraint.
11705  *
11706  * Currently only works for Foreign Key constraints.
11707  *
11708  * If the constraint is modified, returns its address; otherwise, return
11709  * InvalidObjectAddress.
11710  */
11711 static ObjectAddress
11713  bool recursing, LOCKMODE lockmode)
11714 {
11715  Constraint *cmdcon;
11716  Relation conrel;
11717  Relation tgrel;
11718  SysScanDesc scan;
11719  ScanKeyData skey[3];
11720  HeapTuple contuple;
11721  Form_pg_constraint currcon;
11722  ObjectAddress address;
11723  List *otherrelids = NIL;
11724  ListCell *lc;
11725 
11726  cmdcon = castNode(Constraint, cmd->def);
11727 
11728  conrel = table_open(ConstraintRelationId, RowExclusiveLock);
11729  tgrel = table_open(TriggerRelationId, RowExclusiveLock);
11730 
11731  /*
11732  * Find and check the target constraint
11733  */
11734  ScanKeyInit(&skey[0],
11735  Anum_pg_constraint_conrelid,
11736  BTEqualStrategyNumber, F_OIDEQ,
11738  ScanKeyInit(&skey[1],
11739  Anum_pg_constraint_contypid,
11740  BTEqualStrategyNumber, F_OIDEQ,
11742  ScanKeyInit(&skey[2],
11743  Anum_pg_constraint_conname,
11744  BTEqualStrategyNumber, F_NAMEEQ,
11745  CStringGetDatum(cmdcon->conname));
11746  scan = systable_beginscan(conrel, ConstraintRelidTypidNameIndexId,
11747  true, NULL, 3, skey);
11748 
11749  /* There can be at most one matching row */
11750  if (!HeapTupleIsValid(contuple = systable_getnext(scan)))
11751  ereport(ERROR,
11752  (errcode(ERRCODE_UNDEFINED_OBJECT),
11753  errmsg("constraint \"%s\" of relation \"%s\" does not exist",
11754  cmdcon->conname, RelationGetRelationName(rel))));
11755 
11756  currcon = (Form_pg_constraint) GETSTRUCT(contuple);
11757  if (currcon->contype != CONSTRAINT_FOREIGN)
11758  ereport(ERROR,
11759  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
11760  errmsg("constraint \"%s\" of relation \"%s\" is not a foreign key constraint",
11761  cmdcon->conname, RelationGetRelationName(rel))));
11762 
11763  /*
11764  * If it's not the topmost constraint, raise an error.
11765  *
11766  * Altering a non-topmost constraint leaves some triggers untouched, since
11767  * they are not directly connected to this constraint; also, pg_dump would
11768  * ignore the deferrability status of the individual constraint, since it
11769  * only dumps topmost constraints. Avoid these problems by refusing this
11770  * operation and telling the user to alter the parent constraint instead.
11771  */
11772  if (OidIsValid(currcon->conparentid))
11773  {
11774  HeapTuple tp;
11775  Oid parent = currcon->conparentid;
11776  char *ancestorname = NULL;
11777  char *ancestortable = NULL;
11778 
11779  /* Loop to find the topmost constraint */
11780  while (HeapTupleIsValid(tp = SearchSysCache1(CONSTROID, ObjectIdGetDatum(parent))))
11781  {
11783 
11784  /* If no parent, this is the constraint we want */
11785  if (!OidIsValid(contup->conparentid))
11786  {
11787  ancestorname = pstrdup(NameStr(contup->conname));
11788  ancestortable = get_rel_name(contup->conrelid);
11789  ReleaseSysCache(tp);
11790  break;
11791  }
11792 
11793  parent = contup->conparentid;
11794  ReleaseSysCache(tp);
11795  }
11796 
11797  ereport(ERROR,
11798  (errmsg("cannot alter constraint \"%s\" on relation \"%s\"",
11799  cmdcon->conname, RelationGetRelationName(rel)),
11800  ancestorname && ancestortable ?
11801  errdetail("Constraint \"%s\" is derived from constraint \"%s\" of relation \"%s\".",
11802  cmdcon->conname, ancestorname, ancestortable) : 0,
11803  errhint("You may alter the constraint it derives from instead.")));
11804  }
11805 
11806  /*
11807  * Do the actual catalog work. We can skip changing if already in the
11808  * desired state, but not if a partitioned table: partitions need to be
11809  * processed regardless, in case they had the constraint locally changed.
11810  */
11811  address = InvalidObjectAddress;
11812  if (currcon->condeferrable != cmdcon->deferrable ||
11813  currcon->condeferred != cmdcon->initdeferred ||
11814  rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
11815  {
11816  if (ATExecAlterConstrRecurse(cmdcon, conrel, tgrel, rel, contuple,
11817  &otherrelids, lockmode))
11818  ObjectAddressSet(address, ConstraintRelationId, currcon->oid);
11819  }
11820 
11821  /*
11822  * ATExecAlterConstrRecurse already invalidated relcache for the relations
11823  * having the constraint itself; here we also invalidate for relations
11824  * that have any triggers that are part of the constraint.
11825  */
11826  foreach(lc, otherrelids)
11828 
11829  systable_endscan(scan);
11830 
11831  table_close(tgrel, RowExclusiveLock);
11832  table_close(conrel, RowExclusiveLock);
11833 
11834  return address;
11835 }
11836 
11837 /*
11838  * Recursive subroutine of ATExecAlterConstraint. Returns true if the
11839  * constraint is altered.
11840  *
11841  * *otherrelids is appended OIDs of relations containing affected triggers.
11842  *
11843  * Note that we must recurse even when the values are correct, in case
11844  * indirect descendants have had their constraints altered locally.
11845  * (This could be avoided if we forbade altering constraints in partitions
11846  * but existing releases don't do that.)
11847  */
11848 static bool
11850  Relation rel, HeapTuple contuple, List **otherrelids,
11851  LOCKMODE lockmode)
11852 {
11853  Form_pg_constraint currcon;
11854  Oid conoid;
11855  Oid refrelid;
11856  bool changed = false;
11857 
11858  /* since this function recurses, it could be driven to stack overflow */
11860 
11861  currcon = (Form_pg_constraint) GETSTRUCT(contuple);
11862  conoid = currcon->oid;
11863  refrelid = currcon->confrelid;
11864 
11865  /*
11866  * Update pg_constraint with the flags from cmdcon.
11867  *
11868  * If called to modify a constraint that's already in the desired state,
11869  * silently do nothing.
11870  */
11871  if (currcon->condeferrable != cmdcon->deferrable ||
11872  currcon->condeferred != cmdcon->initdeferred)
11873  {
11874  HeapTuple copyTuple;
11875  Form_pg_constraint copy_con;
11876  HeapTuple tgtuple;
11877  ScanKeyData tgkey;
11878  SysScanDesc tgscan;
11879 
11880  copyTuple = heap_copytuple(contuple);
11881  copy_con = (Form_pg_constraint) GETSTRUCT(copyTuple);
11882  copy_con->condeferrable = cmdcon->deferrable;
11883  copy_con->condeferred = cmdcon->initdeferred;
11884  CatalogTupleUpdate(conrel, &copyTuple->t_self, copyTuple);
11885 
11886  InvokeObjectPostAlterHook(ConstraintRelationId,
11887  conoid, 0);
11888 
11889  heap_freetuple(copyTuple);
11890  changed = true;
11891 
11892  /* Make new constraint flags visible to others */
11894 
11895  /*
11896  * Now we need to update the multiple entries in pg_trigger that
11897  * implement the constraint.
11898  */
11899  ScanKeyInit(&tgkey,
11900  Anum_pg_trigger_tgconstraint,
11901  BTEqualStrategyNumber, F_OIDEQ,
11902  ObjectIdGetDatum(conoid));
11903  tgscan = systable_beginscan(tgrel, TriggerConstraintIndexId, true,
11904  NULL, 1, &tgkey);
11905  while (HeapTupleIsValid(tgtuple = systable_getnext(tgscan)))
11906  {
11907  Form_pg_trigger tgform = (Form_pg_trigger) GETSTRUCT(tgtuple);
11908  Form_pg_trigger copy_tg;
11909  HeapTuple tgCopyTuple;
11910 
11911  /*
11912  * Remember OIDs of other relation(s) involved in FK constraint.
11913  * (Note: it's likely that we could skip forcing a relcache inval
11914  * for other rels that don't have a trigger whose properties
11915  * change, but let's be conservative.)
11916  */
11917  if (tgform->tgrelid != RelationGetRelid(rel))
11918  *otherrelids = list_append_unique_oid(*otherrelids,
11919  tgform->tgrelid);
11920 
11921  /*
11922  * Update deferrability of RI_FKey_noaction_del,
11923  * RI_FKey_noaction_upd, RI_FKey_check_ins and RI_FKey_check_upd
11924  * triggers, but not others; see createForeignKeyActionTriggers
11925  * and CreateFKCheckTrigger.
11926  */
11927  if (tgform->tgfoid != F_RI_FKEY_NOACTION_DEL &&
11928  tgform->tgfoid != F_RI_FKEY_NOACTION_UPD &&
11929  tgform->tgfoid != F_RI_FKEY_CHECK_INS &&
11930  tgform->tgfoid != F_RI_FKEY_CHECK_UPD)
11931  continue;
11932 
11933  tgCopyTuple = heap_copytuple(tgtuple);
11934  copy_tg = (Form_pg_trigger) GETSTRUCT(tgCopyTuple);
11935 
11936  copy_tg->tgdeferrable = cmdcon->deferrable;
11937  copy_tg->tginitdeferred = cmdcon->initdeferred;
11938  CatalogTupleUpdate(tgrel, &tgCopyTuple->t_self, tgCopyTuple);
11939 
11940  InvokeObjectPostAlterHook(TriggerRelationId, tgform->oid, 0);
11941 
11942  heap_freetuple(tgCopyTuple);
11943  }
11944 
11945  systable_endscan(tgscan);
11946  }
11947 
11948  /*
11949  * If the table at either end of the constraint is partitioned, we need to
11950  * recurse and handle every constraint that is a child of this one.
11951  *
11952  * (This assumes that the recurse flag is forcibly set for partitioned
11953  * tables, and not set for legacy inheritance, though we don't check for
11954  * that here.)
11955  */
11956  if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE ||
11957  get_rel_relkind(refrelid) == RELKIND_PARTITIONED_TABLE)
11958  {
11959  ScanKeyData pkey;
11960  SysScanDesc pscan;
11961  HeapTuple childtup;
11962 
11963  ScanKeyInit(&pkey,
11964  Anum_pg_constraint_conparentid,
11965  BTEqualStrategyNumber, F_OIDEQ,
11966  ObjectIdGetDatum(conoid));
11967 
11968  pscan = systable_beginscan(conrel, ConstraintParentIndexId,
11969  true, NULL, 1, &pkey);
11970 
11971  while (HeapTupleIsValid(childtup = systable_getnext(pscan)))
11972  {
11973  Form_pg_constraint childcon = (Form_pg_constraint) GETSTRUCT(childtup);
11974  Relation childrel;
11975 
11976  childrel = table_open(childcon->conrelid, lockmode);
11977  ATExecAlterConstrRecurse(cmdcon, conrel, tgrel, childrel, childtup,
11978  otherrelids, lockmode);
11979  table_close(childrel, NoLock);
11980  }
11981 
11982  systable_endscan(pscan);
11983  }
11984 
11985  return changed;
11986 }
11987 
11988 /*
11989  * ALTER TABLE VALIDATE CONSTRAINT
11990  *
11991  * XXX The reason we handle recursion here rather than at Phase 1 is because
11992  * there's no good way to skip recursing when handling foreign keys: there is
11993  * no need to lock children in that case, yet we wouldn't be able to avoid
11994  * doing so at that level.
11995  *
11996  * Return value is the address of the validated constraint. If the constraint
11997  * was already validated, InvalidObjectAddress is returned.
11998  */
11999 static ObjectAddress
12000 ATExecValidateConstraint(List **wqueue, Relation rel, char *constrName,
12001  bool recurse, bool recursing, LOCKMODE lockmode)
12002 {
12003  Relation conrel;
12004  SysScanDesc scan;
12005  ScanKeyData skey[3];
12006  HeapTuple tuple;
12007  Form_pg_constraint con;
12008  ObjectAddress address;
12009 
12010  conrel = table_open(ConstraintRelationId, RowExclusiveLock);
12011 
12012  /*
12013  * Find and check the target constraint
12014  */
12015  ScanKeyInit(&skey[0],
12016  Anum_pg_constraint_conrelid,
12017  BTEqualStrategyNumber, F_OIDEQ,
12019  ScanKeyInit(&skey[1],
12020  Anum_pg_constraint_contypid,
12021  BTEqualStrategyNumber, F_OIDEQ,
12023  ScanKeyInit(&skey[2],
12024  Anum_pg_constraint_conname,
12025  BTEqualStrategyNumber, F_NAMEEQ,
12026  CStringGetDatum(constrName));
12027  scan = systable_beginscan(conrel, ConstraintRelidTypidNameIndexId,
12028  true, NULL, 3, skey);
12029 
12030  /* There can be at most one matching row */
12031  if (!HeapTupleIsValid(tuple = systable_getnext(scan)))
12032  ereport(ERROR,
12033  (errcode(ERRCODE_UNDEFINED_OBJECT),
12034  errmsg("constraint \"%s\" of relation \"%s\" does not exist",
12035  constrName, RelationGetRelationName(rel))));
12036 
12037  con = (Form_pg_constraint) GETSTRUCT(tuple);
12038  if (con->contype != CONSTRAINT_FOREIGN &&
12039  con->contype != CONSTRAINT_CHECK)
12040  ereport(ERROR,
12041  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
12042  errmsg("constraint \"%s\" of relation \"%s\" is not a foreign key or check constraint",
12043  constrName, RelationGetRelationName(rel))));
12044 
12045  if (!con->convalidated)
12046  {
12047  AlteredTableInfo *tab;
12048  HeapTuple copyTuple;
12049  Form_pg_constraint copy_con;
12050 
12051  if (con->contype == CONSTRAINT_FOREIGN)
12052  {
12053  NewConstraint *newcon;
12054  Constraint *fkconstraint;
12055 
12056  /* Queue validation for phase 3 */
12057  fkconstraint = makeNode(Constraint);
12058  /* for now this is all we need */
12059  fkconstraint->conname = constrName;
12060 
12061  newcon = (NewConstraint *) palloc0(sizeof(NewConstraint));
12062  newcon->name = constrName;
12063  newcon->contype = CONSTR_FOREIGN;
12064  newcon->refrelid = con->confrelid;
12065  newcon->refindid = con->conindid;
12066  newcon->conid = con->oid;
12067  newcon->qual = (Node *) fkconstraint;
12068 
12069  /* Find or create work queue entry for this table */
12070  tab = ATGetQueueEntry(wqueue, rel);
12071  tab->constraints = lappend(tab->constraints, newcon);
12072 
12073  /*
12074  * We disallow creating invalid foreign keys to or from
12075  * partitioned tables, so ignoring the recursion bit is okay.
12076  */
12077  }
12078  else if (con->contype == CONSTRAINT_CHECK)
12079  {
12080  List *children = NIL;
12081  ListCell *child;
12082  NewConstraint *newcon;
12083  Datum val;
12084  char *conbin;
12085 
12086  /*
12087  * If we're recursing, the parent has already done this, so skip
12088  * it. Also, if the constraint is a NO INHERIT constraint, we
12089  * shouldn't try to look for it in the children.
12090  */
12091  if (!recursing && !con->connoinherit)
12092  children = find_all_inheritors(RelationGetRelid(rel),
12093  lockmode, NULL);
12094 
12095  /*
12096  * For CHECK constraints, we must ensure that we only mark the
12097  * constraint as validated on the parent if it's already validated
12098  * on the children.
12099  *
12100  * We recurse before validating on the parent, to reduce risk of
12101  * deadlocks.
12102  */
12103  foreach(child, children)
12104  {
12105  Oid childoid = lfirst_oid(child);
12106  Relation childrel;
12107 
12108  if (childoid == RelationGetRelid(rel))
12109  continue;
12110 
12111  /*
12112  * If we are told not to recurse, there had better not be any
12113  * child tables, because we can't mark the constraint on the
12114  * parent valid unless it is valid for all child tables.
12115  */
12116  if (!recurse)
12117  ereport(ERROR,
12118  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
12119  errmsg("constraint must be validated on child tables too")));
12120 
12121  /* find_all_inheritors already got lock */
12122  childrel = table_open(childoid, NoLock);
12123 
12124  ATExecValidateConstraint(wqueue, childrel, constrName, false,
12125  true, lockmode);
12126  table_close(childrel, NoLock);
12127  }
12128 
12129  /* Queue validation for phase 3 */
12130  newcon = (NewConstraint *) palloc0(sizeof(NewConstraint));
12131  newcon->name = constrName;
12132  newcon->contype = CONSTR_CHECK;
12133  newcon->refrelid = InvalidOid;
12134  newcon->refindid = InvalidOid;
12135  newcon->conid = con->oid;
12136 
12137  val = SysCacheGetAttrNotNull(CONSTROID, tuple,
12138  Anum_pg_constraint_conbin);
12139  conbin = TextDatumGetCString(val);
12140  newcon->qual = (Node *) stringToNode(conbin);
12141 
12142  /* Find or create work queue entry for this table */
12143  tab = ATGetQueueEntry(wqueue, rel);
12144  tab->constraints = lappend(tab->constraints, newcon);
12145 
12146  /*
12147  * Invalidate relcache so that others see the new validated
12148  * constraint.
12149  */
12151  }
12152 
12153  /*
12154  * Now update the catalog, while we have the door open.
12155  */
12156  copyTuple = heap_copytuple(tuple);
12157  copy_con = (Form_pg_constraint) GETSTRUCT(copyTuple);
12158  copy_con->convalidated = true;
12159  CatalogTupleUpdate(conrel, &copyTuple->t_self, copyTuple);
12160 
12161  InvokeObjectPostAlterHook(ConstraintRelationId, con->oid, 0);
12162 
12163  heap_freetuple(copyTuple);
12164 
12165  ObjectAddressSet(address, ConstraintRelationId, con->oid);
12166  }
12167  else
12168  address = InvalidObjectAddress; /* already validated */
12169 
12170  systable_endscan(scan);
12171 
12172  table_close(conrel, RowExclusiveLock);
12173 
12174  return address;
12175 }
12176 
12177 
12178 /*
12179  * transformColumnNameList - transform list of column names
12180  *
12181  * Lookup each name and return its attnum and, optionally, type OID
12182  *
12183  * Note: the name of this function suggests that it's general-purpose,
12184  * but actually it's only used to look up names appearing in foreign-key
12185  * clauses. The error messages would need work to use it in other cases,
12186  * and perhaps the validity checks as well.
12187  */
12188 static int
12190  int16 *attnums, Oid *atttypids)
12191 {
12192  ListCell *l;
12193  int attnum;
12194 
12195  attnum = 0;
12196  foreach(l, colList)
12197  {
12198  char *attname = strVal(lfirst(l));
12199  HeapTuple atttuple;
12200  Form_pg_attribute attform;
12201 
12202  atttuple = SearchSysCacheAttName(relId, attname);
12203  if (!HeapTupleIsValid(atttuple))
12204  ereport(ERROR,
12205  (errcode(ERRCODE_UNDEFINED_COLUMN),
12206  errmsg("column \"%s\" referenced in foreign key constraint does not exist",
12207  attname)));
12208  attform = (Form_pg_attribute) GETSTRUCT(atttuple);
12209  if (attform->attnum < 0)
12210  ereport(ERROR,
12211  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
12212  errmsg("system columns cannot be used in foreign keys")));
12213  if (attnum >= INDEX_MAX_KEYS)
12214  ereport(ERROR,
12215  (errcode(ERRCODE_TOO_MANY_COLUMNS),
12216  errmsg("cannot have more than %d keys in a foreign key",
12217  INDEX_MAX_KEYS)));
12218  attnums[attnum] = attform->attnum;
12219  if (atttypids != NULL)
12220  atttypids[attnum] = attform->atttypid;
12221  ReleaseSysCache(atttuple);
12222  attnum++;
12223  }
12224 
12225  return attnum;
12226 }
12227 
12228 /*
12229  * transformFkeyGetPrimaryKey -
12230  *
12231  * Look up the names, attnums, and types of the primary key attributes
12232  * for the pkrel. Also return the index OID and index opclasses of the
12233  * index supporting the primary key. Also return whether the index has
12234  * WITHOUT OVERLAPS.
12235  *
12236  * All parameters except pkrel are output parameters. Also, the function
12237  * return value is the number of attributes in the primary key.
12238  *
12239  * Used when the column list in the REFERENCES specification is omitted.
12240  */
12241 static int
12243  List **attnamelist,
12244  int16 *attnums, Oid *atttypids,
12245  Oid *opclasses, bool *pk_has_without_overlaps)
12246 {
12247  List *indexoidlist;
12248  ListCell *indexoidscan;
12249  HeapTuple indexTuple = NULL;
12250  Form_pg_index indexStruct = NULL;
12251  Datum indclassDatum;
12252  oidvector *indclass;
12253  int i;
12254 
12255  /*
12256  * Get the list of index OIDs for the table from the relcache, and look up
12257  * each one in the pg_index syscache until we find one marked primary key
12258  * (hopefully there isn't more than one such). Insist it's valid, too.
12259  */
12260  *indexOid = InvalidOid;
12261 
12262  indexoidlist = RelationGetIndexList(pkrel);
12263 
12264  foreach(indexoidscan, indexoidlist)
12265  {
12266  Oid indexoid = lfirst_oid(indexoidscan);
12267 
12268  indexTuple = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(indexoid));
12269  if (!HeapTupleIsValid(indexTuple))
12270  elog(ERROR, "cache lookup failed for index %u", indexoid);
12271  indexStruct = (Form_pg_index) GETSTRUCT(indexTuple);
12272  if (indexStruct->indisprimary && indexStruct->indisvalid)
12273  {
12274  /*
12275  * Refuse to use a deferrable primary key. This is per SQL spec,
12276  * and there would be a lot of interesting semantic problems if we
12277  * tried to allow it.
12278  */
12279  if (!indexStruct->indimmediate)
12280  ereport(ERROR,
12281  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
12282  errmsg("cannot use a deferrable primary key for referenced table \"%s\"",
12283  RelationGetRelationName(pkrel))));
12284 
12285  *indexOid = indexoid;
12286  break;
12287  }
12288  ReleaseSysCache(indexTuple);
12289  }
12290 
12291  list_free(indexoidlist);
12292 
12293  /*
12294  * Check that we found it
12295  */
12296  if (!OidIsValid(*indexOid))
12297  ereport(ERROR,
12298  (errcode(ERRCODE_UNDEFINED_OBJECT),
12299  errmsg("there is no primary key for referenced table \"%s\"",
12300  RelationGetRelationName(pkrel))));
12301 
12302  /* Must get indclass the hard way */
12303  indclassDatum = SysCacheGetAttrNotNull(INDEXRELID, indexTuple,
12304  Anum_pg_index_indclass);
12305  indclass = (oidvector *) DatumGetPointer(indclassDatum);
12306 
12307  /*
12308  * Now build the list of PK attributes from the indkey definition (we
12309  * assume a primary key cannot have expressional elements)
12310  */
12311  *attnamelist = NIL;
12312  for (i = 0; i < indexStruct->indnkeyatts; i++)
12313  {
12314  int pkattno = indexStruct->indkey.values[i];
12315 
12316  attnums[i] = pkattno;
12317  atttypids[i] = attnumTypeId(pkrel, pkattno);
12318  opclasses[i] = indclass->values[i];
12319  *attnamelist = lappend(*attnamelist,
12320  makeString(pstrdup(NameStr(*attnumAttName(pkrel, pkattno)))));
12321  }
12322 
12323  *pk_has_without_overlaps = indexStruct->indisexclusion;
12324 
12325  ReleaseSysCache(indexTuple);
12326 
12327  return i;
12328 }
12329 
12330 /*
12331  * transformFkeyCheckAttrs -
12332  *
12333  * Validate that the 'attnums' columns in the 'pkrel' relation are valid to
12334  * reference as part of a foreign key constraint.
12335  *
12336  * Returns the OID of the unique index supporting the constraint and
12337  * populates the caller-provided 'opclasses' array with the opclasses
12338  * associated with the index columns. Also sets whether the index
12339  * uses WITHOUT OVERLAPS.
12340  *
12341  * Raises an ERROR on validation failure.
12342  */
12343 static Oid
12345  int numattrs, int16 *attnums,
12346  bool with_period, Oid *opclasses,
12347  bool *pk_has_without_overlaps)
12348 {
12349  Oid indexoid = InvalidOid;
12350  bool found = false;
12351  bool found_deferrable = false;
12352  List *indexoidlist;
12353  ListCell *indexoidscan;
12354  int i,
12355  j;
12356 
12357  /*
12358  * Reject duplicate appearances of columns in the referenced-columns list.
12359  * Such a case is forbidden by the SQL standard, and even if we thought it
12360  * useful to allow it, there would be ambiguity about how to match the
12361  * list to unique indexes (in particular, it'd be unclear which index
12362  * opclass goes with which FK column).
12363  */
12364  for (i = 0; i < numattrs; i++)
12365  {
12366  for (j = i + 1; j < numattrs; j++)
12367  {
12368  if (attnums[i] == attnums[j])
12369  ereport(ERROR,
12370  (errcode(ERRCODE_INVALID_FOREIGN_KEY),
12371  errmsg("foreign key referenced-columns list must not contain duplicates")));
12372  }
12373  }
12374 
12375  /*
12376  * Get the list of index OIDs for the table from the relcache, and look up
12377  * each one in the pg_index syscache, and match unique indexes to the list
12378  * of attnums we are given.
12379  */
12380  indexoidlist = RelationGetIndexList(pkrel);
12381 
12382  foreach(indexoidscan, indexoidlist)
12383  {
12384  HeapTuple indexTuple;
12385  Form_pg_index indexStruct;
12386 
12387  indexoid = lfirst_oid(indexoidscan);
12388  indexTuple = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(indexoid));
12389  if (!HeapTupleIsValid(indexTuple))
12390  elog(ERROR, "cache lookup failed for index %u", indexoid);
12391  indexStruct = (Form_pg_index) GETSTRUCT(indexTuple);
12392 
12393  /*
12394  * Must have the right number of columns; must be unique (or if
12395  * temporal then exclusion instead) and not a partial index; forget it
12396  * if there are any expressions, too. Invalid indexes are out as well.
12397  */
12398  if (indexStruct->indnkeyatts == numattrs &&
12399  (with_period ? indexStruct->indisexclusion : indexStruct->indisunique) &&
12400  indexStruct->indisvalid &&
12401  heap_attisnull(indexTuple, Anum_pg_index_indpred, NULL) &&
12402  heap_attisnull(indexTuple, Anum_pg_index_indexprs, NULL))
12403  {
12404  Datum indclassDatum;
12405  oidvector *indclass;
12406 
12407  /* Must get indclass the hard way */
12408  indclassDatum = SysCacheGetAttrNotNull(INDEXRELID, indexTuple,
12409  Anum_pg_index_indclass);
12410  indclass = (oidvector *) DatumGetPointer(indclassDatum);
12411 
12412  /*
12413  * The given attnum list may match the index columns in any order.
12414  * Check for a match, and extract the appropriate opclasses while
12415  * we're at it.
12416  *
12417  * We know that attnums[] is duplicate-free per the test at the
12418  * start of this function, and we checked above that the number of
12419  * index columns agrees, so if we find a match for each attnums[]
12420  * entry then we must have a one-to-one match in some order.
12421  */
12422  for (i = 0; i < numattrs; i++)
12423  {
12424  found = false;
12425  for (j = 0; j < numattrs; j++)
12426  {
12427  if (attnums[i] == indexStruct->indkey.values[j])
12428  {
12429  opclasses[i] = indclass->values[j];
12430  found = true;
12431  break;
12432  }
12433  }
12434  if (!found)
12435  break;
12436  }
12437  /* The last attribute in the index must be the PERIOD FK part */
12438  if (found && with_period)
12439  {
12440  int16 periodattnum = attnums[numattrs - 1];
12441 
12442  found = (periodattnum == indexStruct->indkey.values[numattrs - 1]);
12443  }
12444 
12445  /*
12446  * Refuse to use a deferrable unique/primary key. This is per SQL
12447  * spec, and there would be a lot of interesting semantic problems
12448  * if we tried to allow it.
12449  */
12450  if (found && !indexStruct->indimmediate)
12451  {
12452  /*
12453  * Remember that we found an otherwise matching index, so that
12454  * we can generate a more appropriate error message.
12455  */
12456  found_deferrable = true;
12457  found = false;
12458  }
12459 
12460  /* We need to know whether the index has WITHOUT OVERLAPS */
12461  if (found)
12462  *pk_has_without_overlaps = indexStruct->indisexclusion;
12463  }
12464  ReleaseSysCache(indexTuple);
12465  if (found)
12466  break;
12467  }
12468 
12469  if (!found)
12470  {
12471  if (found_deferrable)
12472  ereport(ERROR,
12473  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
12474  errmsg("cannot use a deferrable unique constraint for referenced table \"%s\"",
12475  RelationGetRelationName(pkrel))));
12476  else
12477  ereport(ERROR,
12478  (errcode(ERRCODE_INVALID_FOREIGN_KEY),
12479  errmsg("there is no unique constraint matching given keys for referenced table \"%s\"",
12480  RelationGetRelationName(pkrel))));
12481  }
12482 
12483  list_free(indexoidlist);
12484 
12485  return indexoid;
12486 }
12487 
12488 /*
12489  * findFkeyCast -
12490  *
12491  * Wrapper around find_coercion_pathway() for ATAddForeignKeyConstraint().
12492  * Caller has equal regard for binary coercibility and for an exact match.
12493 */
12494 static CoercionPathType
12495 findFkeyCast(Oid targetTypeId, Oid sourceTypeId, Oid *funcid)
12496 {
12497  CoercionPathType ret;
12498 
12499  if (targetTypeId == sourceTypeId)
12500  {
12502  *funcid = InvalidOid;
12503  }
12504  else
12505  {
12506  ret = find_coercion_pathway(targetTypeId, sourceTypeId,
12507  COERCION_IMPLICIT, funcid);
12508  if (ret == COERCION_PATH_NONE)
12509  /* A previously-relied-upon cast is now gone. */
12510  elog(ERROR, "could not find cast from %u to %u",
12511  sourceTypeId, targetTypeId);
12512  }
12513 
12514  return ret;
12515 }
12516 
12517 /*
12518  * Permissions checks on the referenced table for ADD FOREIGN KEY
12519  *
12520  * Note: we have already checked that the user owns the referencing table,
12521  * else we'd have failed much earlier; no additional checks are needed for it.
12522  */
12523 static void
12524 checkFkeyPermissions(Relation rel, int16 *attnums, int natts)
12525 {
12526  Oid roleid = GetUserId();
12527  AclResult aclresult;
12528  int i;
12529 
12530  /* Okay if we have relation-level REFERENCES permission */
12531  aclresult = pg_class_aclcheck(RelationGetRelid(rel), roleid,
12532  ACL_REFERENCES);
12533  if (aclresult == ACLCHECK_OK)
12534  return;
12535  /* Else we must have REFERENCES on each column */
12536  for (i = 0; i < natts; i++)
12537  {
12538  aclresult = pg_attribute_aclcheck(RelationGetRelid(rel), attnums[i],
12539  roleid, ACL_REFERENCES);
12540  if (aclresult != ACLCHECK_OK)
12541  aclcheck_error(aclresult, get_relkind_objtype(rel->rd_rel->relkind),
12543  }
12544 }
12545 
12546 /*
12547  * Scan the existing rows in a table to verify they meet a proposed FK
12548  * constraint.
12549  *
12550  * Caller must have opened and locked both relations appropriately.
12551  */
12552 static void
12554  Relation rel,
12555  Relation pkrel,
12556  Oid pkindOid,
12557  Oid constraintOid,
12558  bool hasperiod)
12559 {
12560  TupleTableSlot *slot;
12561  TableScanDesc scan;
12562  Trigger trig = {0};
12563  Snapshot snapshot;
12564  MemoryContext oldcxt;
12565  MemoryContext perTupCxt;
12566 
12567  ereport(DEBUG1,
12568  (errmsg_internal("validating foreign key constraint \"%s\"", conname)));
12569 
12570  /*
12571  * Build a trigger call structure; we'll need it either way.
12572  */
12573  trig.tgoid = InvalidOid;
12574  trig.tgname = conname;
12576  trig.tgisinternal = true;
12577  trig.tgconstrrelid = RelationGetRelid(pkrel);
12578  trig.tgconstrindid = pkindOid;
12579  trig.tgconstraint = constraintOid;
12580  trig.tgdeferrable = false;
12581  trig.tginitdeferred = false;
12582  /* we needn't fill in remaining fields */
12583 
12584  /*
12585  * See if we can do it with a single LEFT JOIN query. A false result
12586  * indicates we must proceed with the fire-the-trigger method. We can't do
12587  * a LEFT JOIN for temporal FKs yet, but we can once we support temporal
12588  * left joins.
12589  */
12590  if (!hasperiod && RI_Initial_Check(&trig, rel, pkrel))
12591  return;
12592 
12593  /*
12594  * Scan through each tuple, calling RI_FKey_check_ins (insert trigger) as
12595  * if that tuple had just been inserted. If any of those fail, it should
12596  * ereport(ERROR) and that's that.
12597  */
12598  snapshot = RegisterSnapshot(GetLatestSnapshot());
12599  slot = table_slot_create(rel, NULL);
12600  scan = table_beginscan(rel, snapshot, 0, NULL);
12601 
12603  "validateForeignKeyConstraint",
12605  oldcxt = MemoryContextSwitchTo(perTupCxt);
12606 
12607  while (table_scan_getnextslot(scan, ForwardScanDirection, slot))
12608  {
12609  LOCAL_FCINFO(fcinfo, 0);
12610  TriggerData trigdata = {0};
12611 
12613 
12614  /*
12615  * Make a call to the trigger function
12616  *
12617  * No parameters are passed, but we do set a context
12618  */
12619  MemSet(fcinfo, 0, SizeForFunctionCallInfo(0));
12620 
12621  /*
12622  * We assume RI_FKey_check_ins won't look at flinfo...
12623  */
12624  trigdata.type = T_TriggerData;
12626  trigdata.tg_relation = rel;
12627  trigdata.tg_trigtuple = ExecFetchSlotHeapTuple(slot, false, NULL);
12628  trigdata.tg_trigslot = slot;
12629  trigdata.tg_trigger = &trig;
12630 
12631  fcinfo->context = (Node *) &trigdata;
12632 
12633  RI_FKey_check_ins(fcinfo);
12634 
12635  MemoryContextReset(perTupCxt);
12636  }
12637 
12638  MemoryContextSwitchTo(oldcxt);
12639  MemoryContextDelete(perTupCxt);
12640  table_endscan(scan);
12641  UnregisterSnapshot(snapshot);
12643 }
12644 
12645 /*
12646  * CreateFKCheckTrigger
12647  * Creates the insert (on_insert=true) or update "check" trigger that
12648  * implements a given foreign key
12649  *
12650  * Returns the OID of the so created trigger.
12651  */
12652 static Oid
12653 CreateFKCheckTrigger(Oid myRelOid, Oid refRelOid, Constraint *fkconstraint,
12654  Oid constraintOid, Oid indexOid, Oid parentTrigOid,
12655  bool on_insert)
12656 {
12657  ObjectAddress trigAddress;
12658  CreateTrigStmt *fk_trigger;
12659 
12660  /*
12661  * Note: for a self-referential FK (referencing and referenced tables are
12662  * the same), it is important that the ON UPDATE action fires before the
12663  * CHECK action, since both triggers will fire on the same row during an
12664  * UPDATE event; otherwise the CHECK trigger will be checking a non-final
12665  * state of the row. Triggers fire in name order, so we ensure this by
12666  * using names like "RI_ConstraintTrigger_a_NNNN" for the action triggers
12667  * and "RI_ConstraintTrigger_c_NNNN" for the check triggers.
12668  */
12669  fk_trigger = makeNode(CreateTrigStmt);
12670  fk_trigger->replace = false;
12671  fk_trigger->isconstraint = true;
12672  fk_trigger->trigname = "RI_ConstraintTrigger_c";
12673  fk_trigger->relation = NULL;
12674 
12675  /* Either ON INSERT or ON UPDATE */
12676  if (on_insert)
12677  {
12678  fk_trigger->funcname = SystemFuncName("RI_FKey_check_ins");
12679  fk_trigger->events = TRIGGER_TYPE_INSERT;
12680  }
12681  else
12682  {
12683  fk_trigger->funcname = SystemFuncName("RI_FKey_check_upd");
12684  fk_trigger->events = TRIGGER_TYPE_UPDATE;
12685  }
12686 
12687  fk_trigger->args = NIL;
12688  fk_trigger->row = true;
12689  fk_trigger->timing = TRIGGER_TYPE_AFTER;
12690  fk_trigger->columns = NIL;
12691  fk_trigger->whenClause = NULL;
12692  fk_trigger->transitionRels = NIL;
12693  fk_trigger->deferrable = fkconstraint->deferrable;
12694  fk_trigger->initdeferred = fkconstraint->initdeferred;
12695  fk_trigger->constrrel = NULL;
12696 
12697  trigAddress = CreateTrigger(fk_trigger, NULL, myRelOid, refRelOid,
12698  constraintOid, indexOid, InvalidOid,
12699  parentTrigOid, NULL, true, false);
12700 
12701  /* Make changes-so-far visible */
12703 
12704  return trigAddress.objectId;
12705 }
12706 
12707 /*
12708  * createForeignKeyActionTriggers
12709  * Create the referenced-side "action" triggers that implement a foreign
12710  * key.
12711  *
12712  * Returns the OIDs of the so created triggers in *deleteTrigOid and
12713  * *updateTrigOid.
12714  */
12715 static void
12717  Oid constraintOid, Oid indexOid,
12718  Oid parentDelTrigger, Oid parentUpdTrigger,
12719  Oid *deleteTrigOid, Oid *updateTrigOid)
12720 {
12721  CreateTrigStmt *fk_trigger;
12722  ObjectAddress trigAddress;
12723 
12724  /*
12725  * Build and execute a CREATE CONSTRAINT TRIGGER statement for the ON
12726  * DELETE action on the referenced table.
12727  */
12728  fk_trigger = makeNode(CreateTrigStmt);
12729  fk_trigger->replace = false;
12730  fk_trigger->isconstraint = true;
12731  fk_trigger->trigname = "RI_ConstraintTrigger_a";
12732  fk_trigger->relation = NULL;
12733  fk_trigger->args = NIL;
12734  fk_trigger->row = true;
12735  fk_trigger->timing = TRIGGER_TYPE_AFTER;
12736  fk_trigger->events = TRIGGER_TYPE_DELETE;
12737  fk_trigger->columns = NIL;
12738  fk_trigger->whenClause = NULL;
12739  fk_trigger->transitionRels = NIL;
12740  fk_trigger->constrrel = NULL;
12741 
12742  switch (fkconstraint->fk_del_action)
12743  {
12745  fk_trigger->deferrable = fkconstraint->deferrable;
12746  fk_trigger->initdeferred = fkconstraint->initdeferred;
12747  fk_trigger->funcname = SystemFuncName("RI_FKey_noaction_del");
12748  break;
12750  fk_trigger->deferrable = false;
12751  fk_trigger->initdeferred = false;
12752  fk_trigger->funcname = SystemFuncName("RI_FKey_restrict_del");
12753  break;
12755  fk_trigger->deferrable = false;
12756  fk_trigger->initdeferred = false;
12757  fk_trigger->funcname = SystemFuncName("RI_FKey_cascade_del");
12758  break;
12760  fk_trigger->deferrable = false;
12761  fk_trigger->initdeferred = false;
12762  fk_trigger->funcname = SystemFuncName("RI_FKey_setnull_del");
12763  break;
12765  fk_trigger->deferrable = false;
12766  fk_trigger->initdeferred = false;
12767  fk_trigger->funcname = SystemFuncName("RI_FKey_setdefault_del");
12768  break;
12769  default:
12770  elog(ERROR, "unrecognized FK action type: %d",
12771  (int) fkconstraint->fk_del_action);
12772  break;
12773  }
12774 
12775  trigAddress = CreateTrigger(fk_trigger, NULL, refRelOid,
12776  RelationGetRelid(rel),
12777  constraintOid, indexOid, InvalidOid,
12778  parentDelTrigger, NULL, true, false);
12779  if (deleteTrigOid)
12780  *deleteTrigOid = trigAddress.objectId;
12781 
12782  /* Make changes-so-far visible */
12784 
12785  /*
12786  * Build and execute a CREATE CONSTRAINT TRIGGER statement for the ON
12787  * UPDATE action on the referenced table.
12788  */
12789  fk_trigger = makeNode(CreateTrigStmt);
12790  fk_trigger->replace = false;
12791  fk_trigger->isconstraint = true;
12792  fk_trigger->trigname = "RI_ConstraintTrigger_a";
12793  fk_trigger->relation = NULL;
12794  fk_trigger->args = NIL;
12795  fk_trigger->row = true;
12796  fk_trigger->timing = TRIGGER_TYPE_AFTER;
12797  fk_trigger->events = TRIGGER_TYPE_UPDATE;
12798  fk_trigger->columns = NIL;
12799  fk_trigger->whenClause = NULL;
12800  fk_trigger->transitionRels = NIL;
12801  fk_trigger->constrrel = NULL;
12802 
12803  switch (fkconstraint->fk_upd_action)
12804  {
12806  fk_trigger->deferrable = fkconstraint->deferrable;
12807  fk_trigger->initdeferred = fkconstraint->initdeferred;
12808  fk_trigger->funcname = SystemFuncName("RI_FKey_noaction_upd");
12809  break;
12811  fk_trigger->deferrable = false;
12812  fk_trigger->initdeferred = false;
12813  fk_trigger->funcname = SystemFuncName("RI_FKey_restrict_upd");
12814  break;
12816  fk_trigger->deferrable = false;
12817  fk_trigger->initdeferred = false;
12818  fk_trigger->funcname = SystemFuncName("RI_FKey_cascade_upd");
12819  break;
12821  fk_trigger->deferrable = false;
12822  fk_trigger->initdeferred = false;
12823  fk_trigger->funcname = SystemFuncName("RI_FKey_setnull_upd");
12824  break;
12826  fk_trigger->deferrable = false;
12827  fk_trigger->initdeferred = false;
12828  fk_trigger->funcname = SystemFuncName("RI_FKey_setdefault_upd");
12829  break;
12830  default:
12831  elog(ERROR, "unrecognized FK action type: %d",
12832  (int) fkconstraint->fk_upd_action);
12833  break;
12834  }
12835 
12836  trigAddress = CreateTrigger(fk_trigger, NULL, refRelOid,
12837  RelationGetRelid(rel),
12838  constraintOid, indexOid, InvalidOid,
12839  parentUpdTrigger, NULL, true, false);
12840  if (updateTrigOid)
12841  *updateTrigOid = trigAddress.objectId;
12842 }
12843 
12844 /*
12845  * createForeignKeyCheckTriggers
12846  * Create the referencing-side "check" triggers that implement a foreign
12847  * key.
12848  *
12849  * Returns the OIDs of the so created triggers in *insertTrigOid and
12850  * *updateTrigOid.
12851  */
12852 static void
12854  Constraint *fkconstraint, Oid constraintOid,
12855  Oid indexOid,
12856  Oid parentInsTrigger, Oid parentUpdTrigger,
12857  Oid *insertTrigOid, Oid *updateTrigOid)
12858 {
12859  *insertTrigOid = CreateFKCheckTrigger(myRelOid, refRelOid, fkconstraint,
12860  constraintOid, indexOid,
12861  parentInsTrigger, true);
12862  *updateTrigOid = CreateFKCheckTrigger(myRelOid, refRelOid, fkconstraint,
12863  constraintOid, indexOid,
12864  parentUpdTrigger, false);
12865 }
12866 
12867 /*
12868  * ALTER TABLE DROP CONSTRAINT
12869  *
12870  * Like DROP COLUMN, we can't use the normal ALTER TABLE recursion mechanism.
12871  */
12872 static void
12873 ATExecDropConstraint(Relation rel, const char *constrName,
12874  DropBehavior behavior, bool recurse,
12875  bool missing_ok, LOCKMODE lockmode)
12876 {
12877  Relation conrel;
12878  SysScanDesc scan;
12879  ScanKeyData skey[3];
12880  HeapTuple tuple;
12881  bool found = false;
12882 
12883  conrel = table_open(ConstraintRelationId, RowExclusiveLock);
12884 
12885  /*
12886  * Find and drop the target constraint
12887  */
12888  ScanKeyInit(&skey[0],
12889  Anum_pg_constraint_conrelid,
12890  BTEqualStrategyNumber, F_OIDEQ,
12892  ScanKeyInit(&skey[1],
12893  Anum_pg_constraint_contypid,
12894  BTEqualStrategyNumber, F_OIDEQ,
12896  ScanKeyInit(&skey[2],
12897  Anum_pg_constraint_conname,
12898  BTEqualStrategyNumber, F_NAMEEQ,
12899  CStringGetDatum(constrName));
12900  scan = systable_beginscan(conrel, ConstraintRelidTypidNameIndexId,
12901  true, NULL, 3, skey);
12902 
12903  /* There can be at most one matching row */
12904  if (HeapTupleIsValid(tuple = systable_getnext(scan)))
12905  {
12906  List *readyRels = NIL;
12907 
12908  dropconstraint_internal(rel, tuple, behavior, recurse, false,
12909  missing_ok, &readyRels, lockmode);
12910  found = true;
12911  }
12912 
12913  systable_endscan(scan);
12914 
12915  if (!found)
12916  {
12917  if (!missing_ok)
12918  ereport(ERROR,
12919  errcode(ERRCODE_UNDEFINED_OBJECT),
12920  errmsg("constraint \"%s\" of relation \"%s\" does not exist",
12921  constrName, RelationGetRelationName(rel)));
12922  else
12923  ereport(NOTICE,
12924  errmsg("constraint \"%s\" of relation \"%s\" does not exist, skipping",
12925  constrName, RelationGetRelationName(rel)));
12926  }
12927 
12928  table_close(conrel, RowExclusiveLock);
12929 }
12930 
12931 /*
12932  * Remove a constraint, using its pg_constraint tuple
12933  *
12934  * Implementation for ALTER TABLE DROP CONSTRAINT and ALTER TABLE ALTER COLUMN
12935  * DROP NOT NULL.
12936  *
12937  * Returns the address of the constraint being removed.
12938  */
12939 static ObjectAddress
12941  bool recurse, bool recursing, bool missing_ok, List **readyRels,
12942  LOCKMODE lockmode)
12943 {
12944  Relation conrel;
12945  Form_pg_constraint con;
12946  ObjectAddress conobj;
12947  List *children;
12948  bool is_no_inherit_constraint = false;
12949  char *constrName;
12950  List *unconstrained_cols = NIL;
12951  char *colname = NULL;
12952  bool dropping_pk = false;
12953 
12954  if (list_member_oid(*readyRels, RelationGetRelid(rel)))
12955  return InvalidObjectAddress;
12956  *readyRels = lappend_oid(*readyRels, RelationGetRelid(rel));
12957 
12958  /* Guard against stack overflow due to overly deep inheritance tree. */
12960 
12961  /* At top level, permission check was done in ATPrepCmd, else do it */
12962  if (recursing)
12964 
12965  conrel = table_open(ConstraintRelationId, RowExclusiveLock);
12966 
12967  con = (Form_pg_constraint) GETSTRUCT(constraintTup);
12968  constrName = NameStr(con->conname);
12969 
12970  /*
12971  * If we're asked to drop a constraint which is both defined locally and
12972  * inherited, we can simply mark it as no longer having a local
12973  * definition, and no further changes are required.
12974  *
12975  * XXX We do this for not-null constraints only, not CHECK, because the
12976  * latter have historically not behaved this way and it might be confusing
12977  * to change the behavior now.
12978  */
12979  if (con->contype == CONSTRAINT_NOTNULL &&
12980  con->conislocal && con->coninhcount > 0)
12981  {
12982  HeapTuple copytup;
12983 
12984  copytup = heap_copytuple(constraintTup);
12985  con = (Form_pg_constraint) GETSTRUCT(copytup);
12986  con->conislocal = false;
12987  CatalogTupleUpdate(conrel, &copytup->t_self, copytup);
12988  ObjectAddressSet(conobj, ConstraintRelationId, con->oid);
12989 
12991  table_close(conrel, RowExclusiveLock);
12992  return conobj;
12993  }
12994 
12995  /* Don't allow drop of inherited constraints */
12996  if (con->coninhcount > 0 && !recursing)
12997  ereport(ERROR,
12998  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
12999  errmsg("cannot drop inherited constraint \"%s\" of relation \"%s\"",
13000  constrName, RelationGetRelationName(rel))));
13001 
13002  /*
13003  * See if we have a not-null constraint or a PRIMARY KEY. If so, we have
13004  * more checks and actions below, so obtain the list of columns that are
13005  * constrained by the constraint being dropped.
13006  */
13007  if (con->contype == CONSTRAINT_NOTNULL)
13008  {
13009  AttrNumber colnum;
13010 
13011  colnum = extractNotNullColumn(constraintTup);
13012  unconstrained_cols = list_make1_int(colnum);
13013  colname = NameStr(TupleDescAttr(RelationGetDescr(rel),
13014  colnum - 1)->attname);
13015  }
13016  else if (con->contype == CONSTRAINT_PRIMARY)
13017  {
13018  Datum adatum;
13019  ArrayType *arr;
13020  int numkeys;
13021  bool isNull;
13022  int16 *attnums;
13023 
13024  dropping_pk = true;
13025 
13026  adatum = heap_getattr(constraintTup, Anum_pg_constraint_conkey,
13027  RelationGetDescr(conrel), &isNull);
13028  if (isNull)
13029  elog(ERROR, "null conkey for constraint %u", con->oid);
13030  arr = DatumGetArrayTypeP(adatum); /* ensure not toasted */
13031  numkeys = ARR_DIMS(arr)[0];
13032  if (ARR_NDIM(arr) != 1 ||
13033  numkeys < 0 ||
13034  ARR_HASNULL(arr) ||
13035  ARR_ELEMTYPE(arr) != INT2OID)
13036  elog(ERROR, "conkey is not a 1-D smallint array");
13037  attnums = (int16 *) ARR_DATA_PTR(arr);
13038 
13039  for (int i = 0; i < numkeys; i++)
13040  unconstrained_cols = lappend_int(unconstrained_cols, attnums[i]);
13041  }
13042 
13043  is_no_inherit_constraint = con->connoinherit;
13044 
13045  /*
13046  * If it's a foreign-key constraint, we'd better lock the referenced table
13047  * and check that that's not in use, just as we've already done for the
13048  * constrained table (else we might, eg, be dropping a trigger that has
13049  * unfired events). But we can/must skip that in the self-referential
13050  * case.
13051  */
13052  if (con->contype == CONSTRAINT_FOREIGN &&
13053  con->confrelid != RelationGetRelid(rel))
13054  {
13055  Relation frel;
13056 
13057  /* Must match lock taken by RemoveTriggerById: */
13058  frel = table_open(con->confrelid, AccessExclusiveLock);
13059  CheckTableNotInUse(frel, "ALTER TABLE");
13060  table_close(frel, NoLock);
13061  }
13062 
13063  /*
13064  * Perform the actual constraint deletion
13065  */
13066  ObjectAddressSet(conobj, ConstraintRelationId, con->oid);
13067  performDeletion(&conobj, behavior, 0);
13068 
13069  /*
13070  * If this was a NOT NULL or the primary key, verify that we still have
13071  * constraints to support GENERATED AS IDENTITY or the replica identity.
13072  */
13073  if (unconstrained_cols != NIL)
13074  {
13075  Relation attrel;
13076  Bitmapset *pkcols;
13077  Bitmapset *ircols;
13078 
13079  /* Make implicit attnotnull changes visible */
13081 
13082  attrel = table_open(AttributeRelationId, RowExclusiveLock);
13083 
13084  /*
13085  * We want to test columns for their presence in the primary key, but
13086  * only if we're not dropping it.
13087  */
13088  pkcols = dropping_pk ? NULL :
13092 
13093  foreach_int(attnum, unconstrained_cols)
13094  {
13095  HeapTuple atttup;
13096  HeapTuple contup;
13097  Form_pg_attribute attForm;
13098  char attidentity;
13099 
13100  /*
13101  * Obtain pg_attribute tuple and verify conditions on it.
13102  */
13104  if (!HeapTupleIsValid(atttup))
13105  elog(ERROR, "cache lookup failed for attribute %d of relation %u",
13106  attnum, RelationGetRelid(rel));
13107  attForm = (Form_pg_attribute) GETSTRUCT(atttup);
13108  attidentity = attForm->attidentity;
13109  ReleaseSysCache(atttup);
13110 
13111  /*
13112  * Since the above deletion has been made visible, we can now
13113  * search for any remaining constraints on this column (or these
13114  * columns, in the case we're dropping a multicol primary key.)
13115  * Then, verify whether any further NOT NULL or primary key
13116  * exists: if none and this is a generated identity column or the
13117  * replica identity, abort the whole thing.
13118  */
13120  if (contup ||
13122  pkcols))
13123  continue;
13124 
13125  /*
13126  * It's not valid to drop the not-null constraint for a GENERATED
13127  * AS IDENTITY column.
13128  */
13129  if (attidentity != '\0')
13130  ereport(ERROR,
13131  errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
13132  errmsg("column \"%s\" of relation \"%s\" is an identity column",
13134  false),
13135  RelationGetRelationName(rel)));
13136 
13137  /*
13138  * It's not valid to drop the not-null constraint for a column in
13139  * the replica identity index, either. (FULL is not affected.)
13140  */
13142  ereport(ERROR,
13143  errcode(ERRCODE_INVALID_TABLE_DEFINITION),
13144  errmsg("column \"%s\" is in index used as replica identity",
13145  get_attname(RelationGetRelid(rel), attnum, false)));
13146  }
13147  table_close(attrel, RowExclusiveLock);
13148  }
13149 
13150  /*
13151  * For partitioned tables, non-CHECK, non-NOT-NULL inherited constraints
13152  * are dropped via the dependency mechanism, so we're done here.
13153  */
13154  if (con->contype != CONSTRAINT_CHECK &&
13155  con->contype != CONSTRAINT_NOTNULL &&
13156  rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
13157  {
13158  table_close(conrel, RowExclusiveLock);
13159  return conobj;
13160  }
13161 
13162  /*
13163  * Propagate to children as appropriate. Unlike most other ALTER
13164  * routines, we have to do this one level of recursion at a time; we can't
13165  * use find_all_inheritors to do it in one pass.
13166  */
13167  if (!is_no_inherit_constraint)
13168  children = find_inheritance_children(RelationGetRelid(rel), lockmode);
13169  else
13170  children = NIL;
13171 
13172  /*
13173  * For a partitioned table, if partitions exist and we are told not to
13174  * recurse, it's a user error. It doesn't make sense to have a constraint
13175  * be defined only on the parent, especially if it's a partitioned table.
13176  */
13177  if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE &&
13178  children != NIL && !recurse)
13179  ereport(ERROR,
13180  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
13181  errmsg("cannot remove constraint from only the partitioned table when partitions exist"),
13182  errhint("Do not specify the ONLY keyword.")));
13183 
13184  foreach_oid(childrelid, children)
13185  {
13186  Relation childrel;
13187  HeapTuple tuple;
13188  Form_pg_constraint childcon;
13189 
13190  if (list_member_oid(*readyRels, childrelid))
13191  continue; /* child already processed */
13192 
13193  /* find_inheritance_children already got lock */
13194  childrel = table_open(childrelid, NoLock);
13195  CheckTableNotInUse(childrel, "ALTER TABLE");
13196 
13197  /*
13198  * We search for not-null constraints by column name, and others by
13199  * constraint name.
13200  */
13201  if (con->contype == CONSTRAINT_NOTNULL)
13202  {
13203  tuple = findNotNullConstraint(childrelid, colname);
13204  if (!HeapTupleIsValid(tuple))
13205  elog(ERROR, "cache lookup failed for not-null constraint on column \"%s\" of relation %u",
13206  colname, RelationGetRelid(childrel));
13207  }
13208  else
13209  {
13210  SysScanDesc scan;
13211  ScanKeyData skey[3];
13212 
13213  ScanKeyInit(&skey[0],
13214  Anum_pg_constraint_conrelid,
13215  BTEqualStrategyNumber, F_OIDEQ,
13216  ObjectIdGetDatum(childrelid));
13217  ScanKeyInit(&skey[1],
13218  Anum_pg_constraint_contypid,
13219  BTEqualStrategyNumber, F_OIDEQ,
13221  ScanKeyInit(&skey[2],
13222  Anum_pg_constraint_conname,
13223  BTEqualStrategyNumber, F_NAMEEQ,
13224  CStringGetDatum(constrName));
13225  scan = systable_beginscan(conrel, ConstraintRelidTypidNameIndexId,
13226  true, NULL, 3, skey);
13227  /* There can only be one, so no need to loop */
13228  tuple = systable_getnext(scan);
13229  if (!HeapTupleIsValid(tuple))
13230  ereport(ERROR,
13231  (errcode(ERRCODE_UNDEFINED_OBJECT),
13232  errmsg("constraint \"%s\" of relation \"%s\" does not exist",
13233  constrName,
13234  RelationGetRelationName(childrel))));
13235  tuple = heap_copytuple(tuple);
13236  systable_endscan(scan);
13237  }
13238 
13239  childcon = (Form_pg_constraint) GETSTRUCT(tuple);
13240 
13241  /* Right now only CHECK and not-null constraints can be inherited */
13242  if (childcon->contype != CONSTRAINT_CHECK &&
13243  childcon->contype != CONSTRAINT_NOTNULL)
13244  elog(ERROR, "inherited constraint is not a CHECK or not-null constraint");
13245 
13246  if (childcon->coninhcount <= 0) /* shouldn't happen */
13247  elog(ERROR, "relation %u has non-inherited constraint \"%s\"",
13248  childrelid, NameStr(childcon->conname));
13249 
13250  if (recurse)
13251  {
13252  /*
13253  * If the child constraint has other definition sources, just
13254  * decrement its inheritance count; if not, recurse to delete it.
13255  */
13256  if (childcon->coninhcount == 1 && !childcon->conislocal)
13257  {
13258  /* Time to delete this child constraint, too */
13259  dropconstraint_internal(childrel, tuple, behavior,
13260  recurse, true, missing_ok, readyRels,
13261  lockmode);
13262  }
13263  else
13264  {
13265  /* Child constraint must survive my deletion */
13266  childcon->coninhcount--;
13267  CatalogTupleUpdate(conrel, &tuple->t_self, tuple);
13268 
13269  /* Make update visible */
13271  }
13272  }
13273  else
13274  {
13275  /*
13276  * If we were told to drop ONLY in this table (no recursion) and
13277  * there are no further parents for this constraint, we need to
13278  * mark the inheritors' constraints as locally defined rather than
13279  * inherited.
13280  */
13281  childcon->coninhcount--;
13282  if (childcon->coninhcount == 0)
13283  childcon->conislocal = true;
13284 
13285  CatalogTupleUpdate(conrel, &tuple->t_self, tuple);
13286 
13287  /* Make update visible */
13289  }
13290 
13291  heap_freetuple(tuple);
13292 
13293  table_close(childrel, NoLock);
13294  }
13295 
13296  /*
13297  * In addition, when dropping a primary key from a legacy-inheritance
13298  * parent table, we must recurse to children to mark the corresponding NOT
13299  * NULL constraint as no longer inherited, or drop it if this its last
13300  * reference.
13301  */
13302  if (con->contype == CONSTRAINT_PRIMARY &&
13303  rel->rd_rel->relkind == RELKIND_RELATION &&
13304  rel->rd_rel->relhassubclass)
13305  {
13306  List *colnames = NIL;
13307  List *pkready = NIL;
13308 
13309  /*
13310  * Because primary keys are always marked as NO INHERIT, we don't have
13311  * a list of children yet, so obtain one now.
13312  */
13313  children = find_inheritance_children(RelationGetRelid(rel), lockmode);
13314 
13315  /*
13316  * Find out the list of column names to process. Fortunately, we
13317  * already have the list of column numbers.
13318  */
13319  foreach_int(attnum, unconstrained_cols)
13320  {
13321  colnames = lappend(colnames, get_attname(RelationGetRelid(rel),
13322  attnum, false));
13323  }
13324 
13325  foreach_oid(childrelid, children)
13326  {
13327  Relation childrel;
13328 
13329  if (list_member_oid(pkready, childrelid))
13330  continue; /* child already processed */
13331 
13332  /* find_inheritance_children already got lock */
13333  childrel = table_open(childrelid, NoLock);
13334  CheckTableNotInUse(childrel, "ALTER TABLE");
13335 
13336  foreach_ptr(char, colName, colnames)
13337  {
13338  HeapTuple contup;
13339 
13340  contup = findNotNullConstraint(childrelid, colName);
13341  if (contup == NULL)
13342  elog(ERROR, "cache lookup failed for not-null constraint on column \"%s\", relation \"%s\"",
13343  colName, RelationGetRelationName(childrel));
13344 
13345  dropconstraint_internal(childrel, contup,
13346  DROP_RESTRICT, true, true,
13347  false, &pkready,
13348  lockmode);
13349  pkready = NIL;
13350  }
13351 
13352  table_close(childrel, NoLock);
13353 
13354  pkready = lappend_oid(pkready, childrelid);
13355  }
13356  }
13357 
13358  table_close(conrel, RowExclusiveLock);
13359 
13360  return conobj;
13361 }
13362 
13363 /*
13364  * ALTER COLUMN TYPE
13365  *
13366  * Unlike other subcommand types, we do parse transformation for ALTER COLUMN
13367  * TYPE during phase 1 --- the AlterTableCmd passed in here is already
13368  * transformed (and must be, because we rely on some transformed fields).
13369  *
13370  * The point of this is that the execution of all ALTER COLUMN TYPEs for a
13371  * table will be done "in parallel" during phase 3, so all the USING
13372  * expressions should be parsed assuming the original column types. Also,
13373  * this allows a USING expression to refer to a field that will be dropped.
13374  *
13375  * To make this work safely, AT_PASS_DROP then AT_PASS_ALTER_TYPE must be
13376  * the first two execution steps in phase 2; they must not see the effects
13377  * of any other subcommand types, since the USING expressions are parsed
13378  * against the unmodified table's state.
13379  */
13380 static void
13382  AlteredTableInfo *tab, Relation rel,
13383  bool recurse, bool recursing,
13384  AlterTableCmd *cmd, LOCKMODE lockmode,
13386 {
13387  char *colName = cmd->name;
13388  ColumnDef *def = (ColumnDef *) cmd->def;
13389  TypeName *typeName = def->typeName;
13390  Node *transform = def->cooked_default;
13391  HeapTuple tuple;
13392  Form_pg_attribute attTup;
13394  Oid targettype;
13395  int32 targettypmod;
13396  Oid targetcollid;
13398  ParseState *pstate = make_parsestate(NULL);
13399  AclResult aclresult;
13400  bool is_expr;
13401 
13402  if (rel->rd_rel->reloftype && !recursing)
13403  ereport(ERROR,
13404  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
13405  errmsg("cannot alter column type of typed table")));
13406 
13407  /* lookup the attribute so we can check inheritance status */
13408  tuple = SearchSysCacheAttName(RelationGetRelid(rel), colName);
13409  if (!HeapTupleIsValid(tuple))
13410  ereport(ERROR,
13411  (errcode(ERRCODE_UNDEFINED_COLUMN),
13412  errmsg("column \"%s\" of relation \"%s\" does not exist",
13413  colName, RelationGetRelationName(rel))));
13414  attTup = (Form_pg_attribute) GETSTRUCT(tuple);
13415  attnum = attTup->attnum;
13416 
13417  /* Can't alter a system attribute */
13418  if (attnum <= 0)
13419  ereport(ERROR,
13420  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
13421  errmsg("cannot alter system column \"%s\"",
13422  colName)));
13423 
13424  /*
13425  * Don't alter inherited columns. At outer level, there had better not be
13426  * any inherited definition; when recursing, we assume this was checked at
13427  * the parent level (see below).
13428  */
13429  if (attTup->attinhcount > 0 && !recursing)
13430  ereport(ERROR,
13431  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
13432  errmsg("cannot alter inherited column \"%s\"",
13433  colName)));
13434 
13435  /* Don't alter columns used in the partition key */
13436  if (has_partition_attrs(rel,
13438  &is_expr))
13439  ereport(ERROR,
13440  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
13441  errmsg("cannot alter column \"%s\" because it is part of the partition key of relation \"%s\"",
13442  colName, RelationGetRelationName(rel))));
13443 
13444  /* Look up the target type */
13445  typenameTypeIdAndMod(NULL, typeName, &targettype, &targettypmod);
13446 
13447  aclresult = object_aclcheck(TypeRelationId, targettype, GetUserId(), ACL_USAGE);
13448  if (aclresult != ACLCHECK_OK)
13449  aclcheck_error_type(aclresult, targettype);
13450 
13451  /* And the collation */
13452  targetcollid = GetColumnDefCollation(NULL, def, targettype);
13453 
13454  /* make sure datatype is legal for a column */
13455  CheckAttributeType(colName, targettype, targetcollid,
13456  list_make1_oid(rel->rd_rel->reltype),
13457  0);
13458 
13459  if (tab->relkind == RELKIND_RELATION ||
13460  tab->relkind == RELKIND_PARTITIONED_TABLE)
13461  {
13462  /*
13463  * Set up an expression to transform the old data value to the new
13464  * type. If a USING option was given, use the expression as
13465  * transformed by transformAlterTableStmt, else just take the old
13466  * value and try to coerce it. We do this first so that type
13467  * incompatibility can be detected before we waste effort, and because
13468  * we need the expression to be parsed against the original table row
13469  * type.
13470  */
13471  if (!transform)
13472  {
13473  transform = (Node *) makeVar(1, attnum,
13474  attTup->atttypid, attTup->atttypmod,
13475  attTup->attcollation,
13476  0);
13477  }
13478 
13479  transform = coerce_to_target_type(pstate,
13480  transform, exprType(transform),
13481  targettype, targettypmod,
13484  -1);
13485  if (transform == NULL)
13486  {
13487  /* error text depends on whether USING was specified or not */
13488  if (def->cooked_default != NULL)
13489  ereport(ERROR,
13490  (errcode(ERRCODE_DATATYPE_MISMATCH),
13491  errmsg("result of USING clause for column \"%s\""
13492  " cannot be cast automatically to type %s",
13493  colName, format_type_be(targettype)),
13494  errhint("You might need to add an explicit cast.")));
13495  else
13496  ereport(ERROR,
13497  (errcode(ERRCODE_DATATYPE_MISMATCH),
13498  errmsg("column \"%s\" cannot be cast automatically to type %s",
13499  colName, format_type_be(targettype)),
13500  /* translator: USING is SQL, don't translate it */
13501  errhint("You might need to specify \"USING %s::%s\".",
13502  quote_identifier(colName),
13503  format_type_with_typemod(targettype,
13504  targettypmod))));
13505  }
13506 
13507  /* Fix collations after all else */
13508  assign_expr_collations(pstate, transform);
13509 
13510  /* Plan the expr now so we can accurately assess the need to rewrite. */
13511  transform = (Node *) expression_planner((Expr *) transform);
13512 
13513  /*
13514  * Add a work queue item to make ATRewriteTable update the column
13515  * contents.
13516  */
13518  newval->attnum = attnum;
13519  newval->expr = (Expr *) transform;
13520  newval->is_generated = false;
13521 
13522  tab->newvals = lappend(tab->newvals, newval);
13523  if (ATColumnChangeRequiresRewrite(transform, attnum))
13525  }
13526  else if (transform)
13527  ereport(ERROR,
13528  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
13529  errmsg("\"%s\" is not a table",
13530  RelationGetRelationName(rel))));
13531 
13532  if (!RELKIND_HAS_STORAGE(tab->relkind))
13533  {
13534  /*
13535  * For relations without storage, do this check now. Regular tables
13536  * will check it later when the table is being rewritten.
13537  */
13538  find_composite_type_dependencies(rel->rd_rel->reltype, rel, NULL);
13539  }
13540 
13541  ReleaseSysCache(tuple);
13542 
13543  /*
13544  * Recurse manually by queueing a new command for each child, if
13545  * necessary. We cannot apply ATSimpleRecursion here because we need to
13546  * remap attribute numbers in the USING expression, if any.
13547  *
13548  * If we are told not to recurse, there had better not be any child
13549  * tables; else the alter would put them out of step.
13550  */
13551  if (recurse)
13552  {
13553  Oid relid = RelationGetRelid(rel);
13554  List *child_oids,
13555  *child_numparents;
13556  ListCell *lo,
13557  *li;
13558 
13559  child_oids = find_all_inheritors(relid, lockmode,
13560  &child_numparents);
13561 
13562  /*
13563  * find_all_inheritors does the recursive search of the inheritance
13564  * hierarchy, so all we have to do is process all of the relids in the
13565  * list that it returns.
13566  */
13567  forboth(lo, child_oids, li, child_numparents)
13568  {
13569  Oid childrelid = lfirst_oid(lo);
13570  int numparents = lfirst_int(li);
13571  Relation childrel;
13572  HeapTuple childtuple;
13573  Form_pg_attribute childattTup;
13574 
13575  if (childrelid == relid)
13576  continue;
13577 
13578  /* find_all_inheritors already got lock */
13579  childrel = relation_open(childrelid, NoLock);
13580  CheckTableNotInUse(childrel, "ALTER TABLE");
13581 
13582  /*
13583  * Verify that the child doesn't have any inherited definitions of
13584  * this column that came from outside this inheritance hierarchy.
13585  * (renameatt makes a similar test, though in a different way
13586  * because of its different recursion mechanism.)
13587  */
13588  childtuple = SearchSysCacheAttName(RelationGetRelid(childrel),
13589  colName);
13590  if (!HeapTupleIsValid(childtuple))
13591  ereport(ERROR,
13592  (errcode(ERRCODE_UNDEFINED_COLUMN),
13593  errmsg("column \"%s\" of relation \"%s\" does not exist",
13594  colName, RelationGetRelationName(childrel))));
13595  childattTup = (Form_pg_attribute) GETSTRUCT(childtuple);
13596 
13597  if (childattTup->attinhcount > numparents)
13598  ereport(ERROR,
13599  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
13600  errmsg("cannot alter inherited column \"%s\" of relation \"%s\"",
13601  colName, RelationGetRelationName(childrel))));
13602 
13603  ReleaseSysCache(childtuple);
13604 
13605  /*
13606  * Remap the attribute numbers. If no USING expression was
13607  * specified, there is no need for this step.
13608  */
13609  if (def->cooked_default)
13610  {
13611  AttrMap *attmap;
13612  bool found_whole_row;
13613 
13614  /* create a copy to scribble on */
13615  cmd = copyObject(cmd);
13616 
13617  attmap = build_attrmap_by_name(RelationGetDescr(childrel),
13618  RelationGetDescr(rel),
13619  false);
13620  ((ColumnDef *) cmd->def)->cooked_default =
13622  1, 0,
13623  attmap,
13624  InvalidOid, &found_whole_row);
13625  if (found_whole_row)
13626  ereport(ERROR,
13627  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
13628  errmsg("cannot convert whole-row table reference"),
13629  errdetail("USING expression contains a whole-row table reference.")));
13630  pfree(attmap);
13631  }
13632  ATPrepCmd(wqueue, childrel, cmd, false, true, lockmode, context);
13633  relation_close(childrel, NoLock);
13634  }
13635  }
13636  else if (!recursing &&
13638  ereport(ERROR,
13639  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
13640  errmsg("type of inherited column \"%s\" must be changed in child tables too",
13641  colName)));
13642 
13643  if (tab->relkind == RELKIND_COMPOSITE_TYPE)
13644  ATTypedTableRecursion(wqueue, rel, cmd, lockmode, context);
13645 }
13646 
13647 /*
13648  * When the data type of a column is changed, a rewrite might not be required
13649  * if the new type is sufficiently identical to the old one, and the USING
13650  * clause isn't trying to insert some other value. It's safe to skip the
13651  * rewrite in these cases:
13652  *
13653  * - the old type is binary coercible to the new type
13654  * - the new type is an unconstrained domain over the old type
13655  * - {NEW,OLD} or {OLD,NEW} is {timestamptz,timestamp} and the timezone is UTC
13656  *
13657  * In the case of a constrained domain, we could get by with scanning the
13658  * table and checking the constraint rather than actually rewriting it, but we
13659  * don't currently try to do that.
13660  */
13661 static bool
13663 {
13664  Assert(expr != NULL);
13665 
13666  for (;;)
13667  {
13668  /* only one varno, so no need to check that */
13669  if (IsA(expr, Var) && ((Var *) expr)->varattno == varattno)
13670  return false;
13671  else if (IsA(expr, RelabelType))
13672  expr = (Node *) ((RelabelType *) expr)->arg;
13673  else if (IsA(expr, CoerceToDomain))
13674  {
13675  CoerceToDomain *d = (CoerceToDomain *) expr;
13676 
13678  return true;
13679  expr = (Node *) d->arg;
13680  }
13681  else if (IsA(expr, FuncExpr))
13682  {
13683  FuncExpr *f = (FuncExpr *) expr;
13684 
13685  switch (f->funcid)
13686  {
13687  case F_TIMESTAMPTZ_TIMESTAMP:
13688  case F_TIMESTAMP_TIMESTAMPTZ:
13690  return true;
13691  else
13692  expr = linitial(f->args);
13693  break;
13694  default:
13695  return true;
13696  }
13697  }
13698  else
13699  return true;
13700  }
13701 }
13702 
13703 /*
13704  * ALTER COLUMN .. SET DATA TYPE
13705  *
13706  * Return the address of the modified column.
13707  */
13708 static ObjectAddress
13710  AlterTableCmd *cmd, LOCKMODE lockmode)
13711 {
13712  char *colName = cmd->name;
13713  ColumnDef *def = (ColumnDef *) cmd->def;
13714  TypeName *typeName = def->typeName;
13715  HeapTuple heapTup;
13716  Form_pg_attribute attTup,
13717  attOldTup;
13719  HeapTuple typeTuple;
13720  Form_pg_type tform;
13721  Oid targettype;
13722  int32 targettypmod;
13723  Oid targetcollid;
13724  Node *defaultexpr;
13725  Relation attrelation;
13726  Relation depRel;
13727  ScanKeyData key[3];
13728  SysScanDesc scan;
13729  HeapTuple depTup;
13730  ObjectAddress address;
13731 
13732  /*
13733  * Clear all the missing values if we're rewriting the table, since this
13734  * renders them pointless.
13735  */
13736  if (tab->rewrite)
13737  {
13738  Relation newrel;
13739 
13740  newrel = table_open(RelationGetRelid(rel), NoLock);
13741  RelationClearMissing(newrel);
13742  relation_close(newrel, NoLock);
13743  /* make sure we don't conflict with later attribute modifications */
13745  }
13746 
13747  attrelation = table_open(AttributeRelationId, RowExclusiveLock);
13748 
13749  /* Look up the target column */
13750  heapTup = SearchSysCacheCopyAttName(RelationGetRelid(rel), colName);
13751  if (!HeapTupleIsValid(heapTup)) /* shouldn't happen */
13752  ereport(ERROR,
13753  (errcode(ERRCODE_UNDEFINED_COLUMN),
13754  errmsg("column \"%s\" of relation \"%s\" does not exist",
13755  colName, RelationGetRelationName(rel))));
13756  attTup = (Form_pg_attribute) GETSTRUCT(heapTup);
13757  attnum = attTup->attnum;
13758  attOldTup = TupleDescAttr(tab->oldDesc, attnum - 1);
13759 
13760  /* Check for multiple ALTER TYPE on same column --- can't cope */
13761  if (attTup->atttypid != attOldTup->atttypid ||
13762  attTup->atttypmod != attOldTup->atttypmod)
13763  ereport(ERROR,
13764  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
13765  errmsg("cannot alter type of column \"%s\" twice",
13766  colName)));
13767 
13768  /* Look up the target type (should not fail, since prep found it) */
13769  typeTuple = typenameType(NULL, typeName, &targettypmod);
13770  tform = (Form_pg_type) GETSTRUCT(typeTuple);
13771  targettype = tform->oid;
13772  /* And the collation */
13773  targetcollid = GetColumnDefCollation(NULL, def, targettype);
13774 
13775  /*
13776  * If there is a default expression for the column, get it and ensure we
13777  * can coerce it to the new datatype. (We must do this before changing
13778  * the column type, because build_column_default itself will try to
13779  * coerce, and will not issue the error message we want if it fails.)
13780  *
13781  * We remove any implicit coercion steps at the top level of the old
13782  * default expression; this has been agreed to satisfy the principle of
13783  * least surprise. (The conversion to the new column type should act like
13784  * it started from what the user sees as the stored expression, and the
13785  * implicit coercions aren't going to be shown.)
13786  */
13787  if (attTup->atthasdef)
13788  {
13789  defaultexpr = build_column_default(rel, attnum);
13790  Assert(defaultexpr);
13791  defaultexpr = strip_implicit_coercions(defaultexpr);
13792  defaultexpr = coerce_to_target_type(NULL, /* no UNKNOWN params */
13793  defaultexpr, exprType(defaultexpr),
13794  targettype, targettypmod,
13797  -1);
13798  if (defaultexpr == NULL)
13799  {
13800  if (attTup->attgenerated)
13801  ereport(ERROR,
13802  (errcode(ERRCODE_DATATYPE_MISMATCH),
13803  errmsg("generation expression for column \"%s\" cannot be cast automatically to type %s",
13804  colName, format_type_be(targettype))));
13805  else
13806  ereport(ERROR,
13807  (errcode(ERRCODE_DATATYPE_MISMATCH),
13808  errmsg("default for column \"%s\" cannot be cast automatically to type %s",
13809  colName, format_type_be(targettype))));
13810  }
13811  }
13812  else
13813  defaultexpr = NULL;
13814 
13815  /*
13816  * Find everything that depends on the column (constraints, indexes, etc),
13817  * and record enough information to let us recreate the objects.
13818  *
13819  * The actual recreation does not happen here, but only after we have
13820  * performed all the individual ALTER TYPE operations. We have to save
13821  * the info before executing ALTER TYPE, though, else the deparser will
13822  * get confused.
13823  */
13825 
13826  /*
13827  * Now scan for dependencies of this column on other things. The only
13828  * things we should find are the dependency on the column datatype and
13829  * possibly a collation dependency. Those can be removed.
13830  */
13831  depRel = table_open(DependRelationId, RowExclusiveLock);
13832 
13833  ScanKeyInit(&key[0],
13834  Anum_pg_depend_classid,
13835  BTEqualStrategyNumber, F_OIDEQ,
13836  ObjectIdGetDatum(RelationRelationId));
13837  ScanKeyInit(&key[1],
13838  Anum_pg_depend_objid,
13839  BTEqualStrategyNumber, F_OIDEQ,
13841  ScanKeyInit(&key[2],
13842  Anum_pg_depend_objsubid,
13843  BTEqualStrategyNumber, F_INT4EQ,
13845 
13846  scan = systable_beginscan(depRel, DependDependerIndexId, true,
13847  NULL, 3, key);
13848 
13849  while (HeapTupleIsValid(depTup = systable_getnext(scan)))
13850  {
13851  Form_pg_depend foundDep = (Form_pg_depend) GETSTRUCT(depTup);
13852  ObjectAddress foundObject;
13853 
13854  foundObject.classId = foundDep->refclassid;
13855  foundObject.objectId = foundDep->refobjid;
13856  foundObject.objectSubId = foundDep->refobjsubid;
13857 
13858  if (foundDep->deptype != DEPENDENCY_NORMAL)
13859  elog(ERROR, "found unexpected dependency type '%c'",
13860  foundDep->deptype);
13861  if (!(foundDep->refclassid == TypeRelationId &&
13862  foundDep->refobjid == attTup->atttypid) &&
13863  !(foundDep->refclassid == CollationRelationId &&
13864  foundDep->refobjid == attTup->attcollation))
13865  elog(ERROR, "found unexpected dependency for column: %s",
13866  getObjectDescription(&foundObject, false));
13867 
13868  CatalogTupleDelete(depRel, &depTup->t_self);
13869  }
13870 
13871  systable_endscan(scan);
13872 
13873  table_close(depRel, RowExclusiveLock);
13874 
13875  /*
13876  * Here we go --- change the recorded column type and collation. (Note
13877  * heapTup is a copy of the syscache entry, so okay to scribble on.) First
13878  * fix up the missing value if any.
13879  */
13880  if (attTup->atthasmissing)
13881  {
13882  Datum missingval;
13883  bool missingNull;
13884 
13885  /* if rewrite is true the missing value should already be cleared */
13886  Assert(tab->rewrite == 0);
13887 
13888  /* Get the missing value datum */
13889  missingval = heap_getattr(heapTup,
13890  Anum_pg_attribute_attmissingval,
13891  attrelation->rd_att,
13892  &missingNull);
13893 
13894  /* if it's a null array there is nothing to do */
13895 
13896  if (!missingNull)
13897  {
13898  /*
13899  * Get the datum out of the array and repack it in a new array
13900  * built with the new type data. We assume that since the table
13901  * doesn't need rewriting, the actual Datum doesn't need to be
13902  * changed, only the array metadata.
13903  */
13904 
13905  int one = 1;
13906  bool isNull;
13907  Datum valuesAtt[Natts_pg_attribute] = {0};
13908  bool nullsAtt[Natts_pg_attribute] = {0};
13909  bool replacesAtt[Natts_pg_attribute] = {0};
13910  HeapTuple newTup;
13911 
13912  missingval = array_get_element(missingval,
13913  1,
13914  &one,
13915  0,
13916  attTup->attlen,
13917  attTup->attbyval,
13918  attTup->attalign,
13919  &isNull);
13920  missingval = PointerGetDatum(construct_array(&missingval,
13921  1,
13922  targettype,
13923  tform->typlen,
13924  tform->typbyval,
13925  tform->typalign));
13926 
13927  valuesAtt[Anum_pg_attribute_attmissingval - 1] = missingval;
13928  replacesAtt[Anum_pg_attribute_attmissingval - 1] = true;
13929  nullsAtt[Anum_pg_attribute_attmissingval - 1] = false;
13930 
13931  newTup = heap_modify_tuple(heapTup, RelationGetDescr(attrelation),
13932  valuesAtt, nullsAtt, replacesAtt);
13933  heap_freetuple(heapTup);
13934  heapTup = newTup;
13935  attTup = (Form_pg_attribute) GETSTRUCT(heapTup);
13936  }
13937  }
13938 
13939  attTup->atttypid = targettype;
13940  attTup->atttypmod = targettypmod;
13941  attTup->attcollation = targetcollid;
13942  if (list_length(typeName->arrayBounds) > PG_INT16_MAX)
13943  ereport(ERROR,
13944  errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
13945  errmsg("too many array dimensions"));
13946  attTup->attndims = list_length(typeName->arrayBounds);
13947  attTup->attlen = tform->typlen;
13948  attTup->attbyval = tform->typbyval;
13949  attTup->attalign = tform->typalign;
13950  attTup->attstorage = tform->typstorage;
13951  attTup->attcompression = InvalidCompressionMethod;
13952 
13953  ReleaseSysCache(typeTuple);
13954 
13955  CatalogTupleUpdate(attrelation, &heapTup->t_self, heapTup);
13956 
13957  table_close(attrelation, RowExclusiveLock);
13958 
13959  /* Install dependencies on new datatype and collation */
13962 
13963  /*
13964  * Drop any pg_statistic entry for the column, since it's now wrong type
13965  */
13967 
13968  InvokeObjectPostAlterHook(RelationRelationId,
13969  RelationGetRelid(rel), attnum);
13970 
13971  /*
13972  * Update the default, if present, by brute force --- remove and re-add
13973  * the default. Probably unsafe to take shortcuts, since the new version
13974  * may well have additional dependencies. (It's okay to do this now,
13975  * rather than after other ALTER TYPE commands, since the default won't
13976  * depend on other column types.)
13977  */
13978  if (defaultexpr)
13979  {
13980  /*
13981  * If it's a GENERATED default, drop its dependency records, in
13982  * particular its INTERNAL dependency on the column, which would
13983  * otherwise cause dependency.c to refuse to perform the deletion.
13984  */
13985  if (attTup->attgenerated)
13986  {
13987  Oid attrdefoid = GetAttrDefaultOid(RelationGetRelid(rel), attnum);
13988 
13989  if (!OidIsValid(attrdefoid))
13990  elog(ERROR, "could not find attrdef tuple for relation %u attnum %d",
13991  RelationGetRelid(rel), attnum);
13992  (void) deleteDependencyRecordsFor(AttrDefaultRelationId, attrdefoid, false);
13993  }
13994 
13995  /*
13996  * Make updates-so-far visible, particularly the new pg_attribute row
13997  * which will be updated again.
13998  */
14000 
14001  /*
14002  * We use RESTRICT here for safety, but at present we do not expect
14003  * anything to depend on the default.
14004  */
14006  true);
14007 
14008  StoreAttrDefault(rel, attnum, defaultexpr, true, false);
14009  }
14010 
14011  ObjectAddressSubSet(address, RelationRelationId,
14012  RelationGetRelid(rel), attnum);
14013 
14014  /* Cleanup */
14015  heap_freetuple(heapTup);
14016 
14017  return address;
14018 }
14019 
14020 /*
14021  * Subroutine for ATExecAlterColumnType and ATExecSetExpression: Find everything
14022  * that depends on the column (constraints, indexes, etc), and record enough
14023  * information to let us recreate the objects.
14024  */
14025 static void
14027  Relation rel, AttrNumber attnum, const char *colName)
14028 {
14029  Relation depRel;
14030  ScanKeyData key[3];
14031  SysScanDesc scan;
14032  HeapTuple depTup;
14033 
14034  Assert(subtype == AT_AlterColumnType || subtype == AT_SetExpression);
14035 
14036  depRel = table_open(DependRelationId, RowExclusiveLock);
14037 
14038  ScanKeyInit(&key[0],
14039  Anum_pg_depend_refclassid,
14040  BTEqualStrategyNumber, F_OIDEQ,
14041  ObjectIdGetDatum(RelationRelationId));
14042  ScanKeyInit(&key[1],
14043  Anum_pg_depend_refobjid,
14044  BTEqualStrategyNumber, F_OIDEQ,
14046  ScanKeyInit(&key[2],
14047  Anum_pg_depend_refobjsubid,
14048  BTEqualStrategyNumber, F_INT4EQ,
14050 
14051  scan = systable_beginscan(depRel, DependReferenceIndexId, true,
14052  NULL, 3, key);
14053 
14054  while (HeapTupleIsValid(depTup = systable_getnext(scan)))
14055  {
14056  Form_pg_depend foundDep = (Form_pg_depend) GETSTRUCT(depTup);
14057  ObjectAddress foundObject;
14058 
14059  foundObject.classId = foundDep->classid;
14060  foundObject.objectId = foundDep->objid;
14061  foundObject.objectSubId = foundDep->objsubid;
14062 
14063  switch (foundObject.classId)
14064  {
14065  case RelationRelationId:
14066  {
14067  char relKind = get_rel_relkind(foundObject.objectId);
14068 
14069  if (relKind == RELKIND_INDEX ||
14070  relKind == RELKIND_PARTITIONED_INDEX)
14071  {
14072  Assert(foundObject.objectSubId == 0);
14073  RememberIndexForRebuilding(foundObject.objectId, tab);
14074  }
14075  else if (relKind == RELKIND_SEQUENCE)
14076  {
14077  /*
14078  * This must be a SERIAL column's sequence. We need
14079  * not do anything to it.
14080  */
14081  Assert(foundObject.objectSubId == 0);
14082  }
14083  else
14084  {
14085  /* Not expecting any other direct dependencies... */
14086  elog(ERROR, "unexpected object depending on column: %s",
14087  getObjectDescription(&foundObject, false));
14088  }
14089  break;
14090  }
14091 
14092  case ConstraintRelationId:
14093  Assert(foundObject.objectSubId == 0);
14094  RememberConstraintForRebuilding(foundObject.objectId, tab);
14095  break;
14096 
14097  case RewriteRelationId:
14098  /* XXX someday see if we can cope with revising views */
14099  if (subtype == AT_AlterColumnType)
14100  ereport(ERROR,
14101  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
14102  errmsg("cannot alter type of a column used by a view or rule"),
14103  errdetail("%s depends on column \"%s\"",
14104  getObjectDescription(&foundObject, false),
14105  colName)));
14106  break;
14107 
14108  case TriggerRelationId:
14109 
14110  /*
14111  * A trigger can depend on a column because the column is
14112  * specified as an update target, or because the column is
14113  * used in the trigger's WHEN condition. The first case would
14114  * not require any extra work, but the second case would
14115  * require updating the WHEN expression, which will take a
14116  * significant amount of new code. Since we can't easily tell
14117  * which case applies, we punt for both. FIXME someday.
14118  */
14119  if (subtype == AT_AlterColumnType)
14120  ereport(ERROR,
14121  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
14122  errmsg("cannot alter type of a column used in a trigger definition"),
14123  errdetail("%s depends on column \"%s\"",
14124  getObjectDescription(&foundObject, false),
14125  colName)));
14126  break;
14127 
14128  case PolicyRelationId:
14129 
14130  /*
14131  * A policy can depend on a column because the column is
14132  * specified in the policy's USING or WITH CHECK qual
14133  * expressions. It might be possible to rewrite and recheck
14134  * the policy expression, but punt for now. It's certainly
14135  * easy enough to remove and recreate the policy; still, FIXME
14136  * someday.
14137  */
14138  if (subtype == AT_AlterColumnType)
14139  ereport(ERROR,
14140  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
14141  errmsg("cannot alter type of a column used in a policy definition"),
14142  errdetail("%s depends on column \"%s\"",
14143  getObjectDescription(&foundObject, false),
14144  colName)));
14145  break;
14146 
14147  case AttrDefaultRelationId:
14148  {
14150 
14151  if (col.objectId == RelationGetRelid(rel) &&
14152  col.objectSubId == attnum)
14153  {
14154  /*
14155  * Ignore the column's own default expression. The
14156  * caller deals with it.
14157  */
14158  }
14159  else
14160  {
14161  /*
14162  * This must be a reference from the expression of a
14163  * generated column elsewhere in the same table.
14164  * Changing the type/generated expression of a column
14165  * that is used by a generated column is not allowed
14166  * by SQL standard, so just punt for now. It might be
14167  * doable with some thinking and effort.
14168  */
14169  if (subtype == AT_AlterColumnType)
14170  ereport(ERROR,
14171  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
14172  errmsg("cannot alter type of a column used by a generated column"),
14173  errdetail("Column \"%s\" is used by generated column \"%s\".",
14174  colName,
14175  get_attname(col.objectId,
14176  col.objectSubId,
14177  false))));
14178  }
14179  break;
14180  }
14181 
14182  case StatisticExtRelationId:
14183 
14184  /*
14185  * Give the extended-stats machinery a chance to fix anything
14186  * that this column type change would break.
14187  */
14188  RememberStatisticsForRebuilding(foundObject.objectId, tab);
14189  break;
14190 
14191  default:
14192 
14193  /*
14194  * We don't expect any other sorts of objects to depend on a
14195  * column.
14196  */
14197  elog(ERROR, "unexpected object depending on column: %s",
14198  getObjectDescription(&foundObject, false));
14199  break;
14200  }
14201  }
14202 
14203  systable_endscan(scan);
14204  table_close(depRel, NoLock);
14205 }
14206 
14207 /*
14208  * Subroutine for ATExecAlterColumnType: remember that a replica identity
14209  * needs to be reset.
14210  */
14211 static void
14213 {
14214  if (!get_index_isreplident(indoid))
14215  return;
14216 
14217  if (tab->replicaIdentityIndex)
14218  elog(ERROR, "relation %u has multiple indexes marked as replica identity", tab->relid);
14219 
14220  tab->replicaIdentityIndex = get_rel_name(indoid);
14221 }
14222 
14223 /*
14224  * Subroutine for ATExecAlterColumnType: remember any clustered index.
14225  */
14226 static void
14228 {
14229  if (!get_index_isclustered(indoid))
14230  return;
14231 
14232  if (tab->clusterOnIndex)
14233  elog(ERROR, "relation %u has multiple clustered indexes", tab->relid);
14234 
14235  tab->clusterOnIndex = get_rel_name(indoid);
14236 }
14237 
14238 /*
14239  * Subroutine for ATExecAlterColumnType: remember that a constraint needs
14240  * to be rebuilt (which we might already know).
14241  */
14242 static void
14244 {
14245  /*
14246  * This de-duplication check is critical for two independent reasons: we
14247  * mustn't try to recreate the same constraint twice, and if a constraint
14248  * depends on more than one column whose type is to be altered, we must
14249  * capture its definition string before applying any of the column type
14250  * changes. ruleutils.c will get confused if we ask again later.
14251  */
14252  if (!list_member_oid(tab->changedConstraintOids, conoid))
14253  {
14254  /* OK, capture the constraint's existing definition string */
14255  char *defstring = pg_get_constraintdef_command(conoid);
14256  Oid indoid;
14257 
14259  conoid);
14261  defstring);
14262 
14263  /*
14264  * For the index of a constraint, if any, remember if it is used for
14265  * the table's replica identity or if it is a clustered index, so that
14266  * ATPostAlterTypeCleanup() can queue up commands necessary to restore
14267  * those properties.
14268  */
14269  indoid = get_constraint_index(conoid);
14270  if (OidIsValid(indoid))
14271  {
14273  RememberClusterOnForRebuilding(indoid, tab);
14274  }
14275  }
14276 }
14277 
14278 /*
14279  * Subroutine for ATExecAlterColumnType: remember that an index needs
14280  * to be rebuilt (which we might already know).
14281  */
14282 static void
14284 {
14285  /*
14286  * This de-duplication check is critical for two independent reasons: we
14287  * mustn't try to recreate the same index twice, and if an index depends
14288  * on more than one column whose type is to be altered, we must capture
14289  * its definition string before applying any of the column type changes.
14290  * ruleutils.c will get confused if we ask again later.
14291  */
14292  if (!list_member_oid(tab->changedIndexOids, indoid))
14293  {
14294  /*
14295  * Before adding it as an index-to-rebuild, we'd better see if it
14296  * belongs to a constraint, and if so rebuild the constraint instead.
14297  * Typically this check fails, because constraint indexes normally
14298  * have only dependencies on their constraint. But it's possible for
14299  * such an index to also have direct dependencies on table columns,
14300  * for example with a partial exclusion constraint.
14301  */
14302  Oid conoid = get_index_constraint(indoid);
14303 
14304  if (OidIsValid(conoid))
14305  {
14306  RememberConstraintForRebuilding(conoid, tab);
14307  }
14308  else
14309  {
14310  /* OK, capture the index's existing definition string */
14311  char *defstring = pg_get_indexdef_string(indoid);
14312 
14314  indoid);
14316  defstring);
14317 
14318  /*
14319  * Remember if this index is used for the table's replica identity
14320  * or if it is a clustered index, so that ATPostAlterTypeCleanup()
14321  * can queue up commands necessary to restore those properties.
14322  */
14324  RememberClusterOnForRebuilding(indoid, tab);
14325  }
14326  }
14327 }
14328 
14329 /*
14330  * Subroutine for ATExecAlterColumnType: remember that a statistics object
14331  * needs to be rebuilt (which we might already know).
14332  */
14333 static void
14335 {
14336  /*
14337  * This de-duplication check is critical for two independent reasons: we
14338  * mustn't try to recreate the same statistics object twice, and if the
14339  * statistics object depends on more than one column whose type is to be
14340  * altered, we must capture its definition string before applying any of
14341  * the type changes. ruleutils.c will get confused if we ask again later.
14342  */
14343  if (!list_member_oid(tab->changedStatisticsOids, stxoid))
14344  {
14345  /* OK, capture the statistics object's existing definition string */
14346  char *defstring = pg_get_statisticsobjdef_string(stxoid);
14347 
14349  stxoid);
14351  defstring);
14352  }
14353 }
14354 
14355 /*
14356  * Cleanup after we've finished all the ALTER TYPE or SET EXPRESSION
14357  * operations for a particular relation. We have to drop and recreate all the
14358  * indexes and constraints that depend on the altered columns. We do the
14359  * actual dropping here, but re-creation is managed by adding work queue
14360  * entries to do those steps later.
14361  */
14362 static void
14364 {
14365  ObjectAddress obj;
14366  ObjectAddresses *objects;
14367  ListCell *def_item;
14368  ListCell *oid_item;
14369 
14370  /*
14371  * Collect all the constraints and indexes to drop so we can process them
14372  * in a single call. That way we don't have to worry about dependencies
14373  * among them.
14374  */
14375  objects = new_object_addresses();
14376 
14377  /*
14378  * Re-parse the index and constraint definitions, and attach them to the
14379  * appropriate work queue entries. We do this before dropping because in
14380  * the case of a FOREIGN KEY constraint, we might not yet have exclusive
14381  * lock on the table the constraint is attached to, and we need to get
14382  * that before reparsing/dropping.
14383  *
14384  * We can't rely on the output of deparsing to tell us which relation to
14385  * operate on, because concurrent activity might have made the name
14386  * resolve differently. Instead, we've got to use the OID of the
14387  * constraint or index we're processing to figure out which relation to
14388  * operate on.
14389  */
14390  forboth(oid_item, tab->changedConstraintOids,
14391  def_item, tab->changedConstraintDefs)
14392  {
14393  Oid oldId = lfirst_oid(oid_item);
14394  HeapTuple tup;
14395  Form_pg_constraint con;
14396  Oid relid;
14397  Oid confrelid;
14398  char contype;
14399  bool conislocal;
14400 
14401  tup = SearchSysCache1(CONSTROID, ObjectIdGetDatum(oldId));
14402  if (!HeapTupleIsValid(tup)) /* should not happen */
14403  elog(ERROR, "cache lookup failed for constraint %u", oldId);
14404  con = (Form_pg_constraint) GETSTRUCT(tup);
14405  if (OidIsValid(con->conrelid))
14406  relid = con->conrelid;
14407  else
14408  {
14409  /* must be a domain constraint */
14410  relid = get_typ_typrelid(getBaseType(con->contypid));
14411  if (!OidIsValid(relid))
14412  elog(ERROR, "could not identify relation associated with constraint %u", oldId);
14413  }
14414  confrelid = con->confrelid;
14415  contype = con->contype;
14416  conislocal = con->conislocal;
14417  ReleaseSysCache(tup);
14418 
14419  ObjectAddressSet(obj, ConstraintRelationId, oldId);
14420  add_exact_object_address(&obj, objects);
14421 
14422  /*
14423  * If the constraint is inherited (only), we don't want to inject a
14424  * new definition here; it'll get recreated when
14425  * ATAddCheckNNConstraint recurses from adding the parent table's
14426  * constraint. But we had to carry the info this far so that we can
14427  * drop the constraint below.
14428  */
14429  if (!conislocal)
14430  continue;
14431 
14432  /*
14433  * When rebuilding an FK constraint that references the table we're
14434  * modifying, we might not yet have any lock on the FK's table, so get
14435  * one now. We'll need AccessExclusiveLock for the DROP CONSTRAINT
14436  * step, so there's no value in asking for anything weaker.
14437  */
14438  if (relid != tab->relid && contype == CONSTRAINT_FOREIGN)
14440 
14441  ATPostAlterTypeParse(oldId, relid, confrelid,
14442  (char *) lfirst(def_item),
14443  wqueue, lockmode, tab->rewrite);
14444  }
14445  forboth(oid_item, tab->changedIndexOids,
14446  def_item, tab->changedIndexDefs)
14447  {
14448  Oid oldId = lfirst_oid(oid_item);
14449  Oid relid;
14450 
14451  relid = IndexGetRelation(oldId, false);
14452  ATPostAlterTypeParse(oldId, relid, InvalidOid,
14453  (char *) lfirst(def_item),
14454  wqueue, lockmode, tab->rewrite);
14455 
14456  ObjectAddressSet(obj, RelationRelationId, oldId);
14457  add_exact_object_address(&obj, objects);
14458  }
14459 
14460  /* add dependencies for new statistics */
14461  forboth(oid_item, tab->changedStatisticsOids,
14462  def_item, tab->changedStatisticsDefs)
14463  {
14464  Oid oldId = lfirst_oid(oid_item);
14465  Oid relid;
14466 
14467  relid = StatisticsGetRelation(oldId, false);
14468  ATPostAlterTypeParse(oldId, relid, InvalidOid,
14469  (char *) lfirst(def_item),
14470  wqueue, lockmode, tab->rewrite);
14471 
14472  ObjectAddressSet(obj, StatisticExtRelationId, oldId);
14473  add_exact_object_address(&obj, objects);
14474  }
14475 
14476  /*
14477  * Queue up command to restore replica identity index marking
14478  */
14479  if (tab->replicaIdentityIndex)
14480  {
14483 
14484  subcmd->identity_type = REPLICA_IDENTITY_INDEX;
14485  subcmd->name = tab->replicaIdentityIndex;
14486  cmd->subtype = AT_ReplicaIdentity;
14487  cmd->def = (Node *) subcmd;
14488 
14489  /* do it after indexes and constraints */
14490  tab->subcmds[AT_PASS_OLD_CONSTR] =
14491  lappend(tab->subcmds[AT_PASS_OLD_CONSTR], cmd);
14492  }
14493 
14494  /*
14495  * Queue up command to restore marking of index used for cluster.
14496  */
14497  if (tab->clusterOnIndex)
14498  {
14500 
14501  cmd->subtype = AT_ClusterOn;
14502  cmd->name = tab->clusterOnIndex;
14503 
14504  /* do it after indexes and constraints */
14505  tab->subcmds[AT_PASS_OLD_CONSTR] =
14506  lappend(tab->subcmds[AT_PASS_OLD_CONSTR], cmd);
14507  }
14508 
14509  /*
14510  * It should be okay to use DROP_RESTRICT here, since nothing else should
14511  * be depending on these objects.
14512  */
14514 
14515  free_object_addresses(objects);
14516 
14517  /*
14518  * The objects will get recreated during subsequent passes over the work
14519  * queue.
14520  */
14521 }
14522 
14523 /*
14524  * Parse the previously-saved definition string for a constraint, index or
14525  * statistics object against the newly-established column data type(s), and
14526  * queue up the resulting command parsetrees for execution.
14527  *
14528  * This might fail if, for example, you have a WHERE clause that uses an
14529  * operator that's not available for the new column type.
14530  */
14531 static void
14532 ATPostAlterTypeParse(Oid oldId, Oid oldRelId, Oid refRelId, char *cmd,
14533  List **wqueue, LOCKMODE lockmode, bool rewrite)
14534 {
14535  List *raw_parsetree_list;
14536  List *querytree_list;
14537  ListCell *list_item;
14538  Relation rel;
14539 
14540  /*
14541  * We expect that we will get only ALTER TABLE and CREATE INDEX
14542  * statements. Hence, there is no need to pass them through
14543  * parse_analyze_*() or the rewriter, but instead we need to pass them
14544  * through parse_utilcmd.c to make them ready for execution.
14545  */
14546  raw_parsetree_list = raw_parser(cmd, RAW_PARSE_DEFAULT);
14547  querytree_list = NIL;
14548  foreach(list_item, raw_parsetree_list)
14549  {
14550  RawStmt *rs = lfirst_node(RawStmt, list_item);
14551  Node *stmt = rs->stmt;
14552 
14553  if (IsA(stmt, IndexStmt))
14554  querytree_list = lappend(querytree_list,
14555  transformIndexStmt(oldRelId,
14556  (IndexStmt *) stmt,
14557  cmd));
14558  else if (IsA(stmt, AlterTableStmt))
14559  {
14560  List *beforeStmts;
14561  List *afterStmts;
14562 
14563  stmt = (Node *) transformAlterTableStmt(oldRelId,
14564  (AlterTableStmt *) stmt,
14565  cmd,
14566  &beforeStmts,
14567  &afterStmts);
14568  querytree_list = list_concat(querytree_list, beforeStmts);
14569  querytree_list = lappend(querytree_list, stmt);
14570  querytree_list = list_concat(querytree_list, afterStmts);
14571  }
14572  else if (IsA(stmt, CreateStatsStmt))
14573  querytree_list = lappend(querytree_list,
14574  transformStatsStmt(oldRelId,
14575  (CreateStatsStmt *) stmt,
14576  cmd));
14577  else
14578  querytree_list = lappend(querytree_list, stmt);
14579  }
14580 
14581  /* Caller should already have acquired whatever lock we need. */
14582  rel = relation_open(oldRelId, NoLock);
14583 
14584  /*
14585  * Attach each generated command to the proper place in the work queue.
14586  * Note this could result in creation of entirely new work-queue entries.
14587  *
14588  * Also note that we have to tweak the command subtypes, because it turns
14589  * out that re-creation of indexes and constraints has to act a bit
14590  * differently from initial creation.
14591  */
14592  foreach(list_item, querytree_list)
14593  {
14594  Node *stm = (Node *) lfirst(list_item);
14595  AlteredTableInfo *tab;
14596 
14597  tab = ATGetQueueEntry(wqueue, rel);
14598 
14599  if (IsA(stm, IndexStmt))
14600  {
14601  IndexStmt *stmt = (IndexStmt *) stm;
14602  AlterTableCmd *newcmd;
14603 
14604  if (!rewrite)
14605  TryReuseIndex(oldId, stmt);
14606  stmt->reset_default_tblspc = true;
14607  /* keep the index's comment */
14608  stmt->idxcomment = GetComment(oldId, RelationRelationId, 0);
14609 
14610  newcmd = makeNode(AlterTableCmd);
14611  newcmd->subtype = AT_ReAddIndex;
14612  newcmd->def = (Node *) stmt;
14613  tab->subcmds[AT_PASS_OLD_INDEX] =
14614  lappend(tab->subcmds[AT_PASS_OLD_INDEX], newcmd);
14615  }
14616  else if (IsA(stm, AlterTableStmt))
14617  {
14618  AlterTableStmt *stmt = (AlterTableStmt *) stm;
14619  ListCell *lcmd;
14620 
14621  foreach(lcmd, stmt->cmds)
14622  {
14623  AlterTableCmd *cmd = lfirst_node(AlterTableCmd, lcmd);
14624 
14625  if (cmd->subtype == AT_AddIndex)
14626  {
14627  IndexStmt *indstmt;
14628  Oid indoid;
14629 
14630  indstmt = castNode(IndexStmt, cmd->def);
14631  indoid = get_constraint_index(oldId);
14632 
14633  if (!rewrite)
14634  TryReuseIndex(indoid, indstmt);
14635  /* keep any comment on the index */
14636  indstmt->idxcomment = GetComment(indoid,
14637  RelationRelationId, 0);
14638  indstmt->reset_default_tblspc = true;
14639 
14640  cmd->subtype = AT_ReAddIndex;
14641  tab->subcmds[AT_PASS_OLD_INDEX] =
14642  lappend(tab->subcmds[AT_PASS_OLD_INDEX], cmd);
14643 
14644  /* recreate any comment on the constraint */
14647  oldId,
14648  rel,
14649  NIL,
14650  indstmt->idxname);
14651  }
14652  else if (cmd->subtype == AT_AddConstraint)
14653  {
14654  Constraint *con = castNode(Constraint, cmd->def);
14655 
14656  con->old_pktable_oid = refRelId;
14657  /* rewriting neither side of a FK */
14658  if (con->contype == CONSTR_FOREIGN &&
14659  !rewrite && tab->rewrite == 0)
14660  TryReuseForeignKey(oldId, con);
14661  con->reset_default_tblspc = true;
14662  cmd->subtype = AT_ReAddConstraint;
14663  tab->subcmds[AT_PASS_OLD_CONSTR] =
14664  lappend(tab->subcmds[AT_PASS_OLD_CONSTR], cmd);
14665 
14666  /* recreate any comment on the constraint */
14669  oldId,
14670  rel,
14671  NIL,
14672  con->conname);
14673  }
14674  else if (cmd->subtype == AT_SetAttNotNull)
14675  {
14676  /*
14677  * We see this subtype when a primary key is created
14678  * internally, for example when it is replaced with a new
14679  * constraint (say because one of the columns changes
14680  * type); in this case we need to reinstate attnotnull,
14681  * because it was removed because of the drop of the old
14682  * PK. Schedule this subcommand to an upcoming AT pass.
14683  */
14684  cmd->subtype = AT_SetAttNotNull;
14687  }
14688  else
14689  elog(ERROR, "unexpected statement subtype: %d",
14690  (int) cmd->subtype);
14691  }
14692  }
14693  else if (IsA(stm, AlterDomainStmt))
14694  {
14696 
14697  if (stmt->subtype == 'C') /* ADD CONSTRAINT */
14698  {
14699  Constraint *con = castNode(Constraint, stmt->def);
14701 
14703  cmd->def = (Node *) stmt;
14704  tab->subcmds[AT_PASS_OLD_CONSTR] =
14705  lappend(tab->subcmds[AT_PASS_OLD_CONSTR], cmd);
14706 
14707  /* recreate any comment on the constraint */
14710  oldId,
14711  NULL,
14712  stmt->typeName,
14713  con->conname);
14714  }
14715  else
14716  elog(ERROR, "unexpected statement subtype: %d",
14717  (int) stmt->subtype);
14718  }
14719  else if (IsA(stm, CreateStatsStmt))
14720  {
14722  AlterTableCmd *newcmd;
14723 
14724  /* keep the statistics object's comment */
14725  stmt->stxcomment = GetComment(oldId, StatisticExtRelationId, 0);
14726 
14727  newcmd = makeNode(AlterTableCmd);
14728  newcmd->subtype = AT_ReAddStatistics;
14729  newcmd->def = (Node *) stmt;
14730  tab->subcmds[AT_PASS_MISC] =
14731  lappend(tab->subcmds[AT_PASS_MISC], newcmd);
14732  }
14733  else
14734  elog(ERROR, "unexpected statement type: %d",
14735  (int) nodeTag(stm));
14736  }
14737 
14738  relation_close(rel, NoLock);
14739 }
14740 
14741 /*
14742  * Subroutine for ATPostAlterTypeParse() to recreate any existing comment
14743  * for a table or domain constraint that is being rebuilt.
14744  *
14745  * objid is the OID of the constraint.
14746  * Pass "rel" for a table constraint, or "domname" (domain's qualified name
14747  * as a string list) for a domain constraint.
14748  * (We could dig that info, as well as the conname, out of the pg_constraint
14749  * entry; but callers already have them so might as well pass them.)
14750  */
14751 static void
14753  Relation rel, List *domname,
14754  const char *conname)
14755 {
14756  CommentStmt *cmd;
14757  char *comment_str;
14758  AlterTableCmd *newcmd;
14759 
14760  /* Look for comment for object wanted, and leave if none */
14761  comment_str = GetComment(objid, ConstraintRelationId, 0);
14762  if (comment_str == NULL)
14763  return;
14764 
14765  /* Build CommentStmt node, copying all input data for safety */
14766  cmd = makeNode(CommentStmt);
14767  if (rel)
14768  {
14770  cmd->object = (Node *)
14773  makeString(pstrdup(conname)));
14774  }
14775  else
14776  {
14778  cmd->object = (Node *)
14780  makeString(pstrdup(conname)));
14781  }
14782  cmd->comment = comment_str;
14783 
14784  /* Append it to list of commands */
14785  newcmd = makeNode(AlterTableCmd);
14786  newcmd->subtype = AT_ReAddComment;
14787  newcmd->def = (Node *) cmd;
14788  tab->subcmds[pass] = lappend(tab->subcmds[pass], newcmd);
14789 }
14790 
14791 /*
14792  * Subroutine for ATPostAlterTypeParse(). Calls out to CheckIndexCompatible()
14793  * for the real analysis, then mutates the IndexStmt based on that verdict.
14794  */
14795 static void
14797 {
14798  if (CheckIndexCompatible(oldId,
14799  stmt->accessMethod,
14800  stmt->indexParams,
14801  stmt->excludeOpNames,
14802  stmt->iswithoutoverlaps))
14803  {
14804  Relation irel = index_open(oldId, NoLock);
14805 
14806  /* If it's a partitioned index, there is no storage to share. */
14807  if (irel->rd_rel->relkind != RELKIND_PARTITIONED_INDEX)
14808  {
14809  stmt->oldNumber = irel->rd_locator.relNumber;
14810  stmt->oldCreateSubid = irel->rd_createSubid;
14811  stmt->oldFirstRelfilelocatorSubid = irel->rd_firstRelfilelocatorSubid;
14812  }
14813  index_close(irel, NoLock);
14814  }
14815 }
14816 
14817 /*
14818  * Subroutine for ATPostAlterTypeParse().
14819  *
14820  * Stash the old P-F equality operator into the Constraint node, for possible
14821  * use by ATAddForeignKeyConstraint() in determining whether revalidation of
14822  * this constraint can be skipped.
14823  */
14824 static void
14826 {
14827  HeapTuple tup;
14828  Datum adatum;
14829  ArrayType *arr;
14830  Oid *rawarr;
14831  int numkeys;
14832  int i;
14833 
14834  Assert(con->contype == CONSTR_FOREIGN);
14835  Assert(con->old_conpfeqop == NIL); /* already prepared this node */
14836 
14837  tup = SearchSysCache1(CONSTROID, ObjectIdGetDatum(oldId));
14838  if (!HeapTupleIsValid(tup)) /* should not happen */
14839  elog(ERROR, "cache lookup failed for constraint %u", oldId);
14840 
14841  adatum = SysCacheGetAttrNotNull(CONSTROID, tup,
14842  Anum_pg_constraint_conpfeqop);
14843  arr = DatumGetArrayTypeP(adatum); /* ensure not toasted */
14844  numkeys = ARR_DIMS(arr)[0];
14845  /* test follows the one in ri_FetchConstraintInfo() */
14846  if (ARR_NDIM(arr) != 1 ||
14847  ARR_HASNULL(arr) ||
14848  ARR_ELEMTYPE(arr) != OIDOID)
14849  elog(ERROR, "conpfeqop is not a 1-D Oid array");
14850  rawarr = (Oid *) ARR_DATA_PTR(arr);
14851 
14852  /* stash a List of the operator Oids in our Constraint node */
14853  for (i = 0; i < numkeys; i++)
14854  con->old_conpfeqop = lappend_oid(con->old_conpfeqop, rawarr[i]);
14855 
14856  ReleaseSysCache(tup);
14857 }
14858 
14859 /*
14860  * ALTER COLUMN .. OPTIONS ( ... )
14861  *
14862  * Returns the address of the modified column
14863  */
14864 static ObjectAddress
14866  const char *colName,
14867  List *options,
14868  LOCKMODE lockmode)
14869 {
14870  Relation ftrel;
14871  Relation attrel;
14872  ForeignServer *server;
14873  ForeignDataWrapper *fdw;
14874  HeapTuple tuple;
14875  HeapTuple newtuple;
14876  bool isnull;
14877  Datum repl_val[Natts_pg_attribute];
14878  bool repl_null[Natts_pg_attribute];
14879  bool repl_repl[Natts_pg_attribute];
14880  Datum datum;
14881  Form_pg_foreign_table fttableform;
14882  Form_pg_attribute atttableform;
14884  ObjectAddress address;
14885 
14886  if (options == NIL)
14887  return InvalidObjectAddress;
14888 
14889  /* First, determine FDW validator associated to the foreign table. */
14890  ftrel = table_open(ForeignTableRelationId, AccessShareLock);
14891  tuple = SearchSysCache1(FOREIGNTABLEREL, ObjectIdGetDatum(rel->rd_id));
14892  if (!HeapTupleIsValid(tuple))
14893  ereport(ERROR,
14894  (errcode(ERRCODE_UNDEFINED_OBJECT),
14895  errmsg("foreign table \"%s\" does not exist",
14896  RelationGetRelationName(rel))));
14897  fttableform = (Form_pg_foreign_table) GETSTRUCT(tuple);
14898  server = GetForeignServer(fttableform->ftserver);
14899  fdw = GetForeignDataWrapper(server->fdwid);
14900 
14901  table_close(ftrel, AccessShareLock);
14902  ReleaseSysCache(tuple);
14903 
14904  attrel = table_open(AttributeRelationId, RowExclusiveLock);
14905  tuple = SearchSysCacheAttName(RelationGetRelid(rel), colName);
14906  if (!HeapTupleIsValid(tuple))
14907  ereport(ERROR,
14908  (errcode(ERRCODE_UNDEFINED_COLUMN),
14909  errmsg("column \"%s\" of relation \"%s\" does not exist",
14910  colName, RelationGetRelationName(rel))));
14911 
14912  /* Prevent them from altering a system attribute */
14913  atttableform = (Form_pg_attribute) GETSTRUCT(tuple);
14914  attnum = atttableform->attnum;
14915  if (attnum <= 0)
14916  ereport(ERROR,
14917  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
14918  errmsg("cannot alter system column \"%s\"", colName)));
14919 
14920 
14921  /* Initialize buffers for new tuple values */
14922  memset(repl_val, 0, sizeof(repl_val));
14923  memset(repl_null, false, sizeof(repl_null));
14924  memset(repl_repl, false, sizeof(repl_repl));
14925 
14926  /* Extract the current options */
14927  datum = SysCacheGetAttr(ATTNAME,
14928  tuple,
14929  Anum_pg_attribute_attfdwoptions,
14930  &isnull);
14931  if (isnull)
14932  datum = PointerGetDatum(NULL);
14933 
14934  /* Transform the options */
14935  datum = transformGenericOptions(AttributeRelationId,
14936  datum,
14937  options,
14938  fdw->fdwvalidator);
14939 
14940  if (PointerIsValid(DatumGetPointer(datum)))
14941  repl_val[Anum_pg_attribute_attfdwoptions - 1] = datum;
14942  else
14943  repl_null[Anum_pg_attribute_attfdwoptions - 1] = true;
14944 
14945  repl_repl[Anum_pg_attribute_attfdwoptions - 1] = true;
14946 
14947  /* Everything looks good - update the tuple */
14948 
14949  newtuple = heap_modify_tuple(tuple, RelationGetDescr(attrel),
14950  repl_val, repl_null, repl_repl);
14951 
14952  CatalogTupleUpdate(attrel, &newtuple->t_self, newtuple);
14953 
14954  InvokeObjectPostAlterHook(RelationRelationId,
14955  RelationGetRelid(rel),
14956  atttableform->attnum);
14957  ObjectAddressSubSet(address, RelationRelationId,
14958  RelationGetRelid(rel), attnum);
14959 
14960  ReleaseSysCache(tuple);
14961 
14962  table_close(attrel, RowExclusiveLock);
14963 
14964  heap_freetuple(newtuple);
14965 
14966  return address;
14967 }
14968 
14969 /*
14970  * ALTER TABLE OWNER
14971  *
14972  * recursing is true if we are recursing from a table to its indexes,
14973  * sequences, or toast table. We don't allow the ownership of those things to
14974  * be changed separately from the parent table. Also, we can skip permission
14975  * checks (this is necessary not just an optimization, else we'd fail to
14976  * handle toast tables properly).
14977  *
14978  * recursing is also true if ALTER TYPE OWNER is calling us to fix up a
14979  * free-standing composite type.
14980  */
14981 void
14982 ATExecChangeOwner(Oid relationOid, Oid newOwnerId, bool recursing, LOCKMODE lockmode)
14983 {
14984  Relation target_rel;
14985  Relation class_rel;
14986  HeapTuple tuple;
14987  Form_pg_class tuple_class;
14988 
14989  /*
14990  * Get exclusive lock till end of transaction on the target table. Use
14991  * relation_open so that we can work on indexes and sequences.
14992  */
14993  target_rel = relation_open(relationOid, lockmode);
14994 
14995  /* Get its pg_class tuple, too */
14996  class_rel = table_open(RelationRelationId, RowExclusiveLock);
14997 
14998  tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relationOid));
14999  if (!HeapTupleIsValid(tuple))
15000  elog(ERROR, "cache lookup failed for relation %u", relationOid);
15001  tuple_class = (Form_pg_class) GETSTRUCT(tuple);
15002 
15003  /* Can we change the ownership of this tuple? */
15004  switch (tuple_class->relkind)
15005  {
15006  case RELKIND_RELATION:
15007  case RELKIND_VIEW:
15008  case RELKIND_MATVIEW:
15009  case RELKIND_FOREIGN_TABLE:
15010  case RELKIND_PARTITIONED_TABLE:
15011  /* ok to change owner */
15012  break;
15013  case RELKIND_INDEX:
15014  if (!recursing)
15015  {
15016  /*
15017  * Because ALTER INDEX OWNER used to be allowed, and in fact
15018  * is generated by old versions of pg_dump, we give a warning
15019  * and do nothing rather than erroring out. Also, to avoid
15020  * unnecessary chatter while restoring those old dumps, say
15021  * nothing at all if the command would be a no-op anyway.
15022  */
15023  if (tuple_class->relowner != newOwnerId)
15024  ereport(WARNING,
15025  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
15026  errmsg("cannot change owner of index \"%s\"",
15027  NameStr(tuple_class->relname)),
15028  errhint("Change the ownership of the index's table instead.")));
15029  /* quick hack to exit via the no-op path */
15030  newOwnerId = tuple_class->relowner;
15031  }
15032  break;
15033  case RELKIND_PARTITIONED_INDEX:
15034  if (recursing)
15035  break;
15036  ereport(ERROR,
15037  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
15038  errmsg("cannot change owner of index \"%s\"",
15039  NameStr(tuple_class->relname)),
15040  errhint("Change the ownership of the index's table instead.")));
15041  break;
15042  case RELKIND_SEQUENCE:
15043  if (!recursing &&
15044  tuple_class->relowner != newOwnerId)
15045  {
15046  /* if it's an owned sequence, disallow changing it by itself */
15047  Oid tableId;
15048  int32 colId;
15049 
15050  if (sequenceIsOwned(relationOid, DEPENDENCY_AUTO, &tableId, &colId) ||
15051  sequenceIsOwned(relationOid, DEPENDENCY_INTERNAL, &tableId, &colId))
15052  ereport(ERROR,
15053  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
15054  errmsg("cannot change owner of sequence \"%s\"",
15055  NameStr(tuple_class->relname)),
15056  errdetail("Sequence \"%s\" is linked to table \"%s\".",
15057  NameStr(tuple_class->relname),
15058  get_rel_name(tableId))));
15059  }
15060  break;
15061  case RELKIND_COMPOSITE_TYPE:
15062  if (recursing)
15063  break;
15064  ereport(ERROR,
15065  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
15066  errmsg("\"%s\" is a composite type",
15067  NameStr(tuple_class->relname)),
15068  /* translator: %s is an SQL ALTER command */
15069  errhint("Use %s instead.",
15070  "ALTER TYPE")));
15071  break;
15072  case RELKIND_TOASTVALUE:
15073  if (recursing)
15074  break;
15075  /* FALL THRU */
15076  default:
15077  ereport(ERROR,
15078  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
15079  errmsg("cannot change owner of relation \"%s\"",
15080  NameStr(tuple_class->relname)),
15081  errdetail_relkind_not_supported(tuple_class->relkind)));
15082  }
15083 
15084  /*
15085  * If the new owner is the same as the existing owner, consider the
15086  * command to have succeeded. This is for dump restoration purposes.
15087  */
15088  if (tuple_class->relowner != newOwnerId)
15089  {
15090  Datum repl_val[Natts_pg_class];
15091  bool repl_null[Natts_pg_class];
15092  bool repl_repl[Natts_pg_class];
15093  Acl *newAcl;
15094  Datum aclDatum;
15095  bool isNull;
15096  HeapTuple newtuple;
15097 
15098  /* skip permission checks when recursing to index or toast table */
15099  if (!recursing)
15100  {
15101  /* Superusers can always do it */
15102  if (!superuser())
15103  {
15104  Oid namespaceOid = tuple_class->relnamespace;
15105  AclResult aclresult;
15106 
15107  /* Otherwise, must be owner of the existing object */
15108  if (!object_ownercheck(RelationRelationId, relationOid, GetUserId()))
15110  RelationGetRelationName(target_rel));
15111 
15112  /* Must be able to become new owner */
15113  check_can_set_role(GetUserId(), newOwnerId);
15114 
15115  /* New owner must have CREATE privilege on namespace */
15116  aclresult = object_aclcheck(NamespaceRelationId, namespaceOid, newOwnerId,
15117  ACL_CREATE);
15118  if (aclresult != ACLCHECK_OK)
15119  aclcheck_error(aclresult, OBJECT_SCHEMA,
15120  get_namespace_name(namespaceOid));
15121  }
15122  }
15123 
15124  memset(repl_null, false, sizeof(repl_null));
15125  memset(repl_repl, false, sizeof(repl_repl));
15126 
15127  repl_repl[Anum_pg_class_relowner - 1] = true;
15128  repl_val[Anum_pg_class_relowner - 1] = ObjectIdGetDatum(newOwnerId);
15129 
15130  /*
15131  * Determine the modified ACL for the new owner. This is only
15132  * necessary when the ACL is non-null.
15133  */
15134  aclDatum = SysCacheGetAttr(RELOID, tuple,
15135  Anum_pg_class_relacl,
15136  &isNull);
15137  if (!isNull)
15138  {
15139  newAcl = aclnewowner(DatumGetAclP(aclDatum),
15140  tuple_class->relowner, newOwnerId);
15141  repl_repl[Anum_pg_class_relacl - 1] = true;
15142  repl_val[Anum_pg_class_relacl - 1] = PointerGetDatum(newAcl);
15143  }
15144 
15145  newtuple = heap_modify_tuple(tuple, RelationGetDescr(class_rel), repl_val, repl_null, repl_repl);
15146 
15147  CatalogTupleUpdate(class_rel, &newtuple->t_self, newtuple);
15148 
15149  heap_freetuple(newtuple);
15150 
15151  /*
15152  * We must similarly update any per-column ACLs to reflect the new
15153  * owner; for neatness reasons that's split out as a subroutine.
15154  */
15155  change_owner_fix_column_acls(relationOid,
15156  tuple_class->relowner,
15157  newOwnerId);
15158 
15159  /*
15160  * Update owner dependency reference, if any. A composite type has
15161  * none, because it's tracked for the pg_type entry instead of here;
15162  * indexes and TOAST tables don't have their own entries either.
15163  */
15164  if (tuple_class->relkind != RELKIND_COMPOSITE_TYPE &&
15165  tuple_class->relkind != RELKIND_INDEX &&
15166  tuple_class->relkind != RELKIND_PARTITIONED_INDEX &&
15167  tuple_class->relkind != RELKIND_TOASTVALUE)
15168  changeDependencyOnOwner(RelationRelationId, relationOid,
15169  newOwnerId);
15170 
15171  /*
15172  * Also change the ownership of the table's row type, if it has one
15173  */
15174  if (OidIsValid(tuple_class->reltype))
15175  AlterTypeOwnerInternal(tuple_class->reltype, newOwnerId);
15176 
15177  /*
15178  * If we are operating on a table or materialized view, also change
15179  * the ownership of any indexes and sequences that belong to the
15180  * relation, as well as its toast table (if it has one).
15181  */
15182  if (tuple_class->relkind == RELKIND_RELATION ||
15183  tuple_class->relkind == RELKIND_PARTITIONED_TABLE ||
15184  tuple_class->relkind == RELKIND_MATVIEW ||
15185  tuple_class->relkind == RELKIND_TOASTVALUE)
15186  {
15187  List *index_oid_list;
15188  ListCell *i;
15189 
15190  /* Find all the indexes belonging to this relation */
15191  index_oid_list = RelationGetIndexList(target_rel);
15192 
15193  /* For each index, recursively change its ownership */
15194  foreach(i, index_oid_list)
15195  ATExecChangeOwner(lfirst_oid(i), newOwnerId, true, lockmode);
15196 
15197  list_free(index_oid_list);
15198  }
15199 
15200  /* If it has a toast table, recurse to change its ownership */
15201  if (tuple_class->reltoastrelid != InvalidOid)
15202  ATExecChangeOwner(tuple_class->reltoastrelid, newOwnerId,
15203  true, lockmode);
15204 
15205  /* If it has dependent sequences, recurse to change them too */
15206  change_owner_recurse_to_sequences(relationOid, newOwnerId, lockmode);
15207  }
15208 
15209  InvokeObjectPostAlterHook(RelationRelationId, relationOid, 0);
15210 
15211  ReleaseSysCache(tuple);
15212  table_close(class_rel, RowExclusiveLock);
15213  relation_close(target_rel, NoLock);
15214 }
15215 
15216 /*
15217  * change_owner_fix_column_acls
15218  *
15219  * Helper function for ATExecChangeOwner. Scan the columns of the table
15220  * and fix any non-null column ACLs to reflect the new owner.
15221  */
15222 static void
15223 change_owner_fix_column_acls(Oid relationOid, Oid oldOwnerId, Oid newOwnerId)
15224 {
15225  Relation attRelation;
15226  SysScanDesc scan;
15227  ScanKeyData key[1];
15228  HeapTuple attributeTuple;
15229 
15230  attRelation = table_open(AttributeRelationId, RowExclusiveLock);
15231  ScanKeyInit(&key[0],
15232  Anum_pg_attribute_attrelid,
15233  BTEqualStrategyNumber, F_OIDEQ,
15234  ObjectIdGetDatum(relationOid));
15235  scan = systable_beginscan(attRelation, AttributeRelidNumIndexId,
15236  true, NULL, 1, key);
15237  while (HeapTupleIsValid(attributeTuple = systable_getnext(scan)))
15238  {
15239  Form_pg_attribute att = (Form_pg_attribute) GETSTRUCT(attributeTuple);
15240  Datum repl_val[Natts_pg_attribute];
15241  bool repl_null[Natts_pg_attribute];
15242  bool repl_repl[Natts_pg_attribute];
15243  Acl *newAcl;
15244  Datum aclDatum;
15245  bool isNull;
15246  HeapTuple newtuple;
15247 
15248  /* Ignore dropped columns */
15249  if (att->attisdropped)
15250  continue;
15251 
15252  aclDatum = heap_getattr(attributeTuple,
15253  Anum_pg_attribute_attacl,
15254  RelationGetDescr(attRelation),
15255  &isNull);
15256  /* Null ACLs do not require changes */
15257  if (isNull)
15258  continue;
15259 
15260  memset(repl_null, false, sizeof(repl_null));
15261  memset(repl_repl, false, sizeof(repl_repl));
15262 
15263  newAcl = aclnewowner(DatumGetAclP(aclDatum),
15264  oldOwnerId, newOwnerId);
15265  repl_repl[Anum_pg_attribute_attacl - 1] = true;
15266  repl_val[Anum_pg_attribute_attacl - 1] = PointerGetDatum(newAcl);
15267 
15268  newtuple = heap_modify_tuple(attributeTuple,
15269  RelationGetDescr(attRelation),
15270  repl_val, repl_null, repl_repl);
15271 
15272  CatalogTupleUpdate(attRelation, &newtuple->t_self, newtuple);
15273 
15274  heap_freetuple(newtuple);
15275  }
15276  systable_endscan(scan);
15277  table_close(attRelation, RowExclusiveLock);
15278 }
15279 
15280 /*
15281  * change_owner_recurse_to_sequences
15282  *
15283  * Helper function for ATExecChangeOwner. Examines pg_depend searching
15284  * for sequences that are dependent on serial columns, and changes their
15285  * ownership.
15286  */
15287 static void
15288 change_owner_recurse_to_sequences(Oid relationOid, Oid newOwnerId, LOCKMODE lockmode)
15289 {
15290  Relation depRel;
15291  SysScanDesc scan;
15292  ScanKeyData key[2];
15293  HeapTuple tup;
15294 
15295  /*
15296  * SERIAL sequences are those having an auto dependency on one of the
15297  * table's columns (we don't care *which* column, exactly).
15298  */
15299  depRel = table_open(DependRelationId, AccessShareLock);
15300 
15301  ScanKeyInit(&key[0],
15302  Anum_pg_depend_refclassid,
15303  BTEqualStrategyNumber, F_OIDEQ,
15304  ObjectIdGetDatum(RelationRelationId));
15305  ScanKeyInit(&key[1],
15306  Anum_pg_depend_refobjid,
15307  BTEqualStrategyNumber, F_OIDEQ,
15308  ObjectIdGetDatum(relationOid));
15309  /* we leave refobjsubid unspecified */
15310 
15311  scan = systable_beginscan(depRel, DependReferenceIndexId, true,
15312  NULL, 2, key);
15313 
15314  while (HeapTupleIsValid(tup = systable_getnext(scan)))
15315  {
15316  Form_pg_depend depForm = (Form_pg_depend) GETSTRUCT(tup);
15317  Relation seqRel;
15318 
15319  /* skip dependencies other than auto dependencies on columns */
15320  if (depForm->refobjsubid == 0 ||
15321  depForm->classid != RelationRelationId ||
15322  depForm->objsubid != 0 ||
15323  !(depForm->deptype == DEPENDENCY_AUTO || depForm->deptype == DEPENDENCY_INTERNAL))
15324  continue;
15325 
15326  /* Use relation_open just in case it's an index */
15327  seqRel = relation_open(depForm->objid, lockmode);
15328 
15329  /* skip non-sequence relations */
15330  if (RelationGetForm(seqRel)->relkind != RELKIND_SEQUENCE)
15331  {
15332  /* No need to keep the lock */
15333  relation_close(seqRel, lockmode);
15334  continue;
15335  }
15336 
15337  /* We don't need to close the sequence while we alter it. */
15338  ATExecChangeOwner(depForm->objid, newOwnerId, true, lockmode);
15339 
15340  /* Now we can close it. Keep the lock till end of transaction. */
15341  relation_close(seqRel, NoLock);
15342  }
15343 
15344  systable_endscan(scan);
15345 
15347 }
15348 
15349 /*
15350  * ALTER TABLE CLUSTER ON
15351  *
15352  * The only thing we have to do is to change the indisclustered bits.
15353  *
15354  * Return the address of the new clustering index.
15355  */
15356 static ObjectAddress
15357 ATExecClusterOn(Relation rel, const char *indexName, LOCKMODE lockmode)
15358 {
15359  Oid indexOid;
15360  ObjectAddress address;
15361 
15362  indexOid = get_relname_relid(indexName, rel->rd_rel->relnamespace);
15363 
15364  if (!OidIsValid(indexOid))
15365  ereport(ERROR,
15366  (errcode(ERRCODE_UNDEFINED_OBJECT),
15367  errmsg("index \"%s\" for table \"%s\" does not exist",
15368  indexName, RelationGetRelationName(rel))));
15369 
15370  /* Check index is valid to cluster on */
15371  check_index_is_clusterable(rel, indexOid, lockmode);
15372 
15373  /* And do the work */
15374  mark_index_clustered(rel, indexOid, false);
15375 
15376  ObjectAddressSet(address,
15377  RelationRelationId, indexOid);
15378 
15379  return address;
15380 }
15381 
15382 /*
15383  * ALTER TABLE SET WITHOUT CLUSTER
15384  *
15385  * We have to find any indexes on the table that have indisclustered bit
15386  * set and turn it off.
15387  */
15388 static void
15390 {
15391  mark_index_clustered(rel, InvalidOid, false);
15392 }
15393 
15394 /*
15395  * Preparation phase for SET ACCESS METHOD
15396  *
15397  * Check that the access method exists and determine whether a change is
15398  * actually needed.
15399  */
15400 static void
15401 ATPrepSetAccessMethod(AlteredTableInfo *tab, Relation rel, const char *amname)
15402 {
15403  Oid amoid;
15404 
15405  /*
15406  * Look up the access method name and check that it differs from the
15407  * table's current AM. If DEFAULT was specified for a partitioned table
15408  * (amname is NULL), set it to InvalidOid to reset the catalogued AM.
15409  */
15410  if (amname != NULL)
15411  amoid = get_table_am_oid(amname, false);
15412  else if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
15413  amoid = InvalidOid;
15414  else
15416 
15417  /* if it's a match, phase 3 doesn't need to do anything */
15418  if (rel->rd_rel->relam == amoid)
15419  return;
15420 
15421  /* Save info for Phase 3 to do the real work */
15423  tab->newAccessMethod = amoid;
15424  tab->chgAccessMethod = true;
15425 }
15426 
15427 /*
15428  * Special handling of ALTER TABLE SET ACCESS METHOD for relations with no
15429  * storage that have an interest in preserving AM.
15430  *
15431  * Since these have no storage, setting the access method is a catalog only
15432  * operation.
15433  */
15434 static void
15436 {
15437  Relation pg_class;
15438  Oid oldAccessMethodId;
15439  HeapTuple tuple;
15440  Form_pg_class rd_rel;
15441  Oid reloid = RelationGetRelid(rel);
15442 
15443  /*
15444  * Shouldn't be called on relations having storage; these are processed in
15445  * phase 3.
15446  */
15447  Assert(!RELKIND_HAS_STORAGE(rel->rd_rel->relkind));
15448 
15449  /* Get a modifiable copy of the relation's pg_class row. */
15450  pg_class = table_open(RelationRelationId, RowExclusiveLock);
15451 
15452  tuple = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(reloid));
15453  if (!HeapTupleIsValid(tuple))
15454  elog(ERROR, "cache lookup failed for relation %u", reloid);
15455  rd_rel = (Form_pg_class) GETSTRUCT(tuple);
15456 
15457  /* Update the pg_class row. */
15458  oldAccessMethodId = rd_rel->relam;
15459  rd_rel->relam = newAccessMethodId;
15460 
15461  /* Leave if no update required */
15462  if (rd_rel->relam == oldAccessMethodId)
15463  {
15464  heap_freetuple(tuple);
15465  table_close(pg_class, RowExclusiveLock);
15466  return;
15467  }
15468 
15469  CatalogTupleUpdate(pg_class, &tuple->t_self, tuple);
15470 
15471  /*
15472  * Update the dependency on the new access method. No dependency is added
15473  * if the new access method is InvalidOid (default case). Be very careful
15474  * that this has to compare the previous value stored in pg_class with the
15475  * new one.
15476  */
15477  if (!OidIsValid(oldAccessMethodId) && OidIsValid(rd_rel->relam))
15478  {
15479  ObjectAddress relobj,
15480  referenced;
15481 
15482  /*
15483  * New access method is defined and there was no dependency
15484  * previously, so record a new one.
15485  */
15486  ObjectAddressSet(relobj, RelationRelationId, reloid);
15487  ObjectAddressSet(referenced, AccessMethodRelationId, rd_rel->relam);
15488  recordDependencyOn(&relobj, &referenced, DEPENDENCY_NORMAL);
15489  }
15490  else if (OidIsValid(oldAccessMethodId) &&
15491  !OidIsValid(rd_rel->relam))
15492  {
15493  /*
15494  * There was an access method defined, and no new one, so just remove
15495  * the existing dependency.
15496  */
15497  deleteDependencyRecordsForClass(RelationRelationId, reloid,
15498  AccessMethodRelationId,
15500  }
15501  else
15502  {
15503  Assert(OidIsValid(oldAccessMethodId) &&
15504  OidIsValid(rd_rel->relam));
15505 
15506  /* Both are valid, so update the dependency */
15507  changeDependencyFor(RelationRelationId, reloid,
15508  AccessMethodRelationId,
15509  oldAccessMethodId, rd_rel->relam);
15510  }
15511 
15512  /* make the relam and dependency changes visible */
15514 
15515  InvokeObjectPostAlterHook(RelationRelationId, RelationGetRelid(rel), 0);
15516 
15517  heap_freetuple(tuple);
15518  table_close(pg_class, RowExclusiveLock);
15519 }
15520 
15521 /*
15522  * ALTER TABLE SET TABLESPACE
15523  */
15524 static void
15525 ATPrepSetTableSpace(AlteredTableInfo *tab, Relation rel, const char *tablespacename, LOCKMODE lockmode)
15526 {
15527  Oid tablespaceId;
15528 
15529  /* Check that the tablespace exists */
15530  tablespaceId = get_tablespace_oid(tablespacename, false);
15531 
15532  /* Check permissions except when moving to database's default */
15533  if (OidIsValid(tablespaceId) && tablespaceId != MyDatabaseTableSpace)
15534  {
15535  AclResult aclresult;
15536 
15537  aclresult = object_aclcheck(TableSpaceRelationId, tablespaceId, GetUserId(), ACL_CREATE);
15538  if (aclresult != ACLCHECK_OK)
15539  aclcheck_error(aclresult, OBJECT_TABLESPACE, tablespacename);
15540  }
15541 
15542  /* Save info for Phase 3 to do the real work */
15543  if (OidIsValid(tab->newTableSpace))
15544  ereport(ERROR,
15545  (errcode(ERRCODE_SYNTAX_ERROR),
15546  errmsg("cannot have multiple SET TABLESPACE subcommands")));
15547 
15548  tab->newTableSpace = tablespaceId;
15549 }
15550 
15551 /*
15552  * Set, reset, or replace reloptions.
15553  */
15554 static void
15556  LOCKMODE lockmode)
15557 {
15558  Oid relid;
15559  Relation pgclass;
15560  HeapTuple tuple;
15561  HeapTuple newtuple;
15562  Datum datum;
15563  bool isnull;
15564  Datum newOptions;
15565  Datum repl_val[Natts_pg_class];
15566  bool repl_null[Natts_pg_class];
15567  bool repl_repl[Natts_pg_class];
15568  static char *validnsps[] = HEAP_RELOPT_NAMESPACES;
15569 
15570  if (defList == NIL && operation != AT_ReplaceRelOptions)
15571  return; /* nothing to do */
15572 
15573  pgclass = table_open(RelationRelationId, RowExclusiveLock);
15574 
15575  /* Fetch heap tuple */
15576  relid = RelationGetRelid(rel);
15577  tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
15578  if (!HeapTupleIsValid(tuple))
15579  elog(ERROR, "cache lookup failed for relation %u", relid);
15580 
15581  if (operation == AT_ReplaceRelOptions)
15582  {
15583  /*
15584  * If we're supposed to replace the reloptions list, we just pretend
15585  * there were none before.
15586  */
15587  datum = (Datum) 0;
15588  isnull = true;
15589  }
15590  else
15591  {
15592  /* Get the old reloptions */
15593  datum = SysCacheGetAttr(RELOID, tuple, Anum_pg_class_reloptions,
15594  &isnull);
15595  }
15596 
15597  /* Generate new proposed reloptions (text array) */
15598  newOptions = transformRelOptions(isnull ? (Datum) 0 : datum,
15599  defList, NULL, validnsps, false,
15600  operation == AT_ResetRelOptions);
15601 
15602  /* Validate */
15603  switch (rel->rd_rel->relkind)
15604  {
15605  case RELKIND_RELATION:
15606  case RELKIND_TOASTVALUE:
15607  case RELKIND_MATVIEW:
15608  (void) heap_reloptions(rel->rd_rel->relkind, newOptions, true);
15609  break;
15610  case RELKIND_PARTITIONED_TABLE:
15611  (void) partitioned_table_reloptions(newOptions, true);
15612  break;
15613  case RELKIND_VIEW:
15614  (void) view_reloptions(newOptions, true);
15615  break;
15616  case RELKIND_INDEX:
15617  case RELKIND_PARTITIONED_INDEX:
15618  (void) index_reloptions(rel->rd_indam->amoptions, newOptions, true);
15619  break;
15620  default:
15621  ereport(ERROR,
15622  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
15623  errmsg("cannot set options for relation \"%s\"",
15625  errdetail_relkind_not_supported(rel->rd_rel->relkind)));
15626  break;
15627  }
15628 
15629  /* Special-case validation of view options */
15630  if (rel->rd_rel->relkind == RELKIND_VIEW)
15631  {
15632  Query *view_query = get_view_query(rel);
15633  List *view_options = untransformRelOptions(newOptions);
15634  ListCell *cell;
15635  bool check_option = false;
15636 
15637  foreach(cell, view_options)
15638  {
15639  DefElem *defel = (DefElem *) lfirst(cell);
15640 
15641  if (strcmp(defel->defname, "check_option") == 0)
15642  check_option = true;
15643  }
15644 
15645  /*
15646  * If the check option is specified, look to see if the view is
15647  * actually auto-updatable or not.
15648  */
15649  if (check_option)
15650  {
15651  const char *view_updatable_error =
15652  view_query_is_auto_updatable(view_query, true);
15653 
15654  if (view_updatable_error)
15655  ereport(ERROR,
15656  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
15657  errmsg("WITH CHECK OPTION is supported only on automatically updatable views"),
15658  errhint("%s", _(view_updatable_error))));
15659  }
15660  }
15661 
15662  /*
15663  * All we need do here is update the pg_class row; the new options will be
15664  * propagated into relcaches during post-commit cache inval.
15665  */
15666  memset(repl_val, 0, sizeof(repl_val));
15667  memset(repl_null, false, sizeof(repl_null));
15668  memset(repl_repl, false, sizeof(repl_repl));
15669 
15670  if (newOptions != (Datum) 0)
15671  repl_val[Anum_pg_class_reloptions - 1] = newOptions;
15672  else
15673  repl_null[Anum_pg_class_reloptions - 1] = true;
15674 
15675  repl_repl[Anum_pg_class_reloptions - 1] = true;
15676 
15677  newtuple = heap_modify_tuple(tuple, RelationGetDescr(pgclass),
15678  repl_val, repl_null, repl_repl);
15679 
15680  CatalogTupleUpdate(pgclass, &newtuple->t_self, newtuple);
15681 
15682  InvokeObjectPostAlterHook(RelationRelationId, RelationGetRelid(rel), 0);
15683 
15684  heap_freetuple(newtuple);
15685 
15686  ReleaseSysCache(tuple);
15687 
15688  /* repeat the whole exercise for the toast table, if there's one */
15689  if (OidIsValid(rel->rd_rel->reltoastrelid))
15690  {
15691  Relation toastrel;
15692  Oid toastid = rel->rd_rel->reltoastrelid;
15693 
15694  toastrel = table_open(toastid, lockmode);
15695 
15696  /* Fetch heap tuple */
15697  tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(toastid));
15698  if (!HeapTupleIsValid(tuple))
15699  elog(ERROR, "cache lookup failed for relation %u", toastid);
15700 
15701  if (operation == AT_ReplaceRelOptions)
15702  {
15703  /*
15704  * If we're supposed to replace the reloptions list, we just
15705  * pretend there were none before.
15706  */
15707  datum = (Datum) 0;
15708  isnull = true;
15709  }
15710  else
15711  {
15712  /* Get the old reloptions */
15713  datum = SysCacheGetAttr(RELOID, tuple, Anum_pg_class_reloptions,
15714  &isnull);
15715  }
15716 
15717  newOptions = transformRelOptions(isnull ? (Datum) 0 : datum,
15718  defList, "toast", validnsps, false,
15719  operation == AT_ResetRelOptions);
15720 
15721  (void) heap_reloptions(RELKIND_TOASTVALUE, newOptions, true);
15722 
15723  memset(repl_val, 0, sizeof(repl_val));
15724  memset(repl_null, false, sizeof(repl_null));
15725  memset(repl_repl, false, sizeof(repl_repl));
15726 
15727  if (newOptions != (Datum) 0)
15728  repl_val[Anum_pg_class_reloptions - 1] = newOptions;
15729  else
15730  repl_null[Anum_pg_class_reloptions - 1] = true;
15731 
15732  repl_repl[Anum_pg_class_reloptions - 1] = true;
15733 
15734  newtuple = heap_modify_tuple(tuple, RelationGetDescr(pgclass),
15735  repl_val, repl_null, repl_repl);
15736 
15737  CatalogTupleUpdate(pgclass, &newtuple->t_self, newtuple);
15738 
15739  InvokeObjectPostAlterHookArg(RelationRelationId,
15740  RelationGetRelid(toastrel), 0,
15741  InvalidOid, true);
15742 
15743  heap_freetuple(newtuple);
15744 
15745  ReleaseSysCache(tuple);
15746 
15747  table_close(toastrel, NoLock);
15748  }
15749 
15750  table_close(pgclass, RowExclusiveLock);
15751 }
15752 
15753 /*
15754  * Execute ALTER TABLE SET TABLESPACE for cases where there is no tuple
15755  * rewriting to be done, so we just want to copy the data as fast as possible.
15756  */
15757 static void
15758 ATExecSetTableSpace(Oid tableOid, Oid newTableSpace, LOCKMODE lockmode)
15759 {
15760  Relation rel;
15761  Oid reltoastrelid;
15762  RelFileNumber newrelfilenumber;
15763  RelFileLocator newrlocator;
15764  List *reltoastidxids = NIL;
15765  ListCell *lc;
15766 
15767  /*
15768  * Need lock here in case we are recursing to toast table or index
15769  */
15770  rel = relation_open(tableOid, lockmode);
15771 
15772  /* Check first if relation can be moved to new tablespace */
15773  if (!CheckRelationTableSpaceMove(rel, newTableSpace))
15774  {
15775  InvokeObjectPostAlterHook(RelationRelationId,
15776  RelationGetRelid(rel), 0);
15777  relation_close(rel, NoLock);
15778  return;
15779  }
15780 
15781  reltoastrelid = rel->rd_rel->reltoastrelid;
15782  /* Fetch the list of indexes on toast relation if necessary */
15783  if (OidIsValid(reltoastrelid))
15784  {
15785  Relation toastRel = relation_open(reltoastrelid, lockmode);
15786 
15787  reltoastidxids = RelationGetIndexList(toastRel);
15788  relation_close(toastRel, lockmode);
15789  }
15790 
15791  /*
15792  * Relfilenumbers are not unique in databases across tablespaces, so we
15793  * need to allocate a new one in the new tablespace.
15794  */
15795  newrelfilenumber = GetNewRelFileNumber(newTableSpace, NULL,
15796  rel->rd_rel->relpersistence);
15797 
15798  /* Open old and new relation */
15799  newrlocator = rel->rd_locator;
15800  newrlocator.relNumber = newrelfilenumber;
15801  newrlocator.spcOid = newTableSpace;
15802 
15803  /* hand off to AM to actually create new rel storage and copy the data */
15804  if (rel->rd_rel->relkind == RELKIND_INDEX)
15805  {
15806  index_copy_data(rel, newrlocator);
15807  }
15808  else
15809  {
15810  Assert(RELKIND_HAS_TABLE_AM(rel->rd_rel->relkind));
15811  table_relation_copy_data(rel, &newrlocator);
15812  }
15813 
15814  /*
15815  * Update the pg_class row.
15816  *
15817  * NB: This wouldn't work if ATExecSetTableSpace() were allowed to be
15818  * executed on pg_class or its indexes (the above copy wouldn't contain
15819  * the updated pg_class entry), but that's forbidden with
15820  * CheckRelationTableSpaceMove().
15821  */
15822  SetRelationTableSpace(rel, newTableSpace, newrelfilenumber);
15823 
15824  InvokeObjectPostAlterHook(RelationRelationId, RelationGetRelid(rel), 0);
15825 
15827 
15828  relation_close(rel, NoLock);
15829 
15830  /* Make sure the reltablespace change is visible */
15832 
15833  /* Move associated toast relation and/or indexes, too */
15834  if (OidIsValid(reltoastrelid))
15835  ATExecSetTableSpace(reltoastrelid, newTableSpace, lockmode);
15836  foreach(lc, reltoastidxids)
15837  ATExecSetTableSpace(lfirst_oid(lc), newTableSpace, lockmode);
15838 
15839  /* Clean up */
15840  list_free(reltoastidxids);
15841 }
15842 
15843 /*
15844  * Special handling of ALTER TABLE SET TABLESPACE for relations with no
15845  * storage that have an interest in preserving tablespace.
15846  *
15847  * Since these have no storage the tablespace can be updated with a simple
15848  * metadata only operation to update the tablespace.
15849  */
15850 static void
15852 {
15853  /*
15854  * Shouldn't be called on relations having storage; these are processed in
15855  * phase 3.
15856  */
15857  Assert(!RELKIND_HAS_STORAGE(rel->rd_rel->relkind));
15858 
15859  /* check if relation can be moved to its new tablespace */
15860  if (!CheckRelationTableSpaceMove(rel, newTableSpace))
15861  {
15862  InvokeObjectPostAlterHook(RelationRelationId,
15863  RelationGetRelid(rel),
15864  0);
15865  return;
15866  }
15867 
15868  /* Update can be done, so change reltablespace */
15869  SetRelationTableSpace(rel, newTableSpace, InvalidOid);
15870 
15871  InvokeObjectPostAlterHook(RelationRelationId, RelationGetRelid(rel), 0);
15872 
15873  /* Make sure the reltablespace change is visible */
15875 }
15876 
15877 /*
15878  * Alter Table ALL ... SET TABLESPACE
15879  *
15880  * Allows a user to move all objects of some type in a given tablespace in the
15881  * current database to another tablespace. Objects can be chosen based on the
15882  * owner of the object also, to allow users to move only their objects.
15883  * The user must have CREATE rights on the new tablespace, as usual. The main
15884  * permissions handling is done by the lower-level table move function.
15885  *
15886  * All to-be-moved objects are locked first. If NOWAIT is specified and the
15887  * lock can't be acquired then we ereport(ERROR).
15888  */
15889 Oid
15891 {
15892  List *relations = NIL;
15893  ListCell *l;
15894  ScanKeyData key[1];
15895  Relation rel;
15896  TableScanDesc scan;
15897  HeapTuple tuple;
15898  Oid orig_tablespaceoid;
15899  Oid new_tablespaceoid;
15900  List *role_oids = roleSpecsToIds(stmt->roles);
15901 
15902  /* Ensure we were not asked to move something we can't */
15903  if (stmt->objtype != OBJECT_TABLE && stmt->objtype != OBJECT_INDEX &&
15904  stmt->objtype != OBJECT_MATVIEW)
15905  ereport(ERROR,
15906  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
15907  errmsg("only tables, indexes, and materialized views exist in tablespaces")));
15908 
15909  /* Get the orig and new tablespace OIDs */
15910  orig_tablespaceoid = get_tablespace_oid(stmt->orig_tablespacename, false);
15911  new_tablespaceoid = get_tablespace_oid(stmt->new_tablespacename, false);
15912 
15913  /* Can't move shared relations in to or out of pg_global */
15914  /* This is also checked by ATExecSetTableSpace, but nice to stop earlier */
15915  if (orig_tablespaceoid == GLOBALTABLESPACE_OID ||
15916  new_tablespaceoid == GLOBALTABLESPACE_OID)
15917  ereport(ERROR,
15918  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
15919  errmsg("cannot move relations in to or out of pg_global tablespace")));
15920 
15921  /*
15922  * Must have CREATE rights on the new tablespace, unless it is the
15923  * database default tablespace (which all users implicitly have CREATE
15924  * rights on).
15925  */
15926  if (OidIsValid(new_tablespaceoid) && new_tablespaceoid != MyDatabaseTableSpace)
15927  {
15928  AclResult aclresult;
15929 
15930  aclresult = object_aclcheck(TableSpaceRelationId, new_tablespaceoid, GetUserId(),
15931  ACL_CREATE);
15932  if (aclresult != ACLCHECK_OK)
15933  aclcheck_error(aclresult, OBJECT_TABLESPACE,
15934  get_tablespace_name(new_tablespaceoid));
15935  }
15936 
15937  /*
15938  * Now that the checks are done, check if we should set either to
15939  * InvalidOid because it is our database's default tablespace.
15940  */
15941  if (orig_tablespaceoid == MyDatabaseTableSpace)
15942  orig_tablespaceoid = InvalidOid;
15943 
15944  if (new_tablespaceoid == MyDatabaseTableSpace)
15945  new_tablespaceoid = InvalidOid;
15946 
15947  /* no-op */
15948  if (orig_tablespaceoid == new_tablespaceoid)
15949  return new_tablespaceoid;
15950 
15951  /*
15952  * Walk the list of objects in the tablespace and move them. This will
15953  * only find objects in our database, of course.
15954  */
15955  ScanKeyInit(&key[0],
15956  Anum_pg_class_reltablespace,
15957  BTEqualStrategyNumber, F_OIDEQ,
15958  ObjectIdGetDatum(orig_tablespaceoid));
15959 
15960  rel = table_open(RelationRelationId, AccessShareLock);
15961  scan = table_beginscan_catalog(rel, 1, key);
15962  while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
15963  {
15964  Form_pg_class relForm = (Form_pg_class) GETSTRUCT(tuple);
15965  Oid relOid = relForm->oid;
15966 
15967  /*
15968  * Do not move objects in pg_catalog as part of this, if an admin
15969  * really wishes to do so, they can issue the individual ALTER
15970  * commands directly.
15971  *
15972  * Also, explicitly avoid any shared tables, temp tables, or TOAST
15973  * (TOAST will be moved with the main table).
15974  */
15975  if (IsCatalogNamespace(relForm->relnamespace) ||
15976  relForm->relisshared ||
15977  isAnyTempNamespace(relForm->relnamespace) ||
15978  IsToastNamespace(relForm->relnamespace))
15979  continue;
15980 
15981  /* Only move the object type requested */
15982  if ((stmt->objtype == OBJECT_TABLE &&
15983  relForm->relkind != RELKIND_RELATION &&
15984  relForm->relkind != RELKIND_PARTITIONED_TABLE) ||
15985  (stmt->objtype == OBJECT_INDEX &&
15986  relForm->relkind != RELKIND_INDEX &&
15987  relForm->relkind != RELKIND_PARTITIONED_INDEX) ||
15988  (stmt->objtype == OBJECT_MATVIEW &&
15989  relForm->relkind != RELKIND_MATVIEW))
15990  continue;
15991 
15992  /* Check if we are only moving objects owned by certain roles */
15993  if (role_oids != NIL && !list_member_oid(role_oids, relForm->relowner))
15994  continue;
15995 
15996  /*
15997  * Handle permissions-checking here since we are locking the tables
15998  * and also to avoid doing a bunch of work only to fail part-way. Note
15999  * that permissions will also be checked by AlterTableInternal().
16000  *
16001  * Caller must be considered an owner on the table to move it.
16002  */
16003  if (!object_ownercheck(RelationRelationId, relOid, GetUserId()))
16005  NameStr(relForm->relname));
16006 
16007  if (stmt->nowait &&
16009  ereport(ERROR,
16010  (errcode(ERRCODE_OBJECT_IN_USE),
16011  errmsg("aborting because lock on relation \"%s.%s\" is not available",
16012  get_namespace_name(relForm->relnamespace),
16013  NameStr(relForm->relname))));
16014  else
16016 
16017  /* Add to our list of objects to move */
16018  relations = lappend_oid(relations, relOid);
16019  }
16020 
16021  table_endscan(scan);
16023 
16024  if (relations == NIL)
16025  ereport(NOTICE,
16026  (errcode(ERRCODE_NO_DATA_FOUND),
16027  errmsg("no matching relations in tablespace \"%s\" found",
16028  orig_tablespaceoid == InvalidOid ? "(database default)" :
16029  get_tablespace_name(orig_tablespaceoid))));
16030 
16031  /* Everything is locked, loop through and move all of the relations. */
16032  foreach(l, relations)
16033  {
16034  List *cmds = NIL;
16036 
16037  cmd->subtype = AT_SetTableSpace;
16038  cmd->name = stmt->new_tablespacename;
16039 
16040  cmds = lappend(cmds, cmd);
16041 
16043  /* OID is set by AlterTableInternal */
16044  AlterTableInternal(lfirst_oid(l), cmds, false);
16046  }
16047 
16048  return new_tablespaceoid;
16049 }
16050 
16051 static void
16053 {
16054  SMgrRelation dstrel;
16055 
16056  /*
16057  * Since we copy the file directly without looking at the shared buffers,
16058  * we'd better first flush out any pages of the source relation that are
16059  * in shared buffers. We assume no new changes will be made while we are
16060  * holding exclusive lock on the rel.
16061  */
16062  FlushRelationBuffers(rel);
16063 
16064  /*
16065  * Create and copy all forks of the relation, and schedule unlinking of
16066  * old physical files.
16067  *
16068  * NOTE: any conflict in relfilenumber value will be caught in
16069  * RelationCreateStorage().
16070  */
16071  dstrel = RelationCreateStorage(newrlocator, rel->rd_rel->relpersistence, true);
16072 
16073  /* copy main fork */
16075  rel->rd_rel->relpersistence);
16076 
16077  /* copy those extra forks that exist */
16078  for (ForkNumber forkNum = MAIN_FORKNUM + 1;
16079  forkNum <= MAX_FORKNUM; forkNum++)
16080  {
16081  if (smgrexists(RelationGetSmgr(rel), forkNum))
16082  {
16083  smgrcreate(dstrel, forkNum, false);
16084 
16085  /*
16086  * WAL log creation if the relation is persistent, or this is the
16087  * init fork of an unlogged relation.
16088  */
16089  if (RelationIsPermanent(rel) ||
16090  (rel->rd_rel->relpersistence == RELPERSISTENCE_UNLOGGED &&
16091  forkNum == INIT_FORKNUM))
16092  log_smgrcreate(&newrlocator, forkNum);
16093  RelationCopyStorage(RelationGetSmgr(rel), dstrel, forkNum,
16094  rel->rd_rel->relpersistence);
16095  }
16096  }
16097 
16098  /* drop old relation, and close new one */
16099  RelationDropStorage(rel);
16100  smgrclose(dstrel);
16101 }
16102 
16103 /*
16104  * ALTER TABLE ENABLE/DISABLE TRIGGER
16105  *
16106  * We just pass this off to trigger.c.
16107  */
16108 static void
16109 ATExecEnableDisableTrigger(Relation rel, const char *trigname,
16110  char fires_when, bool skip_system, bool recurse,
16111  LOCKMODE lockmode)
16112 {
16113  EnableDisableTrigger(rel, trigname, InvalidOid,
16114  fires_when, skip_system, recurse,
16115  lockmode);
16116 
16117  InvokeObjectPostAlterHook(RelationRelationId,
16118  RelationGetRelid(rel), 0);
16119 }
16120 
16121 /*
16122  * ALTER TABLE ENABLE/DISABLE RULE
16123  *
16124  * We just pass this off to rewriteDefine.c.
16125  */
16126 static void
16127 ATExecEnableDisableRule(Relation rel, const char *rulename,
16128  char fires_when, LOCKMODE lockmode)
16129 {
16130  EnableDisableRule(rel, rulename, fires_when);
16131 
16132  InvokeObjectPostAlterHook(RelationRelationId,
16133  RelationGetRelid(rel), 0);
16134 }
16135 
16136 /*
16137  * ALTER TABLE INHERIT
16138  *
16139  * Add a parent to the child's parents. This verifies that all the columns and
16140  * check constraints of the parent appear in the child and that they have the
16141  * same data types and expressions.
16142  */
16143 static void
16145 {
16146  if (child_rel->rd_rel->reloftype)
16147  ereport(ERROR,
16148  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
16149  errmsg("cannot change inheritance of typed table")));
16150 
16151  if (child_rel->rd_rel->relispartition)
16152  ereport(ERROR,
16153  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
16154  errmsg("cannot change inheritance of a partition")));
16155 
16156  if (child_rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
16157  ereport(ERROR,
16158  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
16159  errmsg("cannot change inheritance of partitioned table")));
16160 }
16161 
16162 /*
16163  * Return the address of the new parent relation.
16164  */
16165 static ObjectAddress
16166 ATExecAddInherit(Relation child_rel, RangeVar *parent, LOCKMODE lockmode)
16167 {
16168  Relation parent_rel;
16169  List *children;
16170  ObjectAddress address;
16171  const char *trigger_name;
16172 
16173  /*
16174  * A self-exclusive lock is needed here. See the similar case in
16175  * MergeAttributes() for a full explanation.
16176  */
16177  parent_rel = table_openrv(parent, ShareUpdateExclusiveLock);
16178 
16179  /*
16180  * Must be owner of both parent and child -- child was checked by
16181  * ATSimplePermissions call in ATPrepCmd
16182  */
16184 
16185  /* Permanent rels cannot inherit from temporary ones */
16186  if (parent_rel->rd_rel->relpersistence == RELPERSISTENCE_TEMP &&
16187  child_rel->rd_rel->relpersistence != RELPERSISTENCE_TEMP)
16188  ereport(ERROR,
16189  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
16190  errmsg("cannot inherit from temporary relation \"%s\"",
16191  RelationGetRelationName(parent_rel))));
16192 
16193  /* If parent rel is temp, it must belong to this session */
16194  if (parent_rel->rd_rel->relpersistence == RELPERSISTENCE_TEMP &&
16195  !parent_rel->rd_islocaltemp)
16196  ereport(ERROR,
16197  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
16198  errmsg("cannot inherit from temporary relation of another session")));
16199 
16200  /* Ditto for the child */
16201  if (child_rel->rd_rel->relpersistence == RELPERSISTENCE_TEMP &&
16202  !child_rel->rd_islocaltemp)
16203  ereport(ERROR,
16204  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
16205  errmsg("cannot inherit to temporary relation of another session")));
16206 
16207  /* Prevent partitioned tables from becoming inheritance parents */
16208  if (parent_rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
16209  ereport(ERROR,
16210  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
16211  errmsg("cannot inherit from partitioned table \"%s\"",
16212  parent->relname)));
16213 
16214  /* Likewise for partitions */
16215  if (parent_rel->rd_rel->relispartition)
16216  ereport(ERROR,
16217  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
16218  errmsg("cannot inherit from a partition")));
16219 
16220  /*
16221  * Prevent circularity by seeing if proposed parent inherits from child.
16222  * (In particular, this disallows making a rel inherit from itself.)
16223  *
16224  * This is not completely bulletproof because of race conditions: in
16225  * multi-level inheritance trees, someone else could concurrently be
16226  * making another inheritance link that closes the loop but does not join
16227  * either of the rels we have locked. Preventing that seems to require
16228  * exclusive locks on the entire inheritance tree, which is a cure worse
16229  * than the disease. find_all_inheritors() will cope with circularity
16230  * anyway, so don't sweat it too much.
16231  *
16232  * We use weakest lock we can on child's children, namely AccessShareLock.
16233  */
16234  children = find_all_inheritors(RelationGetRelid(child_rel),
16235  AccessShareLock, NULL);
16236 
16237  if (list_member_oid(children, RelationGetRelid(parent_rel)))
16238  ereport(ERROR,
16239  (errcode(ERRCODE_DUPLICATE_TABLE),
16240  errmsg("circular inheritance not allowed"),
16241  errdetail("\"%s\" is already a child of \"%s\".",
16242  parent->relname,
16243  RelationGetRelationName(child_rel))));
16244 
16245  /*
16246  * If child_rel has row-level triggers with transition tables, we
16247  * currently don't allow it to become an inheritance child. See also
16248  * prohibitions in ATExecAttachPartition() and CreateTrigger().
16249  */
16250  trigger_name = FindTriggerIncompatibleWithInheritance(child_rel->trigdesc);
16251  if (trigger_name != NULL)
16252  ereport(ERROR,
16253  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
16254  errmsg("trigger \"%s\" prevents table \"%s\" from becoming an inheritance child",
16255  trigger_name, RelationGetRelationName(child_rel)),
16256  errdetail("ROW triggers with transition tables are not supported in inheritance hierarchies.")));
16257 
16258  /* OK to create inheritance */
16259  CreateInheritance(child_rel, parent_rel, false);
16260 
16261  /*
16262  * If parent_rel has a primary key, then child_rel has not-null
16263  * constraints that make these columns as non nullable. Make those
16264  * constraints as inherited.
16265  */
16266  ATInheritAdjustNotNulls(parent_rel, child_rel, 1);
16267 
16268  ObjectAddressSet(address, RelationRelationId,
16269  RelationGetRelid(parent_rel));
16270 
16271  /* keep our lock on the parent relation until commit */
16272  table_close(parent_rel, NoLock);
16273 
16274  return address;
16275 }
16276 
16277 /*
16278  * CreateInheritance
16279  * Catalog manipulation portion of creating inheritance between a child
16280  * table and a parent table.
16281  *
16282  * Common to ATExecAddInherit() and ATExecAttachPartition().
16283  */
16284 static void
16285 CreateInheritance(Relation child_rel, Relation parent_rel, bool ispartition)
16286 {
16287  Relation catalogRelation;
16288  SysScanDesc scan;
16289  ScanKeyData key;
16290  HeapTuple inheritsTuple;
16291  int32 inhseqno;
16292 
16293  /* Note: get RowExclusiveLock because we will write pg_inherits below. */
16294  catalogRelation = table_open(InheritsRelationId, RowExclusiveLock);
16295 
16296  /*
16297  * Check for duplicates in the list of parents, and determine the highest
16298  * inhseqno already present; we'll use the next one for the new parent.
16299  * Also, if proposed child is a partition, it cannot already be
16300  * inheriting.
16301  *
16302  * Note: we do not reject the case where the child already inherits from
16303  * the parent indirectly; CREATE TABLE doesn't reject comparable cases.
16304  */
16305  ScanKeyInit(&key,
16306  Anum_pg_inherits_inhrelid,
16307  BTEqualStrategyNumber, F_OIDEQ,
16308  ObjectIdGetDatum(RelationGetRelid(child_rel)));
16309  scan = systable_beginscan(catalogRelation, InheritsRelidSeqnoIndexId,
16310  true, NULL, 1, &key);
16311 
16312  /* inhseqno sequences start at 1 */
16313  inhseqno = 0;
16314  while (HeapTupleIsValid(inheritsTuple = systable_getnext(scan)))
16315  {
16316  Form_pg_inherits inh = (Form_pg_inherits) GETSTRUCT(inheritsTuple);
16317 
16318  if (inh->inhparent == RelationGetRelid(parent_rel))
16319  ereport(ERROR,
16320  (errcode(ERRCODE_DUPLICATE_TABLE),
16321  errmsg("relation \"%s\" would be inherited from more than once",
16322  RelationGetRelationName(parent_rel))));
16323 
16324  if (inh->inhseqno > inhseqno)
16325  inhseqno = inh->inhseqno;
16326  }
16327  systable_endscan(scan);
16328 
16329  /* Match up the columns and bump attinhcount as needed */
16330  MergeAttributesIntoExisting(child_rel, parent_rel, ispartition);
16331 
16332  /* Match up the constraints and bump coninhcount as needed */
16333  MergeConstraintsIntoExisting(child_rel, parent_rel);
16334 
16335  /*
16336  * OK, it looks valid. Make the catalog entries that show inheritance.
16337  */
16339  RelationGetRelid(parent_rel),
16340  inhseqno + 1,
16341  catalogRelation,
16342  parent_rel->rd_rel->relkind ==
16343  RELKIND_PARTITIONED_TABLE);
16344 
16345  /* Now we're done with pg_inherits */
16346  table_close(catalogRelation, RowExclusiveLock);
16347 }
16348 
16349 /*
16350  * Obtain the source-text form of the constraint expression for a check
16351  * constraint, given its pg_constraint tuple
16352  */
16353 static char *
16355 {
16356  Form_pg_constraint con;
16357  bool isnull;
16358  Datum attr;
16359  Datum expr;
16360 
16361  con = (Form_pg_constraint) GETSTRUCT(contup);
16362  attr = heap_getattr(contup, Anum_pg_constraint_conbin, tupdesc, &isnull);
16363  if (isnull)
16364  elog(ERROR, "null conbin for constraint %u", con->oid);
16365 
16366  expr = DirectFunctionCall2(pg_get_expr, attr,
16367  ObjectIdGetDatum(con->conrelid));
16368  return TextDatumGetCString(expr);
16369 }
16370 
16371 /*
16372  * Determine whether two check constraints are functionally equivalent
16373  *
16374  * The test we apply is to see whether they reverse-compile to the same
16375  * source string. This insulates us from issues like whether attributes
16376  * have the same physical column numbers in parent and child relations.
16377  */
16378 static bool
16380 {
16383 
16384  if (acon->condeferrable != bcon->condeferrable ||
16385  acon->condeferred != bcon->condeferred ||
16386  strcmp(decompile_conbin(a, tupleDesc),
16387  decompile_conbin(b, tupleDesc)) != 0)
16388  return false;
16389  else
16390  return true;
16391 }
16392 
16393 /*
16394  * Check columns in child table match up with columns in parent, and increment
16395  * their attinhcount.
16396  *
16397  * Called by CreateInheritance
16398  *
16399  * Currently all parent columns must be found in child. Missing columns are an
16400  * error. One day we might consider creating new columns like CREATE TABLE
16401  * does. However, that is widely unpopular --- in the common use case of
16402  * partitioned tables it's a foot-gun.
16403  *
16404  * The data type must match exactly. If the parent column is NOT NULL then
16405  * the child must be as well. Defaults are not compared, however.
16406  */
16407 static void
16408 MergeAttributesIntoExisting(Relation child_rel, Relation parent_rel, bool ispartition)
16409 {
16410  Relation attrrel;
16411  TupleDesc parent_desc;
16412 
16413  attrrel = table_open(AttributeRelationId, RowExclusiveLock);
16414  parent_desc = RelationGetDescr(parent_rel);
16415 
16416  for (AttrNumber parent_attno = 1; parent_attno <= parent_desc->natts; parent_attno++)
16417  {
16418  Form_pg_attribute parent_att = TupleDescAttr(parent_desc, parent_attno - 1);
16419  char *parent_attname = NameStr(parent_att->attname);
16420  HeapTuple tuple;
16421 
16422  /* Ignore dropped columns in the parent. */
16423  if (parent_att->attisdropped)
16424  continue;
16425 
16426  /* Find same column in child (matching on column name). */
16427  tuple = SearchSysCacheCopyAttName(RelationGetRelid(child_rel), parent_attname);
16428  if (HeapTupleIsValid(tuple))
16429  {
16430  Form_pg_attribute child_att = (Form_pg_attribute) GETSTRUCT(tuple);
16431 
16432  if (parent_att->atttypid != child_att->atttypid ||
16433  parent_att->atttypmod != child_att->atttypmod)
16434  ereport(ERROR,
16435  (errcode(ERRCODE_DATATYPE_MISMATCH),
16436  errmsg("child table \"%s\" has different type for column \"%s\"",
16437  RelationGetRelationName(child_rel), parent_attname)));
16438 
16439  if (parent_att->attcollation != child_att->attcollation)
16440  ereport(ERROR,
16441  (errcode(ERRCODE_COLLATION_MISMATCH),
16442  errmsg("child table \"%s\" has different collation for column \"%s\"",
16443  RelationGetRelationName(child_rel), parent_attname)));
16444 
16445  /*
16446  * If the parent has a not-null constraint that's not NO INHERIT,
16447  * make sure the child has one too.
16448  *
16449  * Other constraints are checked elsewhere.
16450  */
16451  if (parent_att->attnotnull && !child_att->attnotnull)
16452  {
16453  HeapTuple contup;
16454 
16455  contup = findNotNullConstraintAttnum(RelationGetRelid(parent_rel),
16456  parent_att->attnum);
16457  if (HeapTupleIsValid(contup) &&
16458  !((Form_pg_constraint) GETSTRUCT(contup))->connoinherit)
16459  ereport(ERROR,
16460  errcode(ERRCODE_DATATYPE_MISMATCH),
16461  errmsg("column \"%s\" in child table must be marked NOT NULL",
16462  parent_attname));
16463  }
16464 
16465  /*
16466  * Child column must be generated if and only if parent column is.
16467  */
16468  if (parent_att->attgenerated && !child_att->attgenerated)
16469  ereport(ERROR,
16470  (errcode(ERRCODE_DATATYPE_MISMATCH),
16471  errmsg("column \"%s\" in child table must be a generated column", parent_attname)));
16472  if (child_att->attgenerated && !parent_att->attgenerated)
16473  ereport(ERROR,
16474  (errcode(ERRCODE_DATATYPE_MISMATCH),
16475  errmsg("column \"%s\" in child table must not be a generated column", parent_attname)));
16476 
16477  /*
16478  * Regular inheritance children are independent enough not to
16479  * inherit identity columns. But partitions are integral part of
16480  * a partitioned table and inherit identity column.
16481  */
16482  if (ispartition)
16483  child_att->attidentity = parent_att->attidentity;
16484 
16485  /*
16486  * OK, bump the child column's inheritance count. (If we fail
16487  * later on, this change will just roll back.)
16488  */
16489  child_att->attinhcount++;
16490  if (child_att->attinhcount < 0)
16491  ereport(ERROR,
16492  errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
16493  errmsg("too many inheritance parents"));
16494 
16495  /*
16496  * In case of partitions, we must enforce that value of attislocal
16497  * is same in all partitions. (Note: there are only inherited
16498  * attributes in partitions)
16499  */
16500  if (parent_rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
16501  {
16502  Assert(child_att->attinhcount == 1);
16503  child_att->attislocal = false;
16504  }
16505 
16506  CatalogTupleUpdate(attrrel, &tuple->t_self, tuple);
16507  heap_freetuple(tuple);
16508  }
16509  else
16510  {
16511  ereport(ERROR,
16512  (errcode(ERRCODE_DATATYPE_MISMATCH),
16513  errmsg("child table is missing column \"%s\"", parent_attname)));
16514  }
16515  }
16516 
16517  table_close(attrrel, RowExclusiveLock);
16518 }
16519 
16520 /*
16521  * Check constraints in child table match up with constraints in parent,
16522  * and increment their coninhcount.
16523  *
16524  * Constraints that are marked ONLY in the parent are ignored.
16525  *
16526  * Called by CreateInheritance
16527  *
16528  * Currently all constraints in parent must be present in the child. One day we
16529  * may consider adding new constraints like CREATE TABLE does.
16530  *
16531  * XXX This is O(N^2) which may be an issue with tables with hundreds of
16532  * constraints. As long as tables have more like 10 constraints it shouldn't be
16533  * a problem though. Even 100 constraints ought not be the end of the world.
16534  *
16535  * XXX See MergeWithExistingConstraint too if you change this code.
16536  */
16537 static void
16539 {
16540  Relation constraintrel;
16541  SysScanDesc parent_scan;
16542  ScanKeyData parent_key;
16543  HeapTuple parent_tuple;
16544  Oid parent_relid = RelationGetRelid(parent_rel);
16545 
16546  constraintrel = table_open(ConstraintRelationId, RowExclusiveLock);
16547 
16548  /* Outer loop scans through the parent's constraint definitions */
16549  ScanKeyInit(&parent_key,
16550  Anum_pg_constraint_conrelid,
16551  BTEqualStrategyNumber, F_OIDEQ,
16552  ObjectIdGetDatum(parent_relid));
16553  parent_scan = systable_beginscan(constraintrel, ConstraintRelidTypidNameIndexId,
16554  true, NULL, 1, &parent_key);
16555 
16556  while (HeapTupleIsValid(parent_tuple = systable_getnext(parent_scan)))
16557  {
16558  Form_pg_constraint parent_con = (Form_pg_constraint) GETSTRUCT(parent_tuple);
16559  SysScanDesc child_scan;
16560  ScanKeyData child_key;
16561  HeapTuple child_tuple;
16562  bool found = false;
16563 
16564  if (parent_con->contype != CONSTRAINT_CHECK &&
16565  parent_con->contype != CONSTRAINT_NOTNULL)
16566  continue;
16567 
16568  /* if the parent's constraint is marked NO INHERIT, it's not inherited */
16569  if (parent_con->connoinherit)
16570  continue;
16571 
16572  /* Search for a child constraint matching this one */
16573  ScanKeyInit(&child_key,
16574  Anum_pg_constraint_conrelid,
16575  BTEqualStrategyNumber, F_OIDEQ,
16576  ObjectIdGetDatum(RelationGetRelid(child_rel)));
16577  child_scan = systable_beginscan(constraintrel, ConstraintRelidTypidNameIndexId,
16578  true, NULL, 1, &child_key);
16579 
16580  while (HeapTupleIsValid(child_tuple = systable_getnext(child_scan)))
16581  {
16582  Form_pg_constraint child_con = (Form_pg_constraint) GETSTRUCT(child_tuple);
16583  HeapTuple child_copy;
16584 
16585  if (child_con->contype != parent_con->contype)
16586  continue;
16587 
16588  /*
16589  * CHECK constraint are matched by name, NOT NULL ones by
16590  * attribute number
16591  */
16592  if (child_con->contype == CONSTRAINT_CHECK)
16593  {
16594  if (strcmp(NameStr(parent_con->conname),
16595  NameStr(child_con->conname)) != 0)
16596  continue;
16597  }
16598  else if (child_con->contype == CONSTRAINT_NOTNULL)
16599  {
16600  AttrNumber parent_attno = extractNotNullColumn(parent_tuple);
16601  AttrNumber child_attno = extractNotNullColumn(child_tuple);
16602 
16603  if (strcmp(get_attname(parent_relid, parent_attno, false),
16604  get_attname(RelationGetRelid(child_rel), child_attno,
16605  false)) != 0)
16606  continue;
16607  }
16608 
16609  if (child_con->contype == CONSTRAINT_CHECK &&
16610  !constraints_equivalent(parent_tuple, child_tuple, RelationGetDescr(constraintrel)))
16611  ereport(ERROR,
16612  (errcode(ERRCODE_DATATYPE_MISMATCH),
16613  errmsg("child table \"%s\" has different definition for check constraint \"%s\"",
16614  RelationGetRelationName(child_rel), NameStr(parent_con->conname))));
16615 
16616  /*
16617  * If the CHECK child constraint is "no inherit" then cannot
16618  * merge.
16619  *
16620  * This is not desirable for not-null constraints, mostly because
16621  * it breaks our pg_upgrade strategy, but it also makes sense on
16622  * its own: if a child has its own not-null constraint and then
16623  * acquires a parent with the same constraint, then we start to
16624  * enforce that constraint for all the descendants of that child
16625  * too, if any.
16626  */
16627  if (child_con->contype == CONSTRAINT_CHECK &&
16628  child_con->connoinherit)
16629  ereport(ERROR,
16630  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
16631  errmsg("constraint \"%s\" conflicts with non-inherited constraint on child table \"%s\"",
16632  NameStr(child_con->conname), RelationGetRelationName(child_rel))));
16633 
16634  /*
16635  * If the child constraint is "not valid" then cannot merge with a
16636  * valid parent constraint
16637  */
16638  if (parent_con->convalidated && !child_con->convalidated)
16639  ereport(ERROR,
16640  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
16641  errmsg("constraint \"%s\" conflicts with NOT VALID constraint on child table \"%s\"",
16642  NameStr(child_con->conname), RelationGetRelationName(child_rel))));
16643 
16644  /*
16645  * OK, bump the child constraint's inheritance count. (If we fail
16646  * later on, this change will just roll back.)
16647  */
16648  child_copy = heap_copytuple(child_tuple);
16649  child_con = (Form_pg_constraint) GETSTRUCT(child_copy);
16650  child_con->coninhcount++;
16651  if (child_con->coninhcount < 0)
16652  ereport(ERROR,
16653  errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
16654  errmsg("too many inheritance parents"));
16655  if (child_con->contype == CONSTRAINT_NOTNULL &&
16656  child_con->connoinherit)
16657  {
16658  /*
16659  * If the child has children, it's not possible to turn a NO
16660  * INHERIT constraint into an inheritable one: we would need
16661  * to recurse to create constraints in those children, but
16662  * this is not a good place to do that.
16663  */
16664  if (child_rel->rd_rel->relhassubclass)
16665  ereport(ERROR,
16666  errmsg("cannot add NOT NULL constraint to column \"%s\" of relation \"%s\" with inheritance children",
16667  get_attname(RelationGetRelid(child_rel),
16668  extractNotNullColumn(child_tuple),
16669  false),
16670  RelationGetRelationName(child_rel)),
16671  errdetail("Existing constraint \"%s\" is marked NO INHERIT.",
16672  NameStr(child_con->conname)));
16673 
16674  child_con->connoinherit = false;
16675  }
16676 
16677  /*
16678  * In case of partitions, an inherited constraint must be
16679  * inherited only once since it cannot have multiple parents and
16680  * it is never considered local.
16681  */
16682  if (parent_rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
16683  {
16684  Assert(child_con->coninhcount == 1);
16685  child_con->conislocal = false;
16686  }
16687 
16688  CatalogTupleUpdate(constraintrel, &child_copy->t_self, child_copy);
16689  heap_freetuple(child_copy);
16690 
16691  found = true;
16692  break;
16693  }
16694 
16695  systable_endscan(child_scan);
16696 
16697  if (!found)
16698  {
16699  if (parent_con->contype == CONSTRAINT_NOTNULL)
16700  ereport(ERROR,
16701  errcode(ERRCODE_DATATYPE_MISMATCH),
16702  errmsg("column \"%s\" in child table must be marked NOT NULL",
16703  get_attname(parent_relid,
16704  extractNotNullColumn(parent_tuple),
16705  false)));
16706 
16707  ereport(ERROR,
16708  (errcode(ERRCODE_DATATYPE_MISMATCH),
16709  errmsg("child table is missing constraint \"%s\"",
16710  NameStr(parent_con->conname))));
16711  }
16712  }
16713 
16714  systable_endscan(parent_scan);
16715  table_close(constraintrel, RowExclusiveLock);
16716 }
16717 
16718 /*
16719  * ALTER TABLE NO INHERIT
16720  *
16721  * Return value is the address of the relation that is no longer parent.
16722  */
16723 static ObjectAddress
16725 {
16726  ObjectAddress address;
16727  Relation parent_rel;
16728 
16729  if (rel->rd_rel->relispartition)
16730  ereport(ERROR,
16731  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
16732  errmsg("cannot change inheritance of a partition")));
16733 
16734  /*
16735  * AccessShareLock on the parent is probably enough, seeing that DROP
16736  * TABLE doesn't lock parent tables at all. We need some lock since we'll
16737  * be inspecting the parent's schema.
16738  */
16739  parent_rel = table_openrv(parent, AccessShareLock);
16740 
16741  /*
16742  * We don't bother to check ownership of the parent table --- ownership of
16743  * the child is presumed enough rights.
16744  */
16745 
16746  /* Off to RemoveInheritance() where most of the work happens */
16747  RemoveInheritance(rel, parent_rel, false);
16748 
16749  /*
16750  * If parent_rel has a primary key, then child_rel has not-null
16751  * constraints that make these columns as non nullable. Mark those
16752  * constraints as no longer inherited by this parent.
16753  */
16754  ATInheritAdjustNotNulls(parent_rel, rel, -1);
16755 
16756  /*
16757  * If the parent has a primary key, then we decrement counts for all NOT
16758  * NULL constraints
16759  */
16760 
16761  ObjectAddressSet(address, RelationRelationId,
16762  RelationGetRelid(parent_rel));
16763 
16764  /* keep our lock on the parent relation until commit */
16765  table_close(parent_rel, NoLock);
16766 
16767  return address;
16768 }
16769 
16770 /*
16771  * MarkInheritDetached
16772  *
16773  * Set inhdetachpending for a partition, for ATExecDetachPartition
16774  * in concurrent mode. While at it, verify that no other partition is
16775  * already pending detach.
16776  */
16777 static void
16778 MarkInheritDetached(Relation child_rel, Relation parent_rel)
16779 {
16780  Relation catalogRelation;
16781  SysScanDesc scan;
16782  ScanKeyData key;
16783  HeapTuple inheritsTuple;
16784  bool found = false;
16785 
16786  Assert(parent_rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
16787 
16788  /*
16789  * Find pg_inherits entries by inhparent. (We need to scan them all in
16790  * order to verify that no other partition is pending detach.)
16791  */
16792  catalogRelation = table_open(InheritsRelationId, RowExclusiveLock);
16793  ScanKeyInit(&key,
16794  Anum_pg_inherits_inhparent,
16795  BTEqualStrategyNumber, F_OIDEQ,
16796  ObjectIdGetDatum(RelationGetRelid(parent_rel)));
16797  scan = systable_beginscan(catalogRelation, InheritsParentIndexId,
16798  true, NULL, 1, &key);
16799 
16800  while (HeapTupleIsValid(inheritsTuple = systable_getnext(scan)))
16801  {
16802  Form_pg_inherits inhForm;
16803 
16804  inhForm = (Form_pg_inherits) GETSTRUCT(inheritsTuple);
16805  if (inhForm->inhdetachpending)
16806  ereport(ERROR,
16807  errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
16808  errmsg("partition \"%s\" already pending detach in partitioned table \"%s.%s\"",
16809  get_rel_name(inhForm->inhrelid),
16810  get_namespace_name(parent_rel->rd_rel->relnamespace),
16811  RelationGetRelationName(parent_rel)),
16812  errhint("Use ALTER TABLE ... DETACH PARTITION ... FINALIZE to complete the pending detach operation."));
16813 
16814  if (inhForm->inhrelid == RelationGetRelid(child_rel))
16815  {
16816  HeapTuple newtup;
16817 
16818  newtup = heap_copytuple(inheritsTuple);
16819  ((Form_pg_inherits) GETSTRUCT(newtup))->inhdetachpending = true;
16820 
16821  CatalogTupleUpdate(catalogRelation,
16822  &inheritsTuple->t_self,
16823  newtup);
16824  found = true;
16825  heap_freetuple(newtup);
16826  /* keep looking, to ensure we catch others pending detach */
16827  }
16828  }
16829 
16830  /* Done */
16831  systable_endscan(scan);
16832  table_close(catalogRelation, RowExclusiveLock);
16833 
16834  if (!found)
16835  ereport(ERROR,
16837  errmsg("relation \"%s\" is not a partition of relation \"%s\"",
16838  RelationGetRelationName(child_rel),
16839  RelationGetRelationName(parent_rel))));
16840 }
16841 
16842 /*
16843  * RemoveInheritance
16844  *
16845  * Drop a parent from the child's parents. This just adjusts the attinhcount
16846  * and attislocal of the columns and removes the pg_inherit and pg_depend
16847  * entries. expect_detached is passed down to DeleteInheritsTuple, q.v..
16848  *
16849  * If attinhcount goes to 0 then attislocal gets set to true. If it goes back
16850  * up attislocal stays true, which means if a child is ever removed from a
16851  * parent then its columns will never be automatically dropped which may
16852  * surprise. But at least we'll never surprise by dropping columns someone
16853  * isn't expecting to be dropped which would actually mean data loss.
16854  *
16855  * coninhcount and conislocal for inherited constraints are adjusted in
16856  * exactly the same way.
16857  *
16858  * Common to ATExecDropInherit() and ATExecDetachPartition().
16859  */
16860 static void
16861 RemoveInheritance(Relation child_rel, Relation parent_rel, bool expect_detached)
16862 {
16863  Relation catalogRelation;
16864  SysScanDesc scan;
16865  ScanKeyData key[3];
16866  HeapTuple attributeTuple,
16867  constraintTuple;
16868  List *connames;
16869  List *nncolumns;
16870  bool found;
16871  bool is_partitioning;
16872 
16873  is_partitioning = (parent_rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
16874 
16875  found = DeleteInheritsTuple(RelationGetRelid(child_rel),
16876  RelationGetRelid(parent_rel),
16877  expect_detached,
16878  RelationGetRelationName(child_rel));
16879  if (!found)
16880  {
16881  if (is_partitioning)
16882  ereport(ERROR,
16884  errmsg("relation \"%s\" is not a partition of relation \"%s\"",
16885  RelationGetRelationName(child_rel),
16886  RelationGetRelationName(parent_rel))));
16887  else
16888  ereport(ERROR,
16890  errmsg("relation \"%s\" is not a parent of relation \"%s\"",
16891  RelationGetRelationName(parent_rel),
16892  RelationGetRelationName(child_rel))));
16893  }
16894 
16895  /*
16896  * Search through child columns looking for ones matching parent rel
16897  */
16898  catalogRelation = table_open(AttributeRelationId, RowExclusiveLock);
16899  ScanKeyInit(&key[0],
16900  Anum_pg_attribute_attrelid,
16901  BTEqualStrategyNumber, F_OIDEQ,
16902  ObjectIdGetDatum(RelationGetRelid(child_rel)));
16903  scan = systable_beginscan(catalogRelation, AttributeRelidNumIndexId,
16904  true, NULL, 1, key);
16905  while (HeapTupleIsValid(attributeTuple = systable_getnext(scan)))
16906  {
16907  Form_pg_attribute att = (Form_pg_attribute) GETSTRUCT(attributeTuple);
16908 
16909  /* Ignore if dropped or not inherited */
16910  if (att->attisdropped)
16911  continue;
16912  if (att->attinhcount <= 0)
16913  continue;
16914 
16916  NameStr(att->attname)))
16917  {
16918  /* Decrement inhcount and possibly set islocal to true */
16919  HeapTuple copyTuple = heap_copytuple(attributeTuple);
16920  Form_pg_attribute copy_att = (Form_pg_attribute) GETSTRUCT(copyTuple);
16921 
16922  copy_att->attinhcount--;
16923  if (copy_att->attinhcount == 0)
16924  copy_att->attislocal = true;
16925 
16926  CatalogTupleUpdate(catalogRelation, &copyTuple->t_self, copyTuple);
16927  heap_freetuple(copyTuple);
16928  }
16929  }
16930  systable_endscan(scan);
16931  table_close(catalogRelation, RowExclusiveLock);
16932 
16933  /*
16934  * Likewise, find inherited check constraints and disinherit them. To do
16935  * this, we first need a list of the names of the parent's check
16936  * constraints. (We cheat a bit by only checking for name matches,
16937  * assuming that the expressions will match.)
16938  *
16939  * For NOT NULL columns, we store column numbers to match.
16940  */
16941  catalogRelation = table_open(ConstraintRelationId, RowExclusiveLock);
16942  ScanKeyInit(&key[0],
16943  Anum_pg_constraint_conrelid,
16944  BTEqualStrategyNumber, F_OIDEQ,
16945  ObjectIdGetDatum(RelationGetRelid(parent_rel)));
16946  scan = systable_beginscan(catalogRelation, ConstraintRelidTypidNameIndexId,
16947  true, NULL, 1, key);
16948 
16949  connames = NIL;
16950  nncolumns = NIL;
16951 
16952  while (HeapTupleIsValid(constraintTuple = systable_getnext(scan)))
16953  {
16954  Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(constraintTuple);
16955 
16956  if (con->contype == CONSTRAINT_CHECK)
16957  connames = lappend(connames, pstrdup(NameStr(con->conname)));
16958  if (con->contype == CONSTRAINT_NOTNULL)
16959  nncolumns = lappend_int(nncolumns, extractNotNullColumn(constraintTuple));
16960  }
16961 
16962  systable_endscan(scan);
16963 
16964  /* Now scan the child's constraints */
16965  ScanKeyInit(&key[0],
16966  Anum_pg_constraint_conrelid,
16967  BTEqualStrategyNumber, F_OIDEQ,
16968  ObjectIdGetDatum(RelationGetRelid(child_rel)));
16969  scan = systable_beginscan(catalogRelation, ConstraintRelidTypidNameIndexId,
16970  true, NULL, 1, key);
16971 
16972  while (HeapTupleIsValid(constraintTuple = systable_getnext(scan)))
16973  {
16974  Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(constraintTuple);
16975  bool match = false;
16976  ListCell *lc;
16977 
16978  /*
16979  * Match CHECK constraints by name, not-null constraints by column
16980  * number, and ignore all others.
16981  */
16982  if (con->contype == CONSTRAINT_CHECK)
16983  {
16984  foreach(lc, connames)
16985  {
16986  if (con->contype == CONSTRAINT_CHECK &&
16987  strcmp(NameStr(con->conname), (char *) lfirst(lc)) == 0)
16988  {
16989  match = true;
16990  break;
16991  }
16992  }
16993  }
16994  else if (con->contype == CONSTRAINT_NOTNULL)
16995  {
16996  AttrNumber child_attno = extractNotNullColumn(constraintTuple);
16997 
16998  foreach(lc, nncolumns)
16999  {
17000  if (lfirst_int(lc) == child_attno)
17001  {
17002  match = true;
17003  break;
17004  }
17005  }
17006  }
17007  else
17008  continue;
17009 
17010  if (match)
17011  {
17012  /* Decrement inhcount and possibly set islocal to true */
17013  HeapTuple copyTuple = heap_copytuple(constraintTuple);
17014  Form_pg_constraint copy_con = (Form_pg_constraint) GETSTRUCT(copyTuple);
17015 
17016  if (copy_con->coninhcount <= 0) /* shouldn't happen */
17017  elog(ERROR, "relation %u has non-inherited constraint \"%s\"",
17018  RelationGetRelid(child_rel), NameStr(copy_con->conname));
17019 
17020  copy_con->coninhcount--;
17021  if (copy_con->coninhcount == 0)
17022  copy_con->conislocal = true;
17023 
17024  CatalogTupleUpdate(catalogRelation, &copyTuple->t_self, copyTuple);
17025  heap_freetuple(copyTuple);
17026  }
17027  }
17028 
17029  systable_endscan(scan);
17030  table_close(catalogRelation, RowExclusiveLock);
17031 
17033  RelationRelationId,
17034  RelationGetRelid(parent_rel),
17035  child_dependency_type(is_partitioning));
17036 
17037  /*
17038  * Post alter hook of this inherits. Since object_access_hook doesn't take
17039  * multiple object identifiers, we relay oid of parent relation using
17040  * auxiliary_id argument.
17041  */
17042  InvokeObjectPostAlterHookArg(InheritsRelationId,
17043  RelationGetRelid(child_rel), 0,
17044  RelationGetRelid(parent_rel), false);
17045 }
17046 
17047 /*
17048  * Adjust coninhcount of not-null constraints upwards or downwards when a
17049  * table is marked as inheriting or no longer doing so a table with a primary
17050  * key.
17051  *
17052  * Note: these constraints are not dropped, even if their inhcount goes to zero
17053  * and conislocal is false. Instead we mark the constraints as locally defined.
17054  * This is seen as more useful behavior, with no downsides. The user can always
17055  * drop them afterwards.
17056  */
17057 static void
17058 ATInheritAdjustNotNulls(Relation parent_rel, Relation child_rel, int inhcount)
17059 {
17060  Bitmapset *pkattnos;
17061 
17062  /* Quick exit when parent has no PK */
17063  if (!parent_rel->rd_rel->relhasindex)
17064  return;
17065 
17066  pkattnos = RelationGetIndexAttrBitmap(parent_rel,
17068  if (pkattnos != NULL)
17069  {
17070  Bitmapset *childattnums = NULL;
17071  AttrMap *attmap;
17072  int i;
17073 
17074  attmap = build_attrmap_by_name(RelationGetDescr(parent_rel),
17075  RelationGetDescr(child_rel), true);
17076 
17077  i = -1;
17078  while ((i = bms_next_member(pkattnos, i)) >= 0)
17079  {
17080  childattnums = bms_add_member(childattnums,
17082  }
17083 
17084  /*
17085  * CCI is needed in case there's a NOT NULL PRIMARY KEY column in the
17086  * parent: the relevant not-null constraint in the child already had
17087  * its inhcount modified earlier.
17088  */
17090  AdjustNotNullInheritance(RelationGetRelid(child_rel), childattnums,
17091  inhcount);
17092  }
17093 }
17094 
17095 /*
17096  * Drop the dependency created by StoreCatalogInheritance1 (CREATE TABLE
17097  * INHERITS/ALTER TABLE INHERIT -- refclassid will be RelationRelationId) or
17098  * heap_create_with_catalog (CREATE TABLE OF/ALTER TABLE OF -- refclassid will
17099  * be TypeRelationId). There's no convenient way to do this, so go trawling
17100  * through pg_depend.
17101  */
17102 static void
17103 drop_parent_dependency(Oid relid, Oid refclassid, Oid refobjid,
17104  DependencyType deptype)
17105 {
17106  Relation catalogRelation;
17107  SysScanDesc scan;
17108  ScanKeyData key[3];
17109  HeapTuple depTuple;
17110 
17111  catalogRelation = table_open(DependRelationId, RowExclusiveLock);
17112 
17113  ScanKeyInit(&key[0],
17114  Anum_pg_depend_classid,
17115  BTEqualStrategyNumber, F_OIDEQ,
17116  ObjectIdGetDatum(RelationRelationId));
17117  ScanKeyInit(&key[1],
17118  Anum_pg_depend_objid,
17119  BTEqualStrategyNumber, F_OIDEQ,
17120  ObjectIdGetDatum(relid));
17121  ScanKeyInit(&key[2],
17122  Anum_pg_depend_objsubid,
17123  BTEqualStrategyNumber, F_INT4EQ,
17124  Int32GetDatum(0));
17125 
17126  scan = systable_beginscan(catalogRelation, DependDependerIndexId, true,
17127  NULL, 3, key);
17128 
17129  while (HeapTupleIsValid(depTuple = systable_getnext(scan)))
17130  {
17131  Form_pg_depend dep = (Form_pg_depend) GETSTRUCT(depTuple);
17132 
17133  if (dep->refclassid == refclassid &&
17134  dep->refobjid == refobjid &&
17135  dep->refobjsubid == 0 &&
17136  dep->deptype == deptype)
17137  CatalogTupleDelete(catalogRelation, &depTuple->t_self);
17138  }
17139 
17140  systable_endscan(scan);
17141  table_close(catalogRelation, RowExclusiveLock);
17142 }
17143 
17144 /*
17145  * ALTER TABLE OF
17146  *
17147  * Attach a table to a composite type, as though it had been created with CREATE
17148  * TABLE OF. All attname, atttypid, atttypmod and attcollation must match. The
17149  * subject table must not have inheritance parents. These restrictions ensure
17150  * that you cannot create a configuration impossible with CREATE TABLE OF alone.
17151  *
17152  * The address of the type is returned.
17153  */
17154 static ObjectAddress
17155 ATExecAddOf(Relation rel, const TypeName *ofTypename, LOCKMODE lockmode)
17156 {
17157  Oid relid = RelationGetRelid(rel);
17158  Type typetuple;
17159  Form_pg_type typeform;
17160  Oid typeid;
17161  Relation inheritsRelation,
17162  relationRelation;
17163  SysScanDesc scan;
17164  ScanKeyData key;
17165  AttrNumber table_attno,
17166  type_attno;
17167  TupleDesc typeTupleDesc,
17168  tableTupleDesc;
17169  ObjectAddress tableobj,
17170  typeobj;
17171  HeapTuple classtuple;
17172 
17173  /* Validate the type. */
17174  typetuple = typenameType(NULL, ofTypename, NULL);
17175  check_of_type(typetuple);
17176  typeform = (Form_pg_type) GETSTRUCT(typetuple);
17177  typeid = typeform->oid;
17178 
17179  /* Fail if the table has any inheritance parents. */
17180  inheritsRelation = table_open(InheritsRelationId, AccessShareLock);
17181  ScanKeyInit(&key,
17182  Anum_pg_inherits_inhrelid,
17183  BTEqualStrategyNumber, F_OIDEQ,
17184  ObjectIdGetDatum(relid));
17185  scan = systable_beginscan(inheritsRelation, InheritsRelidSeqnoIndexId,
17186  true, NULL, 1, &key);
17188  ereport(ERROR,
17189  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
17190  errmsg("typed tables cannot inherit")));
17191  systable_endscan(scan);
17192  table_close(inheritsRelation, AccessShareLock);
17193 
17194  /*
17195  * Check the tuple descriptors for compatibility. Unlike inheritance, we
17196  * require that the order also match. However, attnotnull need not match.
17197  */
17198  typeTupleDesc = lookup_rowtype_tupdesc(typeid, -1);
17199  tableTupleDesc = RelationGetDescr(rel);
17200  table_attno = 1;
17201  for (type_attno = 1; type_attno <= typeTupleDesc->natts; type_attno++)
17202  {
17203  Form_pg_attribute type_attr,
17204  table_attr;
17205  const char *type_attname,
17206  *table_attname;
17207 
17208  /* Get the next non-dropped type attribute. */
17209  type_attr = TupleDescAttr(typeTupleDesc, type_attno - 1);
17210  if (type_attr->attisdropped)
17211  continue;
17212  type_attname = NameStr(type_attr->attname);
17213 
17214  /* Get the next non-dropped table attribute. */
17215  do
17216  {
17217  if (table_attno > tableTupleDesc->natts)
17218  ereport(ERROR,
17219  (errcode(ERRCODE_DATATYPE_MISMATCH),
17220  errmsg("table is missing column \"%s\"",
17221  type_attname)));
17222  table_attr = TupleDescAttr(tableTupleDesc, table_attno - 1);
17223  table_attno++;
17224  } while (table_attr->attisdropped);
17225  table_attname = NameStr(table_attr->attname);
17226 
17227  /* Compare name. */
17228  if (strncmp(table_attname, type_attname, NAMEDATALEN) != 0)
17229  ereport(ERROR,
17230  (errcode(ERRCODE_DATATYPE_MISMATCH),
17231  errmsg("table has column \"%s\" where type requires \"%s\"",
17232  table_attname, type_attname)));
17233 
17234  /* Compare type. */
17235  if (table_attr->atttypid != type_attr->atttypid ||
17236  table_attr->atttypmod != type_attr->atttypmod ||
17237  table_attr->attcollation != type_attr->attcollation)
17238  ereport(ERROR,
17239  (errcode(ERRCODE_DATATYPE_MISMATCH),
17240  errmsg("table \"%s\" has different type for column \"%s\"",
17241  RelationGetRelationName(rel), type_attname)));
17242  }
17243  ReleaseTupleDesc(typeTupleDesc);
17244 
17245  /* Any remaining columns at the end of the table had better be dropped. */
17246  for (; table_attno <= tableTupleDesc->natts; table_attno++)
17247  {
17248  Form_pg_attribute table_attr = TupleDescAttr(tableTupleDesc,
17249  table_attno - 1);
17250 
17251  if (!table_attr->attisdropped)
17252  ereport(ERROR,
17253  (errcode(ERRCODE_DATATYPE_MISMATCH),
17254  errmsg("table has extra column \"%s\"",
17255  NameStr(table_attr->attname))));
17256  }
17257 
17258  /* If the table was already typed, drop the existing dependency. */
17259  if (rel->rd_rel->reloftype)
17260  drop_parent_dependency(relid, TypeRelationId, rel->rd_rel->reloftype,
17262 
17263  /* Record a dependency on the new type. */
17264  tableobj.classId = RelationRelationId;
17265  tableobj.objectId = relid;
17266  tableobj.objectSubId = 0;
17267  typeobj.classId = TypeRelationId;
17268  typeobj.objectId = typeid;
17269  typeobj.objectSubId = 0;
17270  recordDependencyOn(&tableobj, &typeobj, DEPENDENCY_NORMAL);
17271 
17272  /* Update pg_class.reloftype */
17273  relationRelation = table_open(RelationRelationId, RowExclusiveLock);
17274  classtuple = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
17275  if (!HeapTupleIsValid(classtuple))
17276  elog(ERROR, "cache lookup failed for relation %u", relid);
17277  ((Form_pg_class) GETSTRUCT(classtuple))->reloftype = typeid;
17278  CatalogTupleUpdate(relationRelation, &classtuple->t_self, classtuple);
17279 
17280  InvokeObjectPostAlterHook(RelationRelationId, relid, 0);
17281 
17282  heap_freetuple(classtuple);
17283  table_close(relationRelation, RowExclusiveLock);
17284 
17285  ReleaseSysCache(typetuple);
17286 
17287  return typeobj;
17288 }
17289 
17290 /*
17291  * ALTER TABLE NOT OF
17292  *
17293  * Detach a typed table from its originating type. Just clear reloftype and
17294  * remove the dependency.
17295  */
17296 static void
17298 {
17299  Oid relid = RelationGetRelid(rel);
17300  Relation relationRelation;
17301  HeapTuple tuple;
17302 
17303  if (!OidIsValid(rel->rd_rel->reloftype))
17304  ereport(ERROR,
17305  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
17306  errmsg("\"%s\" is not a typed table",
17307  RelationGetRelationName(rel))));
17308 
17309  /*
17310  * We don't bother to check ownership of the type --- ownership of the
17311  * table is presumed enough rights. No lock required on the type, either.
17312  */
17313 
17314  drop_parent_dependency(relid, TypeRelationId, rel->rd_rel->reloftype,
17316 
17317  /* Clear pg_class.reloftype */
17318  relationRelation = table_open(RelationRelationId, RowExclusiveLock);
17319  tuple = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
17320  if (!HeapTupleIsValid(tuple))
17321  elog(ERROR, "cache lookup failed for relation %u", relid);
17322  ((Form_pg_class) GETSTRUCT(tuple))->reloftype = InvalidOid;
17323  CatalogTupleUpdate(relationRelation, &tuple->t_self, tuple);
17324 
17325  InvokeObjectPostAlterHook(RelationRelationId, relid, 0);
17326 
17327  heap_freetuple(tuple);
17328  table_close(relationRelation, RowExclusiveLock);
17329 }
17330 
17331 /*
17332  * relation_mark_replica_identity: Update a table's replica identity
17333  *
17334  * Iff ri_type = REPLICA_IDENTITY_INDEX, indexOid must be the Oid of a suitable
17335  * index. Otherwise, it must be InvalidOid.
17336  *
17337  * Caller had better hold an exclusive lock on the relation, as the results
17338  * of running two of these concurrently wouldn't be pretty.
17339  */
17340 static void
17341 relation_mark_replica_identity(Relation rel, char ri_type, Oid indexOid,
17342  bool is_internal)
17343 {
17344  Relation pg_index;
17345  Relation pg_class;
17346  HeapTuple pg_class_tuple;
17347  HeapTuple pg_index_tuple;
17348  Form_pg_class pg_class_form;
17349  Form_pg_index pg_index_form;
17350  ListCell *index;
17351 
17352  /*
17353  * Check whether relreplident has changed, and update it if so.
17354  */
17355  pg_class = table_open(RelationRelationId, RowExclusiveLock);
17356  pg_class_tuple = SearchSysCacheCopy1(RELOID,
17358  if (!HeapTupleIsValid(pg_class_tuple))
17359  elog(ERROR, "cache lookup failed for relation \"%s\"",
17361  pg_class_form = (Form_pg_class) GETSTRUCT(pg_class_tuple);
17362  if (pg_class_form->relreplident != ri_type)
17363  {
17364  pg_class_form->relreplident = ri_type;
17365  CatalogTupleUpdate(pg_class, &pg_class_tuple->t_self, pg_class_tuple);
17366  }
17367  table_close(pg_class, RowExclusiveLock);
17368  heap_freetuple(pg_class_tuple);
17369 
17370  /*
17371  * Update the per-index indisreplident flags correctly.
17372  */
17373  pg_index = table_open(IndexRelationId, RowExclusiveLock);
17374  foreach(index, RelationGetIndexList(rel))
17375  {
17376  Oid thisIndexOid = lfirst_oid(index);
17377  bool dirty = false;
17378 
17379  pg_index_tuple = SearchSysCacheCopy1(INDEXRELID,
17380  ObjectIdGetDatum(thisIndexOid));
17381  if (!HeapTupleIsValid(pg_index_tuple))
17382  elog(ERROR, "cache lookup failed for index %u", thisIndexOid);
17383  pg_index_form = (Form_pg_index) GETSTRUCT(pg_index_tuple);
17384 
17385  if (thisIndexOid == indexOid)
17386  {
17387  /* Set the bit if not already set. */
17388  if (!pg_index_form->indisreplident)
17389  {
17390  dirty = true;
17391  pg_index_form->indisreplident = true;
17392  }
17393  }
17394  else
17395  {
17396  /* Unset the bit if set. */
17397  if (pg_index_form->indisreplident)
17398  {
17399  dirty = true;
17400  pg_index_form->indisreplident = false;
17401  }
17402  }
17403 
17404  if (dirty)
17405  {
17406  CatalogTupleUpdate(pg_index, &pg_index_tuple->t_self, pg_index_tuple);
17407  InvokeObjectPostAlterHookArg(IndexRelationId, thisIndexOid, 0,
17408  InvalidOid, is_internal);
17409 
17410  /*
17411  * Invalidate the relcache for the table, so that after we commit
17412  * all sessions will refresh the table's replica identity index
17413  * before attempting any UPDATE or DELETE on the table. (If we
17414  * changed the table's pg_class row above, then a relcache inval
17415  * is already queued due to that; but we might not have.)
17416  */
17418  }
17419  heap_freetuple(pg_index_tuple);
17420  }
17421 
17422  table_close(pg_index, RowExclusiveLock);
17423 }
17424 
17425 /*
17426  * ALTER TABLE <name> REPLICA IDENTITY ...
17427  */
17428 static void
17430 {
17431  Oid indexOid;
17432  Relation indexRel;
17433  int key;
17434 
17435  if (stmt->identity_type == REPLICA_IDENTITY_DEFAULT)
17436  {
17437  relation_mark_replica_identity(rel, stmt->identity_type, InvalidOid, true);
17438  return;
17439  }
17440  else if (stmt->identity_type == REPLICA_IDENTITY_FULL)
17441  {
17442  relation_mark_replica_identity(rel, stmt->identity_type, InvalidOid, true);
17443  return;
17444  }
17445  else if (stmt->identity_type == REPLICA_IDENTITY_NOTHING)
17446  {
17447  relation_mark_replica_identity(rel, stmt->identity_type, InvalidOid, true);
17448  return;
17449  }
17450  else if (stmt->identity_type == REPLICA_IDENTITY_INDEX)
17451  {
17452  /* fallthrough */ ;
17453  }
17454  else
17455  elog(ERROR, "unexpected identity type %u", stmt->identity_type);
17456 
17457  /* Check that the index exists */
17458  indexOid = get_relname_relid(stmt->name, rel->rd_rel->relnamespace);
17459  if (!OidIsValid(indexOid))
17460  ereport(ERROR,
17461  (errcode(ERRCODE_UNDEFINED_OBJECT),
17462  errmsg("index \"%s\" for table \"%s\" does not exist",
17463  stmt->name, RelationGetRelationName(rel))));
17464 
17465  indexRel = index_open(indexOid, ShareLock);
17466 
17467  /* Check that the index is on the relation we're altering. */
17468  if (indexRel->rd_index == NULL ||
17469  indexRel->rd_index->indrelid != RelationGetRelid(rel))
17470  ereport(ERROR,
17471  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
17472  errmsg("\"%s\" is not an index for table \"%s\"",
17473  RelationGetRelationName(indexRel),
17474  RelationGetRelationName(rel))));
17475  /* The AM must support uniqueness, and the index must in fact be unique. */
17476  if (!indexRel->rd_indam->amcanunique ||
17477  !indexRel->rd_index->indisunique)
17478  ereport(ERROR,
17479  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
17480  errmsg("cannot use non-unique index \"%s\" as replica identity",
17481  RelationGetRelationName(indexRel))));
17482  /* Deferred indexes are not guaranteed to be always unique. */
17483  if (!indexRel->rd_index->indimmediate)
17484  ereport(ERROR,
17485  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
17486  errmsg("cannot use non-immediate index \"%s\" as replica identity",
17487  RelationGetRelationName(indexRel))));
17488  /* Expression indexes aren't supported. */
17489  if (RelationGetIndexExpressions(indexRel) != NIL)
17490  ereport(ERROR,
17491  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
17492  errmsg("cannot use expression index \"%s\" as replica identity",
17493  RelationGetRelationName(indexRel))));
17494  /* Predicate indexes aren't supported. */
17495  if (RelationGetIndexPredicate(indexRel) != NIL)
17496  ereport(ERROR,
17497  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
17498  errmsg("cannot use partial index \"%s\" as replica identity",
17499  RelationGetRelationName(indexRel))));
17500 
17501  /* Check index for nullable columns. */
17502  for (key = 0; key < IndexRelationGetNumberOfKeyAttributes(indexRel); key++)
17503  {
17504  int16 attno = indexRel->rd_index->indkey.values[key];
17505  Form_pg_attribute attr;
17506 
17507  /*
17508  * Reject any other system columns. (Going forward, we'll disallow
17509  * indexes containing such columns in the first place, but they might
17510  * exist in older branches.)
17511  */
17512  if (attno <= 0)
17513  ereport(ERROR,
17514  (errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
17515  errmsg("index \"%s\" cannot be used as replica identity because column %d is a system column",
17516  RelationGetRelationName(indexRel), attno)));
17517 
17518  attr = TupleDescAttr(rel->rd_att, attno - 1);
17519  if (!attr->attnotnull)
17520  ereport(ERROR,
17521  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
17522  errmsg("index \"%s\" cannot be used as replica identity because column \"%s\" is nullable",
17523  RelationGetRelationName(indexRel),
17524  NameStr(attr->attname))));
17525  }
17526 
17527  /* This index is suitable for use as a replica identity. Mark it. */
17528  relation_mark_replica_identity(rel, stmt->identity_type, indexOid, true);
17529 
17530  index_close(indexRel, NoLock);
17531 }
17532 
17533 /*
17534  * ALTER TABLE ENABLE/DISABLE ROW LEVEL SECURITY
17535  */
17536 static void
17538 {
17539  Relation pg_class;
17540  Oid relid;
17541  HeapTuple tuple;
17542 
17543  relid = RelationGetRelid(rel);
17544 
17545  /* Pull the record for this relation and update it */
17546  pg_class = table_open(RelationRelationId, RowExclusiveLock);
17547 
17548  tuple = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
17549 
17550  if (!HeapTupleIsValid(tuple))
17551  elog(ERROR, "cache lookup failed for relation %u", relid);
17552 
17553  ((Form_pg_class) GETSTRUCT(tuple))->relrowsecurity = rls;
17554  CatalogTupleUpdate(pg_class, &tuple->t_self, tuple);
17555 
17556  InvokeObjectPostAlterHook(RelationRelationId,
17557  RelationGetRelid(rel), 0);
17558 
17559  table_close(pg_class, RowExclusiveLock);
17560  heap_freetuple(tuple);
17561 }
17562 
17563 /*
17564  * ALTER TABLE FORCE/NO FORCE ROW LEVEL SECURITY
17565  */
17566 static void
17568 {
17569  Relation pg_class;
17570  Oid relid;
17571  HeapTuple tuple;
17572 
17573  relid = RelationGetRelid(rel);
17574 
17575  pg_class = table_open(RelationRelationId, RowExclusiveLock);
17576 
17577  tuple = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
17578 
17579  if (!HeapTupleIsValid(tuple))
17580  elog(ERROR, "cache lookup failed for relation %u", relid);
17581 
17582  ((Form_pg_class) GETSTRUCT(tuple))->relforcerowsecurity = force_rls;
17583  CatalogTupleUpdate(pg_class, &tuple->t_self, tuple);
17584 
17585  InvokeObjectPostAlterHook(RelationRelationId,
17586  RelationGetRelid(rel), 0);
17587 
17588  table_close(pg_class, RowExclusiveLock);
17589  heap_freetuple(tuple);
17590 }
17591 
17592 /*
17593  * ALTER FOREIGN TABLE <name> OPTIONS (...)
17594  */
17595 static void
17597 {
17598  Relation ftrel;
17599  ForeignServer *server;
17600  ForeignDataWrapper *fdw;
17601  HeapTuple tuple;
17602  bool isnull;
17603  Datum repl_val[Natts_pg_foreign_table];
17604  bool repl_null[Natts_pg_foreign_table];
17605  bool repl_repl[Natts_pg_foreign_table];
17606  Datum datum;
17607  Form_pg_foreign_table tableform;
17608 
17609  if (options == NIL)
17610  return;
17611 
17612  ftrel = table_open(ForeignTableRelationId, RowExclusiveLock);
17613 
17614  tuple = SearchSysCacheCopy1(FOREIGNTABLEREL,
17615  ObjectIdGetDatum(rel->rd_id));
17616  if (!HeapTupleIsValid(tuple))
17617  ereport(ERROR,
17618  (errcode(ERRCODE_UNDEFINED_OBJECT),
17619  errmsg("foreign table \"%s\" does not exist",
17620  RelationGetRelationName(rel))));
17621  tableform = (Form_pg_foreign_table) GETSTRUCT(tuple);
17622  server = GetForeignServer(tableform->ftserver);
17623  fdw = GetForeignDataWrapper(server->fdwid);
17624 
17625  memset(repl_val, 0, sizeof(repl_val));
17626  memset(repl_null, false, sizeof(repl_null));
17627  memset(repl_repl, false, sizeof(repl_repl));
17628 
17629  /* Extract the current options */
17630  datum = SysCacheGetAttr(FOREIGNTABLEREL,
17631  tuple,
17632  Anum_pg_foreign_table_ftoptions,
17633  &isnull);
17634  if (isnull)
17635  datum = PointerGetDatum(NULL);
17636 
17637  /* Transform the options */
17638  datum = transformGenericOptions(ForeignTableRelationId,
17639  datum,
17640  options,
17641  fdw->fdwvalidator);
17642 
17643  if (PointerIsValid(DatumGetPointer(datum)))
17644  repl_val[Anum_pg_foreign_table_ftoptions - 1] = datum;
17645  else
17646  repl_null[Anum_pg_foreign_table_ftoptions - 1] = true;
17647 
17648  repl_repl[Anum_pg_foreign_table_ftoptions - 1] = true;
17649 
17650  /* Everything looks good - update the tuple */
17651 
17652  tuple = heap_modify_tuple(tuple, RelationGetDescr(ftrel),
17653  repl_val, repl_null, repl_repl);
17654 
17655  CatalogTupleUpdate(ftrel, &tuple->t_self, tuple);
17656 
17657  /*
17658  * Invalidate relcache so that all sessions will refresh any cached plans
17659  * that might depend on the old options.
17660  */
17662 
17663  InvokeObjectPostAlterHook(ForeignTableRelationId,
17664  RelationGetRelid(rel), 0);
17665 
17666  table_close(ftrel, RowExclusiveLock);
17667 
17668  heap_freetuple(tuple);
17669 }
17670 
17671 /*
17672  * ALTER TABLE ALTER COLUMN SET COMPRESSION
17673  *
17674  * Return value is the address of the modified column
17675  */
17676 static ObjectAddress
17678  const char *column,
17679  Node *newValue,
17680  LOCKMODE lockmode)
17681 {
17682  Relation attrel;
17683  HeapTuple tuple;
17684  Form_pg_attribute atttableform;
17686  char *compression;
17687  char cmethod;
17688  ObjectAddress address;
17689 
17690  compression = strVal(newValue);
17691 
17692  attrel = table_open(AttributeRelationId, RowExclusiveLock);
17693 
17694  /* copy the cache entry so we can scribble on it below */
17695  tuple = SearchSysCacheCopyAttName(RelationGetRelid(rel), column);
17696  if (!HeapTupleIsValid(tuple))
17697  ereport(ERROR,
17698  (errcode(ERRCODE_UNDEFINED_COLUMN),
17699  errmsg("column \"%s\" of relation \"%s\" does not exist",
17700  column, RelationGetRelationName(rel))));
17701 
17702  /* prevent them from altering a system attribute */
17703  atttableform = (Form_pg_attribute) GETSTRUCT(tuple);
17704  attnum = atttableform->attnum;
17705  if (attnum <= 0)
17706  ereport(ERROR,
17707  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
17708  errmsg("cannot alter system column \"%s\"", column)));
17709 
17710  /*
17711  * Check that column type is compressible, then get the attribute
17712  * compression method code
17713  */
17714  cmethod = GetAttributeCompression(atttableform->atttypid, compression);
17715 
17716  /* update pg_attribute entry */
17717  atttableform->attcompression = cmethod;
17718  CatalogTupleUpdate(attrel, &tuple->t_self, tuple);
17719 
17720  InvokeObjectPostAlterHook(RelationRelationId,
17721  RelationGetRelid(rel),
17722  attnum);
17723 
17724  /*
17725  * Apply the change to indexes as well (only for simple index columns,
17726  * matching behavior of index.c ConstructTupleDescriptor()).
17727  */
17728  SetIndexStorageProperties(rel, attrel, attnum,
17729  false, 0,
17730  true, cmethod,
17731  lockmode);
17732 
17733  heap_freetuple(tuple);
17734 
17735  table_close(attrel, RowExclusiveLock);
17736 
17737  /* make changes visible */
17739 
17740  ObjectAddressSubSet(address, RelationRelationId,
17741  RelationGetRelid(rel), attnum);
17742  return address;
17743 }
17744 
17745 
17746 /*
17747  * Preparation phase for SET LOGGED/UNLOGGED
17748  *
17749  * This verifies that we're not trying to change a temp table. Also,
17750  * existing foreign key constraints are checked to avoid ending up with
17751  * permanent tables referencing unlogged tables.
17752  *
17753  * Return value is false if the operation is a no-op (in which case the
17754  * checks are skipped), otherwise true.
17755  */
17756 static bool
17758 {
17759  Relation pg_constraint;
17760  HeapTuple tuple;
17761  SysScanDesc scan;
17762  ScanKeyData skey[1];
17763 
17764  /*
17765  * Disallow changing status for a temp table. Also verify whether we can
17766  * get away with doing nothing; in such cases we don't need to run the
17767  * checks below, either.
17768  */
17769  switch (rel->rd_rel->relpersistence)
17770  {
17771  case RELPERSISTENCE_TEMP:
17772  ereport(ERROR,
17773  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
17774  errmsg("cannot change logged status of table \"%s\" because it is temporary",
17776  errtable(rel)));
17777  break;
17778  case RELPERSISTENCE_PERMANENT:
17779  if (toLogged)
17780  /* nothing to do */
17781  return false;
17782  break;
17783  case RELPERSISTENCE_UNLOGGED:
17784  if (!toLogged)
17785  /* nothing to do */
17786  return false;
17787  break;
17788  }
17789 
17790  /*
17791  * Check that the table is not part of any publication when changing to
17792  * UNLOGGED, as UNLOGGED tables can't be published.
17793  */
17794  if (!toLogged &&
17796  ereport(ERROR,
17797  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
17798  errmsg("cannot change table \"%s\" to unlogged because it is part of a publication",
17800  errdetail("Unlogged relations cannot be replicated.")));
17801 
17802  /*
17803  * Check existing foreign key constraints to preserve the invariant that
17804  * permanent tables cannot reference unlogged ones. Self-referencing
17805  * foreign keys can safely be ignored.
17806  */
17807  pg_constraint = table_open(ConstraintRelationId, AccessShareLock);
17808 
17809  /*
17810  * Scan conrelid if changing to permanent, else confrelid. This also
17811  * determines whether a useful index exists.
17812  */
17813  ScanKeyInit(&skey[0],
17814  toLogged ? Anum_pg_constraint_conrelid :
17815  Anum_pg_constraint_confrelid,
17816  BTEqualStrategyNumber, F_OIDEQ,
17818  scan = systable_beginscan(pg_constraint,
17819  toLogged ? ConstraintRelidTypidNameIndexId : InvalidOid,
17820  true, NULL, 1, skey);
17821 
17822  while (HeapTupleIsValid(tuple = systable_getnext(scan)))
17823  {
17825 
17826  if (con->contype == CONSTRAINT_FOREIGN)
17827  {
17828  Oid foreignrelid;
17829  Relation foreignrel;
17830 
17831  /* the opposite end of what we used as scankey */
17832  foreignrelid = toLogged ? con->confrelid : con->conrelid;
17833 
17834  /* ignore if self-referencing */
17835  if (RelationGetRelid(rel) == foreignrelid)
17836  continue;
17837 
17838  foreignrel = relation_open(foreignrelid, AccessShareLock);
17839 
17840  if (toLogged)
17841  {
17842  if (!RelationIsPermanent(foreignrel))
17843  ereport(ERROR,
17844  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
17845  errmsg("could not change table \"%s\" to logged because it references unlogged table \"%s\"",
17847  RelationGetRelationName(foreignrel)),
17848  errtableconstraint(rel, NameStr(con->conname))));
17849  }
17850  else
17851  {
17852  if (RelationIsPermanent(foreignrel))
17853  ereport(ERROR,
17854  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
17855  errmsg("could not change table \"%s\" to unlogged because it references logged table \"%s\"",
17857  RelationGetRelationName(foreignrel)),
17858  errtableconstraint(rel, NameStr(con->conname))));
17859  }
17860 
17861  relation_close(foreignrel, AccessShareLock);
17862  }
17863  }
17864 
17865  systable_endscan(scan);
17866 
17867  table_close(pg_constraint, AccessShareLock);
17868 
17869  return true;
17870 }
17871 
17872 /*
17873  * Execute ALTER TABLE SET SCHEMA
17874  */
17877 {
17878  Relation rel;
17879  Oid relid;
17880  Oid oldNspOid;
17881  Oid nspOid;
17882  RangeVar *newrv;
17883  ObjectAddresses *objsMoved;
17884  ObjectAddress myself;
17885 
17887  stmt->missing_ok ? RVR_MISSING_OK : 0,
17889  (void *) stmt);
17890 
17891  if (!OidIsValid(relid))
17892  {
17893  ereport(NOTICE,
17894  (errmsg("relation \"%s\" does not exist, skipping",
17895  stmt->relation->relname)));
17896  return InvalidObjectAddress;
17897  }
17898 
17899  rel = relation_open(relid, NoLock);
17900 
17901  oldNspOid = RelationGetNamespace(rel);
17902 
17903  /* If it's an owned sequence, disallow moving it by itself. */
17904  if (rel->rd_rel->relkind == RELKIND_SEQUENCE)
17905  {
17906  Oid tableId;
17907  int32 colId;
17908 
17909  if (sequenceIsOwned(relid, DEPENDENCY_AUTO, &tableId, &colId) ||
17910  sequenceIsOwned(relid, DEPENDENCY_INTERNAL, &tableId, &colId))
17911  ereport(ERROR,
17912  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
17913  errmsg("cannot move an owned sequence into another schema"),
17914  errdetail("Sequence \"%s\" is linked to table \"%s\".",
17916  get_rel_name(tableId))));
17917  }
17918 
17919  /* Get and lock schema OID and check its permissions. */
17920  newrv = makeRangeVar(stmt->newschema, RelationGetRelationName(rel), -1);
17921  nspOid = RangeVarGetAndCheckCreationNamespace(newrv, NoLock, NULL);
17922 
17923  /* common checks on switching namespaces */
17924  CheckSetNamespace(oldNspOid, nspOid);
17925 
17926  objsMoved = new_object_addresses();
17927  AlterTableNamespaceInternal(rel, oldNspOid, nspOid, objsMoved);
17928  free_object_addresses(objsMoved);
17929 
17930  ObjectAddressSet(myself, RelationRelationId, relid);
17931 
17932  if (oldschema)
17933  *oldschema = oldNspOid;
17934 
17935  /* close rel, but keep lock until commit */
17936  relation_close(rel, NoLock);
17937 
17938  return myself;
17939 }
17940 
17941 /*
17942  * The guts of relocating a table or materialized view to another namespace:
17943  * besides moving the relation itself, its dependent objects are relocated to
17944  * the new schema.
17945  */
17946 void
17948  ObjectAddresses *objsMoved)
17949 {
17950  Relation classRel;
17951 
17952  Assert(objsMoved != NULL);
17953 
17954  /* OK, modify the pg_class row and pg_depend entry */
17955  classRel = table_open(RelationRelationId, RowExclusiveLock);
17956 
17957  AlterRelationNamespaceInternal(classRel, RelationGetRelid(rel), oldNspOid,
17958  nspOid, true, objsMoved);
17959 
17960  /* Fix the table's row type too, if it has one */
17961  if (OidIsValid(rel->rd_rel->reltype))
17962  AlterTypeNamespaceInternal(rel->rd_rel->reltype,
17963  nspOid, false, false, objsMoved);
17964 
17965  /* Fix other dependent stuff */
17966  AlterIndexNamespaces(classRel, rel, oldNspOid, nspOid, objsMoved);
17967  AlterSeqNamespaces(classRel, rel, oldNspOid, nspOid,
17968  objsMoved, AccessExclusiveLock);
17969  AlterConstraintNamespaces(RelationGetRelid(rel), oldNspOid, nspOid,
17970  false, objsMoved);
17971 
17972  table_close(classRel, RowExclusiveLock);
17973 }
17974 
17975 /*
17976  * The guts of relocating a relation to another namespace: fix the pg_class
17977  * entry, and the pg_depend entry if any. Caller must already have
17978  * opened and write-locked pg_class.
17979  */
17980 void
17982  Oid oldNspOid, Oid newNspOid,
17983  bool hasDependEntry,
17984  ObjectAddresses *objsMoved)
17985 {
17986  HeapTuple classTup;
17987  Form_pg_class classForm;
17988  ObjectAddress thisobj;
17989  bool already_done = false;
17990 
17991  classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relOid));
17992  if (!HeapTupleIsValid(classTup))
17993  elog(ERROR, "cache lookup failed for relation %u", relOid);
17994  classForm = (Form_pg_class) GETSTRUCT(classTup);
17995 
17996  Assert(classForm->relnamespace == oldNspOid);
17997 
17998  thisobj.classId = RelationRelationId;
17999  thisobj.objectId = relOid;
18000  thisobj.objectSubId = 0;
18001 
18002  /*
18003  * If the object has already been moved, don't move it again. If it's
18004  * already in the right place, don't move it, but still fire the object
18005  * access hook.
18006  */
18007  already_done = object_address_present(&thisobj, objsMoved);
18008  if (!already_done && oldNspOid != newNspOid)
18009  {
18010  /* check for duplicate name (more friendly than unique-index failure) */
18011  if (get_relname_relid(NameStr(classForm->relname),
18012  newNspOid) != InvalidOid)
18013  ereport(ERROR,
18014  (errcode(ERRCODE_DUPLICATE_TABLE),
18015  errmsg("relation \"%s\" already exists in schema \"%s\"",
18016  NameStr(classForm->relname),
18017  get_namespace_name(newNspOid))));
18018 
18019  /* classTup is a copy, so OK to scribble on */
18020  classForm->relnamespace = newNspOid;
18021 
18022  CatalogTupleUpdate(classRel, &classTup->t_self, classTup);
18023 
18024  /* Update dependency on schema if caller said so */
18025  if (hasDependEntry &&
18026  changeDependencyFor(RelationRelationId,
18027  relOid,
18028  NamespaceRelationId,
18029  oldNspOid,
18030  newNspOid) != 1)
18031  elog(ERROR, "could not change schema dependency for relation \"%s\"",
18032  NameStr(classForm->relname));
18033  }
18034  if (!already_done)
18035  {
18036  add_exact_object_address(&thisobj, objsMoved);
18037 
18038  InvokeObjectPostAlterHook(RelationRelationId, relOid, 0);
18039  }
18040 
18041  heap_freetuple(classTup);
18042 }
18043 
18044 /*
18045  * Move all indexes for the specified relation to another namespace.
18046  *
18047  * Note: we assume adequate permission checking was done by the caller,
18048  * and that the caller has a suitable lock on the owning relation.
18049  */
18050 static void
18052  Oid oldNspOid, Oid newNspOid, ObjectAddresses *objsMoved)
18053 {
18054  List *indexList;
18055  ListCell *l;
18056 
18057  indexList = RelationGetIndexList(rel);
18058 
18059  foreach(l, indexList)
18060  {
18061  Oid indexOid = lfirst_oid(l);
18062  ObjectAddress thisobj;
18063 
18064  thisobj.classId = RelationRelationId;
18065  thisobj.objectId = indexOid;
18066  thisobj.objectSubId = 0;
18067 
18068  /*
18069  * Note: currently, the index will not have its own dependency on the
18070  * namespace, so we don't need to do changeDependencyFor(). There's no
18071  * row type in pg_type, either.
18072  *
18073  * XXX this objsMoved test may be pointless -- surely we have a single
18074  * dependency link from a relation to each index?
18075  */
18076  if (!object_address_present(&thisobj, objsMoved))
18077  {
18078  AlterRelationNamespaceInternal(classRel, indexOid,
18079  oldNspOid, newNspOid,
18080  false, objsMoved);
18081  add_exact_object_address(&thisobj, objsMoved);
18082  }
18083  }
18084 
18085  list_free(indexList);
18086 }
18087 
18088 /*
18089  * Move all identity and SERIAL-column sequences of the specified relation to another
18090  * namespace.
18091  *
18092  * Note: we assume adequate permission checking was done by the caller,
18093  * and that the caller has a suitable lock on the owning relation.
18094  */
18095 static void
18097  Oid oldNspOid, Oid newNspOid, ObjectAddresses *objsMoved,
18098  LOCKMODE lockmode)
18099 {
18100  Relation depRel;
18101  SysScanDesc scan;
18102  ScanKeyData key[2];
18103  HeapTuple tup;
18104 
18105  /*
18106  * SERIAL sequences are those having an auto dependency on one of the
18107  * table's columns (we don't care *which* column, exactly).
18108  */
18109  depRel = table_open(DependRelationId, AccessShareLock);
18110 
18111  ScanKeyInit(&key[0],
18112  Anum_pg_depend_refclassid,
18113  BTEqualStrategyNumber, F_OIDEQ,
18114  ObjectIdGetDatum(RelationRelationId));
18115  ScanKeyInit(&key[1],
18116  Anum_pg_depend_refobjid,
18117  BTEqualStrategyNumber, F_OIDEQ,
18119  /* we leave refobjsubid unspecified */
18120 
18121  scan = systable_beginscan(depRel, DependReferenceIndexId, true,
18122  NULL, 2, key);
18123 
18124  while (HeapTupleIsValid(tup = systable_getnext(scan)))
18125  {
18126  Form_pg_depend depForm = (Form_pg_depend) GETSTRUCT(tup);
18127  Relation seqRel;
18128 
18129  /* skip dependencies other than auto dependencies on columns */
18130  if (depForm->refobjsubid == 0 ||
18131  depForm->classid != RelationRelationId ||
18132  depForm->objsubid != 0 ||
18133  !(depForm->deptype == DEPENDENCY_AUTO || depForm->deptype == DEPENDENCY_INTERNAL))
18134  continue;
18135 
18136  /* Use relation_open just in case it's an index */
18137  seqRel = relation_open(depForm->objid, lockmode);
18138 
18139  /* skip non-sequence relations */
18140  if (RelationGetForm(seqRel)->relkind != RELKIND_SEQUENCE)
18141  {
18142  /* No need to keep the lock */
18143  relation_close(seqRel, lockmode);
18144  continue;
18145  }
18146 
18147  /* Fix the pg_class and pg_depend entries */
18148  AlterRelationNamespaceInternal(classRel, depForm->objid,
18149  oldNspOid, newNspOid,
18150  true, objsMoved);
18151 
18152  /*
18153  * Sequences used to have entries in pg_type, but no longer do. If we
18154  * ever re-instate that, we'll need to move the pg_type entry to the
18155  * new namespace, too (using AlterTypeNamespaceInternal).
18156  */
18157  Assert(RelationGetForm(seqRel)->reltype == InvalidOid);
18158 
18159  /* Now we can close it. Keep the lock till end of transaction. */
18160  relation_close(seqRel, NoLock);
18161  }
18162 
18163  systable_endscan(scan);
18164 
18166 }
18167 
18168 
18169 /*
18170  * This code supports
18171  * CREATE TEMP TABLE ... ON COMMIT { DROP | PRESERVE ROWS | DELETE ROWS }
18172  *
18173  * Because we only support this for TEMP tables, it's sufficient to remember
18174  * the state in a backend-local data structure.
18175  */
18176 
18177 /*
18178  * Register a newly-created relation's ON COMMIT action.
18179  */
18180 void
18182 {
18183  OnCommitItem *oc;
18184  MemoryContext oldcxt;
18185 
18186  /*
18187  * We needn't bother registering the relation unless there is an ON COMMIT
18188  * action we need to take.
18189  */
18191  return;
18192 
18194 
18195  oc = (OnCommitItem *) palloc(sizeof(OnCommitItem));
18196  oc->relid = relid;
18197  oc->oncommit = action;
18200 
18201  /*
18202  * We use lcons() here so that ON COMMIT actions are processed in reverse
18203  * order of registration. That might not be essential but it seems
18204  * reasonable.
18205  */
18206  on_commits = lcons(oc, on_commits);
18207 
18208  MemoryContextSwitchTo(oldcxt);
18209 }
18210 
18211 /*
18212  * Unregister any ON COMMIT action when a relation is deleted.
18213  *
18214  * Actually, we only mark the OnCommitItem entry as to be deleted after commit.
18215  */
18216 void
18218 {
18219  ListCell *l;
18220 
18221  foreach(l, on_commits)
18222  {
18223  OnCommitItem *oc = (OnCommitItem *) lfirst(l);
18224 
18225  if (oc->relid == relid)
18226  {
18228  break;
18229  }
18230  }
18231 }
18232 
18233 /*
18234  * Perform ON COMMIT actions.
18235  *
18236  * This is invoked just before actually committing, since it's possible
18237  * to encounter errors.
18238  */
18239 void
18241 {
18242  ListCell *l;
18243  List *oids_to_truncate = NIL;
18244  List *oids_to_drop = NIL;
18245 
18246  foreach(l, on_commits)
18247  {
18248  OnCommitItem *oc = (OnCommitItem *) lfirst(l);
18249 
18250  /* Ignore entry if already dropped in this xact */
18252  continue;
18253 
18254  switch (oc->oncommit)
18255  {
18256  case ONCOMMIT_NOOP:
18258  /* Do nothing (there shouldn't be such entries, actually) */
18259  break;
18260  case ONCOMMIT_DELETE_ROWS:
18261 
18262  /*
18263  * If this transaction hasn't accessed any temporary
18264  * relations, we can skip truncating ON COMMIT DELETE ROWS
18265  * tables, as they must still be empty.
18266  */
18268  oids_to_truncate = lappend_oid(oids_to_truncate, oc->relid);
18269  break;
18270  case ONCOMMIT_DROP:
18271  oids_to_drop = lappend_oid(oids_to_drop, oc->relid);
18272  break;
18273  }
18274  }
18275 
18276  /*
18277  * Truncate relations before dropping so that all dependencies between
18278  * relations are removed after they are worked on. Doing it like this
18279  * might be a waste as it is possible that a relation being truncated will
18280  * be dropped anyway due to its parent being dropped, but this makes the
18281  * code more robust because of not having to re-check that the relation
18282  * exists at truncation time.
18283  */
18284  if (oids_to_truncate != NIL)
18285  heap_truncate(oids_to_truncate);
18286 
18287  if (oids_to_drop != NIL)
18288  {
18289  ObjectAddresses *targetObjects = new_object_addresses();
18290 
18291  foreach(l, oids_to_drop)
18292  {
18293  ObjectAddress object;
18294 
18295  object.classId = RelationRelationId;
18296  object.objectId = lfirst_oid(l);
18297  object.objectSubId = 0;
18298 
18299  Assert(!object_address_present(&object, targetObjects));
18300 
18301  add_exact_object_address(&object, targetObjects);
18302  }
18303 
18304  /*
18305  * Object deletion might involve toast table access (to clean up
18306  * toasted catalog entries), so ensure we have a valid snapshot.
18307  */
18309 
18310  /*
18311  * Since this is an automatic drop, rather than one directly initiated
18312  * by the user, we pass the PERFORM_DELETION_INTERNAL flag.
18313  */
18314  performMultipleDeletions(targetObjects, DROP_CASCADE,
18316 
18318 
18319 #ifdef USE_ASSERT_CHECKING
18320 
18321  /*
18322  * Note that table deletion will call remove_on_commit_action, so the
18323  * entry should get marked as deleted.
18324  */
18325  foreach(l, on_commits)
18326  {
18327  OnCommitItem *oc = (OnCommitItem *) lfirst(l);
18328 
18329  if (oc->oncommit != ONCOMMIT_DROP)
18330  continue;
18331 
18333  }
18334 #endif
18335  }
18336 }
18337 
18338 /*
18339  * Post-commit or post-abort cleanup for ON COMMIT management.
18340  *
18341  * All we do here is remove no-longer-needed OnCommitItem entries.
18342  *
18343  * During commit, remove entries that were deleted during this transaction;
18344  * during abort, remove those created during this transaction.
18345  */
18346 void
18348 {
18349  ListCell *cur_item;
18350 
18351  foreach(cur_item, on_commits)
18352  {
18353  OnCommitItem *oc = (OnCommitItem *) lfirst(cur_item);
18354 
18355  if (isCommit ? oc->deleting_subid != InvalidSubTransactionId :
18357  {
18358  /* cur_item must be removed */
18360  pfree(oc);
18361  }
18362  else
18363  {
18364  /* cur_item must be preserved */
18367  }
18368  }
18369 }
18370 
18371 /*
18372  * Post-subcommit or post-subabort cleanup for ON COMMIT management.
18373  *
18374  * During subabort, we can immediately remove entries created during this
18375  * subtransaction. During subcommit, just relabel entries marked during
18376  * this subtransaction as being the parent's responsibility.
18377  */
18378 void
18380  SubTransactionId parentSubid)
18381 {
18382  ListCell *cur_item;
18383 
18384  foreach(cur_item, on_commits)
18385  {
18386  OnCommitItem *oc = (OnCommitItem *) lfirst(cur_item);
18387 
18388  if (!isCommit && oc->creating_subid == mySubid)
18389  {
18390  /* cur_item must be removed */
18392  pfree(oc);
18393  }
18394  else
18395  {
18396  /* cur_item must be preserved */
18397  if (oc->creating_subid == mySubid)
18398  oc->creating_subid = parentSubid;
18399  if (oc->deleting_subid == mySubid)
18400  oc->deleting_subid = isCommit ? parentSubid : InvalidSubTransactionId;
18401  }
18402  }
18403 }
18404 
18405 /*
18406  * This is intended as a callback for RangeVarGetRelidExtended(). It allows
18407  * the relation to be locked only if (1) it's a plain or partitioned table,
18408  * materialized view, or TOAST table and (2) the current user is the owner (or
18409  * the superuser) or has been granted MAINTAIN. This meets the
18410  * permission-checking needs of CLUSTER, REINDEX TABLE, and REFRESH
18411  * MATERIALIZED VIEW; we expose it here so that it can be used by all.
18412  */
18413 void
18415  Oid relId, Oid oldRelId, void *arg)
18416 {
18417  char relkind;
18418  AclResult aclresult;
18419 
18420  /* Nothing to do if the relation was not found. */
18421  if (!OidIsValid(relId))
18422  return;
18423 
18424  /*
18425  * If the relation does exist, check whether it's an index. But note that
18426  * the relation might have been dropped between the time we did the name
18427  * lookup and now. In that case, there's nothing to do.
18428  */
18429  relkind = get_rel_relkind(relId);
18430  if (!relkind)
18431  return;
18432  if (relkind != RELKIND_RELATION && relkind != RELKIND_TOASTVALUE &&
18433  relkind != RELKIND_MATVIEW && relkind != RELKIND_PARTITIONED_TABLE)
18434  ereport(ERROR,
18435  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
18436  errmsg("\"%s\" is not a table or materialized view", relation->relname)));
18437 
18438  /* Check permissions */
18439  aclresult = pg_class_aclcheck(relId, GetUserId(), ACL_MAINTAIN);
18440  if (aclresult != ACLCHECK_OK)
18441  aclcheck_error(aclresult,
18443  relation->relname);
18444 }
18445 
18446 /*
18447  * Callback to RangeVarGetRelidExtended() for TRUNCATE processing.
18448  */
18449 static void
18451  Oid relId, Oid oldRelId, void *arg)
18452 {
18453  HeapTuple tuple;
18454 
18455  /* Nothing to do if the relation was not found. */
18456  if (!OidIsValid(relId))
18457  return;
18458 
18459  tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relId));
18460  if (!HeapTupleIsValid(tuple)) /* should not happen */
18461  elog(ERROR, "cache lookup failed for relation %u", relId);
18462 
18463  truncate_check_rel(relId, (Form_pg_class) GETSTRUCT(tuple));
18464  truncate_check_perms(relId, (Form_pg_class) GETSTRUCT(tuple));
18465 
18466  ReleaseSysCache(tuple);
18467 }
18468 
18469 /*
18470  * Callback for RangeVarGetRelidExtended(). Checks that the current user is
18471  * the owner of the relation, or superuser.
18472  */
18473 void
18475  Oid relId, Oid oldRelId, void *arg)
18476 {
18477  HeapTuple tuple;
18478 
18479  /* Nothing to do if the relation was not found. */
18480  if (!OidIsValid(relId))
18481  return;
18482 
18483  tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relId));
18484  if (!HeapTupleIsValid(tuple)) /* should not happen */
18485  elog(ERROR, "cache lookup failed for relation %u", relId);
18486 
18487  if (!object_ownercheck(RelationRelationId, relId, GetUserId()))
18489  relation->relname);
18490 
18491  if (!allowSystemTableMods &&
18492  IsSystemClass(relId, (Form_pg_class) GETSTRUCT(tuple)))
18493  ereport(ERROR,
18494  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
18495  errmsg("permission denied: \"%s\" is a system catalog",
18496  relation->relname)));
18497 
18498  ReleaseSysCache(tuple);
18499 }
18500 
18501 /*
18502  * Common RangeVarGetRelid callback for rename, set schema, and alter table
18503  * processing.
18504  */
18505 static void
18507  void *arg)
18508 {
18509  Node *stmt = (Node *) arg;
18510  ObjectType reltype;
18511  HeapTuple tuple;
18512  Form_pg_class classform;
18513  AclResult aclresult;
18514  char relkind;
18515 
18516  tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
18517  if (!HeapTupleIsValid(tuple))
18518  return; /* concurrently dropped */
18519  classform = (Form_pg_class) GETSTRUCT(tuple);
18520  relkind = classform->relkind;
18521 
18522  /* Must own relation. */
18523  if (!object_ownercheck(RelationRelationId, relid, GetUserId()))
18525 
18526  /* No system table modifications unless explicitly allowed. */
18527  if (!allowSystemTableMods && IsSystemClass(relid, classform))
18528  ereport(ERROR,
18529  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
18530  errmsg("permission denied: \"%s\" is a system catalog",
18531  rv->relname)));
18532 
18533  /*
18534  * Extract the specified relation type from the statement parse tree.
18535  *
18536  * Also, for ALTER .. RENAME, check permissions: the user must (still)
18537  * have CREATE rights on the containing namespace.
18538  */
18539  if (IsA(stmt, RenameStmt))
18540  {
18541  aclresult = object_aclcheck(NamespaceRelationId, classform->relnamespace,
18542  GetUserId(), ACL_CREATE);
18543  if (aclresult != ACLCHECK_OK)
18544  aclcheck_error(aclresult, OBJECT_SCHEMA,
18545  get_namespace_name(classform->relnamespace));
18546  reltype = ((RenameStmt *) stmt)->renameType;
18547  }
18548  else if (IsA(stmt, AlterObjectSchemaStmt))
18549  reltype = ((AlterObjectSchemaStmt *) stmt)->objectType;
18550 
18551  else if (IsA(stmt, AlterTableStmt))
18552  reltype = ((AlterTableStmt *) stmt)->objtype;
18553  else
18554  {
18555  elog(ERROR, "unrecognized node type: %d", (int) nodeTag(stmt));
18556  reltype = OBJECT_TABLE; /* placate compiler */
18557  }
18558 
18559  /*
18560  * For compatibility with prior releases, we allow ALTER TABLE to be used
18561  * with most other types of relations (but not composite types). We allow
18562  * similar flexibility for ALTER INDEX in the case of RENAME, but not
18563  * otherwise. Otherwise, the user must select the correct form of the
18564  * command for the relation at issue.
18565  */
18566  if (reltype == OBJECT_SEQUENCE && relkind != RELKIND_SEQUENCE)
18567  ereport(ERROR,
18568  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
18569  errmsg("\"%s\" is not a sequence", rv->relname)));
18570 
18571  if (reltype == OBJECT_VIEW && relkind != RELKIND_VIEW)
18572  ereport(ERROR,
18573  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
18574  errmsg("\"%s\" is not a view", rv->relname)));
18575 
18576  if (reltype == OBJECT_MATVIEW && relkind != RELKIND_MATVIEW)
18577  ereport(ERROR,
18578  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
18579  errmsg("\"%s\" is not a materialized view", rv->relname)));
18580 
18581  if (reltype == OBJECT_FOREIGN_TABLE && relkind != RELKIND_FOREIGN_TABLE)
18582  ereport(ERROR,
18583  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
18584  errmsg("\"%s\" is not a foreign table", rv->relname)));
18585 
18586  if (reltype == OBJECT_TYPE && relkind != RELKIND_COMPOSITE_TYPE)
18587  ereport(ERROR,
18588  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
18589  errmsg("\"%s\" is not a composite type", rv->relname)));
18590 
18591  if (reltype == OBJECT_INDEX && relkind != RELKIND_INDEX &&
18592  relkind != RELKIND_PARTITIONED_INDEX
18593  && !IsA(stmt, RenameStmt))
18594  ereport(ERROR,
18595  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
18596  errmsg("\"%s\" is not an index", rv->relname)));
18597 
18598  /*
18599  * Don't allow ALTER TABLE on composite types. We want people to use ALTER
18600  * TYPE for that.
18601  */
18602  if (reltype != OBJECT_TYPE && relkind == RELKIND_COMPOSITE_TYPE)
18603  ereport(ERROR,
18604  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
18605  errmsg("\"%s\" is a composite type", rv->relname),
18606  /* translator: %s is an SQL ALTER command */
18607  errhint("Use %s instead.",
18608  "ALTER TYPE")));
18609 
18610  /*
18611  * Don't allow ALTER TABLE .. SET SCHEMA on relations that can't be moved
18612  * to a different schema, such as indexes and TOAST tables.
18613  */
18615  {
18616  if (relkind == RELKIND_INDEX || relkind == RELKIND_PARTITIONED_INDEX)
18617  ereport(ERROR,
18618  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
18619  errmsg("cannot change schema of index \"%s\"",
18620  rv->relname),
18621  errhint("Change the schema of the table instead.")));
18622  else if (relkind == RELKIND_COMPOSITE_TYPE)
18623  ereport(ERROR,
18624  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
18625  errmsg("cannot change schema of composite type \"%s\"",
18626  rv->relname),
18627  /* translator: %s is an SQL ALTER command */
18628  errhint("Use %s instead.",
18629  "ALTER TYPE")));
18630  else if (relkind == RELKIND_TOASTVALUE)
18631  ereport(ERROR,
18632  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
18633  errmsg("cannot change schema of TOAST table \"%s\"",
18634  rv->relname),
18635  errhint("Change the schema of the table instead.")));
18636  }
18637 
18638  ReleaseSysCache(tuple);
18639 }
18640 
18641 /*
18642  * Transform any expressions present in the partition key
18643  *
18644  * Returns a transformed PartitionSpec.
18645  */
18646 static PartitionSpec *
18648 {
18649  PartitionSpec *newspec;
18650  ParseState *pstate;
18651  ParseNamespaceItem *nsitem;
18652  ListCell *l;
18653 
18654  newspec = makeNode(PartitionSpec);
18655 
18656  newspec->strategy = partspec->strategy;
18657  newspec->partParams = NIL;
18658  newspec->location = partspec->location;
18659 
18660  /* Check valid number of columns for strategy */
18661  if (partspec->strategy == PARTITION_STRATEGY_LIST &&
18662  list_length(partspec->partParams) != 1)
18663  ereport(ERROR,
18664  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
18665  errmsg("cannot use \"list\" partition strategy with more than one column")));
18666 
18667  /*
18668  * Create a dummy ParseState and insert the target relation as its sole
18669  * rangetable entry. We need a ParseState for transformExpr.
18670  */
18671  pstate = make_parsestate(NULL);
18672  nsitem = addRangeTableEntryForRelation(pstate, rel, AccessShareLock,
18673  NULL, false, true);
18674  addNSItemToQuery(pstate, nsitem, true, true, true);
18675 
18676  /* take care of any partition expressions */
18677  foreach(l, partspec->partParams)
18678  {
18680 
18681  if (pelem->expr)
18682  {
18683  /* Copy, to avoid scribbling on the input */
18684  pelem = copyObject(pelem);
18685 
18686  /* Now do parse transformation of the expression */
18687  pelem->expr = transformExpr(pstate, pelem->expr,
18689 
18690  /* we have to fix its collations too */
18691  assign_expr_collations(pstate, pelem->expr);
18692  }
18693 
18694  newspec->partParams = lappend(newspec->partParams, pelem);
18695  }
18696 
18697  return newspec;
18698 }
18699 
18700 /*
18701  * Compute per-partition-column information from a list of PartitionElems.
18702  * Expressions in the PartitionElems must be parse-analyzed already.
18703  */
18704 static void
18705 ComputePartitionAttrs(ParseState *pstate, Relation rel, List *partParams, AttrNumber *partattrs,
18706  List **partexprs, Oid *partopclass, Oid *partcollation,
18707  PartitionStrategy strategy)
18708 {
18709  int attn;
18710  ListCell *lc;
18711  Oid am_oid;
18712 
18713  attn = 0;
18714  foreach(lc, partParams)
18715  {
18716  PartitionElem *pelem = lfirst_node(PartitionElem, lc);
18717  Oid atttype;
18718  Oid attcollation;
18719 
18720  if (pelem->name != NULL)
18721  {
18722  /* Simple attribute reference */
18723  HeapTuple atttuple;
18724  Form_pg_attribute attform;
18725 
18726  atttuple = SearchSysCacheAttName(RelationGetRelid(rel),
18727  pelem->name);
18728  if (!HeapTupleIsValid(atttuple))
18729  ereport(ERROR,
18730  (errcode(ERRCODE_UNDEFINED_COLUMN),
18731  errmsg("column \"%s\" named in partition key does not exist",
18732  pelem->name),
18733  parser_errposition(pstate, pelem->location)));
18734  attform = (Form_pg_attribute) GETSTRUCT(atttuple);
18735 
18736  if (attform->attnum <= 0)
18737  ereport(ERROR,
18738  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
18739  errmsg("cannot use system column \"%s\" in partition key",
18740  pelem->name),
18741  parser_errposition(pstate, pelem->location)));
18742 
18743  /*
18744  * Generated columns cannot work: They are computed after BEFORE
18745  * triggers, but partition routing is done before all triggers.
18746  */
18747  if (attform->attgenerated)
18748  ereport(ERROR,
18749  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
18750  errmsg("cannot use generated column in partition key"),
18751  errdetail("Column \"%s\" is a generated column.",
18752  pelem->name),
18753  parser_errposition(pstate, pelem->location)));
18754 
18755  partattrs[attn] = attform->attnum;
18756  atttype = attform->atttypid;
18757  attcollation = attform->attcollation;
18758  ReleaseSysCache(atttuple);
18759  }
18760  else
18761  {
18762  /* Expression */
18763  Node *expr = pelem->expr;
18764  char partattname[16];
18765 
18766  Assert(expr != NULL);
18767  atttype = exprType(expr);
18768  attcollation = exprCollation(expr);
18769 
18770  /*
18771  * The expression must be of a storable type (e.g., not RECORD).
18772  * The test is the same as for whether a table column is of a safe
18773  * type (which is why we needn't check for the non-expression
18774  * case).
18775  */
18776  snprintf(partattname, sizeof(partattname), "%d", attn + 1);
18777  CheckAttributeType(partattname,
18778  atttype, attcollation,
18780 
18781  /*
18782  * Strip any top-level COLLATE clause. This ensures that we treat
18783  * "x COLLATE y" and "(x COLLATE y)" alike.
18784  */
18785  while (IsA(expr, CollateExpr))
18786  expr = (Node *) ((CollateExpr *) expr)->arg;
18787 
18788  if (IsA(expr, Var) &&
18789  ((Var *) expr)->varattno > 0)
18790  {
18791  /*
18792  * User wrote "(column)" or "(column COLLATE something)".
18793  * Treat it like simple attribute anyway.
18794  */
18795  partattrs[attn] = ((Var *) expr)->varattno;
18796  }
18797  else
18798  {
18799  Bitmapset *expr_attrs = NULL;
18800  int i;
18801 
18802  partattrs[attn] = 0; /* marks the column as expression */
18803  *partexprs = lappend(*partexprs, expr);
18804 
18805  /*
18806  * transformPartitionSpec() should have already rejected
18807  * subqueries, aggregates, window functions, and SRFs, based
18808  * on the EXPR_KIND_ for partition expressions.
18809  */
18810 
18811  /*
18812  * Cannot allow system column references, since that would
18813  * make partition routing impossible: their values won't be
18814  * known yet when we need to do that.
18815  */
18816  pull_varattnos(expr, 1, &expr_attrs);
18817  for (i = FirstLowInvalidHeapAttributeNumber; i < 0; i++)
18818  {
18820  expr_attrs))
18821  ereport(ERROR,
18822  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
18823  errmsg("partition key expressions cannot contain system column references")));
18824  }
18825 
18826  /*
18827  * Generated columns cannot work: They are computed after
18828  * BEFORE triggers, but partition routing is done before all
18829  * triggers.
18830  */
18831  i = -1;
18832  while ((i = bms_next_member(expr_attrs, i)) >= 0)
18833  {
18835 
18836  if (attno > 0 &&
18837  TupleDescAttr(RelationGetDescr(rel), attno - 1)->attgenerated)
18838  ereport(ERROR,
18839  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
18840  errmsg("cannot use generated column in partition key"),
18841  errdetail("Column \"%s\" is a generated column.",
18842  get_attname(RelationGetRelid(rel), attno, false)),
18843  parser_errposition(pstate, pelem->location)));
18844  }
18845 
18846  /*
18847  * Preprocess the expression before checking for mutability.
18848  * This is essential for the reasons described in
18849  * contain_mutable_functions_after_planning. However, we call
18850  * expression_planner for ourselves rather than using that
18851  * function, because if constant-folding reduces the
18852  * expression to a constant, we'd like to know that so we can
18853  * complain below.
18854  *
18855  * Like contain_mutable_functions_after_planning, assume that
18856  * expression_planner won't scribble on its input, so this
18857  * won't affect the partexprs entry we saved above.
18858  */
18859  expr = (Node *) expression_planner((Expr *) expr);
18860 
18861  /*
18862  * Partition expressions cannot contain mutable functions,
18863  * because a given row must always map to the same partition
18864  * as long as there is no change in the partition boundary
18865  * structure.
18866  */
18867  if (contain_mutable_functions(expr))
18868  ereport(ERROR,
18869  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
18870  errmsg("functions in partition key expression must be marked IMMUTABLE")));
18871 
18872  /*
18873  * While it is not exactly *wrong* for a partition expression
18874  * to be a constant, it seems better to reject such keys.
18875  */
18876  if (IsA(expr, Const))
18877  ereport(ERROR,
18878  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
18879  errmsg("cannot use constant expression as partition key")));
18880  }
18881  }
18882 
18883  /*
18884  * Apply collation override if any
18885  */
18886  if (pelem->collation)
18887  attcollation = get_collation_oid(pelem->collation, false);
18888 
18889  /*
18890  * Check we have a collation iff it's a collatable type. The only
18891  * expected failures here are (1) COLLATE applied to a noncollatable
18892  * type, or (2) partition expression had an unresolved collation. But
18893  * we might as well code this to be a complete consistency check.
18894  */
18895  if (type_is_collatable(atttype))
18896  {
18897  if (!OidIsValid(attcollation))
18898  ereport(ERROR,
18899  (errcode(ERRCODE_INDETERMINATE_COLLATION),
18900  errmsg("could not determine which collation to use for partition expression"),
18901  errhint("Use the COLLATE clause to set the collation explicitly.")));
18902  }
18903  else
18904  {
18905  if (OidIsValid(attcollation))
18906  ereport(ERROR,
18907  (errcode(ERRCODE_DATATYPE_MISMATCH),
18908  errmsg("collations are not supported by type %s",
18909  format_type_be(atttype))));
18910  }
18911 
18912  partcollation[attn] = attcollation;
18913 
18914  /*
18915  * Identify the appropriate operator class. For list and range
18916  * partitioning, we use a btree operator class; hash partitioning uses
18917  * a hash operator class.
18918  */
18919  if (strategy == PARTITION_STRATEGY_HASH)
18920  am_oid = HASH_AM_OID;
18921  else
18922  am_oid = BTREE_AM_OID;
18923 
18924  if (!pelem->opclass)
18925  {
18926  partopclass[attn] = GetDefaultOpClass(atttype, am_oid);
18927 
18928  if (!OidIsValid(partopclass[attn]))
18929  {
18930  if (strategy == PARTITION_STRATEGY_HASH)
18931  ereport(ERROR,
18932  (errcode(ERRCODE_UNDEFINED_OBJECT),
18933  errmsg("data type %s has no default operator class for access method \"%s\"",
18934  format_type_be(atttype), "hash"),
18935  errhint("You must specify a hash operator class or define a default hash operator class for the data type.")));
18936  else
18937  ereport(ERROR,
18938  (errcode(ERRCODE_UNDEFINED_OBJECT),
18939  errmsg("data type %s has no default operator class for access method \"%s\"",
18940  format_type_be(atttype), "btree"),
18941  errhint("You must specify a btree operator class or define a default btree operator class for the data type.")));
18942  }
18943  }
18944  else
18945  partopclass[attn] = ResolveOpClass(pelem->opclass,
18946  atttype,
18947  am_oid == HASH_AM_OID ? "hash" : "btree",
18948  am_oid);
18949 
18950  attn++;
18951  }
18952 }
18953 
18954 /*
18955  * PartConstraintImpliedByRelConstraint
18956  * Do scanrel's existing constraints imply the partition constraint?
18957  *
18958  * "Existing constraints" include its check constraints and column-level
18959  * not-null constraints. partConstraint describes the partition constraint,
18960  * in implicit-AND form.
18961  */
18962 bool
18964  List *partConstraint)
18965 {
18966  List *existConstraint = NIL;
18967  TupleConstr *constr = RelationGetDescr(scanrel)->constr;
18968  int i;
18969 
18970  if (constr && constr->has_not_null)
18971  {
18972  int natts = scanrel->rd_att->natts;
18973 
18974  for (i = 1; i <= natts; i++)
18975  {
18976  Form_pg_attribute att = TupleDescAttr(scanrel->rd_att, i - 1);
18977 
18978  if (att->attnotnull && !att->attisdropped)
18979  {
18980  NullTest *ntest = makeNode(NullTest);
18981 
18982  ntest->arg = (Expr *) makeVar(1,
18983  i,
18984  att->atttypid,
18985  att->atttypmod,
18986  att->attcollation,
18987  0);
18988  ntest->nulltesttype = IS_NOT_NULL;
18989 
18990  /*
18991  * argisrow=false is correct even for a composite column,
18992  * because attnotnull does not represent a SQL-spec IS NOT
18993  * NULL test in such a case, just IS DISTINCT FROM NULL.
18994  */
18995  ntest->argisrow = false;
18996  ntest->location = -1;
18997  existConstraint = lappend(existConstraint, ntest);
18998  }
18999  }
19000  }
19001 
19002  return ConstraintImpliedByRelConstraint(scanrel, partConstraint, existConstraint);
19003 }
19004 
19005 /*
19006  * ConstraintImpliedByRelConstraint
19007  * Do scanrel's existing constraints imply the given constraint?
19008  *
19009  * testConstraint is the constraint to validate. provenConstraint is a
19010  * caller-provided list of conditions which this function may assume
19011  * to be true. Both provenConstraint and testConstraint must be in
19012  * implicit-AND form, must only contain immutable clauses, and must
19013  * contain only Vars with varno = 1.
19014  */
19015 bool
19016 ConstraintImpliedByRelConstraint(Relation scanrel, List *testConstraint, List *provenConstraint)
19017 {
19018  List *existConstraint = list_copy(provenConstraint);
19019  TupleConstr *constr = RelationGetDescr(scanrel)->constr;
19020  int num_check,
19021  i;
19022 
19023  num_check = (constr != NULL) ? constr->num_check : 0;
19024  for (i = 0; i < num_check; i++)
19025  {
19026  Node *cexpr;
19027 
19028  /*
19029  * If this constraint hasn't been fully validated yet, we must ignore
19030  * it here.
19031  */
19032  if (!constr->check[i].ccvalid)
19033  continue;
19034 
19035  cexpr = stringToNode(constr->check[i].ccbin);
19036 
19037  /*
19038  * Run each expression through const-simplification and
19039  * canonicalization. It is necessary, because we will be comparing it
19040  * to similarly-processed partition constraint expressions, and may
19041  * fail to detect valid matches without this.
19042  */
19043  cexpr = eval_const_expressions(NULL, cexpr);
19044  cexpr = (Node *) canonicalize_qual((Expr *) cexpr, true);
19045 
19046  existConstraint = list_concat(existConstraint,
19047  make_ands_implicit((Expr *) cexpr));
19048  }
19049 
19050  /*
19051  * Try to make the proof. Since we are comparing CHECK constraints, we
19052  * need to use weak implication, i.e., we assume existConstraint is
19053  * not-false and try to prove the same for testConstraint.
19054  *
19055  * Note that predicate_implied_by assumes its first argument is known
19056  * immutable. That should always be true for both NOT NULL and partition
19057  * constraints, so we don't test it here.
19058  */
19059  return predicate_implied_by(testConstraint, existConstraint, true);
19060 }
19061 
19062 /*
19063  * QueuePartitionConstraintValidation
19064  *
19065  * Add an entry to wqueue to have the given partition constraint validated by
19066  * Phase 3, for the given relation, and all its children.
19067  *
19068  * We first verify whether the given constraint is implied by pre-existing
19069  * relation constraints; if it is, there's no need to scan the table to
19070  * validate, so don't queue in that case.
19071  */
19072 static void
19074  List *partConstraint,
19075  bool validate_default)
19076 {
19077  /*
19078  * Based on the table's existing constraints, determine whether or not we
19079  * may skip scanning the table.
19080  */
19081  if (PartConstraintImpliedByRelConstraint(scanrel, partConstraint))
19082  {
19083  if (!validate_default)
19084  ereport(DEBUG1,
19085  (errmsg_internal("partition constraint for table \"%s\" is implied by existing constraints",
19086  RelationGetRelationName(scanrel))));
19087  else
19088  ereport(DEBUG1,
19089  (errmsg_internal("updated partition constraint for default partition \"%s\" is implied by existing constraints",
19090  RelationGetRelationName(scanrel))));
19091  return;
19092  }
19093 
19094  /*
19095  * Constraints proved insufficient. For plain relations, queue a
19096  * validation item now; for partitioned tables, recurse to process each
19097  * partition.
19098  */
19099  if (scanrel->rd_rel->relkind == RELKIND_RELATION)
19100  {
19101  AlteredTableInfo *tab;
19102 
19103  /* Grab a work queue entry. */
19104  tab = ATGetQueueEntry(wqueue, scanrel);
19105  Assert(tab->partition_constraint == NULL);
19106  tab->partition_constraint = (Expr *) linitial(partConstraint);
19107  tab->validate_default = validate_default;
19108  }
19109  else if (scanrel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
19110  {
19111  PartitionDesc partdesc = RelationGetPartitionDesc(scanrel, true);
19112  int i;
19113 
19114  for (i = 0; i < partdesc->nparts; i++)
19115  {
19116  Relation part_rel;
19117  List *thisPartConstraint;
19118 
19119  /*
19120  * This is the minimum lock we need to prevent deadlocks.
19121  */
19122  part_rel = table_open(partdesc->oids[i], AccessExclusiveLock);
19123 
19124  /*
19125  * Adjust the constraint for scanrel so that it matches this
19126  * partition's attribute numbers.
19127  */
19128  thisPartConstraint =
19129  map_partition_varattnos(partConstraint, 1,
19130  part_rel, scanrel);
19131 
19132  QueuePartitionConstraintValidation(wqueue, part_rel,
19133  thisPartConstraint,
19134  validate_default);
19135  table_close(part_rel, NoLock); /* keep lock till commit */
19136  }
19137  }
19138 }
19139 
19140 /*
19141  * attachPartitionTable: attach a new partition to the partitioned table
19142  *
19143  * wqueue: the ALTER TABLE work queue; can be NULL when not running as part
19144  * of an ALTER TABLE sequence.
19145  * rel: partitioned relation;
19146  * attachrel: relation of attached partition;
19147  * bound: bounds of attached relation.
19148  */
19149 static void
19151 {
19152  /* OK to create inheritance. Rest of the checks performed there */
19153  CreateInheritance(attachrel, rel, true);
19154 
19155  /* Update the pg_class entry. */
19156  StorePartitionBound(attachrel, rel, bound);
19157 
19158  /* Ensure there exists a correct set of indexes in the partition. */
19159  AttachPartitionEnsureIndexes(wqueue, rel, attachrel);
19160 
19161  /* and triggers */
19162  CloneRowTriggersToPartition(rel, attachrel);
19163 
19164  /*
19165  * Clone foreign key constraints. Callee is responsible for setting up
19166  * for phase 3 constraint verification.
19167  */
19168  CloneForeignKeyConstraints(wqueue, rel, attachrel);
19169 }
19170 
19171 /*
19172  * ALTER TABLE <name> ATTACH PARTITION <partition-name> FOR VALUES
19173  *
19174  * Return the address of the newly attached partition.
19175  */
19176 static ObjectAddress
19179 {
19180  Relation attachrel,
19181  catalog;
19182  List *attachrel_children;
19183  List *partConstraint;
19184  SysScanDesc scan;
19185  ScanKeyData skey;
19186  AttrNumber attno;
19187  int natts;
19188  TupleDesc tupleDesc;
19189  ObjectAddress address;
19190  const char *trigger_name;
19191  Oid defaultPartOid;
19192  List *partBoundConstraint;
19193  ParseState *pstate = make_parsestate(NULL);
19194 
19195  pstate->p_sourcetext = context->queryString;
19196 
19197  /*
19198  * We must lock the default partition if one exists, because attaching a
19199  * new partition will change its partition constraint.
19200  */
19201  defaultPartOid =
19203  if (OidIsValid(defaultPartOid))
19204  LockRelationOid(defaultPartOid, AccessExclusiveLock);
19205 
19206  attachrel = table_openrv(cmd->name, AccessExclusiveLock);
19207 
19208  /*
19209  * XXX I think it'd be a good idea to grab locks on all tables referenced
19210  * by FKs at this point also.
19211  */
19212 
19213  /*
19214  * Must be owner of both parent and source table -- parent was checked by
19215  * ATSimplePermissions call in ATPrepCmd
19216  */
19218 
19219  /* A partition can only have one parent */
19220  if (attachrel->rd_rel->relispartition)
19221  ereport(ERROR,
19222  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
19223  errmsg("\"%s\" is already a partition",
19224  RelationGetRelationName(attachrel))));
19225 
19226  if (OidIsValid(attachrel->rd_rel->reloftype))
19227  ereport(ERROR,
19228  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
19229  errmsg("cannot attach a typed table as partition")));
19230 
19231  /*
19232  * Table being attached should not already be part of inheritance; either
19233  * as a child table...
19234  */
19235  catalog = table_open(InheritsRelationId, AccessShareLock);
19236  ScanKeyInit(&skey,
19237  Anum_pg_inherits_inhrelid,
19238  BTEqualStrategyNumber, F_OIDEQ,
19239  ObjectIdGetDatum(RelationGetRelid(attachrel)));
19240  scan = systable_beginscan(catalog, InheritsRelidSeqnoIndexId, true,
19241  NULL, 1, &skey);
19243  ereport(ERROR,
19244  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
19245  errmsg("cannot attach inheritance child as partition")));
19246  systable_endscan(scan);
19247 
19248  /* ...or as a parent table (except the case when it is partitioned) */
19249  ScanKeyInit(&skey,
19250  Anum_pg_inherits_inhparent,
19251  BTEqualStrategyNumber, F_OIDEQ,
19252  ObjectIdGetDatum(RelationGetRelid(attachrel)));
19253  scan = systable_beginscan(catalog, InheritsParentIndexId, true, NULL,
19254  1, &skey);
19255  if (HeapTupleIsValid(systable_getnext(scan)) &&
19256  attachrel->rd_rel->relkind == RELKIND_RELATION)
19257  ereport(ERROR,
19258  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
19259  errmsg("cannot attach inheritance parent as partition")));
19260  systable_endscan(scan);
19261  table_close(catalog, AccessShareLock);
19262 
19263  /*
19264  * Prevent circularity by seeing if rel is a partition of attachrel. (In
19265  * particular, this disallows making a rel a partition of itself.)
19266  *
19267  * We do that by checking if rel is a member of the list of attachrel's
19268  * partitions provided the latter is partitioned at all. We want to avoid
19269  * having to construct this list again, so we request the strongest lock
19270  * on all partitions. We need the strongest lock, because we may decide
19271  * to scan them if we find out that the table being attached (or its leaf
19272  * partitions) may contain rows that violate the partition constraint. If
19273  * the table has a constraint that would prevent such rows, which by
19274  * definition is present in all the partitions, we need not scan the
19275  * table, nor its partitions. But we cannot risk a deadlock by taking a
19276  * weaker lock now and the stronger one only when needed.
19277  */
19278  attachrel_children = find_all_inheritors(RelationGetRelid(attachrel),
19279  AccessExclusiveLock, NULL);
19280  if (list_member_oid(attachrel_children, RelationGetRelid(rel)))
19281  ereport(ERROR,
19282  (errcode(ERRCODE_DUPLICATE_TABLE),
19283  errmsg("circular inheritance not allowed"),
19284  errdetail("\"%s\" is already a child of \"%s\".",
19286  RelationGetRelationName(attachrel))));
19287 
19288  /* If the parent is permanent, so must be all of its partitions. */
19289  if (rel->rd_rel->relpersistence != RELPERSISTENCE_TEMP &&
19290  attachrel->rd_rel->relpersistence == RELPERSISTENCE_TEMP)
19291  ereport(ERROR,
19292  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
19293  errmsg("cannot attach a temporary relation as partition of permanent relation \"%s\"",
19294  RelationGetRelationName(rel))));
19295 
19296  /* Temp parent cannot have a partition that is itself not a temp */
19297  if (rel->rd_rel->relpersistence == RELPERSISTENCE_TEMP &&
19298  attachrel->rd_rel->relpersistence != RELPERSISTENCE_TEMP)
19299  ereport(ERROR,
19300  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
19301  errmsg("cannot attach a permanent relation as partition of temporary relation \"%s\"",
19302  RelationGetRelationName(rel))));
19303 
19304  /* If the parent is temp, it must belong to this session */
19305  if (rel->rd_rel->relpersistence == RELPERSISTENCE_TEMP &&
19306  !rel->rd_islocaltemp)
19307  ereport(ERROR,
19308  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
19309  errmsg("cannot attach as partition of temporary relation of another session")));
19310 
19311  /* Ditto for the partition */
19312  if (attachrel->rd_rel->relpersistence == RELPERSISTENCE_TEMP &&
19313  !attachrel->rd_islocaltemp)
19314  ereport(ERROR,
19315  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
19316  errmsg("cannot attach temporary relation of another session as partition")));
19317 
19318  /*
19319  * Check if attachrel has any identity columns or any columns that aren't
19320  * in the parent.
19321  */
19322  tupleDesc = RelationGetDescr(attachrel);
19323  natts = tupleDesc->natts;
19324  for (attno = 1; attno <= natts; attno++)
19325  {
19326  Form_pg_attribute attribute = TupleDescAttr(tupleDesc, attno - 1);
19327  char *attributeName = NameStr(attribute->attname);
19328 
19329  /* Ignore dropped */
19330  if (attribute->attisdropped)
19331  continue;
19332 
19333  if (attribute->attidentity)
19334  ereport(ERROR,
19335  errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
19336  errmsg("table \"%s\" being attached contains an identity column \"%s\"",
19337  RelationGetRelationName(attachrel), attributeName),
19338  errdetail("The new partition may not contain an identity column."));
19339 
19340  /* Try to find the column in parent (matching on column name) */
19341  if (!SearchSysCacheExists2(ATTNAME,
19343  CStringGetDatum(attributeName)))
19344  ereport(ERROR,
19345  (errcode(ERRCODE_DATATYPE_MISMATCH),
19346  errmsg("table \"%s\" contains column \"%s\" not found in parent \"%s\"",
19347  RelationGetRelationName(attachrel), attributeName,
19349  errdetail("The new partition may contain only the columns present in parent.")));
19350  }
19351 
19352  /*
19353  * If child_rel has row-level triggers with transition tables, we
19354  * currently don't allow it to become a partition. See also prohibitions
19355  * in ATExecAddInherit() and CreateTrigger().
19356  */
19357  trigger_name = FindTriggerIncompatibleWithInheritance(attachrel->trigdesc);
19358  if (trigger_name != NULL)
19359  ereport(ERROR,
19360  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
19361  errmsg("trigger \"%s\" prevents table \"%s\" from becoming a partition",
19362  trigger_name, RelationGetRelationName(attachrel)),
19363  errdetail("ROW triggers with transition tables are not supported on partitions.")));
19364 
19365  /*
19366  * Check that the new partition's bound is valid and does not overlap any
19367  * of existing partitions of the parent - note that it does not return on
19368  * error.
19369  */
19371  cmd->bound, pstate);
19372 
19373  /* Attach a new partition to the partitioned table. */
19374  attachPartitionTable(wqueue, rel, attachrel, cmd->bound);
19375 
19376  /*
19377  * Generate partition constraint from the partition bound specification.
19378  * If the parent itself is a partition, make sure to include its
19379  * constraint as well.
19380  */
19381  partBoundConstraint = get_qual_from_partbound(rel, cmd->bound);
19382  partConstraint = list_concat(partBoundConstraint,
19384 
19385  /* Skip validation if there are no constraints to validate. */
19386  if (partConstraint)
19387  {
19388  /*
19389  * Run the partition quals through const-simplification similar to
19390  * check constraints. We skip canonicalize_qual, though, because
19391  * partition quals should be in canonical form already.
19392  */
19393  partConstraint =
19394  (List *) eval_const_expressions(NULL,
19395  (Node *) partConstraint);
19396 
19397  /* XXX this sure looks wrong */
19398  partConstraint = list_make1(make_ands_explicit(partConstraint));
19399 
19400  /*
19401  * Adjust the generated constraint to match this partition's attribute
19402  * numbers.
19403  */
19404  partConstraint = map_partition_varattnos(partConstraint, 1, attachrel,
19405  rel);
19406 
19407  /* Validate partition constraints against the table being attached. */
19408  QueuePartitionConstraintValidation(wqueue, attachrel, partConstraint,
19409  false);
19410  }
19411 
19412  /*
19413  * If we're attaching a partition other than the default partition and a
19414  * default one exists, then that partition's partition constraint changes,
19415  * so add an entry to the work queue to validate it, too. (We must not do
19416  * this when the partition being attached is the default one; we already
19417  * did it above!)
19418  */
19419  if (OidIsValid(defaultPartOid))
19420  {
19421  Relation defaultrel;
19422  List *defPartConstraint;
19423 
19424  Assert(!cmd->bound->is_default);
19425 
19426  /* we already hold a lock on the default partition */
19427  defaultrel = table_open(defaultPartOid, NoLock);
19428  defPartConstraint =
19429  get_proposed_default_constraint(partBoundConstraint);
19430 
19431  /*
19432  * Map the Vars in the constraint expression from rel's attnos to
19433  * defaultrel's.
19434  */
19435  defPartConstraint =
19436  map_partition_varattnos(defPartConstraint,
19437  1, defaultrel, rel);
19438  QueuePartitionConstraintValidation(wqueue, defaultrel,
19439  defPartConstraint, true);
19440 
19441  /* keep our lock until commit. */
19442  table_close(defaultrel, NoLock);
19443  }
19444 
19445  ObjectAddressSet(address, RelationRelationId, RelationGetRelid(attachrel));
19446 
19447  /*
19448  * If the partition we just attached is partitioned itself, invalidate
19449  * relcache for all descendent partitions too to ensure that their
19450  * rd_partcheck expression trees are rebuilt; partitions already locked at
19451  * the beginning of this function.
19452  */
19453  if (attachrel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
19454  {
19455  ListCell *l;
19456 
19457  foreach(l, attachrel_children)
19458  {
19460  }
19461  }
19462 
19463  /* keep our lock until commit */
19464  table_close(attachrel, NoLock);
19465 
19466  return address;
19467 }
19468 
19469 /*
19470  * AttachPartitionEnsureIndexes
19471  * subroutine for ATExecAttachPartition to create/match indexes
19472  *
19473  * Enforce the indexing rule for partitioned tables during ALTER TABLE / ATTACH
19474  * PARTITION: every partition must have an index attached to each index on the
19475  * partitioned table.
19476  */
19477 static void
19479 {
19480  List *idxes;
19481  List *attachRelIdxs;
19482  Relation *attachrelIdxRels;
19483  IndexInfo **attachInfos;
19484  ListCell *cell;
19485  MemoryContext cxt;
19486  MemoryContext oldcxt;
19487 
19489  "AttachPartitionEnsureIndexes",
19491  oldcxt = MemoryContextSwitchTo(cxt);
19492 
19493  idxes = RelationGetIndexList(rel);
19494  attachRelIdxs = RelationGetIndexList(attachrel);
19495  attachrelIdxRels = palloc(sizeof(Relation) * list_length(attachRelIdxs));
19496  attachInfos = palloc(sizeof(IndexInfo *) * list_length(attachRelIdxs));
19497 
19498  /* Build arrays of all existing indexes and their IndexInfos */
19499  foreach(cell, attachRelIdxs)
19500  {
19501  Oid cldIdxId = lfirst_oid(cell);
19502  int i = foreach_current_index(cell);
19503 
19504  attachrelIdxRels[i] = index_open(cldIdxId, AccessShareLock);
19505  attachInfos[i] = BuildIndexInfo(attachrelIdxRels[i]);
19506  }
19507 
19508  /*
19509  * If we're attaching a foreign table, we must fail if any of the indexes
19510  * is a constraint index; otherwise, there's nothing to do here. Do this
19511  * before starting work, to avoid wasting the effort of building a few
19512  * non-unique indexes before coming across a unique one.
19513  */
19514  if (attachrel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
19515  {
19516  foreach(cell, idxes)
19517  {
19518  Oid idx = lfirst_oid(cell);
19520 
19521  if (idxRel->rd_index->indisunique ||
19522  idxRel->rd_index->indisprimary)
19523  ereport(ERROR,
19524  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
19525  errmsg("cannot attach foreign table \"%s\" as partition of partitioned table \"%s\"",
19526  RelationGetRelationName(attachrel),
19528  errdetail("Partitioned table \"%s\" contains unique indexes.",
19529  RelationGetRelationName(rel))));
19530  index_close(idxRel, AccessShareLock);
19531  }
19532 
19533  goto out;
19534  }
19535 
19536  /*
19537  * For each index on the partitioned table, find a matching one in the
19538  * partition-to-be; if one is not found, create one.
19539  */
19540  foreach(cell, idxes)
19541  {
19542  Oid idx = lfirst_oid(cell);
19544  IndexInfo *info;
19545  AttrMap *attmap;
19546  bool found = false;
19547  Oid constraintOid;
19548 
19549  /*
19550  * Ignore indexes in the partitioned table other than partitioned
19551  * indexes.
19552  */
19553  if (idxRel->rd_rel->relkind != RELKIND_PARTITIONED_INDEX)
19554  {
19555  index_close(idxRel, AccessShareLock);
19556  continue;
19557  }
19558 
19559  /* construct an indexinfo to compare existing indexes against */
19560  info = BuildIndexInfo(idxRel);
19561  attmap = build_attrmap_by_name(RelationGetDescr(attachrel),
19562  RelationGetDescr(rel),
19563  false);
19564  constraintOid = get_relation_idx_constraint_oid(RelationGetRelid(rel), idx);
19565 
19566  /*
19567  * Scan the list of existing indexes in the partition-to-be, and mark
19568  * the first matching, valid, unattached one we find, if any, as
19569  * partition of the parent index. If we find one, we're done.
19570  */
19571  for (int i = 0; i < list_length(attachRelIdxs); i++)
19572  {
19573  Oid cldIdxId = RelationGetRelid(attachrelIdxRels[i]);
19574  Oid cldConstrOid = InvalidOid;
19575 
19576  /* does this index have a parent? if so, can't use it */
19577  if (attachrelIdxRels[i]->rd_rel->relispartition)
19578  continue;
19579 
19580  /* If this index is invalid, can't use it */
19581  if (!attachrelIdxRels[i]->rd_index->indisvalid)
19582  continue;
19583 
19584  if (CompareIndexInfo(attachInfos[i], info,
19585  attachrelIdxRels[i]->rd_indcollation,
19586  idxRel->rd_indcollation,
19587  attachrelIdxRels[i]->rd_opfamily,
19588  idxRel->rd_opfamily,
19589  attmap))
19590  {
19591  /*
19592  * If this index is being created in the parent because of a
19593  * constraint, then the child needs to have a constraint also,
19594  * so look for one. If there is no such constraint, this
19595  * index is no good, so keep looking.
19596  */
19597  if (OidIsValid(constraintOid))
19598  {
19599  cldConstrOid =
19601  cldIdxId);
19602  /* no dice */
19603  if (!OidIsValid(cldConstrOid))
19604  continue;
19605 
19606  /* Ensure they're both the same type of constraint */
19607  if (get_constraint_type(constraintOid) !=
19608  get_constraint_type(cldConstrOid))
19609  continue;
19610  }
19611 
19612  /* bingo. */
19613  IndexSetParentIndex(attachrelIdxRels[i], idx);
19614  if (OidIsValid(constraintOid))
19615  ConstraintSetParentConstraint(cldConstrOid, constraintOid,
19616  RelationGetRelid(attachrel));
19617  found = true;
19618 
19620  break;
19621  }
19622  }
19623 
19624  /*
19625  * If no suitable index was found in the partition-to-be, create one
19626  * now.
19627  */
19628  if (!found)
19629  {
19630  IndexStmt *stmt;
19631  Oid conOid;
19632 
19634  idxRel, attmap,
19635  &conOid);
19636 
19637  /*
19638  * If the index is a primary key, mark all columns as NOT NULL if
19639  * they aren't already.
19640  */
19641  if (stmt->primary)
19642  {
19643  MemoryContextSwitchTo(oldcxt);
19644  for (int j = 0; j < info->ii_NumIndexKeyAttrs; j++)
19645  {
19646  AttrNumber childattno;
19647 
19648  childattno = get_attnum(RelationGetRelid(attachrel),
19650  info->ii_IndexAttrNumbers[j],
19651  false));
19652  set_attnotnull(wqueue, attachrel, childattno,
19653  true, AccessExclusiveLock);
19654  }
19655  MemoryContextSwitchTo(cxt);
19656  }
19657 
19659  RelationGetRelid(idxRel),
19660  conOid,
19661  -1,
19662  true, false, false, false, false);
19663  }
19664 
19665  index_close(idxRel, AccessShareLock);
19666  }
19667 
19668 out:
19669  /* Clean up. */
19670  for (int i = 0; i < list_length(attachRelIdxs); i++)
19671  index_close(attachrelIdxRels[i], AccessShareLock);
19672  MemoryContextSwitchTo(oldcxt);
19673  MemoryContextDelete(cxt);
19674 }
19675 
19676 /*
19677  * CloneRowTriggersToPartition
19678  * subroutine for ATExecAttachPartition/DefineRelation to create row
19679  * triggers on partitions
19680  */
19681 static void
19683 {
19684  Relation pg_trigger;
19685  ScanKeyData key;
19686  SysScanDesc scan;
19687  HeapTuple tuple;
19688  MemoryContext perTupCxt;
19689 
19690  ScanKeyInit(&key, Anum_pg_trigger_tgrelid, BTEqualStrategyNumber,
19691  F_OIDEQ, ObjectIdGetDatum(RelationGetRelid(parent)));
19692  pg_trigger = table_open(TriggerRelationId, RowExclusiveLock);
19693  scan = systable_beginscan(pg_trigger, TriggerRelidNameIndexId,
19694  true, NULL, 1, &key);
19695 
19697  "clone trig", ALLOCSET_SMALL_SIZES);
19698 
19699  while (HeapTupleIsValid(tuple = systable_getnext(scan)))
19700  {
19701  Form_pg_trigger trigForm = (Form_pg_trigger) GETSTRUCT(tuple);
19702  CreateTrigStmt *trigStmt;
19703  Node *qual = NULL;
19704  Datum value;
19705  bool isnull;
19706  List *cols = NIL;
19707  List *trigargs = NIL;
19708  MemoryContext oldcxt;
19709 
19710  /*
19711  * Ignore statement-level triggers; those are not cloned.
19712  */
19713  if (!TRIGGER_FOR_ROW(trigForm->tgtype))
19714  continue;
19715 
19716  /*
19717  * Don't clone internal triggers, because the constraint cloning code
19718  * will.
19719  */
19720  if (trigForm->tgisinternal)
19721  continue;
19722 
19723  /*
19724  * Complain if we find an unexpected trigger type.
19725  */
19726  if (!TRIGGER_FOR_BEFORE(trigForm->tgtype) &&
19727  !TRIGGER_FOR_AFTER(trigForm->tgtype))
19728  elog(ERROR, "unexpected trigger \"%s\" found",
19729  NameStr(trigForm->tgname));
19730 
19731  /* Use short-lived context for CREATE TRIGGER */
19732  oldcxt = MemoryContextSwitchTo(perTupCxt);
19733 
19734  /*
19735  * If there is a WHEN clause, generate a 'cooked' version of it that's
19736  * appropriate for the partition.
19737  */
19738  value = heap_getattr(tuple, Anum_pg_trigger_tgqual,
19739  RelationGetDescr(pg_trigger), &isnull);
19740  if (!isnull)
19741  {
19743  qual = (Node *) map_partition_varattnos((List *) qual, PRS2_OLD_VARNO,
19744  partition, parent);
19745  qual = (Node *) map_partition_varattnos((List *) qual, PRS2_NEW_VARNO,
19746  partition, parent);
19747  }
19748 
19749  /*
19750  * If there is a column list, transform it to a list of column names.
19751  * Note we don't need to map this list in any way ...
19752  */
19753  if (trigForm->tgattr.dim1 > 0)
19754  {
19755  int i;
19756 
19757  for (i = 0; i < trigForm->tgattr.dim1; i++)
19758  {
19759  Form_pg_attribute col;
19760 
19761  col = TupleDescAttr(parent->rd_att,
19762  trigForm->tgattr.values[i] - 1);
19763  cols = lappend(cols,
19764  makeString(pstrdup(NameStr(col->attname))));
19765  }
19766  }
19767 
19768  /* Reconstruct trigger arguments list. */
19769  if (trigForm->tgnargs > 0)
19770  {
19771  char *p;
19772 
19773  value = heap_getattr(tuple, Anum_pg_trigger_tgargs,
19774  RelationGetDescr(pg_trigger), &isnull);
19775  if (isnull)
19776  elog(ERROR, "tgargs is null for trigger \"%s\" in partition \"%s\"",
19777  NameStr(trigForm->tgname), RelationGetRelationName(partition));
19778 
19779  p = (char *) VARDATA_ANY(DatumGetByteaPP(value));
19780 
19781  for (int i = 0; i < trigForm->tgnargs; i++)
19782  {
19783  trigargs = lappend(trigargs, makeString(pstrdup(p)));
19784  p += strlen(p) + 1;
19785  }
19786  }
19787 
19788  trigStmt = makeNode(CreateTrigStmt);
19789  trigStmt->replace = false;
19790  trigStmt->isconstraint = OidIsValid(trigForm->tgconstraint);
19791  trigStmt->trigname = NameStr(trigForm->tgname);
19792  trigStmt->relation = NULL;
19793  trigStmt->funcname = NULL; /* passed separately */
19794  trigStmt->args = trigargs;
19795  trigStmt->row = true;
19796  trigStmt->timing = trigForm->tgtype & TRIGGER_TYPE_TIMING_MASK;
19797  trigStmt->events = trigForm->tgtype & TRIGGER_TYPE_EVENT_MASK;
19798  trigStmt->columns = cols;
19799  trigStmt->whenClause = NULL; /* passed separately */
19800  trigStmt->transitionRels = NIL; /* not supported at present */
19801  trigStmt->deferrable = trigForm->tgdeferrable;
19802  trigStmt->initdeferred = trigForm->tginitdeferred;
19803  trigStmt->constrrel = NULL; /* passed separately */
19804 
19805  CreateTriggerFiringOn(trigStmt, NULL, RelationGetRelid(partition),
19806  trigForm->tgconstrrelid, InvalidOid, InvalidOid,
19807  trigForm->tgfoid, trigForm->oid, qual,
19808  false, true, trigForm->tgenabled);
19809 
19810  MemoryContextSwitchTo(oldcxt);
19811  MemoryContextReset(perTupCxt);
19812  }
19813 
19814  MemoryContextDelete(perTupCxt);
19815 
19816  systable_endscan(scan);
19817  table_close(pg_trigger, RowExclusiveLock);
19818 }
19819 
19820 /*
19821  * ALTER TABLE DETACH PARTITION
19822  *
19823  * Return the address of the relation that is no longer a partition of rel.
19824  *
19825  * If concurrent mode is requested, we run in two transactions. A side-
19826  * effect is that this command cannot run in a multi-part ALTER TABLE.
19827  * Currently, that's enforced by the grammar.
19828  *
19829  * The strategy for concurrency is to first modify the partition's
19830  * pg_inherit catalog row to make it visible to everyone that the
19831  * partition is detached, lock the partition against writes, and commit
19832  * the transaction; anyone who requests the partition descriptor from
19833  * that point onwards has to ignore such a partition. In a second
19834  * transaction, we wait until all transactions that could have seen the
19835  * partition as attached are gone, then we remove the rest of partition
19836  * metadata (pg_inherits and pg_class.relpartbounds).
19837  */
19838 static ObjectAddress
19840  RangeVar *name, bool concurrent)
19841 {
19842  Relation partRel;
19843  ObjectAddress address;
19844  Oid defaultPartOid;
19845 
19846  /*
19847  * We must lock the default partition, because detaching this partition
19848  * will change its partition constraint.
19849  */
19850  defaultPartOid =
19852  if (OidIsValid(defaultPartOid))
19853  {
19854  /*
19855  * Concurrent detaching when a default partition exists is not
19856  * supported. The main problem is that the default partition
19857  * constraint would change. And there's a definitional problem: what
19858  * should happen to the tuples that are being inserted that belong to
19859  * the partition being detached? Putting them on the partition being
19860  * detached would be wrong, since they'd become "lost" after the
19861  * detaching completes but we cannot put them in the default partition
19862  * either until we alter its partition constraint.
19863  *
19864  * I think we could solve this problem if we effected the constraint
19865  * change before committing the first transaction. But the lock would
19866  * have to remain AEL and it would cause concurrent query planning to
19867  * be blocked, so changing it that way would be even worse.
19868  */
19869  if (concurrent)
19870  ereport(ERROR,
19871  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
19872  errmsg("cannot detach partitions concurrently when a default partition exists")));
19873  LockRelationOid(defaultPartOid, AccessExclusiveLock);
19874  }
19875 
19876  /*
19877  * In concurrent mode, the partition is locked with share-update-exclusive
19878  * in the first transaction. This allows concurrent transactions to be
19879  * doing DML to the partition.
19880  */
19881  partRel = table_openrv(name, concurrent ? ShareUpdateExclusiveLock :
19883 
19884  /*
19885  * Check inheritance conditions and either delete the pg_inherits row (in
19886  * non-concurrent mode) or just set the inhdetachpending flag.
19887  */
19888  if (!concurrent)
19889  RemoveInheritance(partRel, rel, false);
19890  else
19891  MarkInheritDetached(partRel, rel);
19892 
19893  /*
19894  * Ensure that foreign keys still hold after this detach. This keeps
19895  * locks on the referencing tables, which prevents concurrent transactions
19896  * from adding rows that we wouldn't see. For this to work in concurrent
19897  * mode, it is critical that the partition appears as no longer attached
19898  * for the RI queries as soon as the first transaction commits.
19899  */
19901 
19902  /*
19903  * Concurrent mode has to work harder; first we add a new constraint to
19904  * the partition that matches the partition constraint. Then we close our
19905  * existing transaction, and in a new one wait for all processes to catch
19906  * up on the catalog updates we've done so far; at that point we can
19907  * complete the operation.
19908  */
19909  if (concurrent)
19910  {
19911  Oid partrelid,
19912  parentrelid;
19913  LOCKTAG tag;
19914  char *parentrelname;
19915  char *partrelname;
19916 
19917  /*
19918  * Add a new constraint to the partition being detached, which
19919  * supplants the partition constraint (unless there is one already).
19920  */
19921  DetachAddConstraintIfNeeded(wqueue, partRel);
19922 
19923  /*
19924  * We're almost done now; the only traces that remain are the
19925  * pg_inherits tuple and the partition's relpartbounds. Before we can
19926  * remove those, we need to wait until all transactions that know that
19927  * this is a partition are gone.
19928  */
19929 
19930  /*
19931  * Remember relation OIDs to re-acquire them later; and relation names
19932  * too, for error messages if something is dropped in between.
19933  */
19934  partrelid = RelationGetRelid(partRel);
19935  parentrelid = RelationGetRelid(rel);
19936  parentrelname = MemoryContextStrdup(PortalContext,
19938  partrelname = MemoryContextStrdup(PortalContext,
19939  RelationGetRelationName(partRel));
19940 
19941  /* Invalidate relcache entries for the parent -- must be before close */
19943 
19944  table_close(partRel, NoLock);
19945  table_close(rel, NoLock);
19946  tab->rel = NULL;
19947 
19948  /* Make updated catalog entry visible */
19951 
19953 
19954  /*
19955  * Now wait. This ensures that all queries that were planned
19956  * including the partition are finished before we remove the rest of
19957  * catalog entries. We don't need or indeed want to acquire this
19958  * lock, though -- that would block later queries.
19959  *
19960  * We don't need to concern ourselves with waiting for a lock on the
19961  * partition itself, since we will acquire AccessExclusiveLock below.
19962  */
19963  SET_LOCKTAG_RELATION(tag, MyDatabaseId, parentrelid);
19965 
19966  /*
19967  * Now acquire locks in both relations again. Note they may have been
19968  * removed in the meantime, so care is required.
19969  */
19970  rel = try_relation_open(parentrelid, ShareUpdateExclusiveLock);
19971  partRel = try_relation_open(partrelid, AccessExclusiveLock);
19972 
19973  /* If the relations aren't there, something bad happened; bail out */
19974  if (rel == NULL)
19975  {
19976  if (partRel != NULL) /* shouldn't happen */
19977  elog(WARNING, "dangling partition \"%s\" remains, can't fix",
19978  partrelname);
19979  ereport(ERROR,
19980  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
19981  errmsg("partitioned table \"%s\" was removed concurrently",
19982  parentrelname)));
19983  }
19984  if (partRel == NULL)
19985  ereport(ERROR,
19986  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
19987  errmsg("partition \"%s\" was removed concurrently", partrelname)));
19988 
19989  tab->rel = rel;
19990  }
19991 
19992  /* Do the final part of detaching */
19993  DetachPartitionFinalize(rel, partRel, concurrent, defaultPartOid);
19994 
19995  ObjectAddressSet(address, RelationRelationId, RelationGetRelid(partRel));
19996 
19997  /* keep our lock until commit */
19998  table_close(partRel, NoLock);
19999 
20000  return address;
20001 }
20002 
20003 /*
20004  * Second part of ALTER TABLE .. DETACH.
20005  *
20006  * This is separate so that it can be run independently when the second
20007  * transaction of the concurrent algorithm fails (crash or abort).
20008  */
20009 static void
20010 DetachPartitionFinalize(Relation rel, Relation partRel, bool concurrent,
20011  Oid defaultPartOid)
20012 {
20013  Relation classRel;
20014  List *fks;
20015  ListCell *cell;
20016  List *indexes;
20017  Datum new_val[Natts_pg_class];
20018  bool new_null[Natts_pg_class],
20019  new_repl[Natts_pg_class];
20020  HeapTuple tuple,
20021  newtuple;
20022  Relation trigrel = NULL;
20023 
20024  if (concurrent)
20025  {
20026  /*
20027  * We can remove the pg_inherits row now. (In the non-concurrent case,
20028  * this was already done).
20029  */
20030  RemoveInheritance(partRel, rel, true);
20031  }
20032 
20033  /* Drop any triggers that were cloned on creation/attach. */
20035 
20036  /*
20037  * Detach any foreign keys that are inherited. This includes creating
20038  * additional action triggers.
20039  */
20040  fks = copyObject(RelationGetFKeyList(partRel));
20041  if (fks != NIL)
20042  trigrel = table_open(TriggerRelationId, RowExclusiveLock);
20043  foreach(cell, fks)
20044  {
20045  ForeignKeyCacheInfo *fk = lfirst(cell);
20046  HeapTuple contup;
20047  Form_pg_constraint conform;
20048  Constraint *fkconstraint;
20049  Oid insertTriggerOid,
20050  updateTriggerOid;
20051 
20052  contup = SearchSysCache1(CONSTROID, ObjectIdGetDatum(fk->conoid));
20053  if (!HeapTupleIsValid(contup))
20054  elog(ERROR, "cache lookup failed for constraint %u", fk->conoid);
20055  conform = (Form_pg_constraint) GETSTRUCT(contup);
20056 
20057  /* consider only the inherited foreign keys */
20058  if (conform->contype != CONSTRAINT_FOREIGN ||
20059  !OidIsValid(conform->conparentid))
20060  {
20061  ReleaseSysCache(contup);
20062  continue;
20063  }
20064 
20065  /* unset conparentid and adjust conislocal, coninhcount, etc. */
20067 
20068  /*
20069  * Also, look up the partition's "check" triggers corresponding to the
20070  * constraint being detached and detach them from the parent triggers.
20071  */
20073  fk->conoid, fk->confrelid, fk->conrelid,
20074  &insertTriggerOid, &updateTriggerOid);
20075  Assert(OidIsValid(insertTriggerOid));
20076  TriggerSetParentTrigger(trigrel, insertTriggerOid, InvalidOid,
20077  RelationGetRelid(partRel));
20078  Assert(OidIsValid(updateTriggerOid));
20079  TriggerSetParentTrigger(trigrel, updateTriggerOid, InvalidOid,
20080  RelationGetRelid(partRel));
20081 
20082  /*
20083  * Make the action triggers on the referenced relation. When this was
20084  * a partition the action triggers pointed to the parent rel (they
20085  * still do), but now we need separate ones of our own.
20086  */
20087  fkconstraint = makeNode(Constraint);
20088  fkconstraint->contype = CONSTRAINT_FOREIGN;
20089  fkconstraint->conname = pstrdup(NameStr(conform->conname));
20090  fkconstraint->deferrable = conform->condeferrable;
20091  fkconstraint->initdeferred = conform->condeferred;
20092  fkconstraint->location = -1;
20093  fkconstraint->pktable = NULL;
20094  fkconstraint->fk_attrs = NIL;
20095  fkconstraint->pk_attrs = NIL;
20096  fkconstraint->fk_matchtype = conform->confmatchtype;
20097  fkconstraint->fk_upd_action = conform->confupdtype;
20098  fkconstraint->fk_del_action = conform->confdeltype;
20099  fkconstraint->fk_del_set_cols = NIL;
20100  fkconstraint->old_conpfeqop = NIL;
20101  fkconstraint->old_pktable_oid = InvalidOid;
20102  fkconstraint->skip_validation = false;
20103  fkconstraint->initially_valid = true;
20104 
20105  createForeignKeyActionTriggers(partRel, conform->confrelid,
20106  fkconstraint, fk->conoid,
20107  conform->conindid,
20109  NULL, NULL);
20110 
20111  ReleaseSysCache(contup);
20112  }
20113  list_free_deep(fks);
20114  if (trigrel)
20115  table_close(trigrel, RowExclusiveLock);
20116 
20117  /*
20118  * Any sub-constraints that are in the referenced-side of a larger
20119  * constraint have to be removed. This partition is no longer part of the
20120  * key space of the constraint.
20121  */
20122  foreach(cell, GetParentedForeignKeyRefs(partRel))
20123  {
20124  Oid constrOid = lfirst_oid(cell);
20125  ObjectAddress constraint;
20126 
20128  deleteDependencyRecordsForClass(ConstraintRelationId,
20129  constrOid,
20130  ConstraintRelationId,
20133 
20134  ObjectAddressSet(constraint, ConstraintRelationId, constrOid);
20135  performDeletion(&constraint, DROP_RESTRICT, 0);
20136  }
20137 
20138  /* Now we can detach indexes */
20139  indexes = RelationGetIndexList(partRel);
20140  foreach(cell, indexes)
20141  {
20142  Oid idxid = lfirst_oid(cell);
20143  Relation idx;
20144  Oid constrOid;
20145 
20146  if (!has_superclass(idxid))
20147  continue;
20148 
20149  Assert((IndexGetRelation(get_partition_parent(idxid, false), false) ==
20150  RelationGetRelid(rel)));
20151 
20154 
20155  /* If there's a constraint associated with the index, detach it too */
20157  idxid);
20158  if (OidIsValid(constrOid))
20160 
20162  }
20163 
20164  /* Update pg_class tuple */
20165  classRel = table_open(RelationRelationId, RowExclusiveLock);
20166  tuple = SearchSysCacheCopy1(RELOID,
20168  if (!HeapTupleIsValid(tuple))
20169  elog(ERROR, "cache lookup failed for relation %u",
20170  RelationGetRelid(partRel));
20171  Assert(((Form_pg_class) GETSTRUCT(tuple))->relispartition);
20172 
20173  /* Clear relpartbound and reset relispartition */
20174  memset(new_val, 0, sizeof(new_val));
20175  memset(new_null, false, sizeof(new_null));
20176  memset(new_repl, false, sizeof(new_repl));
20177  new_val[Anum_pg_class_relpartbound - 1] = (Datum) 0;
20178  new_null[Anum_pg_class_relpartbound - 1] = true;
20179  new_repl[Anum_pg_class_relpartbound - 1] = true;
20180  newtuple = heap_modify_tuple(tuple, RelationGetDescr(classRel),
20181  new_val, new_null, new_repl);
20182 
20183  ((Form_pg_class) GETSTRUCT(newtuple))->relispartition = false;
20184  CatalogTupleUpdate(classRel, &newtuple->t_self, newtuple);
20185  heap_freetuple(newtuple);
20186  table_close(classRel, RowExclusiveLock);
20187 
20188  /*
20189  * Drop identity property from all identity columns of partition.
20190  */
20191  for (int attno = 0; attno < RelationGetNumberOfAttributes(partRel); attno++)
20192  {
20193  Form_pg_attribute attr = TupleDescAttr(partRel->rd_att, attno);
20194 
20195  if (!attr->attisdropped && attr->attidentity)
20196  ATExecDropIdentity(partRel, NameStr(attr->attname), false,
20197  AccessExclusiveLock, true, true);
20198  }
20199 
20200  if (OidIsValid(defaultPartOid))
20201  {
20202  /*
20203  * If the relation being detached is the default partition itself,
20204  * remove it from the parent's pg_partitioned_table entry.
20205  *
20206  * If not, we must invalidate default partition's relcache entry, as
20207  * in StorePartitionBound: its partition constraint depends on every
20208  * other partition's partition constraint.
20209  */
20210  if (RelationGetRelid(partRel) == defaultPartOid)
20212  else
20213  CacheInvalidateRelcacheByRelid(defaultPartOid);
20214  }
20215 
20216  /*
20217  * Invalidate the parent's relcache so that the partition is no longer
20218  * included in its partition descriptor.
20219  */
20221 
20222  /*
20223  * If the partition we just detached is partitioned itself, invalidate
20224  * relcache for all descendent partitions too to ensure that their
20225  * rd_partcheck expression trees are rebuilt; must lock partitions before
20226  * doing so, using the same lockmode as what partRel has been locked with
20227  * by the caller.
20228  */
20229  if (partRel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
20230  {
20231  List *children;
20232 
20233  children = find_all_inheritors(RelationGetRelid(partRel),
20234  AccessExclusiveLock, NULL);
20235  foreach(cell, children)
20236  {
20238  }
20239  }
20240 }
20241 
20242 /*
20243  * ALTER TABLE ... DETACH PARTITION ... FINALIZE
20244  *
20245  * To use when a DETACH PARTITION command previously did not run to
20246  * completion; this completes the detaching process.
20247  */
20248 static ObjectAddress
20250 {
20251  Relation partRel;
20252  ObjectAddress address;
20253  Snapshot snap = GetActiveSnapshot();
20254 
20256 
20257  /*
20258  * Wait until existing snapshots are gone. This is important if the
20259  * second transaction of DETACH PARTITION CONCURRENTLY is canceled: the
20260  * user could immediately run DETACH FINALIZE without actually waiting for
20261  * existing transactions. We must not complete the detach action until
20262  * all such queries are complete (otherwise we would present them with an
20263  * inconsistent view of catalogs).
20264  */
20265  WaitForOlderSnapshots(snap->xmin, false);
20266 
20267  DetachPartitionFinalize(rel, partRel, true, InvalidOid);
20268 
20269  ObjectAddressSet(address, RelationRelationId, RelationGetRelid(partRel));
20270 
20271  table_close(partRel, NoLock);
20272 
20273  return address;
20274 }
20275 
20276 /*
20277  * DetachAddConstraintIfNeeded
20278  * Subroutine for ATExecDetachPartition. Create a constraint that
20279  * takes the place of the partition constraint, but avoid creating
20280  * a dupe if a constraint already exists which implies the needed
20281  * constraint.
20282  */
20283 static void
20285 {
20286  List *constraintExpr;
20287 
20288  constraintExpr = RelationGetPartitionQual(partRel);
20289  constraintExpr = (List *) eval_const_expressions(NULL, (Node *) constraintExpr);
20290 
20291  /*
20292  * Avoid adding a new constraint if the needed constraint is implied by an
20293  * existing constraint
20294  */
20295  if (!PartConstraintImpliedByRelConstraint(partRel, constraintExpr))
20296  {
20297  AlteredTableInfo *tab;
20298  Constraint *n;
20299 
20300  tab = ATGetQueueEntry(wqueue, partRel);
20301 
20302  /* Add constraint on partition, equivalent to the partition constraint */
20303  n = makeNode(Constraint);
20304  n->contype = CONSTR_CHECK;
20305  n->conname = NULL;
20306  n->location = -1;
20307  n->is_no_inherit = false;
20308  n->raw_expr = NULL;
20309  n->cooked_expr = nodeToString(make_ands_explicit(constraintExpr));
20310  n->initially_valid = true;
20311  n->skip_validation = true;
20312  /* It's a re-add, since it nominally already exists */
20313  ATAddCheckNNConstraint(wqueue, tab, partRel, n,
20314  true, false, true, ShareUpdateExclusiveLock);
20315  }
20316 }
20317 
20318 /*
20319  * DropClonedTriggersFromPartition
20320  * subroutine for ATExecDetachPartition to remove any triggers that were
20321  * cloned to the partition when it was created-as-partition or attached.
20322  * This undoes what CloneRowTriggersToPartition did.
20323  */
20324 static void
20326 {
20327  ScanKeyData skey;
20328  SysScanDesc scan;
20329  HeapTuple trigtup;
20330  Relation tgrel;
20331  ObjectAddresses *objects;
20332 
20333  objects = new_object_addresses();
20334 
20335  /*
20336  * Scan pg_trigger to search for all triggers on this rel.
20337  */
20338  ScanKeyInit(&skey, Anum_pg_trigger_tgrelid, BTEqualStrategyNumber,
20339  F_OIDEQ, ObjectIdGetDatum(partitionId));
20340  tgrel = table_open(TriggerRelationId, RowExclusiveLock);
20341  scan = systable_beginscan(tgrel, TriggerRelidNameIndexId,
20342  true, NULL, 1, &skey);
20343  while (HeapTupleIsValid(trigtup = systable_getnext(scan)))
20344  {
20345  Form_pg_trigger pg_trigger = (Form_pg_trigger) GETSTRUCT(trigtup);
20346  ObjectAddress trig;
20347 
20348  /* Ignore triggers that weren't cloned */
20349  if (!OidIsValid(pg_trigger->tgparentid))
20350  continue;
20351 
20352  /*
20353  * Ignore internal triggers that are implementation objects of foreign
20354  * keys, because these will be detached when the foreign keys
20355  * themselves are.
20356  */
20357  if (OidIsValid(pg_trigger->tgconstrrelid))
20358  continue;
20359 
20360  /*
20361  * This is ugly, but necessary: remove the dependency markings on the
20362  * trigger so that it can be removed.
20363  */
20364  deleteDependencyRecordsForClass(TriggerRelationId, pg_trigger->oid,
20365  TriggerRelationId,
20367  deleteDependencyRecordsForClass(TriggerRelationId, pg_trigger->oid,
20368  RelationRelationId,
20370 
20371  /* remember this trigger to remove it below */
20372  ObjectAddressSet(trig, TriggerRelationId, pg_trigger->oid);
20373  add_exact_object_address(&trig, objects);
20374  }
20375 
20376  /* make the dependency removal visible to the deletion below */
20379 
20380  /* done */
20381  free_object_addresses(objects);
20382  systable_endscan(scan);
20383  table_close(tgrel, RowExclusiveLock);
20384 }
20385 
20386 /*
20387  * Before acquiring lock on an index, acquire the same lock on the owning
20388  * table.
20389  */
20391 {
20395 };
20396 
20397 static void
20398 RangeVarCallbackForAttachIndex(const RangeVar *rv, Oid relOid, Oid oldRelOid,
20399  void *arg)
20400 {
20402  Form_pg_class classform;
20403  HeapTuple tuple;
20404 
20405  state = (struct AttachIndexCallbackState *) arg;
20406 
20407  if (!state->lockedParentTbl)
20408  {
20409  LockRelationOid(state->parentTblOid, AccessShareLock);
20410  state->lockedParentTbl = true;
20411  }
20412 
20413  /*
20414  * If we previously locked some other heap, and the name we're looking up
20415  * no longer refers to an index on that relation, release the now-useless
20416  * lock. XXX maybe we should do *after* we verify whether the index does
20417  * not actually belong to the same relation ...
20418  */
20419  if (relOid != oldRelOid && OidIsValid(state->partitionOid))
20420  {
20421  UnlockRelationOid(state->partitionOid, AccessShareLock);
20422  state->partitionOid = InvalidOid;
20423  }
20424 
20425  /* Didn't find a relation, so no need for locking or permission checks. */
20426  if (!OidIsValid(relOid))
20427  return;
20428 
20429  tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relOid));
20430  if (!HeapTupleIsValid(tuple))
20431  return; /* concurrently dropped, so nothing to do */
20432  classform = (Form_pg_class) GETSTRUCT(tuple);
20433  if (classform->relkind != RELKIND_PARTITIONED_INDEX &&
20434  classform->relkind != RELKIND_INDEX)
20435  ereport(ERROR,
20436  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
20437  errmsg("\"%s\" is not an index", rv->relname)));
20438  ReleaseSysCache(tuple);
20439 
20440  /*
20441  * Since we need only examine the heap's tupledesc, an access share lock
20442  * on it (preventing any DDL) is sufficient.
20443  */
20444  state->partitionOid = IndexGetRelation(relOid, false);
20445  LockRelationOid(state->partitionOid, AccessShareLock);
20446 }
20447 
20448 /*
20449  * ALTER INDEX i1 ATTACH PARTITION i2
20450  */
20451 static ObjectAddress
20453 {
20454  Relation partIdx;
20455  Relation partTbl;
20456  Relation parentTbl;
20457  ObjectAddress address;
20458  Oid partIdxId;
20459  Oid currParent;
20461 
20462  /*
20463  * We need to obtain lock on the index 'name' to modify it, but we also
20464  * need to read its owning table's tuple descriptor -- so we need to lock
20465  * both. To avoid deadlocks, obtain lock on the table before doing so on
20466  * the index. Furthermore, we need to examine the parent table of the
20467  * partition, so lock that one too.
20468  */
20469  state.partitionOid = InvalidOid;
20470  state.parentTblOid = parentIdx->rd_index->indrelid;
20471  state.lockedParentTbl = false;
20472  partIdxId =
20475  (void *) &state);
20476  /* Not there? */
20477  if (!OidIsValid(partIdxId))
20478  ereport(ERROR,
20479  (errcode(ERRCODE_UNDEFINED_OBJECT),
20480  errmsg("index \"%s\" does not exist", name->relname)));
20481 
20482  /* no deadlock risk: RangeVarGetRelidExtended already acquired the lock */
20483  partIdx = relation_open(partIdxId, AccessExclusiveLock);
20484 
20485  /* we already hold locks on both tables, so this is safe: */
20486  parentTbl = relation_open(parentIdx->rd_index->indrelid, AccessShareLock);
20487  partTbl = relation_open(partIdx->rd_index->indrelid, NoLock);
20488 
20489  ObjectAddressSet(address, RelationRelationId, RelationGetRelid(partIdx));
20490 
20491  /* Silently do nothing if already in the right state */
20492  currParent = partIdx->rd_rel->relispartition ?
20493  get_partition_parent(partIdxId, false) : InvalidOid;
20494  if (currParent != RelationGetRelid(parentIdx))
20495  {
20496  IndexInfo *childInfo;
20497  IndexInfo *parentInfo;
20498  AttrMap *attmap;
20499  bool found;
20500  int i;
20501  PartitionDesc partDesc;
20502  Oid constraintOid,
20503  cldConstrId = InvalidOid;
20504 
20505  /*
20506  * If this partition already has an index attached, refuse the
20507  * operation.
20508  */
20509  refuseDupeIndexAttach(parentIdx, partIdx, partTbl);
20510 
20511  if (OidIsValid(currParent))
20512  ereport(ERROR,
20513  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
20514  errmsg("cannot attach index \"%s\" as a partition of index \"%s\"",
20515  RelationGetRelationName(partIdx),
20516  RelationGetRelationName(parentIdx)),
20517  errdetail("Index \"%s\" is already attached to another index.",
20518  RelationGetRelationName(partIdx))));
20519 
20520  /* Make sure it indexes a partition of the other index's table */
20521  partDesc = RelationGetPartitionDesc(parentTbl, true);
20522  found = false;
20523  for (i = 0; i < partDesc->nparts; i++)
20524  {
20525  if (partDesc->oids[i] == state.partitionOid)
20526  {
20527  found = true;
20528  break;
20529  }
20530  }
20531  if (!found)
20532  ereport(ERROR,
20533  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
20534  errmsg("cannot attach index \"%s\" as a partition of index \"%s\"",
20535  RelationGetRelationName(partIdx),
20536  RelationGetRelationName(parentIdx)),
20537  errdetail("Index \"%s\" is not an index on any partition of table \"%s\".",
20538  RelationGetRelationName(partIdx),
20539  RelationGetRelationName(parentTbl))));
20540 
20541  /* Ensure the indexes are compatible */
20542  childInfo = BuildIndexInfo(partIdx);
20543  parentInfo = BuildIndexInfo(parentIdx);
20544  attmap = build_attrmap_by_name(RelationGetDescr(partTbl),
20545  RelationGetDescr(parentTbl),
20546  false);
20547  if (!CompareIndexInfo(childInfo, parentInfo,
20548  partIdx->rd_indcollation,
20549  parentIdx->rd_indcollation,
20550  partIdx->rd_opfamily,
20551  parentIdx->rd_opfamily,
20552  attmap))
20553  ereport(ERROR,
20554  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
20555  errmsg("cannot attach index \"%s\" as a partition of index \"%s\"",
20556  RelationGetRelationName(partIdx),
20557  RelationGetRelationName(parentIdx)),
20558  errdetail("The index definitions do not match.")));
20559 
20560  /*
20561  * If there is a constraint in the parent, make sure there is one in
20562  * the child too.
20563  */
20564  constraintOid = get_relation_idx_constraint_oid(RelationGetRelid(parentTbl),
20565  RelationGetRelid(parentIdx));
20566 
20567  if (OidIsValid(constraintOid))
20568  {
20569  cldConstrId = get_relation_idx_constraint_oid(RelationGetRelid(partTbl),
20570  partIdxId);
20571  if (!OidIsValid(cldConstrId))
20572  ereport(ERROR,
20573  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
20574  errmsg("cannot attach index \"%s\" as a partition of index \"%s\"",
20575  RelationGetRelationName(partIdx),
20576  RelationGetRelationName(parentIdx)),
20577  errdetail("The index \"%s\" belongs to a constraint in table \"%s\" but no constraint exists for index \"%s\".",
20578  RelationGetRelationName(parentIdx),
20579  RelationGetRelationName(parentTbl),
20580  RelationGetRelationName(partIdx))));
20581  }
20582 
20583  /*
20584  * If it's a primary key, make sure the columns in the partition are
20585  * NOT NULL.
20586  */
20587  if (parentIdx->rd_index->indisprimary)
20588  verifyPartitionIndexNotNull(childInfo, partTbl);
20589 
20590  /* All good -- do it */
20591  IndexSetParentIndex(partIdx, RelationGetRelid(parentIdx));
20592  if (OidIsValid(constraintOid))
20593  ConstraintSetParentConstraint(cldConstrId, constraintOid,
20594  RelationGetRelid(partTbl));
20595 
20596  free_attrmap(attmap);
20597 
20598  validatePartitionedIndex(parentIdx, parentTbl);
20599  }
20600 
20601  relation_close(parentTbl, AccessShareLock);
20602  /* keep these locks till commit */
20603  relation_close(partTbl, NoLock);
20604  relation_close(partIdx, NoLock);
20605 
20606  return address;
20607 }
20608 
20609 /*
20610  * Verify whether the given partition already contains an index attached
20611  * to the given partitioned index. If so, raise an error.
20612  */
20613 static void
20614 refuseDupeIndexAttach(Relation parentIdx, Relation partIdx, Relation partitionTbl)
20615 {
20616  Oid existingIdx;
20617 
20618  existingIdx = index_get_partition(partitionTbl,
20619  RelationGetRelid(parentIdx));
20620  if (OidIsValid(existingIdx))
20621  ereport(ERROR,
20622  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
20623  errmsg("cannot attach index \"%s\" as a partition of index \"%s\"",
20624  RelationGetRelationName(partIdx),
20625  RelationGetRelationName(parentIdx)),
20626  errdetail("Another index is already attached for partition \"%s\".",
20627  RelationGetRelationName(partitionTbl))));
20628 }
20629 
20630 /*
20631  * Verify whether the set of attached partition indexes to a parent index on
20632  * a partitioned table is complete. If it is, mark the parent index valid.
20633  *
20634  * This should be called each time a partition index is attached.
20635  */
20636 static void
20638 {
20639  Relation inheritsRel;
20640  SysScanDesc scan;
20641  ScanKeyData key;
20642  int tuples = 0;
20643  HeapTuple inhTup;
20644  bool updated = false;
20645 
20646  Assert(partedIdx->rd_rel->relkind == RELKIND_PARTITIONED_INDEX);
20647 
20648  /*
20649  * Scan pg_inherits for this parent index. Count each valid index we find
20650  * (verifying the pg_index entry for each), and if we reach the total
20651  * amount we expect, we can mark this parent index as valid.
20652  */
20653  inheritsRel = table_open(InheritsRelationId, AccessShareLock);
20654  ScanKeyInit(&key, Anum_pg_inherits_inhparent,
20655  BTEqualStrategyNumber, F_OIDEQ,
20656  ObjectIdGetDatum(RelationGetRelid(partedIdx)));
20657  scan = systable_beginscan(inheritsRel, InheritsParentIndexId, true,
20658  NULL, 1, &key);
20659  while ((inhTup = systable_getnext(scan)) != NULL)
20660  {
20661  Form_pg_inherits inhForm = (Form_pg_inherits) GETSTRUCT(inhTup);
20662  HeapTuple indTup;
20663  Form_pg_index indexForm;
20664 
20665  indTup = SearchSysCache1(INDEXRELID,
20666  ObjectIdGetDatum(inhForm->inhrelid));
20667  if (!HeapTupleIsValid(indTup))
20668  elog(ERROR, "cache lookup failed for index %u", inhForm->inhrelid);
20669  indexForm = (Form_pg_index) GETSTRUCT(indTup);
20670  if (indexForm->indisvalid)
20671  tuples += 1;
20672  ReleaseSysCache(indTup);
20673  }
20674 
20675  /* Done with pg_inherits */
20676  systable_endscan(scan);
20677  table_close(inheritsRel, AccessShareLock);
20678 
20679  /*
20680  * If we found as many inherited indexes as the partitioned table has
20681  * partitions, we're good; update pg_index to set indisvalid.
20682  */
20683  if (tuples == RelationGetPartitionDesc(partedTbl, true)->nparts)
20684  {
20685  Relation idxRel;
20686  HeapTuple indTup;
20687  Form_pg_index indexForm;
20688 
20689  idxRel = table_open(IndexRelationId, RowExclusiveLock);
20690  indTup = SearchSysCacheCopy1(INDEXRELID,
20691  ObjectIdGetDatum(RelationGetRelid(partedIdx)));
20692  if (!HeapTupleIsValid(indTup))
20693  elog(ERROR, "cache lookup failed for index %u",
20694  RelationGetRelid(partedIdx));
20695  indexForm = (Form_pg_index) GETSTRUCT(indTup);
20696 
20697  indexForm->indisvalid = true;
20698  updated = true;
20699 
20700  CatalogTupleUpdate(idxRel, &indTup->t_self, indTup);
20701 
20702  table_close(idxRel, RowExclusiveLock);
20703  heap_freetuple(indTup);
20704  }
20705 
20706  /*
20707  * If this index is in turn a partition of a larger index, validating it
20708  * might cause the parent to become valid also. Try that.
20709  */
20710  if (updated && partedIdx->rd_rel->relispartition)
20711  {
20712  Oid parentIdxId,
20713  parentTblId;
20714  Relation parentIdx,
20715  parentTbl;
20716 
20717  /* make sure we see the validation we just did */
20719 
20720  parentIdxId = get_partition_parent(RelationGetRelid(partedIdx), false);
20721  parentTblId = get_partition_parent(RelationGetRelid(partedTbl), false);
20722  parentIdx = relation_open(parentIdxId, AccessExclusiveLock);
20723  parentTbl = relation_open(parentTblId, AccessExclusiveLock);
20724  Assert(!parentIdx->rd_index->indisvalid);
20725 
20726  validatePartitionedIndex(parentIdx, parentTbl);
20727 
20728  relation_close(parentIdx, AccessExclusiveLock);
20729  relation_close(parentTbl, AccessExclusiveLock);
20730  }
20731 }
20732 
20733 /*
20734  * When attaching an index as a partition of a partitioned index which is a
20735  * primary key, verify that all the columns in the partition are marked NOT
20736  * NULL.
20737  */
20738 static void
20740 {
20741  for (int i = 0; i < iinfo->ii_NumIndexKeyAttrs; i++)
20742  {
20744  iinfo->ii_IndexAttrNumbers[i] - 1);
20745 
20746  if (!att->attnotnull)
20747  ereport(ERROR,
20748  errcode(ERRCODE_INVALID_TABLE_DEFINITION),
20749  errmsg("invalid primary key definition"),
20750  errdetail("Column \"%s\" of relation \"%s\" is not marked NOT NULL.",
20751  NameStr(att->attname),
20752  RelationGetRelationName(partition)));
20753  }
20754 }
20755 
20756 /*
20757  * Return an OID list of constraints that reference the given relation
20758  * that are marked as having a parent constraints.
20759  */
20760 static List *
20762 {
20763  Relation pg_constraint;
20764  HeapTuple tuple;
20765  SysScanDesc scan;
20766  ScanKeyData key[2];
20767  List *constraints = NIL;
20768 
20769  /*
20770  * If no indexes, or no columns are referenceable by FKs, we can avoid the
20771  * scan.
20772  */
20773  if (RelationGetIndexList(partition) == NIL ||
20776  return NIL;
20777 
20778  /* Search for constraints referencing this table */
20779  pg_constraint = table_open(ConstraintRelationId, AccessShareLock);
20780  ScanKeyInit(&key[0],
20781  Anum_pg_constraint_confrelid, BTEqualStrategyNumber,
20782  F_OIDEQ, ObjectIdGetDatum(RelationGetRelid(partition)));
20783  ScanKeyInit(&key[1],
20784  Anum_pg_constraint_contype, BTEqualStrategyNumber,
20785  F_CHAREQ, CharGetDatum(CONSTRAINT_FOREIGN));
20786 
20787  /* XXX This is a seqscan, as we don't have a usable index */
20788  scan = systable_beginscan(pg_constraint, InvalidOid, true, NULL, 2, key);
20789  while ((tuple = systable_getnext(scan)) != NULL)
20790  {
20791  Form_pg_constraint constrForm = (Form_pg_constraint) GETSTRUCT(tuple);
20792 
20793  /*
20794  * We only need to process constraints that are part of larger ones.
20795  */
20796  if (!OidIsValid(constrForm->conparentid))
20797  continue;
20798 
20799  constraints = lappend_oid(constraints, constrForm->oid);
20800  }
20801 
20802  systable_endscan(scan);
20803  table_close(pg_constraint, AccessShareLock);
20804 
20805  return constraints;
20806 }
20807 
20808 /*
20809  * During DETACH PARTITION, verify that any foreign keys pointing to the
20810  * partitioned table would not become invalid. An error is raised if any
20811  * referenced values exist.
20812  */
20813 static void
20815 {
20816  List *constraints;
20817  ListCell *cell;
20818 
20819  constraints = GetParentedForeignKeyRefs(partition);
20820 
20821  foreach(cell, constraints)
20822  {
20823  Oid constrOid = lfirst_oid(cell);
20824  HeapTuple tuple;
20825  Form_pg_constraint constrForm;
20826  Relation rel;
20827  Trigger trig = {0};
20828 
20829  tuple = SearchSysCache1(CONSTROID, ObjectIdGetDatum(constrOid));
20830  if (!HeapTupleIsValid(tuple))
20831  elog(ERROR, "cache lookup failed for constraint %u", constrOid);
20832  constrForm = (Form_pg_constraint) GETSTRUCT(tuple);
20833 
20834  Assert(OidIsValid(constrForm->conparentid));
20835  Assert(constrForm->confrelid == RelationGetRelid(partition));
20836 
20837  /* prevent data changes into the referencing table until commit */
20838  rel = table_open(constrForm->conrelid, ShareLock);
20839 
20840  trig.tgoid = InvalidOid;
20841  trig.tgname = NameStr(constrForm->conname);
20843  trig.tgisinternal = true;
20844  trig.tgconstrrelid = RelationGetRelid(partition);
20845  trig.tgconstrindid = constrForm->conindid;
20846  trig.tgconstraint = constrForm->oid;
20847  trig.tgdeferrable = false;
20848  trig.tginitdeferred = false;
20849  /* we needn't fill in remaining fields */
20850 
20851  RI_PartitionRemove_Check(&trig, rel, partition);
20852 
20853  ReleaseSysCache(tuple);
20854 
20855  table_close(rel, NoLock);
20856  }
20857 }
20858 
20859 /*
20860  * resolve column compression specification to compression method.
20861  */
20862 static char
20863 GetAttributeCompression(Oid atttypid, const char *compression)
20864 {
20865  char cmethod;
20866 
20867  if (compression == NULL || strcmp(compression, "default") == 0)
20868  return InvalidCompressionMethod;
20869 
20870  /*
20871  * To specify a nondefault method, the column data type must be toastable.
20872  * Note this says nothing about whether the column's attstorage setting
20873  * permits compression; we intentionally allow attstorage and
20874  * attcompression to be independent. But with a non-toastable type,
20875  * attstorage could not be set to a value that would permit compression.
20876  *
20877  * We don't actually need to enforce this, since nothing bad would happen
20878  * if attcompression were non-default; it would never be consulted. But
20879  * it seems more user-friendly to complain about a certainly-useless
20880  * attempt to set the property.
20881  */
20882  if (!TypeIsToastable(atttypid))
20883  ereport(ERROR,
20884  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
20885  errmsg("column data type %s does not support compression",
20886  format_type_be(atttypid))));
20887 
20888  cmethod = CompressionNameToMethod(compression);
20889  if (!CompressionMethodIsValid(cmethod))
20890  ereport(ERROR,
20891  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
20892  errmsg("invalid compression method \"%s\"", compression)));
20893 
20894  return cmethod;
20895 }
20896 
20897 /*
20898  * resolve column storage specification
20899  */
20900 static char
20901 GetAttributeStorage(Oid atttypid, const char *storagemode)
20902 {
20903  char cstorage = 0;
20904 
20905  if (pg_strcasecmp(storagemode, "plain") == 0)
20906  cstorage = TYPSTORAGE_PLAIN;
20907  else if (pg_strcasecmp(storagemode, "external") == 0)
20908  cstorage = TYPSTORAGE_EXTERNAL;
20909  else if (pg_strcasecmp(storagemode, "extended") == 0)
20910  cstorage = TYPSTORAGE_EXTENDED;
20911  else if (pg_strcasecmp(storagemode, "main") == 0)
20912  cstorage = TYPSTORAGE_MAIN;
20913  else if (pg_strcasecmp(storagemode, "default") == 0)
20914  cstorage = get_typstorage(atttypid);
20915  else
20916  ereport(ERROR,
20917  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
20918  errmsg("invalid storage type \"%s\"",
20919  storagemode)));
20920 
20921  /*
20922  * safety check: do not allow toasted storage modes unless column datatype
20923  * is TOAST-aware.
20924  */
20925  if (!(cstorage == TYPSTORAGE_PLAIN || TypeIsToastable(atttypid)))
20926  ereport(ERROR,
20927  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
20928  errmsg("column data type %s can only have storage PLAIN",
20929  format_type_be(atttypid))));
20930 
20931  return cstorage;
20932 }
20933 
20934 /*
20935  * Struct with context of new partition for inserting rows from split partition
20936  */
20938 {
20939  ExprState *partqualstate; /* expression for checking slot for partition
20940  * (NULL for DEFAULT partition) */
20941  BulkInsertState bistate; /* state of bulk inserts for partition */
20942  TupleTableSlot *dstslot; /* slot for inserting row into partition */
20943  Relation partRel; /* relation for partition */
20945 
20946 
20947 /*
20948  * createSplitPartitionContext: create context for partition and fill it
20949  */
20950 static SplitPartitionContext *
20952 {
20954 
20956  pc->partRel = partRel;
20957 
20958  /*
20959  * Prepare a BulkInsertState for table_tuple_insert. The FSM is empty, so
20960  * don't bother using it.
20961  */
20962  pc->bistate = GetBulkInsertState();
20963 
20964  /* Create tuple slot for new partition. */
20968 
20969  return pc;
20970 }
20971 
20972 /*
20973  * deleteSplitPartitionContext: delete context for partition
20974  */
20975 static void
20977 {
20980 
20981  table_finish_bulk_insert(pc->partRel, ti_options);
20982 
20983  pfree(pc);
20984 }
20985 
20986 /*
20987  * moveSplitTableRows: scan split partition (splitRel) of partitioned table
20988  * (rel) and move rows into new partitions.
20989  *
20990  * New partitions description:
20991  * partlist: list of pointers to SinglePartitionSpec structures.
20992  * newPartRels: list of Relations.
20993  * defaultPartOid: oid of DEFAULT partition, for table rel.
20994  */
20995 static void
20996 moveSplitTableRows(Relation rel, Relation splitRel, List *partlist, List *newPartRels, Oid defaultPartOid)
20997 {
20998  /* The FSM is empty, so don't bother using it. */
20999  int ti_options = TABLE_INSERT_SKIP_FSM;
21000  CommandId mycid;
21001  EState *estate;
21002  ListCell *listptr,
21003  *listptr2;
21004  TupleTableSlot *srcslot;
21005  ExprContext *econtext;
21006  TableScanDesc scan;
21007  Snapshot snapshot;
21008  MemoryContext oldCxt;
21009  List *partContexts = NIL;
21010  TupleConversionMap *tuple_map;
21011  SplitPartitionContext *defaultPartCtx = NULL,
21012  *pc;
21013  bool isOldDefaultPart = false;
21014 
21015  mycid = GetCurrentCommandId(true);
21016 
21017  estate = CreateExecutorState();
21018 
21019  forboth(listptr, partlist, listptr2, newPartRels)
21020  {
21021  SinglePartitionSpec *sps = (SinglePartitionSpec *) lfirst(listptr);
21022 
21023  pc = createSplitPartitionContext((Relation) lfirst(listptr2));
21024 
21025  if (sps->bound->is_default)
21026  {
21027  /* We should not create constraint for detached DEFAULT partition. */
21028  defaultPartCtx = pc;
21029  }
21030  else
21031  {
21032  List *partConstraint;
21033 
21034  /* Build expression execution states for partition check quals. */
21035  partConstraint = get_qual_from_partbound(rel, sps->bound);
21036  partConstraint =
21037  (List *) eval_const_expressions(NULL,
21038  (Node *) partConstraint);
21039  /* Make boolean expression for ExecCheck(). */
21040  partConstraint = list_make1(make_ands_explicit(partConstraint));
21041 
21042  /*
21043  * Map the vars in the constraint expression from rel's attnos to
21044  * splitRel's.
21045  */
21046  partConstraint = map_partition_varattnos(partConstraint,
21047  1, splitRel, rel);
21048 
21049  pc->partqualstate =
21050  ExecPrepareExpr((Expr *) linitial(partConstraint), estate);
21051  Assert(pc->partqualstate != NULL);
21052  }
21053 
21054  /* Store partition context into list. */
21055  partContexts = lappend(partContexts, pc);
21056  }
21057 
21058  /*
21059  * Create partition context for DEFAULT partition. We can insert values
21060  * into this partition in case spaces with values between new partitions.
21061  */
21062  if (!defaultPartCtx && OidIsValid(defaultPartOid))
21063  {
21064  /* Indicate that we allocate context for old DEFAULT partition */
21065  isOldDefaultPart = true;
21066  defaultPartCtx = createSplitPartitionContext(table_open(defaultPartOid, AccessExclusiveLock));
21067  }
21068 
21069  econtext = GetPerTupleExprContext(estate);
21070 
21071  /* Create necessary tuple slot. */
21072  srcslot = MakeSingleTupleTableSlot(RelationGetDescr(splitRel),
21073  table_slot_callbacks(splitRel));
21074 
21075  /*
21076  * Map computing for moving attributes of split partition to new partition
21077  * (for first new partition, but other new partitions can use the same
21078  * map).
21079  */
21080  pc = (SplitPartitionContext *) lfirst(list_head(partContexts));
21081  tuple_map = convert_tuples_by_name(RelationGetDescr(splitRel),
21082  RelationGetDescr(pc->partRel));
21083 
21084  /* Scan through the rows. */
21085  snapshot = RegisterSnapshot(GetLatestSnapshot());
21086  scan = table_beginscan(splitRel, snapshot, 0, NULL);
21087 
21088  /*
21089  * Switch to per-tuple memory context and reset it for each tuple
21090  * produced, so we don't leak memory.
21091  */
21093 
21094  while (table_scan_getnextslot(scan, ForwardScanDirection, srcslot))
21095  {
21096  bool found = false;
21097  TupleTableSlot *insertslot;
21098 
21099  /* Extract data from old tuple. */
21100  slot_getallattrs(srcslot);
21101 
21102  econtext->ecxt_scantuple = srcslot;
21103 
21104  /* Search partition for current slot srcslot. */
21105  foreach(listptr, partContexts)
21106  {
21107  pc = (SplitPartitionContext *) lfirst(listptr);
21108 
21109  if (pc->partqualstate /* skip DEFAULT partition */ &&
21110  ExecCheck(pc->partqualstate, econtext))
21111  {
21112  found = true;
21113  break;
21114  }
21115  ResetExprContext(econtext);
21116  }
21117  if (!found)
21118  {
21119  /* Use DEFAULT partition if it exists. */
21120  if (defaultPartCtx)
21121  pc = defaultPartCtx;
21122  else
21123  ereport(ERROR,
21124  (errcode(ERRCODE_CHECK_VIOLATION),
21125  errmsg("can not find partition for split partition row"),
21126  errtable(splitRel)));
21127  }
21128 
21129  if (tuple_map)
21130  {
21131  /* Need to use map to copy attributes. */
21132  insertslot = execute_attr_map_slot(tuple_map->attrMap, srcslot, pc->dstslot);
21133  }
21134  else
21135  {
21136  /* Copy attributes directly. */
21137  insertslot = pc->dstslot;
21138 
21139  ExecClearTuple(insertslot);
21140 
21141  memcpy(insertslot->tts_values, srcslot->tts_values,
21142  sizeof(Datum) * srcslot->tts_nvalid);
21143  memcpy(insertslot->tts_isnull, srcslot->tts_isnull,
21144  sizeof(bool) * srcslot->tts_nvalid);
21145 
21146  ExecStoreVirtualTuple(insertslot);
21147  }
21148 
21149  /* Write the tuple out to the new relation. */
21150  table_tuple_insert(pc->partRel, insertslot, mycid,
21151  ti_options, pc->bistate);
21152 
21153  ResetExprContext(econtext);
21154 
21156  }
21157 
21158  MemoryContextSwitchTo(oldCxt);
21159 
21160  table_endscan(scan);
21161  UnregisterSnapshot(snapshot);
21162 
21163  if (tuple_map)
21164  free_conversion_map(tuple_map);
21165 
21167 
21168  FreeExecutorState(estate);
21169 
21170  foreach(listptr, partContexts)
21171  deleteSplitPartitionContext((SplitPartitionContext *) lfirst(listptr), ti_options);
21172 
21173  /* Need to close table and free buffers for DEFAULT partition. */
21174  if (isOldDefaultPart)
21175  {
21176  Relation defaultPartRel = defaultPartCtx->partRel;
21177 
21178  deleteSplitPartitionContext(defaultPartCtx, ti_options);
21179  /* Keep the lock until commit. */
21180  table_close(defaultPartRel, NoLock);
21181  }
21182 }
21183 
21184 /*
21185  * createPartitionTable: create table for a new partition with given name
21186  * (newPartName) like table (modelRelName)
21187  *
21188  * Emulates command: CREATE TABLE <newPartName> (LIKE <modelRelName>
21189  * INCLUDING ALL EXCLUDING INDEXES EXCLUDING IDENTITY)
21190  */
21191 static void
21192 createPartitionTable(RangeVar *newPartName, RangeVar *modelRelName,
21194 {
21195  CreateStmt *createStmt;
21196  TableLikeClause *tlc;
21197  PlannedStmt *wrapper;
21198 
21199  createStmt = makeNode(CreateStmt);
21200  createStmt->relation = newPartName;
21201  createStmt->tableElts = NIL;
21202  createStmt->inhRelations = NIL;
21203  createStmt->constraints = NIL;
21204  createStmt->options = NIL;
21205  createStmt->oncommit = ONCOMMIT_NOOP;
21206  createStmt->tablespacename = NULL;
21207  createStmt->if_not_exists = false;
21208 
21209  tlc = makeNode(TableLikeClause);
21210  tlc->relation = modelRelName;
21211 
21212  /*
21213  * Indexes will be inherited on "attach new partitions" stage, after data
21214  * moving.
21215  */
21217  tlc->relationOid = InvalidOid;
21218  createStmt->tableElts = lappend(createStmt->tableElts, tlc);
21219 
21220  /* Need to make a wrapper PlannedStmt. */
21221  wrapper = makeNode(PlannedStmt);
21222  wrapper->commandType = CMD_UTILITY;
21223  wrapper->canSetTag = false;
21224  wrapper->utilityStmt = (Node *) createStmt;
21225  wrapper->stmt_location = context->pstmt->stmt_location;
21226  wrapper->stmt_len = context->pstmt->stmt_len;
21227 
21228  ProcessUtility(wrapper,
21229  context->queryString,
21230  false,
21232  NULL,
21233  NULL,
21234  None_Receiver,
21235  NULL);
21236 }
21237 
21238 /*
21239  * ALTER TABLE <name> SPLIT PARTITION <partition-name> INTO <partition-list>
21240  */
21241 static void
21244 {
21245  Relation splitRel;
21246  Oid splitRelOid;
21247  char relname[NAMEDATALEN];
21248  Oid namespaceId;
21249  ListCell *listptr,
21250  *listptr2;
21251  bool isSameName = false;
21252  char tmpRelName[NAMEDATALEN];
21253  List *newPartRels = NIL;
21254  ObjectAddress object;
21255  RangeVar *parentName;
21256  Oid defaultPartOid;
21257 
21258  defaultPartOid = get_default_oid_from_partdesc(RelationGetPartitionDesc(rel, true));
21259 
21260  /*
21261  * We are going to detach and remove this partition: need to use exclusive
21262  * lock for preventing DML-queries to the partition.
21263  */
21264  splitRel = table_openrv(cmd->name, AccessExclusiveLock);
21265 
21266  splitRelOid = RelationGetRelid(splitRel);
21267 
21268  /* Check descriptions of new partitions. */
21269  foreach(listptr, cmd->partlist)
21270  {
21271  Oid existing_relid;
21272  SinglePartitionSpec *sps = (SinglePartitionSpec *) lfirst(listptr);
21273 
21275 
21276  /*
21277  * Look up the namespace in which we are supposed to create the
21278  * partition, check we have permission to create there, lock it
21279  * against concurrent drop, and mark stmt->relation as
21280  * RELPERSISTENCE_TEMP if a temporary namespace is selected.
21281  */
21282  namespaceId =
21284 
21285  /*
21286  * This would fail later on anyway if the relation already exists. But
21287  * by catching it here we can emit a nicer error message.
21288  */
21289  existing_relid = get_relname_relid(relname, namespaceId);
21290  if (existing_relid == splitRelOid && !isSameName)
21291  /* One new partition can have the same name as split partition. */
21292  isSameName = true;
21293  else if (existing_relid != InvalidOid)
21294  ereport(ERROR,
21295  (errcode(ERRCODE_DUPLICATE_TABLE),
21296  errmsg("relation \"%s\" already exists", relname)));
21297  }
21298 
21299  /* Detach split partition. */
21300  RemoveInheritance(splitRel, rel, false);
21301  /* Do the final part of detaching. */
21302  DetachPartitionFinalize(rel, splitRel, false, defaultPartOid);
21303 
21304  /*
21305  * If new partition has the same name as split partition then we should
21306  * rename split partition for reusing name.
21307  */
21308  if (isSameName)
21309  {
21310  /*
21311  * We must bump the command counter to make the split partition tuple
21312  * visible for renaming.
21313  */
21315  /* Rename partition. */
21316  sprintf(tmpRelName, "split-%u-%X-tmp", RelationGetRelid(rel), MyProcPid);
21317  RenameRelationInternal(splitRelOid, tmpRelName, false, false);
21318 
21319  /*
21320  * We must bump the command counter to make the split partition tuple
21321  * visible after renaming.
21322  */
21324  }
21325 
21326  /* Create new partitions (like split partition), without indexes. */
21328  RelationGetRelationName(rel), -1);
21329  foreach(listptr, cmd->partlist)
21330  {
21331  SinglePartitionSpec *sps = (SinglePartitionSpec *) lfirst(listptr);
21332  Relation newPartRel;
21333 
21334  createPartitionTable(sps->name, parentName, context);
21335 
21336  /* Open the new partition and acquire exclusive lock on it. */
21337  newPartRel = table_openrv(sps->name, AccessExclusiveLock);
21338 
21339  newPartRels = lappend(newPartRels, newPartRel);
21340  }
21341 
21342  /* Copy data from split partition to new partitions. */
21343  moveSplitTableRows(rel, splitRel, cmd->partlist, newPartRels, defaultPartOid);
21344  /* Keep the lock until commit. */
21345  table_close(splitRel, NoLock);
21346 
21347  /* Attach new partitions to partitioned table. */
21348  forboth(listptr, cmd->partlist, listptr2, newPartRels)
21349  {
21350  SinglePartitionSpec *sps = (SinglePartitionSpec *) lfirst(listptr);
21351  Relation newPartRel = (Relation) lfirst(listptr2);
21352 
21353  /*
21354  * wqueue = NULL: verification for each cloned constraint is not
21355  * needed.
21356  */
21357  attachPartitionTable(NULL, rel, newPartRel, sps->bound);
21358  /* Keep the lock until commit. */
21359  table_close(newPartRel, NoLock);
21360  }
21361 
21362  /* Drop split partition. */
21363  object.classId = RelationRelationId;
21364  object.objectId = splitRelOid;
21365  object.objectSubId = 0;
21366  /* Probably DROP_CASCADE is not needed. */
21367  performDeletion(&object, DROP_RESTRICT, 0);
21368 }
21369 
21370 /*
21371  * moveMergedTablesRows: scan partitions to be merged (mergingPartitionsList)
21372  * of the partitioned table (rel) and move rows into the new partition
21373  * (newPartRel).
21374  */
21375 static void
21376 moveMergedTablesRows(Relation rel, List *mergingPartitionsList,
21377  Relation newPartRel)
21378 {
21379  CommandId mycid;
21380 
21381  /* The FSM is empty, so don't bother using it. */
21382  int ti_options = TABLE_INSERT_SKIP_FSM;
21383  ListCell *listptr;
21384  BulkInsertState bistate; /* state of bulk inserts for partition */
21385  TupleTableSlot *dstslot;
21386 
21387  mycid = GetCurrentCommandId(true);
21388 
21389  /* Prepare a BulkInsertState for table_tuple_insert. */
21390  bistate = GetBulkInsertState();
21391 
21392  /* Create necessary tuple slot. */
21393  dstslot = MakeSingleTupleTableSlot(RelationGetDescr(newPartRel),
21394  table_slot_callbacks(newPartRel));
21395  ExecStoreAllNullTuple(dstslot);
21396 
21397  foreach(listptr, mergingPartitionsList)
21398  {
21399  Relation mergingPartition = (Relation) lfirst(listptr);
21400  TupleTableSlot *srcslot;
21401  TupleConversionMap *tuple_map;
21402  TableScanDesc scan;
21403  Snapshot snapshot;
21404 
21405  /* Create tuple slot for new partition. */
21406  srcslot = MakeSingleTupleTableSlot(RelationGetDescr(mergingPartition),
21407  table_slot_callbacks(mergingPartition));
21408 
21409  /*
21410  * Map computing for moving attributes of merged partition to new
21411  * partition.
21412  */
21413  tuple_map = convert_tuples_by_name(RelationGetDescr(mergingPartition),
21414  RelationGetDescr(newPartRel));
21415 
21416  /* Scan through the rows. */
21417  snapshot = RegisterSnapshot(GetLatestSnapshot());
21418  scan = table_beginscan(mergingPartition, snapshot, 0, NULL);
21419 
21420  while (table_scan_getnextslot(scan, ForwardScanDirection, srcslot))
21421  {
21422  TupleTableSlot *insertslot;
21423 
21424  /* Extract data from old tuple. */
21425  slot_getallattrs(srcslot);
21426 
21427  if (tuple_map)
21428  {
21429  /* Need to use map to copy attributes. */
21430  insertslot = execute_attr_map_slot(tuple_map->attrMap, srcslot, dstslot);
21431  }
21432  else
21433  {
21434  /* Copy attributes directly. */
21435  insertslot = dstslot;
21436 
21437  ExecClearTuple(insertslot);
21438 
21439  memcpy(insertslot->tts_values, srcslot->tts_values,
21440  sizeof(Datum) * srcslot->tts_nvalid);
21441  memcpy(insertslot->tts_isnull, srcslot->tts_isnull,
21442  sizeof(bool) * srcslot->tts_nvalid);
21443 
21444  ExecStoreVirtualTuple(insertslot);
21445  }
21446 
21447  /* Write the tuple out to the new relation. */
21448  table_tuple_insert(newPartRel, insertslot, mycid,
21449  ti_options, bistate);
21450 
21452  }
21453 
21454  table_endscan(scan);
21455  UnregisterSnapshot(snapshot);
21456 
21457  if (tuple_map)
21458  free_conversion_map(tuple_map);
21459 
21461  }
21462 
21464  FreeBulkInsertState(bistate);
21465 
21466  table_finish_bulk_insert(newPartRel, ti_options);
21467 }
21468 
21469 /*
21470  * ALTER TABLE <name> MERGE PARTITIONS <partition-list> INTO <partition-name>
21471  */
21472 static void
21475 {
21476  Relation newPartRel;
21477  ListCell *listptr;
21478  List *mergingPartitionsList = NIL;
21479  Oid defaultPartOid;
21480  char tmpRelName[NAMEDATALEN];
21481  RangeVar *mergePartName = cmd->name;
21482  bool isSameName = false;
21483 
21484  /*
21485  * Lock all merged partitions, check them and create list with partitions
21486  * contexts.
21487  */
21488  foreach(listptr, cmd->partlist)
21489  {
21490  RangeVar *name = (RangeVar *) lfirst(listptr);
21491  Relation mergingPartition;
21492 
21493  /*
21494  * We are going to detach and remove this partition: need to use
21495  * exclusive lock for preventing DML-queries to the partition.
21496  */
21497  mergingPartition = table_openrv(name, AccessExclusiveLock);
21498 
21499  /*
21500  * Checking that two partitions have the same name was before, in
21501  * function transformPartitionCmdForMerge().
21502  */
21503  if (equal(name, cmd->name))
21504  /* One new partition can have the same name as merged partition. */
21505  isSameName = true;
21506 
21507  /* Store a next merging partition into the list. */
21508  mergingPartitionsList = lappend(mergingPartitionsList,
21509  mergingPartition);
21510  }
21511 
21512  /* Detach all merged partitions. */
21513  defaultPartOid =
21515  foreach(listptr, mergingPartitionsList)
21516  {
21517  Relation mergingPartition = (Relation) lfirst(listptr);
21518 
21519  /* Remove the pg_inherits row first. */
21520  RemoveInheritance(mergingPartition, rel, false);
21521  /* Do the final part of detaching. */
21522  DetachPartitionFinalize(rel, mergingPartition, false, defaultPartOid);
21523  }
21524 
21525  /* Create table for new partition, use partitioned table as model. */
21526  if (isSameName)
21527  {
21528  /* Create partition table with generated temporary name. */
21529  sprintf(tmpRelName, "merge-%u-%X-tmp", RelationGetRelid(rel), MyProcPid);
21531  tmpRelName, -1);
21532  }
21533  createPartitionTable(mergePartName,
21535  RelationGetRelationName(rel), -1),
21536  context);
21537 
21538  /*
21539  * Open the new partition and acquire exclusive lock on it. This will
21540  * stop all the operations with partitioned table. This might seem
21541  * excessive, but this is the way we make sure nobody is planning queries
21542  * involving merging partitions.
21543  */
21544  newPartRel = table_openrv(mergePartName, AccessExclusiveLock);
21545 
21546  /* Copy data from merged partitions to new partition. */
21547  moveMergedTablesRows(rel, mergingPartitionsList, newPartRel);
21548 
21549  /*
21550  * Attach a new partition to the partitioned table. wqueue = NULL:
21551  * verification for each cloned constraint is not need.
21552  */
21553  attachPartitionTable(NULL, rel, newPartRel, cmd->bound);
21554 
21555  /* Unlock and drop merged partitions. */
21556  foreach(listptr, mergingPartitionsList)
21557  {
21558  ObjectAddress object;
21559  Relation mergingPartition = (Relation) lfirst(listptr);
21560 
21561  /* Get relation id before table_close() call. */
21562  object.objectId = RelationGetRelid(mergingPartition);
21563  object.classId = RelationRelationId;
21564  object.objectSubId = 0;
21565 
21566  /* Keep the lock until commit. */
21567  table_close(mergingPartition, NoLock);
21568 
21569  performDeletion(&object, DROP_RESTRICT, 0);
21570  }
21571  list_free(mergingPartitionsList);
21572 
21573  /* Rename new partition if it is needed. */
21574  if (isSameName)
21575  {
21576  /*
21577  * We must bump the command counter to make the new partition tuple
21578  * visible for rename.
21579  */
21581  /* Rename partition. */
21583  cmd->name->relname, false, false);
21584  }
21585  /* Keep the lock until commit. */
21586  table_close(newPartRel, NoLock);
21587 }
Datum idx(PG_FUNCTION_ARGS)
Definition: _int_op.c:259
Acl * aclnewowner(const Acl *old_acl, Oid oldOwnerId, Oid newOwnerId)
Definition: acl.c:1096
void check_can_set_role(Oid member, Oid role)
Definition: acl.c:5185
Oid get_rolespec_oid(const RoleSpec *role, bool missing_ok)
Definition: acl.c:5448
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:2688
AclResult pg_attribute_aclcheck(Oid table_oid, AttrNumber attnum, Oid roleid, AclMode mode)
Definition: aclchk.c:3908
AclResult object_aclcheck(Oid classid, Oid objectid, Oid roleid, AclMode mode)
Definition: aclchk.c:3876
bool object_ownercheck(Oid classid, Oid objectid, Oid roleid)
Definition: aclchk.c:4130
void aclcheck_error_type(AclResult aclerr, Oid typeOid)
Definition: aclchk.c:3007
AclResult pg_class_aclcheck(Oid table_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4079
Oid get_table_am_oid(const char *amname, bool missing_ok)
Definition: amcmds.c:173
#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:3354
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:6261
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
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:815
#define bms_is_empty(a)
Definition: bitmapset.h:118
void FlushRelationBuffers(Relation rel)
Definition: bufmgr.c:4435
#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:200
bool IsSystemRelation(Relation relation)
Definition: catalog.c:73
RelFileNumber GetNewRelFileNumber(Oid reltablespace, Relation pg_class, char relpersistence)
Definition: catalog.c:500
bool IsCatalogNamespace(Oid namespaceId)
Definition: catalog.c:182
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:1432
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:2591
ObjectAddresses * new_object_addresses(void)
Definition: dependency.c:2485
void add_exact_object_address(const ObjectAddress *object, ObjectAddresses *addrs)
Definition: dependency.c:2531
void free_object_addresses(ObjectAddresses *addrs)
Definition: dependency.c:2771
#define PERFORM_DELETION_CONCURRENTLY
Definition: dependency.h:86
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:87
#define PERFORM_DELETION_INTERNAL
Definition: dependency.h:85
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:1159
int errdetail(const char *fmt,...)
Definition: elog.c:1205
int errhint(const char *fmt,...)
Definition: elog.c:1319
int errcode(int sqlerrcode)
Definition: elog.c:859
int errmsg(const char *fmt,...)
Definition: elog.c:1072
#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
StrategyNumber GistTranslateStratnum(Oid opclass, StrategyNumber strat)
Definition: gistutil.c:1081
bool IsBinaryUpgrade
Definition: globals.c:118
int MyProcPid
Definition: globals.c:45
bool allowSystemTableMods
Definition: globals.c:127
Oid MyDatabaseTableSpace
Definition: globals.c:93
Oid MyDatabaseId
Definition: globals.c:91
#define newval
for(;;)
void RelationClearMissing(Relation rel)
Definition: heap.c:1937
void StorePartitionKey(Relation rel, char strategy, int16 partnatts, AttrNumber *partattrs, List *partexprs, Oid *partopclass, Oid *partcollation)
Definition: heap.c:3684
List * heap_truncate_find_FKs(List *relationIds)
Definition: heap.c:3557
void RemoveStatistics(Oid relid, AttrNumber attnum)
Definition: heap.c:3282
List * AddRelationNotNullConstraints(Relation rel, List *constraints, List *old_notnulls)
Definition: heap.c:2827
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:1104
void heap_truncate(List *relids)
Definition: heap.c:3377
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:3462
void StorePartitionBound(Relation rel, Relation parent, PartitionBoundSpec *bound)
Definition: heap.c:3840
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:3418
List * AddRelationNewConstraints(Relation rel, List *newColDefaults, List *newConstraints, bool allow_merge, bool is_local, bool is_internal, const char *queryString)
Definition: heap.c:2307
#define CHKATYPE_IS_PARTKEY
Definition: heap.h:25
HeapTuple heap_getnext(TableScanDesc sscan, ScanDirection direction)
Definition: heapam.c:1248
BulkInsertState GetBulkInsertState(void)
Definition: heapam.c:1923
void FreeBulkInsertState(BulkInsertState bistate)
Definition: heapam.c:1940
#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:3527
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:2514
bool reindex_relation(const ReindexStmt *stmt, Oid relid, int flags, const ReindexParams *params)
Definition: index.c:3892
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:2407
#define REINDEX_REL_PROCESS_TOAST
Definition: index.h:159
#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
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:535
void IndexSetParentIndex(Relation partitionIdx, Oid parentOid)
Definition: indexcmds.c:4396
Oid GetDefaultOpClass(Oid type_id, Oid am_id)
Definition: indexcmds.c:2338
bool CheckIndexCompatible(Oid oldId, const char *accessMethodName, const List *attributeList, const List *exclusionOpNames, bool isWithoutOverlaps)
Definition: indexcmds.c:177
void WaitForOlderSnapshots(TransactionId limitXmin, bool progress)
Definition: indexcmds.c:428
Oid ResolveOpClass(const List *opclass, Oid attrType, const char *accessMethodName, Oid accessMethodId)
Definition: indexcmds.c:2253
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:907
void LockRelationOid(Oid relid, LOCKMODE lockmode)
Definition: lmgr.c:108
#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:1695
void pfree(void *pointer)
Definition: mcxt.c:1520
void * palloc0(Size size)
Definition: mcxt.c:1346
MemoryContext CurrentMemoryContext
Definition: mcxt.c:143
char * MemoryContextStrdup(MemoryContext context, const char *string)
Definition: mcxt.c:1682
MemoryContext CacheMemoryContext
Definition: mcxt.c:152
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:454
void * palloc(Size size)
Definition: mcxt.c:1316
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:729
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:121
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:2726
#define ACL_MAINTAIN
Definition: parsenodes.h:90
#define ACL_USAGE
Definition: parsenodes.h:84
#define FKCONSTR_ACTION_SETDEFAULT
Definition: parsenodes.h:2729
PartitionStrategy
Definition: parsenodes.h:871
@ PARTITION_STRATEGY_HASH
Definition: parsenodes.h:874
@ PARTITION_STRATEGY_LIST
Definition: parsenodes.h:872
ConstrType
Definition: parsenodes.h:2706
@ CONSTR_FOREIGN
Definition: parsenodes.h:2717
@ CONSTR_UNIQUE
Definition: parsenodes.h:2715
@ CONSTR_DEFAULT
Definition: parsenodes.h:2710
@ CONSTR_NOTNULL
Definition: parsenodes.h:2709
@ CONSTR_CHECK
Definition: parsenodes.h:2713
@ CONSTR_EXCLUSION
Definition: parsenodes.h:2716
@ CONSTR_PRIMARY
Definition: parsenodes.h:2714
DropBehavior
Definition: parsenodes.h:2335
@ DROP_CASCADE
Definition: parsenodes.h:2337
@ DROP_RESTRICT
Definition: parsenodes.h:2336
ObjectType
Definition: parsenodes.h:2262
@ OBJECT_MATVIEW
Definition: parsenodes.h:2286
@ OBJECT_SCHEMA
Definition: parsenodes.h:2299
@ OBJECT_FOREIGN_TABLE
Definition: parsenodes.h:2281
@ OBJECT_TABLESPACE
Definition: parsenodes.h:2305
@ OBJECT_INDEX
Definition: parsenodes.h:2283
@ OBJECT_SEQUENCE
Definition: parsenodes.h:2300
@ OBJECT_TABLE
Definition: parsenodes.h:2304
@ OBJECT_VIEW
Definition: parsenodes.h:2314
@ OBJECT_TYPE
Definition: parsenodes.h:2312
@ OBJECT_TABCONSTRAINT
Definition: parsenodes.h:2303
@ OBJECT_DOMCONSTRAINT
Definition: parsenodes.h:2276
AlterTableType
Definition: parsenodes.h:2354
@ AT_AddIndexConstraint
Definition: parsenodes.h:2377
@ AT_MergePartitions
Definition: parsenodes.h:2419
@ AT_DropOf
Definition: parsenodes.h:2408
@ AT_SetOptions
Definition: parsenodes.h:2365
@ AT_DropIdentity
Definition: parsenodes.h:2422
@ AT_SetAttNotNull
Definition: parsenodes.h:2361
@ AT_DisableTrigUser
Definition: parsenodes.h:2400
@ AT_DropNotNull
Definition: parsenodes.h:2359
@ AT_AddOf
Definition: parsenodes.h:2407
@ AT_ResetOptions
Definition: parsenodes.h:2366
@ AT_ReplicaIdentity
Definition: parsenodes.h:2409
@ AT_ReplaceRelOptions
Definition: parsenodes.h:2392
@ AT_EnableRowSecurity
Definition: parsenodes.h:2410
@ AT_AddColumnToView
Definition: parsenodes.h:2356
@ AT_ResetRelOptions
Definition: parsenodes.h:2391
@ AT_EnableReplicaTrig
Definition: parsenodes.h:2395
@ AT_DropOids
Definition: parsenodes.h:2387
@ AT_SetIdentity
Definition: parsenodes.h:2421
@ AT_ReAddStatistics
Definition: parsenodes.h:2423
@ AT_SetUnLogged
Definition: parsenodes.h:2386
@ AT_DisableTrig
Definition: parsenodes.h:2396
@ AT_SetCompression
Definition: parsenodes.h:2368
@ AT_DropExpression
Definition: parsenodes.h:2363
@ AT_AddIndex
Definition: parsenodes.h:2370
@ AT_EnableReplicaRule
Definition: parsenodes.h:2403
@ AT_ReAddIndex
Definition: parsenodes.h:2371
@ AT_DropConstraint
Definition: parsenodes.h:2378
@ AT_SetNotNull
Definition: parsenodes.h:2360
@ AT_ClusterOn
Definition: parsenodes.h:2383
@ AT_AddIdentity
Definition: parsenodes.h:2420
@ AT_ForceRowSecurity
Definition: parsenodes.h:2412
@ AT_EnableAlwaysRule
Definition: parsenodes.h:2402
@ AT_SetAccessMethod
Definition: parsenodes.h:2388
@ AT_AlterColumnType
Definition: parsenodes.h:2380
@ AT_DetachPartitionFinalize
Definition: parsenodes.h:2417
@ AT_AddInherit
Definition: parsenodes.h:2405
@ AT_ReAddDomainConstraint
Definition: parsenodes.h:2374
@ AT_EnableTrig
Definition: parsenodes.h:2393
@ AT_DropColumn
Definition: parsenodes.h:2369
@ AT_ReAddComment
Definition: parsenodes.h:2379
@ AT_AlterColumnGenericOptions
Definition: parsenodes.h:2381
@ AT_DisableTrigAll
Definition: parsenodes.h:2398
@ AT_EnableRule
Definition: parsenodes.h:2401
@ AT_NoForceRowSecurity
Definition: parsenodes.h:2413
@ AT_DetachPartition
Definition: parsenodes.h:2416
@ AT_SetStatistics
Definition: parsenodes.h:2364
@ AT_AttachPartition
Definition: parsenodes.h:2415
@ AT_AddConstraint
Definition: parsenodes.h:2372
@ AT_DropInherit
Definition: parsenodes.h:2406
@ AT_EnableAlwaysTrig
Definition: parsenodes.h:2394
@ AT_SetLogged
Definition: parsenodes.h:2385
@ AT_SetStorage
Definition: parsenodes.h:2367
@ AT_DisableRule
Definition: parsenodes.h:2404
@ AT_DisableRowSecurity
Definition: parsenodes.h:2411
@ AT_SetRelOptions
Definition: parsenodes.h:2390
@ AT_ChangeOwner
Definition: parsenodes.h:2382
@ AT_EnableTrigUser
Definition: parsenodes.h:2399
@ AT_SetExpression
Definition: parsenodes.h:2362
@ AT_ReAddConstraint
Definition: parsenodes.h:2373
@ AT_SetTableSpace
Definition: parsenodes.h:2389
@ AT_GenericOptions
Definition: parsenodes.h:2414
@ AT_ColumnDefault
Definition: parsenodes.h:2357
@ AT_CookedColumnDefault
Definition: parsenodes.h:2358
@ AT_AlterConstraint
Definition: parsenodes.h:2375
@ AT_EnableTrigAll
Definition: parsenodes.h:2397
@ AT_SplitPartition
Definition: parsenodes.h:2418
@ AT_DropCluster
Definition: parsenodes.h:2384
@ AT_ValidateConstraint
Definition: parsenodes.h:2376
@ AT_AddColumn
Definition: parsenodes.h:2355
#define ACL_REFERENCES
Definition: parsenodes.h:81
#define FKCONSTR_ACTION_CASCADE
Definition: parsenodes.h:2727
#define ACL_TRUNCATE
Definition: parsenodes.h:80
#define ACL_CREATE
Definition: parsenodes.h:85
#define FKCONSTR_ACTION_SETNULL
Definition: parsenodes.h:2728
@ CREATE_TABLE_LIKE_IDENTITY
Definition: parsenodes.h:766
@ CREATE_TABLE_LIKE_ALL
Definition: parsenodes.h:770
@ CREATE_TABLE_LIKE_INDEXES
Definition: parsenodes.h:767
#define FKCONSTR_ACTION_NOACTION
Definition: parsenodes.h:2725
@ 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:70
Oid get_default_oid_from_partdesc(PartitionDesc partdesc)
Definition: partdesc.c:459
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)
HeapTuple findNotNullConstraint(Oid relid, const char *colname)
bool ConstraintNameIsUsed(ConstraintCategory conCat, Oid objId, const char *conname)
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 conPeriod, bool is_internal)
Definition: pg_constraint.c:51
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)
List * RelationGetNotNullConstraints(Oid relid, bool cooked)
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 AdjustNotNullInheritance(Oid relid, Bitmapset *columns, int count)
HeapTuple findNotNullConstraintAttnum(Oid relid, AttrNumber attnum)
void AlterConstraintNamespaces(Oid ownerId, Oid oldNspId, Oid newNspId, bool isType, ObjectAddresses *objsMoved)
void FindFKPeriodOpers(Oid opclass, Oid *containedbyoperoid, Oid *aggedcontainedbyoperoid)
Oid get_relation_constraint_oid(Oid relid, const char *conname, bool missing_ok)
AttrNumber extractNotNullColumn(HeapTuple constrTup)
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:44
long changeDependencyFor(Oid classId, Oid objectId, Oid refClassId, Oid oldRefObjectId, Oid newRefObjectId)
Definition: pg_depend.c:456
long deleteDependencyRecordsForClass(Oid classId, Oid objectId, Oid refclassId, char deptype)
Definition: pg_depend.c:350
long deleteDependencyRecordsFor(Oid classId, Oid objectId, bool skipExtensionDeps)
Definition: pg_depend.c:300
Oid get_index_constraint(Oid indexId)
Definition: pg_depend.c:968
Oid getIdentitySequence(Oid relid, AttrNumber attnum, bool missing_ok)
Definition: pg_depend.c:944
List * getOwnedSequences(Oid relid)
Definition: pg_depend.c:935
bool sequenceIsOwned(Oid seqId, char deptype, Oid *tableId, int32 *colId)
Definition: pg_depend.c:827
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
#define foreach_node(type, var, lst)
Definition: pg_list.h:496
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 list_make1_int(x1)
Definition: pg_list.h:227
#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
#define foreach_int(var, lst)
Definition: pg_list.h:470
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:308
void changeDependencyOnTablespace(Oid classId, Oid objectId, Oid newTablespaceId)
Definition: pg_shdepend.c:377
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:6457
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:3531
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:706
@ IS_NOT_NULL
Definition: primnodes.h:1924
@ COERCION_ASSIGNMENT
Definition: primnodes.h:685
@ COERCION_IMPLICIT
Definition: primnodes.h:684
tree context
Definition: radixtree.h:1829
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:4760
int errtableconstraint(Relation rel, const char *conname)
Definition: relcache.c:5999
int errtablecol(Relation rel, int attnum)
Definition: relcache.c:5962
List * RelationGetIndexPredicate(Relation relation)
Definition: relcache.c:5138
Bitmapset * RelationGetIndexAttrBitmap(Relation relation, IndexAttrBitmapKind attrKind)
Definition: relcache.c:5231
List * RelationGetFKeyList(Relation relation)
Definition: relcache.c:4651
void RelationSetNewRelfilenumber(Relation relation, char persistence)
Definition: relcache.c:3726
void RelationAssumeNewRelfilelocator(Relation relation)
Definition: relcache.c:3925
int errtable(Relation rel)
Definition: relcache.c:5945
List * RelationGetIndexExpressions(Relation relation)
Definition: relcache.c:5025
struct RelationData * Relation
Definition: relcache.h:27
@ INDEX_ATTR_BITMAP_KEY
Definition: relcache.h:61
@ INDEX_ATTR_BITMAP_PRIMARY_KEY
Definition: relcache.h:62
@ INDEX_ATTR_BITMAP_IDENTITY_KEY
Definition: relcache.h:63
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:471
bool RI_Initial_Check(Trigger *trigger, Relation fk_rel, Relation pk_rel)
Definition: ri_triggers.c:1443
void RI_PartitionRemove_Check(Trigger *trigger, Relation fk_rel, Relation pk_rel)
Definition: ri_triggers.c:1738
int RI_FKey_trigger_type(Oid tgfoid)
Definition: ri_triggers.c:3123
char * pg_get_constraintdef_command(Oid constraintId)
Definition: ruleutils.c:2168
const char * quote_identifier(const char *ident)
Definition: ruleutils.c:12623
char * pg_get_statisticsobjdef_string(Oid statextid)
Definition: ruleutils.c:1611
Datum pg_get_expr(PG_FUNCTION_ARGS)
Definition: ruleutils.c:2655
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
uint16 StrategyNumber
Definition: stratnum.h:22
#define RTOverlapStrategyNumber
Definition: stratnum.h:53
#define RTEqualStrategyNumber
Definition: stratnum.h:68
#define InvalidStrategy
Definition: stratnum.h:24
#define BTEqualStrategyNumber
Definition: stratnum.h:31
#define ERRCODE_DUPLICATE_OBJECT
Definition: streamutil.c:32
RoleSpec * newowner
Definition: parsenodes.h:2441
DropBehavior behavior
Definition: parsenodes.h:2444
AlterTableType subtype
Definition: parsenodes.h:2436
RangeVar * relation
Definition: parsenodes.h:2347
ObjectType objtype
Definition: parsenodes.h:2349
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:3268
ObjectType objtype
Definition: parsenodes.h:3266
Node * object
Definition: parsenodes.h:3267
char * ccname
Definition: tupdesc.h:30
bool ccvalid
Definition: tupdesc.h:32
char * ccbin
Definition: tupdesc.h:31
bool initdeferred
Definition: parsenodes.h:2742
ParseLoc location
Definition: parsenodes.h:2783
bool reset_default_tblspc
Definition: parsenodes.h:2764
List * keys
Definition: parsenodes.h:2754
List * pk_attrs
Definition: parsenodes.h:2772
List * fk_del_set_cols
Definition: parsenodes.h:2778
bool fk_with_period
Definition: parsenodes.h:2773
ConstrType contype
Definition: parsenodes.h:2739
Oid old_pktable_oid
Definition: parsenodes.h:2780
bool is_no_inherit
Definition: parsenodes.h:2745
char fk_upd_action
Definition: parsenodes.h:2776
List * old_conpfeqop
Definition: parsenodes.h:2779
char fk_matchtype
Definition: parsenodes.h:2775
bool pk_with_period
Definition: parsenodes.h:2774
char * cooked_expr
Definition: parsenodes.h:2748
bool initially_valid
Definition: parsenodes.h:2744
bool skip_validation
Definition: parsenodes.h:2743
bool deferrable
Definition: parsenodes.h:2741
Node * raw_expr
Definition: parsenodes.h:2746
char * conname
Definition: parsenodes.h:2740
RangeVar * pktable
Definition: parsenodes.h:2770
char fk_del_action
Definition: parsenodes.h:2777
List * fk_attrs
Definition: parsenodes.h:2771
Oid conoid
Definition: heap.h:39
char * name
Definition: heap.h:40
AttrNumber attnum
Definition: heap.h:41
bool skip_validation
Definition: heap.h:43
bool is_no_inherit
Definition: heap.h:46
int inhcount
Definition: heap.h:45
bool is_local
Definition: heap.h:44
ConstrType contype
Definition: heap.h:37
Node * expr
Definition: heap.h:42
List * tableElts
Definition: parsenodes.h:2659
OnCommitAction oncommit
Definition: parsenodes.h:2668
List * options
Definition: parsenodes.h:2667
bool if_not_exists
Definition: parsenodes.h:2671
List * inhRelations
Definition: parsenodes.h:2660
RangeVar * relation
Definition: parsenodes.h:2658
char * tablespacename
Definition: parsenodes.h:2669
List * constraints
Definition: parsenodes.h:2665
Node * whenClause
Definition: parsenodes.h:3027
List * transitionRels
Definition: parsenodes.h:3029
RangeVar * constrrel
Definition: parsenodes.h:3033
RangeVar * relation
Definition: parsenodes.h:3018
char * defname
Definition: parsenodes.h:815
bool missing_ok
Definition: parsenodes.h:3243
List * objects
Definition: parsenodes.h:3240
ObjectType removeType
Definition: parsenodes.h:3241
bool concurrent
Definition: parsenodes.h:3244
DropBehavior behavior
Definition: parsenodes.h:3242
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:720
List * args
Definition: primnodes.h:738
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
int ii_NumIndexKeyAttrs
Definition: execnodes.h:185
AttrNumber ii_IndexAttrNumbers[INDEX_MAX_KEYS]
Definition: execnodes.h:186
bool reset_default_tblspc
Definition: parsenodes.h:3388
List * indexParams
Definition: parsenodes.h:3366
char * idxname
Definition: parsenodes.h:3362
char * idxcomment
Definition: parsenodes.h:3372
bool primary
Definition: parsenodes.h:3380
Definition: lock.h:165
Definition: pg_list.h:54
AttrNumber attnum
Definition: tablecmds.c:234
bool is_generated
Definition: tablecmds.c:237
ExprState * exprstate
Definition: tablecmds.c:236
char * name
Definition: tablecmds.c:214
ConstrType contype
Definition: tablecmds.c:215
bool conwithperiod
Definition: tablecmds.c:218
Node * qual
Definition: tablecmds.c:220
ExprState * qualstate
Definition: tablecmds.c:221
Definition: nodes.h:129
NullTestType nulltesttype
Definition: primnodes.h:1931
ParseLoc location
Definition: primnodes.h:1934
Expr * arg
Definition: primnodes.h:1930
SubTransactionId creating_subid
Definition: tablecmds.c:124
SubTransactionId deleting_subid
Definition: tablecmds.c:125
OnCommitAction oncommit
Definition: tablecmds.c:115
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 * 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:2027
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:20942
BulkInsertState bistate
Definition: tablecmds.c:20941
ExprState * partqualstate
Definition: tablecmds.c:20939
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
AttrDefault * defval
Definition: tupdesc.h:39
bool has_generated_stored
Definition: tupdesc.h:45
struct AttrMissing * missing
Definition: tupdesc.h:41
ConstrCheck * check
Definition: tupdesc.h:40
uint16 num_defval
Definition: tupdesc.h:42
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:248
int nonexistent_code
Definition: tablecmds.c:246
const char * nonexistent_msg
Definition: tablecmds.c:247
const char * drophint_msg
Definition: tablecmds.c:250
const char * nota_msg
Definition: tablecmds.c:249
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:918
static void table_endscan(TableScanDesc scan)
Definition: tableam.h:1029
#define TABLE_INSERT_SKIP_FSM
Definition: tableam.h:260
static void table_finish_bulk_insert(Relation rel, int options)
Definition: tableam.h:1605
static void table_tuple_insert(Relation rel, TupleTableSlot *slot, CommandId cid, int options, struct BulkInsertStateData *bistate)
Definition: tableam.h:1412
static void table_relation_copy_data(Relation rel, const RelFileLocator *newrlocator)
Definition: tableam.h:1661
static bool table_scan_getnextslot(TableScanDesc sscan, ScanDirection direction, TupleTableSlot *slot)
Definition: tableam.h:1065
static AttrNumber renameatt_internal(Oid myrelid, const char *oldattname, const char *newattname, bool recurse, bool recursing, int expected_parents, DropBehavior behavior)
Definition: tablecmds.c:3777
void ResetRelRewrite(Oid myrelid)
Definition: tablecmds.c:4293
static void MergeAttributesIntoExisting(Relation child_rel, Relation parent_rel, bool ispartition)
Definition: tablecmds.c:16408
static void MarkInheritDetached(Relation child_rel, Relation parent_rel)
Definition: tablecmds.c:16778
static ObjectAddress ATExecAlterColumnGenericOptions(Relation rel, const char *colName, List *options, LOCKMODE lockmode)
Definition: tablecmds.c:14865
static void ATRewriteCatalogs(List **wqueue, LOCKMODE lockmode, AlterTableUtilityContext *context)
Definition: tablecmds.c:5204
static ObjectAddress ATExecAddInherit(Relation child_rel, RangeVar *parent, LOCKMODE lockmode)
Definition: tablecmds.c:16166
ObjectAddress RenameRelation(RenameStmt *stmt)
Definition: tablecmds.c:4139
static AlteredTableInfo * ATGetQueueEntry(List **wqueue, Relation rel)
Definition: tablecmds.c:6429
static void ATExecDropOf(Relation rel, LOCKMODE lockmode)
Definition: tablecmds.c:17297
static ColumnDef * MergeInheritedAttribute(List *inh_columns, int exist_attno, const ColumnDef *newdef)
Definition: tablecmds.c:3368
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, bool with_period)
Definition: tablecmds.c:10705
#define ATT_TABLE
Definition: tablecmds.c:326
static bool ConstraintImpliedByRelConstraint(Relation scanrel, List *testConstraint, List *provenConstraint)
Definition: tablecmds.c:19016
static const char * storage_name(char c)
Definition: tablecmds.c:2407
static ObjectAddress ATExecDropExpression(Relation rel, const char *colName, bool missing_ok, LOCKMODE lockmode)
Definition: tablecmds.c:8697
void AtEOSubXact_on_commit_actions(bool isCommit, SubTransactionId mySubid, SubTransactionId parentSubid)
Definition: tablecmds.c:18379
static void add_column_datatype_dependency(Oid relid, int32 attnum, Oid typid)
Definition: tablecmds.c:7527
static ObjectAddress ATExecColumnDefault(Relation rel, const char *colName, Node *newDefault, LOCKMODE lockmode)
Definition: tablecmds.c:8086
static void ATPostAlterTypeParse(Oid oldId, Oid oldRelId, Oid refRelId, char *cmd, List **wqueue, LOCKMODE lockmode, bool rewrite)
Definition: tablecmds.c:14532
static void ATExecSetTableSpace(Oid tableOid, Oid newTableSpace, LOCKMODE lockmode)
Definition: tablecmds.c:15758
static void drop_parent_dependency(Oid relid, Oid refclassid, Oid refobjid, DependencyType deptype)
Definition: tablecmds.c:17103
static void RemoveInheritance(Relation child_rel, Relation parent_rel, bool expect_detached)
Definition: tablecmds.c:16861
#define AT_NUM_PASSES
Definition: tablecmds.c:164
void PreCommit_on_commit_actions(void)
Definition: tablecmds.c:18240
struct SplitPartitionContext SplitPartitionContext
static ObjectAddress ATExecDropIdentity(Relation rel, const char *colName, bool missing_ok, LOCKMODE lockmode, bool recurse, bool recursing)
Definition: tablecmds.c:8424
static char GetAttributeCompression(Oid atttypid, const char *compression)
Definition: tablecmds.c:20863
static int findAttrByName(const char *attributeName, const List *columns)
Definition: tablecmds.c:3558
static int transformFkeyGetPrimaryKey(Relation pkrel, Oid *indexOid, List **attnamelist, int16 *attnums, Oid *atttypids, Oid *opclasses, bool *pk_has_without_overlaps)
Definition: tablecmds.c:12242
static void createPartitionTable(RangeVar *newPartName, RangeVar *modelRelName, AlterTableUtilityContext *context)
Definition: tablecmds.c:21192
static void RememberIndexForRebuilding(Oid indoid, AlteredTableInfo *tab)
Definition: tablecmds.c:14283
static bool ATColumnChangeRequiresRewrite(Node *expr, AttrNumber varattno)
Definition: tablecmds.c:13662
static char * ChooseForeignKeyConstraintNameAddition(List *colnames)
Definition: tablecmds.c:9686
static ObjectAddress ATExecValidateConstraint(List **wqueue, Relation rel, char *constrName, bool recurse, bool recursing, LOCKMODE lockmode)
Definition: tablecmds.c:12000
void AlterTable(AlterTableStmt *stmt, LOCKMODE lockmode, AlterTableUtilityContext *context)
Definition: tablecmds.c:4433
static void RememberStatisticsForRebuilding(Oid stxoid, AlteredTableInfo *tab)
Definition: tablecmds.c:14334
static CoercionPathType findFkeyCast(Oid targetTypeId, Oid sourceTypeId, Oid *funcid)
Definition: tablecmds.c:12495
static void add_column_collation_dependency(Oid relid, int32 attnum, Oid collid)
Definition: tablecmds.c:7545
static ObjectAddress ATExecDropNotNull(Relation rel, const char *colName, bool recurse, LOCKMODE lockmode)
Definition: tablecmds.c:7570
static Oid transformFkeyCheckAttrs(Relation pkrel, int numattrs, int16 *attnums, bool with_period, Oid *opclasses, bool *pk_has_without_overlaps)
Definition: tablecmds.c:12344
#define ATT_SEQUENCE
Definition: tablecmds.c:333
void RemoveRelations(DropStmt *drop)
Definition: tablecmds.c:1484
static void ATPrepSetTableSpace(AlteredTableInfo *tab, Relation rel, const char *tablespacename, LOCKMODE lockmode)
Definition: tablecmds.c:15525
static void ATTypedTableRecursion(List **wqueue, Relation rel, AlterTableCmd *cmd, LOCKMODE lockmode, AlterTableUtilityContext *context)
Definition: tablecmds.c:6762
static void RememberReplicaIdentityForRebuilding(Oid indoid, AlteredTableInfo *tab)
Definition: tablecmds.c:14212
static ObjectAddress ATExecSetNotNull(List **wqueue, Relation rel, char *constrname, char *colName, bool recurse, bool recursing, List **readyRels, LOCKMODE lockmode)
Definition: tablecmds.c:7816
static List * GetParentedForeignKeyRefs(Relation partition)
Definition: tablecmds.c:20761
void AlterRelationNamespaceInternal(Relation classRel, Oid relOid, Oid oldNspOid, Oid newNspOid, bool hasDependEntry, ObjectAddresses *objsMoved)
Definition: tablecmds.c:17981
static ObjectAddress ATExecAddConstraint(List **wqueue, AlteredTableInfo *tab, Relation rel, Constraint *newConstraint, bool recurse, bool is_readd, LOCKMODE lockmode)
Definition: tablecmds.c:9612
ObjectAddress renameatt(RenameStmt *stmt)
Definition: tablecmds.c:3942
void ATExecChangeOwner(Oid relationOid, Oid newOwnerId, bool recursing, LOCKMODE lockmode)
Definition: tablecmds.c:14982
static void RangeVarCallbackForAlterRelation(const RangeVar *rv, Oid relid, Oid oldrelid, void *arg)
Definition: tablecmds.c:18506
static ObjectAddress ATExecSetAttNotNull(List **wqueue, Relation rel, const char *colName, LOCKMODE lockmode)
Definition: tablecmds.c:8020
static void DropErrorMsgWrongType(const char *relname, char wrongkind, char rightkind)
Definition: tablecmds.c:1457
LOCKMODE AlterTableGetLockLevel(List *cmds)
Definition: tablecmds.c:4507
static int transformColumnNameList(Oid relId, List *colList, int16 *attnums, Oid *atttypids)
Definition: tablecmds.c:12189
static void verifyPartitionIndexNotNull(IndexInfo *iinfo, Relation partIdx)
Definition: tablecmds.c:20739
struct ForeignTruncateInfo ForeignTruncateInfo
static ObjectAddress ATExecDetachPartition(List **wqueue, AlteredTableInfo *tab, Relation rel, RangeVar *name, bool concurrent)
Definition: tablecmds.c:19839
static bool ATExecAlterConstrRecurse(Constraint *cmdcon, Relation conrel, Relation tgrel, Relation rel, HeapTuple contuple, List **otherrelids, LOCKMODE lockmode)
Definition: tablecmds.c:11849
static void AlterSeqNamespaces(Relation classRel, Relation rel, Oid oldNspOid, Oid newNspOid, ObjectAddresses *objsMoved, LOCKMODE lockmode)
Definition: tablecmds.c:18096
static void RangeVarCallbackForRenameAttribute(const RangeVar *rv, Oid relid, Oid oldrelid, void *arg)
Definition: tablecmds.c:3922
TupleDesc BuildDescForRelation(const List *columns)
Definition: tablecmds.c:1307
static void attachPartitionTable(List **wqueue, Relation rel, Relation attachrel, PartitionBoundSpec *bound)
Definition: tablecmds.c:19150
static void ATExecForceNoForceRowSecurity(Relation rel, bool force_rls)
Definition: tablecmds.c:17567
void AtEOXact_on_commit_actions(bool isCommit)
Definition: tablecmds.c:18347
static void checkFkeyPermissions(Relation rel, int16 *attnums, int natts)
Definition: tablecmds.c:12524
struct OnCommitItem OnCommitItem
void CheckTableNotInUse(Relation rel, const char *stmt)
Definition: tablecmds.c:4346
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, bool with_period)
Definition: tablecmds.c:10482
static void moveSplitTableRows(Relation rel, Relation splitRel, List *partlist, List *newPartRels, Oid defaultPartOid)
Definition: tablecmds.c:20996
static void ATExecEnableDisableTrigger(Relation rel, const char *trigname, char fires_when, bool skip_system, bool recurse, LOCKMODE lockmode)
Definition: tablecmds.c:16109
static void createForeignKeyActionTriggers(Relation rel, Oid refRelOid, Constraint *fkconstraint, Oid constraintOid, Oid indexOid, Oid parentDelTrigger, Oid parentUpdTrigger, Oid *deleteTrigOid, Oid *updateTrigOid)
Definition: tablecmds.c:12716
static void renameatt_check(Oid myrelid, Form_pg_class classform, bool recursing)
Definition: tablecmds.c:3728
static void RangeVarCallbackForAttachIndex(const RangeVar *rv, Oid relOid, Oid oldRelOid, void *arg)
Definition: tablecmds.c:20398
static void ATCheckPartitionsNotInUse(Relation rel, LOCKMODE lockmode)
Definition: tablecmds.c:6732
static void truncate_check_activity(Relation rel)
Definition: tablecmds.c:2384
static void validatePartitionedIndex(Relation partedIdx, Relation partedTbl)
Definition: tablecmds.c:20637
static ObjectAddress ATAddForeignKeyConstraint(List **wqueue, AlteredTableInfo *tab, Relation rel, Constraint *fkconstraint, bool recurse, bool recursing, LOCKMODE lockmode)
Definition: tablecmds.c:9886
static void ATExecSetAccessMethodNoStorage(Relation rel, Oid newAccessMethod)
Definition: tablecmds.c:15435
static void TryReuseIndex(Oid oldId, IndexStmt *stmt)
Definition: tablecmds.c:14796
static void GetForeignKeyCheckTriggers(Relation trigrel, Oid conoid, Oid confrelid, Oid conrelid, Oid *insertTriggerOid, Oid *updateTriggerOid)
Definition: tablecmds.c:11646
static void RememberClusterOnForRebuilding(Oid indoid, AlteredTableInfo *tab)
Definition: tablecmds.c:14227
static ObjectAddress ATExecSetOptions(Relation rel, const char *colName, Node *options, bool isReset, LOCKMODE lockmode)
Definition: tablecmds.c:8923
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:9156
static void CloneFkReferencing(List **wqueue, Relation parentRel, Relation partRel)
Definition: tablecmds.c:11170
static void SetIndexStorageProperties(Relation rel, Relation attrelation, AttrNumber attnum, bool setstorage, char newstorage, bool setcompression, char newcompression, LOCKMODE lockmode)
Definition: tablecmds.c:9002
static void ATController(AlterTableStmt *parsetree, Relation rel, List *cmds, bool recurse, LOCKMODE lockmode, AlterTableUtilityContext *context)
Definition: tablecmds.c:4778
bool CheckRelationTableSpaceMove(Relation rel, Oid newTableSpaceId)
Definition: tablecmds.c:3629
static void ATExecSetRowSecurity(Relation rel, bool rls)
Definition: tablecmds.c:17537
void find_composite_type_dependencies(Oid typeOid, Relation origRelation, const char *origTypeName)
Definition: tablecmds.c:6807
static void truncate_check_perms(Oid relid, Form_pg_class reltuple)
Definition: tablecmds.c:2366
static void truncate_check_rel(Oid relid, Form_pg_class reltuple)
Definition: tablecmds.c:2318
#define ATT_INDEX
Definition: tablecmds.c:329
static void change_owner_recurse_to_sequences(Oid relationOid, Oid newOwnerId, LOCKMODE lockmode)
Definition: tablecmds.c:15288
static void StoreCatalogInheritance1(Oid relationId, Oid parentOid, int32 seqNumber, Relation inhRelation, bool child_is_partition)
Definition: tablecmds.c:3513
static void RememberAllDependentForRebuilding(AlteredTableInfo *tab, AlterTableType subtype, Relation rel, AttrNumber attnum, const char *colName)
Definition: tablecmds.c:14026
static void ATPrepDropExpression(Relation rel, AlterTableCmd *cmd, bool recurse, bool recursing, LOCKMODE lockmode)
Definition: tablecmds.c:8651
static ObjectAddress ATExecCookedColumnDefault(Relation rel, AttrNumber attnum, Node *newDefault)
Definition: tablecmds.c:8172
static void moveMergedTablesRows(Relation rel, List *mergingPartitionsList, Relation newPartRel)
Definition: tablecmds.c:21376
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:3980
static void DropErrorMsgNonExistent(RangeVar *rel, char rightkind, bool missing_ok)
Definition: tablecmds.c:1409
static void ATPostAlterTypeCleanup(List **wqueue, AlteredTableInfo *tab, LOCKMODE lockmode)
Definition: tablecmds.c:14363
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:11442
static void ATExecMergePartitions(List **wqueue, AlteredTableInfo *tab, Relation rel, PartitionCmd *cmd, AlterTableUtilityContext *context)
Definition: tablecmds.c:21473
static AlterTableCmd * ATParseTransformCmd(List **wqueue, AlteredTableInfo *tab, Relation rel, AlterTableCmd *cmd, bool recurse, LOCKMODE lockmode, AlterTablePass cur_pass, AlterTableUtilityContext *context)
Definition: tablecmds.c:5630
void AlterTableNamespaceInternal(Relation rel, Oid oldNspOid, Oid nspOid, ObjectAddresses *objsMoved)
Definition: tablecmds.c:17947
static ObjectAddress ATAddCheckNNConstraint(List **wqueue, AlteredTableInfo *tab, Relation rel, Constraint *constr, bool recurse, bool recursing, bool is_readd, LOCKMODE lockmode)
Definition: tablecmds.c:9728
static void CloneFkReferenced(Relation parentRel, Relation partitionRel)
Definition: tablecmds.c:10964
static void MergeConstraintsIntoExisting(Relation child_rel, Relation parent_rel)
Definition: tablecmds.c:16538
static void ATPrepDropColumn(List **wqueue, Relation rel, bool recurse, bool recursing, AlterTableCmd *cmd, LOCKMODE lockmode, AlterTableUtilityContext *context)
Definition: tablecmds.c:9128
void SetRelationHasSubclass(Oid relationId, bool relhassubclass)
Definition: tablecmds.c:3588
static void MergeChildAttribute(List *inh_columns, int exist_attno, int newcol_attno, const ColumnDef *newdef)
Definition: tablecmds.c:3207
static void ATSimplePermissions(AlterTableType cmdtype, Relation rel, int allowed_targets)
Definition: tablecmds.c:6612
static List * MergeCheckConstraint(List *constraints, const char *name, Node *expr)
Definition: tablecmds.c:3141
static void ATExecSetRelOptions(Relation rel, List *defList, AlterTableType operation, LOCKMODE lockmode)
Definition: tablecmds.c:15555
static ObjectAddress ATExecSetIdentity(Relation rel, const char *colName, Node *def, LOCKMODE lockmode, bool recurse, bool recursing)
Definition: tablecmds.c:8307
ObjectAddress AlterTableNamespace(AlterObjectSchemaStmt *stmt, Oid *oldschema)
Definition: tablecmds.c:17876
static void RememberConstraintForRebuilding(Oid conoid, AlteredTableInfo *tab)
Definition: tablecmds.c:14243
void ExecuteTruncate(TruncateStmt *stmt)
Definition: tablecmds.c:1807
static ObjectAddress dropconstraint_internal(Relation rel, HeapTuple constraintTup, DropBehavior behavior, bool recurse, bool recursing, bool missing_ok, List **readyRels, LOCKMODE lockmode)
Definition: tablecmds.c:12940
static bool ATPrepChangePersistence(Relation rel, bool toLogged)
Definition: tablecmds.c:17757
static void relation_mark_replica_identity(Relation rel, char ri_type, Oid indexOid, bool is_internal)
Definition: tablecmds.c:17341
#define ATT_FOREIGN_TABLE
Definition: tablecmds.c:331
static ObjectAddress ATExecAlterConstraint(Relation rel, AlterTableCmd *cmd, bool recurse, bool recursing, LOCKMODE lockmode)
Definition: tablecmds.c:11712
static void ATPrepAddColumn(List **wqueue, Relation rel, bool recurse, bool recursing, bool is_view, AlterTableCmd *cmd, LOCKMODE lockmode, AlterTableUtilityContext *context)
Definition: tablecmds.c:7057
static void ComputePartitionAttrs(ParseState *pstate, Relation rel, List *partParams, AttrNumber *partattrs, List **partexprs, Oid *partopclass, Oid *partcollation, PartitionStrategy strategy)
Definition: tablecmds.c:18705
static void CloneRowTriggersToPartition(Relation parent, Relation partition)
Definition: tablecmds.c:19682
static void ATInheritAdjustNotNulls(Relation parent_rel, Relation child_rel, int inhcount)
Definition: tablecmds.c:17058
static void AttachPartitionEnsureIndexes(List **wqueue, Relation rel, Relation attachrel)
Definition: tablecmds.c:19478
static void StoreCatalogInheritance(Oid relationId, List *supers, bool child_is_partition)
Definition: tablecmds.c:3469
static void ATExecGenericOptions(Relation rel, List *options)
Definition: tablecmds.c:17596
static void TryReuseForeignKey(Oid oldId, Constraint *con)
Definition: tablecmds.c:14825
struct AlteredTableInfo AlteredTableInfo
static void validateFkOnDeleteSetColumns(int numfks, const int16 *fkattnums, int numfksetcols, const int16 *fksetcolsattnums, List *fksetcols)
Definition: tablecmds.c:10420
Oid AlterTableLookupRelation(AlterTableStmt *stmt, LOCKMODE lockmode)
Definition: tablecmds.c:4374
static void ATPrepAddPrimaryKey(List **wqueue, Relation rel, AlterTableCmd *cmd, LOCKMODE lockmode, AlterTableUtilityContext *context)
Definition: tablecmds.c:9352
struct NewConstraint NewConstraint
static ObjectAddress ATExecSetStatistics(Relation rel, const char *colName, int16 colNum, Node *newValue, LOCKMODE lockmode)
Definition: tablecmds.c:8788
static void ATSimpleRecursion(List **wqueue, Relation rel, AlterTableCmd *cmd, bool recurse, LOCKMODE lockmode, AlterTableUtilityContext *context)
Definition: tablecmds.c:6687
static void DetachPartitionFinalize(Relation rel, Relation partRel, bool concurrent, Oid defaultPartOid)
Definition: tablecmds.c:20010
static void RebuildConstraintComment(AlteredTableInfo *tab, AlterTablePass pass, Oid objid, Relation rel, List *domname, const char *conname)
Definition: tablecmds.c:14752
static void CloneForeignKeyConstraints(List **wqueue, Relation parentRel, Relation partitionRel)
Definition: tablecmds.c:10933
static bool check_for_column_name_collision(Relation rel, const char *colname, bool if_not_exists)
Definition: tablecmds.c:7474
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:7081
AlterTablePass
Definition: tablecmds.c:146
@ 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:150
@ AT_PASS_OLD_COL_ATTRS
Definition: tablecmds.c:152
@ AT_PASS_OLD_INDEX
Definition: tablecmds.c:153
@ AT_PASS_ALTER_TYPE
Definition: tablecmds.c:149
@ AT_PASS_ADD_INDEXCONSTR
Definition: tablecmds.c:158
@ AT_PASS_DROP
Definition: tablecmds.c:148
@ AT_PASS_MISC
Definition: tablecmds.c:161
@ AT_PASS_COL_ATTRS
Definition: tablecmds.c:157
@ AT_PASS_SET_EXPRESSION
Definition: tablecmds.c:151
@ AT_PASS_ADD_INDEX
Definition: tablecmds.c:159
@ AT_PASS_UNSET
Definition: tablecmds.c:147
static ObjectAddress ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel, AlterTableCmd *cmd, LOCKMODE lockmode)
Definition: tablecmds.c:13709
static void validateForeignKeyConstraint(char *conname, Relation rel, Relation pkrel, Oid pkindOid, Oid constraintOid, bool hasperiod)
Definition: tablecmds.c:12553
void SetRelationTableSpace(Relation rel, Oid newTableSpaceId, RelFileNumber newRelFilenumber)
Definition: tablecmds.c:3686
void remove_on_commit_action(Oid relid)
Definition: tablecmds.c:18217
static void DetachAddConstraintIfNeeded(List **wqueue, Relation partRel)
Definition: tablecmds.c:20284
static void ATExecDropCluster(Relation rel, LOCKMODE lockmode)
Definition: tablecmds.c:15389
static bool set_attnotnull(List **wqueue, Relation rel, AttrNumber attnum, bool recurse, LOCKMODE lockmode)
Definition: tablecmds.c:7732
#define ATT_PARTITIONED_INDEX
Definition: tablecmds.c:332
static void CreateInheritance(Relation child_rel, Relation parent_rel, bool ispartition)
Definition: tablecmds.c:16285
static const struct dropmsgstrings dropmsgstringarray[]
Definition: tablecmds.c:253
static ObjectAddress ATExecSetExpression(AlteredTableInfo *tab, Relation rel, const char *colName, Node *newExpr, LOCKMODE lockmode)
Definition: tablecmds.c:8538
ObjectAddress DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId, ObjectAddress *typaddress, const char *queryString)
Definition: tablecmds.c:700
static Oid CreateFKCheckTrigger(Oid myRelOid, Oid refRelOid, Constraint *fkconstraint, Oid constraintOid, Oid indexOid, Oid parentTrigOid, bool on_insert)
Definition: tablecmds.c:12653
static SplitPartitionContext * createSplitPartitionContext(Relation partRel)
Definition: tablecmds.c:20951
static void DropClonedTriggersFromPartition(Oid partitionId)
Definition: tablecmds.c:20325
static void QueuePartitionConstraintValidation(List **wqueue, Relation scanrel, List *partConstraint, bool validate_default)
Definition: tablecmds.c:19073
static ObjectAddress ATExecAddOf(Relation rel, const TypeName *ofTypename, LOCKMODE lockmode)
Definition: tablecmds.c:17155
static void RangeVarCallbackForDropRelation(const RangeVar *rel, Oid relOid, Oid oldRelOid, void *arg)
Definition: tablecmds.c:1648
void AlterTableInternal(Oid relid, List *cmds, bool recurse)
Definition: tablecmds.c:4462
static void GetForeignKeyActionTriggers(Relation trigrel, Oid conoid, Oid confrelid, Oid conrelid, Oid *deleteTriggerOid, Oid *updateTriggerOid)
Definition: tablecmds.c:11585
void check_of_type(HeapTuple typetuple)
Definition: tablecmds.c:7014
static ObjectAddress ATExecDropInherit(Relation rel, RangeVar *parent, LOCKMODE lockmode)
Definition: tablecmds.c:16724
static void ATDetachCheckNoForeignKeyRefs(Relation partition)
Definition: tablecmds.c:20814
static ObjectAddress ATExecAddIndexConstraint(AlteredTableInfo *tab, Relation rel, IndexStmt *stmt, LOCKMODE lockmode)
Definition: tablecmds.c:9520
#define ATT_VIEW
Definition: tablecmds.c:327
static void AlterIndexNamespaces(Relation classRel, Relation rel, Oid oldNspOid, Oid newNspOid, ObjectAddresses *objsMoved)
Definition: tablecmds.c:18051
static char * decompile_conbin(HeapTuple contup, TupleDesc tupdesc)
Definition: tablecmds.c:16354
static void ATExecCmd(List **wqueue, AlteredTableInfo *tab, AlterTableCmd *cmd, LOCKMODE lockmode, AlterTablePass cur_pass, AlterTableUtilityContext *context)
Definition: tablecmds.c:5278
static void ATExecReplicaIdentity(Relation rel, ReplicaIdentityStmt *stmt, LOCKMODE lockmode)
Definition: tablecmds.c:17429
static void createForeignKeyCheckTriggers(Oid myRelOid, Oid refRelOid, Constraint *fkconstraint, Oid constraintOid, Oid indexOid, Oid parentInsTrigger, Oid parentUpdTrigger, Oid *insertTrigOid, Oid *updateTrigOid)
Definition: tablecmds.c:12853
static void ATPrepAddInherit(Relation child_rel)
Definition: tablecmds.c:16144
static ObjectAddress ATExecDetachPartitionFinalize(Relation rel, RangeVar *name)
Definition: tablecmds.c:20249
static ObjectAddress ATExecSetStorage(Relation rel, const char *colName, Node *newValue, LOCKMODE lockmode)
Definition: tablecmds.c:9065
static ObjectAddress ATExecAttachPartition(List **wqueue, Relation rel, PartitionCmd *cmd, AlterTableUtilityContext *context)
Definition: tablecmds.c:19177
static List * find_typed_table_dependencies(Oid typeOid, const char *typeName, DropBehavior behavior)
Definition: tablecmds.c:6965
Oid AlterTableMoveAll(AlterTableMoveAllStmt *stmt)
Definition: tablecmds.c:15890
static ObjectAddress ATExecAddIdentity(Relation rel, const char *colName, Node *def, LOCKMODE lockmode, bool recurse, bool recursing)
Definition: tablecmds.c:8201
static void ATExecDropConstraint(Relation rel, const char *constrName, DropBehavior behavior, bool recurse, bool missing_ok, LOCKMODE lockmode)
Definition: tablecmds.c:12873
static ObjectAddress ATExecAddIndex(AlteredTableInfo *tab, Relation rel, IndexStmt *stmt, bool is_rebuild, LOCKMODE lockmode)
Definition: tablecmds.c:9436
static ObjectAddress ATExecSetCompression(Relation rel, const char *column, Node *newValue, LOCKMODE lockmode)
Definition: tablecmds.c:17677
static PartitionSpec * transformPartitionSpec(Relation rel, PartitionSpec *partspec)
Definition: tablecmds.c:18647
static void ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd, bool recurse, bool recursing, LOCKMODE lockmode, AlterTableUtilityContext *context)
Definition: tablecmds.c:4813
static void ATRewriteTable(AlteredTableInfo *tab, Oid OIDNewHeap, LOCKMODE lockmode)
Definition: tablecmds.c:6052
static void index_copy_data(Relation rel, RelFileLocator newrlocator)
Definition: tablecmds.c:16052
void RenameRelationInternal(Oid myrelid, const char *newrelname, bool is_internal, bool is_index)
Definition: tablecmds.c:4203
static void ATExecSetTableSpaceNoStorage(Relation rel, Oid newTableSpace)
Definition: tablecmds.c:15851
static void ATPrepAlterColumnType(List **wqueue, AlteredTableInfo *tab, Relation rel, bool recurse, bool recursing, AlterTableCmd *cmd, LOCKMODE lockmode, AlterTableUtilityContext *context)
Definition: tablecmds.c:13381
static void deleteSplitPartitionContext(SplitPartitionContext *pc, int ti_options)
Definition: tablecmds.c:20976
static void change_owner_fix_column_acls(Oid relationOid, Oid oldOwnerId, Oid newOwnerId)
Definition: tablecmds.c:15223
#define ATT_COMPOSITE_TYPE
Definition: tablecmds.c:330
static ObjectAddress ATExecAttachPartitionIdx(List **wqueue, Relation parentIdx, RangeVar *name)
Definition: tablecmds.c:20452
bool PartConstraintImpliedByRelConstraint(Relation scanrel, List *partConstraint)
Definition: tablecmds.c:18963
void RangeVarCallbackMaintainsTable(const RangeVar *relation, Oid relId, Oid oldRelId, void *arg)
Definition: tablecmds.c:18414
static void ATExecSplitPartition(List **wqueue, AlteredTableInfo *tab, Relation rel, PartitionCmd *cmd, AlterTableUtilityContext *context)
Definition: tablecmds.c:21242
static const char * alter_table_type_to_string(AlterTableType cmdtype)
Definition: tablecmds.c:6463
static List * on_commits
Definition: tablecmds.c:128
static bool constraints_equivalent(HeapTuple a, HeapTuple b, TupleDesc tupleDesc)
Definition: tablecmds.c:16379
static ObjectAddress ATExecAddStatistics(AlteredTableInfo *tab, Relation rel, CreateStatsStmt *stmt, bool is_rebuild, LOCKMODE lockmode)
Definition: tablecmds.c:9499
ObjectAddress RenameConstraint(RenameStmt *stmt)
Definition: tablecmds.c:4089
static void ATRewriteTables(AlterTableStmt *parsetree, List **wqueue, LOCKMODE lockmode, AlterTableUtilityContext *context)
Definition: tablecmds.c:5767
void register_on_commit_action(Oid relid, OnCommitAction action)
Definition: tablecmds.c:18181
static void RangeVarCallbackForTruncate(const RangeVar *relation, Oid relId, Oid oldRelId, void *arg)
Definition: tablecmds.c:18450
static ObjectAddress ATExecClusterOn(Relation rel, const char *indexName, LOCKMODE lockmode)
Definition: tablecmds.c:15357
static char GetAttributeStorage(Oid atttypid, const char *storagemode)
Definition: tablecmds.c:20901
void RangeVarCallbackOwnsRelation(const RangeVar *relation, Oid relId, Oid oldRelId, void *arg)
Definition: tablecmds.c:18474
#define ATT_MATVIEW
Definition: tablecmds.c:328
#define child_dependency_type(child_is_partition)
Definition: tablecmds.c:354
static void refuseDupeIndexAttach(Relation parentIdx, Relation partIdx, Relation partitionTbl)
Definition: tablecmds.c:20614
void ExecuteTruncateGuts(List *explicit_rels, List *relids, List *relids_logged, DropBehavior behavior, bool restart_seqs, bool run_as_table_owner)
Definition: tablecmds.c:1931
static List * MergeAttributes(List *columns, const List *supers, char relpersistence, bool is_partition, List **supconstr, List **supnotnulls)
Definition: tablecmds.c:2491
static void ATExecEnableDisableRule(Relation rel, const char *rulename, char fires_when, LOCKMODE lockmode)
Definition: tablecmds.c:16127
struct NewColumnValue NewColumnValue
static void ATPrepSetAccessMethod(AlteredTableInfo *tab, Relation rel, const char *amname)
Definition: tablecmds.c:15401
static bool NotNullImpliedByRelConstraints(Relation rel, Form_pg_attribute attr)
Definition: tablecmds.c:8049
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:1216
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:5974
void AfterTriggerEndQuery(EState *estate)
Definition: trigger.c:5038
void AfterTriggerBeginQuery(void)
Definition: trigger.c:5018
#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:3989
ObjectAddress AlterDomainAddConstraint(List *names, Node *newConstraint, ObjectAddress *constrAddr)
Definition: typecmds.c:2897
Oid AlterTypeNamespaceInternal(Oid typeOid, Oid nspOid, bool isImplicitArray, bool errorOnTableType, ObjectAddresses *objsMoved)
Definition: typecmds.c:4132
void checkDomainOwner(HeapTuple tup)
Definition: typecmds.c:3490
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:788
void CommandCounterIncrement(void)
Definition: xact.c:1097
void StartTransactionCommand(void)
Definition: xact.c:2995
void CommitTransactionCommand(void)
Definition: xact.c:3093
int MyXactFlags
Definition: xact.c:134
CommandId GetCurrentCommandId(bool used)
Definition: xact.c:826
#define XACT_FLAGS_ACCESSEDTEMPNAMESPACE
Definition: xact.h:102
#define XLogLogicalInfoActive()
Definition: xlog.h:124
#define XLOG_INCLUDE_ORIGIN
Definition: xlog.h:152
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