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_proc.h"
50 #include "catalog/pg_rewrite.h"
52 #include "catalog/pg_tablespace.h"
53 #include "catalog/pg_trigger.h"
54 #include "catalog/pg_type.h"
55 #include "catalog/storage.h"
56 #include "catalog/storage_xlog.h"
57 #include "catalog/toasting.h"
58 #include "commands/cluster.h"
59 #include "commands/comment.h"
60 #include "commands/defrem.h"
61 #include "commands/event_trigger.h"
62 #include "commands/sequence.h"
63 #include "commands/tablecmds.h"
64 #include "commands/tablespace.h"
65 #include "commands/trigger.h"
66 #include "commands/typecmds.h"
67 #include "commands/user.h"
68 #include "commands/vacuum.h"
69 #include "common/int.h"
70 #include "executor/executor.h"
71 #include "foreign/fdwapi.h"
72 #include "foreign/foreign.h"
73 #include "miscadmin.h"
74 #include "nodes/makefuncs.h"
75 #include "nodes/nodeFuncs.h"
76 #include "nodes/parsenodes.h"
77 #include "optimizer/optimizer.h"
78 #include "parser/parse_coerce.h"
79 #include "parser/parse_collate.h"
80 #include "parser/parse_expr.h"
81 #include "parser/parse_relation.h"
82 #include "parser/parse_type.h"
83 #include "parser/parse_utilcmd.h"
84 #include "parser/parser.h"
86 #include "partitioning/partdesc.h"
87 #include "pgstat.h"
88 #include "rewrite/rewriteDefine.h"
89 #include "rewrite/rewriteHandler.h"
90 #include "rewrite/rewriteManip.h"
91 #include "storage/bufmgr.h"
92 #include "storage/lmgr.h"
93 #include "storage/lock.h"
94 #include "storage/predicate.h"
95 #include "storage/smgr.h"
96 #include "tcop/utility.h"
97 #include "utils/acl.h"
98 #include "utils/builtins.h"
99 #include "utils/fmgroids.h"
100 #include "utils/inval.h"
101 #include "utils/lsyscache.h"
102 #include "utils/memutils.h"
103 #include "utils/partcache.h"
104 #include "utils/relcache.h"
105 #include "utils/ruleutils.h"
106 #include "utils/snapmgr.h"
107 #include "utils/syscache.h"
108 #include "utils/timestamp.h"
109 #include "utils/typcache.h"
110 #include "utils/usercontext.h"
111 
112 /*
113  * ON COMMIT action list
114  */
115 typedef struct OnCommitItem
116 {
117  Oid relid; /* relid of relation */
118  OnCommitAction oncommit; /* what to do at end of xact */
119 
120  /*
121  * If this entry was created during the current transaction,
122  * creating_subid is the ID of the creating subxact; if created in a prior
123  * transaction, creating_subid is zero. If deleted during the current
124  * transaction, deleting_subid is the ID of the deleting subxact; if no
125  * deletion request is pending, deleting_subid is zero.
126  */
130 
131 static List *on_commits = NIL;
132 
133 
134 /*
135  * State information for ALTER TABLE
136  *
137  * The pending-work queue for an ALTER TABLE is a List of AlteredTableInfo
138  * structs, one for each table modified by the operation (the named table
139  * plus any child tables that are affected). We save lists of subcommands
140  * to apply to this table (possibly modified by parse transformation steps);
141  * these lists will be executed in Phase 2. If a Phase 3 step is needed,
142  * necessary information is stored in the constraints and newvals lists.
143  *
144  * Phase 2 is divided into multiple passes; subcommands are executed in
145  * a pass determined by subcommand type.
146  */
147 
148 typedef enum AlterTablePass
149 {
150  AT_PASS_UNSET = -1, /* UNSET will cause ERROR */
151  AT_PASS_DROP, /* DROP (all flavors) */
152  AT_PASS_ALTER_TYPE, /* ALTER COLUMN TYPE */
153  AT_PASS_ADD_COL, /* ADD COLUMN */
154  AT_PASS_SET_EXPRESSION, /* ALTER SET EXPRESSION */
155  AT_PASS_OLD_INDEX, /* re-add existing indexes */
156  AT_PASS_OLD_CONSTR, /* re-add existing constraints */
157  /* We could support a RENAME COLUMN pass here, but not currently used */
158  AT_PASS_ADD_CONSTR, /* ADD constraints (initial examination) */
159  AT_PASS_COL_ATTRS, /* set column attributes, eg NOT NULL */
160  AT_PASS_ADD_INDEXCONSTR, /* ADD index-based constraints */
161  AT_PASS_ADD_INDEX, /* ADD indexes */
162  AT_PASS_ADD_OTHERCONSTR, /* ADD other constraints, defaults */
163  AT_PASS_MISC, /* other stuff */
165 
166 #define AT_NUM_PASSES (AT_PASS_MISC + 1)
167 
168 typedef struct AlteredTableInfo
169 {
170  /* Information saved before any work commences: */
171  Oid relid; /* Relation to work on */
172  char relkind; /* Its relkind */
173  TupleDesc oldDesc; /* Pre-modification tuple descriptor */
174 
175  /*
176  * Transiently set during Phase 2, normally set to NULL.
177  *
178  * ATRewriteCatalogs sets this when it starts, and closes when ATExecCmd
179  * returns control. This can be exploited by ATExecCmd subroutines to
180  * close/reopen across transaction boundaries.
181  */
183 
184  /* Information saved by Phase 1 for Phase 2: */
185  List *subcmds[AT_NUM_PASSES]; /* Lists of AlterTableCmd */
186  /* Information saved by Phases 1/2 for Phase 3: */
187  List *constraints; /* List of NewConstraint */
188  List *newvals; /* List of NewColumnValue */
189  List *afterStmts; /* List of utility command parsetrees */
190  bool verify_new_notnull; /* T if we should recheck NOT NULL */
191  int rewrite; /* Reason for forced rewrite, if any */
192  bool chgAccessMethod; /* T if SET ACCESS METHOD is used */
193  Oid newAccessMethod; /* new access method; 0 means no change,
194  * if above is true */
195  Oid newTableSpace; /* new tablespace; 0 means no change */
196  bool chgPersistence; /* T if SET LOGGED/UNLOGGED is used */
197  char newrelpersistence; /* if above is true */
198  Expr *partition_constraint; /* for attach partition validation */
199  /* true, if validating default due to some other attach/detach */
201  /* Objects to rebuild after completing ALTER TYPE operations */
202  List *changedConstraintOids; /* OIDs of constraints to rebuild */
203  List *changedConstraintDefs; /* string definitions of same */
204  List *changedIndexOids; /* OIDs of indexes to rebuild */
205  List *changedIndexDefs; /* string definitions of same */
206  char *replicaIdentityIndex; /* index to reset as REPLICA IDENTITY */
207  char *clusterOnIndex; /* index to use for CLUSTER */
208  List *changedStatisticsOids; /* OIDs of statistics to rebuild */
209  List *changedStatisticsDefs; /* string definitions of same */
211 
212 /* Struct describing one new constraint to check in Phase 3 scan */
213 /* Note: new not-null constraints are handled elsewhere */
214 typedef struct NewConstraint
215 {
216  char *name; /* Constraint name, or NULL if none */
217  ConstrType contype; /* CHECK or FOREIGN */
218  Oid refrelid; /* PK rel, if FOREIGN */
219  Oid refindid; /* OID of PK's index, if FOREIGN */
220  bool conwithperiod; /* Whether the new FOREIGN KEY uses PERIOD */
221  Oid conid; /* OID of pg_constraint entry, if FOREIGN */
222  Node *qual; /* Check expr or CONSTR_FOREIGN Constraint */
223  ExprState *qualstate; /* Execution state for CHECK expr */
225 
226 /*
227  * Struct describing one new column value that needs to be computed during
228  * Phase 3 copy (this could be either a new column with a non-null default, or
229  * a column that we're changing the type of). Columns without such an entry
230  * are just copied from the old table during ATRewriteTable. Note that the
231  * expr is an expression over *old* table values, except when is_generated
232  * is true; then it is an expression over columns of the *new* tuple.
233  */
234 typedef struct NewColumnValue
235 {
236  AttrNumber attnum; /* which column */
237  Expr *expr; /* expression to compute */
238  ExprState *exprstate; /* execution state */
239  bool is_generated; /* is it a GENERATED expression? */
241 
242 /*
243  * Error-reporting support for RemoveRelations
244  */
246 {
247  char kind;
249  const char *nonexistent_msg;
250  const char *skipping_msg;
251  const char *nota_msg;
252  const char *drophint_msg;
253 };
254 
255 static const struct dropmsgstrings dropmsgstringarray[] = {
256  {RELKIND_RELATION,
258  gettext_noop("table \"%s\" does not exist"),
259  gettext_noop("table \"%s\" does not exist, skipping"),
260  gettext_noop("\"%s\" is not a table"),
261  gettext_noop("Use DROP TABLE to remove a table.")},
262  {RELKIND_SEQUENCE,
264  gettext_noop("sequence \"%s\" does not exist"),
265  gettext_noop("sequence \"%s\" does not exist, skipping"),
266  gettext_noop("\"%s\" is not a sequence"),
267  gettext_noop("Use DROP SEQUENCE to remove a sequence.")},
268  {RELKIND_VIEW,
270  gettext_noop("view \"%s\" does not exist"),
271  gettext_noop("view \"%s\" does not exist, skipping"),
272  gettext_noop("\"%s\" is not a view"),
273  gettext_noop("Use DROP VIEW to remove a view.")},
274  {RELKIND_MATVIEW,
276  gettext_noop("materialized view \"%s\" does not exist"),
277  gettext_noop("materialized view \"%s\" does not exist, skipping"),
278  gettext_noop("\"%s\" is not a materialized view"),
279  gettext_noop("Use DROP MATERIALIZED VIEW to remove a materialized view.")},
280  {RELKIND_INDEX,
281  ERRCODE_UNDEFINED_OBJECT,
282  gettext_noop("index \"%s\" does not exist"),
283  gettext_noop("index \"%s\" does not exist, skipping"),
284  gettext_noop("\"%s\" is not an index"),
285  gettext_noop("Use DROP INDEX to remove an index.")},
286  {RELKIND_COMPOSITE_TYPE,
287  ERRCODE_UNDEFINED_OBJECT,
288  gettext_noop("type \"%s\" does not exist"),
289  gettext_noop("type \"%s\" does not exist, skipping"),
290  gettext_noop("\"%s\" is not a type"),
291  gettext_noop("Use DROP TYPE to remove a type.")},
292  {RELKIND_FOREIGN_TABLE,
293  ERRCODE_UNDEFINED_OBJECT,
294  gettext_noop("foreign table \"%s\" does not exist"),
295  gettext_noop("foreign table \"%s\" does not exist, skipping"),
296  gettext_noop("\"%s\" is not a foreign table"),
297  gettext_noop("Use DROP FOREIGN TABLE to remove a foreign table.")},
298  {RELKIND_PARTITIONED_TABLE,
300  gettext_noop("table \"%s\" does not exist"),
301  gettext_noop("table \"%s\" does not exist, skipping"),
302  gettext_noop("\"%s\" is not a table"),
303  gettext_noop("Use DROP TABLE to remove a table.")},
304  {RELKIND_PARTITIONED_INDEX,
305  ERRCODE_UNDEFINED_OBJECT,
306  gettext_noop("index \"%s\" does not exist"),
307  gettext_noop("index \"%s\" does not exist, skipping"),
308  gettext_noop("\"%s\" is not an index"),
309  gettext_noop("Use DROP INDEX to remove an index.")},
310  {'\0', 0, NULL, NULL, NULL, NULL}
311 };
312 
313 /* communication between RemoveRelations and RangeVarCallbackForDropRelation */
315 {
316  /* These fields are set by RemoveRelations: */
319  /* These fields are state to track which subsidiary locks are held: */
322  /* These fields are passed back by RangeVarCallbackForDropRelation: */
325 };
326 
327 /* Alter table target-type flags for ATSimplePermissions */
328 #define ATT_TABLE 0x0001
329 #define ATT_VIEW 0x0002
330 #define ATT_MATVIEW 0x0004
331 #define ATT_INDEX 0x0008
332 #define ATT_COMPOSITE_TYPE 0x0010
333 #define ATT_FOREIGN_TABLE 0x0020
334 #define ATT_PARTITIONED_INDEX 0x0040
335 #define ATT_SEQUENCE 0x0080
336 #define ATT_PARTITIONED_TABLE 0x0100
337 
338 /*
339  * ForeignTruncateInfo
340  *
341  * Information related to truncation of foreign tables. This is used for
342  * the elements in a hash table. It uses the server OID as lookup key,
343  * and includes a per-server list of all foreign tables involved in the
344  * truncation.
345  */
346 typedef struct ForeignTruncateInfo
347 {
351 
352 /* Partial or complete FK creation in addFkConstraint() */
354 {
359 
360 /*
361  * Partition tables are expected to be dropped when the parent partitioned
362  * table gets dropped. Hence for partitioning we use AUTO dependency.
363  * Otherwise, for regular inheritance use NORMAL dependency.
364  */
365 #define child_dependency_type(child_is_partition) \
366  ((child_is_partition) ? DEPENDENCY_AUTO : DEPENDENCY_NORMAL)
367 
368 static void truncate_check_rel(Oid relid, Form_pg_class reltuple);
369 static void truncate_check_perms(Oid relid, Form_pg_class reltuple);
370 static void truncate_check_activity(Relation rel);
371 static void RangeVarCallbackForTruncate(const RangeVar *relation,
372  Oid relId, Oid oldRelId, void *arg);
373 static List *MergeAttributes(List *columns, const List *supers, char relpersistence,
374  bool is_partition, List **supconstr);
375 static List *MergeCheckConstraint(List *constraints, const char *name, Node *expr);
376 static void MergeChildAttribute(List *inh_columns, int exist_attno, int newcol_attno, const ColumnDef *newdef);
377 static ColumnDef *MergeInheritedAttribute(List *inh_columns, int exist_attno, const ColumnDef *newdef);
378 static void MergeAttributesIntoExisting(Relation child_rel, Relation parent_rel, bool ispartition);
379 static void MergeConstraintsIntoExisting(Relation child_rel, Relation parent_rel);
380 static void StoreCatalogInheritance(Oid relationId, List *supers,
381  bool child_is_partition);
382 static void StoreCatalogInheritance1(Oid relationId, Oid parentOid,
383  int32 seqNumber, Relation inhRelation,
384  bool child_is_partition);
385 static int findAttrByName(const char *attributeName, const List *columns);
386 static void AlterIndexNamespaces(Relation classRel, Relation rel,
387  Oid oldNspOid, Oid newNspOid, ObjectAddresses *objsMoved);
388 static void AlterSeqNamespaces(Relation classRel, Relation rel,
389  Oid oldNspOid, Oid newNspOid, ObjectAddresses *objsMoved,
390  LOCKMODE lockmode);
392  bool recurse, bool recursing, LOCKMODE lockmode);
393 static bool ATExecAlterConstrRecurse(Constraint *cmdcon, Relation conrel, Relation tgrel,
394  Relation rel, HeapTuple contuple, List **otherrelids,
395  LOCKMODE lockmode);
397  Relation rel, char *constrName,
398  bool recurse, bool recursing, LOCKMODE lockmode);
399 static int transformColumnNameList(Oid relId, List *colList,
400  int16 *attnums, Oid *atttypids);
401 static int transformFkeyGetPrimaryKey(Relation pkrel, Oid *indexOid,
402  List **attnamelist,
403  int16 *attnums, Oid *atttypids,
404  Oid *opclasses, bool *pk_has_without_overlaps);
406  int numattrs, int16 *attnums,
407  bool with_period, Oid *opclasses,
408  bool *pk_has_without_overlaps);
409 static void checkFkeyPermissions(Relation rel, int16 *attnums, int natts);
410 static CoercionPathType findFkeyCast(Oid targetTypeId, Oid sourceTypeId,
411  Oid *funcid);
412 static void validateForeignKeyConstraint(char *conname,
413  Relation rel, Relation pkrel,
414  Oid pkindOid, Oid constraintOid, bool hasperiod);
415 static void CheckAlterTableIsSafe(Relation rel);
416 static void ATController(AlterTableStmt *parsetree,
417  Relation rel, List *cmds, bool recurse, LOCKMODE lockmode,
419 static void ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd,
420  bool recurse, bool recursing, LOCKMODE lockmode,
422 static void ATRewriteCatalogs(List **wqueue, LOCKMODE lockmode,
424 static void ATExecCmd(List **wqueue, AlteredTableInfo *tab,
425  AlterTableCmd *cmd, LOCKMODE lockmode, AlterTablePass cur_pass,
428  Relation rel, AlterTableCmd *cmd,
429  bool recurse, LOCKMODE lockmode,
430  AlterTablePass cur_pass,
432 static void ATRewriteTables(AlterTableStmt *parsetree,
433  List **wqueue, LOCKMODE lockmode,
435 static void ATRewriteTable(AlteredTableInfo *tab, Oid OIDNewHeap, LOCKMODE lockmode);
436 static AlteredTableInfo *ATGetQueueEntry(List **wqueue, Relation rel);
437 static void ATSimplePermissions(AlterTableType cmdtype, Relation rel, int allowed_targets);
438 static void ATSimpleRecursion(List **wqueue, Relation rel,
439  AlterTableCmd *cmd, bool recurse, LOCKMODE lockmode,
441 static void ATCheckPartitionsNotInUse(Relation rel, LOCKMODE lockmode);
442 static void ATTypedTableRecursion(List **wqueue, Relation rel, AlterTableCmd *cmd,
443  LOCKMODE lockmode,
445 static List *find_typed_table_dependencies(Oid typeOid, const char *typeName,
446  DropBehavior behavior);
447 static void ATPrepAddColumn(List **wqueue, Relation rel, bool recurse, bool recursing,
448  bool is_view, AlterTableCmd *cmd, LOCKMODE lockmode,
450 static ObjectAddress ATExecAddColumn(List **wqueue, AlteredTableInfo *tab,
451  Relation rel, AlterTableCmd **cmd,
452  bool recurse, bool recursing,
453  LOCKMODE lockmode, AlterTablePass cur_pass,
455 static bool check_for_column_name_collision(Relation rel, const char *colname,
456  bool if_not_exists);
457 static void add_column_datatype_dependency(Oid relid, int32 attnum, Oid typid);
459 static ObjectAddress ATExecDropNotNull(Relation rel, const char *colName, LOCKMODE lockmode);
460 static void ATPrepSetNotNull(List **wqueue, Relation rel,
461  AlterTableCmd *cmd, bool recurse, bool recursing,
462  LOCKMODE lockmode,
465  const char *colName, LOCKMODE lockmode);
466 static void ATExecCheckNotNull(AlteredTableInfo *tab, Relation rel,
467  const char *colName, LOCKMODE lockmode);
469 static bool ConstraintImpliedByRelConstraint(Relation scanrel,
470  List *testConstraint, List *provenConstraint);
471 static ObjectAddress ATExecColumnDefault(Relation rel, const char *colName,
472  Node *newDefault, LOCKMODE lockmode);
474  Node *newDefault);
475 static ObjectAddress ATExecAddIdentity(Relation rel, const char *colName,
476  Node *def, LOCKMODE lockmode, bool recurse, bool recursing);
477 static ObjectAddress ATExecSetIdentity(Relation rel, const char *colName,
478  Node *def, LOCKMODE lockmode, bool recurse, bool recursing);
479 static ObjectAddress ATExecDropIdentity(Relation rel, const char *colName, bool missing_ok, LOCKMODE lockmode,
480  bool recurse, bool recursing);
481 static ObjectAddress ATExecSetExpression(AlteredTableInfo *tab, Relation rel, const char *colName,
482  Node *newExpr, LOCKMODE lockmode);
483 static void ATPrepDropExpression(Relation rel, AlterTableCmd *cmd, bool recurse, bool recursing, LOCKMODE lockmode);
484 static ObjectAddress ATExecDropExpression(Relation rel, const char *colName, bool missing_ok, LOCKMODE lockmode);
485 static ObjectAddress ATExecSetStatistics(Relation rel, const char *colName, int16 colNum,
486  Node *newValue, LOCKMODE lockmode);
487 static ObjectAddress ATExecSetOptions(Relation rel, const char *colName,
488  Node *options, bool isReset, LOCKMODE lockmode);
489 static ObjectAddress ATExecSetStorage(Relation rel, const char *colName,
490  Node *newValue, LOCKMODE lockmode);
491 static void ATPrepDropColumn(List **wqueue, Relation rel, bool recurse, bool recursing,
492  AlterTableCmd *cmd, LOCKMODE lockmode,
494 static ObjectAddress ATExecDropColumn(List **wqueue, Relation rel, const char *colName,
495  DropBehavior behavior,
496  bool recurse, bool recursing,
497  bool missing_ok, LOCKMODE lockmode,
498  ObjectAddresses *addrs);
500  IndexStmt *stmt, bool is_rebuild, LOCKMODE lockmode);
502  CreateStatsStmt *stmt, bool is_rebuild, LOCKMODE lockmode);
503 static ObjectAddress ATExecAddConstraint(List **wqueue,
504  AlteredTableInfo *tab, Relation rel,
505  Constraint *newConstraint, bool recurse, bool is_readd,
506  LOCKMODE lockmode);
507 static char *ChooseForeignKeyConstraintNameAddition(List *colnames);
509  IndexStmt *stmt, LOCKMODE lockmode);
510 static ObjectAddress ATAddCheckConstraint(List **wqueue,
511  AlteredTableInfo *tab, Relation rel,
512  Constraint *constr,
513  bool recurse, bool recursing, bool is_readd,
514  LOCKMODE lockmode);
516  Relation rel, Constraint *fkconstraint,
517  bool recurse, bool recursing,
518  LOCKMODE lockmode);
519 static void validateFkOnDeleteSetColumns(int numfks, const int16 *fkattnums,
520  int numfksetcols, const int16 *fksetcolsattnums,
521  List *fksetcols);
523  char *constraintname,
524  Constraint *fkconstraint, Relation rel,
525  Relation pkrel, Oid indexOid,
526  Oid parentConstr,
527  int numfks, int16 *pkattnum, int16 *fkattnum,
528  Oid *pfeqoperators, Oid *ppeqoperators,
529  Oid *ffeqoperators, int numfkdelsetcols,
530  int16 *fkdelsetcols, bool is_internal,
531  bool with_period);
532 static void addFkRecurseReferenced(Constraint *fkconstraint,
533  Relation rel, Relation pkrel, Oid indexOid, Oid parentConstr,
534  int numfks, int16 *pkattnum, int16 *fkattnum,
535  Oid *pfeqoperators, Oid *ppeqoperators, Oid *ffeqoperators,
536  int numfkdelsetcols, int16 *fkdelsetcols,
537  bool old_check_ok,
538  Oid parentDelTrigger, Oid parentUpdTrigger,
539  bool with_period);
540 static void addFkRecurseReferencing(List **wqueue, Constraint *fkconstraint,
541  Relation rel, Relation pkrel, Oid indexOid, Oid parentConstr,
542  int numfks, int16 *pkattnum, int16 *fkattnum,
543  Oid *pfeqoperators, Oid *ppeqoperators, Oid *ffeqoperators,
544  int numfkdelsetcols, int16 *fkdelsetcols,
545  bool old_check_ok, LOCKMODE lockmode,
546  Oid parentInsTrigger, Oid parentUpdTrigger,
547  bool with_period);
548 static void CloneForeignKeyConstraints(List **wqueue, Relation parentRel,
549  Relation partitionRel);
550 static void CloneFkReferenced(Relation parentRel, Relation partitionRel);
551 static void CloneFkReferencing(List **wqueue, Relation parentRel,
552  Relation partRel);
553 static void createForeignKeyCheckTriggers(Oid myRelOid, Oid refRelOid,
554  Constraint *fkconstraint, Oid constraintOid,
555  Oid indexOid,
556  Oid parentInsTrigger, Oid parentUpdTrigger,
557  Oid *insertTrigOid, Oid *updateTrigOid);
558 static void createForeignKeyActionTriggers(Relation rel, Oid refRelOid,
559  Constraint *fkconstraint, Oid constraintOid,
560  Oid indexOid,
561  Oid parentDelTrigger, Oid parentUpdTrigger,
562  Oid *deleteTrigOid, Oid *updateTrigOid);
564  Oid partRelid,
565  Oid parentConstrOid, int numfks,
566  AttrNumber *mapped_conkey, AttrNumber *confkey,
567  Oid *conpfeqop,
568  Oid parentInsTrigger,
569  Oid parentUpdTrigger,
570  Relation trigrel);
571 static void GetForeignKeyActionTriggers(Relation trigrel,
572  Oid conoid, Oid confrelid, Oid conrelid,
573  Oid *deleteTriggerOid,
574  Oid *updateTriggerOid);
575 static void GetForeignKeyCheckTriggers(Relation trigrel,
576  Oid conoid, Oid confrelid, Oid conrelid,
577  Oid *insertTriggerOid,
578  Oid *updateTriggerOid);
579 static void ATExecDropConstraint(Relation rel, const char *constrName,
580  DropBehavior behavior,
581  bool recurse, bool recursing,
582  bool missing_ok, LOCKMODE lockmode);
583 static void ATPrepAlterColumnType(List **wqueue,
584  AlteredTableInfo *tab, Relation rel,
585  bool recurse, bool recursing,
586  AlterTableCmd *cmd, LOCKMODE lockmode,
588 static bool ATColumnChangeRequiresRewrite(Node *expr, AttrNumber varattno);
590  AlterTableCmd *cmd, LOCKMODE lockmode);
592  Relation rel, AttrNumber attnum, const char *colName);
593 static void RememberConstraintForRebuilding(Oid conoid, AlteredTableInfo *tab);
594 static void RememberIndexForRebuilding(Oid indoid, AlteredTableInfo *tab);
595 static void RememberStatisticsForRebuilding(Oid stxoid, AlteredTableInfo *tab);
596 static void ATPostAlterTypeCleanup(List **wqueue, AlteredTableInfo *tab,
597  LOCKMODE lockmode);
598 static void ATPostAlterTypeParse(Oid oldId, Oid oldRelId, Oid refRelId,
599  char *cmd, List **wqueue, LOCKMODE lockmode,
600  bool rewrite);
602  Oid objid, Relation rel, List *domname,
603  const char *conname);
604 static void TryReuseIndex(Oid oldId, IndexStmt *stmt);
605 static void TryReuseForeignKey(Oid oldId, Constraint *con);
606 static ObjectAddress ATExecAlterColumnGenericOptions(Relation rel, const char *colName,
607  List *options, LOCKMODE lockmode);
608 static void change_owner_fix_column_acls(Oid relationOid,
609  Oid oldOwnerId, Oid newOwnerId);
610 static void change_owner_recurse_to_sequences(Oid relationOid,
611  Oid newOwnerId, LOCKMODE lockmode);
612 static ObjectAddress ATExecClusterOn(Relation rel, const char *indexName,
613  LOCKMODE lockmode);
614 static void ATExecDropCluster(Relation rel, LOCKMODE lockmode);
615 static void ATPrepSetAccessMethod(AlteredTableInfo *tab, Relation rel, const char *amname);
616 static void ATExecSetAccessMethodNoStorage(Relation rel, Oid newAccessMethodId);
618  bool toLogged);
619 static void ATPrepSetTableSpace(AlteredTableInfo *tab, Relation rel,
620  const char *tablespacename, LOCKMODE lockmode);
621 static void ATExecSetTableSpace(Oid tableOid, Oid newTableSpace, LOCKMODE lockmode);
622 static void ATExecSetTableSpaceNoStorage(Relation rel, Oid newTableSpace);
623 static void ATExecSetRelOptions(Relation rel, List *defList,
624  AlterTableType operation,
625  LOCKMODE lockmode);
626 static void ATExecEnableDisableTrigger(Relation rel, const char *trigname,
627  char fires_when, bool skip_system, bool recurse,
628  LOCKMODE lockmode);
629 static void ATExecEnableDisableRule(Relation rel, const char *rulename,
630  char fires_when, LOCKMODE lockmode);
631 static void ATPrepAddInherit(Relation child_rel);
632 static ObjectAddress ATExecAddInherit(Relation child_rel, RangeVar *parent, LOCKMODE lockmode);
633 static ObjectAddress ATExecDropInherit(Relation rel, RangeVar *parent, LOCKMODE lockmode);
634 static void drop_parent_dependency(Oid relid, Oid refclassid, Oid refobjid,
635  DependencyType deptype);
636 static ObjectAddress ATExecAddOf(Relation rel, const TypeName *ofTypename, LOCKMODE lockmode);
637 static void ATExecDropOf(Relation rel, LOCKMODE lockmode);
638 static void ATExecReplicaIdentity(Relation rel, ReplicaIdentityStmt *stmt, LOCKMODE lockmode);
639 static void ATExecGenericOptions(Relation rel, List *options);
640 static void ATExecSetRowSecurity(Relation rel, bool rls);
641 static void ATExecForceNoForceRowSecurity(Relation rel, bool force_rls);
643  const char *column, Node *newValue, LOCKMODE lockmode);
644 
645 static void index_copy_data(Relation rel, RelFileLocator newrlocator);
646 static const char *storage_name(char c);
647 
648 static void RangeVarCallbackForDropRelation(const RangeVar *rel, Oid relOid,
649  Oid oldRelOid, void *arg);
650 static void RangeVarCallbackForAlterRelation(const RangeVar *rv, Oid relid,
651  Oid oldrelid, void *arg);
653 static void ComputePartitionAttrs(ParseState *pstate, Relation rel, List *partParams, AttrNumber *partattrs,
654  List **partexprs, Oid *partopclass, Oid *partcollation,
655  PartitionStrategy strategy);
656 static void CreateInheritance(Relation child_rel, Relation parent_rel, bool ispartition);
657 static void RemoveInheritance(Relation child_rel, Relation parent_rel,
658  bool expect_detached);
659 static ObjectAddress ATExecAttachPartition(List **wqueue, Relation rel,
660  PartitionCmd *cmd,
662 static void AttachPartitionEnsureIndexes(List **wqueue, Relation rel, Relation attachrel);
663 static void QueuePartitionConstraintValidation(List **wqueue, Relation scanrel,
664  List *partConstraint,
665  bool validate_default);
666 static void CloneRowTriggersToPartition(Relation parent, Relation partition);
667 static void DetachAddConstraintIfNeeded(List **wqueue, Relation partRel);
668 static void DropClonedTriggersFromPartition(Oid partitionId);
670  Relation rel, RangeVar *name,
671  bool concurrent);
672 static void DetachPartitionFinalize(Relation rel, Relation partRel,
673  bool concurrent, Oid defaultPartOid);
675 static ObjectAddress ATExecAttachPartitionIdx(List **wqueue, Relation parentIdx,
676  RangeVar *name);
677 static void validatePartitionedIndex(Relation partedIdx, Relation partedTbl);
678 static void refuseDupeIndexAttach(Relation parentIdx, Relation partIdx,
679  Relation partitionTbl);
680 static List *GetParentedForeignKeyRefs(Relation partition);
681 static void ATDetachCheckNoForeignKeyRefs(Relation partition);
682 static char GetAttributeCompression(Oid atttypid, const char *compression);
683 static char GetAttributeStorage(Oid atttypid, const char *storagemode);
684 
685 
686 /* ----------------------------------------------------------------
687  * DefineRelation
688  * Creates a new relation.
689  *
690  * stmt carries parsetree information from an ordinary CREATE TABLE statement.
691  * The other arguments are used to extend the behavior for other cases:
692  * relkind: relkind to assign to the new relation
693  * ownerId: if not InvalidOid, use this as the new relation's owner.
694  * typaddress: if not null, it's set to the pg_type entry's address.
695  * queryString: for error reporting
696  *
697  * Note that permissions checks are done against current user regardless of
698  * ownerId. A nonzero ownerId is used when someone is creating a relation
699  * "on behalf of" someone else, so we still want to see that the current user
700  * has permissions to do it.
701  *
702  * If successful, returns the address of the new relation.
703  * ----------------------------------------------------------------
704  */
706 DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId,
707  ObjectAddress *typaddress, const char *queryString)
708 {
709  char relname[NAMEDATALEN];
710  Oid namespaceId;
711  Oid relationId;
712  Oid tablespaceId;
713  Relation rel;
715  List *inheritOids;
716  List *old_constraints;
717  List *rawDefaults;
718  List *cookedDefaults;
719  Datum reloptions;
720  ListCell *listptr;
722  bool partitioned;
723  const char *const validnsps[] = HEAP_RELOPT_NAMESPACES;
724  Oid ofTypeId;
725  ObjectAddress address;
726  LOCKMODE parentLockmode;
727  Oid accessMethodId = InvalidOid;
728 
729  /*
730  * Truncate relname to appropriate length (probably a waste of time, as
731  * parser should have done this already).
732  */
733  strlcpy(relname, stmt->relation->relname, NAMEDATALEN);
734 
735  /*
736  * Check consistency of arguments
737  */
738  if (stmt->oncommit != ONCOMMIT_NOOP
739  && stmt->relation->relpersistence != RELPERSISTENCE_TEMP)
740  ereport(ERROR,
741  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
742  errmsg("ON COMMIT can only be used on temporary tables")));
743 
744  if (stmt->partspec != NULL)
745  {
746  if (relkind != RELKIND_RELATION)
747  elog(ERROR, "unexpected relkind: %d", (int) relkind);
748 
749  relkind = RELKIND_PARTITIONED_TABLE;
750  partitioned = true;
751  }
752  else
753  partitioned = false;
754 
755  if (relkind == RELKIND_PARTITIONED_TABLE &&
756  stmt->relation->relpersistence == RELPERSISTENCE_UNLOGGED)
757  ereport(ERROR,
758  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
759  errmsg("partitioned tables cannot be unlogged")));
760 
761  /*
762  * Look up the namespace in which we are supposed to create the relation,
763  * check we have permission to create there, lock it against concurrent
764  * drop, and mark stmt->relation as RELPERSISTENCE_TEMP if a temporary
765  * namespace is selected.
766  */
767  namespaceId =
769 
770  /*
771  * Security check: disallow creating temp tables from security-restricted
772  * code. This is needed because calling code might not expect untrusted
773  * tables to appear in pg_temp at the front of its search path.
774  */
775  if (stmt->relation->relpersistence == RELPERSISTENCE_TEMP
777  ereport(ERROR,
778  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
779  errmsg("cannot create temporary table within security-restricted operation")));
780 
781  /*
782  * Determine the lockmode to use when scanning parents. A self-exclusive
783  * lock is needed here.
784  *
785  * For regular inheritance, if two backends attempt to add children to the
786  * same parent simultaneously, and that parent has no pre-existing
787  * children, then both will attempt to update the parent's relhassubclass
788  * field, leading to a "tuple concurrently updated" error. Also, this
789  * interlocks against a concurrent ANALYZE on the parent table, which
790  * might otherwise be attempting to clear the parent's relhassubclass
791  * field, if its previous children were recently dropped.
792  *
793  * If the child table is a partition, then we instead grab an exclusive
794  * lock on the parent because its partition descriptor will be changed by
795  * addition of the new partition.
796  */
797  parentLockmode = (stmt->partbound != NULL ? AccessExclusiveLock :
799 
800  /* Determine the list of OIDs of the parents. */
801  inheritOids = NIL;
802  foreach(listptr, stmt->inhRelations)
803  {
804  RangeVar *rv = (RangeVar *) lfirst(listptr);
805  Oid parentOid;
806 
807  parentOid = RangeVarGetRelid(rv, parentLockmode, false);
808 
809  /*
810  * Reject duplications in the list of parents.
811  */
812  if (list_member_oid(inheritOids, parentOid))
813  ereport(ERROR,
814  (errcode(ERRCODE_DUPLICATE_TABLE),
815  errmsg("relation \"%s\" would be inherited from more than once",
816  get_rel_name(parentOid))));
817 
818  inheritOids = lappend_oid(inheritOids, parentOid);
819  }
820 
821  /*
822  * Select tablespace to use: an explicitly indicated one, or (in the case
823  * of a partitioned table) the parent's, if it has one.
824  */
825  if (stmt->tablespacename)
826  {
827  tablespaceId = get_tablespace_oid(stmt->tablespacename, false);
828 
829  if (partitioned && tablespaceId == MyDatabaseTableSpace)
830  ereport(ERROR,
831  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
832  errmsg("cannot specify default tablespace for partitioned relations")));
833  }
834  else if (stmt->partbound)
835  {
836  Assert(list_length(inheritOids) == 1);
837  tablespaceId = get_rel_tablespace(linitial_oid(inheritOids));
838  }
839  else
840  tablespaceId = InvalidOid;
841 
842  /* still nothing? use the default */
843  if (!OidIsValid(tablespaceId))
844  tablespaceId = GetDefaultTablespace(stmt->relation->relpersistence,
845  partitioned);
846 
847  /* Check permissions except when using database's default */
848  if (OidIsValid(tablespaceId) && tablespaceId != MyDatabaseTableSpace)
849  {
850  AclResult aclresult;
851 
852  aclresult = object_aclcheck(TableSpaceRelationId, tablespaceId, GetUserId(),
853  ACL_CREATE);
854  if (aclresult != ACLCHECK_OK)
856  get_tablespace_name(tablespaceId));
857  }
858 
859  /* In all cases disallow placing user relations in pg_global */
860  if (tablespaceId == GLOBALTABLESPACE_OID)
861  ereport(ERROR,
862  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
863  errmsg("only shared relations can be placed in pg_global tablespace")));
864 
865  /* Identify user ID that will own the table */
866  if (!OidIsValid(ownerId))
867  ownerId = GetUserId();
868 
869  /*
870  * Parse and validate reloptions, if any.
871  */
872  reloptions = transformRelOptions((Datum) 0, stmt->options, NULL, validnsps,
873  true, false);
874 
875  switch (relkind)
876  {
877  case RELKIND_VIEW:
878  (void) view_reloptions(reloptions, true);
879  break;
880  case RELKIND_PARTITIONED_TABLE:
881  (void) partitioned_table_reloptions(reloptions, true);
882  break;
883  default:
884  (void) heap_reloptions(relkind, reloptions, true);
885  }
886 
887  if (stmt->ofTypename)
888  {
889  AclResult aclresult;
890 
891  ofTypeId = typenameTypeId(NULL, stmt->ofTypename);
892 
893  aclresult = object_aclcheck(TypeRelationId, ofTypeId, GetUserId(), ACL_USAGE);
894  if (aclresult != ACLCHECK_OK)
895  aclcheck_error_type(aclresult, ofTypeId);
896  }
897  else
898  ofTypeId = InvalidOid;
899 
900  /*
901  * Look up inheritance ancestors and generate relation schema, including
902  * inherited attributes. (Note that stmt->tableElts is destructively
903  * modified by MergeAttributes.)
904  */
905  stmt->tableElts =
906  MergeAttributes(stmt->tableElts, inheritOids,
907  stmt->relation->relpersistence,
908  stmt->partbound != NULL,
909  &old_constraints);
910 
911  /*
912  * Create a tuple descriptor from the relation schema. Note that this
913  * deals with column names, types, and not-null constraints, but not
914  * default values or CHECK constraints; we handle those below.
915  */
916  descriptor = BuildDescForRelation(stmt->tableElts);
917 
918  /*
919  * Find columns with default values and prepare for insertion of the
920  * defaults. Pre-cooked (that is, inherited) defaults go into a list of
921  * CookedConstraint structs that we'll pass to heap_create_with_catalog,
922  * while raw defaults go into a list of RawColumnDefault structs that will
923  * be processed by AddRelationNewConstraints. (We can't deal with raw
924  * expressions until we can do transformExpr.)
925  *
926  * We can set the atthasdef flags now in the tuple descriptor; this just
927  * saves StoreAttrDefault from having to do an immediate update of the
928  * pg_attribute rows.
929  */
930  rawDefaults = NIL;
931  cookedDefaults = NIL;
932  attnum = 0;
933 
934  foreach(listptr, stmt->tableElts)
935  {
936  ColumnDef *colDef = lfirst(listptr);
937  Form_pg_attribute attr;
938 
939  attnum++;
940  attr = TupleDescAttr(descriptor, attnum - 1);
941 
942  if (colDef->raw_default != NULL)
943  {
944  RawColumnDefault *rawEnt;
945 
946  Assert(colDef->cooked_default == NULL);
947 
948  rawEnt = (RawColumnDefault *) palloc(sizeof(RawColumnDefault));
949  rawEnt->attnum = attnum;
950  rawEnt->raw_default = colDef->raw_default;
951  rawEnt->missingMode = false;
952  rawEnt->generated = colDef->generated;
953  rawDefaults = lappend(rawDefaults, rawEnt);
954  attr->atthasdef = true;
955  }
956  else if (colDef->cooked_default != NULL)
957  {
958  CookedConstraint *cooked;
959 
960  cooked = (CookedConstraint *) palloc(sizeof(CookedConstraint));
961  cooked->contype = CONSTR_DEFAULT;
962  cooked->conoid = InvalidOid; /* until created */
963  cooked->name = NULL;
964  cooked->attnum = attnum;
965  cooked->expr = colDef->cooked_default;
966  cooked->skip_validation = false;
967  cooked->is_local = true; /* not used for defaults */
968  cooked->inhcount = 0; /* ditto */
969  cooked->is_no_inherit = false;
970  cookedDefaults = lappend(cookedDefaults, cooked);
971  attr->atthasdef = true;
972  }
973  }
974 
975  /*
976  * For relations with table AM and partitioned tables, select access
977  * method to use: an explicitly indicated one, or (in the case of a
978  * partitioned table) the parent's, if it has one.
979  */
980  if (stmt->accessMethod != NULL)
981  {
982  Assert(RELKIND_HAS_TABLE_AM(relkind) || relkind == RELKIND_PARTITIONED_TABLE);
983  accessMethodId = get_table_am_oid(stmt->accessMethod, false);
984  }
985  else if (RELKIND_HAS_TABLE_AM(relkind) || relkind == RELKIND_PARTITIONED_TABLE)
986  {
987  if (stmt->partbound)
988  {
989  Assert(list_length(inheritOids) == 1);
990  accessMethodId = get_rel_relam(linitial_oid(inheritOids));
991  }
992 
993  if (RELKIND_HAS_TABLE_AM(relkind) && !OidIsValid(accessMethodId))
994  accessMethodId = get_table_am_oid(default_table_access_method, false);
995  }
996 
997  /*
998  * Create the relation. Inherited defaults and constraints are passed in
999  * for immediate handling --- since they don't need parsing, they can be
1000  * stored immediately.
1001  */
1002  relationId = heap_create_with_catalog(relname,
1003  namespaceId,
1004  tablespaceId,
1005  InvalidOid,
1006  InvalidOid,
1007  ofTypeId,
1008  ownerId,
1009  accessMethodId,
1010  descriptor,
1011  list_concat(cookedDefaults,
1012  old_constraints),
1013  relkind,
1014  stmt->relation->relpersistence,
1015  false,
1016  false,
1017  stmt->oncommit,
1018  reloptions,
1019  true,
1021  false,
1022  InvalidOid,
1023  typaddress);
1024 
1025  /*
1026  * We must bump the command counter to make the newly-created relation
1027  * tuple visible for opening.
1028  */
1030 
1031  /*
1032  * Open the new relation and acquire exclusive lock on it. This isn't
1033  * really necessary for locking out other backends (since they can't see
1034  * the new rel anyway until we commit), but it keeps the lock manager from
1035  * complaining about deadlock risks.
1036  */
1037  rel = relation_open(relationId, AccessExclusiveLock);
1038 
1039  /*
1040  * Now add any newly specified column default and generation expressions
1041  * to the new relation. These are passed to us in the form of raw
1042  * parsetrees; we need to transform them to executable expression trees
1043  * before they can be added. The most convenient way to do that is to
1044  * apply the parser's transformExpr routine, but transformExpr doesn't
1045  * work unless we have a pre-existing relation. So, the transformation has
1046  * to be postponed to this final step of CREATE TABLE.
1047  *
1048  * This needs to be before processing the partitioning clauses because
1049  * those could refer to generated columns.
1050  */
1051  if (rawDefaults)
1052  AddRelationNewConstraints(rel, rawDefaults, NIL,
1053  true, true, false, queryString);
1054 
1055  /*
1056  * Make column generation expressions visible for use by partitioning.
1057  */
1059 
1060  /* Process and store partition bound, if any. */
1061  if (stmt->partbound)
1062  {
1063  PartitionBoundSpec *bound;
1064  ParseState *pstate;
1065  Oid parentId = linitial_oid(inheritOids),
1066  defaultPartOid;
1067  Relation parent,
1068  defaultRel = NULL;
1069  ParseNamespaceItem *nsitem;
1070 
1071  /* Already have strong enough lock on the parent */
1072  parent = table_open(parentId, NoLock);
1073 
1074  /*
1075  * We are going to try to validate the partition bound specification
1076  * against the partition key of parentRel, so it better have one.
1077  */
1078  if (parent->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
1079  ereport(ERROR,
1080  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1081  errmsg("\"%s\" is not partitioned",
1082  RelationGetRelationName(parent))));
1083 
1084  /*
1085  * The partition constraint of the default partition depends on the
1086  * partition bounds of every other partition. It is possible that
1087  * another backend might be about to execute a query on the default
1088  * partition table, and that the query relies on previously cached
1089  * default partition constraints. We must therefore take a table lock
1090  * strong enough to prevent all queries on the default partition from
1091  * proceeding until we commit and send out a shared-cache-inval notice
1092  * that will make them update their index lists.
1093  *
1094  * Order of locking: The relation being added won't be visible to
1095  * other backends until it is committed, hence here in
1096  * DefineRelation() the order of locking the default partition and the
1097  * relation being added does not matter. But at all other places we
1098  * need to lock the default relation before we lock the relation being
1099  * added or removed i.e. we should take the lock in same order at all
1100  * the places such that lock parent, lock default partition and then
1101  * lock the partition so as to avoid a deadlock.
1102  */
1103  defaultPartOid =
1105  true));
1106  if (OidIsValid(defaultPartOid))
1107  defaultRel = table_open(defaultPartOid, AccessExclusiveLock);
1108 
1109  /* Transform the bound values */
1110  pstate = make_parsestate(NULL);
1111  pstate->p_sourcetext = queryString;
1112 
1113  /*
1114  * Add an nsitem containing this relation, so that transformExpr
1115  * called on partition bound expressions is able to report errors
1116  * using a proper context.
1117  */
1118  nsitem = addRangeTableEntryForRelation(pstate, rel, AccessShareLock,
1119  NULL, false, false);
1120  addNSItemToQuery(pstate, nsitem, false, true, true);
1121 
1122  bound = transformPartitionBound(pstate, parent, stmt->partbound);
1123 
1124  /*
1125  * Check first that the new partition's bound is valid and does not
1126  * overlap with any of existing partitions of the parent.
1127  */
1128  check_new_partition_bound(relname, parent, bound, pstate);
1129 
1130  /*
1131  * If the default partition exists, its partition constraints will
1132  * change after the addition of this new partition such that it won't
1133  * allow any row that qualifies for this new partition. So, check that
1134  * the existing data in the default partition satisfies the constraint
1135  * as it will exist after adding this partition.
1136  */
1137  if (OidIsValid(defaultPartOid))
1138  {
1139  check_default_partition_contents(parent, defaultRel, bound);
1140  /* Keep the lock until commit. */
1141  table_close(defaultRel, NoLock);
1142  }
1143 
1144  /* Update the pg_class entry. */
1145  StorePartitionBound(rel, parent, bound);
1146 
1147  table_close(parent, NoLock);
1148  }
1149 
1150  /* Store inheritance information for new rel. */
1151  StoreCatalogInheritance(relationId, inheritOids, stmt->partbound != NULL);
1152 
1153  /*
1154  * Process the partitioning specification (if any) and store the partition
1155  * key information into the catalog.
1156  */
1157  if (partitioned)
1158  {
1159  ParseState *pstate;
1160  int partnatts;
1161  AttrNumber partattrs[PARTITION_MAX_KEYS];
1162  Oid partopclass[PARTITION_MAX_KEYS];
1163  Oid partcollation[PARTITION_MAX_KEYS];
1164  List *partexprs = NIL;
1165 
1166  pstate = make_parsestate(NULL);
1167  pstate->p_sourcetext = queryString;
1168 
1169  partnatts = list_length(stmt->partspec->partParams);
1170 
1171  /* Protect fixed-size arrays here and in executor */
1172  if (partnatts > PARTITION_MAX_KEYS)
1173  ereport(ERROR,
1174  (errcode(ERRCODE_TOO_MANY_COLUMNS),
1175  errmsg("cannot partition using more than %d columns",
1176  PARTITION_MAX_KEYS)));
1177 
1178  /*
1179  * We need to transform the raw parsetrees corresponding to partition
1180  * expressions into executable expression trees. Like column defaults
1181  * and CHECK constraints, we could not have done the transformation
1182  * earlier.
1183  */
1184  stmt->partspec = transformPartitionSpec(rel, stmt->partspec);
1185 
1186  ComputePartitionAttrs(pstate, rel, stmt->partspec->partParams,
1187  partattrs, &partexprs, partopclass,
1188  partcollation, stmt->partspec->strategy);
1189 
1190  StorePartitionKey(rel, stmt->partspec->strategy, partnatts, partattrs,
1191  partexprs,
1192  partopclass, partcollation);
1193 
1194  /* make it all visible */
1196  }
1197 
1198  /*
1199  * If we're creating a partition, create now all the indexes, triggers,
1200  * FKs defined in the parent.
1201  *
1202  * We can't do it earlier, because DefineIndex wants to know the partition
1203  * key which we just stored.
1204  */
1205  if (stmt->partbound)
1206  {
1207  Oid parentId = linitial_oid(inheritOids);
1208  Relation parent;
1209  List *idxlist;
1210  ListCell *cell;
1211 
1212  /* Already have strong enough lock on the parent */
1213  parent = table_open(parentId, NoLock);
1214  idxlist = RelationGetIndexList(parent);
1215 
1216  /*
1217  * For each index in the parent table, create one in the partition
1218  */
1219  foreach(cell, idxlist)
1220  {
1221  Relation idxRel = index_open(lfirst_oid(cell), AccessShareLock);
1222  AttrMap *attmap;
1223  IndexStmt *idxstmt;
1224  Oid constraintOid;
1225 
1226  if (rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
1227  {
1228  if (idxRel->rd_index->indisunique)
1229  ereport(ERROR,
1230  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1231  errmsg("cannot create foreign partition of partitioned table \"%s\"",
1232  RelationGetRelationName(parent)),
1233  errdetail("Table \"%s\" contains indexes that are unique.",
1234  RelationGetRelationName(parent))));
1235  else
1236  {
1237  index_close(idxRel, AccessShareLock);
1238  continue;
1239  }
1240  }
1241 
1243  RelationGetDescr(parent),
1244  false);
1245  idxstmt =
1246  generateClonedIndexStmt(NULL, idxRel,
1247  attmap, &constraintOid);
1249  idxstmt,
1250  InvalidOid,
1251  RelationGetRelid(idxRel),
1252  constraintOid,
1253  -1,
1254  false, false, false, false, false);
1255 
1256  index_close(idxRel, AccessShareLock);
1257  }
1258 
1259  list_free(idxlist);
1260 
1261  /*
1262  * If there are any row-level triggers, clone them to the new
1263  * partition.
1264  */
1265  if (parent->trigdesc != NULL)
1266  CloneRowTriggersToPartition(parent, rel);
1267 
1268  /*
1269  * And foreign keys too. Note that because we're freshly creating the
1270  * table, there is no need to verify these new constraints.
1271  */
1272  CloneForeignKeyConstraints(NULL, parent, rel);
1273 
1274  table_close(parent, NoLock);
1275  }
1276 
1277  /*
1278  * Now add any newly specified CHECK constraints to the new relation. Same
1279  * as for defaults above, but these need to come after partitioning is set
1280  * up.
1281  */
1282  if (stmt->constraints)
1283  AddRelationNewConstraints(rel, NIL, stmt->constraints,
1284  true, true, false, queryString);
1285 
1286  ObjectAddressSet(address, RelationRelationId, relationId);
1287 
1288  /*
1289  * Clean up. We keep lock on new relation (although it shouldn't be
1290  * visible to anyone else anyway, until commit).
1291  */
1292  relation_close(rel, NoLock);
1293 
1294  return address;
1295 }
1296 
1297 /*
1298  * BuildDescForRelation
1299  *
1300  * Given a list of ColumnDef nodes, build a TupleDesc.
1301  *
1302  * Note: This is only for the limited purpose of table and view creation. Not
1303  * everything is filled in. A real tuple descriptor should be obtained from
1304  * the relcache.
1305  */
1306 TupleDesc
1308 {
1309  int natts;
1311  ListCell *l;
1312  TupleDesc desc;
1313  char *attname;
1314  Oid atttypid;
1315  int32 atttypmod;
1316  Oid attcollation;
1317  int attdim;
1318 
1319  /*
1320  * allocate a new tuple descriptor
1321  */
1322  natts = list_length(columns);
1323  desc = CreateTemplateTupleDesc(natts);
1324 
1325  attnum = 0;
1326 
1327  foreach(l, columns)
1328  {
1329  ColumnDef *entry = lfirst(l);
1330  AclResult aclresult;
1331  Form_pg_attribute att;
1332 
1333  /*
1334  * for each entry in the list, get the name and type information from
1335  * the list and have TupleDescInitEntry fill in the attribute
1336  * information we need.
1337  */
1338  attnum++;
1339 
1340  attname = entry->colname;
1341  typenameTypeIdAndMod(NULL, entry->typeName, &atttypid, &atttypmod);
1342 
1343  aclresult = object_aclcheck(TypeRelationId, atttypid, GetUserId(), ACL_USAGE);
1344  if (aclresult != ACLCHECK_OK)
1345  aclcheck_error_type(aclresult, atttypid);
1346 
1347  attcollation = GetColumnDefCollation(NULL, entry, atttypid);
1348  attdim = list_length(entry->typeName->arrayBounds);
1349  if (attdim > PG_INT16_MAX)
1350  ereport(ERROR,
1351  errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
1352  errmsg("too many array dimensions"));
1353 
1354  if (entry->typeName->setof)
1355  ereport(ERROR,
1356  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
1357  errmsg("column \"%s\" cannot be declared SETOF",
1358  attname)));
1359 
1361  atttypid, atttypmod, attdim);
1362  att = TupleDescAttr(desc, attnum - 1);
1363 
1364  /* Override TupleDescInitEntry's settings as requested */
1365  TupleDescInitEntryCollation(desc, attnum, attcollation);
1366 
1367  /* Fill in additional stuff not handled by TupleDescInitEntry */
1368  att->attnotnull = entry->is_not_null;
1369  att->attislocal = entry->is_local;
1370  att->attinhcount = entry->inhcount;
1371  att->attidentity = entry->identity;
1372  att->attgenerated = entry->generated;
1373  att->attcompression = GetAttributeCompression(att->atttypid, entry->compression);
1374  if (entry->storage)
1375  att->attstorage = entry->storage;
1376  else if (entry->storage_name)
1377  att->attstorage = GetAttributeStorage(att->atttypid, entry->storage_name);
1378  }
1379 
1380  return desc;
1381 }
1382 
1383 /*
1384  * Emit the right error or warning message for a "DROP" command issued on a
1385  * non-existent relation
1386  */
1387 static void
1388 DropErrorMsgNonExistent(RangeVar *rel, char rightkind, bool missing_ok)
1389 {
1390  const struct dropmsgstrings *rentry;
1391 
1392  if (rel->schemaname != NULL &&
1394  {
1395  if (!missing_ok)
1396  {
1397  ereport(ERROR,
1398  (errcode(ERRCODE_UNDEFINED_SCHEMA),
1399  errmsg("schema \"%s\" does not exist", rel->schemaname)));
1400  }
1401  else
1402  {
1403  ereport(NOTICE,
1404  (errmsg("schema \"%s\" does not exist, skipping",
1405  rel->schemaname)));
1406  }
1407  return;
1408  }
1409 
1410  for (rentry = dropmsgstringarray; rentry->kind != '\0'; rentry++)
1411  {
1412  if (rentry->kind == rightkind)
1413  {
1414  if (!missing_ok)
1415  {
1416  ereport(ERROR,
1417  (errcode(rentry->nonexistent_code),
1418  errmsg(rentry->nonexistent_msg, rel->relname)));
1419  }
1420  else
1421  {
1422  ereport(NOTICE, (errmsg(rentry->skipping_msg, rel->relname)));
1423  break;
1424  }
1425  }
1426  }
1427 
1428  Assert(rentry->kind != '\0'); /* Should be impossible */
1429 }
1430 
1431 /*
1432  * Emit the right error message for a "DROP" command issued on a
1433  * relation of the wrong type
1434  */
1435 static void
1436 DropErrorMsgWrongType(const char *relname, char wrongkind, char rightkind)
1437 {
1438  const struct dropmsgstrings *rentry;
1439  const struct dropmsgstrings *wentry;
1440 
1441  for (rentry = dropmsgstringarray; rentry->kind != '\0'; rentry++)
1442  if (rentry->kind == rightkind)
1443  break;
1444  Assert(rentry->kind != '\0');
1445 
1446  for (wentry = dropmsgstringarray; wentry->kind != '\0'; wentry++)
1447  if (wentry->kind == wrongkind)
1448  break;
1449  /* wrongkind could be something we don't have in our table... */
1450 
1451  ereport(ERROR,
1452  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1453  errmsg(rentry->nota_msg, relname),
1454  (wentry->kind != '\0') ? errhint("%s", _(wentry->drophint_msg)) : 0));
1455 }
1456 
1457 /*
1458  * RemoveRelations
1459  * Implements DROP TABLE, DROP INDEX, DROP SEQUENCE, DROP VIEW,
1460  * DROP MATERIALIZED VIEW, DROP FOREIGN TABLE
1461  */
1462 void
1464 {
1465  ObjectAddresses *objects;
1466  char relkind;
1467  ListCell *cell;
1468  int flags = 0;
1469  LOCKMODE lockmode = AccessExclusiveLock;
1470 
1471  /* DROP CONCURRENTLY uses a weaker lock, and has some restrictions */
1472  if (drop->concurrent)
1473  {
1474  /*
1475  * Note that for temporary relations this lock may get upgraded later
1476  * on, but as no other session can access a temporary relation, this
1477  * is actually fine.
1478  */
1479  lockmode = ShareUpdateExclusiveLock;
1480  Assert(drop->removeType == OBJECT_INDEX);
1481  if (list_length(drop->objects) != 1)
1482  ereport(ERROR,
1483  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1484  errmsg("DROP INDEX CONCURRENTLY does not support dropping multiple objects")));
1485  if (drop->behavior == DROP_CASCADE)
1486  ereport(ERROR,
1487  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1488  errmsg("DROP INDEX CONCURRENTLY does not support CASCADE")));
1489  }
1490 
1491  /*
1492  * First we identify all the relations, then we delete them in a single
1493  * performMultipleDeletions() call. This is to avoid unwanted DROP
1494  * RESTRICT errors if one of the relations depends on another.
1495  */
1496 
1497  /* Determine required relkind */
1498  switch (drop->removeType)
1499  {
1500  case OBJECT_TABLE:
1501  relkind = RELKIND_RELATION;
1502  break;
1503 
1504  case OBJECT_INDEX:
1505  relkind = RELKIND_INDEX;
1506  break;
1507 
1508  case OBJECT_SEQUENCE:
1509  relkind = RELKIND_SEQUENCE;
1510  break;
1511 
1512  case OBJECT_VIEW:
1513  relkind = RELKIND_VIEW;
1514  break;
1515 
1516  case OBJECT_MATVIEW:
1517  relkind = RELKIND_MATVIEW;
1518  break;
1519 
1520  case OBJECT_FOREIGN_TABLE:
1521  relkind = RELKIND_FOREIGN_TABLE;
1522  break;
1523 
1524  default:
1525  elog(ERROR, "unrecognized drop object type: %d",
1526  (int) drop->removeType);
1527  relkind = 0; /* keep compiler quiet */
1528  break;
1529  }
1530 
1531  /* Lock and validate each relation; build a list of object addresses */
1532  objects = new_object_addresses();
1533 
1534  foreach(cell, drop->objects)
1535  {
1536  RangeVar *rel = makeRangeVarFromNameList((List *) lfirst(cell));
1537  Oid relOid;
1538  ObjectAddress obj;
1540 
1541  /*
1542  * These next few steps are a great deal like relation_openrv, but we
1543  * don't bother building a relcache entry since we don't need it.
1544  *
1545  * Check for shared-cache-inval messages before trying to access the
1546  * relation. This is needed to cover the case where the name
1547  * identifies a rel that has been dropped and recreated since the
1548  * start of our transaction: if we don't flush the old syscache entry,
1549  * then we'll latch onto that entry and suffer an error later.
1550  */
1552 
1553  /* Look up the appropriate relation using namespace search. */
1554  state.expected_relkind = relkind;
1555  state.heap_lockmode = drop->concurrent ?
1557  /* We must initialize these fields to show that no locks are held: */
1558  state.heapOid = InvalidOid;
1559  state.partParentOid = InvalidOid;
1560 
1561  relOid = RangeVarGetRelidExtended(rel, lockmode, RVR_MISSING_OK,
1563  (void *) &state);
1564 
1565  /* Not there? */
1566  if (!OidIsValid(relOid))
1567  {
1568  DropErrorMsgNonExistent(rel, relkind, drop->missing_ok);
1569  continue;
1570  }
1571 
1572  /*
1573  * Decide if concurrent mode needs to be used here or not. The
1574  * callback retrieved the rel's persistence for us.
1575  */
1576  if (drop->concurrent &&
1577  state.actual_relpersistence != RELPERSISTENCE_TEMP)
1578  {
1579  Assert(list_length(drop->objects) == 1 &&
1580  drop->removeType == OBJECT_INDEX);
1582  }
1583 
1584  /*
1585  * Concurrent index drop cannot be used with partitioned indexes,
1586  * either.
1587  */
1588  if ((flags & PERFORM_DELETION_CONCURRENTLY) != 0 &&
1589  state.actual_relkind == RELKIND_PARTITIONED_INDEX)
1590  ereport(ERROR,
1591  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1592  errmsg("cannot drop partitioned index \"%s\" concurrently",
1593  rel->relname)));
1594 
1595  /*
1596  * If we're told to drop a partitioned index, we must acquire lock on
1597  * all the children of its parent partitioned table before proceeding.
1598  * Otherwise we'd try to lock the child index partitions before their
1599  * tables, leading to potential deadlock against other sessions that
1600  * will lock those objects in the other order.
1601  */
1602  if (state.actual_relkind == RELKIND_PARTITIONED_INDEX)
1603  (void) find_all_inheritors(state.heapOid,
1604  state.heap_lockmode,
1605  NULL);
1606 
1607  /* OK, we're ready to delete this one */
1608  obj.classId = RelationRelationId;
1609  obj.objectId = relOid;
1610  obj.objectSubId = 0;
1611 
1612  add_exact_object_address(&obj, objects);
1613  }
1614 
1615  performMultipleDeletions(objects, drop->behavior, flags);
1616 
1617  free_object_addresses(objects);
1618 }
1619 
1620 /*
1621  * Before acquiring a table lock, check whether we have sufficient rights.
1622  * In the case of DROP INDEX, also try to lock the table before the index.
1623  * Also, if the table to be dropped is a partition, we try to lock the parent
1624  * first.
1625  */
1626 static void
1627 RangeVarCallbackForDropRelation(const RangeVar *rel, Oid relOid, Oid oldRelOid,
1628  void *arg)
1629 {
1630  HeapTuple tuple;
1632  char expected_relkind;
1633  bool is_partition;
1634  Form_pg_class classform;
1636  bool invalid_system_index = false;
1637 
1638  state = (struct DropRelationCallbackState *) arg;
1639  heap_lockmode = state->heap_lockmode;
1640 
1641  /*
1642  * If we previously locked some other index's heap, and the name we're
1643  * looking up no longer refers to that relation, release the now-useless
1644  * lock.
1645  */
1646  if (relOid != oldRelOid && OidIsValid(state->heapOid))
1647  {
1649  state->heapOid = InvalidOid;
1650  }
1651 
1652  /*
1653  * Similarly, if we previously locked some other partition's heap, and the
1654  * name we're looking up no longer refers to that relation, release the
1655  * now-useless lock.
1656  */
1657  if (relOid != oldRelOid && OidIsValid(state->partParentOid))
1658  {
1659  UnlockRelationOid(state->partParentOid, AccessExclusiveLock);
1660  state->partParentOid = InvalidOid;
1661  }
1662 
1663  /* Didn't find a relation, so no need for locking or permission checks. */
1664  if (!OidIsValid(relOid))
1665  return;
1666 
1667  tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relOid));
1668  if (!HeapTupleIsValid(tuple))
1669  return; /* concurrently dropped, so nothing to do */
1670  classform = (Form_pg_class) GETSTRUCT(tuple);
1671  is_partition = classform->relispartition;
1672 
1673  /* Pass back some data to save lookups in RemoveRelations */
1674  state->actual_relkind = classform->relkind;
1675  state->actual_relpersistence = classform->relpersistence;
1676 
1677  /*
1678  * Both RELKIND_RELATION and RELKIND_PARTITIONED_TABLE are OBJECT_TABLE,
1679  * but RemoveRelations() can only pass one relkind for a given relation.
1680  * It chooses RELKIND_RELATION for both regular and partitioned tables.
1681  * That means we must be careful before giving the wrong type error when
1682  * the relation is RELKIND_PARTITIONED_TABLE. An equivalent problem
1683  * exists with indexes.
1684  */
1685  if (classform->relkind == RELKIND_PARTITIONED_TABLE)
1686  expected_relkind = RELKIND_RELATION;
1687  else if (classform->relkind == RELKIND_PARTITIONED_INDEX)
1688  expected_relkind = RELKIND_INDEX;
1689  else
1690  expected_relkind = classform->relkind;
1691 
1692  if (state->expected_relkind != expected_relkind)
1693  DropErrorMsgWrongType(rel->relname, classform->relkind,
1694  state->expected_relkind);
1695 
1696  /* Allow DROP to either table owner or schema owner */
1697  if (!object_ownercheck(RelationRelationId, relOid, GetUserId()) &&
1698  !object_ownercheck(NamespaceRelationId, classform->relnamespace, GetUserId()))
1700  get_relkind_objtype(classform->relkind),
1701  rel->relname);
1702 
1703  /*
1704  * Check the case of a system index that might have been invalidated by a
1705  * failed concurrent process and allow its drop. For the time being, this
1706  * only concerns indexes of toast relations that became invalid during a
1707  * REINDEX CONCURRENTLY process.
1708  */
1709  if (IsSystemClass(relOid, classform) && classform->relkind == RELKIND_INDEX)
1710  {
1711  HeapTuple locTuple;
1712  Form_pg_index indexform;
1713  bool indisvalid;
1714 
1715  locTuple = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(relOid));
1716  if (!HeapTupleIsValid(locTuple))
1717  {
1718  ReleaseSysCache(tuple);
1719  return;
1720  }
1721 
1722  indexform = (Form_pg_index) GETSTRUCT(locTuple);
1723  indisvalid = indexform->indisvalid;
1724  ReleaseSysCache(locTuple);
1725 
1726  /* Mark object as being an invalid index of system catalogs */
1727  if (!indisvalid)
1728  invalid_system_index = true;
1729  }
1730 
1731  /* In the case of an invalid index, it is fine to bypass this check */
1732  if (!invalid_system_index && !allowSystemTableMods && IsSystemClass(relOid, classform))
1733  ereport(ERROR,
1734  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1735  errmsg("permission denied: \"%s\" is a system catalog",
1736  rel->relname)));
1737 
1738  ReleaseSysCache(tuple);
1739 
1740  /*
1741  * In DROP INDEX, attempt to acquire lock on the parent table before
1742  * locking the index. index_drop() will need this anyway, and since
1743  * regular queries lock tables before their indexes, we risk deadlock if
1744  * we do it the other way around. No error if we don't find a pg_index
1745  * entry, though --- the relation may have been dropped. Note that this
1746  * code will execute for either plain or partitioned indexes.
1747  */
1748  if (expected_relkind == RELKIND_INDEX &&
1749  relOid != oldRelOid)
1750  {
1751  state->heapOid = IndexGetRelation(relOid, true);
1752  if (OidIsValid(state->heapOid))
1753  LockRelationOid(state->heapOid, heap_lockmode);
1754  }
1755 
1756  /*
1757  * Similarly, if the relation is a partition, we must acquire lock on its
1758  * parent before locking the partition. That's because queries lock the
1759  * parent before its partitions, so we risk deadlock if we do it the other
1760  * way around.
1761  */
1762  if (is_partition && relOid != oldRelOid)
1763  {
1764  state->partParentOid = get_partition_parent(relOid, true);
1765  if (OidIsValid(state->partParentOid))
1766  LockRelationOid(state->partParentOid, AccessExclusiveLock);
1767  }
1768 }
1769 
1770 /*
1771  * ExecuteTruncate
1772  * Executes a TRUNCATE command.
1773  *
1774  * This is a multi-relation truncate. We first open and grab exclusive
1775  * lock on all relations involved, checking permissions and otherwise
1776  * verifying that the relation is OK for truncation. Note that if relations
1777  * are foreign tables, at this stage, we have not yet checked that their
1778  * foreign data in external data sources are OK for truncation. These are
1779  * checked when foreign data are actually truncated later. In CASCADE mode,
1780  * relations having FK references to the targeted relations are automatically
1781  * added to the group; in RESTRICT mode, we check that all FK references are
1782  * internal to the group that's being truncated. Finally all the relations
1783  * are truncated and reindexed.
1784  */
1785 void
1787 {
1788  List *rels = NIL;
1789  List *relids = NIL;
1790  List *relids_logged = NIL;
1791  ListCell *cell;
1792 
1793  /*
1794  * Open, exclusive-lock, and check all the explicitly-specified relations
1795  */
1796  foreach(cell, stmt->relations)
1797  {
1798  RangeVar *rv = lfirst(cell);
1799  Relation rel;
1800  bool recurse = rv->inh;
1801  Oid myrelid;
1802  LOCKMODE lockmode = AccessExclusiveLock;
1803 
1804  myrelid = RangeVarGetRelidExtended(rv, lockmode,
1806  NULL);
1807 
1808  /* don't throw error for "TRUNCATE foo, foo" */
1809  if (list_member_oid(relids, myrelid))
1810  continue;
1811 
1812  /* open the relation, we already hold a lock on it */
1813  rel = table_open(myrelid, NoLock);
1814 
1815  /*
1816  * RangeVarGetRelidExtended() has done most checks with its callback,
1817  * but other checks with the now-opened Relation remain.
1818  */
1820 
1821  rels = lappend(rels, rel);
1822  relids = lappend_oid(relids, myrelid);
1823 
1824  /* Log this relation only if needed for logical decoding */
1825  if (RelationIsLogicallyLogged(rel))
1826  relids_logged = lappend_oid(relids_logged, myrelid);
1827 
1828  if (recurse)
1829  {
1830  ListCell *child;
1831  List *children;
1832 
1833  children = find_all_inheritors(myrelid, lockmode, NULL);
1834 
1835  foreach(child, children)
1836  {
1837  Oid childrelid = lfirst_oid(child);
1838 
1839  if (list_member_oid(relids, childrelid))
1840  continue;
1841 
1842  /* find_all_inheritors already got lock */
1843  rel = table_open(childrelid, NoLock);
1844 
1845  /*
1846  * It is possible that the parent table has children that are
1847  * temp tables of other backends. We cannot safely access
1848  * such tables (because of buffering issues), and the best
1849  * thing to do is to silently ignore them. Note that this
1850  * check is the same as one of the checks done in
1851  * truncate_check_activity() called below, still it is kept
1852  * here for simplicity.
1853  */
1854  if (RELATION_IS_OTHER_TEMP(rel))
1855  {
1856  table_close(rel, lockmode);
1857  continue;
1858  }
1859 
1860  /*
1861  * Inherited TRUNCATE commands perform access permission
1862  * checks on the parent table only. So we skip checking the
1863  * children's permissions and don't call
1864  * truncate_check_perms() here.
1865  */
1868 
1869  rels = lappend(rels, rel);
1870  relids = lappend_oid(relids, childrelid);
1871 
1872  /* Log this relation only if needed for logical decoding */
1873  if (RelationIsLogicallyLogged(rel))
1874  relids_logged = lappend_oid(relids_logged, childrelid);
1875  }
1876  }
1877  else if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
1878  ereport(ERROR,
1879  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1880  errmsg("cannot truncate only a partitioned table"),
1881  errhint("Do not specify the ONLY keyword, or use TRUNCATE ONLY on the partitions directly.")));
1882  }
1883 
1884  ExecuteTruncateGuts(rels, relids, relids_logged,
1885  stmt->behavior, stmt->restart_seqs, false);
1886 
1887  /* And close the rels */
1888  foreach(cell, rels)
1889  {
1890  Relation rel = (Relation) lfirst(cell);
1891 
1892  table_close(rel, NoLock);
1893  }
1894 }
1895 
1896 /*
1897  * ExecuteTruncateGuts
1898  *
1899  * Internal implementation of TRUNCATE. This is called by the actual TRUNCATE
1900  * command (see above) as well as replication subscribers that execute a
1901  * replicated TRUNCATE action.
1902  *
1903  * explicit_rels is the list of Relations to truncate that the command
1904  * specified. relids is the list of Oids corresponding to explicit_rels.
1905  * relids_logged is the list of Oids (a subset of relids) that require
1906  * WAL-logging. This is all a bit redundant, but the existing callers have
1907  * this information handy in this form.
1908  */
1909 void
1910 ExecuteTruncateGuts(List *explicit_rels,
1911  List *relids,
1912  List *relids_logged,
1913  DropBehavior behavior, bool restart_seqs,
1914  bool run_as_table_owner)
1915 {
1916  List *rels;
1917  List *seq_relids = NIL;
1918  HTAB *ft_htab = NULL;
1919  EState *estate;
1920  ResultRelInfo *resultRelInfos;
1921  ResultRelInfo *resultRelInfo;
1922  SubTransactionId mySubid;
1923  ListCell *cell;
1924  Oid *logrelids;
1925 
1926  /*
1927  * Check the explicitly-specified relations.
1928  *
1929  * In CASCADE mode, suck in all referencing relations as well. This
1930  * requires multiple iterations to find indirectly-dependent relations. At
1931  * each phase, we need to exclusive-lock new rels before looking for their
1932  * dependencies, else we might miss something. Also, we check each rel as
1933  * soon as we open it, to avoid a faux pas such as holding lock for a long
1934  * time on a rel we have no permissions for.
1935  */
1936  rels = list_copy(explicit_rels);
1937  if (behavior == DROP_CASCADE)
1938  {
1939  for (;;)
1940  {
1941  List *newrelids;
1942 
1943  newrelids = heap_truncate_find_FKs(relids);
1944  if (newrelids == NIL)
1945  break; /* nothing else to add */
1946 
1947  foreach(cell, newrelids)
1948  {
1949  Oid relid = lfirst_oid(cell);
1950  Relation rel;
1951 
1952  rel = table_open(relid, AccessExclusiveLock);
1953  ereport(NOTICE,
1954  (errmsg("truncate cascades to table \"%s\"",
1955  RelationGetRelationName(rel))));
1956  truncate_check_rel(relid, rel->rd_rel);
1957  truncate_check_perms(relid, rel->rd_rel);
1959  rels = lappend(rels, rel);
1960  relids = lappend_oid(relids, relid);
1961 
1962  /* Log this relation only if needed for logical decoding */
1963  if (RelationIsLogicallyLogged(rel))
1964  relids_logged = lappend_oid(relids_logged, relid);
1965  }
1966  }
1967  }
1968 
1969  /*
1970  * Check foreign key references. In CASCADE mode, this should be
1971  * unnecessary since we just pulled in all the references; but as a
1972  * cross-check, do it anyway if in an Assert-enabled build.
1973  */
1974 #ifdef USE_ASSERT_CHECKING
1975  heap_truncate_check_FKs(rels, false);
1976 #else
1977  if (behavior == DROP_RESTRICT)
1978  heap_truncate_check_FKs(rels, false);
1979 #endif
1980 
1981  /*
1982  * If we are asked to restart sequences, find all the sequences, lock them
1983  * (we need AccessExclusiveLock for ResetSequence), and check permissions.
1984  * We want to do this early since it's pointless to do all the truncation
1985  * work only to fail on sequence permissions.
1986  */
1987  if (restart_seqs)
1988  {
1989  foreach(cell, rels)
1990  {
1991  Relation rel = (Relation) lfirst(cell);
1992  List *seqlist = getOwnedSequences(RelationGetRelid(rel));
1993  ListCell *seqcell;
1994 
1995  foreach(seqcell, seqlist)
1996  {
1997  Oid seq_relid = lfirst_oid(seqcell);
1998  Relation seq_rel;
1999 
2000  seq_rel = relation_open(seq_relid, AccessExclusiveLock);
2001 
2002  /* This check must match AlterSequence! */
2003  if (!object_ownercheck(RelationRelationId, seq_relid, GetUserId()))
2005  RelationGetRelationName(seq_rel));
2006 
2007  seq_relids = lappend_oid(seq_relids, seq_relid);
2008 
2009  relation_close(seq_rel, NoLock);
2010  }
2011  }
2012  }
2013 
2014  /* Prepare to catch AFTER triggers. */
2016 
2017  /*
2018  * To fire triggers, we'll need an EState as well as a ResultRelInfo for
2019  * each relation. We don't need to call ExecOpenIndices, though.
2020  *
2021  * We put the ResultRelInfos in the es_opened_result_relations list, even
2022  * though we don't have a range table and don't populate the
2023  * es_result_relations array. That's a bit bogus, but it's enough to make
2024  * ExecGetTriggerResultRel() find them.
2025  */
2026  estate = CreateExecutorState();
2027  resultRelInfos = (ResultRelInfo *)
2028  palloc(list_length(rels) * sizeof(ResultRelInfo));
2029  resultRelInfo = resultRelInfos;
2030  foreach(cell, rels)
2031  {
2032  Relation rel = (Relation) lfirst(cell);
2033 
2034  InitResultRelInfo(resultRelInfo,
2035  rel,
2036  0, /* dummy rangetable index */
2037  NULL,
2038  0);
2039  estate->es_opened_result_relations =
2040  lappend(estate->es_opened_result_relations, resultRelInfo);
2041  resultRelInfo++;
2042  }
2043 
2044  /*
2045  * Process all BEFORE STATEMENT TRUNCATE triggers before we begin
2046  * truncating (this is because one of them might throw an error). Also, if
2047  * we were to allow them to prevent statement execution, that would need
2048  * to be handled here.
2049  */
2050  resultRelInfo = resultRelInfos;
2051  foreach(cell, rels)
2052  {
2053  UserContext ucxt;
2054 
2055  if (run_as_table_owner)
2056  SwitchToUntrustedUser(resultRelInfo->ri_RelationDesc->rd_rel->relowner,
2057  &ucxt);
2058  ExecBSTruncateTriggers(estate, resultRelInfo);
2059  if (run_as_table_owner)
2060  RestoreUserContext(&ucxt);
2061  resultRelInfo++;
2062  }
2063 
2064  /*
2065  * OK, truncate each table.
2066  */
2067  mySubid = GetCurrentSubTransactionId();
2068 
2069  foreach(cell, rels)
2070  {
2071  Relation rel = (Relation) lfirst(cell);
2072 
2073  /* Skip partitioned tables as there is nothing to do */
2074  if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
2075  continue;
2076 
2077  /*
2078  * Build the lists of foreign tables belonging to each foreign server
2079  * and pass each list to the foreign data wrapper's callback function,
2080  * so that each server can truncate its all foreign tables in bulk.
2081  * Each list is saved as a single entry in a hash table that uses the
2082  * server OID as lookup key.
2083  */
2084  if (rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
2085  {
2087  bool found;
2088  ForeignTruncateInfo *ft_info;
2089 
2090  /* First time through, initialize hashtable for foreign tables */
2091  if (!ft_htab)
2092  {
2093  HASHCTL hctl;
2094 
2095  memset(&hctl, 0, sizeof(HASHCTL));
2096  hctl.keysize = sizeof(Oid);
2097  hctl.entrysize = sizeof(ForeignTruncateInfo);
2098  hctl.hcxt = CurrentMemoryContext;
2099 
2100  ft_htab = hash_create("TRUNCATE for Foreign Tables",
2101  32, /* start small and extend */
2102  &hctl,
2104  }
2105 
2106  /* Find or create cached entry for the foreign table */
2107  ft_info = hash_search(ft_htab, &serverid, HASH_ENTER, &found);
2108  if (!found)
2109  ft_info->rels = NIL;
2110 
2111  /*
2112  * Save the foreign table in the entry of the server that the
2113  * foreign table belongs to.
2114  */
2115  ft_info->rels = lappend(ft_info->rels, rel);
2116  continue;
2117  }
2118 
2119  /*
2120  * Normally, we need a transaction-safe truncation here. However, if
2121  * the table was either created in the current (sub)transaction or has
2122  * a new relfilenumber in the current (sub)transaction, then we can
2123  * just truncate it in-place, because a rollback would cause the whole
2124  * table or the current physical file to be thrown away anyway.
2125  */
2126  if (rel->rd_createSubid == mySubid ||
2127  rel->rd_newRelfilelocatorSubid == mySubid)
2128  {
2129  /* Immediate, non-rollbackable truncation is OK */
2130  heap_truncate_one_rel(rel);
2131  }
2132  else
2133  {
2134  Oid heap_relid;
2135  Oid toast_relid;
2136  ReindexParams reindex_params = {0};
2137 
2138  /*
2139  * This effectively deletes all rows in the table, and may be done
2140  * in a serializable transaction. In that case we must record a
2141  * rw-conflict in to this transaction from each transaction
2142  * holding a predicate lock on the table.
2143  */
2145 
2146  /*
2147  * Need the full transaction-safe pushups.
2148  *
2149  * Create a new empty storage file for the relation, and assign it
2150  * as the relfilenumber value. The old storage file is scheduled
2151  * for deletion at commit.
2152  */
2153  RelationSetNewRelfilenumber(rel, rel->rd_rel->relpersistence);
2154 
2155  heap_relid = RelationGetRelid(rel);
2156 
2157  /*
2158  * The same for the toast table, if any.
2159  */
2160  toast_relid = rel->rd_rel->reltoastrelid;
2161  if (OidIsValid(toast_relid))
2162  {
2163  Relation toastrel = relation_open(toast_relid,
2165 
2166  RelationSetNewRelfilenumber(toastrel,
2167  toastrel->rd_rel->relpersistence);
2168  table_close(toastrel, NoLock);
2169  }
2170 
2171  /*
2172  * Reconstruct the indexes to match, and we're done.
2173  */
2174  reindex_relation(NULL, heap_relid, REINDEX_REL_PROCESS_TOAST,
2175  &reindex_params);
2176  }
2177 
2178  pgstat_count_truncate(rel);
2179  }
2180 
2181  /* Now go through the hash table, and truncate foreign tables */
2182  if (ft_htab)
2183  {
2184  ForeignTruncateInfo *ft_info;
2185  HASH_SEQ_STATUS seq;
2186 
2187  hash_seq_init(&seq, ft_htab);
2188 
2189  PG_TRY();
2190  {
2191  while ((ft_info = hash_seq_search(&seq)) != NULL)
2192  {
2193  FdwRoutine *routine = GetFdwRoutineByServerId(ft_info->serverid);
2194 
2195  /* truncate_check_rel() has checked that already */
2196  Assert(routine->ExecForeignTruncate != NULL);
2197 
2198  routine->ExecForeignTruncate(ft_info->rels,
2199  behavior,
2200  restart_seqs);
2201  }
2202  }
2203  PG_FINALLY();
2204  {
2205  hash_destroy(ft_htab);
2206  }
2207  PG_END_TRY();
2208  }
2209 
2210  /*
2211  * Restart owned sequences if we were asked to.
2212  */
2213  foreach(cell, seq_relids)
2214  {
2215  Oid seq_relid = lfirst_oid(cell);
2216 
2217  ResetSequence(seq_relid);
2218  }
2219 
2220  /*
2221  * Write a WAL record to allow this set of actions to be logically
2222  * decoded.
2223  *
2224  * Assemble an array of relids so we can write a single WAL record for the
2225  * whole action.
2226  */
2227  if (relids_logged != NIL)
2228  {
2229  xl_heap_truncate xlrec;
2230  int i = 0;
2231 
2232  /* should only get here if wal_level >= logical */
2234 
2235  logrelids = palloc(list_length(relids_logged) * sizeof(Oid));
2236  foreach(cell, relids_logged)
2237  logrelids[i++] = lfirst_oid(cell);
2238 
2239  xlrec.dbId = MyDatabaseId;
2240  xlrec.nrelids = list_length(relids_logged);
2241  xlrec.flags = 0;
2242  if (behavior == DROP_CASCADE)
2243  xlrec.flags |= XLH_TRUNCATE_CASCADE;
2244  if (restart_seqs)
2246 
2247  XLogBeginInsert();
2248  XLogRegisterData((char *) &xlrec, SizeOfHeapTruncate);
2249  XLogRegisterData((char *) logrelids, list_length(relids_logged) * sizeof(Oid));
2250 
2252 
2253  (void) XLogInsert(RM_HEAP_ID, XLOG_HEAP_TRUNCATE);
2254  }
2255 
2256  /*
2257  * Process all AFTER STATEMENT TRUNCATE triggers.
2258  */
2259  resultRelInfo = resultRelInfos;
2260  foreach(cell, rels)
2261  {
2262  UserContext ucxt;
2263 
2264  if (run_as_table_owner)
2265  SwitchToUntrustedUser(resultRelInfo->ri_RelationDesc->rd_rel->relowner,
2266  &ucxt);
2267  ExecASTruncateTriggers(estate, resultRelInfo);
2268  if (run_as_table_owner)
2269  RestoreUserContext(&ucxt);
2270  resultRelInfo++;
2271  }
2272 
2273  /* Handle queued AFTER triggers */
2274  AfterTriggerEndQuery(estate);
2275 
2276  /* We can clean up the EState now */
2277  FreeExecutorState(estate);
2278 
2279  /*
2280  * Close any rels opened by CASCADE (can't do this while EState still
2281  * holds refs)
2282  */
2283  rels = list_difference_ptr(rels, explicit_rels);
2284  foreach(cell, rels)
2285  {
2286  Relation rel = (Relation) lfirst(cell);
2287 
2288  table_close(rel, NoLock);
2289  }
2290 }
2291 
2292 /*
2293  * Check that a given relation is safe to truncate. Subroutine for
2294  * ExecuteTruncate() and RangeVarCallbackForTruncate().
2295  */
2296 static void
2298 {
2299  char *relname = NameStr(reltuple->relname);
2300 
2301  /*
2302  * Only allow truncate on regular tables, foreign tables using foreign
2303  * data wrappers supporting TRUNCATE and partitioned tables (although, the
2304  * latter are only being included here for the following checks; no
2305  * physical truncation will occur in their case.).
2306  */
2307  if (reltuple->relkind == RELKIND_FOREIGN_TABLE)
2308  {
2309  Oid serverid = GetForeignServerIdByRelId(relid);
2310  FdwRoutine *fdwroutine = GetFdwRoutineByServerId(serverid);
2311 
2312  if (!fdwroutine->ExecForeignTruncate)
2313  ereport(ERROR,
2314  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2315  errmsg("cannot truncate foreign table \"%s\"",
2316  relname)));
2317  }
2318  else if (reltuple->relkind != RELKIND_RELATION &&
2319  reltuple->relkind != RELKIND_PARTITIONED_TABLE)
2320  ereport(ERROR,
2321  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2322  errmsg("\"%s\" is not a table", relname)));
2323 
2324  /*
2325  * Most system catalogs can't be truncated at all, or at least not unless
2326  * allow_system_table_mods=on. As an exception, however, we allow
2327  * pg_largeobject to be truncated as part of pg_upgrade, because we need
2328  * to change its relfilenode to match the old cluster, and allowing a
2329  * TRUNCATE command to be executed is the easiest way of doing that.
2330  */
2331  if (!allowSystemTableMods && IsSystemClass(relid, reltuple)
2332  && (!IsBinaryUpgrade || relid != LargeObjectRelationId))
2333  ereport(ERROR,
2334  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
2335  errmsg("permission denied: \"%s\" is a system catalog",
2336  relname)));
2337 
2338  InvokeObjectTruncateHook(relid);
2339 }
2340 
2341 /*
2342  * Check that current user has the permission to truncate given relation.
2343  */
2344 static void
2346 {
2347  char *relname = NameStr(reltuple->relname);
2348  AclResult aclresult;
2349 
2350  /* Permissions checks */
2351  aclresult = pg_class_aclcheck(relid, GetUserId(), ACL_TRUNCATE);
2352  if (aclresult != ACLCHECK_OK)
2353  aclcheck_error(aclresult, get_relkind_objtype(reltuple->relkind),
2354  relname);
2355 }
2356 
2357 /*
2358  * Set of extra sanity checks to check if a given relation is safe to
2359  * truncate. This is split with truncate_check_rel() as
2360  * RangeVarCallbackForTruncate() cannot open a Relation yet.
2361  */
2362 static void
2364 {
2365  /*
2366  * Don't allow truncate on temp tables of other backends ... their local
2367  * buffer manager is not going to cope.
2368  */
2369  if (RELATION_IS_OTHER_TEMP(rel))
2370  ereport(ERROR,
2371  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2372  errmsg("cannot truncate temporary tables of other sessions")));
2373 
2374  /*
2375  * Also check for active uses of the relation in the current transaction,
2376  * including open scans and pending AFTER trigger events.
2377  */
2378  CheckTableNotInUse(rel, "TRUNCATE");
2379 }
2380 
2381 /*
2382  * storage_name
2383  * returns the name corresponding to a typstorage/attstorage enum value
2384  */
2385 static const char *
2387 {
2388  switch (c)
2389  {
2390  case TYPSTORAGE_PLAIN:
2391  return "PLAIN";
2392  case TYPSTORAGE_EXTERNAL:
2393  return "EXTERNAL";
2394  case TYPSTORAGE_EXTENDED:
2395  return "EXTENDED";
2396  case TYPSTORAGE_MAIN:
2397  return "MAIN";
2398  default:
2399  return "???";
2400  }
2401 }
2402 
2403 /*----------
2404  * MergeAttributes
2405  * Returns new schema given initial schema and superclasses.
2406  *
2407  * Input arguments:
2408  * 'columns' is the column/attribute definition for the table. (It's a list
2409  * of ColumnDef's.) It is destructively changed.
2410  * 'supers' is a list of OIDs of parent relations, already locked by caller.
2411  * 'relpersistence' is the persistence type of the table.
2412  * 'is_partition' tells if the table is a partition.
2413  *
2414  * Output arguments:
2415  * 'supconstr' receives a list of constraints belonging to the parents,
2416  * updated as necessary to be valid for the child.
2417  *
2418  * Return value:
2419  * Completed schema list.
2420  *
2421  * Notes:
2422  * The order in which the attributes are inherited is very important.
2423  * Intuitively, the inherited attributes should come first. If a table
2424  * inherits from multiple parents, the order of those attributes are
2425  * according to the order of the parents specified in CREATE TABLE.
2426  *
2427  * Here's an example:
2428  *
2429  * create table person (name text, age int4, location point);
2430  * create table emp (salary int4, manager text) inherits(person);
2431  * create table student (gpa float8) inherits (person);
2432  * create table stud_emp (percent int4) inherits (emp, student);
2433  *
2434  * The order of the attributes of stud_emp is:
2435  *
2436  * person {1:name, 2:age, 3:location}
2437  * / \
2438  * {6:gpa} student emp {4:salary, 5:manager}
2439  * \ /
2440  * stud_emp {7:percent}
2441  *
2442  * If the same attribute name appears multiple times, then it appears
2443  * in the result table in the proper location for its first appearance.
2444  *
2445  * Constraints (including not-null constraints) for the child table
2446  * are the union of all relevant constraints, from both the child schema
2447  * and parent tables.
2448  *
2449  * The default value for a child column is defined as:
2450  * (1) If the child schema specifies a default, that value is used.
2451  * (2) If neither the child nor any parent specifies a default, then
2452  * the column will not have a default.
2453  * (3) If conflicting defaults are inherited from different parents
2454  * (and not overridden by the child), an error is raised.
2455  * (4) Otherwise the inherited default is used.
2456  *
2457  * Note that the default-value infrastructure is used for generated
2458  * columns' expressions too, so most of the preceding paragraph applies
2459  * to generation expressions too. We insist that a child column be
2460  * generated if and only if its parent(s) are, but it need not have
2461  * the same generation expression.
2462  *----------
2463  */
2464 static List *
2465 MergeAttributes(List *columns, const List *supers, char relpersistence,
2466  bool is_partition, List **supconstr)
2467 {
2468  List *inh_columns = NIL;
2469  List *constraints = NIL;
2470  bool have_bogus_defaults = false;
2471  int child_attno;
2472  static Node bogus_marker = {0}; /* marks conflicting defaults */
2473  List *saved_columns = NIL;
2474  ListCell *lc;
2475 
2476  /*
2477  * Check for and reject tables with too many columns. We perform this
2478  * check relatively early for two reasons: (a) we don't run the risk of
2479  * overflowing an AttrNumber in subsequent code (b) an O(n^2) algorithm is
2480  * okay if we're processing <= 1600 columns, but could take minutes to
2481  * execute if the user attempts to create a table with hundreds of
2482  * thousands of columns.
2483  *
2484  * Note that we also need to check that we do not exceed this figure after
2485  * including columns from inherited relations.
2486  */
2487  if (list_length(columns) > MaxHeapAttributeNumber)
2488  ereport(ERROR,
2489  (errcode(ERRCODE_TOO_MANY_COLUMNS),
2490  errmsg("tables can have at most %d columns",
2492 
2493  /*
2494  * Check for duplicate names in the explicit list of attributes.
2495  *
2496  * Although we might consider merging such entries in the same way that we
2497  * handle name conflicts for inherited attributes, it seems to make more
2498  * sense to assume such conflicts are errors.
2499  *
2500  * We don't use foreach() here because we have two nested loops over the
2501  * columns list, with possible element deletions in the inner one. If we
2502  * used foreach_delete_current() it could only fix up the state of one of
2503  * the loops, so it seems cleaner to use looping over list indexes for
2504  * both loops. Note that any deletion will happen beyond where the outer
2505  * loop is, so its index never needs adjustment.
2506  */
2507  for (int coldefpos = 0; coldefpos < list_length(columns); coldefpos++)
2508  {
2509  ColumnDef *coldef = list_nth_node(ColumnDef, columns, coldefpos);
2510 
2511  if (!is_partition && coldef->typeName == NULL)
2512  {
2513  /*
2514  * Typed table column option that does not belong to a column from
2515  * the type. This works because the columns from the type come
2516  * first in the list. (We omit this check for partition column
2517  * lists; those are processed separately below.)
2518  */
2519  ereport(ERROR,
2520  (errcode(ERRCODE_UNDEFINED_COLUMN),
2521  errmsg("column \"%s\" does not exist",
2522  coldef->colname)));
2523  }
2524 
2525  /* restpos scans all entries beyond coldef; incr is in loop body */
2526  for (int restpos = coldefpos + 1; restpos < list_length(columns);)
2527  {
2528  ColumnDef *restdef = list_nth_node(ColumnDef, columns, restpos);
2529 
2530  if (strcmp(coldef->colname, restdef->colname) == 0)
2531  {
2532  if (coldef->is_from_type)
2533  {
2534  /*
2535  * merge the column options into the column from the type
2536  */
2537  coldef->is_not_null = restdef->is_not_null;
2538  coldef->raw_default = restdef->raw_default;
2539  coldef->cooked_default = restdef->cooked_default;
2540  coldef->constraints = restdef->constraints;
2541  coldef->is_from_type = false;
2542  columns = list_delete_nth_cell(columns, restpos);
2543  }
2544  else
2545  ereport(ERROR,
2546  (errcode(ERRCODE_DUPLICATE_COLUMN),
2547  errmsg("column \"%s\" specified more than once",
2548  coldef->colname)));
2549  }
2550  else
2551  restpos++;
2552  }
2553  }
2554 
2555  /*
2556  * In case of a partition, there are no new column definitions, only dummy
2557  * ColumnDefs created for column constraints. Set them aside for now and
2558  * process them at the end.
2559  */
2560  if (is_partition)
2561  {
2562  saved_columns = columns;
2563  columns = NIL;
2564  }
2565 
2566  /*
2567  * Scan the parents left-to-right, and merge their attributes to form a
2568  * list of inherited columns (inh_columns).
2569  */
2570  child_attno = 0;
2571  foreach(lc, supers)
2572  {
2573  Oid parent = lfirst_oid(lc);
2574  Relation relation;
2575  TupleDesc tupleDesc;
2576  TupleConstr *constr;
2577  AttrMap *newattmap;
2578  List *inherited_defaults;
2579  List *cols_with_defaults;
2580  ListCell *lc1;
2581  ListCell *lc2;
2582 
2583  /* caller already got lock */
2584  relation = table_open(parent, NoLock);
2585 
2586  /*
2587  * Check for active uses of the parent partitioned table in the
2588  * current transaction, such as being used in some manner by an
2589  * enclosing command.
2590  */
2591  if (is_partition)
2592  CheckTableNotInUse(relation, "CREATE TABLE .. PARTITION OF");
2593 
2594  /*
2595  * We do not allow partitioned tables and partitions to participate in
2596  * regular inheritance.
2597  */
2598  if (relation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE && !is_partition)
2599  ereport(ERROR,
2600  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2601  errmsg("cannot inherit from partitioned table \"%s\"",
2602  RelationGetRelationName(relation))));
2603  if (relation->rd_rel->relispartition && !is_partition)
2604  ereport(ERROR,
2605  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2606  errmsg("cannot inherit from partition \"%s\"",
2607  RelationGetRelationName(relation))));
2608 
2609  if (relation->rd_rel->relkind != RELKIND_RELATION &&
2610  relation->rd_rel->relkind != RELKIND_FOREIGN_TABLE &&
2611  relation->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
2612  ereport(ERROR,
2613  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2614  errmsg("inherited relation \"%s\" is not a table or foreign table",
2615  RelationGetRelationName(relation))));
2616 
2617  /*
2618  * If the parent is permanent, so must be all of its partitions. Note
2619  * that inheritance allows that case.
2620  */
2621  if (is_partition &&
2622  relation->rd_rel->relpersistence != RELPERSISTENCE_TEMP &&
2623  relpersistence == RELPERSISTENCE_TEMP)
2624  ereport(ERROR,
2625  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2626  errmsg("cannot create a temporary relation as partition of permanent relation \"%s\"",
2627  RelationGetRelationName(relation))));
2628 
2629  /* Permanent rels cannot inherit from temporary ones */
2630  if (relpersistence != RELPERSISTENCE_TEMP &&
2631  relation->rd_rel->relpersistence == RELPERSISTENCE_TEMP)
2632  ereport(ERROR,
2633  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2634  errmsg(!is_partition
2635  ? "cannot inherit from temporary relation \"%s\""
2636  : "cannot create a permanent relation as partition of temporary relation \"%s\"",
2637  RelationGetRelationName(relation))));
2638 
2639  /* If existing rel is temp, it must belong to this session */
2640  if (relation->rd_rel->relpersistence == RELPERSISTENCE_TEMP &&
2641  !relation->rd_islocaltemp)
2642  ereport(ERROR,
2643  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2644  errmsg(!is_partition
2645  ? "cannot inherit from temporary relation of another session"
2646  : "cannot create as partition of temporary relation of another session")));
2647 
2648  /*
2649  * We should have an UNDER permission flag for this, but for now,
2650  * demand that creator of a child table own the parent.
2651  */
2652  if (!object_ownercheck(RelationRelationId, RelationGetRelid(relation), GetUserId()))
2654  RelationGetRelationName(relation));
2655 
2656  tupleDesc = RelationGetDescr(relation);
2657  constr = tupleDesc->constr;
2658 
2659  /*
2660  * newattmap->attnums[] will contain the child-table attribute numbers
2661  * for the attributes of this parent table. (They are not the same
2662  * for parents after the first one, nor if we have dropped columns.)
2663  */
2664  newattmap = make_attrmap(tupleDesc->natts);
2665 
2666  /* We can't process inherited defaults until newattmap is complete. */
2667  inherited_defaults = cols_with_defaults = NIL;
2668 
2669  for (AttrNumber parent_attno = 1; parent_attno <= tupleDesc->natts;
2670  parent_attno++)
2671  {
2672  Form_pg_attribute attribute = TupleDescAttr(tupleDesc,
2673  parent_attno - 1);
2674  char *attributeName = NameStr(attribute->attname);
2675  int exist_attno;
2676  ColumnDef *newdef;
2677  ColumnDef *mergeddef;
2678 
2679  /*
2680  * Ignore dropped columns in the parent.
2681  */
2682  if (attribute->attisdropped)
2683  continue; /* leave newattmap->attnums entry as zero */
2684 
2685  /*
2686  * Create new column definition
2687  */
2688  newdef = makeColumnDef(attributeName, attribute->atttypid,
2689  attribute->atttypmod, attribute->attcollation);
2690  newdef->is_not_null = attribute->attnotnull;
2691  newdef->storage = attribute->attstorage;
2692  newdef->generated = attribute->attgenerated;
2693  if (CompressionMethodIsValid(attribute->attcompression))
2694  newdef->compression =
2695  pstrdup(GetCompressionMethodName(attribute->attcompression));
2696 
2697  /*
2698  * Regular inheritance children are independent enough not to
2699  * inherit identity columns. But partitions are integral part of
2700  * a partitioned table and inherit identity column.
2701  */
2702  if (is_partition)
2703  newdef->identity = attribute->attidentity;
2704 
2705  /*
2706  * Does it match some previously considered column from another
2707  * parent?
2708  */
2709  exist_attno = findAttrByName(attributeName, inh_columns);
2710  if (exist_attno > 0)
2711  {
2712  /*
2713  * Yes, try to merge the two column definitions.
2714  */
2715  mergeddef = MergeInheritedAttribute(inh_columns, exist_attno, newdef);
2716 
2717  newattmap->attnums[parent_attno - 1] = exist_attno;
2718 
2719  /*
2720  * Partitions have only one parent, so conflict should never
2721  * occur.
2722  */
2723  Assert(!is_partition);
2724  }
2725  else
2726  {
2727  /*
2728  * No, create a new inherited column
2729  */
2730  newdef->inhcount = 1;
2731  newdef->is_local = false;
2732  inh_columns = lappend(inh_columns, newdef);
2733 
2734  newattmap->attnums[parent_attno - 1] = ++child_attno;
2735  mergeddef = newdef;
2736  }
2737 
2738  /*
2739  * Locate default/generation expression if any
2740  */
2741  if (attribute->atthasdef)
2742  {
2743  Node *this_default;
2744 
2745  this_default = TupleDescGetDefault(tupleDesc, parent_attno);
2746  if (this_default == NULL)
2747  elog(ERROR, "default expression not found for attribute %d of relation \"%s\"",
2748  parent_attno, RelationGetRelationName(relation));
2749 
2750  /*
2751  * If it's a GENERATED default, it might contain Vars that
2752  * need to be mapped to the inherited column(s)' new numbers.
2753  * We can't do that till newattmap is ready, so just remember
2754  * all the inherited default expressions for the moment.
2755  */
2756  inherited_defaults = lappend(inherited_defaults, this_default);
2757  cols_with_defaults = lappend(cols_with_defaults, mergeddef);
2758  }
2759  }
2760 
2761  /*
2762  * Now process any inherited default expressions, adjusting attnos
2763  * using the completed newattmap map.
2764  */
2765  forboth(lc1, inherited_defaults, lc2, cols_with_defaults)
2766  {
2767  Node *this_default = (Node *) lfirst(lc1);
2768  ColumnDef *def = (ColumnDef *) lfirst(lc2);
2769  bool found_whole_row;
2770 
2771  /* Adjust Vars to match new table's column numbering */
2772  this_default = map_variable_attnos(this_default,
2773  1, 0,
2774  newattmap,
2775  InvalidOid, &found_whole_row);
2776 
2777  /*
2778  * For the moment we have to reject whole-row variables. We could
2779  * convert them, if we knew the new table's rowtype OID, but that
2780  * hasn't been assigned yet. (A variable could only appear in a
2781  * generation expression, so the error message is correct.)
2782  */
2783  if (found_whole_row)
2784  ereport(ERROR,
2785  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2786  errmsg("cannot convert whole-row table reference"),
2787  errdetail("Generation expression for column \"%s\" contains a whole-row reference to table \"%s\".",
2788  def->colname,
2789  RelationGetRelationName(relation))));
2790 
2791  /*
2792  * If we already had a default from some prior parent, check to
2793  * see if they are the same. If so, no problem; if not, mark the
2794  * column as having a bogus default. Below, we will complain if
2795  * the bogus default isn't overridden by the child columns.
2796  */
2797  Assert(def->raw_default == NULL);
2798  if (def->cooked_default == NULL)
2799  def->cooked_default = this_default;
2800  else if (!equal(def->cooked_default, this_default))
2801  {
2802  def->cooked_default = &bogus_marker;
2803  have_bogus_defaults = true;
2804  }
2805  }
2806 
2807  /*
2808  * Now copy the CHECK constraints of this parent, adjusting attnos
2809  * using the completed newattmap map. Identically named constraints
2810  * are merged if possible, else we throw error.
2811  */
2812  if (constr && constr->num_check > 0)
2813  {
2814  ConstrCheck *check = constr->check;
2815 
2816  for (int i = 0; i < constr->num_check; i++)
2817  {
2818  char *name = check[i].ccname;
2819  Node *expr;
2820  bool found_whole_row;
2821 
2822  /* ignore if the constraint is non-inheritable */
2823  if (check[i].ccnoinherit)
2824  continue;
2825 
2826  /* Adjust Vars to match new table's column numbering */
2827  expr = map_variable_attnos(stringToNode(check[i].ccbin),
2828  1, 0,
2829  newattmap,
2830  InvalidOid, &found_whole_row);
2831 
2832  /*
2833  * For the moment we have to reject whole-row variables. We
2834  * could convert them, if we knew the new table's rowtype OID,
2835  * but that hasn't been assigned yet.
2836  */
2837  if (found_whole_row)
2838  ereport(ERROR,
2839  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2840  errmsg("cannot convert whole-row table reference"),
2841  errdetail("Constraint \"%s\" contains a whole-row reference to table \"%s\".",
2842  name,
2843  RelationGetRelationName(relation))));
2844 
2845  constraints = MergeCheckConstraint(constraints, name, expr);
2846  }
2847  }
2848 
2849  free_attrmap(newattmap);
2850 
2851  /*
2852  * Close the parent rel, but keep our lock on it until xact commit.
2853  * That will prevent someone else from deleting or ALTERing the parent
2854  * before the child is committed.
2855  */
2856  table_close(relation, NoLock);
2857  }
2858 
2859  /*
2860  * If we had no inherited attributes, the result columns are just the
2861  * explicitly declared columns. Otherwise, we need to merge the declared
2862  * columns into the inherited column list. Although, we never have any
2863  * explicitly declared columns if the table is a partition.
2864  */
2865  if (inh_columns != NIL)
2866  {
2867  int newcol_attno = 0;
2868 
2869  foreach(lc, columns)
2870  {
2871  ColumnDef *newdef = lfirst_node(ColumnDef, lc);
2872  char *attributeName = newdef->colname;
2873  int exist_attno;
2874 
2875  /*
2876  * Partitions have only one parent and have no column definitions
2877  * of their own, so conflict should never occur.
2878  */
2879  Assert(!is_partition);
2880 
2881  newcol_attno++;
2882 
2883  /*
2884  * Does it match some inherited column?
2885  */
2886  exist_attno = findAttrByName(attributeName, inh_columns);
2887  if (exist_attno > 0)
2888  {
2889  /*
2890  * Yes, try to merge the two column definitions.
2891  */
2892  MergeChildAttribute(inh_columns, exist_attno, newcol_attno, newdef);
2893  }
2894  else
2895  {
2896  /*
2897  * No, attach new column unchanged to result columns.
2898  */
2899  inh_columns = lappend(inh_columns, newdef);
2900  }
2901  }
2902 
2903  columns = inh_columns;
2904 
2905  /*
2906  * Check that we haven't exceeded the legal # of columns after merging
2907  * in inherited columns.
2908  */
2909  if (list_length(columns) > MaxHeapAttributeNumber)
2910  ereport(ERROR,
2911  (errcode(ERRCODE_TOO_MANY_COLUMNS),
2912  errmsg("tables can have at most %d columns",
2914  }
2915 
2916  /*
2917  * Now that we have the column definition list for a partition, we can
2918  * check whether the columns referenced in the column constraint specs
2919  * actually exist. Also, we merge parent's not-null constraints and
2920  * defaults into each corresponding column definition.
2921  */
2922  if (is_partition)
2923  {
2924  foreach(lc, saved_columns)
2925  {
2926  ColumnDef *restdef = lfirst(lc);
2927  bool found = false;
2928  ListCell *l;
2929 
2930  foreach(l, columns)
2931  {
2932  ColumnDef *coldef = lfirst(l);
2933 
2934  if (strcmp(coldef->colname, restdef->colname) == 0)
2935  {
2936  found = true;
2937  coldef->is_not_null |= restdef->is_not_null;
2938 
2939  /*
2940  * Check for conflicts related to generated columns.
2941  *
2942  * Same rules as above: generated-ness has to match the
2943  * parent, but the contents of the generation expression
2944  * can be different.
2945  */
2946  if (coldef->generated)
2947  {
2948  if (restdef->raw_default && !restdef->generated)
2949  ereport(ERROR,
2950  (errcode(ERRCODE_INVALID_COLUMN_DEFINITION),
2951  errmsg("column \"%s\" inherits from generated column but specifies default",
2952  restdef->colname)));
2953  if (restdef->identity)
2954  ereport(ERROR,
2955  (errcode(ERRCODE_INVALID_COLUMN_DEFINITION),
2956  errmsg("column \"%s\" inherits from generated column but specifies identity",
2957  restdef->colname)));
2958  }
2959  else
2960  {
2961  if (restdef->generated)
2962  ereport(ERROR,
2963  (errcode(ERRCODE_INVALID_COLUMN_DEFINITION),
2964  errmsg("child column \"%s\" specifies generation expression",
2965  restdef->colname),
2966  errhint("A child table column cannot be generated unless its parent column is.")));
2967  }
2968 
2969  /*
2970  * Override the parent's default value for this column
2971  * (coldef->cooked_default) with the partition's local
2972  * definition (restdef->raw_default), if there's one. It
2973  * should be physically impossible to get a cooked default
2974  * in the local definition or a raw default in the
2975  * inherited definition, but make sure they're nulls, for
2976  * future-proofing.
2977  */
2978  Assert(restdef->cooked_default == NULL);
2979  Assert(coldef->raw_default == NULL);
2980  if (restdef->raw_default)
2981  {
2982  coldef->raw_default = restdef->raw_default;
2983  coldef->cooked_default = NULL;
2984  }
2985  }
2986  }
2987 
2988  /* complain for constraints on columns not in parent */
2989  if (!found)
2990  ereport(ERROR,
2991  (errcode(ERRCODE_UNDEFINED_COLUMN),
2992  errmsg("column \"%s\" does not exist",
2993  restdef->colname)));
2994  }
2995  }
2996 
2997  /*
2998  * If we found any conflicting parent default values, check to make sure
2999  * they were overridden by the child.
3000  */
3001  if (have_bogus_defaults)
3002  {
3003  foreach(lc, columns)
3004  {
3005  ColumnDef *def = lfirst(lc);
3006 
3007  if (def->cooked_default == &bogus_marker)
3008  {
3009  if (def->generated)
3010  ereport(ERROR,
3011  (errcode(ERRCODE_INVALID_COLUMN_DEFINITION),
3012  errmsg("column \"%s\" inherits conflicting generation expressions",
3013  def->colname),
3014  errhint("To resolve the conflict, specify a generation expression explicitly.")));
3015  else
3016  ereport(ERROR,
3017  (errcode(ERRCODE_INVALID_COLUMN_DEFINITION),
3018  errmsg("column \"%s\" inherits conflicting default values",
3019  def->colname),
3020  errhint("To resolve the conflict, specify a default explicitly.")));
3021  }
3022  }
3023  }
3024 
3025  *supconstr = constraints;
3026 
3027  return columns;
3028 }
3029 
3030 
3031 /*
3032  * MergeCheckConstraint
3033  * Try to merge an inherited CHECK constraint with previous ones
3034  *
3035  * If we inherit identically-named constraints from multiple parents, we must
3036  * merge them, or throw an error if they don't have identical definitions.
3037  *
3038  * constraints is a list of CookedConstraint structs for previous constraints.
3039  *
3040  * If the new constraint matches an existing one, then the existing
3041  * constraint's inheritance count is updated. If there is a conflict (same
3042  * name but different expression), throw an error. If the constraint neither
3043  * matches nor conflicts with an existing one, a new constraint is appended to
3044  * the list.
3045  */
3046 static List *
3047 MergeCheckConstraint(List *constraints, const char *name, Node *expr)
3048 {
3049  ListCell *lc;
3050  CookedConstraint *newcon;
3051 
3052  foreach(lc, constraints)
3053  {
3054  CookedConstraint *ccon = (CookedConstraint *) lfirst(lc);
3055 
3056  Assert(ccon->contype == CONSTR_CHECK);
3057 
3058  /* Non-matching names never conflict */
3059  if (strcmp(ccon->name, name) != 0)
3060  continue;
3061 
3062  if (equal(expr, ccon->expr))
3063  {
3064  /* OK to merge constraint with existing */
3065  if (pg_add_s16_overflow(ccon->inhcount, 1,
3066  &ccon->inhcount))
3067  ereport(ERROR,
3068  errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
3069  errmsg("too many inheritance parents"));
3070  return constraints;
3071  }
3072 
3073  ereport(ERROR,
3075  errmsg("check constraint name \"%s\" appears multiple times but with different expressions",
3076  name)));
3077  }
3078 
3079  /*
3080  * Constraint couldn't be merged with an existing one and also didn't
3081  * conflict with an existing one, so add it as a new one to the list.
3082  */
3083  newcon = palloc0_object(CookedConstraint);
3084  newcon->contype = CONSTR_CHECK;
3085  newcon->name = pstrdup(name);
3086  newcon->expr = expr;
3087  newcon->inhcount = 1;
3088  return lappend(constraints, newcon);
3089 }
3090 
3091 /*
3092  * MergeChildAttribute
3093  * Merge given child attribute definition into given inherited attribute.
3094  *
3095  * Input arguments:
3096  * 'inh_columns' is the list of inherited ColumnDefs.
3097  * 'exist_attno' is the number of the inherited attribute in inh_columns
3098  * 'newcol_attno' is the attribute number in child table's schema definition
3099  * 'newdef' is the column/attribute definition from the child table.
3100  *
3101  * The ColumnDef in 'inh_columns' list is modified. The child attribute's
3102  * ColumnDef remains unchanged.
3103  *
3104  * Notes:
3105  * - The attribute is merged according to the rules laid out in the prologue
3106  * of MergeAttributes().
3107  * - If matching inherited attribute exists but the child attribute can not be
3108  * merged into it, the function throws respective errors.
3109  * - A partition can not have its own column definitions. Hence this function
3110  * is applicable only to a regular inheritance child.
3111  */
3112 static void
3113 MergeChildAttribute(List *inh_columns, int exist_attno, int newcol_attno, const ColumnDef *newdef)
3114 {
3115  char *attributeName = newdef->colname;
3116  ColumnDef *inhdef;
3117  Oid inhtypeid,
3118  newtypeid;
3119  int32 inhtypmod,
3120  newtypmod;
3121  Oid inhcollid,
3122  newcollid;
3123 
3124  if (exist_attno == newcol_attno)
3125  ereport(NOTICE,
3126  (errmsg("merging column \"%s\" with inherited definition",
3127  attributeName)));
3128  else
3129  ereport(NOTICE,
3130  (errmsg("moving and merging column \"%s\" with inherited definition", attributeName),
3131  errdetail("User-specified column moved to the position of the inherited column.")));
3132 
3133  inhdef = list_nth_node(ColumnDef, inh_columns, exist_attno - 1);
3134 
3135  /*
3136  * Must have the same type and typmod
3137  */
3138  typenameTypeIdAndMod(NULL, inhdef->typeName, &inhtypeid, &inhtypmod);
3139  typenameTypeIdAndMod(NULL, newdef->typeName, &newtypeid, &newtypmod);
3140  if (inhtypeid != newtypeid || inhtypmod != newtypmod)
3141  ereport(ERROR,
3142  (errcode(ERRCODE_DATATYPE_MISMATCH),
3143  errmsg("column \"%s\" has a type conflict",
3144  attributeName),
3145  errdetail("%s versus %s",
3146  format_type_with_typemod(inhtypeid, inhtypmod),
3147  format_type_with_typemod(newtypeid, newtypmod))));
3148 
3149  /*
3150  * Must have the same collation
3151  */
3152  inhcollid = GetColumnDefCollation(NULL, inhdef, inhtypeid);
3153  newcollid = GetColumnDefCollation(NULL, newdef, newtypeid);
3154  if (inhcollid != newcollid)
3155  ereport(ERROR,
3156  (errcode(ERRCODE_COLLATION_MISMATCH),
3157  errmsg("column \"%s\" has a collation conflict",
3158  attributeName),
3159  errdetail("\"%s\" versus \"%s\"",
3160  get_collation_name(inhcollid),
3161  get_collation_name(newcollid))));
3162 
3163  /*
3164  * Identity is never inherited by a regular inheritance child. Pick
3165  * child's identity definition if there's one.
3166  */
3167  inhdef->identity = newdef->identity;
3168 
3169  /*
3170  * Copy storage parameter
3171  */
3172  if (inhdef->storage == 0)
3173  inhdef->storage = newdef->storage;
3174  else if (newdef->storage != 0 && inhdef->storage != newdef->storage)
3175  ereport(ERROR,
3176  (errcode(ERRCODE_DATATYPE_MISMATCH),
3177  errmsg("column \"%s\" has a storage parameter conflict",
3178  attributeName),
3179  errdetail("%s versus %s",
3180  storage_name(inhdef->storage),
3181  storage_name(newdef->storage))));
3182 
3183  /*
3184  * Copy compression parameter
3185  */
3186  if (inhdef->compression == NULL)
3187  inhdef->compression = newdef->compression;
3188  else if (newdef->compression != NULL)
3189  {
3190  if (strcmp(inhdef->compression, newdef->compression) != 0)
3191  ereport(ERROR,
3192  (errcode(ERRCODE_DATATYPE_MISMATCH),
3193  errmsg("column \"%s\" has a compression method conflict",
3194  attributeName),
3195  errdetail("%s versus %s", inhdef->compression, newdef->compression)));
3196  }
3197 
3198  /*
3199  * Merge of not-null constraints = OR 'em together
3200  */
3201  inhdef->is_not_null |= newdef->is_not_null;
3202 
3203  /*
3204  * Check for conflicts related to generated columns.
3205  *
3206  * If the parent column is generated, the child column will be made a
3207  * generated column if it isn't already. If it is a generated column,
3208  * we'll take its generation expression in preference to the parent's. We
3209  * must check that the child column doesn't specify a default value or
3210  * identity, which matches the rules for a single column in
3211  * parse_utilcmd.c.
3212  *
3213  * Conversely, if the parent column is not generated, the child column
3214  * can't be either. (We used to allow that, but it results in being able
3215  * to override the generation expression via UPDATEs through the parent.)
3216  */
3217  if (inhdef->generated)
3218  {
3219  if (newdef->raw_default && !newdef->generated)
3220  ereport(ERROR,
3221  (errcode(ERRCODE_INVALID_COLUMN_DEFINITION),
3222  errmsg("column \"%s\" inherits from generated column but specifies default",
3223  inhdef->colname)));
3224  if (newdef->identity)
3225  ereport(ERROR,
3226  (errcode(ERRCODE_INVALID_COLUMN_DEFINITION),
3227  errmsg("column \"%s\" inherits from generated column but specifies identity",
3228  inhdef->colname)));
3229  }
3230  else
3231  {
3232  if (newdef->generated)
3233  ereport(ERROR,
3234  (errcode(ERRCODE_INVALID_COLUMN_DEFINITION),
3235  errmsg("child column \"%s\" specifies generation expression",
3236  inhdef->colname),
3237  errhint("A child table column cannot be generated unless its parent column is.")));
3238  }
3239 
3240  /*
3241  * If new def has a default, override previous default
3242  */
3243  if (newdef->raw_default != NULL)
3244  {
3245  inhdef->raw_default = newdef->raw_default;
3246  inhdef->cooked_default = newdef->cooked_default;
3247  }
3248 
3249  /* Mark the column as locally defined */
3250  inhdef->is_local = true;
3251 }
3252 
3253 /*
3254  * MergeInheritedAttribute
3255  * Merge given parent attribute definition into specified attribute
3256  * inherited from the previous parents.
3257  *
3258  * Input arguments:
3259  * 'inh_columns' is the list of previously inherited ColumnDefs.
3260  * 'exist_attno' is the number the existing matching attribute in inh_columns.
3261  * 'newdef' is the new parent column/attribute definition to be merged.
3262  *
3263  * The matching ColumnDef in 'inh_columns' list is modified and returned.
3264  *
3265  * Notes:
3266  * - The attribute is merged according to the rules laid out in the prologue
3267  * of MergeAttributes().
3268  * - If matching inherited attribute exists but the new attribute can not be
3269  * merged into it, the function throws respective errors.
3270  * - A partition inherits from only a single parent. Hence this function is
3271  * applicable only to a regular inheritance.
3272  */
3273 static ColumnDef *
3275  int exist_attno,
3276  const ColumnDef *newdef)
3277 {
3278  char *attributeName = newdef->colname;
3279  ColumnDef *prevdef;
3280  Oid prevtypeid,
3281  newtypeid;
3282  int32 prevtypmod,
3283  newtypmod;
3284  Oid prevcollid,
3285  newcollid;
3286 
3287  ereport(NOTICE,
3288  (errmsg("merging multiple inherited definitions of column \"%s\"",
3289  attributeName)));
3290  prevdef = list_nth_node(ColumnDef, inh_columns, exist_attno - 1);
3291 
3292  /*
3293  * Must have the same type and typmod
3294  */
3295  typenameTypeIdAndMod(NULL, prevdef->typeName, &prevtypeid, &prevtypmod);
3296  typenameTypeIdAndMod(NULL, newdef->typeName, &newtypeid, &newtypmod);
3297  if (prevtypeid != newtypeid || prevtypmod != newtypmod)
3298  ereport(ERROR,
3299  (errcode(ERRCODE_DATATYPE_MISMATCH),
3300  errmsg("inherited column \"%s\" has a type conflict",
3301  attributeName),
3302  errdetail("%s versus %s",
3303  format_type_with_typemod(prevtypeid, prevtypmod),
3304  format_type_with_typemod(newtypeid, newtypmod))));
3305 
3306  /*
3307  * Merge of not-null constraints = OR 'em together
3308  */
3309  prevdef->is_not_null |= newdef->is_not_null;
3310 
3311  /*
3312  * Must have the same collation
3313  */
3314  prevcollid = GetColumnDefCollation(NULL, prevdef, prevtypeid);
3315  newcollid = GetColumnDefCollation(NULL, newdef, newtypeid);
3316  if (prevcollid != newcollid)
3317  ereport(ERROR,
3318  (errcode(ERRCODE_COLLATION_MISMATCH),
3319  errmsg("inherited column \"%s\" has a collation conflict",
3320  attributeName),
3321  errdetail("\"%s\" versus \"%s\"",
3322  get_collation_name(prevcollid),
3323  get_collation_name(newcollid))));
3324 
3325  /*
3326  * Copy/check storage parameter
3327  */
3328  if (prevdef->storage == 0)
3329  prevdef->storage = newdef->storage;
3330  else if (prevdef->storage != newdef->storage)
3331  ereport(ERROR,
3332  (errcode(ERRCODE_DATATYPE_MISMATCH),
3333  errmsg("inherited column \"%s\" has a storage parameter conflict",
3334  attributeName),
3335  errdetail("%s versus %s",
3336  storage_name(prevdef->storage),
3337  storage_name(newdef->storage))));
3338 
3339  /*
3340  * Copy/check compression parameter
3341  */
3342  if (prevdef->compression == NULL)
3343  prevdef->compression = newdef->compression;
3344  else if (newdef->compression != NULL)
3345  {
3346  if (strcmp(prevdef->compression, newdef->compression) != 0)
3347  ereport(ERROR,
3348  (errcode(ERRCODE_DATATYPE_MISMATCH),
3349  errmsg("column \"%s\" has a compression method conflict",
3350  attributeName),
3351  errdetail("%s versus %s",
3352  prevdef->compression, newdef->compression)));
3353  }
3354 
3355  /*
3356  * Check for GENERATED conflicts
3357  */
3358  if (prevdef->generated != newdef->generated)
3359  ereport(ERROR,
3360  (errcode(ERRCODE_DATATYPE_MISMATCH),
3361  errmsg("inherited column \"%s\" has a generation conflict",
3362  attributeName)));
3363 
3364  /*
3365  * Default and other constraints are handled by the caller.
3366  */
3367 
3368  if (pg_add_s16_overflow(prevdef->inhcount, 1,
3369  &prevdef->inhcount))
3370  ereport(ERROR,
3371  errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
3372  errmsg("too many inheritance parents"));
3373 
3374  return prevdef;
3375 }
3376 
3377 /*
3378  * StoreCatalogInheritance
3379  * Updates the system catalogs with proper inheritance information.
3380  *
3381  * supers is a list of the OIDs of the new relation's direct ancestors.
3382  */
3383 static void
3384 StoreCatalogInheritance(Oid relationId, List *supers,
3385  bool child_is_partition)
3386 {
3387  Relation relation;
3388  int32 seqNumber;
3389  ListCell *entry;
3390 
3391  /*
3392  * sanity checks
3393  */
3394  Assert(OidIsValid(relationId));
3395 
3396  if (supers == NIL)
3397  return;
3398 
3399  /*
3400  * Store INHERITS information in pg_inherits using direct ancestors only.
3401  * Also enter dependencies on the direct ancestors, and make sure they are
3402  * marked with relhassubclass = true.
3403  *
3404  * (Once upon a time, both direct and indirect ancestors were found here
3405  * and then entered into pg_ipl. Since that catalog doesn't exist
3406  * anymore, there's no need to look for indirect ancestors.)
3407  */
3408  relation = table_open(InheritsRelationId, RowExclusiveLock);
3409 
3410  seqNumber = 1;
3411  foreach(entry, supers)
3412  {
3413  Oid parentOid = lfirst_oid(entry);
3414 
3415  StoreCatalogInheritance1(relationId, parentOid, seqNumber, relation,
3416  child_is_partition);
3417  seqNumber++;
3418  }
3419 
3420  table_close(relation, RowExclusiveLock);
3421 }
3422 
3423 /*
3424  * Make catalog entries showing relationId as being an inheritance child
3425  * of parentOid. inhRelation is the already-opened pg_inherits catalog.
3426  */
3427 static void
3428 StoreCatalogInheritance1(Oid relationId, Oid parentOid,
3429  int32 seqNumber, Relation inhRelation,
3430  bool child_is_partition)
3431 {
3432  ObjectAddress childobject,
3433  parentobject;
3434 
3435  /* store the pg_inherits row */
3436  StoreSingleInheritance(relationId, parentOid, seqNumber);
3437 
3438  /*
3439  * Store a dependency too
3440  */
3441  parentobject.classId = RelationRelationId;
3442  parentobject.objectId = parentOid;
3443  parentobject.objectSubId = 0;
3444  childobject.classId = RelationRelationId;
3445  childobject.objectId = relationId;
3446  childobject.objectSubId = 0;
3447 
3448  recordDependencyOn(&childobject, &parentobject,
3449  child_dependency_type(child_is_partition));
3450 
3451  /*
3452  * Post creation hook of this inheritance. Since object_access_hook
3453  * doesn't take multiple object identifiers, we relay oid of parent
3454  * relation using auxiliary_id argument.
3455  */
3456  InvokeObjectPostAlterHookArg(InheritsRelationId,
3457  relationId, 0,
3458  parentOid, false);
3459 
3460  /*
3461  * Mark the parent as having subclasses.
3462  */
3463  SetRelationHasSubclass(parentOid, true);
3464 }
3465 
3466 /*
3467  * Look for an existing column entry with the given name.
3468  *
3469  * Returns the index (starting with 1) if attribute already exists in columns,
3470  * 0 if it doesn't.
3471  */
3472 static int
3473 findAttrByName(const char *attributeName, const List *columns)
3474 {
3475  ListCell *lc;
3476  int i = 1;
3477 
3478  foreach(lc, columns)
3479  {
3480  if (strcmp(attributeName, lfirst_node(ColumnDef, lc)->colname) == 0)
3481  return i;
3482 
3483  i++;
3484  }
3485  return 0;
3486 }
3487 
3488 
3489 /*
3490  * SetRelationHasSubclass
3491  * Set the value of the relation's relhassubclass field in pg_class.
3492  *
3493  * It's always safe to set this field to true, because all SQL commands are
3494  * ready to see true and then find no children. On the other hand, commands
3495  * generally assume zero children if this is false.
3496  *
3497  * Caller must hold any self-exclusive lock until end of transaction. If the
3498  * new value is false, caller must have acquired that lock before reading the
3499  * evidence that justified the false value. That way, it properly waits if
3500  * another backend is simultaneously concluding no need to change the tuple
3501  * (new and old values are true).
3502  *
3503  * NOTE: an important side-effect of this operation is that an SI invalidation
3504  * message is sent out to all backends --- including me --- causing plans
3505  * referencing the relation to be rebuilt with the new list of children.
3506  * This must happen even if we find that no change is needed in the pg_class
3507  * row.
3508  */
3509 void
3510 SetRelationHasSubclass(Oid relationId, bool relhassubclass)
3511 {
3512  Relation relationRelation;
3513  HeapTuple tuple;
3514  Form_pg_class classtuple;
3515 
3517  ShareUpdateExclusiveLock, false) ||
3518  CheckRelationOidLockedByMe(relationId,
3519  ShareRowExclusiveLock, true));
3520 
3521  /*
3522  * Fetch a modifiable copy of the tuple, modify it, update pg_class.
3523  */
3524  relationRelation = table_open(RelationRelationId, RowExclusiveLock);
3525  tuple = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relationId));
3526  if (!HeapTupleIsValid(tuple))
3527  elog(ERROR, "cache lookup failed for relation %u", relationId);
3528  classtuple = (Form_pg_class) GETSTRUCT(tuple);
3529 
3530  if (classtuple->relhassubclass != relhassubclass)
3531  {
3532  classtuple->relhassubclass = relhassubclass;
3533  CatalogTupleUpdate(relationRelation, &tuple->t_self, tuple);
3534  }
3535  else
3536  {
3537  /* no need to change tuple, but force relcache rebuild anyway */
3539  }
3540 
3541  heap_freetuple(tuple);
3542  table_close(relationRelation, RowExclusiveLock);
3543 }
3544 
3545 /*
3546  * CheckRelationTableSpaceMove
3547  * Check if relation can be moved to new tablespace.
3548  *
3549  * NOTE: The caller must hold AccessExclusiveLock on the relation.
3550  *
3551  * Returns true if the relation can be moved to the new tablespace; raises
3552  * an error if it is not possible to do the move; returns false if the move
3553  * would have no effect.
3554  */
3555 bool
3557 {
3558  Oid oldTableSpaceId;
3559 
3560  /*
3561  * No work if no change in tablespace. Note that MyDatabaseTableSpace is
3562  * stored as 0.
3563  */
3564  oldTableSpaceId = rel->rd_rel->reltablespace;
3565  if (newTableSpaceId == oldTableSpaceId ||
3566  (newTableSpaceId == MyDatabaseTableSpace && oldTableSpaceId == 0))
3567  return false;
3568 
3569  /*
3570  * We cannot support moving mapped relations into different tablespaces.
3571  * (In particular this eliminates all shared catalogs.)
3572  */
3573  if (RelationIsMapped(rel))
3574  ereport(ERROR,
3575  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3576  errmsg("cannot move system relation \"%s\"",
3577  RelationGetRelationName(rel))));
3578 
3579  /* Cannot move a non-shared relation into pg_global */
3580  if (newTableSpaceId == GLOBALTABLESPACE_OID)
3581  ereport(ERROR,
3582  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
3583  errmsg("only shared relations can be placed in pg_global tablespace")));
3584 
3585  /*
3586  * Do not allow moving temp tables of other backends ... their local
3587  * buffer manager is not going to cope.
3588  */
3589  if (RELATION_IS_OTHER_TEMP(rel))
3590  ereport(ERROR,
3591  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3592  errmsg("cannot move temporary tables of other sessions")));
3593 
3594  return true;
3595 }
3596 
3597 /*
3598  * SetRelationTableSpace
3599  * Set new reltablespace and relfilenumber in pg_class entry.
3600  *
3601  * newTableSpaceId is the new tablespace for the relation, and
3602  * newRelFilenumber its new filenumber. If newRelFilenumber is
3603  * InvalidRelFileNumber, this field is not updated.
3604  *
3605  * NOTE: The caller must hold AccessExclusiveLock on the relation.
3606  *
3607  * The caller of this routine had better check if a relation can be
3608  * moved to this new tablespace by calling CheckRelationTableSpaceMove()
3609  * first, and is responsible for making the change visible with
3610  * CommandCounterIncrement().
3611  */
3612 void
3614  Oid newTableSpaceId,
3615  RelFileNumber newRelFilenumber)
3616 {
3617  Relation pg_class;
3618  HeapTuple tuple;
3619  ItemPointerData otid;
3620  Form_pg_class rd_rel;
3621  Oid reloid = RelationGetRelid(rel);
3622 
3623  Assert(CheckRelationTableSpaceMove(rel, newTableSpaceId));
3624 
3625  /* Get a modifiable copy of the relation's pg_class row. */
3626  pg_class = table_open(RelationRelationId, RowExclusiveLock);
3627 
3628  tuple = SearchSysCacheLockedCopy1(RELOID, ObjectIdGetDatum(reloid));
3629  if (!HeapTupleIsValid(tuple))
3630  elog(ERROR, "cache lookup failed for relation %u", reloid);
3631  otid = tuple->t_self;
3632  rd_rel = (Form_pg_class) GETSTRUCT(tuple);
3633 
3634  /* Update the pg_class row. */
3635  rd_rel->reltablespace = (newTableSpaceId == MyDatabaseTableSpace) ?
3636  InvalidOid : newTableSpaceId;
3637  if (RelFileNumberIsValid(newRelFilenumber))
3638  rd_rel->relfilenode = newRelFilenumber;
3639  CatalogTupleUpdate(pg_class, &otid, tuple);
3640  UnlockTuple(pg_class, &otid, InplaceUpdateTupleLock);
3641 
3642  /*
3643  * Record dependency on tablespace. This is only required for relations
3644  * that have no physical storage.
3645  */
3646  if (!RELKIND_HAS_STORAGE(rel->rd_rel->relkind))
3647  changeDependencyOnTablespace(RelationRelationId, reloid,
3648  rd_rel->reltablespace);
3649 
3650  heap_freetuple(tuple);
3651  table_close(pg_class, RowExclusiveLock);
3652 }
3653 
3654 /*
3655  * renameatt_check - basic sanity checks before attribute rename
3656  */
3657 static void
3658 renameatt_check(Oid myrelid, Form_pg_class classform, bool recursing)
3659 {
3660  char relkind = classform->relkind;
3661 
3662  if (classform->reloftype && !recursing)
3663  ereport(ERROR,
3664  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3665  errmsg("cannot rename column of typed table")));
3666 
3667  /*
3668  * Renaming the columns of sequences or toast tables doesn't actually
3669  * break anything from the system's point of view, since internal
3670  * references are by attnum. But it doesn't seem right to allow users to
3671  * change names that are hardcoded into the system, hence the following
3672  * restriction.
3673  */
3674  if (relkind != RELKIND_RELATION &&
3675  relkind != RELKIND_VIEW &&
3676  relkind != RELKIND_MATVIEW &&
3677  relkind != RELKIND_COMPOSITE_TYPE &&
3678  relkind != RELKIND_INDEX &&
3679  relkind != RELKIND_PARTITIONED_INDEX &&
3680  relkind != RELKIND_FOREIGN_TABLE &&
3681  relkind != RELKIND_PARTITIONED_TABLE)
3682  ereport(ERROR,
3683  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3684  errmsg("cannot rename columns of relation \"%s\"",
3685  NameStr(classform->relname)),
3687 
3688  /*
3689  * permissions checking. only the owner of a class can change its schema.
3690  */
3691  if (!object_ownercheck(RelationRelationId, myrelid, GetUserId()))
3693  NameStr(classform->relname));
3694  if (!allowSystemTableMods && IsSystemClass(myrelid, classform))
3695  ereport(ERROR,
3696  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
3697  errmsg("permission denied: \"%s\" is a system catalog",
3698  NameStr(classform->relname))));
3699 }
3700 
3701 /*
3702  * renameatt_internal - workhorse for renameatt
3703  *
3704  * Return value is the attribute number in the 'myrelid' relation.
3705  */
3706 static AttrNumber
3708  const char *oldattname,
3709  const char *newattname,
3710  bool recurse,
3711  bool recursing,
3712  int expected_parents,
3713  DropBehavior behavior)
3714 {
3715  Relation targetrelation;
3716  Relation attrelation;
3717  HeapTuple atttup;
3718  Form_pg_attribute attform;
3720 
3721  /*
3722  * Grab an exclusive lock on the target table, which we will NOT release
3723  * until end of transaction.
3724  */
3725  targetrelation = relation_open(myrelid, AccessExclusiveLock);
3726  renameatt_check(myrelid, RelationGetForm(targetrelation), recursing);
3727 
3728  /*
3729  * if the 'recurse' flag is set then we are supposed to rename this
3730  * attribute in all classes that inherit from 'relname' (as well as in
3731  * 'relname').
3732  *
3733  * any permissions or problems with duplicate attributes will cause the
3734  * whole transaction to abort, which is what we want -- all or nothing.
3735  */
3736  if (recurse)
3737  {
3738  List *child_oids,
3739  *child_numparents;
3740  ListCell *lo,
3741  *li;
3742 
3743  /*
3744  * we need the number of parents for each child so that the recursive
3745  * calls to renameatt() can determine whether there are any parents
3746  * outside the inheritance hierarchy being processed.
3747  */
3748  child_oids = find_all_inheritors(myrelid, AccessExclusiveLock,
3749  &child_numparents);
3750 
3751  /*
3752  * find_all_inheritors does the recursive search of the inheritance
3753  * hierarchy, so all we have to do is process all of the relids in the
3754  * list that it returns.
3755  */
3756  forboth(lo, child_oids, li, child_numparents)
3757  {
3758  Oid childrelid = lfirst_oid(lo);
3759  int numparents = lfirst_int(li);
3760 
3761  if (childrelid == myrelid)
3762  continue;
3763  /* note we need not recurse again */
3764  renameatt_internal(childrelid, oldattname, newattname, false, true, numparents, behavior);
3765  }
3766  }
3767  else
3768  {
3769  /*
3770  * If we are told not to recurse, there had better not be any child
3771  * tables; else the rename would put them out of step.
3772  *
3773  * expected_parents will only be 0 if we are not already recursing.
3774  */
3775  if (expected_parents == 0 &&
3776  find_inheritance_children(myrelid, NoLock) != NIL)
3777  ereport(ERROR,
3778  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
3779  errmsg("inherited column \"%s\" must be renamed in child tables too",
3780  oldattname)));
3781  }
3782 
3783  /* rename attributes in typed tables of composite type */
3784  if (targetrelation->rd_rel->relkind == RELKIND_COMPOSITE_TYPE)
3785  {
3786  List *child_oids;
3787  ListCell *lo;
3788 
3789  child_oids = find_typed_table_dependencies(targetrelation->rd_rel->reltype,
3790  RelationGetRelationName(targetrelation),
3791  behavior);
3792 
3793  foreach(lo, child_oids)
3794  renameatt_internal(lfirst_oid(lo), oldattname, newattname, true, true, 0, behavior);
3795  }
3796 
3797  attrelation = table_open(AttributeRelationId, RowExclusiveLock);
3798 
3799  atttup = SearchSysCacheCopyAttName(myrelid, oldattname);
3800  if (!HeapTupleIsValid(atttup))
3801  ereport(ERROR,
3802  (errcode(ERRCODE_UNDEFINED_COLUMN),
3803  errmsg("column \"%s\" does not exist",
3804  oldattname)));
3805  attform = (Form_pg_attribute) GETSTRUCT(atttup);
3806 
3807  attnum = attform->attnum;
3808  if (attnum <= 0)
3809  ereport(ERROR,
3810  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3811  errmsg("cannot rename system column \"%s\"",
3812  oldattname)));
3813 
3814  /*
3815  * if the attribute is inherited, forbid the renaming. if this is a
3816  * top-level call to renameatt(), then expected_parents will be 0, so the
3817  * effect of this code will be to prohibit the renaming if the attribute
3818  * is inherited at all. if this is a recursive call to renameatt(),
3819  * expected_parents will be the number of parents the current relation has
3820  * within the inheritance hierarchy being processed, so we'll prohibit the
3821  * renaming only if there are additional parents from elsewhere.
3822  */
3823  if (attform->attinhcount > expected_parents)
3824  ereport(ERROR,
3825  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
3826  errmsg("cannot rename inherited column \"%s\"",
3827  oldattname)));
3828 
3829  /* new name should not already exist */
3830  (void) check_for_column_name_collision(targetrelation, newattname, false);
3831 
3832  /* apply the update */
3833  namestrcpy(&(attform->attname), newattname);
3834 
3835  CatalogTupleUpdate(attrelation, &atttup->t_self, atttup);
3836 
3837  InvokeObjectPostAlterHook(RelationRelationId, myrelid, attnum);
3838 
3839  heap_freetuple(atttup);
3840 
3841  table_close(attrelation, RowExclusiveLock);
3842 
3843  relation_close(targetrelation, NoLock); /* close rel but keep lock */
3844 
3845  return attnum;
3846 }
3847 
3848 /*
3849  * Perform permissions and integrity checks before acquiring a relation lock.
3850  */
3851 static void
3853  void *arg)
3854 {
3855  HeapTuple tuple;
3856  Form_pg_class form;
3857 
3858  tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
3859  if (!HeapTupleIsValid(tuple))
3860  return; /* concurrently dropped */
3861  form = (Form_pg_class) GETSTRUCT(tuple);
3862  renameatt_check(relid, form, false);
3863  ReleaseSysCache(tuple);
3864 }
3865 
3866 /*
3867  * renameatt - changes the name of an attribute in a relation
3868  *
3869  * The returned ObjectAddress is that of the renamed column.
3870  */
3873 {
3874  Oid relid;
3876  ObjectAddress address;
3877 
3878  /* lock level taken here should match renameatt_internal */
3880  stmt->missing_ok ? RVR_MISSING_OK : 0,
3882  NULL);
3883 
3884  if (!OidIsValid(relid))
3885  {
3886  ereport(NOTICE,
3887  (errmsg("relation \"%s\" does not exist, skipping",
3888  stmt->relation->relname)));
3889  return InvalidObjectAddress;
3890  }
3891 
3892  attnum =
3893  renameatt_internal(relid,
3894  stmt->subname, /* old att name */
3895  stmt->newname, /* new att name */
3896  stmt->relation->inh, /* recursive? */
3897  false, /* recursing? */
3898  0, /* expected inhcount */
3899  stmt->behavior);
3900 
3901  ObjectAddressSubSet(address, RelationRelationId, relid, attnum);
3902 
3903  return address;
3904 }
3905 
3906 /*
3907  * same logic as renameatt_internal
3908  */
3909 static ObjectAddress
3911  Oid mytypid,
3912  const char *oldconname,
3913  const char *newconname,
3914  bool recurse,
3915  bool recursing,
3916  int expected_parents)
3917 {
3918  Relation targetrelation = NULL;
3919  Oid constraintOid;
3920  HeapTuple tuple;
3921  Form_pg_constraint con;
3922  ObjectAddress address;
3923 
3924  Assert(!myrelid || !mytypid);
3925 
3926  if (mytypid)
3927  {
3928  constraintOid = get_domain_constraint_oid(mytypid, oldconname, false);
3929  }
3930  else
3931  {
3932  targetrelation = relation_open(myrelid, AccessExclusiveLock);
3933 
3934  /*
3935  * don't tell it whether we're recursing; we allow changing typed
3936  * tables here
3937  */
3938  renameatt_check(myrelid, RelationGetForm(targetrelation), false);
3939 
3940  constraintOid = get_relation_constraint_oid(myrelid, oldconname, false);
3941  }
3942 
3943  tuple = SearchSysCache1(CONSTROID, ObjectIdGetDatum(constraintOid));
3944  if (!HeapTupleIsValid(tuple))
3945  elog(ERROR, "cache lookup failed for constraint %u",
3946  constraintOid);
3947  con = (Form_pg_constraint) GETSTRUCT(tuple);
3948 
3949  if (myrelid && con->contype == CONSTRAINT_CHECK && !con->connoinherit)
3950  {
3951  if (recurse)
3952  {
3953  List *child_oids,
3954  *child_numparents;
3955  ListCell *lo,
3956  *li;
3957 
3958  child_oids = find_all_inheritors(myrelid, AccessExclusiveLock,
3959  &child_numparents);
3960 
3961  forboth(lo, child_oids, li, child_numparents)
3962  {
3963  Oid childrelid = lfirst_oid(lo);
3964  int numparents = lfirst_int(li);
3965 
3966  if (childrelid == myrelid)
3967  continue;
3968 
3969  rename_constraint_internal(childrelid, InvalidOid, oldconname, newconname, false, true, numparents);
3970  }
3971  }
3972  else
3973  {
3974  if (expected_parents == 0 &&
3975  find_inheritance_children(myrelid, NoLock) != NIL)
3976  ereport(ERROR,
3977  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
3978  errmsg("inherited constraint \"%s\" must be renamed in child tables too",
3979  oldconname)));
3980  }
3981 
3982  if (con->coninhcount > expected_parents)
3983  ereport(ERROR,
3984  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
3985  errmsg("cannot rename inherited constraint \"%s\"",
3986  oldconname)));
3987  }
3988 
3989  if (con->conindid
3990  && (con->contype == CONSTRAINT_PRIMARY
3991  || con->contype == CONSTRAINT_UNIQUE
3992  || con->contype == CONSTRAINT_EXCLUSION))
3993  /* rename the index; this renames the constraint as well */
3994  RenameRelationInternal(con->conindid, newconname, false, true);
3995  else
3996  RenameConstraintById(constraintOid, newconname);
3997 
3998  ObjectAddressSet(address, ConstraintRelationId, constraintOid);
3999 
4000  ReleaseSysCache(tuple);
4001 
4002  if (targetrelation)
4003  {
4004  /*
4005  * Invalidate relcache so as others can see the new constraint name.
4006  */
4007  CacheInvalidateRelcache(targetrelation);
4008 
4009  relation_close(targetrelation, NoLock); /* close rel but keep lock */
4010  }
4011 
4012  return address;
4013 }
4014 
4017 {
4018  Oid relid = InvalidOid;
4019  Oid typid = InvalidOid;
4020 
4021  if (stmt->renameType == OBJECT_DOMCONSTRAINT)
4022  {
4023  Relation rel;
4024  HeapTuple tup;
4025 
4026  typid = typenameTypeId(NULL, makeTypeNameFromNameList(castNode(List, stmt->object)));
4027  rel = table_open(TypeRelationId, RowExclusiveLock);
4028  tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
4029  if (!HeapTupleIsValid(tup))
4030  elog(ERROR, "cache lookup failed for type %u", typid);
4031  checkDomainOwner(tup);
4032  ReleaseSysCache(tup);
4033  table_close(rel, NoLock);
4034  }
4035  else
4036  {
4037  /* lock level taken here should match rename_constraint_internal */
4039  stmt->missing_ok ? RVR_MISSING_OK : 0,
4041  NULL);
4042  if (!OidIsValid(relid))
4043  {
4044  ereport(NOTICE,
4045  (errmsg("relation \"%s\" does not exist, skipping",
4046  stmt->relation->relname)));
4047  return InvalidObjectAddress;
4048  }
4049  }
4050 
4051  return
4052  rename_constraint_internal(relid, typid,
4053  stmt->subname,
4054  stmt->newname,
4055  (stmt->relation &&
4056  stmt->relation->inh), /* recursive? */
4057  false, /* recursing? */
4058  0 /* expected inhcount */ );
4059 }
4060 
4061 /*
4062  * Execute ALTER TABLE/INDEX/SEQUENCE/VIEW/MATERIALIZED VIEW/FOREIGN TABLE
4063  * RENAME
4064  */
4067 {
4068  bool is_index_stmt = stmt->renameType == OBJECT_INDEX;
4069  Oid relid;
4070  ObjectAddress address;
4071 
4072  /*
4073  * Grab an exclusive lock on the target table, index, sequence, view,
4074  * materialized view, or foreign table, which we will NOT release until
4075  * end of transaction.
4076  *
4077  * Lock level used here should match RenameRelationInternal, to avoid lock
4078  * escalation. However, because ALTER INDEX can be used with any relation
4079  * type, we mustn't believe without verification.
4080  */
4081  for (;;)
4082  {
4083  LOCKMODE lockmode;
4084  char relkind;
4085  bool obj_is_index;
4086 
4087  lockmode = is_index_stmt ? ShareUpdateExclusiveLock : AccessExclusiveLock;
4088 
4089  relid = RangeVarGetRelidExtended(stmt->relation, lockmode,
4090  stmt->missing_ok ? RVR_MISSING_OK : 0,
4092  (void *) stmt);
4093 
4094  if (!OidIsValid(relid))
4095  {
4096  ereport(NOTICE,
4097  (errmsg("relation \"%s\" does not exist, skipping",
4098  stmt->relation->relname)));
4099  return InvalidObjectAddress;
4100  }
4101 
4102  /*
4103  * We allow mismatched statement and object types (e.g., ALTER INDEX
4104  * to rename a table), but we might've used the wrong lock level. If
4105  * that happens, retry with the correct lock level. We don't bother
4106  * if we already acquired AccessExclusiveLock with an index, however.
4107  */
4108  relkind = get_rel_relkind(relid);
4109  obj_is_index = (relkind == RELKIND_INDEX ||
4110  relkind == RELKIND_PARTITIONED_INDEX);
4111  if (obj_is_index || is_index_stmt == obj_is_index)
4112  break;
4113 
4114  UnlockRelationOid(relid, lockmode);
4115  is_index_stmt = obj_is_index;
4116  }
4117 
4118  /* Do the work */
4119  RenameRelationInternal(relid, stmt->newname, false, is_index_stmt);
4120 
4121  ObjectAddressSet(address, RelationRelationId, relid);
4122 
4123  return address;
4124 }
4125 
4126 /*
4127  * RenameRelationInternal - change the name of a relation
4128  */
4129 void
4130 RenameRelationInternal(Oid myrelid, const char *newrelname, bool is_internal, bool is_index)
4131 {
4132  Relation targetrelation;
4133  Relation relrelation; /* for RELATION relation */
4134  ItemPointerData otid;
4135  HeapTuple reltup;
4136  Form_pg_class relform;
4137  Oid namespaceId;
4138 
4139  /*
4140  * Grab a lock on the target relation, which we will NOT release until end
4141  * of transaction. We need at least a self-exclusive lock so that
4142  * concurrent DDL doesn't overwrite the rename if they start updating
4143  * while still seeing the old version. The lock also guards against
4144  * triggering relcache reloads in concurrent sessions, which might not
4145  * handle this information changing under them. For indexes, we can use a
4146  * reduced lock level because RelationReloadIndexInfo() handles indexes
4147  * specially.
4148  */
4149  targetrelation = relation_open(myrelid, is_index ? ShareUpdateExclusiveLock : AccessExclusiveLock);
4150  namespaceId = RelationGetNamespace(targetrelation);
4151 
4152  /*
4153  * Find relation's pg_class tuple, and make sure newrelname isn't in use.
4154  */
4155  relrelation = table_open(RelationRelationId, RowExclusiveLock);
4156 
4157  reltup = SearchSysCacheLockedCopy1(RELOID, ObjectIdGetDatum(myrelid));
4158  if (!HeapTupleIsValid(reltup)) /* shouldn't happen */
4159  elog(ERROR, "cache lookup failed for relation %u", myrelid);
4160  otid = reltup->t_self;
4161  relform = (Form_pg_class) GETSTRUCT(reltup);
4162 
4163  if (get_relname_relid(newrelname, namespaceId) != InvalidOid)
4164  ereport(ERROR,
4165  (errcode(ERRCODE_DUPLICATE_TABLE),
4166  errmsg("relation \"%s\" already exists",
4167  newrelname)));
4168 
4169  /*
4170  * RenameRelation is careful not to believe the caller's idea of the
4171  * relation kind being handled. We don't have to worry about this, but
4172  * let's not be totally oblivious to it. We can process an index as
4173  * not-an-index, but not the other way around.
4174  */
4175  Assert(!is_index ||
4176  is_index == (targetrelation->rd_rel->relkind == RELKIND_INDEX ||
4177  targetrelation->rd_rel->relkind == RELKIND_PARTITIONED_INDEX));
4178 
4179  /*
4180  * Update pg_class tuple with new relname. (Scribbling on reltup is OK
4181  * because it's a copy...)
4182  */
4183  namestrcpy(&(relform->relname), newrelname);
4184 
4185  CatalogTupleUpdate(relrelation, &otid, reltup);
4186  UnlockTuple(relrelation, &otid, InplaceUpdateTupleLock);
4187 
4188  InvokeObjectPostAlterHookArg(RelationRelationId, myrelid, 0,
4189  InvalidOid, is_internal);
4190 
4191  heap_freetuple(reltup);
4192  table_close(relrelation, RowExclusiveLock);
4193 
4194  /*
4195  * Also rename the associated type, if any.
4196  */
4197  if (OidIsValid(targetrelation->rd_rel->reltype))
4198  RenameTypeInternal(targetrelation->rd_rel->reltype,
4199  newrelname, namespaceId);
4200 
4201  /*
4202  * Also rename the associated constraint, if any.
4203  */
4204  if (targetrelation->rd_rel->relkind == RELKIND_INDEX ||
4205  targetrelation->rd_rel->relkind == RELKIND_PARTITIONED_INDEX)
4206  {
4207  Oid constraintId = get_index_constraint(myrelid);
4208 
4209  if (OidIsValid(constraintId))
4210  RenameConstraintById(constraintId, newrelname);
4211  }
4212 
4213  /*
4214  * Close rel, but keep lock!
4215  */
4216  relation_close(targetrelation, NoLock);
4217 }
4218 
4219 /*
4220  * ResetRelRewrite - reset relrewrite
4221  */
4222 void
4224 {
4225  Relation relrelation; /* for RELATION relation */
4226  HeapTuple reltup;
4227  Form_pg_class relform;
4228 
4229  /*
4230  * Find relation's pg_class tuple.
4231  */
4232  relrelation = table_open(RelationRelationId, RowExclusiveLock);
4233 
4234  reltup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(myrelid));
4235  if (!HeapTupleIsValid(reltup)) /* shouldn't happen */
4236  elog(ERROR, "cache lookup failed for relation %u", myrelid);
4237  relform = (Form_pg_class) GETSTRUCT(reltup);
4238 
4239  /*
4240  * Update pg_class tuple.
4241  */
4242  relform->relrewrite = InvalidOid;
4243 
4244  CatalogTupleUpdate(relrelation, &reltup->t_self, reltup);
4245 
4246  heap_freetuple(reltup);
4247  table_close(relrelation, RowExclusiveLock);
4248 }
4249 
4250 /*
4251  * Disallow ALTER TABLE (and similar commands) when the current backend has
4252  * any open reference to the target table besides the one just acquired by
4253  * the calling command; this implies there's an open cursor or active plan.
4254  * We need this check because our lock doesn't protect us against stomping
4255  * on our own foot, only other people's feet!
4256  *
4257  * For ALTER TABLE, the only case known to cause serious trouble is ALTER
4258  * COLUMN TYPE, and some changes are obviously pretty benign, so this could
4259  * possibly be relaxed to only error out for certain types of alterations.
4260  * But the use-case for allowing any of these things is not obvious, so we
4261  * won't work hard at it for now.
4262  *
4263  * We also reject these commands if there are any pending AFTER trigger events
4264  * for the rel. This is certainly necessary for the rewriting variants of
4265  * ALTER TABLE, because they don't preserve tuple TIDs and so the pending
4266  * events would try to fetch the wrong tuples. It might be overly cautious
4267  * in other cases, but again it seems better to err on the side of paranoia.
4268  *
4269  * REINDEX calls this with "rel" referencing the index to be rebuilt; here
4270  * we are worried about active indexscans on the index. The trigger-event
4271  * check can be skipped, since we are doing no damage to the parent table.
4272  *
4273  * The statement name (eg, "ALTER TABLE") is passed for use in error messages.
4274  */
4275 void
4277 {
4278  int expected_refcnt;
4279 
4280  expected_refcnt = rel->rd_isnailed ? 2 : 1;
4281  if (rel->rd_refcnt != expected_refcnt)
4282  ereport(ERROR,
4283  (errcode(ERRCODE_OBJECT_IN_USE),
4284  /* translator: first %s is a SQL command, eg ALTER TABLE */
4285  errmsg("cannot %s \"%s\" because it is being used by active queries in this session",
4286  stmt, RelationGetRelationName(rel))));
4287 
4288  if (rel->rd_rel->relkind != RELKIND_INDEX &&
4289  rel->rd_rel->relkind != RELKIND_PARTITIONED_INDEX &&
4291  ereport(ERROR,
4292  (errcode(ERRCODE_OBJECT_IN_USE),
4293  /* translator: first %s is a SQL command, eg ALTER TABLE */
4294  errmsg("cannot %s \"%s\" because it has pending trigger events",
4295  stmt, RelationGetRelationName(rel))));
4296 }
4297 
4298 /*
4299  * CheckAlterTableIsSafe
4300  * Verify that it's safe to allow ALTER TABLE on this relation.
4301  *
4302  * This consists of CheckTableNotInUse() plus a check that the relation
4303  * isn't another session's temp table. We must split out the temp-table
4304  * check because there are callers of CheckTableNotInUse() that don't want
4305  * that, notably DROP TABLE. (We must allow DROP or we couldn't clean out
4306  * an orphaned temp schema.) Compare truncate_check_activity().
4307  */
4308 static void
4310 {
4311  /*
4312  * Don't allow ALTER on temp tables of other backends. Their local buffer
4313  * manager is not going to cope if we need to change the table's contents.
4314  * Even if we don't, there may be optimizations that assume temp tables
4315  * aren't subject to such interference.
4316  */
4317  if (RELATION_IS_OTHER_TEMP(rel))
4318  ereport(ERROR,
4319  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
4320  errmsg("cannot alter temporary tables of other sessions")));
4321 
4322  /*
4323  * Also check for active uses of the relation in the current transaction,
4324  * including open scans and pending AFTER trigger events.
4325  */
4326  CheckTableNotInUse(rel, "ALTER TABLE");
4327 }
4328 
4329 /*
4330  * AlterTableLookupRelation
4331  * Look up, and lock, the OID for the relation named by an alter table
4332  * statement.
4333  */
4334 Oid
4336 {
4337  return RangeVarGetRelidExtended(stmt->relation, lockmode,
4338  stmt->missing_ok ? RVR_MISSING_OK : 0,
4340  (void *) stmt);
4341 }
4342 
4343 /*
4344  * AlterTable
4345  * Execute ALTER TABLE, which can be a list of subcommands
4346  *
4347  * ALTER TABLE is performed in three phases:
4348  * 1. Examine subcommands and perform pre-transformation checking.
4349  * 2. Validate and transform subcommands, and update system catalogs.
4350  * 3. Scan table(s) to check new constraints, and optionally recopy
4351  * the data into new table(s).
4352  * Phase 3 is not performed unless one or more of the subcommands requires
4353  * it. The intention of this design is to allow multiple independent
4354  * updates of the table schema to be performed with only one pass over the
4355  * data.
4356  *
4357  * ATPrepCmd performs phase 1. A "work queue" entry is created for
4358  * each table to be affected (there may be multiple affected tables if the
4359  * commands traverse a table inheritance hierarchy). Also we do preliminary
4360  * validation of the subcommands. Because earlier subcommands may change
4361  * the catalog state seen by later commands, there are limits to what can
4362  * be done in this phase. Generally, this phase acquires table locks,
4363  * checks permissions and relkind, and recurses to find child tables.
4364  *
4365  * ATRewriteCatalogs performs phase 2 for each affected table.
4366  * Certain subcommands need to be performed before others to avoid
4367  * unnecessary conflicts; for example, DROP COLUMN should come before
4368  * ADD COLUMN. Therefore phase 1 divides the subcommands into multiple
4369  * lists, one for each logical "pass" of phase 2.
4370  *
4371  * ATRewriteTables performs phase 3 for those tables that need it.
4372  *
4373  * For most subcommand types, phases 2 and 3 do no explicit recursion,
4374  * since phase 1 already does it. However, for certain subcommand types
4375  * it is only possible to determine how to recurse at phase 2 time; for
4376  * those cases, phase 1 sets the cmd->recurse flag.
4377  *
4378  * Thanks to the magic of MVCC, an error anywhere along the way rolls back
4379  * the whole operation; we don't have to do anything special to clean up.
4380  *
4381  * The caller must lock the relation, with an appropriate lock level
4382  * for the subcommands requested, using AlterTableGetLockLevel(stmt->cmds)
4383  * or higher. We pass the lock level down
4384  * so that we can apply it recursively to inherited tables. Note that the
4385  * lock level we want as we recurse might well be higher than required for
4386  * that specific subcommand. So we pass down the overall lock requirement,
4387  * rather than reassess it at lower levels.
4388  *
4389  * The caller also provides a "context" which is to be passed back to
4390  * utility.c when we need to execute a subcommand such as CREATE INDEX.
4391  * Some of the fields therein, such as the relid, are used here as well.
4392  */
4393 void
4396 {
4397  Relation rel;
4398 
4399  /* Caller is required to provide an adequate lock. */
4400  rel = relation_open(context->relid, NoLock);
4401 
4402  CheckAlterTableIsSafe(rel);
4403 
4404  ATController(stmt, rel, stmt->cmds, stmt->relation->inh, lockmode, context);
4405 }
4406 
4407 /*
4408  * AlterTableInternal
4409  *
4410  * ALTER TABLE with target specified by OID
4411  *
4412  * We do not reject if the relation is already open, because it's quite
4413  * likely that one or more layers of caller have it open. That means it
4414  * is unsafe to use this entry point for alterations that could break
4415  * existing query plans. On the assumption it's not used for such, we
4416  * don't have to reject pending AFTER triggers, either.
4417  *
4418  * Also, since we don't have an AlterTableUtilityContext, this cannot be
4419  * used for any subcommand types that require parse transformation or
4420  * could generate subcommands that have to be passed to ProcessUtility.
4421  */
4422 void
4423 AlterTableInternal(Oid relid, List *cmds, bool recurse)
4424 {
4425  Relation rel;
4426  LOCKMODE lockmode = AlterTableGetLockLevel(cmds);
4427 
4428  rel = relation_open(relid, lockmode);
4429 
4431 
4432  ATController(NULL, rel, cmds, recurse, lockmode, NULL);
4433 }
4434 
4435 /*
4436  * AlterTableGetLockLevel
4437  *
4438  * Sets the overall lock level required for the supplied list of subcommands.
4439  * Policy for doing this set according to needs of AlterTable(), see
4440  * comments there for overall explanation.
4441  *
4442  * Function is called before and after parsing, so it must give same
4443  * answer each time it is called. Some subcommands are transformed
4444  * into other subcommand types, so the transform must never be made to a
4445  * lower lock level than previously assigned. All transforms are noted below.
4446  *
4447  * Since this is called before we lock the table we cannot use table metadata
4448  * to influence the type of lock we acquire.
4449  *
4450  * There should be no lockmodes hardcoded into the subcommand functions. All
4451  * lockmode decisions for ALTER TABLE are made here only. The one exception is
4452  * ALTER TABLE RENAME which is treated as a different statement type T_RenameStmt
4453  * and does not travel through this section of code and cannot be combined with
4454  * any of the subcommands given here.
4455  *
4456  * Note that Hot Standby only knows about AccessExclusiveLocks on the primary
4457  * so any changes that might affect SELECTs running on standbys need to use
4458  * AccessExclusiveLocks even if you think a lesser lock would do, unless you
4459  * have a solution for that also.
4460  *
4461  * Also note that pg_dump uses only an AccessShareLock, meaning that anything
4462  * that takes a lock less than AccessExclusiveLock can change object definitions
4463  * while pg_dump is running. Be careful to check that the appropriate data is
4464  * derived by pg_dump using an MVCC snapshot, rather than syscache lookups,
4465  * otherwise we might end up with an inconsistent dump that can't restore.
4466  */
4467 LOCKMODE
4469 {
4470  /*
4471  * This only works if we read catalog tables using MVCC snapshots.
4472  */
4473  ListCell *lcmd;
4475 
4476  foreach(lcmd, cmds)
4477  {
4478  AlterTableCmd *cmd = (AlterTableCmd *) lfirst(lcmd);
4479  LOCKMODE cmd_lockmode = AccessExclusiveLock; /* default for compiler */
4480 
4481  switch (cmd->subtype)
4482  {
4483  /*
4484  * These subcommands rewrite the heap, so require full locks.
4485  */
4486  case AT_AddColumn: /* may rewrite heap, in some cases and visible
4487  * to SELECT */
4488  case AT_SetAccessMethod: /* must rewrite heap */
4489  case AT_SetTableSpace: /* must rewrite heap */
4490  case AT_AlterColumnType: /* must rewrite heap */
4491  cmd_lockmode = AccessExclusiveLock;
4492  break;
4493 
4494  /*
4495  * These subcommands may require addition of toast tables. If
4496  * we add a toast table to a table currently being scanned, we
4497  * might miss data added to the new toast table by concurrent
4498  * insert transactions.
4499  */
4500  case AT_SetStorage: /* may add toast tables, see
4501  * ATRewriteCatalogs() */
4502  cmd_lockmode = AccessExclusiveLock;
4503  break;
4504 
4505  /*
4506  * Removing constraints can affect SELECTs that have been
4507  * optimized assuming the constraint holds true. See also
4508  * CloneFkReferenced.
4509  */
4510  case AT_DropConstraint: /* as DROP INDEX */
4511  case AT_DropNotNull: /* may change some SQL plans */
4512  cmd_lockmode = AccessExclusiveLock;
4513  break;
4514 
4515  /*
4516  * Subcommands that may be visible to concurrent SELECTs
4517  */
4518  case AT_DropColumn: /* change visible to SELECT */
4519  case AT_AddColumnToView: /* CREATE VIEW */
4520  case AT_DropOids: /* used to equiv to DropColumn */
4521  case AT_EnableAlwaysRule: /* may change SELECT rules */
4522  case AT_EnableReplicaRule: /* may change SELECT rules */
4523  case AT_EnableRule: /* may change SELECT rules */
4524  case AT_DisableRule: /* may change SELECT rules */
4525  cmd_lockmode = AccessExclusiveLock;
4526  break;
4527 
4528  /*
4529  * Changing owner may remove implicit SELECT privileges
4530  */
4531  case AT_ChangeOwner: /* change visible to SELECT */
4532  cmd_lockmode = AccessExclusiveLock;
4533  break;
4534 
4535  /*
4536  * Changing foreign table options may affect optimization.
4537  */
4538  case AT_GenericOptions:
4540  cmd_lockmode = AccessExclusiveLock;
4541  break;
4542 
4543  /*
4544  * These subcommands affect write operations only.
4545  */
4546  case AT_EnableTrig:
4547  case AT_EnableAlwaysTrig:
4548  case AT_EnableReplicaTrig:
4549  case AT_EnableTrigAll:
4550  case AT_EnableTrigUser:
4551  case AT_DisableTrig:
4552  case AT_DisableTrigAll:
4553  case AT_DisableTrigUser:
4554  cmd_lockmode = ShareRowExclusiveLock;
4555  break;
4556 
4557  /*
4558  * These subcommands affect write operations only. XXX
4559  * Theoretically, these could be ShareRowExclusiveLock.
4560  */
4561  case AT_ColumnDefault:
4563  case AT_AlterConstraint:
4564  case AT_AddIndex: /* from ADD CONSTRAINT */
4565  case AT_AddIndexConstraint:
4566  case AT_ReplicaIdentity:
4567  case AT_SetNotNull:
4568  case AT_EnableRowSecurity:
4569  case AT_DisableRowSecurity:
4570  case AT_ForceRowSecurity:
4571  case AT_NoForceRowSecurity:
4572  case AT_AddIdentity:
4573  case AT_DropIdentity:
4574  case AT_SetIdentity:
4575  case AT_SetExpression:
4576  case AT_DropExpression:
4577  case AT_SetCompression:
4578  cmd_lockmode = AccessExclusiveLock;
4579  break;
4580 
4581  case AT_AddConstraint:
4582  case AT_ReAddConstraint: /* becomes AT_AddConstraint */
4583  case AT_ReAddDomainConstraint: /* becomes AT_AddConstraint */
4584  if (IsA(cmd->def, Constraint))
4585  {
4586  Constraint *con = (Constraint *) cmd->def;
4587 
4588  switch (con->contype)
4589  {
4590  case CONSTR_EXCLUSION:
4591  case CONSTR_PRIMARY:
4592  case CONSTR_UNIQUE:
4593 
4594  /*
4595  * Cases essentially the same as CREATE INDEX. We
4596  * could reduce the lock strength to ShareLock if
4597  * we can work out how to allow concurrent catalog
4598  * updates. XXX Might be set down to
4599  * ShareRowExclusiveLock but requires further
4600  * analysis.
4601  */
4602  cmd_lockmode = AccessExclusiveLock;
4603  break;
4604  case CONSTR_FOREIGN:
4605 
4606  /*
4607  * We add triggers to both tables when we add a
4608  * Foreign Key, so the lock level must be at least
4609  * as strong as CREATE TRIGGER.
4610  */
4611  cmd_lockmode = ShareRowExclusiveLock;
4612  break;
4613 
4614  default:
4615  cmd_lockmode = AccessExclusiveLock;
4616  }
4617  }
4618  break;
4619 
4620  /*
4621  * These subcommands affect inheritance behaviour. Queries
4622  * started before us will continue to see the old inheritance
4623  * behaviour, while queries started after we commit will see
4624  * new behaviour. No need to prevent reads or writes to the
4625  * subtable while we hook it up though. Changing the TupDesc
4626  * may be a problem, so keep highest lock.
4627  */
4628  case AT_AddInherit:
4629  case AT_DropInherit:
4630  cmd_lockmode = AccessExclusiveLock;
4631  break;
4632 
4633  /*
4634  * These subcommands affect implicit row type conversion. They
4635  * have affects similar to CREATE/DROP CAST on queries. don't
4636  * provide for invalidating parse trees as a result of such
4637  * changes, so we keep these at AccessExclusiveLock.
4638  */
4639  case AT_AddOf:
4640  case AT_DropOf:
4641  cmd_lockmode = AccessExclusiveLock;
4642  break;
4643 
4644  /*
4645  * Only used by CREATE OR REPLACE VIEW which must conflict
4646  * with an SELECTs currently using the view.
4647  */
4648  case AT_ReplaceRelOptions:
4649  cmd_lockmode = AccessExclusiveLock;
4650  break;
4651 
4652  /*
4653  * These subcommands affect general strategies for performance
4654  * and maintenance, though don't change the semantic results
4655  * from normal data reads and writes. Delaying an ALTER TABLE
4656  * behind currently active writes only delays the point where
4657  * the new strategy begins to take effect, so there is no
4658  * benefit in waiting. In this case the minimum restriction
4659  * applies: we don't currently allow concurrent catalog
4660  * updates.
4661  */
4662  case AT_SetStatistics: /* Uses MVCC in getTableAttrs() */
4663  case AT_ClusterOn: /* Uses MVCC in getIndexes() */
4664  case AT_DropCluster: /* Uses MVCC in getIndexes() */
4665  case AT_SetOptions: /* Uses MVCC in getTableAttrs() */
4666  case AT_ResetOptions: /* Uses MVCC in getTableAttrs() */
4667  cmd_lockmode = ShareUpdateExclusiveLock;
4668  break;
4669 
4670  case AT_SetLogged:
4671  case AT_SetUnLogged:
4672  cmd_lockmode = AccessExclusiveLock;
4673  break;
4674 
4675  case AT_ValidateConstraint: /* Uses MVCC in getConstraints() */
4676  cmd_lockmode = ShareUpdateExclusiveLock;
4677  break;
4678 
4679  /*
4680  * Rel options are more complex than first appears. Options
4681  * are set here for tables, views and indexes; for historical
4682  * reasons these can all be used with ALTER TABLE, so we can't
4683  * decide between them using the basic grammar.
4684  */
4685  case AT_SetRelOptions: /* Uses MVCC in getIndexes() and
4686  * getTables() */
4687  case AT_ResetRelOptions: /* Uses MVCC in getIndexes() and
4688  * getTables() */
4689  cmd_lockmode = AlterTableGetRelOptionsLockLevel((List *) cmd->def);
4690  break;
4691 
4692  case AT_AttachPartition:
4693  cmd_lockmode = ShareUpdateExclusiveLock;
4694  break;
4695 
4696  case AT_DetachPartition:
4697  if (((PartitionCmd *) cmd->def)->concurrent)
4698  cmd_lockmode = ShareUpdateExclusiveLock;
4699  else
4700  cmd_lockmode = AccessExclusiveLock;
4701  break;
4702 
4704  cmd_lockmode = ShareUpdateExclusiveLock;
4705  break;
4706 
4707  case AT_CheckNotNull:
4708 
4709  /*
4710  * This only examines the table's schema; but lock must be
4711  * strong enough to prevent concurrent DROP NOT NULL.
4712  */
4713  cmd_lockmode = AccessShareLock;
4714  break;
4715 
4716  default: /* oops */
4717  elog(ERROR, "unrecognized alter table type: %d",
4718  (int) cmd->subtype);
4719  break;
4720  }
4721 
4722  /*
4723  * Take the greatest lockmode from any subcommand
4724  */
4725  if (cmd_lockmode > lockmode)
4726  lockmode = cmd_lockmode;
4727  }
4728 
4729  return lockmode;
4730 }
4731 
4732 /*
4733  * ATController provides top level control over the phases.
4734  *
4735  * parsetree is passed in to allow it to be passed to event triggers
4736  * when requested.
4737  */
4738 static void
4740  Relation rel, List *cmds, bool recurse, LOCKMODE lockmode,
4742 {
4743  List *wqueue = NIL;
4744  ListCell *lcmd;
4745 
4746  /* Phase 1: preliminary examination of commands, create work queue */
4747  foreach(lcmd, cmds)
4748  {
4749  AlterTableCmd *cmd = (AlterTableCmd *) lfirst(lcmd);
4750 
4751  ATPrepCmd(&wqueue, rel, cmd, recurse, false, lockmode, context);
4752  }
4753 
4754  /* Close the relation, but keep lock until commit */
4755  relation_close(rel, NoLock);
4756 
4757  /* Phase 2: update system catalogs */
4758  ATRewriteCatalogs(&wqueue, lockmode, context);
4759 
4760  /* Phase 3: scan/rewrite tables as needed, and run afterStmts */
4761  ATRewriteTables(parsetree, &wqueue, lockmode, context);
4762 }
4763 
4764 /*
4765  * ATPrepCmd
4766  *
4767  * Traffic cop for ALTER TABLE Phase 1 operations, including simple
4768  * recursion and permission checks.
4769  *
4770  * Caller must have acquired appropriate lock type on relation already.
4771  * This lock should be held until commit.
4772  */
4773 static void
4774 ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd,
4775  bool recurse, bool recursing, LOCKMODE lockmode,
4777 {
4778  AlteredTableInfo *tab;
4780 
4781  /* Find or create work queue entry for this table */
4782  tab = ATGetQueueEntry(wqueue, rel);
4783 
4784  /*
4785  * Disallow any ALTER TABLE other than ALTER TABLE DETACH FINALIZE on
4786  * partitions that are pending detach.
4787  */
4788  if (rel->rd_rel->relispartition &&
4791  ereport(ERROR,
4792  errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
4793  errmsg("cannot alter partition \"%s\" with an incomplete detach",
4795  errhint("Use ALTER TABLE ... DETACH PARTITION ... FINALIZE to complete the pending detach operation."));
4796 
4797  /*
4798  * Copy the original subcommand for each table, so we can scribble on it.
4799  * This avoids conflicts when different child tables need to make
4800  * different parse transformations (for example, the same column may have
4801  * different column numbers in different children).
4802  */
4803  cmd = copyObject(cmd);
4804 
4805  /*
4806  * Do permissions and relkind checking, recursion to child tables if
4807  * needed, and any additional phase-1 processing needed. (But beware of
4808  * adding any processing that looks at table details that another
4809  * subcommand could change. In some cases we reject multiple subcommands
4810  * that could try to change the same state in contrary ways.)
4811  */
4812  switch (cmd->subtype)
4813  {
4814  case AT_AddColumn: /* ADD COLUMN */
4815  ATSimplePermissions(cmd->subtype, rel,
4818  ATPrepAddColumn(wqueue, rel, recurse, recursing, false, cmd,
4819  lockmode, context);
4820  /* Recursion occurs during execution phase */
4821  pass = AT_PASS_ADD_COL;
4822  break;
4823  case AT_AddColumnToView: /* add column via CREATE OR REPLACE VIEW */
4824  ATSimplePermissions(cmd->subtype, rel, ATT_VIEW);
4825  ATPrepAddColumn(wqueue, rel, recurse, recursing, true, cmd,
4826  lockmode, context);
4827  /* Recursion occurs during execution phase */
4828  pass = AT_PASS_ADD_COL;
4829  break;
4830  case AT_ColumnDefault: /* ALTER COLUMN DEFAULT */
4831 
4832  /*
4833  * We allow defaults on views so that INSERT into a view can have
4834  * default-ish behavior. This works because the rewriter
4835  * substitutes default values into INSERTs before it expands
4836  * rules.
4837  */
4838  ATSimplePermissions(cmd->subtype, rel,
4841  ATSimpleRecursion(wqueue, rel, cmd, recurse, lockmode, context);
4842  /* No command-specific prep needed */
4843  pass = cmd->def ? AT_PASS_ADD_OTHERCONSTR : AT_PASS_DROP;
4844  break;
4845  case AT_CookedColumnDefault: /* add a pre-cooked default */
4846  /* This is currently used only in CREATE TABLE */
4847  /* (so the permission check really isn't necessary) */
4848  ATSimplePermissions(cmd->subtype, rel,
4850  /* This command never recurses */
4851  pass = AT_PASS_ADD_OTHERCONSTR;
4852  break;
4853  case AT_AddIdentity:
4854  ATSimplePermissions(cmd->subtype, rel,
4857  /* Set up recursion for phase 2; no other prep needed */
4858  if (recurse)
4859  cmd->recurse = true;
4860  pass = AT_PASS_ADD_OTHERCONSTR;
4861  break;
4862  case AT_SetIdentity:
4863  ATSimplePermissions(cmd->subtype, rel,
4866  /* Set up recursion for phase 2; no other prep needed */
4867  if (recurse)
4868  cmd->recurse = true;
4869  /* This should run after AddIdentity, so do it in MISC pass */
4870  pass = AT_PASS_MISC;
4871  break;
4872  case AT_DropIdentity:
4873  ATSimplePermissions(cmd->subtype, rel,
4876  /* Set up recursion for phase 2; no other prep needed */
4877  if (recurse)
4878  cmd->recurse = true;
4879  pass = AT_PASS_DROP;
4880  break;
4881  case AT_DropNotNull: /* ALTER COLUMN DROP NOT NULL */
4882  ATSimplePermissions(cmd->subtype, rel,
4884  ATSimpleRecursion(wqueue, rel, cmd, recurse, lockmode, context);
4885  pass = AT_PASS_DROP;
4886  break;
4887  case AT_SetNotNull: /* ALTER COLUMN SET NOT NULL */
4888  ATSimplePermissions(cmd->subtype, rel,
4890  /* Need command-specific recursion decision */
4891  ATPrepSetNotNull(wqueue, rel, cmd, recurse, recursing,
4892  lockmode, context);
4893  pass = AT_PASS_COL_ATTRS;
4894  break;
4895  case AT_CheckNotNull: /* check column is already marked NOT NULL */
4896  ATSimplePermissions(cmd->subtype, rel,
4898  ATSimpleRecursion(wqueue, rel, cmd, recurse, lockmode, context);
4899  /* No command-specific prep needed */
4900  pass = AT_PASS_COL_ATTRS;
4901  break;
4902  case AT_SetExpression: /* ALTER COLUMN SET EXPRESSION */
4903  ATSimplePermissions(cmd->subtype, rel,
4905  ATSimpleRecursion(wqueue, rel, cmd, recurse, lockmode, context);
4906  pass = AT_PASS_SET_EXPRESSION;
4907  break;
4908  case AT_DropExpression: /* ALTER COLUMN DROP EXPRESSION */
4909  ATSimplePermissions(cmd->subtype, rel,
4911  ATSimpleRecursion(wqueue, rel, cmd, recurse, lockmode, context);
4912  ATPrepDropExpression(rel, cmd, recurse, recursing, lockmode);
4913  pass = AT_PASS_DROP;
4914  break;
4915  case AT_SetStatistics: /* ALTER COLUMN SET STATISTICS */
4916  ATSimplePermissions(cmd->subtype, rel,
4919  ATSimpleRecursion(wqueue, rel, cmd, recurse, lockmode, context);
4920  /* No command-specific prep needed */
4921  pass = AT_PASS_MISC;
4922  break;
4923  case AT_SetOptions: /* ALTER COLUMN SET ( options ) */
4924  case AT_ResetOptions: /* ALTER COLUMN RESET ( options ) */
4925  ATSimplePermissions(cmd->subtype, rel,
4928  /* This command never recurses */
4929  pass = AT_PASS_MISC;
4930  break;
4931  case AT_SetStorage: /* ALTER COLUMN SET STORAGE */
4932  ATSimplePermissions(cmd->subtype, rel,
4935  ATSimpleRecursion(wqueue, rel, cmd, recurse, lockmode, context);
4936  /* No command-specific prep needed */
4937  pass = AT_PASS_MISC;
4938  break;
4939  case AT_SetCompression: /* ALTER COLUMN SET COMPRESSION */
4940  ATSimplePermissions(cmd->subtype, rel,
4942  /* This command never recurses */
4943  /* No command-specific prep needed */
4944  pass = AT_PASS_MISC;
4945  break;
4946  case AT_DropColumn: /* DROP COLUMN */
4947  ATSimplePermissions(cmd->subtype, rel,
4950  ATPrepDropColumn(wqueue, rel, recurse, recursing, cmd,
4951  lockmode, context);
4952  /* Recursion occurs during execution phase */
4953  pass = AT_PASS_DROP;
4954  break;
4955  case AT_AddIndex: /* ADD INDEX */
4957  /* This command never recurses */
4958  /* No command-specific prep needed */
4959  pass = AT_PASS_ADD_INDEX;
4960  break;
4961  case AT_AddConstraint: /* ADD CONSTRAINT */
4962  ATSimplePermissions(cmd->subtype, rel,
4964  /* Recursion occurs during execution phase */
4965  /* No command-specific prep needed except saving recurse flag */
4966  if (recurse)
4967  cmd->recurse = true;
4968  pass = AT_PASS_ADD_CONSTR;
4969  break;
4970  case AT_AddIndexConstraint: /* ADD CONSTRAINT USING INDEX */
4972  /* This command never recurses */
4973  /* No command-specific prep needed */
4974  pass = AT_PASS_ADD_INDEXCONSTR;
4975  break;
4976  case AT_DropConstraint: /* DROP CONSTRAINT */
4977  ATSimplePermissions(cmd->subtype, rel,
4979  ATCheckPartitionsNotInUse(rel, lockmode);
4980  /* Other recursion occurs during execution phase */
4981  /* No command-specific prep needed except saving recurse flag */
4982  if (recurse)
4983  cmd->recurse = true;
4984  pass = AT_PASS_DROP;
4985  break;
4986  case AT_AlterColumnType: /* ALTER COLUMN TYPE */
4987  ATSimplePermissions(cmd->subtype, rel,
4990  /* See comments for ATPrepAlterColumnType */
4991  cmd = ATParseTransformCmd(wqueue, tab, rel, cmd, recurse, lockmode,
4993  Assert(cmd != NULL);
4994  /* Performs own recursion */
4995  ATPrepAlterColumnType(wqueue, tab, rel, recurse, recursing, cmd,
4996  lockmode, context);
4997  pass = AT_PASS_ALTER_TYPE;
4998  break;
5001  /* This command never recurses */
5002  /* No command-specific prep needed */
5003  pass = AT_PASS_MISC;
5004  break;
5005  case AT_ChangeOwner: /* ALTER OWNER */
5006  /* This command never recurses */
5007  /* No command-specific prep needed */
5008  pass = AT_PASS_MISC;
5009  break;
5010  case AT_ClusterOn: /* CLUSTER ON */
5011  case AT_DropCluster: /* SET WITHOUT CLUSTER */
5012  ATSimplePermissions(cmd->subtype, rel,
5014  /* These commands never recurse */
5015  /* No command-specific prep needed */
5016  pass = AT_PASS_MISC;
5017  break;
5018  case AT_SetLogged: /* SET LOGGED */
5019  case AT_SetUnLogged: /* SET UNLOGGED */
5021  if (tab->chgPersistence)
5022  ereport(ERROR,
5023  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
5024  errmsg("cannot change persistence setting twice")));
5025  ATPrepChangePersistence(tab, rel, cmd->subtype == AT_SetLogged);
5026  pass = AT_PASS_MISC;
5027  break;
5028  case AT_DropOids: /* SET WITHOUT OIDS */
5029  ATSimplePermissions(cmd->subtype, rel,
5031  pass = AT_PASS_DROP;
5032  break;
5033  case AT_SetAccessMethod: /* SET ACCESS METHOD */
5034  ATSimplePermissions(cmd->subtype, rel,
5036 
5037  /* check if another access method change was already requested */
5038  if (tab->chgAccessMethod)
5039  ereport(ERROR,
5040  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
5041  errmsg("cannot have multiple SET ACCESS METHOD subcommands")));
5042 
5043  ATPrepSetAccessMethod(tab, rel, cmd->name);
5044  pass = AT_PASS_MISC; /* does not matter; no work in Phase 2 */
5045  break;
5046  case AT_SetTableSpace: /* SET TABLESPACE */
5049  /* This command never recurses */
5050  ATPrepSetTableSpace(tab, rel, cmd->name, lockmode);
5051  pass = AT_PASS_MISC; /* doesn't actually matter */
5052  break;
5053  case AT_SetRelOptions: /* SET (...) */
5054  case AT_ResetRelOptions: /* RESET (...) */
5055  case AT_ReplaceRelOptions: /* reset them all, then set just these */
5056  ATSimplePermissions(cmd->subtype, rel,
5059  /* This command never recurses */
5060  /* No command-specific prep needed */
5061  pass = AT_PASS_MISC;
5062  break;
5063  case AT_AddInherit: /* INHERIT */
5064  ATSimplePermissions(cmd->subtype, rel,
5066  /* This command never recurses */
5067  ATPrepAddInherit(rel);
5068  pass = AT_PASS_MISC;
5069  break;
5070  case AT_DropInherit: /* NO INHERIT */
5071  ATSimplePermissions(cmd->subtype, rel,
5073  /* This command never recurses */
5074  /* No command-specific prep needed */
5075  pass = AT_PASS_MISC;
5076  break;
5077  case AT_AlterConstraint: /* ALTER CONSTRAINT */
5078  ATSimplePermissions(cmd->subtype, rel,
5080  /* Recursion occurs during execution phase */
5081  pass = AT_PASS_MISC;
5082  break;
5083  case AT_ValidateConstraint: /* VALIDATE CONSTRAINT */
5084  ATSimplePermissions(cmd->subtype, rel,
5086  /* Recursion occurs during execution phase */
5087  /* No command-specific prep needed except saving recurse flag */
5088  if (recurse)
5089  cmd->recurse = true;
5090  pass = AT_PASS_MISC;
5091  break;
5092  case AT_ReplicaIdentity: /* REPLICA IDENTITY ... */
5093  ATSimplePermissions(cmd->subtype, rel,
5095  pass = AT_PASS_MISC;
5096  /* This command never recurses */
5097  /* No command-specific prep needed */
5098  break;
5099  case AT_EnableTrig: /* ENABLE TRIGGER variants */
5100  case AT_EnableAlwaysTrig:
5101  case AT_EnableReplicaTrig:
5102  case AT_EnableTrigAll:
5103  case AT_EnableTrigUser:
5104  case AT_DisableTrig: /* DISABLE TRIGGER variants */
5105  case AT_DisableTrigAll:
5106  case AT_DisableTrigUser:
5107  ATSimplePermissions(cmd->subtype, rel,
5109  /* Set up recursion for phase 2; no other prep needed */
5110  if (recurse)
5111  cmd->recurse = true;
5112  pass = AT_PASS_MISC;
5113  break;
5114  case AT_EnableRule: /* ENABLE/DISABLE RULE variants */
5115  case AT_EnableAlwaysRule:
5116  case AT_EnableReplicaRule:
5117  case AT_DisableRule:
5118  case AT_AddOf: /* OF */
5119  case AT_DropOf: /* NOT OF */
5120  case AT_EnableRowSecurity:
5121  case AT_DisableRowSecurity:
5122  case AT_ForceRowSecurity:
5123  case AT_NoForceRowSecurity:
5124  ATSimplePermissions(cmd->subtype, rel,
5126  /* These commands never recurse */
5127  /* No command-specific prep needed */
5128  pass = AT_PASS_MISC;
5129  break;
5130  case AT_GenericOptions:
5132  /* No command-specific prep needed */
5133  pass = AT_PASS_MISC;
5134  break;
5135  case AT_AttachPartition:
5136  ATSimplePermissions(cmd->subtype, rel,
5138  /* No command-specific prep needed */
5139  pass = AT_PASS_MISC;
5140  break;
5141  case AT_DetachPartition:
5143  /* No command-specific prep needed */
5144  pass = AT_PASS_MISC;
5145  break;
5148  /* No command-specific prep needed */
5149  pass = AT_PASS_MISC;
5150  break;
5151  default: /* oops */
5152  elog(ERROR, "unrecognized alter table type: %d",
5153  (int) cmd->subtype);
5154  pass = AT_PASS_UNSET; /* keep compiler quiet */
5155  break;
5156  }
5157  Assert(pass > AT_PASS_UNSET);
5158 
5159  /* Add the subcommand to the appropriate list for phase 2 */
5160  tab->subcmds[pass] = lappend(tab->subcmds[pass], cmd);
5161 }
5162 
5163 /*
5164  * ATRewriteCatalogs
5165  *
5166  * Traffic cop for ALTER TABLE Phase 2 operations. Subcommands are
5167  * dispatched in a "safe" execution order (designed to avoid unnecessary
5168  * conflicts).
5169  */
5170 static void
5171 ATRewriteCatalogs(List **wqueue, LOCKMODE lockmode,
5173 {
5174  ListCell *ltab;
5175 
5176  /*
5177  * We process all the tables "in parallel", one pass at a time. This is
5178  * needed because we may have to propagate work from one table to another
5179  * (specifically, ALTER TYPE on a foreign key's PK has to dispatch the
5180  * re-adding of the foreign key constraint to the other table). Work can
5181  * only be propagated into later passes, however.
5182  */
5183  for (AlterTablePass pass = 0; pass < AT_NUM_PASSES; pass++)
5184  {
5185  /* Go through each table that needs to be processed */
5186  foreach(ltab, *wqueue)
5187  {
5188  AlteredTableInfo *tab = (AlteredTableInfo *) lfirst(ltab);
5189  List *subcmds = tab->subcmds[pass];
5190  ListCell *lcmd;
5191 
5192  if (subcmds == NIL)
5193  continue;
5194 
5195  /*
5196  * Open the relation and store it in tab. This allows subroutines
5197  * close and reopen, if necessary. Appropriate lock was obtained
5198  * by phase 1, needn't get it again.
5199  */
5200  tab->rel = relation_open(tab->relid, NoLock);
5201 
5202  foreach(lcmd, subcmds)
5203  ATExecCmd(wqueue, tab,
5204  lfirst_node(AlterTableCmd, lcmd),
5205  lockmode, pass, context);
5206 
5207  /*
5208  * After the ALTER TYPE or SET EXPRESSION pass, do cleanup work
5209  * (this is not done in ATExecAlterColumnType since it should be
5210  * done only once if multiple columns of a table are altered).
5211  */
5212  if (pass == AT_PASS_ALTER_TYPE || pass == AT_PASS_SET_EXPRESSION)
5213  ATPostAlterTypeCleanup(wqueue, tab, lockmode);
5214 
5215  if (tab->rel)
5216  {
5217  relation_close(tab->rel, NoLock);
5218  tab->rel = NULL;
5219  }
5220  }
5221  }
5222 
5223  /* Check to see if a toast table must be added. */
5224  foreach(ltab, *wqueue)
5225  {
5226  AlteredTableInfo *tab = (AlteredTableInfo *) lfirst(ltab);
5227 
5228  /*
5229  * If the table is source table of ATTACH PARTITION command, we did
5230  * not modify anything about it that will change its toasting
5231  * requirement, so no need to check.
5232  */
5233  if (((tab->relkind == RELKIND_RELATION ||
5234  tab->relkind == RELKIND_PARTITIONED_TABLE) &&
5235  tab->partition_constraint == NULL) ||
5236  tab->relkind == RELKIND_MATVIEW)
5237  AlterTableCreateToastTable(tab->relid, (Datum) 0, lockmode);
5238  }
5239 }
5240 
5241 /*
5242  * ATExecCmd: dispatch a subcommand to appropriate execution routine
5243  */
5244 static void
5246  AlterTableCmd *cmd, LOCKMODE lockmode, AlterTablePass cur_pass,
5248 {
5250  Relation rel = tab->rel;
5251 
5252  switch (cmd->subtype)
5253  {
5254  case AT_AddColumn: /* ADD COLUMN */
5255  case AT_AddColumnToView: /* add column via CREATE OR REPLACE VIEW */
5256  address = ATExecAddColumn(wqueue, tab, rel, &cmd,
5257  cmd->recurse, false,
5258  lockmode, cur_pass, context);
5259  break;
5260  case AT_ColumnDefault: /* ALTER COLUMN DEFAULT */
5261  address = ATExecColumnDefault(rel, cmd->name, cmd->def, lockmode);
5262  break;
5263  case AT_CookedColumnDefault: /* add a pre-cooked default */
5264  address = ATExecCookedColumnDefault(rel, cmd->num, cmd->def);
5265  break;
5266  case AT_AddIdentity:
5267  cmd = ATParseTransformCmd(wqueue, tab, rel, cmd, false, lockmode,
5268  cur_pass, context);
5269  Assert(cmd != NULL);
5270  address = ATExecAddIdentity(rel, cmd->name, cmd->def, lockmode, cmd->recurse, false);
5271  break;
5272  case AT_SetIdentity:
5273  cmd = ATParseTransformCmd(wqueue, tab, rel, cmd, false, lockmode,
5274  cur_pass, context);
5275  Assert(cmd != NULL);
5276  address = ATExecSetIdentity(rel, cmd->name, cmd->def, lockmode, cmd->recurse, false);
5277  break;
5278  case AT_DropIdentity:
5279  address = ATExecDropIdentity(rel, cmd->name, cmd->missing_ok, lockmode, cmd->recurse, false);
5280  break;
5281  case AT_DropNotNull: /* ALTER COLUMN DROP NOT NULL */
5282  address = ATExecDropNotNull(rel, cmd->name, lockmode);
5283  break;
5284  case AT_SetNotNull: /* ALTER COLUMN SET NOT NULL */
5285  address = ATExecSetNotNull(tab, rel, cmd->name, lockmode);
5286  break;
5287  case AT_CheckNotNull: /* check column is already marked NOT NULL */
5288  ATExecCheckNotNull(tab, rel, cmd->name, lockmode);
5289  break;
5290  case AT_SetExpression:
5291  address = ATExecSetExpression(tab, rel, cmd->name, cmd->def, lockmode);
5292  break;
5293  case AT_DropExpression:
5294  address = ATExecDropExpression(rel, cmd->name, cmd->missing_ok, lockmode);
5295  break;
5296  case AT_SetStatistics: /* ALTER COLUMN SET STATISTICS */
5297  address = ATExecSetStatistics(rel, cmd->name, cmd->num, cmd->def, lockmode);
5298  break;
5299  case AT_SetOptions: /* ALTER COLUMN SET ( options ) */
5300  address = ATExecSetOptions(rel, cmd->name, cmd->def, false, lockmode);
5301  break;
5302  case AT_ResetOptions: /* ALTER COLUMN RESET ( options ) */
5303  address = ATExecSetOptions(rel, cmd->name, cmd->def, true, lockmode);
5304  break;
5305  case AT_SetStorage: /* ALTER COLUMN SET STORAGE */
5306  address = ATExecSetStorage(rel, cmd->name, cmd->def, lockmode);
5307  break;
5308  case AT_SetCompression: /* ALTER COLUMN SET COMPRESSION */
5309  address = ATExecSetCompression(rel, cmd->name, cmd->def,
5310  lockmode);
5311  break;
5312  case AT_DropColumn: /* DROP COLUMN */
5313  address = ATExecDropColumn(wqueue, rel, cmd->name,
5314  cmd->behavior, cmd->recurse, false,
5315  cmd->missing_ok, lockmode,
5316  NULL);
5317  break;
5318  case AT_AddIndex: /* ADD INDEX */
5319  address = ATExecAddIndex(tab, rel, (IndexStmt *) cmd->def, false,
5320  lockmode);
5321  break;
5322  case AT_ReAddIndex: /* ADD INDEX */
5323  address = ATExecAddIndex(tab, rel, (IndexStmt *) cmd->def, true,
5324  lockmode);
5325  break;
5326  case AT_ReAddStatistics: /* ADD STATISTICS */
5327  address = ATExecAddStatistics(tab, rel, (CreateStatsStmt *) cmd->def,
5328  true, lockmode);
5329  break;
5330  case AT_AddConstraint: /* ADD CONSTRAINT */
5331  /* Transform the command only during initial examination */
5332  if (cur_pass == AT_PASS_ADD_CONSTR)
5333  cmd = ATParseTransformCmd(wqueue, tab, rel, cmd,
5334  cmd->recurse, lockmode,
5335  cur_pass, context);
5336  /* Depending on constraint type, might be no more work to do now */
5337  if (cmd != NULL)
5338  address =
5339  ATExecAddConstraint(wqueue, tab, rel,
5340  (Constraint *) cmd->def,
5341  cmd->recurse, false, lockmode);
5342  break;
5343  case AT_ReAddConstraint: /* Re-add pre-existing check constraint */
5344  address =
5345  ATExecAddConstraint(wqueue, tab, rel, (Constraint *) cmd->def,
5346  true, true, lockmode);
5347  break;
5348  case AT_ReAddDomainConstraint: /* Re-add pre-existing domain check
5349  * constraint */
5350  address =
5351  AlterDomainAddConstraint(((AlterDomainStmt *) cmd->def)->typeName,
5352  ((AlterDomainStmt *) cmd->def)->def,
5353  NULL);
5354  break;
5355  case AT_ReAddComment: /* Re-add existing comment */
5356  address = CommentObject((CommentStmt *) cmd->def);
5357  break;
5358  case AT_AddIndexConstraint: /* ADD CONSTRAINT USING INDEX */
5359  address = ATExecAddIndexConstraint(tab, rel, (IndexStmt *) cmd->def,
5360  lockmode);
5361  break;
5362  case AT_AlterConstraint: /* ALTER CONSTRAINT */
5363  address = ATExecAlterConstraint(rel, cmd, false, false, lockmode);
5364  break;
5365  case AT_ValidateConstraint: /* VALIDATE CONSTRAINT */
5366  address = ATExecValidateConstraint(wqueue, rel, cmd->name, cmd->recurse,
5367  false, lockmode);
5368  break;
5369  case AT_DropConstraint: /* DROP CONSTRAINT */
5370  ATExecDropConstraint(rel, cmd->name, cmd->behavior,
5371  cmd->recurse, false,
5372  cmd->missing_ok, lockmode);
5373  break;
5374  case AT_AlterColumnType: /* ALTER COLUMN TYPE */
5375  /* parse transformation was done earlier */
5376  address = ATExecAlterColumnType(tab, rel, cmd, lockmode);
5377  break;
5378  case AT_AlterColumnGenericOptions: /* ALTER COLUMN OPTIONS */
5379  address =
5381  (List *) cmd->def, lockmode);
5382  break;
5383  case AT_ChangeOwner: /* ALTER OWNER */
5385  get_rolespec_oid(cmd->newowner, false),
5386  false, lockmode);
5387  break;
5388  case AT_ClusterOn: /* CLUSTER ON */
5389  address = ATExecClusterOn(rel, cmd->name, lockmode);
5390  break;
5391  case AT_DropCluster: /* SET WITHOUT CLUSTER */
5392  ATExecDropCluster(rel, lockmode);
5393  break;
5394  case AT_SetLogged: /* SET LOGGED */
5395  case AT_SetUnLogged: /* SET UNLOGGED */
5396  break;
5397  case AT_DropOids: /* SET WITHOUT OIDS */
5398  /* nothing to do here, oid columns don't exist anymore */
5399  break;
5400  case AT_SetAccessMethod: /* SET ACCESS METHOD */
5401 
5402  /*
5403  * Only do this for partitioned tables, for which this is just a
5404  * catalog change. Tables with storage are handled by Phase 3.
5405  */
5406  if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE &&
5407  tab->chgAccessMethod)
5409  break;
5410  case AT_SetTableSpace: /* SET TABLESPACE */
5411 
5412  /*
5413  * Only do this for partitioned tables and indexes, for which this
5414  * is just a catalog change. Other relation types which have
5415  * storage are handled by Phase 3.
5416  */
5417  if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE ||
5418  rel->rd_rel->relkind == RELKIND_PARTITIONED_INDEX)
5420 
5421  break;
5422  case AT_SetRelOptions: /* SET (...) */
5423  case AT_ResetRelOptions: /* RESET (...) */
5424  case AT_ReplaceRelOptions: /* replace entire option list */
5425  ATExecSetRelOptions(rel, (List *) cmd->def, cmd->subtype, lockmode);
5426  break;
5427  case AT_EnableTrig: /* ENABLE TRIGGER name */
5428  ATExecEnableDisableTrigger(rel, cmd->name,
5429  TRIGGER_FIRES_ON_ORIGIN, false,
5430  cmd->recurse,
5431  lockmode);
5432  break;
5433  case AT_EnableAlwaysTrig: /* ENABLE ALWAYS TRIGGER name */
5434  ATExecEnableDisableTrigger(rel, cmd->name,
5435  TRIGGER_FIRES_ALWAYS, false,
5436  cmd->recurse,
5437  lockmode);
5438  break;
5439  case AT_EnableReplicaTrig: /* ENABLE REPLICA TRIGGER name */
5440  ATExecEnableDisableTrigger(rel, cmd->name,
5441  TRIGGER_FIRES_ON_REPLICA, false,
5442  cmd->recurse,
5443  lockmode);
5444  break;
5445  case AT_DisableTrig: /* DISABLE TRIGGER name */
5446  ATExecEnableDisableTrigger(rel, cmd->name,
5447  TRIGGER_DISABLED, false,
5448  cmd->recurse,
5449  lockmode);
5450  break;
5451  case AT_EnableTrigAll: /* ENABLE TRIGGER ALL */
5452  ATExecEnableDisableTrigger(rel, NULL,
5453  TRIGGER_FIRES_ON_ORIGIN, false,
5454  cmd->recurse,
5455  lockmode);
5456  break;
5457  case AT_DisableTrigAll: /* DISABLE TRIGGER ALL */
5458  ATExecEnableDisableTrigger(rel, NULL,
5459  TRIGGER_DISABLED, false,
5460  cmd->recurse,
5461  lockmode);
5462  break;
5463  case AT_EnableTrigUser: /* ENABLE TRIGGER USER */
5464  ATExecEnableDisableTrigger(rel, NULL,
5466  cmd->recurse,
5467  lockmode);
5468  break;
5469  case AT_DisableTrigUser: /* DISABLE TRIGGER USER */
5470  ATExecEnableDisableTrigger(rel, NULL,
5471  TRIGGER_DISABLED, true,
5472  cmd->recurse,
5473  lockmode);
5474  break;
5475 
5476  case AT_EnableRule: /* ENABLE RULE name */
5477  ATExecEnableDisableRule(rel, cmd->name,
5478  RULE_FIRES_ON_ORIGIN, lockmode);
5479  break;
5480  case AT_EnableAlwaysRule: /* ENABLE ALWAYS RULE name */
5481  ATExecEnableDisableRule(rel, cmd->name,
5482  RULE_FIRES_ALWAYS, lockmode);
5483  break;
5484  case AT_EnableReplicaRule: /* ENABLE REPLICA RULE name */
5485  ATExecEnableDisableRule(rel, cmd->name,
5486  RULE_FIRES_ON_REPLICA, lockmode);
5487  break;
5488  case AT_DisableRule: /* DISABLE RULE name */
5489  ATExecEnableDisableRule(rel, cmd->name,
5490  RULE_DISABLED, lockmode);
5491  break;
5492 
5493  case AT_AddInherit:
5494  address = ATExecAddInherit(rel, (RangeVar *) cmd->def, lockmode);
5495  break;
5496  case AT_DropInherit:
5497  address = ATExecDropInherit(rel, (RangeVar *) cmd->def, lockmode);
5498  break;
5499  case AT_AddOf:
5500  address = ATExecAddOf(rel, (TypeName *) cmd->def, lockmode);
5501  break;
5502  case AT_DropOf:
5503  ATExecDropOf(rel, lockmode);
5504  break;
5505  case AT_ReplicaIdentity:
5506  ATExecReplicaIdentity(rel, (ReplicaIdentityStmt *) cmd->def, lockmode);
5507  break;
5508  case AT_EnableRowSecurity:
5509  ATExecSetRowSecurity(rel, true);
5510  break;
5511  case AT_DisableRowSecurity:
5512  ATExecSetRowSecurity(rel, false);
5513  break;
5514  case AT_ForceRowSecurity:
5515  ATExecForceNoForceRowSecurity(rel, true);
5516  break;
5517  case AT_NoForceRowSecurity:
5518  ATExecForceNoForceRowSecurity(rel, false);
5519  break;
5520  case AT_GenericOptions:
5521  ATExecGenericOptions(rel, (List *) cmd->def);
5522  break;
5523  case AT_AttachPartition:
5524  cmd = ATParseTransformCmd(wqueue, tab, rel, cmd, false, lockmode,
5525  cur_pass, context);
5526  Assert(cmd != NULL);
5527  if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
5528  address = ATExecAttachPartition(wqueue, rel, (PartitionCmd *) cmd->def,
5529  context);
5530  else
5531  address = ATExecAttachPartitionIdx(wqueue, rel,
5532  ((PartitionCmd *) cmd->def)->name);
5533  break;
5534  case AT_DetachPartition:
5535  cmd = ATParseTransformCmd(wqueue, tab, rel, cmd, false, lockmode,
5536  cur_pass, context);
5537  Assert(cmd != NULL);
5538  /* ATPrepCmd ensures it must be a table */
5539  Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
5540  address = ATExecDetachPartition(wqueue, tab, rel,
5541  ((PartitionCmd *) cmd->def)->name,
5542  ((PartitionCmd *) cmd->def)->concurrent);
5543  break;
5545  address = ATExecDetachPartitionFinalize(rel, ((PartitionCmd *) cmd->def)->name);
5546  break;
5547  default: /* oops */
5548  elog(ERROR, "unrecognized alter table type: %d",
5549  (int) cmd->subtype);
5550  break;
5551  }
5552 
5553  /*
5554  * Report the subcommand to interested event triggers.
5555  */
5556  if (cmd)
5557  EventTriggerCollectAlterTableSubcmd((Node *) cmd, address);
5558 
5559  /*
5560  * Bump the command counter to ensure the next subcommand in the sequence
5561  * can see the changes so far
5562  */
5564 }
5565 
5566 /*
5567  * ATParseTransformCmd: perform parse transformation for one subcommand
5568  *
5569  * Returns the transformed subcommand tree, if there is one, else NULL.
5570  *
5571  * The parser may hand back additional AlterTableCmd(s) and/or other
5572  * utility statements, either before or after the original subcommand.
5573  * Other AlterTableCmds are scheduled into the appropriate slot of the
5574  * AlteredTableInfo (they had better be for later passes than the current one).
5575  * Utility statements that are supposed to happen before the AlterTableCmd
5576  * are executed immediately. Those that are supposed to happen afterwards
5577  * are added to the tab->afterStmts list to be done at the very end.
5578  */
5579 static AlterTableCmd *
5581  AlterTableCmd *cmd, bool recurse, LOCKMODE lockmode,
5583 {
5584  AlterTableCmd *newcmd = NULL;
5586  List *beforeStmts;
5587  List *afterStmts;
5588  ListCell *lc;
5589 
5590  /* Gin up an AlterTableStmt with just this subcommand and this table */
5591  atstmt->relation =
5594  -1);
5595  atstmt->relation->inh = recurse;
5596  atstmt->cmds = list_make1(cmd);
5597  atstmt->objtype = OBJECT_TABLE; /* needn't be picky here */
5598  atstmt->missing_ok = false;
5599 
5600  /* Transform the AlterTableStmt */
5602  atstmt,
5603  context->queryString,
5604  &beforeStmts,
5605  &afterStmts);
5606 
5607  /* Execute any statements that should happen before these subcommand(s) */
5608  foreach(lc, beforeStmts)
5609  {
5610  Node *stmt = (Node *) lfirst(lc);
5611 
5614  }
5615 
5616  /* Examine the transformed subcommands and schedule them appropriately */
5617  foreach(lc, atstmt->cmds)
5618  {
5620  AlterTablePass pass;
5621 
5622  /*
5623  * This switch need only cover the subcommand types that can be added
5624  * by parse_utilcmd.c; otherwise, we'll use the default strategy of
5625  * executing the subcommand immediately, as a substitute for the
5626  * original subcommand. (Note, however, that this does cause
5627  * AT_AddConstraint subcommands to be rescheduled into later passes,
5628  * which is important for index and foreign key constraints.)
5629  *
5630  * We assume we needn't do any phase-1 checks for added subcommands.
5631  */
5632  switch (cmd2->subtype)
5633  {
5634  case AT_SetNotNull:
5635  /* Need command-specific recursion decision */
5636  ATPrepSetNotNull(wqueue, rel, cmd2,
5637  recurse, false,
5638  lockmode, context);
5639  pass = AT_PASS_COL_ATTRS;
5640  break;
5641  case AT_AddIndex:
5642  /* This command never recurses */
5643  /* No command-specific prep needed */
5644  pass = AT_PASS_ADD_INDEX;
5645  break;
5646  case AT_AddIndexConstraint:
5647  /* This command never recurses */
5648  /* No command-specific prep needed */
5649  pass = AT_PASS_ADD_INDEXCONSTR;
5650  break;
5651  case AT_AddConstraint:
5652  /* Recursion occurs during execution phase */
5653  if (recurse)
5654  cmd2->recurse = true;
5655  switch (castNode(Constraint, cmd2->def)->contype)
5656  {
5657  case CONSTR_PRIMARY:
5658  case CONSTR_UNIQUE:
5659  case CONSTR_EXCLUSION:
5660  pass = AT_PASS_ADD_INDEXCONSTR;
5661  break;
5662  default:
5663  pass = AT_PASS_ADD_OTHERCONSTR;
5664  break;
5665  }
5666  break;
5668  /* This command never recurses */
5669  /* No command-specific prep needed */
5670  pass = AT_PASS_MISC;
5671  break;
5672  default:
5673  pass = cur_pass;
5674  break;
5675  }
5676 
5677  if (pass < cur_pass)
5678  {
5679  /* Cannot schedule into a pass we already finished */
5680  elog(ERROR, "ALTER TABLE scheduling failure: too late for pass %d",
5681  pass);
5682  }
5683  else if (pass > cur_pass)
5684  {
5685  /* OK, queue it up for later */
5686  tab->subcmds[pass] = lappend(tab->subcmds[pass], cmd2);
5687  }
5688  else
5689  {
5690  /*
5691  * We should see at most one subcommand for the current pass,
5692  * which is the transformed version of the original subcommand.
5693  */
5694  if (newcmd == NULL && cmd->subtype == cmd2->subtype)
5695  {
5696  /* Found the transformed version of our subcommand */
5697  newcmd = cmd2;
5698  }
5699  else
5700  elog(ERROR, "ALTER TABLE scheduling failure: bogus item for pass %d",
5701  pass);
5702  }
5703  }
5704 
5705  /* Queue up any after-statements to happen at the end */
5706  tab->afterStmts = list_concat(tab->afterStmts, afterStmts);
5707 
5708  return newcmd;
5709 }
5710 
5711 /*
5712  * ATRewriteTables: ALTER TABLE phase 3
5713  */
5714 static void
5715 ATRewriteTables(AlterTableStmt *parsetree, List **wqueue, LOCKMODE lockmode,
5717 {
5718  ListCell *ltab;
5719 
5720  /* Go through each table that needs to be checked or rewritten */
5721  foreach(ltab, *wqueue)
5722  {
5723  AlteredTableInfo *tab = (AlteredTableInfo *) lfirst(ltab);
5724 
5725  /* Relations without storage may be ignored here */
5726  if (!RELKIND_HAS_STORAGE(tab->relkind))
5727  continue;
5728 
5729  /*
5730  * If we change column data types, the operation has to be propagated
5731  * to tables that use this table's rowtype as a column type.
5732  * tab->newvals will also be non-NULL in the case where we're adding a
5733  * column with a default. We choose to forbid that case as well,
5734  * since composite types might eventually support defaults.
5735  *
5736  * (Eventually we'll probably need to check for composite type
5737  * dependencies even when we're just scanning the table without a
5738  * rewrite, but at the moment a composite type does not enforce any
5739  * constraints, so it's not necessary/appropriate to enforce them just
5740  * during ALTER.)
5741  */
5742  if (tab->newvals != NIL || tab->rewrite > 0)
5743  {
5744  Relation rel;
5745 
5746  rel = table_open(tab->relid, NoLock);
5747  find_composite_type_dependencies(rel->rd_rel->reltype, rel, NULL);
5748  table_close(rel, NoLock);
5749  }
5750 
5751  /*
5752  * We only need to rewrite the table if at least one column needs to
5753  * be recomputed, or we are changing its persistence or access method.
5754  *
5755  * There are two reasons for requiring a rewrite when changing
5756  * persistence: on one hand, we need to ensure that the buffers
5757  * belonging to each of the two relations are marked with or without
5758  * BM_PERMANENT properly. On the other hand, since rewriting creates
5759  * and assigns a new relfilenumber, we automatically create or drop an
5760  * init fork for the relation as appropriate.
5761  */
5762  if (tab->rewrite > 0 && tab->relkind != RELKIND_SEQUENCE)
5763  {
5764  /* Build a temporary relation and copy data */
5765  Relation OldHeap;
5766  Oid OIDNewHeap;
5767  Oid NewAccessMethod;
5768  Oid NewTableSpace;
5769  char persistence;
5770 
5771  OldHeap = table_open(tab->relid, NoLock);
5772 
5773  /*
5774  * We don't support rewriting of system catalogs; there are too
5775  * many corner cases and too little benefit. In particular this
5776  * is certainly not going to work for mapped catalogs.
5777  */
5778  if (IsSystemRelation(OldHeap))
5779  ereport(ERROR,
5780  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
5781  errmsg("cannot rewrite system relation \"%s\"",
5782  RelationGetRelationName(OldHeap))));
5783 
5784  if (RelationIsUsedAsCatalogTable(OldHeap))
5785  ereport(ERROR,
5786  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
5787  errmsg("cannot rewrite table \"%s\" used as a catalog table",
5788  RelationGetRelationName(OldHeap))));
5789 
5790  /*
5791  * Don't allow rewrite on temp tables of other backends ... their
5792  * local buffer manager is not going to cope. (This is redundant
5793  * with the check in CheckAlterTableIsSafe, but for safety we'll
5794  * check here too.)
5795  */
5796  if (RELATION_IS_OTHER_TEMP(OldHeap))
5797  ereport(ERROR,
5798  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
5799  errmsg("cannot rewrite temporary tables of other sessions")));
5800 
5801  /*
5802  * Select destination tablespace (same as original unless user
5803  * requested a change)
5804  */
5805  if (tab->newTableSpace)
5806  NewTableSpace = tab->newTableSpace;
5807  else
5808  NewTableSpace = OldHeap->rd_rel->reltablespace;
5809 
5810  /*
5811  * Select destination access method (same as original unless user
5812  * requested a change)
5813  */
5814  if (tab->chgAccessMethod)
5815  NewAccessMethod = tab->newAccessMethod;
5816  else
5817  NewAccessMethod = OldHeap->rd_rel->relam;
5818 
5819  /*
5820  * Select persistence of transient table (same as original unless
5821  * user requested a change)
5822  */
5823  persistence = tab->chgPersistence ?
5824  tab->newrelpersistence : OldHeap->rd_rel->relpersistence;
5825 
5826  table_close(OldHeap, NoLock);
5827 
5828  /*
5829  * Fire off an Event Trigger now, before actually rewriting the
5830  * table.
5831  *
5832  * We don't support Event Trigger for nested commands anywhere,
5833  * here included, and parsetree is given NULL when coming from
5834  * AlterTableInternal.
5835  *
5836  * And fire it only once.
5837  */
5838  if (parsetree)
5839  EventTriggerTableRewrite((Node *) parsetree,
5840  tab->relid,
5841  tab->rewrite);
5842 
5843  /*
5844  * Create transient table that will receive the modified data.
5845  *
5846  * Ensure it is marked correctly as logged or unlogged. We have
5847  * to do this here so that buffers for the new relfilenumber will
5848  * have the right persistence set, and at the same time ensure
5849  * that the original filenumbers's buffers will get read in with
5850  * the correct setting (i.e. the original one). Otherwise a
5851  * rollback after the rewrite would possibly result with buffers
5852  * for the original filenumbers having the wrong persistence
5853  * setting.
5854  *
5855  * NB: This relies on swap_relation_files() also swapping the
5856  * persistence. That wouldn't work for pg_class, but that can't be
5857  * unlogged anyway.
5858  */
5859  OIDNewHeap = make_new_heap(tab->relid, NewTableSpace, NewAccessMethod,
5860  persistence, lockmode);
5861 
5862  /*
5863  * Copy the heap data into the new table with the desired
5864  * modifications, and test the current data within the table
5865  * against new constraints generated by ALTER TABLE commands.
5866  */
5867  ATRewriteTable(tab, OIDNewHeap, lockmode);
5868 
5869  /*
5870  * Swap the physical files of the old and new heaps, then rebuild
5871  * indexes and discard the old heap. We can use RecentXmin for
5872  * the table's new relfrozenxid because we rewrote all the tuples
5873  * in ATRewriteTable, so no older Xid remains in the table. Also,
5874  * we never try to swap toast tables by content, since we have no
5875  * interest in letting this code work on system catalogs.
5876  */
5877  finish_heap_swap(tab->relid, OIDNewHeap,
5878  false, false, true,
5879  !OidIsValid(tab->newTableSpace),
5880  RecentXmin,
5882  persistence);
5883 
5884  InvokeObjectPostAlterHook(RelationRelationId, tab->relid, 0);
5885  }
5886  else if (tab->rewrite > 0 && tab->relkind == RELKIND_SEQUENCE)
5887  {
5888  if (tab->chgPersistence)
5890  }
5891  else
5892  {
5893  /*
5894  * If required, test the current data within the table against new
5895  * constraints generated by ALTER TABLE commands, but don't
5896  * rebuild data.
5897  */
5898  if (tab->constraints != NIL || tab->verify_new_notnull ||
5899  tab->partition_constraint != NULL)
5900  ATRewriteTable(tab, InvalidOid, lockmode);
5901 
5902  /*
5903  * If we had SET TABLESPACE but no reason to reconstruct tuples,
5904  * just do a block-by-block copy.
5905  */
5906  if (tab->newTableSpace)
5907  ATExecSetTableSpace(tab->relid, tab->newTableSpace, lockmode);
5908  }
5909 
5910  /*
5911  * Also change persistence of owned sequences, so that it matches the
5912  * table persistence.
5913  */
5914  if (tab->chgPersistence)
5915  {
5916  List *seqlist = getOwnedSequences(tab->relid);
5917  ListCell *lc;
5918 
5919  foreach(lc, seqlist)
5920  {
5921  Oid seq_relid = lfirst_oid(lc);
5922 
5924  }
5925  }
5926  }
5927 
5928  /*
5929  * Foreign key constraints are checked in a final pass, since (a) it's
5930  * generally best to examine each one separately, and (b) it's at least
5931  * theoretically possible that we have changed both relations of the
5932  * foreign key, and we'd better have finished both rewrites before we try
5933  * to read the tables.
5934  */
5935  foreach(ltab, *wqueue)
5936  {
5937  AlteredTableInfo *tab = (AlteredTableInfo *) lfirst(ltab);
5938  Relation rel = NULL;
5939  ListCell *lcon;
5940 
5941  /* Relations without storage may be ignored here too */
5942  if (!RELKIND_HAS_STORAGE(tab->relkind))
5943  continue;
5944 
5945  foreach(lcon, tab->constraints)
5946  {
5947  NewConstraint *con = lfirst(lcon);
5948 
5949  if (con->contype == CONSTR_FOREIGN)
5950  {
5951  Constraint *fkconstraint = (Constraint *) con->qual;
5952  Relation refrel;
5953 
5954  if (rel == NULL)
5955  {
5956  /* Long since locked, no need for another */
5957  rel = table_open(tab->relid, NoLock);
5958  }
5959 
5960  refrel = table_open(con->refrelid, RowShareLock);
5961 
5962  validateForeignKeyConstraint(fkconstraint->conname, rel, refrel,
5963  con->refindid,
5964  con->conid,
5965  con->conwithperiod);
5966 
5967  /*
5968  * No need to mark the constraint row as validated, we did
5969  * that when we inserted the row earlier.
5970  */
5971 
5972  table_close(refrel, NoLock);
5973  }
5974  }
5975 
5976  if (rel)
5977  table_close(rel, NoLock);
5978  }
5979 
5980  /* Finally, run any afterStmts that were queued up */
5981  foreach(ltab, *wqueue)
5982  {
5983  AlteredTableInfo *tab = (AlteredTableInfo *) lfirst(ltab);
5984  ListCell *lc;
5985 
5986  foreach(lc, tab->afterStmts)
5987  {
5988  Node *stmt = (Node *) lfirst(lc);
5989 
5992  }
5993  }
5994 }
5995 
5996 /*
5997  * ATRewriteTable: scan or rewrite one table
5998  *
5999  * OIDNewHeap is InvalidOid if we don't need to rewrite
6000  */
6001 static void
6002 ATRewriteTable(AlteredTableInfo *tab, Oid OIDNewHeap, LOCKMODE lockmode)
6003 {
6004  Relation oldrel;
6005  Relation newrel;
6006  TupleDesc oldTupDesc;
6007  TupleDesc newTupDesc;
6008  bool needscan = false;
6009  List *notnull_attrs;
6010  int i;
6011  ListCell *l;
6012  EState *estate;
6013  CommandId mycid;
6014  BulkInsertState bistate;
6015  int ti_options;
6016  ExprState *partqualstate = NULL;
6017 
6018  /*
6019  * Open the relation(s). We have surely already locked the existing
6020  * table.
6021  */
6022  oldrel = table_open(tab->relid, NoLock);
6023  oldTupDesc = tab->oldDesc;
6024  newTupDesc = RelationGetDescr(oldrel); /* includes all mods */
6025 
6026  if (OidIsValid(OIDNewHeap))
6027  newrel = table_open(OIDNewHeap, lockmode);
6028  else
6029  newrel = NULL;
6030 
6031  /*
6032  * Prepare a BulkInsertState and options for table_tuple_insert. The FSM
6033  * is empty, so don't bother using it.
6034  */
6035  if (newrel)
6036  {
6037  mycid = GetCurrentCommandId(true);
6038  bistate = GetBulkInsertState();
6039  ti_options = TABLE_INSERT_SKIP_FSM;
6040  }
6041  else
6042  {
6043  /* keep compiler quiet about using these uninitialized */
6044  mycid = 0;
6045  bistate = NULL;
6046  ti_options = 0;
6047  }
6048 
6049  /*
6050  * Generate the constraint and default execution states
6051  */
6052 
6053  estate = CreateExecutorState();
6054 
6055  /* Build the needed expression execution states */
6056  foreach(l, tab->constraints)
6057  {
6058  NewConstraint *con = lfirst(l);
6059 
6060  switch (con->contype)
6061  {
6062  case CONSTR_CHECK:
6063  needscan = true;
6064  con->qualstate = ExecPrepareExpr((Expr *) con->qual, estate);
6065  break;
6066  case CONSTR_FOREIGN:
6067  /* Nothing to do here */
6068  break;
6069  default:
6070  elog(ERROR, "unrecognized constraint type: %d",
6071  (int) con->contype);
6072  }
6073  }
6074 
6075  /* Build expression execution states for partition check quals */
6076  if (tab->partition_constraint)
6077  {
6078  needscan = true;
6079  partqualstate = ExecPrepareExpr(tab->partition_constraint, estate);
6080  }
6081 
6082  foreach(l, tab->newvals)
6083  {
6084  NewColumnValue *ex = lfirst(l);
6085 
6086  /* expr already planned */
6087  ex->exprstate = ExecInitExpr((Expr *) ex->expr, NULL);
6088  }
6089 
6090  notnull_attrs = NIL;
6091  if (newrel || tab->verify_new_notnull)
6092  {
6093  /*
6094  * If we are rebuilding the tuples OR if we added any new but not
6095  * verified not-null constraints, check all not-null constraints. This
6096  * is a bit of overkill but it minimizes risk of bugs, and
6097  * heap_attisnull is a pretty cheap test anyway.
6098  */
6099  for (i = 0; i < newTupDesc->natts; i++)
6100  {
6101  Form_pg_attribute attr = TupleDescAttr(newTupDesc, i);
6102 
6103  if (attr->attnotnull && !attr->attisdropped)
6104  notnull_attrs = lappend_int(notnull_attrs, i);
6105  }
6106  if (notnull_attrs)
6107  needscan = true;
6108  }
6109 
6110  if (newrel || needscan)
6111  {
6112  ExprContext *econtext;
6113  TupleTableSlot *oldslot;
6114  TupleTableSlot *newslot;
6115  TableScanDesc scan;
6116  MemoryContext oldCxt;
6117  List *dropped_attrs = NIL;
6118  ListCell *lc;
6119  Snapshot snapshot;
6120 
6121  if (newrel)
6122  ereport(DEBUG1,
6123  (errmsg_internal("rewriting table \"%s\"",
6124  RelationGetRelationName(oldrel))));
6125  else
6126  ereport(DEBUG1,
6127  (errmsg_internal("verifying table \"%s\"",
6128  RelationGetRelationName(oldrel))));
6129 
6130  if (newrel)
6131  {
6132  /*
6133  * All predicate locks on the tuples or pages are about to be made
6134  * invalid, because we move tuples around. Promote them to
6135  * relation locks.
6136  */
6138  }
6139 
6140  econtext = GetPerTupleExprContext(estate);
6141 
6142  /*
6143  * Create necessary tuple slots. When rewriting, two slots are needed,
6144  * otherwise one suffices. In the case where one slot suffices, we
6145  * need to use the new tuple descriptor, otherwise some constraints
6146  * can't be evaluated. Note that even when the tuple layout is the
6147  * same and no rewrite is required, the tupDescs might not be
6148  * (consider ADD COLUMN without a default).
6149  */
6150  if (tab->rewrite)
6151  {
6152  Assert(newrel != NULL);
6153  oldslot = MakeSingleTupleTableSlot(oldTupDesc,
6154  table_slot_callbacks(oldrel));
6155  newslot = MakeSingleTupleTableSlot(newTupDesc,
6156  table_slot_callbacks(newrel));
6157 
6158  /*
6159  * Set all columns in the new slot to NULL initially, to ensure
6160  * columns added as part of the rewrite are initialized to NULL.
6161  * That is necessary as tab->newvals will not contain an
6162  * expression for columns with a NULL default, e.g. when adding a
6163  * column without a default together with a column with a default
6164  * requiring an actual rewrite.
6165  */
6166  ExecStoreAllNullTuple(newslot);
6167  }
6168  else
6169  {
6170  oldslot = MakeSingleTupleTableSlot(newTupDesc,
6171  table_slot_callbacks(oldrel));
6172  newslot = NULL;
6173  }
6174 
6175  /*
6176  * Any attributes that are dropped according to the new tuple
6177  * descriptor can be set to NULL. We precompute the list of dropped
6178  * attributes to avoid needing to do so in the per-tuple loop.
6179  */
6180  for (i = 0; i < newTupDesc->natts; i++)
6181  {
6182  if (TupleDescAttr(newTupDesc, i)->attisdropped)
6183  dropped_attrs = lappend_int(dropped_attrs, i);
6184  }
6185 
6186  /*
6187  * Scan through the rows, generating a new row if needed and then
6188  * checking all the constraints.
6189  */
6190  snapshot = RegisterSnapshot(GetLatestSnapshot());
6191  scan = table_beginscan(oldrel, snapshot, 0, NULL);
6192 
6193  /*
6194  * Switch to per-tuple memory context and reset it for each tuple
6195  * produced, so we don't leak memory.
6196  */
6198 
6199  while (table_scan_getnextslot(scan, ForwardScanDirection, oldslot))
6200  {
6201  TupleTableSlot *insertslot;
6202 
6203  if (tab->rewrite > 0)
6204  {
6205  /* Extract data from old tuple */
6206  slot_getallattrs(oldslot);
6207  ExecClearTuple(newslot);
6208 
6209  /* copy attributes */
6210  memcpy(newslot->tts_values, oldslot->tts_values,
6211  sizeof(Datum) * oldslot->tts_nvalid);
6212  memcpy(newslot->tts_isnull, oldslot->tts_isnull,
6213  sizeof(bool) * oldslot->tts_nvalid);
6214 
6215  /* Set dropped attributes to null in new tuple */
6216  foreach(lc, dropped_attrs)
6217  newslot->tts_isnull[lfirst_int(lc)] = true;
6218 
6219  /*
6220  * Constraints and GENERATED expressions might reference the
6221  * tableoid column, so fill tts_tableOid with the desired
6222  * value. (We must do this each time, because it gets
6223  * overwritten with newrel's OID during storing.)
6224  */
6225  newslot->tts_tableOid = RelationGetRelid(oldrel);
6226 
6227  /*
6228  * Process supplied expressions to replace selected columns.
6229  *
6230  * First, evaluate expressions whose inputs come from the old
6231  * tuple.
6232  */
6233  econtext->ecxt_scantuple = oldslot;
6234 
6235  foreach(l, tab->newvals)
6236  {
6237  NewColumnValue *ex = lfirst(l);
6238 
6239  if (ex->is_generated)
6240  continue;
6241 
6242  newslot->tts_values[ex->attnum - 1]
6243  = ExecEvalExpr(ex->exprstate,
6244  econtext,
6245  &newslot->tts_isnull[ex->attnum - 1]);
6246  }
6247 
6248  ExecStoreVirtualTuple(newslot);
6249 
6250  /*
6251  * Now, evaluate any expressions whose inputs come from the
6252  * new tuple. We assume these columns won't reference each
6253  * other, so that there's no ordering dependency.
6254  */
6255  econtext->ecxt_scantuple = newslot;
6256 
6257  foreach(l, tab->newvals)
6258  {
6259  NewColumnValue *ex = lfirst(l);
6260 
6261  if (!ex->is_generated)
6262  continue;
6263 
6264  newslot->tts_values[ex->attnum - 1]
6265  = ExecEvalExpr(ex->exprstate,
6266  econtext,
6267  &newslot->tts_isnull[ex->attnum - 1]);
6268  }
6269 
6270  insertslot = newslot;
6271  }
6272  else
6273  {
6274  /*
6275  * If there's no rewrite, old and new table are guaranteed to
6276  * have the same AM, so we can just use the old slot to verify
6277  * new constraints etc.
6278  */
6279  insertslot = oldslot;
6280  }
6281 
6282  /* Now check any constraints on the possibly-changed tuple */
6283  econtext->ecxt_scantuple = insertslot;
6284 
6285  foreach(l, notnull_attrs)
6286  {
6287  int attn = lfirst_int(l);
6288 
6289  if (slot_attisnull(insertslot, attn + 1))
6290  {
6291  Form_pg_attribute attr = TupleDescAttr(newTupDesc, attn);
6292 
6293  ereport(ERROR,
6294  (errcode(ERRCODE_NOT_NULL_VIOLATION),
6295  errmsg("column \"%s\" of relation \"%s\" contains null values",
6296  NameStr(attr->attname),
6297  RelationGetRelationName(oldrel)),
6298  errtablecol(oldrel, attn + 1)));
6299  }
6300  }
6301 
6302  foreach(l, tab->constraints)
6303  {
6304  NewConstraint *con = lfirst(l);
6305 
6306  switch (con->contype)
6307  {
6308  case CONSTR_CHECK:
6309  if (!ExecCheck(con->qualstate, econtext))
6310  ereport(ERROR,
6311  (errcode(ERRCODE_CHECK_VIOLATION),
6312  errmsg("check constraint \"%s\" of relation \"%s\" is violated by some row",
6313  con->name,
6314  RelationGetRelationName(oldrel)),
6315  errtableconstraint(oldrel, con->name)));
6316  break;
6317  case CONSTR_FOREIGN:
6318  /* Nothing to do here */
6319  break;
6320  default:
6321  elog(ERROR, "unrecognized constraint type: %d",
6322  (int) con->contype);
6323  }
6324  }
6325 
6326  if (partqualstate && !ExecCheck(partqualstate, econtext))
6327  {
6328  if (tab->validate_default)
6329  ereport(ERROR,
6330  (errcode(ERRCODE_CHECK_VIOLATION),
6331  errmsg("updated partition constraint for default partition \"%s\" would be violated by some row",
6332  RelationGetRelationName(oldrel)),
6333  errtable(oldrel)));
6334  else
6335  ereport(ERROR,
6336  (errcode(ERRCODE_CHECK_VIOLATION),
6337  errmsg("partition constraint of relation \"%s\" is violated by some row",
6338  RelationGetRelationName(oldrel)),
6339  errtable(oldrel)));
6340  }
6341 
6342  /* Write the tuple out to the new relation */
6343  if (newrel)
6344  table_tuple_insert(newrel, insertslot, mycid,
6345  ti_options, bistate);
6346 
6347  ResetExprContext(econtext);
6348 
6350  }
6351 
6352  MemoryContextSwitchTo(oldCxt);
6353  table_endscan(scan);
6354  UnregisterSnapshot(snapshot);
6355 
6357  if (newslot)
6359  }
6360 
6361  FreeExecutorState(estate);
6362 
6363  table_close(oldrel, NoLock);
6364  if (newrel)
6365  {
6366  FreeBulkInsertState(bistate);
6367 
6368  table_finish_bulk_insert(newrel, ti_options);
6369 
6370  table_close(newrel, NoLock);
6371  }
6372 }
6373 
6374 /*
6375  * ATGetQueueEntry: find or create an entry in the ALTER TABLE work queue
6376  */
6377 static AlteredTableInfo *
6379 {
6380  Oid relid = RelationGetRelid(rel);
6381  AlteredTableInfo *tab;
6382  ListCell *ltab;
6383 
6384  foreach(ltab, *wqueue)
6385  {
6386  tab = (AlteredTableInfo *) lfirst(ltab);
6387  if (tab->relid == relid)
6388  return tab;
6389  }
6390 
6391  /*
6392  * Not there, so add it. Note that we make a copy of the relation's
6393  * existing descriptor before anything interesting can happen to it.
6394  */
6395  tab = (AlteredTableInfo *) palloc0(sizeof(AlteredTableInfo));
6396  tab->relid = relid;
6397  tab->rel = NULL; /* set later */
6398  tab->relkind = rel->rd_rel->relkind;
6400  tab->newAccessMethod = InvalidOid;
6401  tab->chgAccessMethod = false;
6402  tab->newTableSpace = InvalidOid;
6403  tab->newrelpersistence = RELPERSISTENCE_PERMANENT;
6404  tab->chgPersistence = false;
6405 
6406  *wqueue = lappend(*wqueue, tab);
6407 
6408  return tab;
6409 }
6410 
6411 static const char *
6413 {
6414  switch (cmdtype)
6415  {
6416  case AT_AddColumn:
6417  case AT_AddColumnToView:
6418  return "ADD COLUMN";
6419  case AT_ColumnDefault:
6421  return "ALTER COLUMN ... SET DEFAULT";
6422  case AT_DropNotNull:
6423  return "ALTER COLUMN ... DROP NOT NULL";
6424  case AT_SetNotNull:
6425  return "ALTER COLUMN ... SET NOT NULL";
6426  case AT_SetExpression:
6427  return "ALTER COLUMN ... SET EXPRESSION";
6428  case AT_DropExpression:
6429  return "ALTER COLUMN ... DROP EXPRESSION";
6430  case AT_CheckNotNull:
6431  return NULL; /* not real grammar */
6432  case AT_SetStatistics:
6433  return "ALTER COLUMN ... SET STATISTICS";
6434  case AT_SetOptions:
6435  return "ALTER COLUMN ... SET";
6436  case AT_ResetOptions:
6437  return "ALTER COLUMN ... RESET";
6438  case AT_SetStorage:
6439  return "ALTER COLUMN ... SET STORAGE";
6440  case AT_SetCompression:
6441  return "ALTER COLUMN ... SET COMPRESSION";
6442  case AT_DropColumn:
6443  return "DROP COLUMN";
6444  case AT_AddIndex:
6445  case AT_ReAddIndex:
6446  return NULL; /* not real grammar */
6447  case AT_AddConstraint:
6448  case AT_ReAddConstraint:
6450  case AT_AddIndexConstraint:
6451  return "ADD CONSTRAINT";
6452  case AT_AlterConstraint:
6453  return "ALTER CONSTRAINT";
6454  case AT_ValidateConstraint:
6455  return "VALIDATE CONSTRAINT";
6456  case AT_DropConstraint:
6457  return "DROP CONSTRAINT";
6458  case AT_ReAddComment:
6459  return NULL; /* not real grammar */
6460  case AT_AlterColumnType:
6461  return "ALTER COLUMN ... SET DATA TYPE";
6463  return "ALTER COLUMN ... OPTIONS";
6464  case AT_ChangeOwner:
6465  return "OWNER TO";
6466  case AT_ClusterOn:
6467  return "CLUSTER ON";
6468  case AT_DropCluster:
6469  return "SET WITHOUT CLUSTER";
6470  case AT_SetAccessMethod:
6471  return "SET ACCESS METHOD";
6472  case AT_SetLogged:
6473  return "SET LOGGED";
6474  case AT_SetUnLogged:
6475  return "SET UNLOGGED";
6476  case AT_DropOids:
6477  return "SET WITHOUT OIDS";
6478  case AT_SetTableSpace:
6479  return "SET TABLESPACE";
6480  case AT_SetRelOptions:
6481  return "SET";
6482  case AT_ResetRelOptions:
6483  return "RESET";
6484  case AT_ReplaceRelOptions:
6485  return NULL; /* not real grammar */
6486  case AT_EnableTrig:
6487  return "ENABLE TRIGGER";
6488  case AT_EnableAlwaysTrig:
6489  return "ENABLE ALWAYS TRIGGER";
6490  case AT_EnableReplicaTrig:
6491  return "ENABLE REPLICA TRIGGER";
6492  case AT_DisableTrig:
6493  return "DISABLE TRIGGER";
6494  case AT_EnableTrigAll:
6495  return "ENABLE TRIGGER ALL";
6496  case AT_DisableTrigAll:
6497  return "DISABLE TRIGGER ALL";
6498  case AT_EnableTrigUser:
6499  return "ENABLE TRIGGER USER";
6500  case AT_DisableTrigUser:
6501  return "DISABLE TRIGGER USER";
6502  case AT_EnableRule:
6503  return "ENABLE RULE";
6504  case AT_EnableAlwaysRule:
6505  return "ENABLE ALWAYS RULE";
6506  case AT_EnableReplicaRule:
6507  return "ENABLE REPLICA RULE";
6508  case AT_DisableRule:
6509  return "DISABLE RULE";
6510  case AT_AddInherit:
6511  return "INHERIT";
6512  case AT_DropInherit:
6513  return "NO INHERIT";
6514  case AT_AddOf:
6515  return "OF";
6516  case AT_DropOf:
6517  return "NOT OF";
6518  case AT_ReplicaIdentity:
6519  return "REPLICA IDENTITY";
6520  case AT_EnableRowSecurity:
6521  return "ENABLE ROW SECURITY";
6522  case AT_DisableRowSecurity:
6523  return "DISABLE ROW SECURITY";
6524  case AT_ForceRowSecurity:
6525  return "FORCE ROW SECURITY";
6526  case AT_NoForceRowSecurity:
6527  return "NO FORCE ROW SECURITY";
6528  case AT_GenericOptions:
6529  return "OPTIONS";
6530  case AT_AttachPartition:
6531  return "ATTACH PARTITION";
6532  case AT_DetachPartition:
6533  return "DETACH PARTITION";
6535  return "DETACH PARTITION ... FINALIZE";
6536  case AT_AddIdentity:
6537  return "ALTER COLUMN ... ADD IDENTITY";
6538  case AT_SetIdentity:
6539  return "ALTER COLUMN ... SET";
6540  case AT_DropIdentity:
6541  return "ALTER COLUMN ... DROP IDENTITY";
6542  case AT_ReAddStatistics:
6543  return NULL; /* not real grammar */
6544  }
6545 
6546  return NULL;
6547 }
6548 
6549 /*
6550  * ATSimplePermissions
6551  *
6552  * - Ensure that it is a relation (or possibly a view)
6553  * - Ensure this user is the owner
6554  * - Ensure that it is not a system table
6555  */
6556 static void
6557 ATSimplePermissions(AlterTableType cmdtype, Relation rel, int allowed_targets)
6558 {
6559  int actual_target;
6560 
6561  switch (rel->rd_rel->relkind)
6562  {
6563  case RELKIND_RELATION:
6564  actual_target = ATT_TABLE;
6565  break;
6566  case RELKIND_PARTITIONED_TABLE:
6567  actual_target = ATT_PARTITIONED_TABLE;
6568  break;
6569  case RELKIND_VIEW:
6570  actual_target = ATT_VIEW;
6571  break;
6572  case RELKIND_MATVIEW:
6573  actual_target = ATT_MATVIEW;
6574  break;
6575  case RELKIND_INDEX:
6576  actual_target = ATT_INDEX;
6577  break;
6578  case RELKIND_PARTITIONED_INDEX:
6579  actual_target = ATT_PARTITIONED_INDEX;
6580  break;
6581  case RELKIND_COMPOSITE_TYPE:
6582  actual_target = ATT_COMPOSITE_TYPE;
6583  break;
6584  case RELKIND_FOREIGN_TABLE:
6585  actual_target = ATT_FOREIGN_TABLE;
6586  break;
6587  case RELKIND_SEQUENCE:
6588  actual_target = ATT_SEQUENCE;
6589  break;
6590  default:
6591  actual_target = 0;
6592  break;
6593  }
6594 
6595  /* Wrong target type? */
6596  if ((actual_target & allowed_targets) == 0)
6597  {
6598  const char *action_str = alter_table_type_to_string(cmdtype);
6599 
6600  if (action_str)
6601  ereport(ERROR,
6602  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
6603  /* translator: %s is a group of some SQL keywords */
6604  errmsg("ALTER action %s cannot be performed on relation \"%s\"",
6605  action_str, RelationGetRelationName(rel)),
6606  errdetail_relkind_not_supported(rel->rd_rel->relkind)));
6607  else
6608  /* internal error? */
6609  elog(ERROR, "invalid ALTER action attempted on relation \"%s\"",
6611  }
6612 
6613  /* Permissions checks */
6614  if (!object_ownercheck(RelationRelationId, RelationGetRelid(rel), GetUserId()))
6617 
6619  ereport(ERROR,
6620  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
6621  errmsg("permission denied: \"%s\" is a system catalog",
6622  RelationGetRelationName(rel))));
6623 }
6624 
6625 /*
6626  * ATSimpleRecursion
6627  *
6628  * Simple table recursion sufficient for most ALTER TABLE operations.
6629  * All direct and indirect children are processed in an unspecified order.
6630  * Note that if a child inherits from the original table via multiple
6631  * inheritance paths, it will be visited just once.
6632  */
6633 static void
6635  AlterTableCmd *cmd, bool recurse, LOCKMODE lockmode,
6637 {
6638  /*
6639  * Propagate to children, if desired and if there are (or might be) any
6640  * children.
6641  */
6642  if (recurse && rel->rd_rel->relhassubclass)
6643  {
6644  Oid relid = RelationGetRelid(rel);
6645  ListCell *child;
6646  List *children;
6647 
6648  children = find_all_inheritors(relid, lockmode, NULL);
6649 
6650  /*
6651  * find_all_inheritors does the recursive search of the inheritance
6652  * hierarchy, so all we have to do is process all of the relids in the
6653  * list that it returns.
6654  */
6655  foreach(child, children)
6656  {
6657  Oid childrelid = lfirst_oid(child);
6658  Relation childrel;
6659 
6660  if (childrelid == relid)
6661  continue;
6662  /* find_all_inheritors already got lock */
6663  childrel = relation_open(childrelid, NoLock);
6664  CheckAlterTableIsSafe(childrel);
6665  ATPrepCmd(wqueue, childrel, cmd, false, true, lockmode, context);
6666  relation_close(childrel, NoLock);
6667  }
6668  }
6669 }
6670 
6671 /*
6672  * Obtain list of partitions of the given table, locking them all at the given
6673  * lockmode and ensuring that they all pass CheckAlterTableIsSafe.
6674  *
6675  * This function is a no-op if the given relation is not a partitioned table;
6676  * in particular, nothing is done if it's a legacy inheritance parent.
6677  */
6678 static void
6680 {
6681  if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
6682  {
6683  List *inh;
6684  ListCell *cell;
6685 
6686  inh = find_all_inheritors(RelationGetRelid(rel), lockmode, NULL);
6687  /* first element is the parent rel; must ignore it */
6688  for_each_from(cell, inh, 1)
6689  {
6690  Relation childrel;
6691 
6692  /* find_all_inheritors already got lock */
6693  childrel = table_open(lfirst_oid(cell), NoLock);
6694  CheckAlterTableIsSafe(childrel);
6695  table_close(childrel, NoLock);
6696  }
6697  list_free(inh);
6698  }
6699 }
6700 
6701 /*
6702  * ATTypedTableRecursion
6703  *
6704  * Propagate ALTER TYPE operations to the typed tables of that type.
6705  * Also check the RESTRICT/CASCADE behavior. Given CASCADE, also permit
6706  * recursion to inheritance children of the typed tables.
6707  */
6708 static void
6711 {
6712  ListCell *child;
6713  List *children;
6714 
6715  Assert(rel->rd_rel->relkind == RELKIND_COMPOSITE_TYPE);
6716 
6717  children = find_typed_table_dependencies(rel->rd_rel->reltype,
6719  cmd->behavior);
6720 
6721  foreach(child, children)
6722  {
6723  Oid childrelid = lfirst_oid(child);
6724  Relation childrel;
6725 
6726  childrel = relation_open(childrelid, lockmode);
6727  CheckAlterTableIsSafe(childrel);
6728  ATPrepCmd(wqueue, childrel, cmd, true, true, lockmode, context);
6729  relation_close(childrel, NoLock);
6730  }
6731 }
6732 
6733 
6734 /*
6735  * find_composite_type_dependencies
6736  *
6737  * Check to see if the type "typeOid" is being used as a column in some table
6738  * (possibly nested several levels deep in composite types, arrays, etc!).
6739  * Eventually, we'd like to propagate the check or rewrite operation
6740  * into such tables, but for now, just error out if we find any.
6741  *
6742  * Caller should provide either the associated relation of a rowtype,
6743  * or a type name (not both) for use in the error message, if any.
6744  *
6745  * Note that "typeOid" is not necessarily a composite type; it could also be
6746  * another container type such as an array or range, or a domain over one of
6747  * these things. The name of this function is therefore somewhat historical,
6748  * but it's not worth changing.
6749  *
6750  * We assume that functions and views depending on the type are not reasons
6751  * to reject the ALTER. (How safe is this really?)
6752  */
6753 void
6755  const char *origTypeName)
6756 {
6757  Relation depRel;
6758  ScanKeyData key[2];
6759  SysScanDesc depScan;
6760  HeapTuple depTup;
6761 
6762  /* since this function recurses, it could be driven to stack overflow */
6764 
6765  /*
6766  * We scan pg_depend to find those things that depend on the given type.
6767  * (We assume we can ignore refobjsubid for a type.)
6768  */
6769  depRel = table_open(DependRelationId, AccessShareLock);
6770 
6771  ScanKeyInit(&key[0],
6772  Anum_pg_depend_refclassid,
6773  BTEqualStrategyNumber, F_OIDEQ,
6774  ObjectIdGetDatum(TypeRelationId));
6775  ScanKeyInit(&key[1],
6776  Anum_pg_depend_refobjid,
6777  BTEqualStrategyNumber, F_OIDEQ,
6778  ObjectIdGetDatum(typeOid));
6779 
6780  depScan = systable_beginscan(depRel, DependReferenceIndexId, true,
6781  NULL, 2, key);
6782 
6783  while (HeapTupleIsValid(depTup = systable_getnext(depScan)))
6784  {
6785  Form_pg_depend pg_depend = (Form_pg_depend) GETSTRUCT(depTup);
6786  Relation rel;
6787  TupleDesc tupleDesc;
6788  Form_pg_attribute att;
6789 
6790  /* Check for directly dependent types */
6791  if (pg_depend->classid == TypeRelationId)
6792  {
6793  /*
6794  * This must be an array, domain, or range containing the given
6795  * type, so recursively check for uses of this type. Note that
6796  * any error message will mention the original type not the
6797  * container; this is intentional.
6798  */
6799  find_composite_type_dependencies(pg_depend->objid,
6800  origRelation, origTypeName);
6801  continue;
6802  }
6803 
6804  /* Else, ignore dependees that aren't relations */
6805  if (pg_depend->classid != RelationRelationId)
6806  continue;
6807 
6808  rel = relation_open(pg_depend->objid, AccessShareLock);
6809  tupleDesc = RelationGetDescr(rel);
6810 
6811  /*
6812  * If objsubid identifies a specific column, refer to that in error
6813  * messages. Otherwise, search to see if there's a user column of the
6814  * type. (We assume system columns are never of interesting types.)
6815  * The search is needed because an index containing an expression
6816  * column of the target type will just be recorded as a whole-relation
6817  * dependency. If we do not find a column of the type, the dependency
6818  * must indicate that the type is transiently referenced in an index
6819  * expression but not stored on disk, which we assume is OK, just as
6820  * we do for references in views. (It could also be that the target
6821  * type is embedded in some container type that is stored in an index
6822  * column, but the previous recursion should catch such cases.)
6823  */
6824  if (pg_depend->objsubid > 0 && pg_depend->objsubid <= tupleDesc->natts)
6825  att = TupleDescAttr(tupleDesc, pg_depend->objsubid - 1);
6826  else
6827  {
6828  att = NULL;
6829  for (int attno = 1; attno <= tupleDesc->natts; attno++)
6830  {
6831  att = TupleDescAttr(tupleDesc, attno - 1);
6832  if (att->atttypid == typeOid && !att->attisdropped)
6833  break;
6834  att = NULL;
6835  }
6836  if (att == NULL)
6837  {
6838  /* No such column, so assume OK */
6840  continue;
6841  }
6842  }
6843 
6844  /*
6845  * We definitely should reject if the relation has storage. If it's
6846  * partitioned, then perhaps we don't have to reject: if there are
6847  * partitions then we'll fail when we find one, else there is no
6848  * stored data to worry about. However, it's possible that the type
6849  * change would affect conclusions about whether the type is sortable
6850  * or hashable and thus (if it's a partitioning column) break the
6851  * partitioning rule. For now, reject for partitioned rels too.
6852  */
6853  if (RELKIND_HAS_STORAGE(rel->rd_rel->relkind) ||
6854  RELKIND_HAS_PARTITIONS(rel->rd_rel->relkind))
6855  {
6856  if (origTypeName)
6857  ereport(ERROR,
6858  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
6859  errmsg("cannot alter type \"%s\" because column \"%s.%s\" uses it",
6860  origTypeName,
6862  NameStr(att->attname))));
6863  else if (origRelation->rd_rel->relkind == RELKIND_COMPOSITE_TYPE)
6864  ereport(ERROR,
6865  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
6866  errmsg("cannot alter type \"%s\" because column \"%s.%s\" uses it",
6867  RelationGetRelationName(origRelation),
6869  NameStr(att->attname))));
6870  else if (origRelation->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
6871  ereport(ERROR,
6872  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
6873  errmsg("cannot alter foreign table \"%s\" because column \"%s.%s\" uses its row type",
6874  RelationGetRelationName(origRelation),
6876  NameStr(att->attname))));
6877  else
6878  ereport(ERROR,
6879  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
6880  errmsg("cannot alter table \"%s\" because column \"%s.%s\" uses its row type",
6881  RelationGetRelationName(origRelation),
6883  NameStr(att->attname))));
6884  }
6885  else if (OidIsValid(rel->rd_rel->reltype))
6886  {
6887  /*
6888  * A view or composite type itself isn't a problem, but we must
6889  * recursively check for indirect dependencies via its rowtype.
6890  */
6892  origRelation, origTypeName);
6893  }
6894 
6896  }
6897 
6898  systable_endscan(depScan);
6899 
6901 }
6902 
6903 
6904 /*
6905  * find_typed_table_dependencies
6906  *
6907  * Check to see if a composite type is being used as the type of a
6908  * typed table. Abort if any are found and behavior is RESTRICT.
6909  * Else return the list of tables.
6910  */
6911 static List *
6912 find_typed_table_dependencies(Oid typeOid, const char *typeName, DropBehavior behavior)
6913 {
6914  Relation classRel;
6915  ScanKeyData key[1];
6916  TableScanDesc scan;
6917  HeapTuple tuple;
6918  List *result = NIL;
6919 
6920  classRel = table_open(RelationRelationId, AccessShareLock);
6921 
6922  ScanKeyInit(&key[0],
6923  Anum_pg_class_reloftype,
6924  BTEqualStrategyNumber, F_OIDEQ,
6925  ObjectIdGetDatum(typeOid));
6926 
6927  scan = table_beginscan_catalog(classRel, 1, key);
6928 
6929  while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
6930  {
6931  Form_pg_class classform = (Form_pg_class) GETSTRUCT(tuple);
6932 
6933  if (behavior == DROP_RESTRICT)
6934  ereport(ERROR,
6935  (errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
6936  errmsg("cannot alter type \"%s\" because it is the type of a typed table",
6937  typeName),
6938  errhint("Use ALTER ... CASCADE to alter the typed tables too.")));
6939  else
6940  result = lappend_oid(result, classform->oid);
6941  }
6942 
6943  table_endscan(scan);
6944  table_close(classRel, AccessShareLock);
6945 
6946  return result;
6947 }
6948 
6949 
6950 /*
6951  * check_of_type
6952  *
6953  * Check whether a type is suitable for CREATE TABLE OF/ALTER TABLE OF. If it
6954  * isn't suitable, throw an error. Currently, we require that the type
6955  * originated with CREATE TYPE AS. We could support any row type, but doing so
6956  * would require handling a number of extra corner cases in the DDL commands.
6957  * (Also, allowing domain-over-composite would open up a can of worms about
6958  * whether and how the domain's constraints should apply to derived tables.)
6959  */
6960 void
6962 {
6963  Form_pg_type typ = (Form_pg_type) GETSTRUCT(typetuple);
6964  bool typeOk = false;
6965 
6966  if (typ->typtype == TYPTYPE_COMPOSITE)
6967  {
6968  Relation typeRelation;
6969 
6970  Assert(OidIsValid(typ->typrelid));
6971  typeRelation = relation_open(typ->typrelid, AccessShareLock);
6972  typeOk = (typeRelation->rd_rel->relkind == RELKIND_COMPOSITE_TYPE);
6973 
6974  /*
6975  * Close the parent rel, but keep our AccessShareLock on it until xact
6976  * commit. That will prevent someone else from deleting or ALTERing
6977  * the type before the typed table creation/conversion commits.
6978  */
6979  relation_close(typeRelation, NoLock);
6980 
6981  if (!typeOk)
6982  ereport(ERROR,
6983  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
6984  errmsg("type %s is the row type of another table",
6985  format_type_be(typ->oid)),
6986  errdetail("A typed table must use a stand-alone composite type created with CREATE TYPE.")));
6987  }
6988  else
6989  ereport(ERROR,
6990  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
6991  errmsg("type %s is not a composite type",
6992  format_type_be(typ->oid))));
6993 }
6994 
6995 
6996 /*
6997  * ALTER TABLE ADD COLUMN
6998  *
6999  * Adds an additional attribute to a relation making the assumption that
7000  * CHECK, NOT NULL, and FOREIGN KEY constraints will be removed from the
7001  * AT_AddColumn AlterTableCmd by parse_utilcmd.c and added as independent
7002  * AlterTableCmd's.
7003  *
7004  * ADD COLUMN cannot use the normal ALTER TABLE recursion mechanism, because we
7005  * have to decide at runtime whether to recurse or not depending on whether we
7006  * actually add a column or merely merge with an existing column. (We can't
7007  * check this in a static pre-pass because it won't handle multiple inheritance
7008  * situations correctly.)
7009  */
7010 static void
7011 ATPrepAddColumn(List **wqueue, Relation rel, bool recurse, bool recursing,
7012  bool is_view, AlterTableCmd *cmd, LOCKMODE lockmode,
7014 {
7015  if (rel->rd_rel->reloftype && !recursing)
7016  ereport(ERROR,
7017  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
7018  errmsg("cannot add column to typed table")));
7019 
7020  if (rel->rd_rel->relkind == RELKIND_COMPOSITE_TYPE)
7021  ATTypedTableRecursion(wqueue, rel, cmd, lockmode, context);
7022 
7023  if (recurse && !is_view)
7024  cmd->recurse = true;
7025 }
7026 
7027 /*
7028  * Add a column to a table. The return value is the address of the
7029  * new column in the parent relation.
7030  *
7031  * cmd is pass-by-ref so that we can replace it with the parse-transformed
7032  * copy (but that happens only after we check for IF NOT EXISTS).
7033  */
7034 static ObjectAddress
7036  AlterTableCmd **cmd, bool recurse, bool recursing,
7037  LOCKMODE lockmode, AlterTablePass cur_pass,
7039 {
7040  Oid myrelid = RelationGetRelid(rel);
7041  ColumnDef *colDef = castNode(ColumnDef, (*cmd)->def);
7042  bool if_not_exists = (*cmd)->missing_ok;
7043  Relation pgclass,
7044  attrdesc;
7045  HeapTuple reltup;
7046  Form_pg_class relform;
7047  Form_pg_attribute attribute;
7048  int newattnum;
7049  char relkind;
7050  Expr *defval;
7051  List *children;
7052  ListCell *child;
7053  AlterTableCmd *childcmd;
7054  ObjectAddress address;
7055  TupleDesc tupdesc;
7056 
7057  /* since this function recurses, it could be driven to stack overflow */
7059 
7060  /* At top level, permission check was done in ATPrepCmd, else do it */
7061  if (recursing)
7062  ATSimplePermissions((*cmd)->subtype, rel,
7064 
7065  if (rel->rd_rel->relispartition && !recursing)
7066  ereport(ERROR,
7067  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
7068  errmsg("cannot add column to a partition")));
7069 
7070  attrdesc = table_open(AttributeRelationId, RowExclusiveLock);
7071 
7072  /*
7073  * Are we adding the column to a recursion child? If so, check whether to
7074  * merge with an existing definition for the column. If we do merge, we
7075  * must not recurse. Children will already have the column, and recursing
7076  * into them would mess up attinhcount.
7077  */
7078  if (colDef->inhcount > 0)
7079  {
7080  HeapTuple tuple;
7081 
7082  /* Does child already have a column by this name? */
7083  tuple = SearchSysCacheCopyAttName(myrelid, colDef->colname);
7084  if (HeapTupleIsValid(tuple))
7085  {
7086  Form_pg_attribute childatt = (Form_pg_attribute) GETSTRUCT(tuple);
7087  Oid ctypeId;
7088  int32 ctypmod;
7089  Oid ccollid;
7090 
7091  /* Child column must match on type, typmod, and collation */
7092  typenameTypeIdAndMod(NULL, colDef->typeName, &ctypeId, &ctypmod);
7093  if (ctypeId != childatt->atttypid ||
7094  ctypmod != childatt->atttypmod)
7095  ereport(ERROR,
7096  (errcode(ERRCODE_DATATYPE_MISMATCH),
7097  errmsg("child table \"%s\" has different type for column \"%s\"",
7098  RelationGetRelationName(rel), colDef->colname)));
7099  ccollid = GetColumnDefCollation(NULL, colDef, ctypeId);
7100  if (ccollid != childatt->attcollation)
7101  ereport(ERROR,
7102  (errcode(ERRCODE_COLLATION_MISMATCH),
7103  errmsg("child table \"%s\" has different collation for column \"%s\"",
7104  RelationGetRelationName(rel), colDef->colname),
7105  errdetail("\"%s\" versus \"%s\"",
7106  get_collation_name(ccollid),
7107  get_collation_name(childatt->attcollation))));
7108 
7109  /* Bump the existing child att's inhcount */
7110  if (pg_add_s16_overflow(childatt->attinhcount, 1,
7111  &childatt->attinhcount))
7112  ereport(ERROR,
7113  errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
7114  errmsg("too many inheritance parents"));
7115  CatalogTupleUpdate(attrdesc, &tuple->t_self, tuple);
7116 
7117  heap_freetuple(tuple);
7118 
7119  /* Inform the user about the merge */
7120  ereport(NOTICE,
7121  (errmsg("merging definition of column \"%s\" for child \"%s\"",
7122  colDef->colname, RelationGetRelationName(rel))));
7123 
7124  table_close(attrdesc, RowExclusiveLock);
7125 
7126  /* Make the child column change visible */
7128 
7129  return InvalidObjectAddress;
7130  }
7131  }
7132 
7133  /* skip if the name already exists and if_not_exists is true */
7134  if (!check_for_column_name_collision(rel, colDef->colname, if_not_exists))
7135  {
7136  table_close(attrdesc, RowExclusiveLock);
7137  return InvalidObjectAddress;
7138  }
7139 
7140  /*
7141  * Okay, we need to add the column, so go ahead and do parse
7142  * transformation. This can result in queueing up, or even immediately
7143  * executing, subsidiary operations (such as creation of unique indexes);
7144  * so we mustn't do it until we have made the if_not_exists check.
7145  *
7146  * When recursing, the command was already transformed and we needn't do
7147  * so again. Also, if context isn't given we can't transform. (That
7148  * currently happens only for AT_AddColumnToView; we expect that view.c
7149  * passed us a ColumnDef that doesn't need work.)
7150  */
7151  if (context != NULL && !recursing)
7152  {
7153  *cmd = ATParseTransformCmd(wqueue, tab, rel, *cmd, recurse, lockmode,
7154  cur_pass, context);
7155  Assert(*cmd != NULL);
7156  colDef = castNode(ColumnDef, (*cmd)->def);
7157  }
7158 
7159  /*
7160  * Regular inheritance children are independent enough not to inherit the
7161  * identity column from parent hence cannot recursively add identity
7162  * column if the table has inheritance children.
7163  *
7164  * Partitions, on the other hand, are integral part of a partitioned table
7165  * and inherit identity column. Hence propagate identity column down the
7166  * partition hierarchy.
7167  */
7168  if (colDef->identity &&
7169  recurse &&
7170  rel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE &&
7171  find_inheritance_children(myrelid, NoLock) != NIL)
7172  ereport(ERROR,
7173  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
7174  errmsg("cannot recursively add identity column to table that has child tables")));
7175 
7176  pgclass = table_open(RelationRelationId, RowExclusiveLock);
7177 
7178  reltup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(myrelid));
7179  if (!HeapTupleIsValid(reltup))
7180  elog(ERROR, "cache lookup failed for relation %u", myrelid);
7181  relform = (Form_pg_class) GETSTRUCT(reltup);
7182  relkind = relform->relkind;
7183 
7184  /* Determine the new attribute's number */
7185  newattnum = relform->relnatts + 1;
7186  if (newattnum > MaxHeapAttributeNumber)
7187  ereport(ERROR,
7188  (errcode(ERRCODE_TOO_MANY_COLUMNS),
7189  errmsg("tables can have at most %d columns",
7191 
7192  /*
7193  * Construct new attribute's pg_attribute entry.
7194  */
7195  tupdesc = BuildDescForRelation(list_make1(colDef));
7196 
7197  attribute = TupleDescAttr(tupdesc, 0);
7198 
7199  /* Fix up attribute number */
7200  attribute->attnum = newattnum;
7201 
7202  /* make sure datatype is legal for a column */
7203  CheckAttributeType(NameStr(attribute->attname), attribute->atttypid, attribute->attcollation,
7204  list_make1_oid(rel->rd_rel->reltype),
7205  0);
7206 
7207  InsertPgAttributeTuples(attrdesc, tupdesc, myrelid, NULL, NULL);
7208 
7209  table_close(attrdesc, RowExclusiveLock);
7210 
7211  /*
7212  * Update pg_class tuple as appropriate
7213  */
7214  relform->relnatts = newattnum;
7215 
7216  CatalogTupleUpdate(pgclass, &reltup->t_self, reltup);
7217 
7218  heap_freetuple(reltup);
7219 
7220  /* Post creation hook for new attribute */
7221  InvokeObjectPostCreateHook(RelationRelationId, myrelid, newattnum);
7222 
7223  table_close(pgclass, RowExclusiveLock);
7224 
7225  /* Make the attribute's catalog entry visible */
7227 
7228  /*
7229  * Store the DEFAULT, if any, in the catalogs
7230  */
7231  if (colDef->raw_default)
7232  {
7233  RawColumnDefault *rawEnt;
7234 
7235  rawEnt = (RawColumnDefault *) palloc(sizeof(RawColumnDefault));
7236  rawEnt->attnum = attribute->attnum;
7237  rawEnt->raw_default = copyObject(colDef->raw_default);
7238 
7239  /*
7240  * Attempt to skip a complete table rewrite by storing the specified
7241  * DEFAULT value outside of the heap. This may be disabled inside
7242  * AddRelationNewConstraints if the optimization cannot be applied.
7243  */
7244  rawEnt->missingMode = (!colDef->generated);
7245 
7246  rawEnt->generated = colDef->generated;
7247 
7248  /*
7249  * This function is intended for CREATE TABLE, so it processes a
7250  * _list_ of defaults, but we just do one.
7251  */
7253  false, true, false, NULL);
7254 
7255  /* Make the additional catalog changes visible */
7257 
7258  /*
7259  * Did the request for a missing value work? If not we'll have to do a
7260  * rewrite
7261  */
7262  if (!rawEnt->missingMode)
7264  }
7265 
7266  /*
7267  * Tell Phase 3 to fill in the default expression, if there is one.
7268  *
7269  * If there is no default, Phase 3 doesn't have to do anything, because
7270  * that effectively means that the default is NULL. The heap tuple access
7271  * routines always check for attnum > # of attributes in tuple, and return
7272  * NULL if so, so without any modification of the tuple data we will get
7273  * the effect of NULL values in the new column.
7274  *
7275  * An exception occurs when the new column is of a domain type: the domain
7276  * might have a not-null constraint, or a check constraint that indirectly
7277  * rejects nulls. If there are any domain constraints then we construct
7278  * an explicit NULL default value that will be passed through
7279  * CoerceToDomain processing. (This is a tad inefficient, since it causes
7280  * rewriting the table which we really don't have to do, but the present
7281  * design of domain processing doesn't offer any simple way of checking
7282  * the constraints more directly.)
7283  *
7284  * Note: we use build_column_default, and not just the cooked default
7285  * returned by AddRelationNewConstraints, so that the right thing happens
7286  * when a datatype's default applies.
7287  *
7288  * Note: it might seem that this should happen at the end of Phase 2, so
7289  * that the effects of subsequent subcommands can be taken into account.
7290  * It's intentional that we do it now, though. The new column should be
7291  * filled according to what is said in the ADD COLUMN subcommand, so that
7292  * the effects are the same as if this subcommand had been run by itself
7293  * and the later subcommands had been issued in new ALTER TABLE commands.
7294  *
7295  * We can skip this entirely for relations without storage, since Phase 3
7296  * is certainly not going to touch them. System attributes don't have
7297  * interesting defaults, either.
7298  */
7299  if (RELKIND_HAS_STORAGE(relkind))
7300  {
7301  /*
7302  * For an identity column, we can't use build_column_default(),
7303  * because the sequence ownership isn't set yet. So do it manually.
7304  */
7305  if (colDef->identity)
7306  {
7308 
7309  nve->seqid = RangeVarGetRelid(colDef->identitySequence, NoLock, false);
7310  nve->typeId = attribute->atttypid;
7311 
7312  defval = (Expr *) nve;
7313 
7314  /* must do a rewrite for identity columns */
7316  }
7317  else
7318  defval = (Expr *) build_column_default(rel, attribute->attnum);
7319 
7320  if (!defval && DomainHasConstraints(attribute->atttypid))
7321  {
7322  Oid baseTypeId;
7323  int32 baseTypeMod;
7324  Oid baseTypeColl;
7325 
7326  baseTypeMod = attribute->atttypmod;
7327  baseTypeId = getBaseTypeAndTypmod(attribute->atttypid, &baseTypeMod);
7328  baseTypeColl = get_typcollation(baseTypeId);
7329  defval = (Expr *) makeNullConst(baseTypeId, baseTypeMod, baseTypeColl);
7330  defval = (Expr *) coerce_to_target_type(NULL,
7331  (Node *) defval,
7332  baseTypeId,
7333  attribute->atttypid,
7334  attribute->atttypmod,
7337  -1);
7338  if (defval == NULL) /* should not happen */
7339  elog(ERROR, "failed to coerce base type to domain");
7340  }
7341 
7342  if (defval)
7343  {
7345 
7347  newval->attnum = attribute->attnum;
7348  newval->expr = expression_planner(defval);
7349  newval->is_generated = (colDef->generated != '\0');
7350 
7351  tab->newvals = lappend(tab->newvals, newval);
7352  }
7353 
7354  if (DomainHasConstraints(attribute->atttypid))
7356 
7357  if (!TupleDescAttr(rel->rd_att, attribute->attnum - 1)->atthasmissing)
7358  {
7359  /*
7360  * If the new column is NOT NULL, and there is no missing value,
7361  * tell Phase 3 it needs to check for NULLs.
7362  */
7363  tab->verify_new_notnull |= colDef->is_not_null;
7364  }
7365  }
7366 
7367  /*
7368  * Add needed dependency entries for the new column.
7369  */
7370  add_column_datatype_dependency(myrelid, newattnum, attribute->atttypid);
7371  add_column_collation_dependency(myrelid, newattnum, attribute->attcollation);
7372 
7373  /*
7374  * Propagate to children as appropriate. Unlike most other ALTER
7375  * routines, we have to do this one level of recursion at a time; we can't
7376  * use find_all_inheritors to do it in one pass.
7377  */
7378  children =
7380 
7381  /*
7382  * If we are told not to recurse, there had better not be any child
7383  * tables; else the addition would put them out of step.
7384  */
7385  if (children && !recurse)
7386  ereport(ERROR,
7387  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
7388  errmsg("column must be added to child tables too")));
7389 
7390  /* Children should see column as singly inherited */
7391  if (!recursing)
7392  {
7393  childcmd = copyObject(*cmd);
7394  colDef = castNode(ColumnDef, childcmd->def);
7395  colDef->inhcount = 1;
7396  colDef->is_local = false;
7397  }
7398  else
7399  childcmd = *cmd; /* no need to copy again */
7400 
7401  foreach(child, children)
7402  {
7403  Oid childrelid = lfirst_oid(child);
7404  Relation childrel;
7405  AlteredTableInfo *childtab;
7406 
7407  /* find_inheritance_children already got lock */
7408  childrel = table_open(childrelid, NoLock);
7409  CheckAlterTableIsSafe(childrel);
7410 
7411  /* Find or create work queue entry for this table */
7412  childtab = ATGetQueueEntry(wqueue, childrel);
7413 
7414  /* Recurse to child; return value is ignored */
7415  ATExecAddColumn(wqueue, childtab, childrel,
7416  &childcmd, recurse, true,
7417  lockmode, cur_pass, context);
7418 
7419  table_close(childrel, NoLock);
7420  }
7421 
7422  ObjectAddressSubSet(address, RelationRelationId, myrelid, newattnum);
7423  return address;
7424 }
7425 
7426 /*
7427  * If a new or renamed column will collide with the name of an existing
7428  * column and if_not_exists is false then error out, else do nothing.
7429  */
7430 static bool
7432  bool if_not_exists)
7433 {
7434  HeapTuple attTuple;
7435  int attnum;
7436 
7437  /*
7438  * this test is deliberately not attisdropped-aware, since if one tries to
7439  * add a column matching a dropped column name, it's gonna fail anyway.
7440  */
7441  attTuple = SearchSysCache2(ATTNAME,
7443  PointerGetDatum(colname));
7444  if (!HeapTupleIsValid(attTuple))
7445  return true;
7446 
7447  attnum = ((Form_pg_attribute) GETSTRUCT(attTuple))->attnum;
7448  ReleaseSysCache(attTuple);
7449 
7450  /*
7451  * We throw a different error message for conflicts with system column
7452  * names, since they are normally not shown and the user might otherwise
7453  * be confused about the reason for the conflict.
7454  */
7455  if (attnum <= 0)
7456  ereport(ERROR,
7457  (errcode(ERRCODE_DUPLICATE_COLUMN),
7458  errmsg("column name \"%s\" conflicts with a system column name",
7459  colname)));
7460  else
7461  {
7462  if (if_not_exists)
7463  {
7464  ereport(NOTICE,
7465  (errcode(ERRCODE_DUPLICATE_COLUMN),
7466  errmsg("column \"%s\" of relation \"%s\" already exists, skipping",
7467  colname, RelationGetRelationName(rel))));
7468  return false;
7469  }
7470 
7471  ereport(ERROR,
7472  (errcode(ERRCODE_DUPLICATE_COLUMN),
7473  errmsg("column \"%s\" of relation \"%s\" already exists",
7474  colname, RelationGetRelationName(rel))));
7475  }
7476 
7477  return true;
7478 }
7479 
7480 /*
7481  * Install a column's dependency on its datatype.
7482  */
7483 static void
7485 {
7486  ObjectAddress myself,
7487  referenced;
7488 
7489  myself.classId = RelationRelationId;
7490  myself.objectId = relid;
7491  myself.objectSubId = attnum;
7492  referenced.classId = TypeRelationId;
7493  referenced.objectId = typid;
7494  referenced.objectSubId = 0;
7495  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
7496 }
7497 
7498 /*
7499  * Install a column's dependency on its collation.
7500  */
7501 static void
7503 {
7504  ObjectAddress myself,
7505  referenced;
7506 
7507  /* We know the default collation is pinned, so don't bother recording it */
7508  if (OidIsValid(collid) && collid != DEFAULT_COLLATION_OID)
7509  {
7510  myself.classId = RelationRelationId;
7511  myself.objectId = relid;
7512  myself.objectSubId = attnum;
7513  referenced.classId = CollationRelationId;
7514  referenced.objectId = collid;
7515  referenced.objectSubId = 0;
7516  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
7517  }
7518 }
7519 
7520 /*
7521  * ALTER TABLE ALTER COLUMN DROP NOT NULL
7522  *
7523  * Return the address of the modified column. If the column was already
7524  * nullable, InvalidObjectAddress is returned.
7525  */
7526 static ObjectAddress
7527 ATExecDropNotNull(Relation rel, const char *colName, LOCKMODE lockmode)
7528 {
7529  HeapTuple tuple;
7530  Form_pg_attribute attTup;
7532  Relation attr_rel;
7533  List *indexoidlist;
7534  ObjectAddress address;
7535 
7536  /*
7537  * lookup the attribute
7538  */
7539  attr_rel = table_open(AttributeRelationId, RowExclusiveLock);
7540 
7541  tuple = SearchSysCacheCopyAttName(RelationGetRelid(rel), colName);
7542  if (!HeapTupleIsValid(tuple))
7543  ereport(ERROR,
7544  (errcode(ERRCODE_UNDEFINED_COLUMN),
7545  errmsg("column \"%s\" of relation \"%s\" does not exist",
7546  colName, RelationGetRelationName(rel))));
7547  attTup = (Form_pg_attribute) GETSTRUCT(tuple);
7548  attnum = attTup->attnum;
7549 
7550  /* Prevent them from altering a system attribute */
7551  if (attnum <= 0)
7552  ereport(ERROR,
7553  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
7554  errmsg("cannot alter system column \"%s\"",
7555  colName)));
7556 
7557  if (attTup->attidentity)
7558  ereport(ERROR,
7559  (errcode(ERRCODE_SYNTAX_ERROR),
7560  errmsg("column \"%s\" of relation \"%s\" is an identity column",
7561  colName, RelationGetRelationName(rel))));
7562 
7563  /*
7564  * Check that the attribute is not in a primary key or in an index used as
7565  * a replica identity.
7566  *
7567  * Note: we'll throw error even if the pkey index is not valid.
7568  */
7569 
7570  /* Loop over all indexes on the relation */
7571  indexoidlist = RelationGetIndexList(rel);
7572 
7573  foreach_oid(indexoid, indexoidlist)
7574  {
7575  HeapTuple indexTuple;
7576  Form_pg_index indexStruct;
7577 
7578  indexTuple = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(indexoid));
7579  if (!HeapTupleIsValid(indexTuple))
7580  elog(ERROR, "cache lookup failed for index %u", indexoid);
7581  indexStruct = (Form_pg_index) GETSTRUCT(indexTuple);
7582 
7583  /*
7584  * If the index is not a primary key or an index used as replica
7585  * identity, skip the check.
7586  */
7587  if (indexStruct->indisprimary || indexStruct->indisreplident)
7588  {
7589  /*
7590  * Loop over each attribute in the primary key or the index used
7591  * as replica identity and see if it matches the to-be-altered
7592  * attribute.
7593  */
7594  for (int i = 0; i < indexStruct->indnkeyatts; i++)
7595  {
7596  if (indexStruct->indkey.values[i] == attnum)
7597  {
7598  if (indexStruct->indisprimary)
7599  ereport(ERROR,
7600  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
7601  errmsg("column \"%s\" is in a primary key",
7602  colName)));
7603  else
7604  ereport(ERROR,
7605  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
7606  errmsg("column \"%s\" is in index used as replica identity",
7607  colName)));
7608  }
7609  }
7610  }
7611 
7612  ReleaseSysCache(indexTuple);
7613  }
7614 
7615  list_free(indexoidlist);
7616 
7617  /* If rel is partition, shouldn't drop NOT NULL if parent has the same */
7618  if (rel->rd_rel->relispartition)
7619  {
7620  Oid parentId = get_partition_parent(RelationGetRelid(rel), false);
7621  Relation parent = table_open(parentId, AccessShareLock);
7622  TupleDesc tupDesc = RelationGetDescr(parent);
7623  AttrNumber parent_attnum;
7624 
7625  parent_attnum = get_attnum(parentId, colName);
7626  if (TupleDescAttr(tupDesc, parent_attnum - 1)->attnotnull)
7627  ereport(ERROR,
7628  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
7629  errmsg("column \"%s\" is marked NOT NULL in parent table",
7630  colName)));
7631  table_close(parent, AccessShareLock);
7632  }
7633 
7634  /*
7635  * Okay, actually perform the catalog change ... if needed
7636  */
7637  if (attTup->attnotnull)
7638  {
7639  attTup->attnotnull = false;
7640 
7641  CatalogTupleUpdate(attr_rel, &tuple->t_self, tuple);
7642 
7643  ObjectAddressSubSet(address, RelationRelationId,
7644  RelationGetRelid(rel), attnum);
7645  }
7646  else
7647  address = InvalidObjectAddress;
7648 
7649  InvokeObjectPostAlterHook(RelationRelationId,
7650  RelationGetRelid(rel), attnum);
7651 
7652  table_close(attr_rel, RowExclusiveLock);
7653 
7654  return address;
7655 }
7656 
7657 /*
7658  * ALTER TABLE ALTER COLUMN SET NOT NULL
7659  */
7660 
7661 static void
7663  AlterTableCmd *cmd, bool recurse, bool recursing,
7665 {
7666  /*
7667  * If we're already recursing, there's nothing to do; the topmost
7668  * invocation of ATSimpleRecursion already visited all children.
7669  */
7670  if (recursing)
7671  return;
7672 
7673  /*
7674  * If the target column is already marked NOT NULL, we can skip recursing
7675  * to children, because their columns should already be marked NOT NULL as
7676  * well. But there's no point in checking here unless the relation has
7677  * some children; else we can just wait till execution to check. (If it
7678  * does have children, however, this can save taking per-child locks
7679  * unnecessarily. This greatly improves concurrency in some parallel
7680  * restore scenarios.)
7681  *
7682  * Unfortunately, we can only apply this optimization to partitioned
7683  * tables, because traditional inheritance doesn't enforce that child
7684  * columns be NOT NULL when their parent is. (That's a bug that should
7685  * get fixed someday.)
7686  */
7687  if (rel->rd_rel->relhassubclass &&
7688  rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
7689  {
7690  HeapTuple tuple;
7691  bool attnotnull;
7692 
7693  tuple = SearchSysCacheAttName(RelationGetRelid(rel), cmd->name);
7694 
7695  /* Might as well throw the error now, if name is bad */
7696  if (!HeapTupleIsValid(tuple))
7697  ereport(ERROR,
7698  (errcode(ERRCODE_UNDEFINED_COLUMN),
7699  errmsg("column \"%s\" of relation \"%s\" does not exist",
7700  cmd->name, RelationGetRelationName(rel))));
7701 
7703  ReleaseSysCache(tuple);
7704  if (attnotnull)
7705  return;
7706  }
7707 
7708  /*
7709  * If we have ALTER TABLE ONLY ... SET NOT NULL on a partitioned table,
7710  * apply ALTER TABLE ... CHECK NOT NULL to every child. Otherwise, use
7711  * normal recursion logic.
7712  */
7713  if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE &&
7714  !recurse)
7715  {
7717 
7718  newcmd->subtype = AT_CheckNotNull;
7719  newcmd->name = pstrdup(cmd->name);
7720  ATSimpleRecursion(wqueue, rel, newcmd, true, lockmode, context);
7721  }
7722  else
7723  ATSimpleRecursion(wqueue, rel, cmd, recurse, lockmode, context);
7724 }
7725 
7726 /*
7727  * Return the address of the modified column. If the column was already NOT
7728  * NULL, InvalidObjectAddress is returned.
7729  */
7730 static ObjectAddress
7732  const char *colName, LOCKMODE lockmode)
7733 {
7734  HeapTuple tuple;
7735  Form_pg_attribute attTup;
7737  Relation attr_rel;
7738  ObjectAddress address;
7739 
7740  /*
7741  * lookup the attribute
7742  */
7743  attr_rel = table_open(AttributeRelationId, RowExclusiveLock);
7744 
7745  tuple = SearchSysCacheCopyAttName(RelationGetRelid(rel), colName);
7746 
7747  if (!HeapTupleIsValid(tuple))
7748  ereport(ERROR,
7749  (errcode(ERRCODE_UNDEFINED_COLUMN),
7750  errmsg("column \"%s\" of relation \"%s\" does not exist",
7751  colName, RelationGetRelationName(rel))));
7752 
7753  attTup = (Form_pg_attribute) GETSTRUCT(tuple);
7754  attnum = attTup->attnum;
7755 
7756  /* Prevent them from altering a system attribute */
7757  if (attnum <= 0)
7758  ereport(ERROR,
7759  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
7760  errmsg("cannot alter system column \"%s\"",
7761  colName)));
7762 
7763  /*
7764  * Okay, actually perform the catalog change ... if needed
7765  */
7766  if (!attTup->attnotnull)
7767  {
7768  attTup->attnotnull = true;
7769 
7770  CatalogTupleUpdate(attr_rel, &tuple->t_self, tuple);
7771 
7772  /*
7773  * Ordinarily phase 3 must ensure that no NULLs exist in columns that
7774  * are set NOT NULL; however, if we can find a constraint which proves
7775  * this then we can skip that. We needn't bother looking if we've
7776  * already found that we must verify some other not-null constraint.
7777  */
7778  if (!tab->verify_new_notnull && !NotNullImpliedByRelConstraints(rel, attTup))
7779  {
7780  /* Tell Phase 3 it needs to test the constraint */
7781  tab->verify_new_notnull = true;
7782  }
7783 
7784  ObjectAddressSubSet(address, RelationRelationId,
7785  RelationGetRelid(rel), attnum);
7786  }
7787  else
7788  address = InvalidObjectAddress;
7789 
7790  InvokeObjectPostAlterHook(RelationRelationId,
7791  RelationGetRelid(rel), attnum);
7792 
7793  table_close(attr_rel, RowExclusiveLock);
7794 
7795  return address;
7796 }
7797 
7798 /*
7799  * ALTER TABLE ALTER COLUMN CHECK NOT NULL
7800  *
7801  * This doesn't exist in the grammar, but we generate AT_CheckNotNull
7802  * commands against the partitions of a partitioned table if the user
7803  * writes ALTER TABLE ONLY ... SET NOT NULL on the partitioned table,
7804  * or tries to create a primary key on it (which internally creates
7805  * AT_SetNotNull on the partitioned table). Such a command doesn't
7806  * allow us to actually modify any partition, but we want to let it
7807  * go through if the partitions are already properly marked.
7808  *
7809  * In future, this might need to adjust the child table's state, likely
7810  * by incrementing an inheritance count for the attnotnull constraint.
7811  * For now we need only check for the presence of the flag.
7812  */
7813 static void
7815  const char *colName, LOCKMODE lockmode)
7816 {
7817  HeapTuple tuple;
7818 
7819  tuple = SearchSysCacheAttName(RelationGetRelid(rel), colName);
7820 
7821  if (!HeapTupleIsValid(tuple))
7822  ereport(ERROR,
7823  errcode(ERRCODE_UNDEFINED_COLUMN),
7824  errmsg("column \"%s\" of relation \"%s\" does not exist",
7825  colName, RelationGetRelationName(rel)));
7826 
7827  if (!((Form_pg_attribute) GETSTRUCT(tuple))->attnotnull)
7828  ereport(ERROR,
7829  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
7830  errmsg("constraint must be added to child tables too"),
7831  errdetail("Column \"%s\" of relation \"%s\" is not already NOT NULL.",
7832  colName, RelationGetRelationName(rel)),
7833  errhint("Do not specify the ONLY keyword.")));
7834 
7835  ReleaseSysCache(tuple);
7836 }
7837 
7838 /*
7839  * NotNullImpliedByRelConstraints
7840  * Does rel's existing constraints imply NOT NULL for the given attribute?
7841  */
7842 static bool
7844 {
7845  NullTest *nnulltest = makeNode(NullTest);
7846 
7847  nnulltest->arg = (Expr *) makeVar(1,
7848  attr->attnum,
7849  attr->atttypid,
7850  attr->atttypmod,
7851  attr->attcollation,
7852  0);
7853  nnulltest->nulltesttype = IS_NOT_NULL;
7854 
7855  /*
7856  * argisrow = false is correct even for a composite column, because
7857  * attnotnull does not represent a SQL-spec IS NOT NULL test in such a
7858  * case, just IS DISTINCT FROM NULL.
7859  */
7860  nnulltest->argisrow = false;
7861  nnulltest->location = -1;
7862 
7863  if (ConstraintImpliedByRelConstraint(rel, list_make1(nnulltest), NIL))
7864  {
7865  ereport(DEBUG1,
7866  (errmsg_internal("existing constraints on column \"%s.%s\" are sufficient to prove that it does not contain nulls",
7867  RelationGetRelationName(rel), NameStr(attr->attname))));
7868  return true;
7869  }
7870 
7871  return false;
7872 }
7873 
7874 /*
7875  * ALTER TABLE ALTER COLUMN SET/DROP DEFAULT
7876  *
7877  * Return the address of the affected column.
7878  */
7879 static ObjectAddress
7880 ATExecColumnDefault(Relation rel, const char *colName,
7881  Node *newDefault, LOCKMODE lockmode)
7882 {
7883  TupleDesc tupdesc = RelationGetDescr(rel);
7885  ObjectAddress address;
7886 
7887  /*
7888  * get the number of the attribute
7889  */
7890  attnum = get_attnum(RelationGetRelid(rel), colName);
7891  if (attnum == InvalidAttrNumber)
7892  ereport(ERROR,
7893  (errcode(ERRCODE_UNDEFINED_COLUMN),
7894  errmsg("column \"%s\" of relation \"%s\" does not exist",
7895  colName, RelationGetRelationName(rel))));
7896 
7897  /* Prevent them from altering a system attribute */
7898  if (attnum <= 0)
7899  ereport(ERROR,
7900  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
7901  errmsg("cannot alter system column \"%s\"",
7902  colName)));
7903 
7904  if (TupleDescAttr(tupdesc, attnum - 1)->attidentity)
7905  ereport(ERROR,
7906  (errcode(ERRCODE_SYNTAX_ERROR),
7907  errmsg("column \"%s\" of relation \"%s\" is an identity column",
7908  colName, RelationGetRelationName(rel)),
7909  /* translator: %s is an SQL ALTER command */
7910  newDefault ? 0 : errhint("Use %s instead.",
7911  "ALTER TABLE ... ALTER COLUMN ... DROP IDENTITY")));
7912 
7913  if (TupleDescAttr(tupdesc, attnum - 1)->attgenerated)
7914  ereport(ERROR,
7915  (errcode(ERRCODE_SYNTAX_ERROR),
7916  errmsg("column \"%s\" of relation \"%s\" is a generated column",
7917  colName, RelationGetRelationName(rel)),
7918  newDefault ?
7919  /* translator: %s is an SQL ALTER command */
7920  errhint("Use %s instead.", "ALTER TABLE ... ALTER COLUMN ... SET EXPRESSION") :
7921  (TupleDescAttr(tupdesc, attnum - 1)->attgenerated == ATTRIBUTE_GENERATED_STORED ?
7922  errhint("Use %s instead.", "ALTER TABLE ... ALTER COLUMN ... DROP EXPRESSION") : 0)));
7923 
7924  /*
7925  * Remove any old default for the column. We use RESTRICT here for
7926  * safety, but at present we do not expect anything to depend on the
7927  * default.
7928  *
7929  * We treat removing the existing default as an internal operation when it
7930  * is preparatory to adding a new default, but as a user-initiated
7931  * operation when the user asked for a drop.
7932  */
7934  newDefault != NULL);
7935 
7936  if (newDefault)
7937  {
7938  /* SET DEFAULT */
7939  RawColumnDefault *rawEnt;
7940 
7941  rawEnt = (RawColumnDefault *) palloc(sizeof(RawColumnDefault));
7942  rawEnt->attnum = attnum;
7943  rawEnt->raw_default = newDefault;
7944  rawEnt->missingMode = false;
7945  rawEnt->generated = '\0';
7946 
7947  /*
7948  * This function is intended for CREATE TABLE, so it processes a
7949  * _list_ of defaults, but we just do one.
7950  */
7952  false, true, false, NULL);
7953  }
7954 
7955  ObjectAddressSubSet(address, RelationRelationId,
7956  RelationGetRelid(rel), attnum);
7957  return address;
7958 }
7959 
7960 /*
7961  * Add a pre-cooked default expression.
7962  *
7963  * Return the address of the affected column.
7964  */
7965 static ObjectAddress
7967  Node *newDefault)
7968 {
7969  ObjectAddress address;
7970 
7971  /* We assume no checking is required */
7972 
7973  /*
7974  * Remove any old default for the column. We use RESTRICT here for
7975  * safety, but at present we do not expect anything to depend on the
7976  * default. (In ordinary cases, there could not be a default in place
7977  * anyway, but it's possible when combining LIKE with inheritance.)
7978  */
7980  true);
7981 
7982  (void) StoreAttrDefault(rel, attnum, newDefault, true, false);
7983 
7984  ObjectAddressSubSet(address, RelationRelationId,
7985  RelationGetRelid(rel), attnum);
7986  return address;
7987 }
7988 
7989 /*
7990  * ALTER TABLE ALTER COLUMN ADD IDENTITY
7991  *
7992  * Return the address of the affected column.
7993  */
7994 static ObjectAddress
7995 ATExecAddIdentity(Relation rel, const char *colName,
7996  Node *def, LOCKMODE lockmode, bool recurse, bool recursing)
7997 {
7998  Relation attrelation;
7999  HeapTuple tuple;
8000  Form_pg_attribute attTup;
8002  ObjectAddress address;
8003  ColumnDef *cdef = castNode(ColumnDef, def);
8004  bool ispartitioned;
8005 
8006  ispartitioned = (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
8007  if (ispartitioned && !recurse)
8008  ereport(ERROR,
8009  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
8010  errmsg("cannot add identity to a column of only the partitioned table"),
8011  errhint("Do not specify the ONLY keyword.")));
8012 
8013  if (rel->rd_rel->relispartition && !recursing)
8014  ereport(ERROR,
8015  errcode(ERRCODE_INVALID_TABLE_DEFINITION),
8016  errmsg("cannot add identity to a column of a partition"));
8017 
8018  attrelation = table_open(AttributeRelationId, RowExclusiveLock);
8019 
8020  tuple = SearchSysCacheCopyAttName(RelationGetRelid(rel), colName);
8021  if (!HeapTupleIsValid(tuple))
8022  ereport(ERROR,
8023  (errcode(ERRCODE_UNDEFINED_COLUMN),
8024  errmsg("column \"%s\" of relation \"%s\" does not exist",
8025  colName, RelationGetRelationName(rel))));
8026  attTup = (Form_pg_attribute) GETSTRUCT(tuple);
8027  attnum = attTup->attnum;
8028 
8029  /* Can't alter a system attribute */
8030  if (attnum <= 0)
8031  ereport(ERROR,
8032  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
8033  errmsg("cannot alter system column \"%s\"",
8034  colName)));
8035 
8036  /*
8037  * Creating a column as identity implies NOT NULL, so adding the identity
8038  * to an existing column that is not NOT NULL would create a state that
8039  * cannot be reproduced without contortions.
8040  */
8041  if (!attTup->attnotnull)
8042  ereport(ERROR,
8043  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
8044  errmsg("column \"%s\" of relation \"%s\" must be declared NOT NULL before identity can be added",
8045  colName, RelationGetRelationName(rel))));
8046 
8047  if (attTup->attidentity)
8048  ereport(ERROR,
8049  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
8050  errmsg("column \"%s\" of relation \"%s\" is already an identity column",
8051  colName, RelationGetRelationName(rel))));
8052 
8053  if (attTup->atthasdef)
8054  ereport(ERROR,
8055  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
8056  errmsg("column \"%s\" of relation \"%s\" already has a default value",
8057  colName, RelationGetRelationName(rel))));
8058 
8059  attTup->attidentity = cdef->identity;
8060  CatalogTupleUpdate(attrelation, &tuple->t_self, tuple);
8061 
8062  InvokeObjectPostAlterHook(RelationRelationId,
8063  RelationGetRelid(rel),
8064  attTup->attnum);
8065  ObjectAddressSubSet(address, RelationRelationId,
8066  RelationGetRelid(rel), attnum);
8067  heap_freetuple(tuple);
8068 
8069  table_close(attrelation, RowExclusiveLock);
8070 
8071  /*
8072  * Recurse to propagate the identity column to partitions. Identity is
8073  * not inherited in regular inheritance children.
8074  */
8075  if (recurse && ispartitioned)
8076  {
8077  List *children;
8078  ListCell *lc;
8079 
8080  children = find_inheritance_children(RelationGetRelid(rel), lockmode);
8081 
8082  foreach(lc, children)
8083  {
8084  Relation childrel;
8085 
8086  childrel = table_open(lfirst_oid(lc), NoLock);
8087  ATExecAddIdentity(childrel, colName, def, lockmode, recurse, true);
8088  table_close(childrel, NoLock);
8089  }
8090  }
8091 
8092  return address;
8093 }
8094 
8095 /*
8096  * ALTER TABLE ALTER COLUMN SET { GENERATED or sequence options }
8097  *
8098  * Return the address of the affected column.
8099  */
8100 static ObjectAddress
8101 ATExecSetIdentity(Relation rel, const char *colName, Node *def,
8102  LOCKMODE lockmode, bool recurse, bool recursing)
8103 {
8104  ListCell *option;
8105  DefElem *generatedEl = NULL;
8106  HeapTuple tuple;
8107  Form_pg_attribute attTup;
8109  Relation attrelation;
8110  ObjectAddress address;
8111  bool ispartitioned;
8112 
8113  ispartitioned = (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
8114  if (ispartitioned && !recurse)
8115  ereport(ERROR,
8116  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
8117  errmsg("cannot change identity column of only the partitioned table"),
8118  errhint("Do not specify the ONLY keyword.")));
8119 
8120  if (rel->rd_rel->relispartition && !recursing)
8121  ereport(ERROR,
8122  errcode(ERRCODE_INVALID_TABLE_DEFINITION),
8123  errmsg("cannot change identity column of a partition"));
8124 
8125  foreach(option, castNode(List, def))
8126  {
8127  DefElem *defel = lfirst_node(DefElem, option);
8128 
8129  if (strcmp(defel->defname, "generated") == 0)
8130  {
8131  if (generatedEl)
8132  ereport(ERROR,
8133  (errcode(ERRCODE_SYNTAX_ERROR),
8134  errmsg("conflicting or redundant options")));
8135  generatedEl = defel;
8136  }
8137  else
8138  elog(ERROR, "option \"%s\" not recognized",
8139  defel->defname);
8140  }
8141 
8142  /*
8143  * Even if there is nothing to change here, we run all the checks. There
8144  * will be a subsequent ALTER SEQUENCE that relies on everything being
8145  * there.
8146  */
8147 
8148  attrelation = table_open(AttributeRelationId, RowExclusiveLock);
8149  tuple = SearchSysCacheCopyAttName(RelationGetRelid(rel), colName);
8150  if (!HeapTupleIsValid(tuple))
8151  ereport(ERROR,
8152  (errcode(ERRCODE_UNDEFINED_COLUMN),
8153  errmsg("column \"%s\" of relation \"%s\" does not exist",
8154  colName, RelationGetRelationName(rel))));
8155 
8156  attTup = (Form_pg_attribute) GETSTRUCT(tuple);
8157  attnum = attTup->attnum;
8158 
8159  if (attnum <= 0)
8160  ereport(ERROR,
8161  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
8162  errmsg("cannot alter system column \"%s\"",
8163  colName)));
8164 
8165  if (!attTup->attidentity)
8166  ereport(ERROR,
8167  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
8168  errmsg("column \"%s\" of relation \"%s\" is not an identity column",
8169  colName, RelationGetRelationName(rel))));
8170 
8171  if (generatedEl)
8172  {
8173  attTup->attidentity = defGetInt32(generatedEl);
8174  CatalogTupleUpdate(attrelation, &tuple->t_self, tuple);
8175 
8176  InvokeObjectPostAlterHook(RelationRelationId,
8177  RelationGetRelid(rel),
8178  attTup->attnum);
8179  ObjectAddressSubSet(address, RelationRelationId,
8180  RelationGetRelid(rel), attnum);
8181  }
8182  else
8183  address = InvalidObjectAddress;
8184 
8185  heap_freetuple(tuple);
8186  table_close(attrelation, RowExclusiveLock);
8187 
8188  /*
8189  * Recurse to propagate the identity change to partitions. Identity is not
8190  * inherited in regular inheritance children.
8191  */
8192  if (generatedEl && recurse && ispartitioned)
8193  {
8194  List *children;
8195  ListCell *lc;
8196 
8197  children = find_inheritance_children(RelationGetRelid(rel), lockmode);
8198 
8199  foreach(lc, children)
8200  {
8201  Relation childrel;
8202 
8203  childrel = table_open(lfirst_oid(lc), NoLock);
8204  ATExecSetIdentity(childrel, colName, def, lockmode, recurse, true);
8205  table_close(childrel, NoLock);
8206  }
8207  }
8208 
8209  return address;
8210 }
8211 
8212 /*
8213  * ALTER TABLE ALTER COLUMN DROP IDENTITY
8214  *
8215  * Return the address of the affected column.
8216  */
8217 static ObjectAddress
8218 ATExecDropIdentity(Relation rel, const char *colName, bool missing_ok, LOCKMODE lockmode,
8219  bool recurse, bool recursing)
8220 {
8221  HeapTuple tuple;
8222  Form_pg_attribute attTup;
8224  Relation attrelation;
8225  ObjectAddress address;
8226  Oid seqid;
8227  ObjectAddress seqaddress;
8228  bool ispartitioned;
8229 
8230  ispartitioned = (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
8231  if (ispartitioned && !recurse)
8232  ereport(ERROR,
8233  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
8234  errmsg("cannot drop identity from a column of only the partitioned table"),
8235  errhint("Do not specify the ONLY keyword.")));
8236 
8237  if (rel->rd_rel->relispartition && !recursing)
8238  ereport(ERROR,
8239  errcode(ERRCODE_INVALID_TABLE_DEFINITION),
8240  errmsg("cannot drop identity from a column of a partition"));
8241 
8242  attrelation = table_open(AttributeRelationId, RowExclusiveLock);
8243  tuple = SearchSysCacheCopyAttName(RelationGetRelid(rel), colName);
8244  if (!HeapTupleIsValid(tuple))
8245  ereport(ERROR,
8246  (errcode(ERRCODE_UNDEFINED_COLUMN),
8247  errmsg("column \"%s\" of relation \"%s\" does not exist",
8248  colName, RelationGetRelationName(rel))));
8249 
8250  attTup = (Form_pg_attribute) GETSTRUCT(tuple);
8251  attnum = attTup->attnum;
8252 
8253  if (attnum <= 0)
8254  ereport(ERROR,
8255  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
8256  errmsg("cannot alter system column \"%s\"",
8257  colName)));
8258 
8259  if (!attTup->attidentity)
8260  {
8261  if (!missing_ok)
8262  ereport(ERROR,
8263  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
8264  errmsg("column \"%s\" of relation \"%s\" is not an identity column",
8265  colName, RelationGetRelationName(rel))));
8266  else
8267  {
8268  ereport(NOTICE,
8269  (errmsg("column \"%s\" of relation \"%s\" is not an identity column, skipping",
8270  colName, RelationGetRelationName(rel))));
8271  heap_freetuple(tuple);
8272  table_close(attrelation, RowExclusiveLock);
8273  return InvalidObjectAddress;
8274  }
8275  }
8276 
8277  attTup->attidentity = '\0';
8278  CatalogTupleUpdate(attrelation, &tuple->t_self, tuple);
8279 
8280  InvokeObjectPostAlterHook(RelationRelationId,
8281  RelationGetRelid(rel),
8282  attTup->attnum);
8283  ObjectAddressSubSet(address, RelationRelationId,
8284  RelationGetRelid(rel), attnum);
8285  heap_freetuple(tuple);
8286 
8287  table_close(attrelation, RowExclusiveLock);
8288 
8289  /*
8290  * Recurse to drop the identity from column in partitions. Identity is
8291  * not inherited in regular inheritance children so ignore them.
8292  */
8293  if (recurse && ispartitioned)
8294  {
8295  List *children;
8296  ListCell *lc;
8297 
8298  children = find_inheritance_children(RelationGetRelid(rel), lockmode);
8299 
8300  foreach(lc, children)
8301  {
8302  Relation childrel;
8303 
8304  childrel = table_open(lfirst_oid(lc), NoLock);
8305  ATExecDropIdentity(childrel, colName, false, lockmode, recurse, true);
8306  table_close(childrel, NoLock);
8307  }
8308  }
8309 
8310  if (!recursing)
8311  {
8312  /* drop the internal sequence */
8313  seqid = getIdentitySequence(rel, attnum, false);
8314  deleteDependencyRecordsForClass(RelationRelationId, seqid,
8315  RelationRelationId, DEPENDENCY_INTERNAL);
8317  seqaddress.classId = RelationRelationId;
8318  seqaddress.objectId = seqid;
8319  seqaddress.objectSubId = 0;
8321  }
8322 
8323  return address;
8324 }
8325 
8326 /*
8327  * ALTER TABLE ALTER COLUMN SET EXPRESSION
8328  *
8329  * Return the address of the affected column.
8330  */
8331 static ObjectAddress
8332 ATExecSetExpression(AlteredTableInfo *tab, Relation rel, const char *colName,
8333  Node *newExpr, LOCKMODE lockmode)
8334 {
8335  HeapTuple tuple;
8336  Form_pg_attribute attTup;
8338  Oid attrdefoid;
8339  ObjectAddress address;
8340  Expr *defval;
8342  RawColumnDefault *rawEnt;
8343 
8344  tuple = SearchSysCacheAttName(RelationGetRelid(rel), colName);
8345  if (!HeapTupleIsValid(tuple))
8346  ereport(ERROR,
8347  (errcode(ERRCODE_UNDEFINED_COLUMN),
8348  errmsg("column \"%s\" of relation \"%s\" does not exist",
8349  colName, RelationGetRelationName(rel))));
8350 
8351  attTup = (Form_pg_attribute) GETSTRUCT(tuple);
8352  attnum = attTup->attnum;
8353 
8354  if (attnum <= 0)
8355  ereport(ERROR,
8356  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
8357  errmsg("cannot alter system column \"%s\"",
8358  colName)));
8359 
8360  if (attTup->attgenerated != ATTRIBUTE_GENERATED_STORED)
8361  ereport(ERROR,
8362  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
8363  errmsg("column \"%s\" of relation \"%s\" is not a generated column",
8364  colName, RelationGetRelationName(rel))));
8365  ReleaseSysCache(tuple);
8366 
8367  /*
8368  * Clear all the missing values if we're rewriting the table, since this
8369  * renders them pointless.
8370  */
8371  RelationClearMissing(rel);
8372 
8373  /* make sure we don't conflict with later attribute modifications */
8375 
8376  /*
8377  * Find everything that depends on the column (constraints, indexes, etc),
8378  * and record enough information to let us recreate the objects after
8379  * rewrite.
8380  */
8382 
8383  /*
8384  * Drop the dependency records of the GENERATED expression, in particular
8385  * its INTERNAL dependency on the column, which would otherwise cause
8386  * dependency.c to refuse to perform the deletion.
8387  */
8388  attrdefoid = GetAttrDefaultOid(RelationGetRelid(rel), attnum);
8389  if (!OidIsValid(attrdefoid))
8390  elog(ERROR, "could not find attrdef tuple for relation %u attnum %d",
8391  RelationGetRelid(rel), attnum);
8392  (void) deleteDependencyRecordsFor(AttrDefaultRelationId, attrdefoid, false);
8393 
8394  /* Make above changes visible */
8396 
8397  /*
8398  * Get rid of the GENERATED expression itself. We use RESTRICT here for
8399  * safety, but at present we do not expect anything to depend on the
8400  * expression.
8401  */
8403  false, false);
8404 
8405  /* Prepare to store the new expression, in the catalogs */
8406  rawEnt = (RawColumnDefault *) palloc(sizeof(RawColumnDefault));
8407  rawEnt->attnum = attnum;
8408  rawEnt->raw_default = newExpr;
8409  rawEnt->missingMode = false;
8410  rawEnt->generated = ATTRIBUTE_GENERATED_STORED;
8411 
8412  /* Store the generated expression */
8414  false, true, false, NULL);
8415 
8416  /* Make above new expression visible */
8418 
8419  /* Prepare for table rewrite */
8420  defval = (Expr *) build_column_default(rel, attnum);
8421 
8423  newval->attnum = attnum;
8424  newval->expr = expression_planner(defval);
8425  newval->is_generated = true;
8426 
8427  tab->newvals = lappend(tab->newvals, newval);
8429 
8430  /* Drop any pg_statistic entry for the column */
8432 
8433  InvokeObjectPostAlterHook(RelationRelationId,
8434  RelationGetRelid(rel), attnum);
8435 
8436  ObjectAddressSubSet(address, RelationRelationId,
8437  RelationGetRelid(rel), attnum);
8438  return address;
8439 }
8440 
8441 /*
8442  * ALTER TABLE ALTER COLUMN DROP EXPRESSION
8443  */
8444 static void
8445 ATPrepDropExpression(Relation rel, AlterTableCmd *cmd, bool recurse, bool recursing, LOCKMODE lockmode)
8446 {
8447  /*
8448  * Reject ONLY if there are child tables. We could implement this, but it
8449  * is a bit complicated. GENERATED clauses must be attached to the column
8450  * definition and cannot be added later like DEFAULT, so if a child table
8451  * has a generation expression that the parent does not have, the child
8452  * column will necessarily be an attislocal column. So to implement ONLY
8453  * here, we'd need extra code to update attislocal of the direct child
8454  * tables, somewhat similar to how DROP COLUMN does it, so that the
8455  * resulting state can be properly dumped and restored.
8456  */
8457  if (!recurse &&
8459  ereport(ERROR,
8460  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
8461  errmsg("ALTER TABLE / DROP EXPRESSION must be applied to child tables too")));
8462 
8463  /*
8464  * Cannot drop generation expression from inherited columns.
8465  */
8466  if (!recursing)
8467  {
8468  HeapTuple tuple;
8469  Form_pg_attribute attTup;
8470 
8471  tuple = SearchSysCacheCopyAttName(RelationGetRelid(rel), cmd->name);
8472  if (!HeapTupleIsValid(tuple))
8473  ereport(ERROR,
8474  (errcode(ERRCODE_UNDEFINED_COLUMN),
8475  errmsg("column \"%s\" of relation \"%s\" does not exist",
8476  cmd->name, RelationGetRelationName(rel))));
8477 
8478  attTup = (Form_pg_attribute) GETSTRUCT(tuple);
8479 
8480  if (attTup->attinhcount > 0)
8481  ereport(ERROR,
8482  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
8483  errmsg("cannot drop generation expression from inherited column")));
8484  }
8485 }
8486 
8487 /*
8488  * Return the address of the affected column.
8489  */
8490 static ObjectAddress
8491 ATExecDropExpression(Relation rel, const char *colName, bool missing_ok, LOCKMODE lockmode)
8492 {
8493  HeapTuple tuple;
8494  Form_pg_attribute attTup;
8496  Relation attrelation;
8497  Oid attrdefoid;
8498  ObjectAddress address;
8499 
8500  attrelation = table_open(AttributeRelationId, RowExclusiveLock);
8501  tuple = SearchSysCacheCopyAttName(RelationGetRelid(rel), colName);
8502  if (!HeapTupleIsValid(tuple))
8503  ereport(ERROR,
8504  (errcode(ERRCODE_UNDEFINED_COLUMN),
8505  errmsg("column \"%s\" of relation \"%s\" does not exist",
8506  colName, RelationGetRelationName(rel))));
8507 
8508  attTup = (Form_pg_attribute) GETSTRUCT(tuple);
8509  attnum = attTup->attnum;
8510 
8511  if (attnum <= 0)
8512  ereport(ERROR,
8513  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
8514  errmsg("cannot alter system column \"%s\"",
8515  colName)));
8516 
8517  if (attTup->attgenerated != ATTRIBUTE_GENERATED_STORED)
8518  {
8519  if (!missing_ok)
8520  ereport(ERROR,
8521  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
8522  errmsg("column \"%s\" of relation \"%s\" is not a stored generated column",
8523  colName, RelationGetRelationName(rel))));
8524  else
8525  {
8526  ereport(NOTICE,
8527  (errmsg("column \"%s\" of relation \"%s\" is not a stored generated column, skipping",
8528  colName, RelationGetRelationName(rel))));
8529  heap_freetuple(tuple);
8530  table_close(attrelation, RowExclusiveLock);
8531  return InvalidObjectAddress;
8532  }
8533  }
8534 
8535  /*
8536  * Mark the column as no longer generated. (The atthasdef flag needs to
8537  * get cleared too, but RemoveAttrDefault will handle that.)
8538  */
8539  attTup->attgenerated = '\0';
8540  CatalogTupleUpdate(attrelation, &tuple->t_self, tuple);
8541 
8542  InvokeObjectPostAlterHook(RelationRelationId,
8543  RelationGetRelid(rel),
8544  attnum);
8545  heap_freetuple(tuple);
8546 
8547  table_close(attrelation, RowExclusiveLock);
8548 
8549  /*
8550  * Drop the dependency records of the GENERATED expression, in particular
8551  * its INTERNAL dependency on the column, which would otherwise cause
8552  * dependency.c to refuse to perform the deletion.
8553  */
8554  attrdefoid = GetAttrDefaultOid(RelationGetRelid(rel), attnum);
8555  if (!OidIsValid(attrdefoid))
8556  elog(ERROR, "could not find attrdef tuple for relation %u attnum %d",
8557  RelationGetRelid(rel), attnum);
8558  (void) deleteDependencyRecordsFor(AttrDefaultRelationId, attrdefoid, false);
8559 
8560  /* Make above changes visible */
8562 
8563  /*
8564  * Get rid of the GENERATED expression itself. We use RESTRICT here for
8565  * safety, but at present we do not expect anything to depend on the
8566  * default.
8567  */
8569  false, false);
8570 
8571  ObjectAddressSubSet(address, RelationRelationId,
8572  RelationGetRelid(rel), attnum);
8573  return address;
8574 }
8575 
8576 /*
8577  * ALTER TABLE ALTER COLUMN SET STATISTICS
8578  *
8579  * Return value is the address of the modified column
8580  */
8581 static ObjectAddress
8582 ATExecSetStatistics(Relation rel, const char *colName, int16 colNum, Node *newValue, LOCKMODE lockmode)
8583 {
8584  int newtarget = 0;
8585  bool newtarget_default;
8586  Relation attrelation;
8587  HeapTuple tuple,
8588  newtuple;
8589  Form_pg_attribute attrtuple;
8591  ObjectAddress address;
8592  Datum repl_val[Natts_pg_attribute];
8593  bool repl_null[Natts_pg_attribute];
8594  bool repl_repl[Natts_pg_attribute];
8595 
8596  /*
8597  * We allow referencing columns by numbers only for indexes, since table
8598  * column numbers could contain gaps if columns are later dropped.
8599  */
8600  if (rel->rd_rel->relkind != RELKIND_INDEX &&
8601  rel->rd_rel->relkind != RELKIND_PARTITIONED_INDEX &&
8602  !colName)
8603  ereport(ERROR,
8604  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
8605  errmsg("cannot refer to non-index column by number")));
8606 
8607  /* -1 was used in previous versions for the default setting */
8608  if (newValue && intVal(newValue) != -1)
8609  {
8610  newtarget = intVal(newValue);
8611  newtarget_default = false;
8612  }
8613  else
8614  newtarget_default = true;
8615 
8616  if (!newtarget_default)
8617  {
8618  /*
8619  * Limit target to a sane range
8620  */
8621  if (newtarget < 0)
8622  {
8623  ereport(ERROR,
8624  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
8625  errmsg("statistics target %d is too low",
8626  newtarget)));
8627  }
8628  else if (newtarget > MAX_STATISTICS_TARGET)
8629  {
8630  newtarget = MAX_STATISTICS_TARGET;
8631  ereport(WARNING,
8632  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
8633  errmsg("lowering statistics target to %d",
8634  newtarget)));
8635  }
8636  }
8637 
8638  attrelation = table_open(AttributeRelationId, RowExclusiveLock);
8639 
8640  if (colName)
8641  {
8642  tuple = SearchSysCacheAttName(RelationGetRelid(rel), colName);
8643 
8644  if (!HeapTupleIsValid(tuple))
8645  ereport(ERROR,
8646  (errcode(ERRCODE_UNDEFINED_COLUMN),
8647  errmsg("column \"%s\" of relation \"%s\" does not exist",
8648  colName, RelationGetRelationName(rel))));
8649  }
8650  else
8651  {
8652  tuple = SearchSysCacheAttNum(RelationGetRelid(rel), colNum);
8653 
8654  if (!HeapTupleIsValid(tuple))
8655  ereport(ERROR,
8656  (errcode(ERRCODE_UNDEFINED_COLUMN),
8657  errmsg("column number %d of relation \"%s\" does not exist",
8658  colNum, RelationGetRelationName(rel))));
8659  }
8660 
8661  attrtuple = (Form_pg_attribute) GETSTRUCT(tuple);
8662 
8663  attnum = attrtuple->attnum;
8664  if (attnum <= 0)
8665  ereport(ERROR,
8666  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
8667  errmsg("cannot alter system column \"%s\"",
8668  colName)));
8669 
8670  if (rel->rd_rel->relkind == RELKIND_INDEX ||
8671  rel->rd_rel->relkind == RELKIND_PARTITIONED_INDEX)
8672  {
8673  if (attnum > rel->rd_index->indnkeyatts)
8674  ereport(ERROR,
8675  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
8676  errmsg("cannot alter statistics on included column \"%s\" of index \"%s\"",
8677  NameStr(attrtuple->attname), RelationGetRelationName(rel))));
8678  else if (rel->rd_index->indkey.values[attnum - 1] != 0)
8679  ereport(ERROR,
8680  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
8681  errmsg("cannot alter statistics on non-expression column \"%s\" of index \"%s\"",
8682  NameStr(attrtuple->attname), RelationGetRelationName(rel)),
8683  errhint("Alter statistics on table column instead.")));
8684  }
8685 
8686  /* Build new tuple. */
8687  memset(repl_null, false, sizeof(repl_null));
8688  memset(repl_repl, false, sizeof(repl_repl));
8689  if (!newtarget_default)
8690  repl_val[Anum_pg_attribute_attstattarget - 1] = newtarget;
8691  else
8692  repl_null[Anum_pg_attribute_attstattarget - 1] = true;
8693  repl_repl[Anum_pg_attribute_attstattarget - 1] = true;
8694  newtuple = heap_modify_tuple(tuple, RelationGetDescr(attrelation),
8695  repl_val, repl_null, repl_repl);
8696  CatalogTupleUpdate(attrelation, &tuple->t_self, newtuple);
8697 
8698  InvokeObjectPostAlterHook(RelationRelationId,
8699  RelationGetRelid(rel),
8700  attrtuple->attnum);
8701  ObjectAddressSubSet(address, RelationRelationId,
8702  RelationGetRelid(rel), attnum);
8703 
8704  heap_freetuple(newtuple);
8705 
8706  ReleaseSysCache(tuple);
8707 
8708  table_close(attrelation, RowExclusiveLock);
8709 
8710  return address;
8711 }
8712 
8713 /*
8714  * Return value is the address of the modified column
8715  */
8716 static ObjectAddress
8717 ATExecSetOptions(Relation rel, const char *colName, Node *options,
8718  bool isReset, LOCKMODE lockmode)
8719 {
8720  Relation attrelation;
8721  HeapTuple tuple,
8722  newtuple;
8723  Form_pg_attribute attrtuple;
8725  Datum datum,
8726  newOptions;
8727  bool isnull;
8728  ObjectAddress address;
8729  Datum repl_val[Natts_pg_attribute];
8730  bool repl_null[Natts_pg_attribute];
8731  bool repl_repl[Natts_pg_attribute];
8732 
8733  attrelation = table_open(AttributeRelationId, RowExclusiveLock);
8734 
8735  tuple = SearchSysCacheAttName(RelationGetRelid(rel), colName);
8736 
8737  if (!HeapTupleIsValid(tuple))
8738  ereport(ERROR,
8739  (errcode(ERRCODE_UNDEFINED_COLUMN),
8740  errmsg("column \"%s\" of relation \"%s\" does not exist",
8741  colName, RelationGetRelationName(rel))));
8742  attrtuple = (Form_pg_attribute) GETSTRUCT(tuple);
8743 
8744  attnum = attrtuple->attnum;
8745  if (attnum <= 0)
8746  ereport(ERROR,
8747  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
8748  errmsg("cannot alter system column \"%s\"",
8749  colName)));
8750 
8751  /* Generate new proposed attoptions (text array) */
8752  datum = SysCacheGetAttr(ATTNAME, tuple, Anum_pg_attribute_attoptions,
8753  &isnull);
8754  newOptions = transformRelOptions(isnull ? (Datum) 0 : datum,
8755  castNode(List, options), NULL, NULL,
8756  false, isReset);
8757  /* Validate new options */
8758  (void) attribute_reloptions(newOptions, true);
8759 
8760  /* Build new tuple. */
8761  memset(repl_null, false, sizeof(repl_null));
8762  memset(repl_repl, false, sizeof(repl_repl));
8763  if (newOptions != (Datum) 0)
8764  repl_val[Anum_pg_attribute_attoptions - 1] = newOptions;
8765  else
8766  repl_null[Anum_pg_attribute_attoptions - 1] = true;
8767  repl_repl[Anum_pg_attribute_attoptions - 1] = true;
8768  newtuple = heap_modify_tuple(tuple, RelationGetDescr(attrelation),
8769  repl_val, repl_null, repl_repl);
8770 
8771  /* Update system catalog. */
8772  CatalogTupleUpdate(attrelation, &newtuple->t_self, newtuple);
8773 
8774  InvokeObjectPostAlterHook(RelationRelationId,
8775  RelationGetRelid(rel),
8776  attrtuple->attnum);
8777  ObjectAddressSubSet(address, RelationRelationId,
8778  RelationGetRelid(rel), attnum);
8779 
8780  heap_freetuple(newtuple);
8781 
8782  ReleaseSysCache(tuple);
8783 
8784  table_close(attrelation, RowExclusiveLock);
8785 
8786  return address;
8787 }
8788 
8789 /*
8790  * Helper function for ATExecSetStorage and ATExecSetCompression
8791  *
8792  * Set the attstorage and/or attcompression fields for index columns
8793  * associated with the specified table column.
8794  */
8795 static void
8798  bool setstorage, char newstorage,
8799  bool setcompression, char newcompression,
8800  LOCKMODE lockmode)
8801 {
8802  ListCell *lc;
8803 
8804  foreach(lc, RelationGetIndexList(rel))
8805  {
8806  Oid indexoid = lfirst_oid(lc);
8807  Relation indrel;
8808  AttrNumber indattnum = 0;
8809  HeapTuple tuple;
8810 
8811  indrel = index_open(indexoid, lockmode);
8812 
8813  for (int i = 0; i < indrel->rd_index->indnatts; i++)
8814  {
8815  if (indrel->rd_index->indkey.values[i] == attnum)
8816  {
8817  indattnum = i + 1;
8818  break;
8819  }
8820  }
8821 
8822  if (indattnum == 0)
8823  {
8824  index_close(indrel, lockmode);
8825  continue;
8826  }
8827 
8828  tuple = SearchSysCacheCopyAttNum(RelationGetRelid(indrel), indattnum);
8829 
8830  if (HeapTupleIsValid(tuple))
8831  {
8832  Form_pg_attribute attrtuple = (Form_pg_attribute) GETSTRUCT(tuple);
8833 
8834  if (setstorage)
8835  attrtuple->attstorage = newstorage;
8836 
8837  if (setcompression)
8838  attrtuple->attcompression = newcompression;
8839 
8840  CatalogTupleUpdate(attrelation, &tuple->t_self, tuple);
8841 
8842  InvokeObjectPostAlterHook(RelationRelationId,
8843  RelationGetRelid(rel),
8844  attrtuple->attnum);
8845 
8846  heap_freetuple(tuple);
8847  }
8848 
8849  index_close(indrel, lockmode);
8850  }
8851 }
8852 
8853 /*
8854  * ALTER TABLE ALTER COLUMN SET STORAGE
8855  *
8856  * Return value is the address of the modified column
8857  */
8858 static ObjectAddress
8859 ATExecSetStorage(Relation rel, const char *colName, Node *newValue, LOCKMODE lockmode)
8860 {
8861  Relation attrelation;
8862  HeapTuple tuple;
8863  Form_pg_attribute attrtuple;
8865  ObjectAddress address;
8866 
8867  attrelation = table_open(AttributeRelationId, RowExclusiveLock);
8868 
8869  tuple = SearchSysCacheCopyAttName(RelationGetRelid(rel), colName);
8870 
8871  if (!HeapTupleIsValid(tuple))
8872  ereport(ERROR,
8873  (errcode(ERRCODE_UNDEFINED_COLUMN),
8874  errmsg("column \"%s\" of relation \"%s\" does not exist",
8875  colName, RelationGetRelationName(rel))));
8876  attrtuple = (Form_pg_attribute) GETSTRUCT(tuple);
8877 
8878  attnum = attrtuple->attnum;
8879  if (attnum <= 0)
8880  ereport(ERROR,
8881  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
8882  errmsg("cannot alter system column \"%s\"",
8883  colName)));
8884 
8885  attrtuple->attstorage = GetAttributeStorage(attrtuple->atttypid, strVal(newValue));
8886 
8887  CatalogTupleUpdate(attrelation, &tuple->t_self, tuple);
8888 
8889  InvokeObjectPostAlterHook(RelationRelationId,
8890  RelationGetRelid(rel),
8891  attrtuple->attnum);
8892 
8893  /*
8894  * Apply the change to indexes as well (only for simple index columns,
8895  * matching behavior of index.c ConstructTupleDescriptor()).
8896  */
8897  SetIndexStorageProperties(rel, attrelation, attnum,
8898  true, attrtuple->attstorage,
8899  false, 0,
8900  lockmode);
8901 
8902  heap_freetuple(tuple);
8903 
8904  table_close(attrelation, RowExclusiveLock);
8905 
8906  ObjectAddressSubSet(address, RelationRelationId,
8907  RelationGetRelid(rel), attnum);
8908  return address;
8909 }
8910 
8911 
8912 /*
8913  * ALTER TABLE DROP COLUMN
8914  *
8915  * DROP COLUMN cannot use the normal ALTER TABLE recursion mechanism,
8916  * because we have to decide at runtime whether to recurse or not depending
8917  * on whether attinhcount goes to zero or not. (We can't check this in a
8918  * static pre-pass because it won't handle multiple inheritance situations
8919  * correctly.)
8920  */
8921 static void
8922 ATPrepDropColumn(List **wqueue, Relation rel, bool recurse, bool recursing,
8923  AlterTableCmd *cmd, LOCKMODE lockmode,
8925 {
8926  if (rel->rd_rel->reloftype && !recursing)
8927  ereport(ERROR,
8928  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
8929  errmsg("cannot drop column from typed table")));
8930 
8931  if (rel->rd_rel->relkind == RELKIND_COMPOSITE_TYPE)
8932  ATTypedTableRecursion(wqueue, rel, cmd, lockmode, context);
8933 
8934  if (recurse)
8935  cmd->recurse = true;
8936 }
8937 
8938 /*
8939  * Drops column 'colName' from relation 'rel' and returns the address of the
8940  * dropped column. The column is also dropped (or marked as no longer
8941  * inherited from relation) from the relation's inheritance children, if any.
8942  *
8943  * In the recursive invocations for inheritance child relations, instead of
8944  * dropping the column directly (if to be dropped at all), its object address
8945  * is added to 'addrs', which must be non-NULL in such invocations. All
8946  * columns are dropped at the same time after all the children have been
8947  * checked recursively.
8948  */
8949 static ObjectAddress
8950 ATExecDropColumn(List **wqueue, Relation rel, const char *colName,
8951  DropBehavior behavior,
8952  bool recurse, bool recursing,
8953  bool missing_ok, LOCKMODE lockmode,
8954  ObjectAddresses *addrs)
8955 {
8956  HeapTuple tuple;
8957  Form_pg_attribute targetatt;
8959  List *children;
8960  ObjectAddress object;
8961  bool is_expr;
8962 
8963  /* At top level, permission check was done in ATPrepCmd, else do it */
8964  if (recursing)
8967 
8968  /* Initialize addrs on the first invocation */
8969  Assert(!recursing || addrs != NULL);
8970 
8971  /* since this function recurses, it could be driven to stack overflow */
8973 
8974  if (!recursing)
8975  addrs = new_object_addresses();
8976 
8977  /*
8978  * get the number of the attribute
8979  */
8980  tuple = SearchSysCacheAttName(RelationGetRelid(rel), colName);
8981  if (!HeapTupleIsValid(tuple))
8982  {
8983  if (!missing_ok)
8984  {
8985  ereport(ERROR,
8986  (errcode(ERRCODE_UNDEFINED_COLUMN),
8987  errmsg("column \"%s\" of relation \"%s\" does not exist",
8988  colName, RelationGetRelationName(rel))));
8989  }
8990  else
8991  {
8992  ereport(NOTICE,
8993  (errmsg("column \"%s\" of relation \"%s\" does not exist, skipping",
8994  colName, RelationGetRelationName(rel))));
8995  return InvalidObjectAddress;
8996  }
8997  }
8998  targetatt = (Form_pg_attribute) GETSTRUCT(tuple);
8999 
9000  attnum = targetatt->attnum;
9001 
9002  /* Can't drop a system attribute */
9003  if (attnum <= 0)
9004  ereport(ERROR,
9005  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
9006  errmsg("cannot drop system column \"%s\"",
9007  colName)));
9008 
9009  /*
9010  * Don't drop inherited columns, unless recursing (presumably from a drop
9011  * of the parent column)
9012  */
9013  if (targetatt->attinhcount > 0 && !recursing)
9014  ereport(ERROR,
9015  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
9016  errmsg("cannot drop inherited column \"%s\"",
9017  colName)));
9018 
9019  /*
9020  * Don't drop columns used in the partition key, either. (If we let this
9021  * go through, the key column's dependencies would cause a cascaded drop
9022  * of the whole table, which is surely not what the user expected.)
9023  */
9024  if (has_partition_attrs(rel,
9026  &is_expr))
9027  ereport(ERROR,
9028  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
9029  errmsg("cannot drop column \"%s\" because it is part of the partition key of relation \"%s\"",
9030  colName, RelationGetRelationName(rel))));
9031 
9032  ReleaseSysCache(tuple);
9033 
9034  /*
9035  * Propagate to children as appropriate. Unlike most other ALTER
9036  * routines, we have to do this one level of recursion at a time; we can't
9037  * use find_all_inheritors to do it in one pass.
9038  */
9039  children =
9041 
9042  if (children)
9043  {
9044  Relation attr_rel;
9045  ListCell *child;
9046 
9047  /*
9048  * In case of a partitioned table, the column must be dropped from the
9049  * partitions as well.
9050  */
9051  if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE && !recurse)
9052  ereport(ERROR,
9053  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
9054  errmsg("cannot drop column from only the partitioned table when partitions exist"),
9055  errhint("Do not specify the ONLY keyword.")));
9056 
9057  attr_rel = table_open(AttributeRelationId, RowExclusiveLock);
9058  foreach(child, children)
9059  {
9060  Oid childrelid = lfirst_oid(child);
9061  Relation childrel;
9062  Form_pg_attribute childatt;
9063 
9064  /* find_inheritance_children already got lock */
9065  childrel = table_open(childrelid, NoLock);
9066  CheckAlterTableIsSafe(childrel);
9067 
9068  tuple = SearchSysCacheCopyAttName(childrelid, colName);
9069  if (!HeapTupleIsValid(tuple)) /* shouldn't happen */
9070  elog(ERROR, "cache lookup failed for attribute \"%s\" of relation %u",
9071  colName, childrelid);
9072  childatt = (Form_pg_attribute) GETSTRUCT(tuple);
9073 
9074  if (childatt->attinhcount <= 0) /* shouldn't happen */
9075  elog(ERROR, "relation %u has non-inherited attribute \"%s\"",
9076  childrelid, colName);
9077 
9078  if (recurse)
9079  {
9080  /*
9081  * If the child column has other definition sources, just
9082  * decrement its inheritance count; if not, recurse to delete
9083  * it.
9084  */
9085  if (childatt->attinhcount == 1 && !childatt->attislocal)
9086  {
9087  /* Time to delete this child column, too */
9088  ATExecDropColumn(wqueue, childrel, colName,
9089  behavior, true, true,
9090  false, lockmode, addrs);
9091  }
9092  else
9093  {
9094  /* Child column must survive my deletion */
9095  childatt->attinhcount--;
9096 
9097  CatalogTupleUpdate(attr_rel, &tuple->t_self, tuple);
9098 
9099  /* Make update visible */
9101  }
9102  }
9103  else
9104  {
9105  /*
9106  * If we were told to drop ONLY in this table (no recursion),
9107  * we need to mark the inheritors' attributes as locally
9108  * defined rather than inherited.
9109  */
9110  childatt->attinhcount--;
9111  childatt->attislocal = true;
9112 
9113  CatalogTupleUpdate(attr_rel, &tuple->t_self, tuple);
9114 
9115  /* Make update visible */
9117  }
9118 
9119  heap_freetuple(tuple);
9120 
9121  table_close(childrel, NoLock);
9122  }
9123  table_close(attr_rel, RowExclusiveLock);
9124  }
9125 
9126  /* Add object to delete */
9127  object.classId = RelationRelationId;
9128  object.objectId = RelationGetRelid(rel);
9129  object.objectSubId = attnum;
9130  add_exact_object_address(&object, addrs);
9131 
9132  if (!recursing)
9133  {
9134  /* Recursion has ended, drop everything that was collected */
9135  performMultipleDeletions(addrs, behavior, 0);
9136  free_object_addresses(addrs);
9137  }
9138 
9139  return object;
9140 }
9141 
9142 /*
9143  * ALTER TABLE ADD INDEX
9144  *
9145  * There is no such command in the grammar, but parse_utilcmd.c converts
9146  * UNIQUE and PRIMARY KEY constraints into AT_AddIndex subcommands. This lets
9147  * us schedule creation of the index at the appropriate time during ALTER.
9148  *
9149  * Return value is the address of the new index.
9150  */
9151 static ObjectAddress
9153  IndexStmt *stmt, bool is_rebuild, LOCKMODE lockmode)
9154 {
9155  bool check_rights;
9156  bool skip_build;
9157  bool quiet;
9158  ObjectAddress address;
9159 
9160  Assert(IsA(stmt, IndexStmt));
9161  Assert(!stmt->concurrent);
9162 
9163  /* The IndexStmt has already been through transformIndexStmt */
9164  Assert(stmt->transformed);
9165 
9166  /* suppress schema rights check when rebuilding existing index */
9167  check_rights = !is_rebuild;
9168  /* skip index build if phase 3 will do it or we're reusing an old one */
9169  skip_build = tab->rewrite > 0 || RelFileNumberIsValid(stmt->oldNumber);
9170  /* suppress notices when rebuilding existing index */
9171  quiet = is_rebuild;
9172 
9173  address = DefineIndex(RelationGetRelid(rel),
9174  stmt,
9175  InvalidOid, /* no predefined OID */
9176  InvalidOid, /* no parent index */
9177  InvalidOid, /* no parent constraint */
9178  -1, /* total_parts unknown */
9179  true, /* is_alter_table */
9180  check_rights,
9181  false, /* check_not_in_use - we did it already */
9182  skip_build,
9183  quiet);
9184 
9185  /*
9186  * If TryReuseIndex() stashed a relfilenumber for us, we used it for the
9187  * new index instead of building from scratch. Restore associated fields.
9188  * This may store InvalidSubTransactionId in both fields, in which case
9189  * relcache.c will assume it can rebuild the relcache entry. Hence, do
9190  * this after the CCI that made catalog rows visible to any rebuild. The
9191  * DROP of the old edition of this index will have scheduled the storage
9192  * for deletion at commit, so cancel that pending deletion.
9193  */
9194  if (RelFileNumberIsValid(stmt->oldNumber))
9195  {
9196  Relation irel = index_open(address.objectId, NoLock);
9197 
9198  irel->rd_createSubid = stmt->oldCreateSubid;
9199  irel->rd_firstRelfilelocatorSubid = stmt->oldFirstRelfilelocatorSubid;
9200  RelationPreserveStorage(irel->rd_locator, true);
9201  index_close(irel, NoLock);
9202  }
9203 
9204  return address;
9205 }
9206 
9207 /*
9208  * ALTER TABLE ADD STATISTICS
9209  *
9210  * This is no such command in the grammar, but we use this internally to add
9211  * AT_ReAddStatistics subcommands to rebuild extended statistics after a table
9212  * column type change.
9213  */
9214 static ObjectAddress
9216  CreateStatsStmt *stmt, bool is_rebuild, LOCKMODE lockmode)
9217 {
9218  ObjectAddress address;
9219 
9221 
9222  /* The CreateStatsStmt has already been through transformStatsStmt */
9223  Assert(stmt->transformed);
9224 
9225  address = CreateStatistics(stmt);
9226 
9227  return address;
9228 }
9229 
9230 /*
9231  * ALTER TABLE ADD CONSTRAINT USING INDEX
9232  *
9233  * Returns the address of the new constraint.
9234  */
9235 static ObjectAddress
9237  IndexStmt *stmt, LOCKMODE lockmode)
9238 {
9239  Oid index_oid = stmt->indexOid;
9240  Relation indexRel;
9241  char *indexName;
9242  IndexInfo *indexInfo;
9243  char *constraintName;
9244  char constraintType;
9245  ObjectAddress address;
9246  bits16 flags;
9247 
9248  Assert(IsA(stmt, IndexStmt));
9249  Assert(OidIsValid(index_oid));
9250  Assert(stmt->isconstraint);
9251 
9252  /*
9253  * Doing this on partitioned tables is not a simple feature to implement,
9254  * so let's punt for now.
9255  */
9256  if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
9257  ereport(ERROR,
9258  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
9259  errmsg("ALTER TABLE / ADD CONSTRAINT USING INDEX is not supported on partitioned tables")));
9260 
9261  indexRel = index_open(index_oid, AccessShareLock);
9262 
9263  indexName = pstrdup(RelationGetRelationName(indexRel));
9264 
9265  indexInfo = BuildIndexInfo(indexRel);
9266 
9267  /* this should have been checked at parse time */
9268  if (!indexInfo->ii_Unique)
9269  elog(ERROR, "index \"%s\" is not unique", indexName);
9270 
9271  /*
9272  * Determine name to assign to constraint. We require a constraint to
9273  * have the same name as the underlying index; therefore, use the index's
9274  * existing name as the default constraint name, and if the user
9275  * explicitly gives some other name for the constraint, rename the index
9276  * to match.
9277  */
9278  constraintName = stmt->idxname;
9279  if (constraintName == NULL)
9280  constraintName = indexName;
9281  else if (strcmp(constraintName, indexName) != 0)
9282  {
9283  ereport(NOTICE,
9284  (errmsg("ALTER TABLE / ADD CONSTRAINT USING INDEX will rename index \"%s\" to \"%s\"",
9285  indexName, constraintName)));
9286  RenameRelationInternal(index_oid, constraintName, false, true);
9287  }
9288 
9289  /* Extra checks needed if making primary key */
9290  if (stmt->primary)
9291  index_check_primary_key(rel, indexInfo, true, stmt);
9292 
9293  /* Note we currently don't support EXCLUSION constraints here */
9294  if (stmt->primary)
9295  constraintType = CONSTRAINT_PRIMARY;
9296  else
9297  constraintType = CONSTRAINT_UNIQUE;
9298 
9299  /* Create the catalog entries for the constraint */
9302  (stmt->initdeferred ? INDEX_CONSTR_CREATE_INIT_DEFERRED : 0) |
9303  (stmt->deferrable ? INDEX_CONSTR_CREATE_DEFERRABLE : 0) |
9304  (stmt->primary ? INDEX_CONSTR_CREATE_MARK_AS_PRIMARY : 0);
9305 
9306  address = index_constraint_create(rel,
9307  index_oid,
9308  InvalidOid,
9309  indexInfo,
9310  constraintName,
9311  constraintType,
9312  flags,
9314  false); /* is_internal */
9315 
9316  index_close(indexRel, NoLock);
9317 
9318  return address;
9319 }
9320 
9321 /*
9322  * ALTER TABLE ADD CONSTRAINT
9323  *
9324  * Return value is the address of the new constraint; if no constraint was
9325  * added, InvalidObjectAddress is returned.
9326  */
9327 static ObjectAddress
9329  Constraint *newConstraint, bool recurse, bool is_readd,
9330  LOCKMODE lockmode)
9331 {
9333 
9334  Assert(IsA(newConstraint, Constraint));
9335 
9336  /*
9337  * Currently, we only expect to see CONSTR_CHECK and CONSTR_FOREIGN nodes
9338  * arriving here (see the preprocessing done in parse_utilcmd.c). Use a
9339  * switch anyway to make it easier to add more code later.
9340  */
9341  switch (newConstraint->contype)
9342  {
9343  case CONSTR_CHECK:
9344  address =
9345  ATAddCheckConstraint(wqueue, tab, rel,
9346  newConstraint, recurse, false, is_readd,
9347  lockmode);
9348  break;
9349 
9350  case CONSTR_FOREIGN:
9351 
9352  /*
9353  * Assign or validate constraint name
9354  */
9355  if (newConstraint->conname)
9356  {
9358  RelationGetRelid(rel),
9359  newConstraint->conname))
9360  ereport(ERROR,
9362  errmsg("constraint \"%s\" for relation \"%s\" already exists",
9363  newConstraint->conname,
9364  RelationGetRelationName(rel))));
9365  }
9366  else
9367  newConstraint->conname =
9370  "fkey",
9371  RelationGetNamespace(rel),
9372  NIL);
9373 
9374  address = ATAddForeignKeyConstraint(wqueue, tab, rel,
9375  newConstraint,
9376  recurse, false,
9377  lockmode);
9378  break;
9379 
9380  default:
9381  elog(ERROR, "unrecognized constraint type: %d",
9382  (int) newConstraint->contype);
9383  }
9384 
9385  return address;
9386 }
9387 
9388 /*
9389  * Generate the column-name portion of the constraint name for a new foreign
9390  * key given the list of column names that reference the referenced
9391  * table. This will be passed to ChooseConstraintName along with the parent
9392  * table name and the "fkey" suffix.
9393  *
9394  * We know that less than NAMEDATALEN characters will actually be used, so we
9395  * can truncate the result once we've generated that many.
9396  *
9397  * XXX see also ChooseExtendedStatisticNameAddition and
9398  * ChooseIndexNameAddition.
9399  */
9400 static char *
9402 {
9403  char buf[NAMEDATALEN * 2];
9404  int buflen = 0;
9405  ListCell *lc;
9406 
9407  buf[0] = '\0';
9408  foreach(lc, colnames)
9409  {
9410  const char *name = strVal(lfirst(lc));
9411 
9412  if (buflen > 0)
9413  buf[buflen++] = '_'; /* insert _ between names */
9414 
9415  /*
9416  * At this point we have buflen <= NAMEDATALEN. name should be less
9417  * than NAMEDATALEN already, but use strlcpy for paranoia.
9418  */
9419  strlcpy(buf + buflen, name, NAMEDATALEN);
9420  buflen += strlen(buf + buflen);
9421  if (buflen >= NAMEDATALEN)
9422  break;
9423  }
9424  return pstrdup(buf);
9425 }
9426 
9427 /*
9428  * Add a check constraint to a single table and its children. Returns the
9429  * address of the constraint added to the parent relation, if one gets added,
9430  * or InvalidObjectAddress otherwise.
9431  *
9432  * Subroutine for ATExecAddConstraint.
9433  *
9434  * We must recurse to child tables during execution, rather than using
9435  * ALTER TABLE's normal prep-time recursion. The reason is that all the
9436  * constraints *must* be given the same name, else they won't be seen as
9437  * related later. If the user didn't explicitly specify a name, then
9438  * AddRelationNewConstraints would normally assign different names to the
9439  * child constraints. To fix that, we must capture the name assigned at
9440  * the parent table and pass that down.
9441  */
9442 static ObjectAddress
9444  Constraint *constr, bool recurse, bool recursing,
9445  bool is_readd, LOCKMODE lockmode)
9446 {
9447  List *newcons;
9448  ListCell *lcon;
9449  List *children;
9450  ListCell *child;
9452 
9453  /* At top level, permission check was done in ATPrepCmd, else do it */
9454  if (recursing)
9457 
9458  /*
9459  * Call AddRelationNewConstraints to do the work, making sure it works on
9460  * a copy of the Constraint so transformExpr can't modify the original. It
9461  * returns a list of cooked constraints.
9462  *
9463  * If the constraint ends up getting merged with a pre-existing one, it's
9464  * omitted from the returned list, which is what we want: we do not need
9465  * to do any validation work. That can only happen at child tables,
9466  * though, since we disallow merging at the top level.
9467  */
9468  newcons = AddRelationNewConstraints(rel, NIL,
9469  list_make1(copyObject(constr)),
9470  recursing || is_readd, /* allow_merge */
9471  !recursing, /* is_local */
9472  is_readd, /* is_internal */
9473  NULL); /* queryString not available
9474  * here */
9475 
9476  /* we don't expect more than one constraint here */
9477  Assert(list_length(newcons) <= 1);
9478 
9479  /* Add each to-be-validated constraint to Phase 3's queue */
9480  foreach(lcon, newcons)
9481  {
9482  CookedConstraint *ccon = (CookedConstraint *) lfirst(lcon);
9483 
9484  if (!ccon->skip_validation)
9485  {
9486  NewConstraint *newcon;
9487 
9488  newcon = (NewConstraint *) palloc0(sizeof(NewConstraint));
9489  newcon->name = ccon->name;
9490  newcon->contype = ccon->contype;
9491  newcon->qual = ccon->expr;
9492 
9493  tab->constraints = lappend(tab->constraints, newcon);
9494  }
9495 
9496  /* Save the actually assigned name if it was defaulted */
9497  if (constr->conname == NULL)
9498  constr->conname = ccon->name;
9499 
9500  ObjectAddressSet(address, ConstraintRelationId, ccon->conoid);
9501  }
9502 
9503  /* At this point we must have a locked-down name to use */
9504  Assert(constr->conname != NULL);
9505 
9506  /* Advance command counter in case same table is visited multiple times */
9508 
9509  /*
9510  * If the constraint got merged with an existing constraint, we're done.
9511  * We mustn't recurse to child tables in this case, because they've
9512  * already got the constraint, and visiting them again would lead to an
9513  * incorrect value for coninhcount.
9514  */
9515  if (newcons == NIL)
9516  return address;
9517 
9518  /*
9519  * If adding a NO INHERIT constraint, no need to find our children.
9520  */
9521  if (constr->is_no_inherit)
9522  return address;
9523 
9524  /*
9525  * Propagate to children as appropriate. Unlike most other ALTER
9526  * routines, we have to do this one level of recursion at a time; we can't
9527  * use find_all_inheritors to do it in one pass.
9528  */
9529  children =
9531 
9532  /*
9533  * Check if ONLY was specified with ALTER TABLE. If so, allow the
9534  * constraint creation only if there are no children currently. Error out
9535  * otherwise.
9536  */
9537  if (!recurse && children != NIL)
9538  ereport(ERROR,
9539  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
9540  errmsg("constraint must be added to child tables too")));
9541 
9542  foreach(child, children)
9543  {
9544  Oid childrelid = lfirst_oid(child);
9545  Relation childrel;
9546  AlteredTableInfo *childtab;
9547 
9548  /* find_inheritance_children already got lock */
9549  childrel = table_open(childrelid, NoLock);
9550  CheckAlterTableIsSafe(childrel);
9551 
9552  /* Find or create work queue entry for this table */
9553  childtab = ATGetQueueEntry(wqueue, childrel);
9554 
9555  /* Recurse to child */
9556  ATAddCheckConstraint(wqueue, childtab, childrel,
9557  constr, recurse, true, is_readd, lockmode);
9558 
9559  table_close(childrel, NoLock);
9560  }
9561 
9562  return address;
9563 }
9564 
9565 /*
9566  * Add a foreign-key constraint to a single table; return the new constraint's
9567  * address.
9568  *
9569  * Subroutine for ATExecAddConstraint. Must already hold exclusive
9570  * lock on the rel, and have done appropriate validity checks for it.
9571  * We do permissions checks here, however.
9572  *
9573  * When the referenced or referencing tables (or both) are partitioned,
9574  * multiple pg_constraint rows are required -- one for each partitioned table
9575  * and each partition on each side (fortunately, not one for every combination
9576  * thereof). We also need action triggers on each leaf partition on the
9577  * referenced side, and check triggers on each leaf partition on the
9578  * referencing side.
9579  */
9580 static ObjectAddress
9582  Constraint *fkconstraint,
9583  bool recurse, bool recursing, LOCKMODE lockmode)
9584 {
9585  Relation pkrel;
9586  int16 pkattnum[INDEX_MAX_KEYS] = {0};
9587  int16 fkattnum[INDEX_MAX_KEYS] = {0};
9588  Oid pktypoid[INDEX_MAX_KEYS] = {0};
9589  Oid fktypoid[INDEX_MAX_KEYS] = {0};
9590  Oid opclasses[INDEX_MAX_KEYS] = {0};
9591  Oid pfeqoperators[INDEX_MAX_KEYS] = {0};
9592  Oid ppeqoperators[INDEX_MAX_KEYS] = {0};
9593  Oid ffeqoperators[INDEX_MAX_KEYS] = {0};
9594  int16 fkdelsetcols[INDEX_MAX_KEYS] = {0};
9595  bool with_period;
9596  bool pk_has_without_overlaps;
9597  int i;
9598  int numfks,
9599  numpks,
9600  numfkdelsetcols;
9601  Oid indexOid;
9602  bool old_check_ok;
9603  ObjectAddress address;
9604  ListCell *old_pfeqop_item = list_head(fkconstraint->old_conpfeqop);
9605 
9606  /*
9607  * Grab ShareRowExclusiveLock on the pk table, so that someone doesn't
9608  * delete rows out from under us.
9609  */
9610  if (OidIsValid(fkconstraint->old_pktable_oid))
9611  pkrel = table_open(fkconstraint->old_pktable_oid, ShareRowExclusiveLock);
9612  else
9613  pkrel = table_openrv(fkconstraint->pktable, ShareRowExclusiveLock);
9614 
9615  /*
9616  * Validity checks (permission checks wait till we have the column
9617  * numbers)
9618  */
9619  if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
9620  {
9621  if (!recurse)
9622  ereport(ERROR,
9623  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
9624  errmsg("cannot use ONLY for foreign key on partitioned table \"%s\" referencing relation \"%s\"",
9626  RelationGetRelationName(pkrel))));
9627  if (fkconstraint->skip_validation && !fkconstraint->initially_valid)
9628  ereport(ERROR,
9629  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
9630  errmsg("cannot add NOT VALID foreign key on partitioned table \"%s\" referencing relation \"%s\"",
9632  RelationGetRelationName(pkrel)),
9633  errdetail("This feature is not yet supported on partitioned tables.")));
9634  }
9635 
9636  if (pkrel->rd_rel->relkind != RELKIND_RELATION &&
9637  pkrel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
9638  ereport(ERROR,
9639  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
9640  errmsg("referenced relation \"%s\" is not a table",
9641  RelationGetRelationName(pkrel))));
9642 
9643  if (!allowSystemTableMods && IsSystemRelation(pkrel))
9644  ereport(ERROR,
9645  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
9646  errmsg("permission denied: \"%s\" is a system catalog",
9647  RelationGetRelationName(pkrel))));
9648 
9649  /*
9650  * References from permanent or unlogged tables to temp tables, and from
9651  * permanent tables to unlogged tables, are disallowed because the
9652  * referenced data can vanish out from under us. References from temp
9653  * tables to any other table type are also disallowed, because other
9654  * backends might need to run the RI triggers on the perm table, but they
9655  * can't reliably see tuples in the local buffers of other backends.
9656  */
9657  switch (rel->rd_rel->relpersistence)
9658  {
9659  case RELPERSISTENCE_PERMANENT:
9660  if (!RelationIsPermanent(pkrel))
9661  ereport(ERROR,
9662  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
9663  errmsg("constraints on permanent tables may reference only permanent tables")));
9664  break;
9665  case RELPERSISTENCE_UNLOGGED:
9666  if (!RelationIsPermanent(pkrel)
9667  && pkrel->rd_rel->relpersistence != RELPERSISTENCE_UNLOGGED)
9668  ereport(ERROR,
9669  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
9670  errmsg("constraints on unlogged tables may reference only permanent or unlogged tables")));
9671  break;
9672  case RELPERSISTENCE_TEMP:
9673  if (pkrel->rd_rel->relpersistence != RELPERSISTENCE_TEMP)
9674  ereport(ERROR,
9675  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
9676  errmsg("constraints on temporary tables may reference only temporary tables")));
9677  if (!pkrel->rd_islocaltemp || !rel->rd_islocaltemp)
9678  ereport(ERROR,
9679  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
9680  errmsg("constraints on temporary tables must involve temporary tables of this session")));
9681  break;
9682  }
9683 
9684  /*
9685  * Look up the referencing attributes to make sure they exist, and record
9686  * their attnums and type OIDs.
9687  */
9689  fkconstraint->fk_attrs,
9690  fkattnum, fktypoid);
9691  with_period = fkconstraint->fk_with_period || fkconstraint->pk_with_period;
9692  if (with_period && !fkconstraint->fk_with_period)
9693  ereport(ERROR,
9694  errcode(ERRCODE_INVALID_FOREIGN_KEY),
9695  errmsg("foreign key uses PERIOD on the referenced table but not the referencing table"));
9696 
9697  numfkdelsetcols = transformColumnNameList(RelationGetRelid(rel),
9698  fkconstraint->fk_del_set_cols,
9699  fkdelsetcols, NULL);
9700  validateFkOnDeleteSetColumns(numfks, fkattnum,
9701  numfkdelsetcols, fkdelsetcols,
9702  fkconstraint->fk_del_set_cols);
9703 
9704  /*
9705  * If the attribute list for the referenced table was omitted, lookup the
9706  * definition of the primary key and use it. Otherwise, validate the
9707  * supplied attribute list. In either case, discover the index OID and
9708  * index opclasses, and the attnums and type OIDs of the attributes.
9709  */
9710  if (fkconstraint->pk_attrs == NIL)
9711  {
9712  numpks = transformFkeyGetPrimaryKey(pkrel, &indexOid,
9713  &fkconstraint->pk_attrs,
9714  pkattnum, pktypoid,
9715  opclasses, &pk_has_without_overlaps);
9716 
9717  /* If the primary key uses WITHOUT OVERLAPS, the fk must use PERIOD */
9718  if (pk_has_without_overlaps && !fkconstraint->fk_with_period)
9719  ereport(ERROR,
9720  errcode(ERRCODE_INVALID_FOREIGN_KEY),
9721  errmsg("foreign key uses PERIOD on the referenced table but not the referencing table"));
9722  }
9723  else
9724  {
9725  numpks = transformColumnNameList(RelationGetRelid(pkrel),
9726  fkconstraint->pk_attrs,
9727  pkattnum, pktypoid);
9728 
9729  /* Since we got pk_attrs, one should be a period. */
9730  if (with_period && !fkconstraint->pk_with_period)
9731  ereport(ERROR,
9732  errcode(ERRCODE_INVALID_FOREIGN_KEY),
9733  errmsg("foreign key uses PERIOD on the referencing table but not the referenced table"));
9734 
9735  /* Look for an index matching the column list */
9736  indexOid = transformFkeyCheckAttrs(pkrel, numpks, pkattnum,
9737  with_period, opclasses, &pk_has_without_overlaps);
9738  }
9739 
9740  /*
9741  * If the referenced primary key has WITHOUT OVERLAPS, the foreign key
9742  * must use PERIOD.
9743  */
9744  if (pk_has_without_overlaps && !with_period)
9745  ereport(ERROR,
9746  errcode(ERRCODE_INVALID_FOREIGN_KEY),
9747  errmsg("foreign key must use PERIOD when referencing a primary using WITHOUT OVERLAPS"));
9748 
9749  /*
9750  * Now we can check permissions.
9751  */
9752  checkFkeyPermissions(pkrel, pkattnum, numpks);
9753 
9754  /*
9755  * Check some things for generated columns.
9756  */
9757  for (i = 0; i < numfks; i++)
9758  {
9759  char attgenerated = TupleDescAttr(RelationGetDescr(rel), fkattnum[i] - 1)->attgenerated;
9760 
9761  if (attgenerated)
9762  {
9763  /*
9764  * Check restrictions on UPDATE/DELETE actions, per SQL standard
9765  */
9766  if (fkconstraint->fk_upd_action == FKCONSTR_ACTION_SETNULL ||
9767  fkconstraint->fk_upd_action == FKCONSTR_ACTION_SETDEFAULT ||
9768  fkconstraint->fk_upd_action == FKCONSTR_ACTION_CASCADE)
9769  ereport(ERROR,
9770  (errcode(ERRCODE_SYNTAX_ERROR),
9771  errmsg("invalid %s action for foreign key constraint containing generated column",
9772  "ON UPDATE")));
9773  if (fkconstraint->fk_del_action == FKCONSTR_ACTION_SETNULL ||
9774  fkconstraint->fk_del_action == FKCONSTR_ACTION_SETDEFAULT)
9775  ereport(ERROR,
9776  (errcode(ERRCODE_SYNTAX_ERROR),
9777  errmsg("invalid %s action for foreign key constraint containing generated column",
9778  "ON DELETE")));
9779  }
9780  }
9781 
9782  /*
9783  * Some actions are currently unsupported for foreign keys using PERIOD.
9784  */
9785  if (fkconstraint->fk_with_period)
9786  {
9787  if (fkconstraint->fk_upd_action == FKCONSTR_ACTION_CASCADE ||
9788  fkconstraint->fk_upd_action == FKCONSTR_ACTION_SETNULL ||
9789  fkconstraint->fk_upd_action == FKCONSTR_ACTION_SETDEFAULT)
9790  ereport(ERROR,
9791  errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
9792  errmsg("unsupported %s action for foreign key constraint using PERIOD",
9793  "ON UPDATE"));
9794 
9795  if (fkconstraint->fk_del_action == FKCONSTR_ACTION_CASCADE ||
9796  fkconstraint->fk_del_action == FKCONSTR_ACTION_SETNULL ||
9797  fkconstraint->fk_del_action == FKCONSTR_ACTION_SETDEFAULT)
9798  ereport(ERROR,
9799  errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
9800  errmsg("unsupported %s action for foreign key constraint using PERIOD",
9801  "ON DELETE"));
9802  }
9803 
9804  /*
9805  * Look up the equality operators to use in the constraint.
9806  *
9807  * Note that we have to be careful about the difference between the actual
9808  * PK column type and the opclass' declared input type, which might be
9809  * only binary-compatible with it. The declared opcintype is the right
9810  * thing to probe pg_amop with.
9811  */
9812  if (numfks != numpks)
9813  ereport(ERROR,
9814  (errcode(ERRCODE_INVALID_FOREIGN_KEY),
9815  errmsg("number of referencing and referenced columns for foreign key disagree")));
9816 
9817  /*
9818  * On the strength of a previous constraint, we might avoid scanning
9819  * tables to validate this one. See below.
9820  */
9821  old_check_ok = (fkconstraint->old_conpfeqop != NIL);
9822  Assert(!old_check_ok || numfks == list_length(fkconstraint->old_conpfeqop));
9823 
9824  for (i = 0; i < numpks; i++)
9825  {
9826  Oid pktype = pktypoid[i];
9827  Oid fktype = fktypoid[i];
9828  Oid fktyped;
9829  HeapTuple cla_ht;
9830  Form_pg_opclass cla_tup;
9831  Oid amid;
9832  Oid opfamily;
9833  Oid opcintype;
9834  Oid pfeqop;
9835  Oid ppeqop;
9836  Oid ffeqop;
9837  int16 eqstrategy;
9838  Oid pfeqop_right;
9839 
9840  /* We need several fields out of the pg_opclass entry */
9841  cla_ht = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclasses[i]));
9842  if (!HeapTupleIsValid(cla_ht))
9843  elog(ERROR, "cache lookup failed for opclass %u", opclasses[i]);
9844  cla_tup = (Form_pg_opclass) GETSTRUCT(cla_ht);
9845  amid = cla_tup->opcmethod;
9846  opfamily = cla_tup->opcfamily;
9847  opcintype = cla_tup->opcintype;
9848  ReleaseSysCache(cla_ht);
9849 
9850  if (with_period)
9851  {
9852  StrategyNumber rtstrategy;
9853  bool for_overlaps = with_period && i == numpks - 1;
9854 
9855  /*
9856  * GiST indexes are required to support temporal foreign keys
9857  * because they combine equals and overlaps.
9858  */
9859  if (amid != GIST_AM_OID)
9860  elog(ERROR, "only GiST indexes are supported for temporal foreign keys");
9861 
9862  rtstrategy = for_overlaps ? RTOverlapStrategyNumber : RTEqualStrategyNumber;
9863 
9864  /*
9865  * An opclass can use whatever strategy numbers it wants, so we
9866  * ask the opclass what number it actually uses instead of our RT*
9867  * constants.
9868  */
9869  eqstrategy = GistTranslateStratnum(opclasses[i], rtstrategy);
9870  if (eqstrategy == InvalidStrategy)
9871  {
9872  HeapTuple tuple;
9873 
9874  tuple = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclasses[i]));
9875  if (!HeapTupleIsValid(tuple))
9876  elog(ERROR, "cache lookup failed for operator class %u", opclasses[i]);
9877 
9878  ereport(ERROR,
9879  errcode(ERRCODE_UNDEFINED_OBJECT),
9880  for_overlaps
9881  ? errmsg("could not identify an overlaps operator for foreign key")
9882  : errmsg("could not identify an equality operator for foreign key"),
9883  errdetail("Could not translate strategy number %d for operator class \"%s\" for access method \"%s\".",
9884  rtstrategy, NameStr(((Form_pg_opclass) GETSTRUCT(tuple))->opcname), "gist"));
9885  }
9886  }
9887  else
9888  {
9889  /*
9890  * Check it's a btree; currently this can never fail since no
9891  * other index AMs support unique indexes. If we ever did have
9892  * other types of unique indexes, we'd need a way to determine
9893  * which operator strategy number is equality. (We could use
9894  * something like GistTranslateStratnum.)
9895  */
9896  if (amid != BTREE_AM_OID)
9897  elog(ERROR, "only b-tree indexes are supported for foreign keys");
9898  eqstrategy = BTEqualStrategyNumber;
9899  }
9900 
9901  /*
9902  * There had better be a primary equality operator for the index.
9903  * We'll use it for PK = PK comparisons.
9904  */
9905  ppeqop = get_opfamily_member(opfamily, opcintype, opcintype,
9906  eqstrategy);
9907 
9908  if (!OidIsValid(ppeqop))
9909  elog(ERROR, "missing operator %d(%u,%u) in opfamily %u",
9910  eqstrategy, opcintype, opcintype, opfamily);
9911 
9912  /*
9913  * Are there equality operators that take exactly the FK type? Assume
9914  * we should look through any domain here.
9915  */
9916  fktyped = getBaseType(fktype);
9917 
9918  pfeqop = get_opfamily_member(opfamily, opcintype, fktyped,
9919  eqstrategy);
9920  if (OidIsValid(pfeqop))
9921  {
9922  pfeqop_right = fktyped;
9923  ffeqop = get_opfamily_member(opfamily, fktyped, fktyped,
9924  eqstrategy);
9925  }
9926  else
9927  {
9928  /* keep compiler quiet */
9929  pfeqop_right = InvalidOid;
9930  ffeqop = InvalidOid;
9931  }
9932 
9933  if (!(OidIsValid(pfeqop) && OidIsValid(ffeqop)))
9934  {
9935  /*
9936  * Otherwise, look for an implicit cast from the FK type to the
9937  * opcintype, and if found, use the primary equality operator.
9938  * This is a bit tricky because opcintype might be a polymorphic
9939  * type such as ANYARRAY or ANYENUM; so what we have to test is
9940  * whether the two actual column types can be concurrently cast to
9941  * that type. (Otherwise, we'd fail to reject combinations such
9942  * as int[] and point[].)
9943  */
9944  Oid input_typeids[2];
9945  Oid target_typeids[2];
9946 
9947  input_typeids[0] = pktype;
9948  input_typeids[1] = fktype;
9949  target_typeids[0] = opcintype;
9950  target_typeids[1] = opcintype;
9951  if (can_coerce_type(2, input_typeids, target_typeids,
9953  {
9954  pfeqop = ffeqop = ppeqop;
9955  pfeqop_right = opcintype;
9956  }
9957  }
9958 
9959  if (!(OidIsValid(pfeqop) && OidIsValid(ffeqop)))
9960  ereport(ERROR,
9961  (errcode(ERRCODE_DATATYPE_MISMATCH),
9962  errmsg("foreign key constraint \"%s\" cannot be implemented",
9963  fkconstraint->conname),
9964  errdetail("Key columns \"%s\" and \"%s\" "
9965  "are of incompatible types: %s and %s.",
9966  strVal(list_nth(fkconstraint->fk_attrs, i)),
9967  strVal(list_nth(fkconstraint->pk_attrs, i)),
9968  format_type_be(fktype),
9969  format_type_be(pktype))));
9970 
9971  if (old_check_ok)
9972  {
9973  /*
9974  * When a pfeqop changes, revalidate the constraint. We could
9975  * permit intra-opfamily changes, but that adds subtle complexity
9976  * without any concrete benefit for core types. We need not
9977  * assess ppeqop or ffeqop, which RI_Initial_Check() does not use.
9978  */
9979  old_check_ok = (pfeqop == lfirst_oid(old_pfeqop_item));
9980  old_pfeqop_item = lnext(fkconstraint->old_conpfeqop,
9981  old_pfeqop_item);
9982  }
9983  if (old_check_ok)
9984  {
9985  Oid old_fktype;
9986  Oid new_fktype;
9987  CoercionPathType old_pathtype;
9988  CoercionPathType new_pathtype;
9989  Oid old_castfunc;
9990  Oid new_castfunc;
9992  fkattnum[i] - 1);
9993 
9994  /*
9995  * Identify coercion pathways from each of the old and new FK-side
9996  * column types to the right (foreign) operand type of the pfeqop.
9997  * We may assume that pg_constraint.conkey is not changing.
9998  */
9999  old_fktype = attr->atttypid;
10000  new_fktype = fktype;
10001  old_pathtype = findFkeyCast(pfeqop_right, old_fktype,
10002  &old_castfunc);
10003  new_pathtype = findFkeyCast(pfeqop_right, new_fktype,
10004  &new_castfunc);
10005 
10006  /*
10007  * Upon a change to the cast from the FK column to its pfeqop
10008  * operand, revalidate the constraint. For this evaluation, a
10009  * binary coercion cast is equivalent to no cast at all. While
10010  * type implementors should design implicit casts with an eye
10011  * toward consistency of operations like equality, we cannot
10012  * assume here that they have done so.
10013  *
10014  * A function with a polymorphic argument could change behavior
10015  * arbitrarily in response to get_fn_expr_argtype(). Therefore,
10016  * when the cast destination is polymorphic, we only avoid
10017  * revalidation if the input type has not changed at all. Given
10018  * just the core data types and operator classes, this requirement
10019  * prevents no would-be optimizations.
10020  *
10021  * If the cast converts from a base type to a domain thereon, then
10022  * that domain type must be the opcintype of the unique index.
10023  * Necessarily, the primary key column must then be of the domain
10024  * type. Since the constraint was previously valid, all values on
10025  * the foreign side necessarily exist on the primary side and in
10026  * turn conform to the domain. Consequently, we need not treat
10027  * domains specially here.
10028  *
10029  * Since we require that all collations share the same notion of
10030  * equality (which they do, because texteq reduces to bitwise
10031  * equality), we don't compare collation here.
10032  *
10033  * We need not directly consider the PK type. It's necessarily
10034  * binary coercible to the opcintype of the unique index column,
10035  * and ri_triggers.c will only deal with PK datums in terms of
10036  * that opcintype. Changing the opcintype also changes pfeqop.
10037  */
10038  old_check_ok = (new_pathtype == old_pathtype &&
10039  new_castfunc == old_castfunc &&
10040  (!IsPolymorphicType(pfeqop_right) ||
10041  new_fktype == old_fktype));
10042  }
10043 
10044  pfeqoperators[i] = pfeqop;
10045  ppeqoperators[i] = ppeqop;
10046  ffeqoperators[i] = ffeqop;
10047  }
10048 
10049  /*
10050  * For FKs with PERIOD we need additional operators to check whether the
10051  * referencing row's range is contained by the aggregated ranges of the
10052  * referenced row(s). For rangetypes and multirangetypes this is
10053  * fk.periodatt <@ range_agg(pk.periodatt). Those are the only types we
10054  * support for now. FKs will look these up at "runtime", but we should
10055  * make sure the lookup works here, even if we don't use the values.
10056  */
10057  if (with_period)
10058  {
10059  Oid periodoperoid;
10060  Oid aggedperiodoperoid;
10061 
10062  FindFKPeriodOpers(opclasses[numpks - 1], &periodoperoid, &aggedperiodoperoid);
10063  }
10064 
10065  /* First, create the constraint catalog entry itself. */
10066  address = addFkConstraint(addFkBothSides,
10067  fkconstraint->conname, fkconstraint, rel, pkrel,
10068  indexOid,
10069  InvalidOid, /* no parent constraint */
10070  numfks,
10071  pkattnum,
10072  fkattnum,
10073  pfeqoperators,
10074  ppeqoperators,
10075  ffeqoperators,
10076  numfkdelsetcols,
10077  fkdelsetcols,
10078  false,
10079  with_period);
10080 
10081  /* Next process the action triggers at the referenced side and recurse */
10082  addFkRecurseReferenced(fkconstraint, rel, pkrel,
10083  indexOid,
10084  address.objectId,
10085  numfks,
10086  pkattnum,
10087  fkattnum,
10088  pfeqoperators,
10089  ppeqoperators,
10090  ffeqoperators,
10091  numfkdelsetcols,
10092  fkdelsetcols,
10093  old_check_ok,
10095  with_period);
10096 
10097  /* Lastly create the check triggers at the referencing side and recurse */
10098  addFkRecurseReferencing(wqueue, fkconstraint, rel, pkrel,
10099  indexOid,
10100  address.objectId,
10101  numfks,
10102  pkattnum,
10103  fkattnum,
10104  pfeqoperators,
10105  ppeqoperators,
10106  ffeqoperators,
10107  numfkdelsetcols,
10108  fkdelsetcols,
10109  old_check_ok,
10110  lockmode,
10112  with_period);
10113 
10114  /*
10115  * Done. Close pk table, but keep lock until we've committed.
10116  */
10117  table_close(pkrel, NoLock);
10118 
10119  return address;
10120 }
10121 
10122 /*
10123  * validateFkOnDeleteSetColumns
10124  * Verifies that columns used in ON DELETE SET NULL/DEFAULT (...)
10125  * column lists are valid.
10126  */
10127 void
10128 validateFkOnDeleteSetColumns(int numfks, const int16 *fkattnums,
10129  int numfksetcols, const int16 *fksetcolsattnums,
10130  List *fksetcols)
10131 {
10132  for (int i = 0; i < numfksetcols; i++)
10133  {
10134  int16 setcol_attnum = fksetcolsattnums[i];
10135  bool seen = false;
10136 
10137  for (int j = 0; j < numfks; j++)
10138  {
10139  if (fkattnums[j] == setcol_attnum)
10140  {
10141  seen = true;
10142  break;
10143  }
10144  }
10145 
10146  if (!seen)
10147  {
10148  char *col = strVal(list_nth(fksetcols, i));
10149 
10150  ereport(ERROR,
10151  (errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
10152  errmsg("column \"%s\" referenced in ON DELETE SET action must be part of foreign key", col)));
10153  }
10154  }
10155 }
10156 
10157 /*
10158  * addFkConstraint
10159  * Install pg_constraint entries to implement a foreign key constraint.
10160  * Caller must separately invoke addFkRecurseReferenced and
10161  * addFkRecurseReferencing, as appropriate, to install pg_trigger entries
10162  * and (for partitioned tables) recurse to partitions.
10163  *
10164  * fkside: the side of the FK (or both) to create. Caller should
10165  * call addFkRecurseReferenced if this is addFkReferencedSide,
10166  * addFkRecurseReferencing if it's addFkReferencingSide, or both if it's
10167  * addFkBothSides.
10168  * constraintname: the base name for the constraint being added,
10169  * copied to fkconstraint->conname if the latter is not set
10170  * fkconstraint: the constraint being added
10171  * rel: the root referencing relation
10172  * pkrel: the referenced relation; might be a partition, if recursing
10173  * indexOid: the OID of the index (on pkrel) implementing this constraint
10174  * parentConstr: the OID of a parent constraint; InvalidOid if this is a
10175  * top-level constraint
10176  * numfks: the number of columns in the foreign key
10177  * pkattnum: the attnum array of referenced attributes
10178  * fkattnum: the attnum array of referencing attributes
10179  * pf/pp/ffeqoperators: OID array of operators between columns
10180  * numfkdelsetcols: the number of columns in the ON DELETE SET NULL/DEFAULT
10181  * (...) clause
10182  * fkdelsetcols: the attnum array of the columns in the ON DELETE SET
10183  * NULL/DEFAULT clause
10184  * with_period: true if this is a temporal FK
10185  */
10186 static ObjectAddress
10188  char *constraintname, Constraint *fkconstraint,
10189  Relation rel, Relation pkrel, Oid indexOid, Oid parentConstr,
10190  int numfks, int16 *pkattnum,
10191  int16 *fkattnum, Oid *pfeqoperators, Oid *ppeqoperators,
10192  Oid *ffeqoperators, int numfkdelsetcols, int16 *fkdelsetcols,
10193  bool is_internal, bool with_period)
10194 {
10195  ObjectAddress address;
10196  Oid constrOid;
10197  char *conname;
10198  bool conislocal;
10199  int16 coninhcount;
10200  bool connoinherit;
10201 
10202  /*
10203  * Verify relkind for each referenced partition. At the top level, this
10204  * is redundant with a previous check, but we need it when recursing.
10205  */
10206  if (pkrel->rd_rel->relkind != RELKIND_RELATION &&
10207  pkrel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
10208  ereport(ERROR,
10209  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
10210  errmsg("referenced relation \"%s\" is not a table",
10211  RelationGetRelationName(pkrel))));
10212 
10213  /*
10214  * Caller supplies us with a constraint name; however, it may be used in
10215  * this partition, so come up with a different one in that case.
10216  */
10218  RelationGetRelid(rel),
10219  constraintname))
10222  "fkey",
10223  RelationGetNamespace(rel), NIL);
10224  else
10225  conname = constraintname;
10226 
10227  if (fkconstraint->conname == NULL)
10228  fkconstraint->conname = pstrdup(conname);
10229 
10230  if (OidIsValid(parentConstr))
10231  {
10232  conislocal = false;
10233  coninhcount = 1;
10234  connoinherit = false;
10235  }
10236  else
10237  {
10238  conislocal = true;
10239  coninhcount = 0;
10240 
10241  /*
10242  * always inherit for partitioned tables, never for legacy inheritance
10243  */
10244  connoinherit = rel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE;
10245  }
10246 
10247  /*
10248  * Record the FK constraint in pg_constraint.
10249  */
10250  constrOid = CreateConstraintEntry(conname,
10251  RelationGetNamespace(rel),
10252  CONSTRAINT_FOREIGN,
10253  fkconstraint->deferrable,
10254  fkconstraint->initdeferred,
10255  fkconstraint->initially_valid,
10256  parentConstr,
10257  RelationGetRelid(rel),
10258  fkattnum,
10259  numfks,
10260  numfks,
10261  InvalidOid, /* not a domain constraint */
10262  indexOid,
10263  RelationGetRelid(pkrel),
10264  pkattnum,
10265  pfeqoperators,
10266  ppeqoperators,
10267  ffeqoperators,
10268  numfks,
10269  fkconstraint->fk_upd_action,
10270  fkconstraint->fk_del_action,
10271  fkdelsetcols,
10272  numfkdelsetcols,
10273  fkconstraint->fk_matchtype,
10274  NULL, /* no exclusion constraint */
10275  NULL, /* no check constraint */
10276  NULL,
10277  conislocal, /* islocal */
10278  coninhcount, /* inhcount */
10279  connoinherit, /* conNoInherit */
10280  with_period, /* conPeriod */
10281  is_internal); /* is_internal */
10282 
10283  ObjectAddressSet(address, ConstraintRelationId, constrOid);
10284 
10285  /*
10286  * In partitioning cases, create the dependency entries for this
10287  * constraint. (For non-partitioned cases, relevant entries were created
10288  * by CreateConstraintEntry.)
10289  *
10290  * On the referenced side, we need the constraint to have an internal
10291  * dependency on its parent constraint; this means that this constraint
10292  * cannot be dropped on its own -- only through the parent constraint. It
10293  * also means the containing partition cannot be dropped on its own, but
10294  * it can be detached, at which point this dependency is removed (after
10295  * verifying that no rows are referenced via this FK.)
10296  *
10297  * When processing the referencing side, we link the constraint via the
10298  * special partitioning dependencies: the parent constraint is the primary
10299  * dependent, and the partition on which the foreign key exists is the
10300  * secondary dependency. That way, this constraint is dropped if either
10301  * of these objects is.
10302  *
10303  * Note that this is only necessary for the subsidiary pg_constraint rows
10304  * in partitions; the topmost row doesn't need any of this.
10305  */
10306  if (OidIsValid(parentConstr))
10307  {
10308  ObjectAddress referenced;
10309 
10310  ObjectAddressSet(referenced, ConstraintRelationId, parentConstr);
10311 
10312  Assert(fkside != addFkBothSides);
10313  if (fkside == addFkReferencedSide)
10314  recordDependencyOn(&address, &referenced, DEPENDENCY_INTERNAL);
10315  else
10316  {
10317  recordDependencyOn(&address, &referenced, DEPENDENCY_PARTITION_PRI);
10318  ObjectAddressSet(referenced, RelationRelationId, RelationGetRelid(rel));
10319  recordDependencyOn(&address, &referenced, DEPENDENCY_PARTITION_SEC);
10320  }
10321  }
10322 
10323  /* make new constraint visible, in case we add more */
10325 
10326  return address;
10327 }
10328 
10329 /*
10330  * addFkRecurseReferenced
10331  * Recursive helper for the referenced side of foreign key creation,
10332  * which creates the action triggers and recurses
10333  *
10334  * If the referenced relation is a plain relation, create the necessary action
10335  * triggers that implement the constraint. If the referenced relation is a
10336  * partitioned table, then we create a pg_constraint row referencing the parent
10337  * of the referencing side for it and recurse on this routine for each
10338  * partition.
10339  *
10340  * fkconstraint: the constraint being added
10341  * rel: the root referencing relation
10342  * pkrel: the referenced relation; might be a partition, if recursing
10343  * indexOid: the OID of the index (on pkrel) implementing this constraint
10344  * parentConstr: the OID of a parent constraint; InvalidOid if this is a
10345  * top-level constraint
10346  * numfks: the number of columns in the foreign key
10347  * pkattnum: the attnum array of referenced attributes
10348  * fkattnum: the attnum array of referencing attributes
10349  * numfkdelsetcols: the number of columns in the ON DELETE SET
10350  * NULL/DEFAULT (...) clause
10351  * fkdelsetcols: the attnum array of the columns in the ON DELETE SET
10352  * NULL/DEFAULT clause
10353  * pf/pp/ffeqoperators: OID array of operators between columns
10354  * old_check_ok: true if this constraint replaces an existing one that
10355  * was already validated (thus this one doesn't need validation)
10356  * parentDelTrigger and parentUpdTrigger: when recursively called on a
10357  * partition, the OIDs of the parent action triggers for DELETE and
10358  * UPDATE respectively.
10359  * with_period: true if this is a temporal FK
10360  */
10361 static void
10363  Relation pkrel, Oid indexOid, Oid parentConstr,
10364  int numfks,
10365  int16 *pkattnum, int16 *fkattnum, Oid *pfeqoperators,
10366  Oid *ppeqoperators, Oid *ffeqoperators,
10367  int numfkdelsetcols, int16 *fkdelsetcols,
10368  bool old_check_ok,
10369  Oid parentDelTrigger, Oid parentUpdTrigger,
10370  bool with_period)
10371 {
10372  Oid deleteTriggerOid,
10373  updateTriggerOid;
10374 
10375  /*
10376  * Create the action triggers that enforce the constraint.
10377  */
10379  fkconstraint,
10380  parentConstr, indexOid,
10381  parentDelTrigger, parentUpdTrigger,
10382  &deleteTriggerOid, &updateTriggerOid);
10383 
10384  /*
10385  * If the referenced table is partitioned, recurse on ourselves to handle
10386  * each partition. We need one pg_constraint row created for each
10387  * partition in addition to the pg_constraint row for the parent table.
10388  */
10389  if (pkrel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
10390  {
10391  PartitionDesc pd = RelationGetPartitionDesc(pkrel, true);
10392 
10393  for (int i = 0; i < pd->nparts; i++)
10394  {
10395  Relation partRel;
10396  AttrMap *map;
10397  AttrNumber *mapped_pkattnum;
10398  Oid partIndexId;
10399  ObjectAddress address;
10400 
10401  partRel = table_open(pd->oids[i], ShareRowExclusiveLock);
10402 
10403  /*
10404  * Map the attribute numbers in the referenced side of the FK
10405  * definition to match the partition's column layout.
10406  */
10408  RelationGetDescr(pkrel),
10409  false);
10410  if (map)
10411  {
10412  mapped_pkattnum = palloc(sizeof(AttrNumber) * numfks);
10413  for (int j = 0; j < numfks; j++)
10414  mapped_pkattnum[j] = map->attnums[pkattnum[j] - 1];
10415  }
10416  else
10417  mapped_pkattnum = pkattnum;
10418 
10419  /* Determine the index to use at this level */
10420  partIndexId = index_get_partition(partRel, indexOid);
10421  if (!OidIsValid(partIndexId))
10422  elog(ERROR, "index for %u not found in partition %s",
10423  indexOid, RelationGetRelationName(partRel));
10424 
10425  /* Create entry at this level ... */
10427  fkconstraint->conname, fkconstraint, rel,
10428  partRel, partIndexId, parentConstr,
10429  numfks, mapped_pkattnum,
10430  fkattnum, pfeqoperators, ppeqoperators,
10431  ffeqoperators, numfkdelsetcols,
10432  fkdelsetcols, true, with_period);
10433  /* ... and recurse to our children */
10434  addFkRecurseReferenced(fkconstraint, rel, partRel,
10435  partIndexId, address.objectId, numfks,
10436  mapped_pkattnum, fkattnum,
10437  pfeqoperators, ppeqoperators, ffeqoperators,
10438  numfkdelsetcols, fkdelsetcols,
10439  old_check_ok,
10440  deleteTriggerOid, updateTriggerOid,
10441  with_period);
10442 
10443  /* Done -- clean up (but keep the lock) */
10444  table_close(partRel, NoLock);
10445  if (map)
10446  {
10447  pfree(mapped_pkattnum);
10448  free_attrmap(map);
10449  }
10450  }
10451  }
10452 }
10453 
10454 /*
10455  * addFkRecurseReferencing
10456  * Recursive helper for the referencing side of foreign key creation,
10457  * which creates the check triggers and recurses
10458  *
10459  * If the referencing relation is a plain relation, create the necessary check
10460  * triggers that implement the constraint, and set up for Phase 3 constraint
10461  * verification. If the referencing relation is a partitioned table, then
10462  * we create a pg_constraint row for it and recurse on this routine for each
10463  * partition.
10464  *
10465  * We assume that the referenced relation is locked against concurrent
10466  * deletions. If it's a partitioned relation, every partition must be so
10467  * locked.
10468  *
10469  * wqueue: the ALTER TABLE work queue; NULL when not running as part
10470  * of an ALTER TABLE sequence.
10471  * fkconstraint: the constraint being added
10472  * rel: the referencing relation; might be a partition, if recursing
10473  * pkrel: the root referenced relation
10474  * indexOid: the OID of the index (on pkrel) implementing this constraint
10475  * parentConstr: the OID of the parent constraint (there is always one)
10476  * numfks: the number of columns in the foreign key
10477  * pkattnum: the attnum array of referenced attributes
10478  * fkattnum: the attnum array of referencing attributes
10479  * pf/pp/ffeqoperators: OID array of operators between columns
10480  * numfkdelsetcols: the number of columns in the ON DELETE SET NULL/DEFAULT
10481  * (...) clause
10482  * fkdelsetcols: the attnum array of the columns in the ON DELETE SET
10483  * NULL/DEFAULT clause
10484  * old_check_ok: true if this constraint replaces an existing one that
10485  * was already validated (thus this one doesn't need validation)
10486  * lockmode: the lockmode to acquire on partitions when recursing
10487  * parentInsTrigger and parentUpdTrigger: when being recursively called on
10488  * a partition, the OIDs of the parent check triggers for INSERT and
10489  * UPDATE respectively.
10490  * with_period: true if this is a temporal FK
10491  */
10492 static void
10493 addFkRecurseReferencing(List **wqueue, Constraint *fkconstraint, Relation rel,
10494  Relation pkrel, Oid indexOid, Oid parentConstr,
10495  int numfks, int16 *pkattnum, int16 *fkattnum,
10496  Oid *pfeqoperators, Oid *ppeqoperators, Oid *ffeqoperators,
10497  int numfkdelsetcols, int16 *fkdelsetcols,
10498  bool old_check_ok, LOCKMODE lockmode,
10499  Oid parentInsTrigger, Oid parentUpdTrigger,
10500  bool with_period)
10501 {
10502  Oid insertTriggerOid,
10503  updateTriggerOid;
10504 
10505  Assert(OidIsValid(parentConstr));
10506 
10507  if (rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
10508  ereport(ERROR,
10509  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
10510  errmsg("foreign key constraints are not supported on foreign tables")));
10511 
10512  /*
10513  * Add the check triggers to it and, if necessary, schedule it to be
10514  * checked in Phase 3.
10515  *
10516  * If the relation is partitioned, drill down to do it to its partitions.
10517  */
10519  RelationGetRelid(pkrel),
10520  fkconstraint,
10521  parentConstr,
10522  indexOid,
10523  parentInsTrigger, parentUpdTrigger,
10524  &insertTriggerOid, &updateTriggerOid);
10525 
10526  if (rel->rd_rel->relkind == RELKIND_RELATION)
10527  {
10528  /*
10529  * Tell Phase 3 to check that the constraint is satisfied by existing
10530  * rows. We can skip this during table creation, when requested
10531  * explicitly by specifying NOT VALID in an ADD FOREIGN KEY command,
10532  * and when we're recreating a constraint following a SET DATA TYPE
10533  * operation that did not impugn its validity.
10534  */
10535  if (wqueue && !old_check_ok && !fkconstraint->skip_validation)
10536  {
10537  NewConstraint *newcon;
10538  AlteredTableInfo *tab;
10539 
10540  tab = ATGetQueueEntry(wqueue, rel);
10541 
10542  newcon = (NewConstraint *) palloc0(sizeof(NewConstraint));
10543  newcon->name = get_constraint_name(parentConstr);
10544  newcon->contype = CONSTR_FOREIGN;
10545  newcon->refrelid = RelationGetRelid(pkrel);
10546  newcon->refindid = indexOid;
10547  newcon->conid = parentConstr;
10548  newcon->conwithperiod = fkconstraint->fk_with_period;
10549  newcon->qual = (Node *) fkconstraint;
10550 
10551  tab->constraints = lappend(tab->constraints, newcon);
10552  }
10553  }
10554  else if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
10555  {
10556  PartitionDesc pd = RelationGetPartitionDesc(rel, true);
10557  Relation trigrel;
10558 
10559  /*
10560  * Triggers of the foreign keys will be manipulated a bunch of times
10561  * in the loop below. To avoid repeatedly opening/closing the trigger
10562  * catalog relation, we open it here and pass it to the subroutines
10563  * called below.
10564  */
10565  trigrel = table_open(TriggerRelationId, RowExclusiveLock);
10566 
10567  /*
10568  * Recurse to take appropriate action on each partition; either we
10569  * find an existing constraint to reparent to ours, or we create a new
10570  * one.
10571  */
10572  for (int i = 0; i < pd->nparts; i++)
10573  {
10574  Oid partitionId = pd->oids[i];
10575  Relation partition = table_open(partitionId, lockmode);
10576  List *partFKs;
10577  AttrMap *attmap;
10578  AttrNumber mapped_fkattnum[INDEX_MAX_KEYS];
10579  bool attached;
10580  ObjectAddress address;
10581  ListCell *cell;
10582 
10583  CheckAlterTableIsSafe(partition);
10584 
10585  attmap = build_attrmap_by_name(RelationGetDescr(partition),
10586  RelationGetDescr(rel),
10587  false);
10588  for (int j = 0; j < numfks; j++)
10589  mapped_fkattnum[j] = attmap->attnums[fkattnum[j] - 1];
10590 
10591  /* Check whether an existing constraint can be repurposed */
10592  partFKs = copyObject(RelationGetFKeyList(partition));
10593  attached = false;
10594  foreach(cell, partFKs)
10595  {
10596  ForeignKeyCacheInfo *fk;
10597 
10598  fk = lfirst_node(ForeignKeyCacheInfo, cell);
10600  partitionId,
10601  parentConstr,
10602  numfks,
10603  mapped_fkattnum,
10604  pkattnum,
10605  pfeqoperators,
10606  insertTriggerOid,
10607  updateTriggerOid,
10608  trigrel))
10609  {
10610  attached = true;
10611  break;
10612  }
10613  }
10614  if (attached)
10615  {
10616  table_close(partition, NoLock);
10617  continue;
10618  }
10619 
10620  /*
10621  * No luck finding a good constraint to reuse; create our own.
10622  */
10624  fkconstraint->conname, fkconstraint,
10625  partition, pkrel, indexOid, parentConstr,
10626  numfks, pkattnum,
10627  mapped_fkattnum, pfeqoperators,
10628  ppeqoperators, ffeqoperators,
10629  numfkdelsetcols, fkdelsetcols, true,
10630  with_period);
10631 
10632  /* call ourselves to finalize the creation and we're done */
10633  addFkRecurseReferencing(wqueue, fkconstraint, partition, pkrel,
10634  indexOid,
10635  address.objectId,
10636  numfks,
10637  pkattnum,
10638  mapped_fkattnum,
10639  pfeqoperators,
10640  ppeqoperators,
10641  ffeqoperators,
10642  numfkdelsetcols,
10643  fkdelsetcols,
10644  old_check_ok,
10645  lockmode,
10646  insertTriggerOid,
10647  updateTriggerOid,
10648  with_period);
10649 
10650  table_close(partition, NoLock);
10651  }
10652 
10653  table_close(trigrel, RowExclusiveLock);
10654  }
10655 }
10656 
10657 /*
10658  * CloneForeignKeyConstraints
10659  * Clone foreign keys from a partitioned table to a newly acquired
10660  * partition.
10661  *
10662  * partitionRel is a partition of parentRel, so we can be certain that it has
10663  * the same columns with the same datatypes. The columns may be in different
10664  * order, though.
10665  *
10666  * wqueue must be passed to set up phase 3 constraint checking, unless the
10667  * referencing-side partition is known to be empty (such as in CREATE TABLE /
10668  * PARTITION OF).
10669  */
10670 static void
10672  Relation partitionRel)
10673 {
10674  /* This only works for declarative partitioning */
10675  Assert(parentRel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
10676 
10677  /*
10678  * Clone constraints for which the parent is on the referenced side.
10679  */
10680  CloneFkReferenced(parentRel, partitionRel);
10681 
10682  /*
10683  * Now clone constraints where the parent is on the referencing side.
10684  */
10685  CloneFkReferencing(wqueue, parentRel, partitionRel);
10686 }
10687 
10688 /*
10689  * CloneFkReferenced
10690  * Subroutine for CloneForeignKeyConstraints
10691  *
10692  * Find all the FKs that have the parent relation on the referenced side;
10693  * clone those constraints to the given partition. This is to be called
10694  * when the partition is being created or attached.
10695  *
10696  * This ignores self-referencing FKs; those are handled by CloneFkReferencing.
10697  *
10698  * This recurses to partitions, if the relation being attached is partitioned.
10699  * Recursion is done by calling addFkRecurseReferenced.
10700  */
10701 static void
10702 CloneFkReferenced(Relation parentRel, Relation partitionRel)
10703 {
10704  Relation pg_constraint;
10705  AttrMap *attmap;
10706  ListCell *cell;
10707  SysScanDesc scan;
10708  ScanKeyData key[2];
10709  HeapTuple tuple;
10710  List *clone = NIL;
10711  Relation trigrel;
10712 
10713  /*
10714  * Search for any constraints where this partition's parent is in the
10715  * referenced side. However, we must not clone any constraint whose
10716  * parent constraint is also going to be cloned, to avoid duplicates. So
10717  * do it in two steps: first construct the list of constraints to clone,
10718  * then go over that list cloning those whose parents are not in the list.
10719  * (We must not rely on the parent being seen first, since the catalog
10720  * scan could return children first.)
10721  */
10722  pg_constraint = table_open(ConstraintRelationId, RowShareLock);
10723  ScanKeyInit(&key[0],
10724  Anum_pg_constraint_confrelid, BTEqualStrategyNumber,
10725  F_OIDEQ, ObjectIdGetDatum(RelationGetRelid(parentRel)));
10726  ScanKeyInit(&key[1],
10727  Anum_pg_constraint_contype, BTEqualStrategyNumber,
10728  F_CHAREQ, CharGetDatum(CONSTRAINT_FOREIGN));
10729  /* This is a seqscan, as we don't have a usable index ... */
10730  scan = systable_beginscan(pg_constraint, InvalidOid, true,
10731  NULL, 2, key);
10732  while ((tuple = systable_getnext(scan)) != NULL)
10733  {
10734  Form_pg_constraint constrForm = (Form_pg_constraint) GETSTRUCT(tuple);
10735 
10736  clone = lappend_oid(clone, constrForm->oid);
10737  }
10738  systable_endscan(scan);
10739  table_close(pg_constraint, RowShareLock);
10740 
10741  /*
10742  * Triggers of the foreign keys will be manipulated a bunch of times in
10743  * the loop below. To avoid repeatedly opening/closing the trigger
10744  * catalog relation, we open it here and pass it to the subroutines called
10745  * below.
10746  */
10747  trigrel = table_open(TriggerRelationId, RowExclusiveLock);
10748 
10749  attmap = build_attrmap_by_name(RelationGetDescr(partitionRel),
10750  RelationGetDescr(parentRel),
10751  false);
10752  foreach(cell, clone)
10753  {
10754  Oid constrOid = lfirst_oid(cell);
10755  Form_pg_constraint constrForm;
10756  Relation fkRel;
10757  Oid indexOid;
10758  Oid partIndexId;
10759  int numfks;
10760  AttrNumber conkey[INDEX_MAX_KEYS];
10761  AttrNumber mapped_confkey[INDEX_MAX_KEYS];
10762  AttrNumber confkey[INDEX_MAX_KEYS];
10763  Oid conpfeqop[INDEX_MAX_KEYS];
10764  Oid conppeqop[INDEX_MAX_KEYS];
10765  Oid conffeqop[INDEX_MAX_KEYS];
10766  int numfkdelsetcols;
10767  AttrNumber confdelsetcols[INDEX_MAX_KEYS];
10768  Constraint *fkconstraint;
10769  ObjectAddress address;
10770  Oid deleteTriggerOid,
10771  updateTriggerOid;
10772 
10773  tuple = SearchSysCache1(CONSTROID, ObjectIdGetDatum(constrOid));
10774  if (!HeapTupleIsValid(tuple))
10775  elog(ERROR, "cache lookup failed for constraint %u", constrOid);
10776  constrForm = (Form_pg_constraint) GETSTRUCT(tuple);
10777 
10778  /*
10779  * As explained above: don't try to clone a constraint for which we're
10780  * going to clone the parent.
10781  */
10782  if (list_member_oid(clone, constrForm->conparentid))
10783  {
10784  ReleaseSysCache(tuple);
10785  continue;
10786  }
10787 
10788  /*
10789  * Don't clone self-referencing foreign keys, which can be in the
10790  * partitioned table or in the partition-to-be.
10791  */
10792  if (constrForm->conrelid == RelationGetRelid(parentRel) ||
10793  constrForm->conrelid == RelationGetRelid(partitionRel))
10794  {
10795  ReleaseSysCache(tuple);
10796  continue;
10797  }
10798 
10799  /*
10800  * Because we're only expanding the key space at the referenced side,
10801  * we don't need to prevent any operation in the referencing table, so
10802  * AccessShareLock suffices (assumes that dropping the constraint
10803  * acquires AccessExclusiveLock).
10804  */
10805  fkRel = table_open(constrForm->conrelid, AccessShareLock);
10806 
10807  indexOid = constrForm->conindid;
10809  &numfks,
10810  conkey,
10811  confkey,
10812  conpfeqop,
10813  conppeqop,
10814  conffeqop,
10815  &numfkdelsetcols,
10816  confdelsetcols);
10817 
10818  for (int i = 0; i < numfks; i++)
10819  mapped_confkey[i] = attmap->attnums[confkey[i] - 1];
10820 
10821  fkconstraint = makeNode(Constraint);
10822  fkconstraint->contype = CONSTRAINT_FOREIGN;
10823  fkconstraint->conname = NameStr(constrForm->conname);
10824  fkconstraint->deferrable = constrForm->condeferrable;
10825  fkconstraint->initdeferred = constrForm->condeferred;
10826  fkconstraint->location = -1;
10827  fkconstraint->pktable = NULL;
10828  /* ->fk_attrs determined below */
10829  fkconstraint->pk_attrs = NIL;
10830  fkconstraint->fk_matchtype = constrForm->confmatchtype;
10831  fkconstraint->fk_upd_action = constrForm->confupdtype;
10832  fkconstraint->fk_del_action = constrForm->confdeltype;
10833  fkconstraint->fk_del_set_cols = NIL;
10834  fkconstraint->old_conpfeqop = NIL;
10835  fkconstraint->old_pktable_oid = InvalidOid;
10836  fkconstraint->skip_validation = false;
10837  fkconstraint->initially_valid = true;
10838 
10839  /* set up colnames that are used to generate the constraint name */
10840  for (int i = 0; i < numfks; i++)
10841  {
10842  Form_pg_attribute att;
10843 
10844  att = TupleDescAttr(RelationGetDescr(fkRel),
10845  conkey[i] - 1);
10846  fkconstraint->fk_attrs = lappend(fkconstraint->fk_attrs,
10847  makeString(NameStr(att->attname)));
10848  }
10849 
10850  /*
10851  * Add the new foreign key constraint pointing to the new partition.
10852  * Because this new partition appears in the referenced side of the
10853  * constraint, we don't need to set up for Phase 3 check.
10854  */
10855  partIndexId = index_get_partition(partitionRel, indexOid);
10856  if (!OidIsValid(partIndexId))
10857  elog(ERROR, "index for %u not found in partition %s",
10858  indexOid, RelationGetRelationName(partitionRel));
10859 
10860  /*
10861  * Get the "action" triggers belonging to the constraint to pass as
10862  * parent OIDs for similar triggers that will be created on the
10863  * partition in addFkRecurseReferenced().
10864  */
10865  GetForeignKeyActionTriggers(trigrel, constrOid,
10866  constrForm->confrelid, constrForm->conrelid,
10867  &deleteTriggerOid, &updateTriggerOid);
10868 
10869  /* Add this constraint ... */
10871  fkconstraint->conname, fkconstraint, fkRel,
10872  partitionRel, partIndexId, constrOid,
10873  numfks, mapped_confkey,
10874  conkey, conpfeqop, conppeqop, conffeqop,
10875  numfkdelsetcols, confdelsetcols, false,
10876  constrForm->conperiod);
10877  /* ... and recurse */
10878  addFkRecurseReferenced(fkconstraint,
10879  fkRel,
10880  partitionRel,
10881  partIndexId,
10882  address.objectId,
10883  numfks,
10884  mapped_confkey,
10885  conkey,
10886  conpfeqop,
10887  conppeqop,
10888  conffeqop,
10889  numfkdelsetcols,
10890  confdelsetcols,
10891  true,
10892  deleteTriggerOid,
10893  updateTriggerOid,
10894  constrForm->conperiod);
10895 
10896  table_close(fkRel, NoLock);
10897  ReleaseSysCache(tuple);
10898  }
10899 
10900  table_close(trigrel, RowExclusiveLock);
10901 }
10902 
10903 /*
10904  * CloneFkReferencing
10905  * Subroutine for CloneForeignKeyConstraints
10906  *
10907  * For each FK constraint of the parent relation in the given list, find an
10908  * equivalent constraint in its partition relation that can be reparented;
10909  * if one cannot be found, create a new constraint in the partition as its
10910  * child.
10911  *
10912  * If wqueue is given, it is used to set up phase-3 verification for each
10913  * cloned constraint; omit it if such verification is not needed
10914  * (example: the partition is being created anew).
10915  */
10916 static void
10917 CloneFkReferencing(List **wqueue, Relation parentRel, Relation partRel)
10918 {
10919  AttrMap *attmap;
10920  List *partFKs;
10921  List *clone = NIL;
10922  ListCell *cell;
10923  Relation trigrel;
10924 
10925  /* obtain a list of constraints that we need to clone */
10926  foreach(cell, RelationGetFKeyList(parentRel))
10927  {
10928  ForeignKeyCacheInfo *fk = lfirst(cell);
10929 
10930  /*
10931  * Refuse to attach a table as partition that this partitioned table
10932  * already has a foreign key to. This isn't useful schema, which is
10933  * proven by the fact that there have been no user complaints that
10934  * it's already impossible to achieve this in the opposite direction,
10935  * i.e., creating a foreign key that references a partition. This
10936  * restriction allows us to dodge some complexities around
10937  * pg_constraint and pg_trigger row creations that would be needed
10938  * during ATTACH/DETACH for this kind of relationship.
10939  */
10940  if (fk->confrelid == RelationGetRelid(partRel))
10941  ereport(ERROR,
10942  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
10943  errmsg("cannot attach table \"%s\" as a partition because it is referenced by foreign key \"%s\"",
10944  RelationGetRelationName(partRel),
10945  get_constraint_name(fk->conoid))));
10946 
10947  clone = lappend_oid(clone, fk->conoid);
10948  }
10949 
10950  /*
10951  * Silently do nothing if there's nothing to do. In particular, this
10952  * avoids throwing a spurious error for foreign tables.
10953  */
10954  if (clone == NIL)
10955  return;
10956 
10957  if (partRel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
10958  ereport(ERROR,
10959  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
10960  errmsg("foreign key constraints are not supported on foreign tables")));
10961 
10962  /*
10963  * Triggers of the foreign keys will be manipulated a bunch of times in
10964  * the loop below. To avoid repeatedly opening/closing the trigger
10965  * catalog relation, we open it here and pass it to the subroutines called
10966  * below.
10967  */
10968  trigrel = table_open(TriggerRelationId, RowExclusiveLock);
10969 
10970  /*
10971  * The constraint key may differ, if the columns in the partition are
10972  * different. This map is used to convert them.
10973  */
10974  attmap = build_attrmap_by_name(RelationGetDescr(partRel),
10975  RelationGetDescr(parentRel),
10976  false);
10977 
10978  partFKs = copyObject(RelationGetFKeyList(partRel));
10979 
10980  foreach(cell, clone)
10981  {
10982  Oid parentConstrOid = lfirst_oid(cell);
10983  Form_pg_constraint constrForm;
10984  Relation pkrel;
10985  HeapTuple tuple;
10986  int numfks;
10987  AttrNumber conkey[INDEX_MAX_KEYS];
10988  AttrNumber mapped_conkey[INDEX_MAX_KEYS];
10989  AttrNumber confkey[INDEX_MAX_KEYS];
10990  Oid conpfeqop[INDEX_MAX_KEYS];
10991  Oid conppeqop[INDEX_MAX_KEYS];
10992  Oid conffeqop[INDEX_MAX_KEYS];
10993  int numfkdelsetcols;
10994  AttrNumber confdelsetcols[INDEX_MAX_KEYS];
10995  Constraint *fkconstraint;
10996  bool attached;
10997  Oid indexOid;
10998  ObjectAddress address;
10999  ListCell *lc;
11000  Oid insertTriggerOid,
11001  updateTriggerOid;
11002  bool with_period;
11003 
11004  tuple = SearchSysCache1(CONSTROID, ObjectIdGetDatum(parentConstrOid));
11005  if (!HeapTupleIsValid(tuple))
11006  elog(ERROR, "cache lookup failed for constraint %u",
11007  parentConstrOid);
11008  constrForm = (Form_pg_constraint) GETSTRUCT(tuple);
11009 
11010  /* Don't clone constraints whose parents are being cloned */
11011  if (list_member_oid(clone, constrForm->conparentid))
11012  {
11013  ReleaseSysCache(tuple);
11014  continue;
11015  }
11016 
11017  /*
11018  * Need to prevent concurrent deletions. If pkrel is a partitioned
11019  * relation, that means to lock all partitions.
11020  */
11021  pkrel = table_open(constrForm->confrelid, ShareRowExclusiveLock);
11022  if (pkrel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
11023  (void) find_all_inheritors(RelationGetRelid(pkrel),
11024  ShareRowExclusiveLock, NULL);
11025 
11026  DeconstructFkConstraintRow(tuple, &numfks, conkey, confkey,
11027  conpfeqop, conppeqop, conffeqop,
11028  &numfkdelsetcols, confdelsetcols);
11029  for (int i = 0; i < numfks; i++)
11030  mapped_conkey[i] = attmap->attnums[conkey[i] - 1];
11031 
11032  /*
11033  * Get the "check" triggers belonging to the constraint to pass as
11034  * parent OIDs for similar triggers that will be created on the
11035  * partition in addFkRecurseReferencing(). They are also passed to
11036  * tryAttachPartitionForeignKey() below to simply assign as parents to
11037  * the partition's existing "check" triggers, that is, if the
11038  * corresponding constraints is deemed attachable to the parent
11039  * constraint.
11040  */
11041  GetForeignKeyCheckTriggers(trigrel, constrForm->oid,
11042  constrForm->confrelid, constrForm->conrelid,
11043  &insertTriggerOid, &updateTriggerOid);
11044 
11045  /*
11046  * Before creating a new constraint, see whether any existing FKs are
11047  * fit for the purpose. If one is, attach the parent constraint to
11048  * it, and don't clone anything. This way we avoid the expensive
11049  * verification step and don't end up with a duplicate FK, and we
11050  * don't need to recurse to partitions for this constraint.
11051  */
11052  attached = false;
11053  foreach(lc, partFKs)
11054  {
11056 
11058  RelationGetRelid(partRel),
11059  parentConstrOid,
11060  numfks,
11061  mapped_conkey,
11062  confkey,
11063  conpfeqop,
11064  insertTriggerOid,
11065  updateTriggerOid,
11066  trigrel))
11067  {
11068  attached = true;
11069  table_close(pkrel, NoLock);
11070  break;
11071  }
11072  }
11073  if (attached)
11074  {
11075  ReleaseSysCache(tuple);
11076  continue;
11077  }
11078 
11079  /* No dice. Set up to create our own constraint */
11080  fkconstraint = makeNode(Constraint);
11081  fkconstraint->contype = CONSTRAINT_FOREIGN;
11082  /* ->conname determined below */
11083  fkconstraint->deferrable = constrForm->condeferrable;
11084  fkconstraint->initdeferred = constrForm->condeferred;
11085  fkconstraint->location = -1;
11086  fkconstraint->pktable = NULL;
11087  /* ->fk_attrs determined below */
11088  fkconstraint->pk_attrs = NIL;
11089  fkconstraint->fk_matchtype = constrForm->confmatchtype;
11090  fkconstraint->fk_upd_action = constrForm->confupdtype;
11091  fkconstraint->fk_del_action = constrForm->confdeltype;
11092  fkconstraint->fk_del_set_cols = NIL;
11093  fkconstraint->old_conpfeqop = NIL;
11094  fkconstraint->old_pktable_oid = InvalidOid;
11095  fkconstraint->skip_validation = false;
11096  fkconstraint->initially_valid = constrForm->convalidated;
11097  for (int i = 0; i < numfks; i++)
11098  {
11099  Form_pg_attribute att;
11100 
11101  att = TupleDescAttr(RelationGetDescr(partRel),
11102  mapped_conkey[i] - 1);
11103  fkconstraint->fk_attrs = lappend(fkconstraint->fk_attrs,
11104  makeString(NameStr(att->attname)));
11105  }
11106 
11107  indexOid = constrForm->conindid;
11108  with_period = constrForm->conperiod;
11109 
11110  /* Create the pg_constraint entry at this level */
11112  NameStr(constrForm->conname), fkconstraint,
11113  partRel, pkrel, indexOid, parentConstrOid,
11114  numfks, confkey,
11115  mapped_conkey, conpfeqop,
11116  conppeqop, conffeqop,
11117  numfkdelsetcols, confdelsetcols,
11118  false, with_period);
11119 
11120  /* Done with the cloned constraint's tuple */
11121  ReleaseSysCache(tuple);
11122 
11123  /* Create the check triggers, and recurse to partitions, if any */
11124  addFkRecurseReferencing(wqueue,
11125  fkconstraint,
11126  partRel,
11127  pkrel,
11128  indexOid,
11129  address.objectId,
11130  numfks,
11131  confkey,
11132  mapped_conkey,
11133  conpfeqop,
11134  conppeqop,
11135  conffeqop,
11136  numfkdelsetcols,
11137  confdelsetcols,
11138  false, /* no old check exists */
11140  insertTriggerOid,
11141  updateTriggerOid,
11142  with_period);
11143  table_close(pkrel, NoLock);
11144  }
11145 
11146  table_close(trigrel, RowExclusiveLock);
11147 }
11148 
11149 /*
11150  * When the parent of a partition receives [the referencing side of] a foreign
11151  * key, we must propagate that foreign key to the partition. However, the
11152  * partition might already have an equivalent foreign key; this routine
11153  * compares the given ForeignKeyCacheInfo (in the partition) to the FK defined
11154  * by the other parameters. If they are equivalent, create the link between
11155  * the two constraints and return true.
11156  *
11157  * If the given FK does not match the one defined by rest of the params,
11158  * return false.
11159  */
11160 static bool
11162  Oid partRelid,
11163  Oid parentConstrOid,
11164  int numfks,
11165  AttrNumber *mapped_conkey,
11166  AttrNumber *confkey,
11167  Oid *conpfeqop,
11168  Oid parentInsTrigger,
11169  Oid parentUpdTrigger,
11170  Relation trigrel)
11171 {
11172  HeapTuple parentConstrTup;
11173  Form_pg_constraint parentConstr;
11174  HeapTuple partcontup;
11175  Form_pg_constraint partConstr;
11176  ScanKeyData key;
11177  SysScanDesc scan;
11178  HeapTuple trigtup;
11179  Oid insertTriggerOid,
11180  updateTriggerOid;
11181 
11182  parentConstrTup = SearchSysCache1(CONSTROID,
11183  ObjectIdGetDatum(parentConstrOid));
11184  if (!HeapTupleIsValid(parentConstrTup))
11185  elog(ERROR, "cache lookup failed for constraint %u", parentConstrOid);
11186  parentConstr = (Form_pg_constraint) GETSTRUCT(parentConstrTup);
11187 
11188  /*
11189  * Do some quick & easy initial checks. If any of these fail, we cannot
11190  * use this constraint.
11191  */
11192  if (fk->confrelid != parentConstr->confrelid || fk->nkeys != numfks)
11193  {
11194  ReleaseSysCache(parentConstrTup);
11195  return false;
11196  }
11197  for (int i = 0; i < numfks; i++)
11198  {
11199  if (fk->conkey[i] != mapped_conkey[i] ||
11200  fk->confkey[i] != confkey[i] ||
11201  fk->conpfeqop[i] != conpfeqop[i])
11202  {
11203  ReleaseSysCache(parentConstrTup);
11204  return false;
11205  }
11206  }
11207 
11208  /*
11209  * Looks good so far; do some more extensive checks. Presumably the check
11210  * for 'convalidated' could be dropped, since we don't really care about
11211  * that, but let's be careful for now.
11212  */
11213  partcontup = SearchSysCache1(CONSTROID,
11214  ObjectIdGetDatum(fk->conoid));
11215  if (!HeapTupleIsValid(partcontup))
11216  elog(ERROR, "cache lookup failed for constraint %u", fk->conoid);
11217  partConstr = (Form_pg_constraint) GETSTRUCT(partcontup);
11218  if (OidIsValid(partConstr->conparentid) ||
11219  !partConstr->convalidated ||
11220  partConstr->condeferrable != parentConstr->condeferrable ||
11221  partConstr->condeferred != parentConstr->condeferred ||
11222  partConstr->confupdtype != parentConstr->confupdtype ||
11223  partConstr->confdeltype != parentConstr->confdeltype ||
11224  partConstr->confmatchtype != parentConstr->confmatchtype)
11225  {
11226  ReleaseSysCache(parentConstrTup);
11227  ReleaseSysCache(partcontup);
11228  return false;
11229  }
11230 
11231  ReleaseSysCache(partcontup);
11232  ReleaseSysCache(parentConstrTup);
11233 
11234  /*
11235  * Looks good! Attach this constraint. The action triggers in the new
11236  * partition become redundant -- the parent table already has equivalent
11237  * ones, and those will be able to reach the partition. Remove the ones
11238  * in the partition. We identify them because they have our constraint
11239  * OID, as well as being on the referenced rel.
11240  */
11241  ScanKeyInit(&key,
11242  Anum_pg_trigger_tgconstraint,
11243  BTEqualStrategyNumber, F_OIDEQ,
11244  ObjectIdGetDatum(fk->conoid));
11245  scan = systable_beginscan(trigrel, TriggerConstraintIndexId, true,
11246  NULL, 1, &key);
11247  while ((trigtup = systable_getnext(scan)) != NULL)
11248  {
11249  Form_pg_trigger trgform = (Form_pg_trigger) GETSTRUCT(trigtup);
11250  ObjectAddress trigger;
11251 
11252  if (trgform->tgconstrrelid != fk->conrelid)
11253  continue;
11254  if (trgform->tgrelid != fk->confrelid)
11255  continue;
11256 
11257  /*
11258  * The constraint is originally set up to contain this trigger as an
11259  * implementation object, so there's a dependency record that links
11260  * the two; however, since the trigger is no longer needed, we remove
11261  * the dependency link in order to be able to drop the trigger while
11262  * keeping the constraint intact.
11263  */
11264  deleteDependencyRecordsFor(TriggerRelationId,
11265  trgform->oid,
11266  false);
11267  /* make dependency deletion visible to performDeletion */
11269  ObjectAddressSet(trigger, TriggerRelationId,
11270  trgform->oid);
11271  performDeletion(&trigger, DROP_RESTRICT, 0);
11272  /* make trigger drop visible, in case the loop iterates */
11274  }
11275 
11276  systable_endscan(scan);
11277 
11278  ConstraintSetParentConstraint(fk->conoid, parentConstrOid, partRelid);
11279 
11280  /*
11281  * Like the constraint, attach partition's "check" triggers to the
11282  * corresponding parent triggers.
11283  */
11285  fk->conoid, fk->confrelid, fk->conrelid,
11286  &insertTriggerOid, &updateTriggerOid);
11287  Assert(OidIsValid(insertTriggerOid) && OidIsValid(parentInsTrigger));
11288  TriggerSetParentTrigger(trigrel, insertTriggerOid, parentInsTrigger,
11289  partRelid);
11290  Assert(OidIsValid(updateTriggerOid) && OidIsValid(parentUpdTrigger));
11291  TriggerSetParentTrigger(trigrel, updateTriggerOid, parentUpdTrigger,
11292  partRelid);
11293 
11294  /*
11295  * If the referenced table is partitioned, then the partition we're
11296  * attaching now has extra pg_constraint rows and action triggers that are
11297  * no longer needed. Remove those.
11298  */
11299  if (get_rel_relkind(fk->confrelid) == RELKIND_PARTITIONED_TABLE)
11300  {
11301  Relation pg_constraint = table_open(ConstraintRelationId, RowShareLock);
11302  ObjectAddresses *objs;
11303  HeapTuple consttup;
11304 
11305  ScanKeyInit(&key,
11306  Anum_pg_constraint_conrelid,
11307  BTEqualStrategyNumber, F_OIDEQ,
11308  ObjectIdGetDatum(fk->conrelid));
11309 
11310  scan = systable_beginscan(pg_constraint,
11311  ConstraintRelidTypidNameIndexId,
11312  true, NULL, 1, &key);
11313  objs = new_object_addresses();
11314  while ((consttup = systable_getnext(scan)) != NULL)
11315  {
11316  Form_pg_constraint conform = (Form_pg_constraint) GETSTRUCT(consttup);
11317 
11318  if (conform->conparentid != fk->conoid)
11319  continue;
11320  else
11321  {
11322  ObjectAddress addr;
11323  SysScanDesc scan2;
11324  ScanKeyData key2;
11326 
11327  ObjectAddressSet(addr, ConstraintRelationId, conform->oid);
11328  add_exact_object_address(&addr, objs);
11329 
11330  /*
11331  * First we must delete the dependency record that binds the
11332  * constraint records together.
11333  */
11334  n = deleteDependencyRecordsForSpecific(ConstraintRelationId,
11335  conform->oid,
11337  ConstraintRelationId,
11338  fk->conoid);
11339  Assert(n == 1); /* actually only one is expected */
11340 
11341  /*
11342  * Now search for the triggers for this constraint and set
11343  * them up for deletion too
11344  */
11345  ScanKeyInit(&key2,
11346  Anum_pg_trigger_tgconstraint,
11347  BTEqualStrategyNumber, F_OIDEQ,
11348  ObjectIdGetDatum(conform->oid));
11349  scan2 = systable_beginscan(trigrel, TriggerConstraintIndexId,
11350  true, NULL, 1, &key2);
11351  while ((trigtup = systable_getnext(scan2)) != NULL)
11352  {
11353  ObjectAddressSet(addr, TriggerRelationId,
11354  ((Form_pg_trigger) GETSTRUCT(trigtup))->oid);
11355  add_exact_object_address(&addr, objs);
11356  }
11357  systable_endscan(scan2);
11358  }
11359  }
11360  /* make the dependency deletions visible */
11364  systable_endscan(scan);
11365 
11366  table_close(pg_constraint, RowShareLock);
11367  }
11368 
11370  return true;
11371 }
11372 
11373 /*
11374  * GetForeignKeyActionTriggers
11375  * Returns delete and update "action" triggers of the given relation
11376  * belonging to the given constraint
11377  */
11378 static void
11380  Oid conoid, Oid confrelid, Oid conrelid,
11381  Oid *deleteTriggerOid,
11382  Oid *updateTriggerOid)
11383 {
11384  ScanKeyData key;
11385  SysScanDesc scan;
11386  HeapTuple trigtup;
11387 
11388  *deleteTriggerOid = *updateTriggerOid = InvalidOid;
11389  ScanKeyInit(&key,
11390  Anum_pg_trigger_tgconstraint,
11391  BTEqualStrategyNumber, F_OIDEQ,
11392  ObjectIdGetDatum(conoid));
11393 
11394  scan = systable_beginscan(trigrel, TriggerConstraintIndexId, true,
11395  NULL, 1, &key);
11396  while ((trigtup = systable_getnext(scan)) != NULL)
11397  {
11398  Form_pg_trigger trgform = (Form_pg_trigger) GETSTRUCT(trigtup);
11399 
11400  if (trgform->tgconstrrelid != conrelid)
11401  continue;
11402  if (trgform->tgrelid != confrelid)
11403  continue;
11404  /* Only ever look at "action" triggers on the PK side. */
11405  if (RI_FKey_trigger_type(trgform->tgfoid) != RI_TRIGGER_PK)
11406  continue;
11407  if (TRIGGER_FOR_DELETE(trgform->tgtype))
11408  {
11409  Assert(*deleteTriggerOid == InvalidOid);
11410  *deleteTriggerOid = trgform->oid;
11411  }
11412  else if (TRIGGER_FOR_UPDATE(trgform->tgtype))
11413  {
11414  Assert(*updateTriggerOid == InvalidOid);
11415  *updateTriggerOid = trgform->oid;
11416  }
11417 #ifndef USE_ASSERT_CHECKING
11418  /* In an assert-enabled build, continue looking to find duplicates */
11419  if (OidIsValid(*deleteTriggerOid) && OidIsValid(*updateTriggerOid))
11420  break;
11421 #endif
11422  }
11423 
11424  if (!OidIsValid(*deleteTriggerOid))
11425  elog(ERROR, "could not find ON DELETE action trigger of foreign key constraint %u",
11426  conoid);
11427  if (!OidIsValid(*updateTriggerOid))
11428  elog(ERROR, "could not find ON UPDATE action trigger of foreign key constraint %u",
11429  conoid);
11430 
11431  systable_endscan(scan);
11432 }
11433 
11434 /*
11435  * GetForeignKeyCheckTriggers
11436  * Returns insert and update "check" triggers of the given relation
11437  * belonging to the given constraint
11438  */
11439 static void
11441  Oid conoid, Oid confrelid, Oid conrelid,
11442  Oid *insertTriggerOid,
11443  Oid *updateTriggerOid)
11444 {
11445  ScanKeyData key;
11446  SysScanDesc scan;
11447  HeapTuple trigtup;
11448 
11449  *insertTriggerOid = *updateTriggerOid = InvalidOid;
11450  ScanKeyInit(&key,
11451  Anum_pg_trigger_tgconstraint,
11452  BTEqualStrategyNumber, F_OIDEQ,
11453  ObjectIdGetDatum(conoid));
11454 
11455  scan = systable_beginscan(trigrel, TriggerConstraintIndexId, true,
11456  NULL, 1, &key);
11457  while ((trigtup = systable_getnext(scan)) != NULL)
11458  {
11459  Form_pg_trigger trgform = (Form_pg_trigger) GETSTRUCT(trigtup);
11460 
11461  if (trgform->tgconstrrelid != confrelid)
11462  continue;
11463  if (trgform->tgrelid != conrelid)
11464  continue;
11465  /* Only ever look at "check" triggers on the FK side. */
11466  if (RI_FKey_trigger_type(trgform->tgfoid) != RI_TRIGGER_FK)
11467  continue;
11468  if (TRIGGER_FOR_INSERT(trgform->tgtype))
11469  {
11470  Assert(*insertTriggerOid == InvalidOid);
11471  *insertTriggerOid = trgform->oid;
11472  }
11473  else if (TRIGGER_FOR_UPDATE(trgform->tgtype))
11474  {
11475  Assert(*updateTriggerOid == InvalidOid);
11476  *updateTriggerOid = trgform->oid;
11477  }
11478 #ifndef USE_ASSERT_CHECKING
11479  /* In an assert-enabled build, continue looking to find duplicates. */
11480  if (OidIsValid(*insertTriggerOid) && OidIsValid(*updateTriggerOid))
11481  break;
11482 #endif
11483  }
11484 
11485  if (!OidIsValid(*insertTriggerOid))
11486  elog(ERROR, "could not find ON INSERT check triggers of foreign key constraint %u",
11487  conoid);
11488  if (!OidIsValid(*updateTriggerOid))
11489  elog(ERROR, "could not find ON UPDATE check triggers of foreign key constraint %u",
11490  conoid);
11491 
11492  systable_endscan(scan);
11493 }
11494 
11495 /*
11496  * ALTER TABLE ALTER CONSTRAINT
11497  *
11498  * Update the attributes of a constraint.
11499  *
11500  * Currently only works for Foreign Key constraints.
11501  *
11502  * If the constraint is modified, returns its address; otherwise, return
11503  * InvalidObjectAddress.
11504  */
11505 static ObjectAddress
11507  bool recursing, LOCKMODE lockmode)
11508 {
11509  Constraint *cmdcon;
11510  Relation conrel;
11511  Relation tgrel;
11512  SysScanDesc scan;
11513  ScanKeyData skey[3];
11514  HeapTuple contuple;
11515  Form_pg_constraint currcon;
11516  ObjectAddress address;
11517  List *otherrelids = NIL;
11518  ListCell *lc;
11519 
11520  cmdcon = castNode(Constraint, cmd->def);
11521 
11522  conrel = table_open(ConstraintRelationId, RowExclusiveLock);
11523  tgrel = table_open(TriggerRelationId, RowExclusiveLock);
11524 
11525  /*
11526  * Find and check the target constraint
11527  */
11528  ScanKeyInit(&skey[0],
11529  Anum_pg_constraint_conrelid,
11530  BTEqualStrategyNumber, F_OIDEQ,
11532  ScanKeyInit(&skey[1],
11533  Anum_pg_constraint_contypid,
11534  BTEqualStrategyNumber, F_OIDEQ,
11536  ScanKeyInit(&skey[2],
11537  Anum_pg_constraint_conname,
11538  BTEqualStrategyNumber, F_NAMEEQ,
11539  CStringGetDatum(cmdcon->conname));
11540  scan = systable_beginscan(conrel, ConstraintRelidTypidNameIndexId,
11541  true, NULL, 3, skey);
11542 
11543  /* There can be at most one matching row */
11544  if (!HeapTupleIsValid(contuple = systable_getnext(scan)))
11545  ereport(ERROR,
11546  (errcode(ERRCODE_UNDEFINED_OBJECT),
11547  errmsg("constraint \"%s\" of relation \"%s\" does not exist",
11548  cmdcon->conname, RelationGetRelationName(rel))));
11549 
11550  currcon = (Form_pg_constraint) GETSTRUCT(contuple);
11551  if (currcon->contype != CONSTRAINT_FOREIGN)
11552  ereport(ERROR,
11553  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
11554  errmsg("constraint \"%s\" of relation \"%s\" is not a foreign key constraint",
11555  cmdcon->conname, RelationGetRelationName(rel))));
11556 
11557  /*
11558  * If it's not the topmost constraint, raise an error.
11559  *
11560  * Altering a non-topmost constraint leaves some triggers untouched, since
11561  * they are not directly connected to this constraint; also, pg_dump would
11562  * ignore the deferrability status of the individual constraint, since it
11563  * only dumps topmost constraints. Avoid these problems by refusing this
11564  * operation and telling the user to alter the parent constraint instead.
11565  */
11566  if (OidIsValid(currcon->conparentid))
11567  {
11568  HeapTuple tp;
11569  Oid parent = currcon->conparentid;
11570  char *ancestorname = NULL;
11571  char *ancestortable = NULL;
11572 
11573  /* Loop to find the topmost constraint */
11574  while (HeapTupleIsValid(tp = SearchSysCache1(CONSTROID, ObjectIdGetDatum(parent))))
11575  {
11577 
11578  /* If no parent, this is the constraint we want */
11579  if (!OidIsValid(contup->conparentid))
11580  {
11581  ancestorname = pstrdup(NameStr(contup->conname));
11582  ancestortable = get_rel_name(contup->conrelid);
11583  ReleaseSysCache(tp);
11584  break;
11585  }
11586 
11587  parent = contup->conparentid;
11588  ReleaseSysCache(tp);
11589  }
11590 
11591  ereport(ERROR,
11592  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
11593  errmsg("cannot alter constraint \"%s\" on relation \"%s\"",
11594  cmdcon->conname, RelationGetRelationName(rel)),
11595  ancestorname && ancestortable ?
11596  errdetail("Constraint \"%s\" is derived from constraint \"%s\" of relation \"%s\".",
11597  cmdcon->conname, ancestorname, ancestortable) : 0,
11598  errhint("You may alter the constraint it derives from instead.")));
11599  }
11600 
11601  /*
11602  * Do the actual catalog work. We can skip changing if already in the
11603  * desired state, but not if a partitioned table: partitions need to be
11604  * processed regardless, in case they had the constraint locally changed.
11605  */
11606  address = InvalidObjectAddress;
11607  if (currcon->condeferrable != cmdcon->deferrable ||
11608  currcon->condeferred != cmdcon->initdeferred ||
11609  rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
11610  {
11611  if (ATExecAlterConstrRecurse(cmdcon, conrel, tgrel, rel, contuple,
11612  &otherrelids, lockmode))
11613  ObjectAddressSet(address, ConstraintRelationId, currcon->oid);
11614  }
11615 
11616  /*
11617  * ATExecAlterConstrRecurse already invalidated relcache for the relations
11618  * having the constraint itself; here we also invalidate for relations
11619  * that have any triggers that are part of the constraint.
11620  */
11621  foreach(lc, otherrelids)
11623 
11624  systable_endscan(scan);
11625 
11626  table_close(tgrel, RowExclusiveLock);
11627  table_close(conrel, RowExclusiveLock);
11628 
11629  return address;
11630 }
11631 
11632 /*
11633  * Recursive subroutine of ATExecAlterConstraint. Returns true if the
11634  * constraint is altered.
11635  *
11636  * *otherrelids is appended OIDs of relations containing affected triggers.
11637  *
11638  * Note that we must recurse even when the values are correct, in case
11639  * indirect descendants have had their constraints altered locally.
11640  * (This could be avoided if we forbade altering constraints in partitions
11641  * but existing releases don't do that.)
11642  */
11643 static bool
11645  Relation rel, HeapTuple contuple, List **otherrelids,
11646  LOCKMODE lockmode)
11647 {
11648  Form_pg_constraint currcon;
11649  Oid conoid;
11650  Oid refrelid;
11651  bool changed = false;
11652 
11653  /* since this function recurses, it could be driven to stack overflow */
11655 
11656  currcon = (Form_pg_constraint) GETSTRUCT(contuple);
11657  conoid = currcon->oid;
11658  refrelid = currcon->confrelid;
11659 
11660  /*
11661  * Update pg_constraint with the flags from cmdcon.
11662  *
11663  * If called to modify a constraint that's already in the desired state,
11664  * silently do nothing.
11665  */
11666  if (currcon->condeferrable != cmdcon->deferrable ||
11667  currcon->condeferred != cmdcon->initdeferred)
11668  {
11669  HeapTuple copyTuple;
11670  Form_pg_constraint copy_con;
11671  HeapTuple tgtuple;
11672  ScanKeyData tgkey;
11673  SysScanDesc tgscan;
11674 
11675  copyTuple = heap_copytuple(contuple);
11676  copy_con = (Form_pg_constraint) GETSTRUCT(copyTuple);
11677  copy_con->condeferrable = cmdcon->deferrable;
11678  copy_con->condeferred = cmdcon->initdeferred;
11679  CatalogTupleUpdate(conrel, &copyTuple->t_self, copyTuple);
11680 
11681  InvokeObjectPostAlterHook(ConstraintRelationId,
11682  conoid, 0);
11683 
11684  heap_freetuple(copyTuple);
11685  changed = true;
11686 
11687  /* Make new constraint flags visible to others */
11689 
11690  /*
11691  * Now we need to update the multiple entries in pg_trigger that
11692  * implement the constraint.
11693  */
11694  ScanKeyInit(&tgkey,
11695  Anum_pg_trigger_tgconstraint,
11696  BTEqualStrategyNumber, F_OIDEQ,
11697  ObjectIdGetDatum(conoid));
11698  tgscan = systable_beginscan(tgrel, TriggerConstraintIndexId, true,
11699  NULL, 1, &tgkey);
11700  while (HeapTupleIsValid(tgtuple = systable_getnext(tgscan)))
11701  {
11702  Form_pg_trigger tgform = (Form_pg_trigger) GETSTRUCT(tgtuple);
11703  Form_pg_trigger copy_tg;
11704  HeapTuple tgCopyTuple;
11705 
11706  /*
11707  * Remember OIDs of other relation(s) involved in FK constraint.
11708  * (Note: it's likely that we could skip forcing a relcache inval
11709  * for other rels that don't have a trigger whose properties
11710  * change, but let's be conservative.)
11711  */
11712  if (tgform->tgrelid != RelationGetRelid(rel))
11713  *otherrelids = list_append_unique_oid(*otherrelids,
11714  tgform->tgrelid);
11715 
11716  /*
11717  * Update deferrability of RI_FKey_noaction_del,
11718  * RI_FKey_noaction_upd, RI_FKey_check_ins and RI_FKey_check_upd
11719  * triggers, but not others; see createForeignKeyActionTriggers
11720  * and CreateFKCheckTrigger.
11721  */
11722  if (tgform->tgfoid != F_RI_FKEY_NOACTION_DEL &&
11723  tgform->tgfoid != F_RI_FKEY_NOACTION_UPD &&
11724  tgform->tgfoid != F_RI_FKEY_CHECK_INS &&
11725  tgform->tgfoid != F_RI_FKEY_CHECK_UPD)
11726  continue;
11727 
11728  tgCopyTuple = heap_copytuple(tgtuple);
11729  copy_tg = (Form_pg_trigger) GETSTRUCT(tgCopyTuple);
11730 
11731  copy_tg->tgdeferrable = cmdcon->deferrable;
11732  copy_tg->tginitdeferred = cmdcon->initdeferred;
11733  CatalogTupleUpdate(tgrel, &tgCopyTuple->t_self, tgCopyTuple);
11734 
11735  InvokeObjectPostAlterHook(TriggerRelationId, tgform->oid, 0);
11736 
11737  heap_freetuple(tgCopyTuple);
11738  }
11739 
11740  systable_endscan(tgscan);
11741  }
11742 
11743  /*
11744  * If the table at either end of the constraint is partitioned, we need to
11745  * recurse and handle every constraint that is a child of this one.
11746  *
11747  * (This assumes that the recurse flag is forcibly set for partitioned
11748  * tables, and not set for legacy inheritance, though we don't check for
11749  * that here.)
11750  */
11751  if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE ||
11752  get_rel_relkind(refrelid) == RELKIND_PARTITIONED_TABLE)
11753  {
11754  ScanKeyData pkey;
11755  SysScanDesc pscan;
11756  HeapTuple childtup;
11757 
11758  ScanKeyInit(&pkey,
11759  Anum_pg_constraint_conparentid,
11760  BTEqualStrategyNumber, F_OIDEQ,
11761  ObjectIdGetDatum(conoid));
11762 
11763  pscan = systable_beginscan(conrel, ConstraintParentIndexId,
11764  true, NULL, 1, &pkey);
11765 
11766  while (HeapTupleIsValid(childtup = systable_getnext(pscan)))
11767  {
11768  Form_pg_constraint childcon = (Form_pg_constraint) GETSTRUCT(childtup);
11769  Relation childrel;
11770 
11771  childrel = table_open(childcon->conrelid, lockmode);
11772  ATExecAlterConstrRecurse(cmdcon, conrel, tgrel, childrel, childtup,
11773  otherrelids, lockmode);
11774  table_close(childrel, NoLock);
11775  }
11776 
11777  systable_endscan(pscan);
11778  }
11779 
11780  return changed;
11781 }
11782 
11783 /*
11784  * ALTER TABLE VALIDATE CONSTRAINT
11785  *
11786  * XXX The reason we handle recursion here rather than at Phase 1 is because
11787  * there's no good way to skip recursing when handling foreign keys: there is
11788  * no need to lock children in that case, yet we wouldn't be able to avoid
11789  * doing so at that level.
11790  *
11791  * Return value is the address of the validated constraint. If the constraint
11792  * was already validated, InvalidObjectAddress is returned.
11793  */
11794 static ObjectAddress
11795 ATExecValidateConstraint(List **wqueue, Relation rel, char *constrName,
11796  bool recurse, bool recursing, LOCKMODE lockmode)
11797 {
11798  Relation conrel;
11799  SysScanDesc scan;
11800  ScanKeyData skey[3];
11801  HeapTuple tuple;
11802  Form_pg_constraint con;
11803  ObjectAddress address;
11804 
11805  conrel = table_open(ConstraintRelationId, RowExclusiveLock);
11806 
11807  /*
11808  * Find and check the target constraint
11809  */
11810  ScanKeyInit(&skey[0],
11811  Anum_pg_constraint_conrelid,
11812  BTEqualStrategyNumber, F_OIDEQ,
11814  ScanKeyInit(&skey[1],
11815  Anum_pg_constraint_contypid,
11816  BTEqualStrategyNumber, F_OIDEQ,
11818  ScanKeyInit(&skey[2],
11819  Anum_pg_constraint_conname,
11820  BTEqualStrategyNumber, F_NAMEEQ,
11821  CStringGetDatum(constrName));
11822  scan = systable_beginscan(conrel, ConstraintRelidTypidNameIndexId,
11823  true, NULL, 3, skey);
11824 
11825  /* There can be at most one matching row */
11826  if (!HeapTupleIsValid(tuple = systable_getnext(scan)))
11827  ereport(ERROR,
11828  (errcode(ERRCODE_UNDEFINED_OBJECT),
11829  errmsg("constraint \"%s\" of relation \"%s\" does not exist",
11830  constrName, RelationGetRelationName(rel))));
11831 
11832  con = (Form_pg_constraint) GETSTRUCT(tuple);
11833  if (con->contype != CONSTRAINT_FOREIGN &&
11834  con->contype != CONSTRAINT_CHECK)
11835  ereport(ERROR,
11836  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
11837  errmsg("constraint \"%s\" of relation \"%s\" is not a foreign key or check constraint",
11838  constrName, RelationGetRelationName(rel))));
11839 
11840  if (!con->convalidated)
11841  {
11842  AlteredTableInfo *tab;
11843  HeapTuple copyTuple;
11844  Form_pg_constraint copy_con;
11845 
11846  if (con->contype == CONSTRAINT_FOREIGN)
11847  {
11848  NewConstraint *newcon;
11849  Constraint *fkconstraint;
11850 
11851  /* Queue validation for phase 3 */
11852  fkconstraint = makeNode(Constraint);
11853  /* for now this is all we need */
11854  fkconstraint->conname = constrName;
11855 
11856  newcon = (NewConstraint *) palloc0(sizeof(NewConstraint));
11857  newcon->name = constrName;
11858  newcon->contype = CONSTR_FOREIGN;
11859  newcon->refrelid = con->confrelid;
11860  newcon->refindid = con->conindid;
11861  newcon->conid = con->oid;
11862  newcon->qual = (Node *) fkconstraint;
11863 
11864  /* Find or create work queue entry for this table */
11865  tab = ATGetQueueEntry(wqueue, rel);
11866  tab->constraints = lappend(tab->constraints, newcon);
11867 
11868  /*
11869  * We disallow creating invalid foreign keys to or from
11870  * partitioned tables, so ignoring the recursion bit is okay.
11871  */
11872  }
11873  else if (con->contype == CONSTRAINT_CHECK)
11874  {
11875  List *children = NIL;
11876  ListCell *child;
11877  NewConstraint *newcon;
11878  Datum val;
11879  char *conbin;
11880 
11881  /*
11882  * If we're recursing, the parent has already done this, so skip
11883  * it. Also, if the constraint is a NO INHERIT constraint, we
11884  * shouldn't try to look for it in the children.
11885  */
11886  if (!recursing && !con->connoinherit)
11887  children = find_all_inheritors(RelationGetRelid(rel),
11888  lockmode, NULL);
11889 
11890  /*
11891  * For CHECK constraints, we must ensure that we only mark the
11892  * constraint as validated on the parent if it's already validated
11893  * on the children.
11894  *
11895  * We recurse before validating on the parent, to reduce risk of
11896  * deadlocks.
11897  */
11898  foreach(child, children)
11899  {
11900  Oid childoid = lfirst_oid(child);
11901  Relation childrel;
11902 
11903  if (childoid == RelationGetRelid(rel))
11904  continue;
11905 
11906  /*
11907  * If we are told not to recurse, there had better not be any
11908  * child tables, because we can't mark the constraint on the
11909  * parent valid unless it is valid for all child tables.
11910  */
11911  if (!recurse)
11912  ereport(ERROR,
11913  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
11914  errmsg("constraint must be validated on child tables too")));
11915 
11916  /* find_all_inheritors already got lock */
11917  childrel = table_open(childoid, NoLock);
11918 
11919  ATExecValidateConstraint(wqueue, childrel, constrName, false,
11920  true, lockmode);
11921  table_close(childrel, NoLock);
11922  }
11923 
11924  /* Queue validation for phase 3 */
11925  newcon = (NewConstraint *) palloc0(sizeof(NewConstraint));
11926  newcon->name = constrName;
11927  newcon->contype = CONSTR_CHECK;
11928  newcon->refrelid = InvalidOid;
11929  newcon->refindid = InvalidOid;
11930  newcon->conid = con->oid;
11931 
11932  val = SysCacheGetAttrNotNull(CONSTROID, tuple,
11933  Anum_pg_constraint_conbin);
11934  conbin = TextDatumGetCString(val);
11935  newcon->qual = (Node *) stringToNode(conbin);
11936 
11937  /* Find or create work queue entry for this table */
11938  tab = ATGetQueueEntry(wqueue, rel);
11939  tab->constraints = lappend(tab->constraints, newcon);
11940 
11941  /*
11942  * Invalidate relcache so that others see the new validated
11943  * constraint.
11944  */
11946  }
11947 
11948  /*
11949  * Now update the catalog, while we have the door open.
11950  */
11951  copyTuple = heap_copytuple(tuple);
11952  copy_con = (Form_pg_constraint) GETSTRUCT(copyTuple);
11953  copy_con->convalidated = true;
11954  CatalogTupleUpdate(conrel, &copyTuple->t_self, copyTuple);
11955 
11956  InvokeObjectPostAlterHook(ConstraintRelationId, con->oid, 0);
11957 
11958  heap_freetuple(copyTuple);
11959 
11960  ObjectAddressSet(address, ConstraintRelationId, con->oid);
11961  }
11962  else
11963  address = InvalidObjectAddress; /* already validated */
11964 
11965  systable_endscan(scan);
11966 
11967  table_close(conrel, RowExclusiveLock);
11968 
11969  return address;
11970 }
11971 
11972 
11973 /*
11974  * transformColumnNameList - transform list of column names
11975  *
11976  * Lookup each name and return its attnum and, optionally, type OID
11977  *
11978  * Note: the name of this function suggests that it's general-purpose,
11979  * but actually it's only used to look up names appearing in foreign-key
11980  * clauses. The error messages would need work to use it in other cases,
11981  * and perhaps the validity checks as well.
11982  */
11983 static int
11985  int16 *attnums, Oid *atttypids)
11986 {
11987  ListCell *l;
11988  int attnum;
11989 
11990  attnum = 0;
11991  foreach(l, colList)
11992  {
11993  char *attname = strVal(lfirst(l));
11994  HeapTuple atttuple;
11995  Form_pg_attribute attform;
11996 
11997  atttuple = SearchSysCacheAttName(relId, attname);
11998  if (!HeapTupleIsValid(atttuple))
11999  ereport(ERROR,
12000  (errcode(ERRCODE_UNDEFINED_COLUMN),
12001  errmsg("column \"%s\" referenced in foreign key constraint does not exist",
12002  attname)));
12003  attform = (Form_pg_attribute) GETSTRUCT(atttuple);
12004  if (attform->attnum < 0)
12005  ereport(ERROR,
12006  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
12007  errmsg("system columns cannot be used in foreign keys")));
12008  if (attnum >= INDEX_MAX_KEYS)
12009  ereport(ERROR,
12010  (errcode(ERRCODE_TOO_MANY_COLUMNS),
12011  errmsg("cannot have more than %d keys in a foreign key",
12012  INDEX_MAX_KEYS)));
12013  attnums[attnum] = attform->attnum;
12014  if (atttypids != NULL)
12015  atttypids[attnum] = attform->atttypid;
12016  ReleaseSysCache(atttuple);
12017  attnum++;
12018  }
12019 
12020  return attnum;
12021 }
12022 
12023 /*
12024  * transformFkeyGetPrimaryKey -
12025  *
12026  * Look up the names, attnums, and types of the primary key attributes
12027  * for the pkrel. Also return the index OID and index opclasses of the
12028  * index supporting the primary key. Also return whether the index has
12029  * WITHOUT OVERLAPS.
12030  *
12031  * All parameters except pkrel are output parameters. Also, the function
12032  * return value is the number of attributes in the primary key.
12033  *
12034  * Used when the column list in the REFERENCES specification is omitted.
12035  */
12036 static int
12038  List **attnamelist,
12039  int16 *attnums, Oid *atttypids,
12040  Oid *opclasses, bool *pk_has_without_overlaps)
12041 {
12042  List *indexoidlist;
12043  ListCell *indexoidscan;
12044  HeapTuple indexTuple = NULL;
12045  Form_pg_index indexStruct = NULL;
12046  Datum indclassDatum;
12047  oidvector *indclass;
12048  int i;
12049 
12050  /*
12051  * Get the list of index OIDs for the table from the relcache, and look up
12052  * each one in the pg_index syscache until we find one marked primary key
12053  * (hopefully there isn't more than one such). Insist it's valid, too.
12054  */
12055  *indexOid = InvalidOid;
12056 
12057  indexoidlist = RelationGetIndexList(pkrel);
12058 
12059  foreach(indexoidscan, indexoidlist)
12060  {
12061  Oid indexoid = lfirst_oid(indexoidscan);
12062 
12063  indexTuple = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(indexoid));
12064  if (!HeapTupleIsValid(indexTuple))
12065  elog(ERROR, "cache lookup failed for index %u", indexoid);
12066  indexStruct = (Form_pg_index) GETSTRUCT(indexTuple);
12067  if (indexStruct->indisprimary && indexStruct->indisvalid)
12068  {
12069  /*
12070  * Refuse to use a deferrable primary key. This is per SQL spec,
12071  * and there would be a lot of interesting semantic problems if we
12072  * tried to allow it.
12073  */
12074  if (!indexStruct->indimmediate)
12075  ereport(ERROR,
12076  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
12077  errmsg("cannot use a deferrable primary key for referenced table \"%s\"",
12078  RelationGetRelationName(pkrel))));
12079 
12080  *indexOid = indexoid;
12081  break;
12082  }
12083  ReleaseSysCache(indexTuple);
12084  }
12085 
12086  list_free(indexoidlist);
12087 
12088  /*
12089  * Check that we found it
12090  */
12091  if (!OidIsValid(*indexOid))
12092  ereport(ERROR,
12093  (errcode(ERRCODE_UNDEFINED_OBJECT),
12094  errmsg("there is no primary key for referenced table \"%s\"",
12095  RelationGetRelationName(pkrel))));
12096 
12097  /* Must get indclass the hard way */
12098  indclassDatum = SysCacheGetAttrNotNull(INDEXRELID, indexTuple,
12099  Anum_pg_index_indclass);
12100  indclass = (oidvector *) DatumGetPointer(indclassDatum);
12101 
12102  /*
12103  * Now build the list of PK attributes from the indkey definition (we
12104  * assume a primary key cannot have expressional elements)
12105  */
12106  *attnamelist = NIL;
12107  for (i = 0; i < indexStruct->indnkeyatts; i++)
12108  {
12109  int pkattno = indexStruct->indkey.values[i];
12110 
12111  attnums[i] = pkattno;
12112  atttypids[i] = attnumTypeId(pkrel, pkattno);
12113  opclasses[i] = indclass->values[i];
12114  *attnamelist = lappend(*attnamelist,
12115  makeString(pstrdup(NameStr(*attnumAttName(pkrel, pkattno)))));
12116  }
12117 
12118  *pk_has_without_overlaps = indexStruct->indisexclusion;
12119 
12120  ReleaseSysCache(indexTuple);
12121 
12122  return i;
12123 }
12124 
12125 /*
12126  * transformFkeyCheckAttrs -
12127  *
12128  * Validate that the 'attnums' columns in the 'pkrel' relation are valid to
12129  * reference as part of a foreign key constraint.
12130  *
12131  * Returns the OID of the unique index supporting the constraint and
12132  * populates the caller-provided 'opclasses' array with the opclasses
12133  * associated with the index columns. Also sets whether the index
12134  * uses WITHOUT OVERLAPS.
12135  *
12136  * Raises an ERROR on validation failure.
12137  */
12138 static Oid
12140  int numattrs, int16 *attnums,
12141  bool with_period, Oid *opclasses,
12142  bool *pk_has_without_overlaps)
12143 {
12144  Oid indexoid = InvalidOid;
12145  bool found = false;
12146  bool found_deferrable = false;
12147  List *indexoidlist;
12148  ListCell *indexoidscan;
12149  int i,
12150  j;
12151 
12152  /*
12153  * Reject duplicate appearances of columns in the referenced-columns list.
12154  * Such a case is forbidden by the SQL standard, and even if we thought it
12155  * useful to allow it, there would be ambiguity about how to match the
12156  * list to unique indexes (in particular, it'd be unclear which index
12157  * opclass goes with which FK column).
12158  */
12159  for (i = 0; i < numattrs; i++)
12160  {
12161  for (j = i + 1; j < numattrs; j++)
12162  {
12163  if (attnums[i] == attnums[j])
12164  ereport(ERROR,
12165  (errcode(ERRCODE_INVALID_FOREIGN_KEY),
12166  errmsg("foreign key referenced-columns list must not contain duplicates")));
12167  }
12168  }
12169 
12170  /*
12171  * Get the list of index OIDs for the table from the relcache, and look up
12172  * each one in the pg_index syscache, and match unique indexes to the list
12173  * of attnums we are given.
12174  */
12175  indexoidlist = RelationGetIndexList(pkrel);
12176 
12177  foreach(indexoidscan, indexoidlist)
12178  {
12179  HeapTuple indexTuple;
12180  Form_pg_index indexStruct;
12181 
12182  indexoid = lfirst_oid(indexoidscan);
12183  indexTuple = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(indexoid));
12184  if (!HeapTupleIsValid(indexTuple))
12185  elog(ERROR, "cache lookup failed for index %u", indexoid);
12186  indexStruct = (Form_pg_index) GETSTRUCT(indexTuple);
12187 
12188  /*
12189  * Must have the right number of columns; must be unique (or if
12190  * temporal then exclusion instead) and not a partial index; forget it
12191  * if there are any expressions, too. Invalid indexes are out as well.
12192  */
12193  if (indexStruct->indnkeyatts == numattrs &&
12194  (with_period ? indexStruct->indisexclusion : indexStruct->indisunique) &&
12195  indexStruct->indisvalid &&
12196  heap_attisnull(indexTuple, Anum_pg_index_indpred, NULL) &&
12197  heap_attisnull(indexTuple, Anum_pg_index_indexprs, NULL))
12198  {
12199  Datum indclassDatum;
12200  oidvector *indclass;
12201 
12202  /* Must get indclass the hard way */
12203  indclassDatum = SysCacheGetAttrNotNull(INDEXRELID, indexTuple,
12204  Anum_pg_index_indclass);
12205  indclass = (oidvector *) DatumGetPointer(indclassDatum);
12206 
12207  /*
12208  * The given attnum list may match the index columns in any order.
12209  * Check for a match, and extract the appropriate opclasses while
12210  * we're at it.
12211  *
12212  * We know that attnums[] is duplicate-free per the test at the
12213  * start of this function, and we checked above that the number of
12214  * index columns agrees, so if we find a match for each attnums[]
12215  * entry then we must have a one-to-one match in some order.
12216  */
12217  for (i = 0; i < numattrs; i++)
12218  {
12219  found = false;
12220  for (j = 0; j < numattrs; j++)
12221  {
12222  if (attnums[i] == indexStruct->indkey.values[j])
12223  {
12224  opclasses[i] = indclass->values[j];
12225  found = true;
12226  break;
12227  }
12228  }
12229  if (!found)
12230  break;
12231  }
12232  /* The last attribute in the index must be the PERIOD FK part */
12233  if (found && with_period)
12234  {
12235  int16 periodattnum = attnums[numattrs - 1];
12236 
12237  found = (periodattnum == indexStruct->indkey.values[numattrs - 1]);
12238  }
12239 
12240  /*
12241  * Refuse to use a deferrable unique/primary key. This is per SQL
12242  * spec, and there would be a lot of interesting semantic problems
12243  * if we tried to allow it.
12244  */
12245  if (found && !indexStruct->indimmediate)
12246  {
12247  /*
12248  * Remember that we found an otherwise matching index, so that
12249  * we can generate a more appropriate error message.
12250  */
12251  found_deferrable = true;
12252  found = false;
12253  }
12254 
12255  /* We need to know whether the index has WITHOUT OVERLAPS */
12256  if (found)
12257  *pk_has_without_overlaps = indexStruct->indisexclusion;
12258  }
12259  ReleaseSysCache(indexTuple);
12260  if (found)
12261  break;
12262  }
12263 
12264  if (!found)
12265  {
12266  if (found_deferrable)
12267  ereport(ERROR,
12268  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
12269  errmsg("cannot use a deferrable unique constraint for referenced table \"%s\"",
12270  RelationGetRelationName(pkrel))));
12271  else
12272  ereport(ERROR,
12273  (errcode(ERRCODE_INVALID_FOREIGN_KEY),
12274  errmsg("there is no unique constraint matching given keys for referenced table \"%s\"",
12275  RelationGetRelationName(pkrel))));
12276  }
12277 
12278  list_free(indexoidlist);
12279 
12280  return indexoid;
12281 }
12282 
12283 /*
12284  * findFkeyCast -
12285  *
12286  * Wrapper around find_coercion_pathway() for ATAddForeignKeyConstraint().
12287  * Caller has equal regard for binary coercibility and for an exact match.
12288 */
12289 static CoercionPathType
12290 findFkeyCast(Oid targetTypeId, Oid sourceTypeId, Oid *funcid)
12291 {
12292  CoercionPathType ret;
12293 
12294  if (targetTypeId == sourceTypeId)
12295  {
12297  *funcid = InvalidOid;
12298  }
12299  else
12300  {
12301  ret = find_coercion_pathway(targetTypeId, sourceTypeId,
12302  COERCION_IMPLICIT, funcid);
12303  if (ret == COERCION_PATH_NONE)
12304  /* A previously-relied-upon cast is now gone. */
12305  elog(ERROR, "could not find cast from %u to %u",
12306  sourceTypeId, targetTypeId);
12307  }
12308 
12309  return ret;
12310 }
12311 
12312 /*
12313  * Permissions checks on the referenced table for ADD FOREIGN KEY
12314  *
12315  * Note: we have already checked that the user owns the referencing table,
12316  * else we'd have failed much earlier; no additional checks are needed for it.
12317  */
12318 static void
12319 checkFkeyPermissions(Relation rel, int16 *attnums, int natts)
12320 {
12321  Oid roleid = GetUserId();
12322  AclResult aclresult;
12323  int i;
12324 
12325  /* Okay if we have relation-level REFERENCES permission */
12326  aclresult = pg_class_aclcheck(RelationGetRelid(rel), roleid,
12327  ACL_REFERENCES);
12328  if (aclresult == ACLCHECK_OK)
12329  return;
12330  /* Else we must have REFERENCES on each column */
12331  for (i = 0; i < natts; i++)
12332  {
12333  aclresult = pg_attribute_aclcheck(RelationGetRelid(rel), attnums[i],
12334  roleid, ACL_REFERENCES);
12335  if (aclresult != ACLCHECK_OK)
12336  aclcheck_error(aclresult, get_relkind_objtype(rel->rd_rel->relkind),
12338  }
12339 }
12340 
12341 /*
12342  * Scan the existing rows in a table to verify they meet a proposed FK
12343  * constraint.
12344  *
12345  * Caller must have opened and locked both relations appropriately.
12346  */
12347 static void
12349  Relation rel,
12350  Relation pkrel,
12351  Oid pkindOid,
12352  Oid constraintOid,
12353  bool hasperiod)
12354 {
12355  TupleTableSlot *slot;
12356  TableScanDesc scan;
12357  Trigger trig = {0};
12358  Snapshot snapshot;
12359  MemoryContext oldcxt;
12360  MemoryContext perTupCxt;
12361 
12362  ereport(DEBUG1,
12363  (errmsg_internal("validating foreign key constraint \"%s\"", conname)));
12364 
12365  /*
12366  * Build a trigger call structure; we'll need it either way.
12367  */
12368  trig.tgoid = InvalidOid;
12369  trig.tgname = conname;
12371  trig.tgisinternal = true;
12372  trig.tgconstrrelid = RelationGetRelid(pkrel);
12373  trig.tgconstrindid = pkindOid;
12374  trig.tgconstraint = constraintOid;
12375  trig.tgdeferrable = false;
12376  trig.tginitdeferred = false;
12377  /* we needn't fill in remaining fields */
12378 
12379  /*
12380  * See if we can do it with a single LEFT JOIN query. A false result
12381  * indicates we must proceed with the fire-the-trigger method. We can't do
12382  * a LEFT JOIN for temporal FKs yet, but we can once we support temporal
12383  * left joins.
12384  */
12385  if (!hasperiod && RI_Initial_Check(&trig, rel, pkrel))
12386  return;
12387 
12388  /*
12389  * Scan through each tuple, calling RI_FKey_check_ins (insert trigger) as
12390  * if that tuple had just been inserted. If any of those fail, it should
12391  * ereport(ERROR) and that's that.
12392  */
12393  snapshot = RegisterSnapshot(GetLatestSnapshot());
12394  slot = table_slot_create(rel, NULL);
12395  scan = table_beginscan(rel, snapshot, 0, NULL);
12396 
12398  "validateForeignKeyConstraint",
12400  oldcxt = MemoryContextSwitchTo(perTupCxt);
12401 
12402  while (table_scan_getnextslot(scan, ForwardScanDirection, slot))
12403  {
12404  LOCAL_FCINFO(fcinfo, 0);
12405  TriggerData trigdata = {0};
12406 
12408 
12409  /*
12410  * Make a call to the trigger function
12411  *
12412  * No parameters are passed, but we do set a context
12413  */
12414  MemSet(fcinfo, 0, SizeForFunctionCallInfo(0));
12415 
12416  /*
12417  * We assume RI_FKey_check_ins won't look at flinfo...
12418  */
12419  trigdata.type = T_TriggerData;
12421  trigdata.tg_relation = rel;
12422  trigdata.tg_trigtuple = ExecFetchSlotHeapTuple(slot, false, NULL);
12423  trigdata.tg_trigslot = slot;
12424  trigdata.tg_trigger = &trig;
12425 
12426  fcinfo->context = (Node *) &trigdata;
12427 
12428  RI_FKey_check_ins(fcinfo);
12429 
12430  MemoryContextReset(perTupCxt);
12431  }
12432 
12433  MemoryContextSwitchTo(oldcxt);
12434  MemoryContextDelete(perTupCxt);
12435  table_endscan(scan);
12436  UnregisterSnapshot(snapshot);
12438 }
12439 
12440 /*
12441  * CreateFKCheckTrigger
12442  * Creates the insert (on_insert=true) or update "check" trigger that
12443  * implements a given foreign key
12444  *
12445  * Returns the OID of the so created trigger.
12446  */
12447 static Oid
12448 CreateFKCheckTrigger(Oid myRelOid, Oid refRelOid, Constraint *fkconstraint,
12449  Oid constraintOid, Oid indexOid, Oid parentTrigOid,
12450  bool on_insert)
12451 {
12452  ObjectAddress trigAddress;
12453  CreateTrigStmt *fk_trigger;
12454 
12455  /*
12456  * Note: for a self-referential FK (referencing and referenced tables are
12457  * the same), it is important that the ON UPDATE action fires before the
12458  * CHECK action, since both triggers will fire on the same row during an
12459  * UPDATE event; otherwise the CHECK trigger will be checking a non-final
12460  * state of the row. Triggers fire in name order, so we ensure this by
12461  * using names like "RI_ConstraintTrigger_a_NNNN" for the action triggers
12462  * and "RI_ConstraintTrigger_c_NNNN" for the check triggers.
12463  */
12464  fk_trigger = makeNode(CreateTrigStmt);
12465  fk_trigger->replace = false;
12466  fk_trigger->isconstraint = true;
12467  fk_trigger->trigname = "RI_ConstraintTrigger_c";
12468  fk_trigger->relation = NULL;
12469 
12470  /* Either ON INSERT or ON UPDATE */
12471  if (on_insert)
12472  {
12473  fk_trigger->funcname = SystemFuncName("RI_FKey_check_ins");
12474  fk_trigger->events = TRIGGER_TYPE_INSERT;
12475  }
12476  else
12477  {
12478  fk_trigger->funcname = SystemFuncName("RI_FKey_check_upd");
12479  fk_trigger->events = TRIGGER_TYPE_UPDATE;
12480  }
12481 
12482  fk_trigger->args = NIL;
12483  fk_trigger->row = true;
12484  fk_trigger->timing = TRIGGER_TYPE_AFTER;
12485  fk_trigger->columns = NIL;
12486  fk_trigger->whenClause = NULL;
12487  fk_trigger->transitionRels = NIL;
12488  fk_trigger->deferrable = fkconstraint->deferrable;
12489  fk_trigger->initdeferred = fkconstraint->initdeferred;
12490  fk_trigger->constrrel = NULL;
12491 
12492  trigAddress = CreateTrigger(fk_trigger, NULL, myRelOid, refRelOid,
12493  constraintOid, indexOid, InvalidOid,
12494  parentTrigOid, NULL, true, false);
12495 
12496  /* Make changes-so-far visible */
12498 
12499  return trigAddress.objectId;
12500 }
12501 
12502 /*
12503  * createForeignKeyActionTriggers
12504  * Create the referenced-side "action" triggers that implement a foreign
12505  * key.
12506  *
12507  * Returns the OIDs of the so created triggers in *deleteTrigOid and
12508  * *updateTrigOid.
12509  */
12510 static void
12512  Oid constraintOid, Oid indexOid,
12513  Oid parentDelTrigger, Oid parentUpdTrigger,
12514  Oid *deleteTrigOid, Oid *updateTrigOid)
12515 {
12516  CreateTrigStmt *fk_trigger;
12517  ObjectAddress trigAddress;
12518 
12519  /*
12520  * Build and execute a CREATE CONSTRAINT TRIGGER statement for the ON
12521  * DELETE action on the referenced table.
12522  */
12523  fk_trigger = makeNode(CreateTrigStmt);
12524  fk_trigger->replace = false;
12525  fk_trigger->isconstraint = true;
12526  fk_trigger->trigname = "RI_ConstraintTrigger_a";
12527  fk_trigger->relation = NULL;
12528  fk_trigger->args = NIL;
12529  fk_trigger->row = true;
12530  fk_trigger->timing = TRIGGER_TYPE_AFTER;
12531  fk_trigger->events = TRIGGER_TYPE_DELETE;
12532  fk_trigger->columns = NIL;
12533  fk_trigger->whenClause = NULL;
12534  fk_trigger->transitionRels = NIL;
12535  fk_trigger->constrrel = NULL;
12536 
12537  switch (fkconstraint->fk_del_action)
12538  {
12540  fk_trigger->deferrable = fkconstraint->deferrable;
12541  fk_trigger->initdeferred = fkconstraint->initdeferred;
12542  fk_trigger->funcname = SystemFuncName("RI_FKey_noaction_del");
12543  break;
12545  fk_trigger->deferrable = false;
12546  fk_trigger->initdeferred = false;
12547  fk_trigger->funcname = SystemFuncName("RI_FKey_restrict_del");
12548  break;
12550  fk_trigger->deferrable = false;
12551  fk_trigger->initdeferred = false;
12552  fk_trigger->funcname = SystemFuncName("RI_FKey_cascade_del");
12553  break;
12555  fk_trigger->deferrable = false;
12556  fk_trigger->initdeferred = false;
12557  fk_trigger->funcname = SystemFuncName("RI_FKey_setnull_del");
12558  break;
12560  fk_trigger->deferrable = false;
12561  fk_trigger->initdeferred = false;
12562  fk_trigger->funcname = SystemFuncName("RI_FKey_setdefault_del");
12563  break;
12564  default:
12565  elog(ERROR, "unrecognized FK action type: %d",
12566  (int) fkconstraint->fk_del_action);
12567  break;
12568  }
12569 
12570  trigAddress = CreateTrigger(fk_trigger, NULL, refRelOid,
12571  RelationGetRelid(rel),
12572  constraintOid, indexOid, InvalidOid,
12573  parentDelTrigger, NULL, true, false);
12574  if (deleteTrigOid)
12575  *deleteTrigOid = trigAddress.objectId;
12576 
12577  /* Make changes-so-far visible */
12579 
12580  /*
12581  * Build and execute a CREATE CONSTRAINT TRIGGER statement for the ON
12582  * UPDATE action on the referenced table.
12583  */
12584  fk_trigger = makeNode(CreateTrigStmt);
12585  fk_trigger->replace = false;
12586  fk_trigger->isconstraint = true;
12587  fk_trigger->trigname = "RI_ConstraintTrigger_a";
12588  fk_trigger->relation = NULL;
12589  fk_trigger->args = NIL;
12590  fk_trigger->row = true;
12591  fk_trigger->timing = TRIGGER_TYPE_AFTER;
12592  fk_trigger->events = TRIGGER_TYPE_UPDATE;
12593  fk_trigger->columns = NIL;
12594  fk_trigger->whenClause = NULL;
12595  fk_trigger->transitionRels = NIL;
12596  fk_trigger->constrrel = NULL;
12597 
12598  switch (fkconstraint->fk_upd_action)
12599  {
12601  fk_trigger->deferrable = fkconstraint->deferrable;
12602  fk_trigger->initdeferred = fkconstraint->initdeferred;
12603  fk_trigger->funcname = SystemFuncName("RI_FKey_noaction_upd");
12604  break;
12606  fk_trigger->deferrable = false;
12607  fk_trigger->initdeferred = false;
12608  fk_trigger->funcname = SystemFuncName("RI_FKey_restrict_upd");
12609  break;
12611  fk_trigger->deferrable = false;
12612  fk_trigger->initdeferred = false;
12613  fk_trigger->funcname = SystemFuncName("RI_FKey_cascade_upd");
12614  break;
12616  fk_trigger->deferrable = false;
12617  fk_trigger->initdeferred = false;
12618  fk_trigger->funcname = SystemFuncName("RI_FKey_setnull_upd");
12619  break;
12621  fk_trigger->deferrable = false;
12622  fk_trigger->initdeferred = false;
12623  fk_trigger->funcname = SystemFuncName("RI_FKey_setdefault_upd");
12624  break;
12625  default:
12626  elog(ERROR, "unrecognized FK action type: %d",
12627  (int) fkconstraint->fk_upd_action);
12628  break;
12629  }
12630 
12631  trigAddress = CreateTrigger(fk_trigger, NULL, refRelOid,
12632  RelationGetRelid(rel),
12633  constraintOid, indexOid, InvalidOid,
12634  parentUpdTrigger, NULL, true, false);
12635  if (updateTrigOid)
12636  *updateTrigOid = trigAddress.objectId;
12637 }
12638 
12639 /*
12640  * createForeignKeyCheckTriggers
12641  * Create the referencing-side "check" triggers that implement a foreign
12642  * key.
12643  *
12644  * Returns the OIDs of the so created triggers in *insertTrigOid and
12645  * *updateTrigOid.
12646  */
12647 static void
12649  Constraint *fkconstraint, Oid constraintOid,
12650  Oid indexOid,
12651  Oid parentInsTrigger, Oid parentUpdTrigger,
12652  Oid *insertTrigOid, Oid *updateTrigOid)
12653 {
12654  *insertTrigOid = CreateFKCheckTrigger(myRelOid, refRelOid, fkconstraint,
12655  constraintOid, indexOid,
12656  parentInsTrigger, true);
12657  *updateTrigOid = CreateFKCheckTrigger(myRelOid, refRelOid, fkconstraint,
12658  constraintOid, indexOid,
12659  parentUpdTrigger, false);
12660 }
12661 
12662 /*
12663  * ALTER TABLE DROP CONSTRAINT
12664  *
12665  * Like DROP COLUMN, we can't use the normal ALTER TABLE recursion mechanism.
12666  */
12667 static void
12668 ATExecDropConstraint(Relation rel, const char *constrName,
12669  DropBehavior behavior,
12670  bool recurse, bool recursing,
12671  bool missing_ok, LOCKMODE lockmode)
12672 {
12673  List *children;
12674  Relation conrel;
12675  Form_pg_constraint con;
12676  SysScanDesc scan;
12677  ScanKeyData skey[3];
12678  HeapTuple tuple;
12679  bool found = false;
12680  bool is_no_inherit_constraint = false;
12681  char contype;
12682 
12683  /* At top level, permission check was done in ATPrepCmd, else do it */
12684  if (recursing)
12687 
12688  conrel = table_open(ConstraintRelationId, RowExclusiveLock);
12689 
12690  /*
12691  * Find and drop the target constraint
12692  */
12693  ScanKeyInit(&skey[0],
12694  Anum_pg_constraint_conrelid,
12695  BTEqualStrategyNumber, F_OIDEQ,
12697  ScanKeyInit(&skey[1],
12698  Anum_pg_constraint_contypid,
12699  BTEqualStrategyNumber, F_OIDEQ,
12701  ScanKeyInit(&skey[2],
12702  Anum_pg_constraint_conname,
12703  BTEqualStrategyNumber, F_NAMEEQ,
12704  CStringGetDatum(constrName));
12705  scan = systable_beginscan(conrel, ConstraintRelidTypidNameIndexId,
12706  true, NULL, 3, skey);
12707 
12708  /* There can be at most one matching row */
12709  if (HeapTupleIsValid(tuple = systable_getnext(scan)))
12710  {
12711  ObjectAddress conobj;
12712 
12713  con = (Form_pg_constraint) GETSTRUCT(tuple);
12714 
12715  /* Don't drop inherited constraints */
12716  if (con->coninhcount > 0 && !recursing)
12717  ereport(ERROR,
12718  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
12719  errmsg("cannot drop inherited constraint \"%s\" of relation \"%s\"",
12720  constrName, RelationGetRelationName(rel))));
12721 
12722  is_no_inherit_constraint = con->connoinherit;
12723  contype = con->contype;
12724 
12725  /*
12726  * If it's a foreign-key constraint, we'd better lock the referenced
12727  * table and check that that's not in use, just as we've already done
12728  * for the constrained table (else we might, eg, be dropping a trigger
12729  * that has unfired events). But we can/must skip that in the
12730  * self-referential case.
12731  */
12732  if (contype == CONSTRAINT_FOREIGN &&
12733  con->confrelid != RelationGetRelid(rel))
12734  {
12735  Relation frel;
12736 
12737  /* Must match lock taken by RemoveTriggerById: */
12738  frel = table_open(con->confrelid, AccessExclusiveLock);
12739  CheckAlterTableIsSafe(frel);
12740  table_close(frel, NoLock);
12741  }
12742 
12743  /*
12744  * Perform the actual constraint deletion
12745  */
12746  conobj.classId = ConstraintRelationId;
12747  conobj.objectId = con->oid;
12748  conobj.objectSubId = 0;
12749 
12750  performDeletion(&conobj, behavior, 0);
12751 
12752  found = true;
12753  }
12754 
12755  systable_endscan(scan);
12756 
12757  if (!found)
12758  {
12759  if (!missing_ok)
12760  {
12761  ereport(ERROR,
12762  (errcode(ERRCODE_UNDEFINED_OBJECT),
12763  errmsg("constraint \"%s\" of relation \"%s\" does not exist",
12764  constrName, RelationGetRelationName(rel))));
12765  }
12766  else
12767  {
12768  ereport(NOTICE,
12769  (errmsg("constraint \"%s\" of relation \"%s\" does not exist, skipping",
12770  constrName, RelationGetRelationName(rel))));
12771  table_close(conrel, RowExclusiveLock);
12772  return;
12773  }
12774  }
12775 
12776  /*
12777  * For partitioned tables, non-CHECK inherited constraints are dropped via
12778  * the dependency mechanism, so we're done here.
12779  */
12780  if (contype != CONSTRAINT_CHECK &&
12781  rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
12782  {
12783  table_close(conrel, RowExclusiveLock);
12784  return;
12785  }
12786 
12787  /*
12788  * Propagate to children as appropriate. Unlike most other ALTER
12789  * routines, we have to do this one level of recursion at a time; we can't
12790  * use find_all_inheritors to do it in one pass.
12791  */
12792  if (!is_no_inherit_constraint)
12793  children = find_inheritance_children(RelationGetRelid(rel), lockmode);
12794  else
12795  children = NIL;
12796 
12797  foreach_oid(childrelid, children)
12798  {
12799  Relation childrel;
12800  HeapTuple copy_tuple;
12801 
12802  /* find_inheritance_children already got lock */
12803  childrel = table_open(childrelid, NoLock);
12804  CheckAlterTableIsSafe(childrel);
12805 
12806  ScanKeyInit(&skey[0],
12807  Anum_pg_constraint_conrelid,
12808  BTEqualStrategyNumber, F_OIDEQ,
12809  ObjectIdGetDatum(childrelid));
12810  ScanKeyInit(&skey[1],
12811  Anum_pg_constraint_contypid,
12812  BTEqualStrategyNumber, F_OIDEQ,
12814  ScanKeyInit(&skey[2],
12815  Anum_pg_constraint_conname,
12816  BTEqualStrategyNumber, F_NAMEEQ,
12817  CStringGetDatum(constrName));
12818  scan = systable_beginscan(conrel, ConstraintRelidTypidNameIndexId,
12819  true, NULL, 3, skey);
12820 
12821  /* There can be at most one matching row */
12822  if (!HeapTupleIsValid(tuple = systable_getnext(scan)))
12823  ereport(ERROR,
12824  (errcode(ERRCODE_UNDEFINED_OBJECT),
12825  errmsg("constraint \"%s\" of relation \"%s\" does not exist",
12826  constrName,
12827  RelationGetRelationName(childrel))));
12828 
12829  copy_tuple = heap_copytuple(tuple);
12830 
12831  systable_endscan(scan);
12832 
12833  con = (Form_pg_constraint) GETSTRUCT(copy_tuple);
12834 
12835  /* Right now only CHECK constraints can be inherited */
12836  if (con->contype != CONSTRAINT_CHECK)
12837  elog(ERROR, "inherited constraint is not a CHECK constraint");
12838 
12839  if (con->coninhcount <= 0) /* shouldn't happen */
12840  elog(ERROR, "relation %u has non-inherited constraint \"%s\"",
12841  childrelid, constrName);
12842 
12843  if (recurse)
12844  {
12845  /*
12846  * If the child constraint has other definition sources, just
12847  * decrement its inheritance count; if not, recurse to delete it.
12848  */
12849  if (con->coninhcount == 1 && !con->conislocal)
12850  {
12851  /* Time to delete this child constraint, too */
12852  ATExecDropConstraint(childrel, constrName, behavior,
12853  true, true,
12854  false, lockmode);
12855  }
12856  else
12857  {
12858  /* Child constraint must survive my deletion */
12859  con->coninhcount--;
12860  CatalogTupleUpdate(conrel, &copy_tuple->t_self, copy_tuple);
12861 
12862  /* Make update visible */
12864  }
12865  }
12866  else
12867  {
12868  /*
12869  * If we were told to drop ONLY in this table (no recursion), we
12870  * need to mark the inheritors' constraints as locally defined
12871  * rather than inherited.
12872  */
12873  con->coninhcount--;
12874  con->conislocal = true;
12875 
12876  CatalogTupleUpdate(conrel, &copy_tuple->t_self, copy_tuple);
12877 
12878  /* Make update visible */
12880  }
12881 
12882  heap_freetuple(copy_tuple);
12883 
12884  table_close(childrel, NoLock);
12885  }
12886 
12887  table_close(conrel, RowExclusiveLock);
12888 }
12889 
12890 /*
12891  * ALTER COLUMN TYPE
12892  *
12893  * Unlike other subcommand types, we do parse transformation for ALTER COLUMN
12894  * TYPE during phase 1 --- the AlterTableCmd passed in here is already
12895  * transformed (and must be, because we rely on some transformed fields).
12896  *
12897  * The point of this is that the execution of all ALTER COLUMN TYPEs for a
12898  * table will be done "in parallel" during phase 3, so all the USING
12899  * expressions should be parsed assuming the original column types. Also,
12900  * this allows a USING expression to refer to a field that will be dropped.
12901  *
12902  * To make this work safely, AT_PASS_DROP then AT_PASS_ALTER_TYPE must be
12903  * the first two execution steps in phase 2; they must not see the effects
12904  * of any other subcommand types, since the USING expressions are parsed
12905  * against the unmodified table's state.
12906  */
12907 static void
12909  AlteredTableInfo *tab, Relation rel,
12910  bool recurse, bool recursing,
12911  AlterTableCmd *cmd, LOCKMODE lockmode,
12913 {
12914  char *colName = cmd->name;
12915  ColumnDef *def = (ColumnDef *) cmd->def;
12916  TypeName *typeName = def->typeName;
12917  Node *transform = def->cooked_default;
12918  HeapTuple tuple;
12919  Form_pg_attribute attTup;
12921  Oid targettype;
12922  int32 targettypmod;
12923  Oid targetcollid;
12925  ParseState *pstate = make_parsestate(NULL);
12926  AclResult aclresult;
12927  bool is_expr;
12928 
12929  if (rel->rd_rel->reloftype && !recursing)
12930  ereport(ERROR,
12931  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
12932  errmsg("cannot alter column type of typed table")));
12933 
12934  /* lookup the attribute so we can check inheritance status */
12935  tuple = SearchSysCacheAttName(RelationGetRelid(rel), colName);
12936  if (!HeapTupleIsValid(tuple))
12937  ereport(ERROR,
12938  (errcode(ERRCODE_UNDEFINED_COLUMN),
12939  errmsg("column \"%s\" of relation \"%s\" does not exist",
12940  colName, RelationGetRelationName(rel))));
12941  attTup = (Form_pg_attribute) GETSTRUCT(tuple);
12942  attnum = attTup->attnum;
12943 
12944  /* Can't alter a system attribute */
12945  if (attnum <= 0)
12946  ereport(ERROR,
12947  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
12948  errmsg("cannot alter system column \"%s\"",
12949  colName)));
12950 
12951  /*
12952  * Cannot specify USING when altering type of a generated column, because
12953  * that would violate the generation expression.
12954  */
12955  if (attTup->attgenerated && def->cooked_default)
12956  ereport(ERROR,
12957  (errcode(ERRCODE_INVALID_COLUMN_DEFINITION),
12958  errmsg("cannot specify USING when altering type of generated column"),
12959  errdetail("Column \"%s\" is a generated column.", colName)));
12960 
12961  /*
12962  * Don't alter inherited columns. At outer level, there had better not be
12963  * any inherited definition; when recursing, we assume this was checked at
12964  * the parent level (see below).
12965  */
12966  if (attTup->attinhcount > 0 && !recursing)
12967  ereport(ERROR,
12968  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
12969  errmsg("cannot alter inherited column \"%s\"",
12970  colName)));
12971 
12972  /* Don't alter columns used in the partition key */
12973  if (has_partition_attrs(rel,
12975  &is_expr))
12976  ereport(ERROR,
12977  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
12978  errmsg("cannot alter column \"%s\" because it is part of the partition key of relation \"%s\"",
12979  colName, RelationGetRelationName(rel))));
12980 
12981  /* Look up the target type */
12982  typenameTypeIdAndMod(NULL, typeName, &targettype, &targettypmod);
12983 
12984  aclresult = object_aclcheck(TypeRelationId, targettype, GetUserId(), ACL_USAGE);
12985  if (aclresult != ACLCHECK_OK)
12986  aclcheck_error_type(aclresult, targettype);
12987 
12988  /* And the collation */
12989  targetcollid = GetColumnDefCollation(NULL, def, targettype);
12990 
12991  /* make sure datatype is legal for a column */
12992  CheckAttributeType(colName, targettype, targetcollid,
12993  list_make1_oid(rel->rd_rel->reltype),
12994  0);
12995 
12996  if (tab->relkind == RELKIND_RELATION ||
12997  tab->relkind == RELKIND_PARTITIONED_TABLE)
12998  {
12999  /*
13000  * Set up an expression to transform the old data value to the new
13001  * type. If a USING option was given, use the expression as
13002  * transformed by transformAlterTableStmt, else just take the old
13003  * value and try to coerce it. We do this first so that type
13004  * incompatibility can be detected before we waste effort, and because
13005  * we need the expression to be parsed against the original table row
13006  * type.
13007  */
13008  if (!transform)
13009  {
13010  transform = (Node *) makeVar(1, attnum,
13011  attTup->atttypid, attTup->atttypmod,
13012  attTup->attcollation,
13013  0);
13014  }
13015 
13016  transform = coerce_to_target_type(pstate,
13017  transform, exprType(transform),
13018  targettype, targettypmod,
13021  -1);
13022  if (transform == NULL)
13023  {
13024  /* error text depends on whether USING was specified or not */
13025  if (def->cooked_default != NULL)
13026  ereport(ERROR,
13027  (errcode(ERRCODE_DATATYPE_MISMATCH),
13028  errmsg("result of USING clause for column \"%s\""
13029  " cannot be cast automatically to type %s",
13030  colName, format_type_be(targettype)),
13031  errhint("You might need to add an explicit cast.")));
13032  else
13033  ereport(ERROR,
13034  (errcode(ERRCODE_DATATYPE_MISMATCH),
13035  errmsg("column \"%s\" cannot be cast automatically to type %s",
13036  colName, format_type_be(targettype)),
13037  !attTup->attgenerated ?
13038  /* translator: USING is SQL, don't translate it */
13039  errhint("You might need to specify \"USING %s::%s\".",
13040  quote_identifier(colName),
13041  format_type_with_typemod(targettype,
13042  targettypmod)) : 0));
13043  }
13044 
13045  /* Fix collations after all else */
13046  assign_expr_collations(pstate, transform);
13047 
13048  /* Plan the expr now so we can accurately assess the need to rewrite. */
13049  transform = (Node *) expression_planner((Expr *) transform);
13050 
13051  /*
13052  * Add a work queue item to make ATRewriteTable update the column
13053  * contents.
13054  */
13056  newval->attnum = attnum;
13057  newval->expr = (Expr *) transform;
13058  newval->is_generated = false;
13059 
13060  tab->newvals = lappend(tab->newvals, newval);
13061  if (ATColumnChangeRequiresRewrite(transform, attnum))
13063  }
13064  else if (transform)
13065  ereport(ERROR,
13066  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
13067  errmsg("\"%s\" is not a table",
13068  RelationGetRelationName(rel))));
13069 
13070  if (!RELKIND_HAS_STORAGE(tab->relkind))
13071  {
13072  /*
13073  * For relations without storage, do this check now. Regular tables
13074  * will check it later when the table is being rewritten.
13075  */
13076  find_composite_type_dependencies(rel->rd_rel->reltype, rel, NULL);
13077  }
13078 
13079  ReleaseSysCache(tuple);
13080 
13081  /*
13082  * Recurse manually by queueing a new command for each child, if
13083  * necessary. We cannot apply ATSimpleRecursion here because we need to
13084  * remap attribute numbers in the USING expression, if any.
13085  *
13086  * If we are told not to recurse, there had better not be any child
13087  * tables; else the alter would put them out of step.
13088  */
13089  if (recurse)
13090  {
13091  Oid relid = RelationGetRelid(rel);
13092  List *child_oids,
13093  *child_numparents;
13094  ListCell *lo,
13095  *li;
13096 
13097  child_oids = find_all_inheritors(relid, lockmode,
13098  &child_numparents);
13099 
13100  /*
13101  * find_all_inheritors does the recursive search of the inheritance
13102  * hierarchy, so all we have to do is process all of the relids in the
13103  * list that it returns.
13104  */
13105  forboth(lo, child_oids, li, child_numparents)
13106  {
13107  Oid childrelid = lfirst_oid(lo);
13108  int numparents = lfirst_int(li);
13109  Relation childrel;
13110  HeapTuple childtuple;
13111  Form_pg_attribute childattTup;
13112 
13113  if (childrelid == relid)
13114  continue;
13115 
13116  /* find_all_inheritors already got lock */
13117  childrel = relation_open(childrelid, NoLock);
13118  CheckAlterTableIsSafe(childrel);
13119 
13120  /*
13121  * Verify that the child doesn't have any inherited definitions of
13122  * this column that came from outside this inheritance hierarchy.
13123  * (renameatt makes a similar test, though in a different way
13124  * because of its different recursion mechanism.)
13125  */
13126  childtuple = SearchSysCacheAttName(RelationGetRelid(childrel),
13127  colName);
13128  if (!HeapTupleIsValid(childtuple))
13129  ereport(ERROR,
13130  (errcode(ERRCODE_UNDEFINED_COLUMN),
13131  errmsg("column \"%s\" of relation \"%s\" does not exist",
13132  colName, RelationGetRelationName(childrel))));
13133  childattTup = (Form_pg_attribute) GETSTRUCT(childtuple);
13134 
13135  if (childattTup->attinhcount > numparents)
13136  ereport(ERROR,
13137  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
13138  errmsg("cannot alter inherited column \"%s\" of relation \"%s\"",
13139  colName, RelationGetRelationName(childrel))));
13140 
13141  ReleaseSysCache(childtuple);
13142 
13143  /*
13144  * Remap the attribute numbers. If no USING expression was
13145  * specified, there is no need for this step.
13146  */
13147  if (def->cooked_default)
13148  {
13149  AttrMap *attmap;
13150  bool found_whole_row;
13151 
13152  /* create a copy to scribble on */
13153  cmd = copyObject(cmd);
13154 
13155  attmap = build_attrmap_by_name(RelationGetDescr(childrel),
13156  RelationGetDescr(rel),
13157  false);
13158  ((ColumnDef *) cmd->def)->cooked_default =
13160  1, 0,
13161  attmap,
13162  InvalidOid, &found_whole_row);
13163  if (found_whole_row)
13164  ereport(ERROR,
13165  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
13166  errmsg("cannot convert whole-row table reference"),
13167  errdetail("USING expression contains a whole-row table reference.")));
13168  pfree(attmap);
13169  }
13170  ATPrepCmd(wqueue, childrel, cmd, false, true, lockmode, context);
13171  relation_close(childrel, NoLock);
13172  }
13173  }
13174  else if (!recursing &&
13176  ereport(ERROR,
13177  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
13178  errmsg("type of inherited column \"%s\" must be changed in child tables too",
13179  colName)));
13180 
13181  if (tab->relkind == RELKIND_COMPOSITE_TYPE)
13182  ATTypedTableRecursion(wqueue, rel, cmd, lockmode, context);
13183 }
13184 
13185 /*
13186  * When the data type of a column is changed, a rewrite might not be required
13187  * if the new type is sufficiently identical to the old one, and the USING
13188  * clause isn't trying to insert some other value. It's safe to skip the
13189  * rewrite in these cases:
13190  *
13191  * - the old type is binary coercible to the new type
13192  * - the new type is an unconstrained domain over the old type
13193  * - {NEW,OLD} or {OLD,NEW} is {timestamptz,timestamp} and the timezone is UTC
13194  *
13195  * In the case of a constrained domain, we could get by with scanning the
13196  * table and checking the constraint rather than actually rewriting it, but we
13197  * don't currently try to do that.
13198  */
13199 static bool
13201 {
13202  Assert(expr != NULL);
13203 
13204  for (;;)
13205  {
13206  /* only one varno, so no need to check that */
13207  if (IsA(expr, Var) && ((Var *) expr)->varattno == varattno)
13208  return false;
13209  else if (IsA(expr, RelabelType))
13210  expr = (Node *) ((RelabelType *) expr)->arg;
13211  else if (IsA(expr, CoerceToDomain))
13212  {
13213  CoerceToDomain *d = (CoerceToDomain *) expr;
13214 
13216  return true;
13217  expr = (Node *) d->arg;
13218  }
13219  else if (IsA(expr, FuncExpr))
13220  {
13221  FuncExpr *f = (FuncExpr *) expr;
13222 
13223  switch (f->funcid)
13224  {
13225  case F_TIMESTAMPTZ_TIMESTAMP:
13226  case F_TIMESTAMP_TIMESTAMPTZ:
13228  return true;
13229  else
13230  expr = linitial(f->args);
13231  break;
13232  default:
13233  return true;
13234  }
13235  }
13236  else
13237  return true;
13238  }
13239 }
13240 
13241 /*
13242  * ALTER COLUMN .. SET DATA TYPE
13243  *
13244  * Return the address of the modified column.
13245  */
13246 static ObjectAddress
13248  AlterTableCmd *cmd, LOCKMODE lockmode)
13249 {
13250  char *colName = cmd->name;
13251  ColumnDef *def = (ColumnDef *) cmd->def;
13252  TypeName *typeName = def->typeName;
13253  HeapTuple heapTup;
13254  Form_pg_attribute attTup,
13255  attOldTup;
13257  HeapTuple typeTuple;
13258  Form_pg_type tform;
13259  Oid targettype;
13260  int32 targettypmod;
13261  Oid targetcollid;
13262  Node *defaultexpr;
13263  Relation attrelation;
13264  Relation depRel;
13265  ScanKeyData key[3];
13266  SysScanDesc scan;
13267  HeapTuple depTup;
13268  ObjectAddress address;
13269 
13270  /*
13271  * Clear all the missing values if we're rewriting the table, since this
13272  * renders them pointless.
13273  */
13274  if (tab->rewrite)
13275  {
13276  Relation newrel;
13277 
13278  newrel = table_open(RelationGetRelid(rel), NoLock);
13279  RelationClearMissing(newrel);
13280  relation_close(newrel, NoLock);
13281  /* make sure we don't conflict with later attribute modifications */
13283  }
13284 
13285  attrelation = table_open(AttributeRelationId, RowExclusiveLock);
13286 
13287  /* Look up the target column */
13288  heapTup = SearchSysCacheCopyAttName(RelationGetRelid(rel), colName);
13289  if (!HeapTupleIsValid(heapTup)) /* shouldn't happen */
13290  ereport(ERROR,
13291  (errcode(ERRCODE_UNDEFINED_COLUMN),
13292  errmsg("column \"%s\" of relation \"%s\" does not exist",
13293  colName, RelationGetRelationName(rel))));
13294  attTup = (Form_pg_attribute) GETSTRUCT(heapTup);
13295  attnum = attTup->attnum;
13296  attOldTup = TupleDescAttr(tab->oldDesc, attnum - 1);
13297 
13298  /* Check for multiple ALTER TYPE on same column --- can't cope */
13299  if (attTup->atttypid != attOldTup->atttypid ||
13300  attTup->atttypmod != attOldTup->atttypmod)
13301  ereport(ERROR,
13302  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
13303  errmsg("cannot alter type of column \"%s\" twice",
13304  colName)));
13305 
13306  /* Look up the target type (should not fail, since prep found it) */
13307  typeTuple = typenameType(NULL, typeName, &targettypmod);
13308  tform = (Form_pg_type) GETSTRUCT(typeTuple);
13309  targettype = tform->oid;
13310  /* And the collation */
13311  targetcollid = GetColumnDefCollation(NULL, def, targettype);
13312 
13313  /*
13314  * If there is a default expression for the column, get it and ensure we
13315  * can coerce it to the new datatype. (We must do this before changing
13316  * the column type, because build_column_default itself will try to
13317  * coerce, and will not issue the error message we want if it fails.)
13318  *
13319  * We remove any implicit coercion steps at the top level of the old
13320  * default expression; this has been agreed to satisfy the principle of
13321  * least surprise. (The conversion to the new column type should act like
13322  * it started from what the user sees as the stored expression, and the
13323  * implicit coercions aren't going to be shown.)
13324  */
13325  if (attTup->atthasdef)
13326  {
13327  defaultexpr = build_column_default(rel, attnum);
13328  Assert(defaultexpr);
13329  defaultexpr = strip_implicit_coercions(defaultexpr);
13330  defaultexpr = coerce_to_target_type(NULL, /* no UNKNOWN params */
13331  defaultexpr, exprType(defaultexpr),
13332  targettype, targettypmod,
13335  -1);
13336  if (defaultexpr == NULL)
13337  {
13338  if (attTup->attgenerated)
13339  ereport(ERROR,
13340  (errcode(ERRCODE_DATATYPE_MISMATCH),
13341  errmsg("generation expression for column \"%s\" cannot be cast automatically to type %s",
13342  colName, format_type_be(targettype))));
13343  else
13344  ereport(ERROR,
13345  (errcode(ERRCODE_DATATYPE_MISMATCH),
13346  errmsg("default for column \"%s\" cannot be cast automatically to type %s",
13347  colName, format_type_be(targettype))));
13348  }
13349  }
13350  else
13351  defaultexpr = NULL;
13352 
13353  /*
13354  * Find everything that depends on the column (constraints, indexes, etc),
13355  * and record enough information to let us recreate the objects.
13356  *
13357  * The actual recreation does not happen here, but only after we have
13358  * performed all the individual ALTER TYPE operations. We have to save
13359  * the info before executing ALTER TYPE, though, else the deparser will
13360  * get confused.
13361  */
13363 
13364  /*
13365  * Now scan for dependencies of this column on other things. The only
13366  * things we should find are the dependency on the column datatype and
13367  * possibly a collation dependency. Those can be removed.
13368  */
13369  depRel = table_open(DependRelationId, RowExclusiveLock);
13370 
13371  ScanKeyInit(&key[0],
13372  Anum_pg_depend_classid,
13373  BTEqualStrategyNumber, F_OIDEQ,
13374  ObjectIdGetDatum(RelationRelationId));
13375  ScanKeyInit(&key[1],
13376  Anum_pg_depend_objid,
13377  BTEqualStrategyNumber, F_OIDEQ,
13379  ScanKeyInit(&key[2],
13380  Anum_pg_depend_objsubid,
13381  BTEqualStrategyNumber, F_INT4EQ,
13383 
13384  scan = systable_beginscan(depRel, DependDependerIndexId, true,
13385  NULL, 3, key);
13386 
13387  while (HeapTupleIsValid(depTup = systable_getnext(scan)))
13388  {
13389  Form_pg_depend foundDep = (Form_pg_depend) GETSTRUCT(depTup);
13390  ObjectAddress foundObject;
13391 
13392  foundObject.classId = foundDep->refclassid;
13393  foundObject.objectId = foundDep->refobjid;
13394  foundObject.objectSubId = foundDep->refobjsubid;
13395 
13396  if (foundDep->deptype != DEPENDENCY_NORMAL)
13397  elog(ERROR, "found unexpected dependency type '%c'",
13398  foundDep->deptype);
13399  if (!(foundDep->refclassid == TypeRelationId &&
13400  foundDep->refobjid == attTup->atttypid) &&
13401  !(foundDep->refclassid == CollationRelationId &&
13402  foundDep->refobjid == attTup->attcollation))
13403  elog(ERROR, "found unexpected dependency for column: %s",
13404  getObjectDescription(&foundObject, false));
13405 
13406  CatalogTupleDelete(depRel, &depTup->t_self);
13407  }
13408 
13409  systable_endscan(scan);
13410 
13411  table_close(depRel, RowExclusiveLock);
13412 
13413  /*
13414  * Here we go --- change the recorded column type and collation. (Note
13415  * heapTup is a copy of the syscache entry, so okay to scribble on.) First
13416  * fix up the missing value if any.
13417  */
13418  if (attTup->atthasmissing)
13419  {
13420  Datum missingval;
13421  bool missingNull;
13422 
13423  /* if rewrite is true the missing value should already be cleared */
13424  Assert(tab->rewrite == 0);
13425 
13426  /* Get the missing value datum */
13427  missingval = heap_getattr(heapTup,
13428  Anum_pg_attribute_attmissingval,
13429  attrelation->rd_att,
13430  &missingNull);
13431 
13432  /* if it's a null array there is nothing to do */
13433 
13434  if (!missingNull)
13435  {
13436  /*
13437  * Get the datum out of the array and repack it in a new array
13438  * built with the new type data. We assume that since the table
13439  * doesn't need rewriting, the actual Datum doesn't need to be
13440  * changed, only the array metadata.
13441  */
13442 
13443  int one = 1;
13444  bool isNull;
13445  Datum valuesAtt[Natts_pg_attribute] = {0};
13446  bool nullsAtt[Natts_pg_attribute] = {0};
13447  bool replacesAtt[Natts_pg_attribute] = {0};
13448  HeapTuple newTup;
13449 
13450  missingval = array_get_element(missingval,
13451  1,
13452  &one,
13453  0,
13454  attTup->attlen,
13455  attTup->attbyval,
13456  attTup->attalign,
13457  &isNull);
13458  missingval = PointerGetDatum(construct_array(&missingval,
13459  1,
13460  targettype,
13461  tform->typlen,
13462  tform->typbyval,
13463  tform->typalign));
13464 
13465  valuesAtt[Anum_pg_attribute_attmissingval - 1] = missingval;
13466  replacesAtt[Anum_pg_attribute_attmissingval - 1] = true;
13467  nullsAtt[Anum_pg_attribute_attmissingval - 1] = false;
13468 
13469  newTup = heap_modify_tuple(heapTup, RelationGetDescr(attrelation),
13470  valuesAtt, nullsAtt, replacesAtt);
13471  heap_freetuple(heapTup);
13472  heapTup = newTup;
13473  attTup = (Form_pg_attribute) GETSTRUCT(heapTup);
13474  }
13475  }
13476 
13477  attTup->atttypid = targettype;
13478  attTup->atttypmod = targettypmod;
13479  attTup->attcollation = targetcollid;
13480  if (list_length(typeName->arrayBounds) > PG_INT16_MAX)
13481  ereport(ERROR,
13482  errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
13483  errmsg("too many array dimensions"));
13484  attTup->attndims = list_length(typeName->arrayBounds);
13485  attTup->attlen = tform->typlen;
13486  attTup->attbyval = tform->typbyval;
13487  attTup->attalign = tform->typalign;
13488  attTup->attstorage = tform->typstorage;
13489  attTup->attcompression = InvalidCompressionMethod;
13490 
13491  ReleaseSysCache(typeTuple);
13492 
13493  CatalogTupleUpdate(attrelation, &heapTup->t_self, heapTup);
13494 
13495  table_close(attrelation, RowExclusiveLock);
13496 
13497  /* Install dependencies on new datatype and collation */
13500 
13501  /*
13502  * Drop any pg_statistic entry for the column, since it's now wrong type
13503  */
13505 
13506  InvokeObjectPostAlterHook(RelationRelationId,
13507  RelationGetRelid(rel), attnum);
13508 
13509  /*
13510  * Update the default, if present, by brute force --- remove and re-add
13511  * the default. Probably unsafe to take shortcuts, since the new version
13512  * may well have additional dependencies. (It's okay to do this now,
13513  * rather than after other ALTER TYPE commands, since the default won't
13514  * depend on other column types.)
13515  */
13516  if (defaultexpr)
13517  {
13518  /*
13519  * If it's a GENERATED default, drop its dependency records, in
13520  * particular its INTERNAL dependency on the column, which would
13521  * otherwise cause dependency.c to refuse to perform the deletion.
13522  */
13523  if (attTup->attgenerated)
13524  {
13525  Oid attrdefoid = GetAttrDefaultOid(RelationGetRelid(rel), attnum);
13526 
13527  if (!OidIsValid(attrdefoid))
13528  elog(ERROR, "could not find attrdef tuple for relation %u attnum %d",
13529  RelationGetRelid(rel), attnum);
13530  (void) deleteDependencyRecordsFor(AttrDefaultRelationId, attrdefoid, false);
13531  }
13532 
13533  /*
13534  * Make updates-so-far visible, particularly the new pg_attribute row
13535  * which will be updated again.
13536  */
13538 
13539  /*
13540  * We use RESTRICT here for safety, but at present we do not expect
13541  * anything to depend on the default.
13542  */
13544  true);
13545 
13546  StoreAttrDefault(rel, attnum, defaultexpr, true, false);
13547  }
13548 
13549  ObjectAddressSubSet(address, RelationRelationId,
13550  RelationGetRelid(rel), attnum);
13551 
13552  /* Cleanup */
13553  heap_freetuple(heapTup);
13554 
13555  return address;
13556 }
13557 
13558 /*
13559  * Subroutine for ATExecAlterColumnType and ATExecSetExpression: Find everything
13560  * that depends on the column (constraints, indexes, etc), and record enough
13561  * information to let us recreate the objects.
13562  */
13563 static void
13565  Relation rel, AttrNumber attnum, const char *colName)
13566 {
13567  Relation depRel;
13568  ScanKeyData key[3];
13569  SysScanDesc scan;
13570  HeapTuple depTup;
13571 
13572  Assert(subtype == AT_AlterColumnType || subtype == AT_SetExpression);
13573 
13574  depRel = table_open(DependRelationId, RowExclusiveLock);
13575 
13576  ScanKeyInit(&key[0],
13577  Anum_pg_depend_refclassid,
13578  BTEqualStrategyNumber, F_OIDEQ,
13579  ObjectIdGetDatum(RelationRelationId));
13580  ScanKeyInit(&key[1],
13581  Anum_pg_depend_refobjid,
13582  BTEqualStrategyNumber, F_OIDEQ,
13584  ScanKeyInit(&key[2],
13585  Anum_pg_depend_refobjsubid,
13586  BTEqualStrategyNumber, F_INT4EQ,
13588 
13589  scan = systable_beginscan(depRel, DependReferenceIndexId, true,
13590  NULL, 3, key);
13591 
13592  while (HeapTupleIsValid(depTup = systable_getnext(scan)))
13593  {
13594  Form_pg_depend foundDep = (Form_pg_depend) GETSTRUCT(depTup);
13595  ObjectAddress foundObject;
13596 
13597  foundObject.classId = foundDep->classid;
13598  foundObject.objectId = foundDep->objid;
13599  foundObject.objectSubId = foundDep->objsubid;
13600 
13601  switch (foundObject.classId)
13602  {
13603  case RelationRelationId:
13604  {
13605  char relKind = get_rel_relkind(foundObject.objectId);
13606 
13607  if (relKind == RELKIND_INDEX ||
13608  relKind == RELKIND_PARTITIONED_INDEX)
13609  {
13610  Assert(foundObject.objectSubId == 0);
13611  RememberIndexForRebuilding(foundObject.objectId, tab);
13612  }
13613  else if (relKind == RELKIND_SEQUENCE)
13614  {
13615  /*
13616  * This must be a SERIAL column's sequence. We need
13617  * not do anything to it.
13618  */
13619  Assert(foundObject.objectSubId == 0);
13620  }
13621  else
13622  {
13623  /* Not expecting any other direct dependencies... */
13624  elog(ERROR, "unexpected object depending on column: %s",
13625  getObjectDescription(&foundObject, false));
13626  }
13627  break;
13628  }
13629 
13630  case ConstraintRelationId:
13631  Assert(foundObject.objectSubId == 0);
13632  RememberConstraintForRebuilding(foundObject.objectId, tab);
13633  break;
13634 
13635  case ProcedureRelationId:
13636 
13637  /*
13638  * A new-style SQL function can depend on a column, if that
13639  * column is referenced in the parsed function body. Ideally
13640  * we'd automatically update the function by deparsing and
13641  * reparsing it, but that's risky and might well fail anyhow.
13642  * FIXME someday.
13643  *
13644  * This is only a problem for AT_AlterColumnType, not
13645  * AT_SetExpression.
13646  */
13647  if (subtype == AT_AlterColumnType)
13648  ereport(ERROR,
13649  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
13650  errmsg("cannot alter type of a column used by a function or procedure"),
13651  errdetail("%s depends on column \"%s\"",
13652  getObjectDescription(&foundObject, false),
13653  colName)));
13654  break;
13655 
13656  case RewriteRelationId:
13657 
13658  /*
13659  * View/rule bodies have pretty much the same issues as
13660  * function bodies. FIXME someday.
13661  */
13662  if (subtype == AT_AlterColumnType)
13663  ereport(ERROR,
13664  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
13665  errmsg("cannot alter type of a column used by a view or rule"),
13666  errdetail("%s depends on column \"%s\"",
13667  getObjectDescription(&foundObject, false),
13668  colName)));
13669  break;
13670 
13671  case TriggerRelationId:
13672 
13673  /*
13674  * A trigger can depend on a column because the column is
13675  * specified as an update target, or because the column is
13676  * used in the trigger's WHEN condition. The first case would
13677  * not require any extra work, but the second case would
13678  * require updating the WHEN expression, which has the same
13679  * issues as above. Since we can't easily tell which case
13680  * applies, we punt for both. FIXME someday.
13681  */
13682  if (subtype == AT_AlterColumnType)
13683  ereport(ERROR,
13684  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
13685  errmsg("cannot alter type of a column used in a trigger definition"),
13686  errdetail("%s depends on column \"%s\"",
13687  getObjectDescription(&foundObject, false),
13688  colName)));
13689  break;
13690 
13691  case PolicyRelationId:
13692 
13693  /*
13694  * A policy can depend on a column because the column is
13695  * specified in the policy's USING or WITH CHECK qual
13696  * expressions. It might be possible to rewrite and recheck
13697  * the policy expression, but punt for now. It's certainly
13698  * easy enough to remove and recreate the policy; still, FIXME
13699  * someday.
13700  */
13701  if (subtype == AT_AlterColumnType)
13702  ereport(ERROR,
13703  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
13704  errmsg("cannot alter type of a column used in a policy definition"),
13705  errdetail("%s depends on column \"%s\"",
13706  getObjectDescription(&foundObject, false),
13707  colName)));
13708  break;
13709 
13710  case AttrDefaultRelationId:
13711  {
13713 
13714  if (col.objectId == RelationGetRelid(rel) &&
13715  col.objectSubId == attnum)
13716  {
13717  /*
13718  * Ignore the column's own default expression. The
13719  * caller deals with it.
13720  */
13721  }
13722  else
13723  {
13724  /*
13725  * This must be a reference from the expression of a
13726  * generated column elsewhere in the same table.
13727  * Changing the type/generated expression of a column
13728  * that is used by a generated column is not allowed
13729  * by SQL standard, so just punt for now. It might be
13730  * doable with some thinking and effort.
13731  */
13732  if (subtype == AT_AlterColumnType)
13733  ereport(ERROR,
13734  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
13735  errmsg("cannot alter type of a column used by a generated column"),
13736  errdetail("Column \"%s\" is used by generated column \"%s\".",
13737  colName,
13738  get_attname(col.objectId,
13739  col.objectSubId,
13740  false))));
13741  }
13742  break;
13743  }
13744 
13745  case StatisticExtRelationId:
13746 
13747  /*
13748  * Give the extended-stats machinery a chance to fix anything
13749  * that this column type change would break.
13750  */
13751  RememberStatisticsForRebuilding(foundObject.objectId, tab);
13752  break;
13753 
13754  case PublicationRelRelationId:
13755 
13756  /*
13757  * Column reference in a PUBLICATION ... FOR TABLE ... WHERE
13758  * clause. Same issues as above. FIXME someday.
13759  */
13760  if (subtype == AT_AlterColumnType)
13761  ereport(ERROR,
13762  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
13763  errmsg("cannot alter type of a column used by a publication WHERE clause"),
13764  errdetail("%s depends on column \"%s\"",
13765  getObjectDescription(&foundObject, false),
13766  colName)));
13767  break;
13768 
13769  default:
13770 
13771  /*
13772  * We don't expect any other sorts of objects to depend on a
13773  * column.
13774  */
13775  elog(ERROR, "unexpected object depending on column: %s",
13776  getObjectDescription(&foundObject, false));
13777  break;
13778  }
13779  }
13780 
13781  systable_endscan(scan);
13782  table_close(depRel, NoLock);
13783 }
13784 
13785 /*
13786  * Subroutine for ATExecAlterColumnType: remember that a replica identity
13787  * needs to be reset.
13788  */
13789 static void
13791 {
13792  if (!get_index_isreplident(indoid))
13793  return;
13794 
13795  if (tab->replicaIdentityIndex)
13796  elog(ERROR, "relation %u has multiple indexes marked as replica identity", tab->relid);
13797 
13798  tab->replicaIdentityIndex = get_rel_name(indoid);
13799 }
13800 
13801 /*
13802  * Subroutine for ATExecAlterColumnType: remember any clustered index.
13803  */
13804 static void
13806 {
13807  if (!get_index_isclustered(indoid))
13808  return;
13809 
13810  if (tab->clusterOnIndex)
13811  elog(ERROR, "relation %u has multiple clustered indexes", tab->relid);
13812 
13813  tab->clusterOnIndex = get_rel_name(indoid);
13814 }
13815 
13816 /*
13817  * Subroutine for ATExecAlterColumnType: remember that a constraint needs
13818  * to be rebuilt (which we might already know).
13819  */
13820 static void
13822 {
13823  /*
13824  * This de-duplication check is critical for two independent reasons: we
13825  * mustn't try to recreate the same constraint twice, and if a constraint
13826  * depends on more than one column whose type is to be altered, we must
13827  * capture its definition string before applying any of the column type
13828  * changes. ruleutils.c will get confused if we ask again later.
13829  */
13830  if (!list_member_oid(tab->changedConstraintOids, conoid))
13831  {
13832  /* OK, capture the constraint's existing definition string */
13833  char *defstring = pg_get_constraintdef_command(conoid);
13834  Oid indoid;
13835 
13837  conoid);
13839  defstring);
13840 
13841  /*
13842  * For the index of a constraint, if any, remember if it is used for
13843  * the table's replica identity or if it is a clustered index, so that
13844  * ATPostAlterTypeCleanup() can queue up commands necessary to restore
13845  * those properties.
13846  */
13847  indoid = get_constraint_index(conoid);
13848  if (OidIsValid(indoid))
13849  {
13851  RememberClusterOnForRebuilding(indoid, tab);
13852  }
13853  }
13854 }
13855 
13856 /*
13857  * Subroutine for ATExecAlterColumnType: remember that an index needs
13858  * to be rebuilt (which we might already know).
13859  */
13860 static void
13862 {
13863  /*
13864  * This de-duplication check is critical for two independent reasons: we
13865  * mustn't try to recreate the same index twice, and if an index depends
13866  * on more than one column whose type is to be altered, we must capture
13867  * its definition string before applying any of the column type changes.
13868  * ruleutils.c will get confused if we ask again later.
13869  */
13870  if (!list_member_oid(tab->changedIndexOids, indoid))
13871  {
13872  /*
13873  * Before adding it as an index-to-rebuild, we'd better see if it
13874  * belongs to a constraint, and if so rebuild the constraint instead.
13875  * Typically this check fails, because constraint indexes normally
13876  * have only dependencies on their constraint. But it's possible for
13877  * such an index to also have direct dependencies on table columns,
13878  * for example with a partial exclusion constraint.
13879  */
13880  Oid conoid = get_index_constraint(indoid);
13881 
13882  if (OidIsValid(conoid))
13883  {
13884  RememberConstraintForRebuilding(conoid, tab);
13885  }
13886  else
13887  {
13888  /* OK, capture the index's existing definition string */
13889  char *defstring = pg_get_indexdef_string(indoid);
13890 
13892  indoid);
13894  defstring);
13895 
13896  /*
13897  * Remember if this index is used for the table's replica identity
13898  * or if it is a clustered index, so that ATPostAlterTypeCleanup()
13899  * can queue up commands necessary to restore those properties.
13900  */
13902  RememberClusterOnForRebuilding(indoid, tab);
13903  }
13904  }
13905 }
13906 
13907 /*
13908  * Subroutine for ATExecAlterColumnType: remember that a statistics object
13909  * needs to be rebuilt (which we might already know).
13910  */
13911 static void
13913 {
13914  /*
13915  * This de-duplication check is critical for two independent reasons: we
13916  * mustn't try to recreate the same statistics object twice, and if the
13917  * statistics object depends on more than one column whose type is to be
13918  * altered, we must capture its definition string before applying any of
13919  * the type changes. ruleutils.c will get confused if we ask again later.
13920  */
13921  if (!list_member_oid(tab->changedStatisticsOids, stxoid))
13922  {
13923  /* OK, capture the statistics object's existing definition string */
13924  char *defstring = pg_get_statisticsobjdef_string(stxoid);
13925 
13927  stxoid);
13929  defstring);
13930  }
13931 }
13932 
13933 /*
13934  * Cleanup after we've finished all the ALTER TYPE or SET EXPRESSION
13935  * operations for a particular relation. We have to drop and recreate all the
13936  * indexes and constraints that depend on the altered columns. We do the
13937  * actual dropping here, but re-creation is managed by adding work queue
13938  * entries to do those steps later.
13939  */
13940 static void
13942 {
13943  ObjectAddress obj;
13944  ObjectAddresses *objects;
13945  ListCell *def_item;
13946  ListCell *oid_item;
13947 
13948  /*
13949  * Collect all the constraints and indexes to drop so we can process them
13950  * in a single call. That way we don't have to worry about dependencies
13951  * among them.
13952  */
13953  objects = new_object_addresses();
13954 
13955  /*
13956  * Re-parse the index and constraint definitions, and attach them to the
13957  * appropriate work queue entries. We do this before dropping because in
13958  * the case of a FOREIGN KEY constraint, we might not yet have exclusive
13959  * lock on the table the constraint is attached to, and we need to get
13960  * that before reparsing/dropping.
13961  *
13962  * We can't rely on the output of deparsing to tell us which relation to
13963  * operate on, because concurrent activity might have made the name
13964  * resolve differently. Instead, we've got to use the OID of the
13965  * constraint or index we're processing to figure out which relation to
13966  * operate on.
13967  */
13968  forboth(oid_item, tab->changedConstraintOids,
13969  def_item, tab->changedConstraintDefs)
13970  {
13971  Oid oldId = lfirst_oid(oid_item);
13972  HeapTuple tup;
13973  Form_pg_constraint con;
13974  Oid relid;
13975  Oid confrelid;
13976  char contype;
13977  bool conislocal;
13978 
13979  tup = SearchSysCache1(CONSTROID, ObjectIdGetDatum(oldId));
13980  if (!HeapTupleIsValid(tup)) /* should not happen */
13981  elog(ERROR, "cache lookup failed for constraint %u", oldId);
13982  con = (Form_pg_constraint) GETSTRUCT(tup);
13983  if (OidIsValid(con->conrelid))
13984  relid = con->conrelid;
13985  else
13986  {
13987  /* must be a domain constraint */
13988  relid = get_typ_typrelid(getBaseType(con->contypid));
13989  if (!OidIsValid(relid))
13990  elog(ERROR, "could not identify relation associated with constraint %u", oldId);
13991  }
13992  confrelid = con->confrelid;
13993  contype = con->contype;
13994  conislocal = con->conislocal;
13995  ReleaseSysCache(tup);
13996 
13997  ObjectAddressSet(obj, ConstraintRelationId, oldId);
13998  add_exact_object_address(&obj, objects);
13999 
14000  /*
14001  * If the constraint is inherited (only), we don't want to inject a
14002  * new definition here; it'll get recreated when ATAddCheckConstraint
14003  * recurses from adding the parent table's constraint. But we had to
14004  * carry the info this far so that we can drop the constraint below.
14005  */
14006  if (!conislocal)
14007  continue;
14008 
14009  /*
14010  * When rebuilding an FK constraint that references the table we're
14011  * modifying, we might not yet have any lock on the FK's table, so get
14012  * one now. We'll need AccessExclusiveLock for the DROP CONSTRAINT
14013  * step, so there's no value in asking for anything weaker.
14014  */
14015  if (relid != tab->relid && contype == CONSTRAINT_FOREIGN)
14017 
14018  ATPostAlterTypeParse(oldId, relid, confrelid,
14019  (char *) lfirst(def_item),
14020  wqueue, lockmode, tab->rewrite);
14021  }
14022  forboth(oid_item, tab->changedIndexOids,
14023  def_item, tab->changedIndexDefs)
14024  {
14025  Oid oldId = lfirst_oid(oid_item);
14026  Oid relid;
14027 
14028  relid = IndexGetRelation(oldId, false);
14029  ATPostAlterTypeParse(oldId, relid, InvalidOid,
14030  (char *) lfirst(def_item),
14031  wqueue, lockmode, tab->rewrite);
14032 
14033  ObjectAddressSet(obj, RelationRelationId, oldId);
14034  add_exact_object_address(&obj, objects);
14035  }
14036 
14037  /* add dependencies for new statistics */
14038  forboth(oid_item, tab->changedStatisticsOids,
14039  def_item, tab->changedStatisticsDefs)
14040  {
14041  Oid oldId = lfirst_oid(oid_item);
14042  Oid relid;
14043 
14044  relid = StatisticsGetRelation(oldId, false);
14045  ATPostAlterTypeParse(oldId, relid, InvalidOid,
14046  (char *) lfirst(def_item),
14047  wqueue, lockmode, tab->rewrite);
14048 
14049  ObjectAddressSet(obj, StatisticExtRelationId, oldId);
14050  add_exact_object_address(&obj, objects);
14051  }
14052 
14053  /*
14054  * Queue up command to restore replica identity index marking
14055  */
14056  if (tab->replicaIdentityIndex)
14057  {
14060 
14061  subcmd->identity_type = REPLICA_IDENTITY_INDEX;
14062  subcmd->name = tab->replicaIdentityIndex;
14063  cmd->subtype = AT_ReplicaIdentity;
14064  cmd->def = (Node *) subcmd;
14065 
14066  /* do it after indexes and constraints */
14067  tab->subcmds[AT_PASS_OLD_CONSTR] =
14068  lappend(tab->subcmds[AT_PASS_OLD_CONSTR], cmd);
14069  }
14070 
14071  /*
14072  * Queue up command to restore marking of index used for cluster.
14073  */
14074  if (tab->clusterOnIndex)
14075  {
14077 
14078  cmd->subtype = AT_ClusterOn;
14079  cmd->name = tab->clusterOnIndex;
14080 
14081  /* do it after indexes and constraints */
14082  tab->subcmds[AT_PASS_OLD_CONSTR] =
14083  lappend(tab->subcmds[AT_PASS_OLD_CONSTR], cmd);
14084  }
14085 
14086  /*
14087  * It should be okay to use DROP_RESTRICT here, since nothing else should
14088  * be depending on these objects.
14089  */
14091 
14092  free_object_addresses(objects);
14093 
14094  /*
14095  * The objects will get recreated during subsequent passes over the work
14096  * queue.
14097  */
14098 }
14099 
14100 /*
14101  * Parse the previously-saved definition string for a constraint, index or
14102  * statistics object against the newly-established column data type(s), and
14103  * queue up the resulting command parsetrees for execution.
14104  *
14105  * This might fail if, for example, you have a WHERE clause that uses an
14106  * operator that's not available for the new column type.
14107  */
14108 static void
14109 ATPostAlterTypeParse(Oid oldId, Oid oldRelId, Oid refRelId, char *cmd,
14110  List **wqueue, LOCKMODE lockmode, bool rewrite)
14111 {
14112  List *raw_parsetree_list;
14113  List *querytree_list;
14114  ListCell *list_item;
14115  Relation rel;
14116 
14117  /*
14118  * We expect that we will get only ALTER TABLE and CREATE INDEX
14119  * statements. Hence, there is no need to pass them through
14120  * parse_analyze_*() or the rewriter, but instead we need to pass them
14121  * through parse_utilcmd.c to make them ready for execution.
14122  */
14123  raw_parsetree_list = raw_parser(cmd, RAW_PARSE_DEFAULT);
14124  querytree_list = NIL;
14125  foreach(list_item, raw_parsetree_list)
14126  {
14127  RawStmt *rs = lfirst_node(RawStmt, list_item);
14128  Node *stmt = rs->stmt;
14129 
14130  if (IsA(stmt, IndexStmt))
14131  querytree_list = lappend(querytree_list,
14132  transformIndexStmt(oldRelId,
14133  (IndexStmt *) stmt,
14134  cmd));
14135  else if (IsA(stmt, AlterTableStmt))
14136  {
14137  List *beforeStmts;
14138  List *afterStmts;
14139 
14140  stmt = (Node *) transformAlterTableStmt(oldRelId,
14141  (AlterTableStmt *) stmt,
14142  cmd,
14143  &beforeStmts,
14144  &afterStmts);
14145  querytree_list = list_concat(querytree_list, beforeStmts);
14146  querytree_list = lappend(querytree_list, stmt);
14147  querytree_list = list_concat(querytree_list, afterStmts);
14148  }
14149  else if (IsA(stmt, CreateStatsStmt))
14150  querytree_list = lappend(querytree_list,
14151  transformStatsStmt(oldRelId,
14152  (CreateStatsStmt *) stmt,
14153  cmd));
14154  else
14155  querytree_list = lappend(querytree_list, stmt);
14156  }
14157 
14158  /* Caller should already have acquired whatever lock we need. */
14159  rel = relation_open(oldRelId, NoLock);
14160 
14161  /*
14162  * Attach each generated command to the proper place in the work queue.
14163  * Note this could result in creation of entirely new work-queue entries.
14164  *
14165  * Also note that we have to tweak the command subtypes, because it turns
14166  * out that re-creation of indexes and constraints has to act a bit
14167  * differently from initial creation.
14168  */
14169  foreach(list_item, querytree_list)
14170  {
14171  Node *stm = (Node *) lfirst(list_item);
14172  AlteredTableInfo *tab;
14173 
14174  tab = ATGetQueueEntry(wqueue, rel);
14175 
14176  if (IsA(stm, IndexStmt))
14177  {
14178  IndexStmt *stmt = (IndexStmt *) stm;
14179  AlterTableCmd *newcmd;
14180 
14181  if (!rewrite)
14182  TryReuseIndex(oldId, stmt);
14183  stmt->reset_default_tblspc = true;
14184  /* keep the index's comment */
14185  stmt->idxcomment = GetComment(oldId, RelationRelationId, 0);
14186 
14187  newcmd = makeNode(AlterTableCmd);
14188  newcmd->subtype = AT_ReAddIndex;
14189  newcmd->def = (Node *) stmt;
14190  tab->subcmds[AT_PASS_OLD_INDEX] =
14191  lappend(tab->subcmds[AT_PASS_OLD_INDEX], newcmd);
14192  }
14193  else if (IsA(stm, AlterTableStmt))
14194  {
14195  AlterTableStmt *stmt = (AlterTableStmt *) stm;
14196  ListCell *lcmd;
14197 
14198  foreach(lcmd, stmt->cmds)
14199  {
14200  AlterTableCmd *cmd = lfirst_node(AlterTableCmd, lcmd);
14201 
14202  if (cmd->subtype == AT_AddIndex)
14203  {
14204  IndexStmt *indstmt;
14205  Oid indoid;
14206 
14207  indstmt = castNode(IndexStmt, cmd->def);
14208  indoid = get_constraint_index(oldId);
14209 
14210  if (!rewrite)
14211  TryReuseIndex(indoid, indstmt);
14212  /* keep any comment on the index */
14213  indstmt->idxcomment = GetComment(indoid,
14214  RelationRelationId, 0);
14215  indstmt->reset_default_tblspc = true;
14216 
14217  cmd->subtype = AT_ReAddIndex;
14218  tab->subcmds[AT_PASS_OLD_INDEX] =
14219  lappend(tab->subcmds[AT_PASS_OLD_INDEX], cmd);
14220 
14221  /* recreate any comment on the constraint */
14224  oldId,
14225  rel,
14226  NIL,
14227  indstmt->idxname);
14228  }
14229  else if (cmd->subtype == AT_AddConstraint)
14230  {
14231  Constraint *con = castNode(Constraint, cmd->def);
14232 
14233  con->old_pktable_oid = refRelId;
14234  /* rewriting neither side of a FK */
14235  if (con->contype == CONSTR_FOREIGN &&
14236  !rewrite && tab->rewrite == 0)
14237  TryReuseForeignKey(oldId, con);
14238  con->reset_default_tblspc = true;
14239  cmd->subtype = AT_ReAddConstraint;
14240  tab->subcmds[AT_PASS_OLD_CONSTR] =
14241  lappend(tab->subcmds[AT_PASS_OLD_CONSTR], cmd);
14242 
14243  /* recreate any comment on the constraint */
14246  oldId,
14247  rel,
14248  NIL,
14249  con->conname);
14250  }
14251  else if (cmd->subtype == AT_SetNotNull)
14252  {
14253  /*
14254  * The parser will create AT_SetNotNull subcommands for
14255  * columns of PRIMARY KEY indexes/constraints, but we need
14256  * not do anything with them here, because the columns'
14257  * NOT NULL marks will already have been propagated into
14258  * the new table definition.
14259  */
14260  }
14261  else
14262  elog(ERROR, "unexpected statement subtype: %d",
14263  (int) cmd->subtype);
14264  }
14265  }
14266  else if (IsA(stm, AlterDomainStmt))
14267  {
14269 
14270  if (stmt->subtype == 'C') /* ADD CONSTRAINT */
14271  {
14272  Constraint *con = castNode(Constraint, stmt->def);
14274 
14276  cmd->def = (Node *) stmt;
14277  tab->subcmds[AT_PASS_OLD_CONSTR] =
14278  lappend(tab->subcmds[AT_PASS_OLD_CONSTR], cmd);
14279 
14280  /* recreate any comment on the constraint */
14283  oldId,
14284  NULL,
14285  stmt->typeName,
14286  con->conname);
14287  }
14288  else
14289  elog(ERROR, "unexpected statement subtype: %d",
14290  (int) stmt->subtype);
14291  }
14292  else if (IsA(stm, CreateStatsStmt))
14293  {
14295  AlterTableCmd *newcmd;
14296 
14297  /* keep the statistics object's comment */
14298  stmt->stxcomment = GetComment(oldId, StatisticExtRelationId, 0);
14299 
14300  newcmd = makeNode(AlterTableCmd);
14301  newcmd->subtype = AT_ReAddStatistics;
14302  newcmd->def = (Node *) stmt;
14303  tab->subcmds[AT_PASS_MISC] =
14304  lappend(tab->subcmds[AT_PASS_MISC], newcmd);
14305  }
14306  else
14307  elog(ERROR, "unexpected statement type: %d",
14308  (int) nodeTag(stm));
14309  }
14310 
14311  relation_close(rel, NoLock);
14312 }
14313 
14314 /*
14315  * Subroutine for ATPostAlterTypeParse() to recreate any existing comment
14316  * for a table or domain constraint that is being rebuilt.
14317  *
14318  * objid is the OID of the constraint.
14319  * Pass "rel" for a table constraint, or "domname" (domain's qualified name
14320  * as a string list) for a domain constraint.
14321  * (We could dig that info, as well as the conname, out of the pg_constraint
14322  * entry; but callers already have them so might as well pass them.)
14323  */
14324 static void
14326  Relation rel, List *domname,
14327  const char *conname)
14328 {
14329  CommentStmt *cmd;
14330  char *comment_str;
14331  AlterTableCmd *newcmd;
14332 
14333  /* Look for comment for object wanted, and leave if none */
14334  comment_str = GetComment(objid, ConstraintRelationId, 0);
14335  if (comment_str == NULL)
14336  return;
14337 
14338  /* Build CommentStmt node, copying all input data for safety */
14339  cmd = makeNode(CommentStmt);
14340  if (rel)
14341  {
14343  cmd->object = (Node *)
14346  makeString(pstrdup(conname)));
14347  }
14348  else
14349  {
14351  cmd->object = (Node *)
14353  makeString(pstrdup(conname)));
14354  }
14355  cmd->comment = comment_str;
14356 
14357  /* Append it to list of commands */
14358  newcmd = makeNode(AlterTableCmd);
14359  newcmd->subtype = AT_ReAddComment;
14360  newcmd->def = (Node *) cmd;
14361  tab->subcmds[pass] = lappend(tab->subcmds[pass], newcmd);
14362 }
14363 
14364 /*
14365  * Subroutine for ATPostAlterTypeParse(). Calls out to CheckIndexCompatible()
14366  * for the real analysis, then mutates the IndexStmt based on that verdict.
14367  */
14368 static void
14370 {
14371  if (CheckIndexCompatible(oldId,
14372  stmt->accessMethod,
14373  stmt->indexParams,
14374  stmt->excludeOpNames,
14375  stmt->iswithoutoverlaps))
14376  {
14377  Relation irel = index_open(oldId, NoLock);
14378 
14379  /* If it's a partitioned index, there is no storage to share. */
14380  if (irel->rd_rel->relkind != RELKIND_PARTITIONED_INDEX)
14381  {
14382  stmt->oldNumber = irel->rd_locator.relNumber;
14383  stmt->oldCreateSubid = irel->rd_createSubid;
14384  stmt->oldFirstRelfilelocatorSubid = irel->rd_firstRelfilelocatorSubid;
14385  }
14386  index_close(irel, NoLock);
14387  }
14388 }
14389 
14390 /*
14391  * Subroutine for ATPostAlterTypeParse().
14392  *
14393  * Stash the old P-F equality operator into the Constraint node, for possible
14394  * use by ATAddForeignKeyConstraint() in determining whether revalidation of
14395  * this constraint can be skipped.
14396  */
14397 static void
14399 {
14400  HeapTuple tup;
14401  Datum adatum;
14402  ArrayType *arr;
14403  Oid *rawarr;
14404  int numkeys;
14405  int i;
14406 
14407  Assert(con->contype == CONSTR_FOREIGN);
14408  Assert(con->old_conpfeqop == NIL); /* already prepared this node */
14409 
14410  tup = SearchSysCache1(CONSTROID, ObjectIdGetDatum(oldId));
14411  if (!HeapTupleIsValid(tup)) /* should not happen */
14412  elog(ERROR, "cache lookup failed for constraint %u", oldId);
14413 
14414  adatum = SysCacheGetAttrNotNull(CONSTROID, tup,
14415  Anum_pg_constraint_conpfeqop);
14416  arr = DatumGetArrayTypeP(adatum); /* ensure not toasted */
14417  numkeys = ARR_DIMS(arr)[0];
14418  /* test follows the one in ri_FetchConstraintInfo() */
14419  if (ARR_NDIM(arr) != 1 ||
14420  ARR_HASNULL(arr) ||
14421  ARR_ELEMTYPE(arr) != OIDOID)
14422  elog(ERROR, "conpfeqop is not a 1-D Oid array");
14423  rawarr = (Oid *) ARR_DATA_PTR(arr);
14424 
14425  /* stash a List of the operator Oids in our Constraint node */
14426  for (i = 0; i < numkeys; i++)
14427  con->old_conpfeqop = lappend_oid(con->old_conpfeqop, rawarr[i]);
14428 
14429  ReleaseSysCache(tup);
14430 }
14431 
14432 /*
14433  * ALTER COLUMN .. OPTIONS ( ... )
14434  *
14435  * Returns the address of the modified column
14436  */
14437 static ObjectAddress
14439  const char *colName,
14440  List *options,
14441  LOCKMODE lockmode)
14442 {
14443  Relation ftrel;
14444  Relation attrel;
14445  ForeignServer *server;
14446  ForeignDataWrapper *fdw;
14447  HeapTuple tuple;
14448  HeapTuple newtuple;
14449  bool isnull;
14450  Datum repl_val[Natts_pg_attribute];
14451  bool repl_null[Natts_pg_attribute];
14452  bool repl_repl[Natts_pg_attribute];
14453  Datum datum;
14454  Form_pg_foreign_table fttableform;
14455  Form_pg_attribute atttableform;
14457  ObjectAddress address;
14458 
14459  if (options == NIL)
14460  return InvalidObjectAddress;
14461 
14462  /* First, determine FDW validator associated to the foreign table. */
14463  ftrel = table_open(ForeignTableRelationId, AccessShareLock);
14464  tuple = SearchSysCache1(FOREIGNTABLEREL, ObjectIdGetDatum(rel->rd_id));
14465  if (!HeapTupleIsValid(tuple))
14466  ereport(ERROR,
14467  (errcode(ERRCODE_UNDEFINED_OBJECT),
14468  errmsg("foreign table \"%s\" does not exist",
14469  RelationGetRelationName(rel))));
14470  fttableform = (Form_pg_foreign_table) GETSTRUCT(tuple);
14471  server = GetForeignServer(fttableform->ftserver);
14472  fdw = GetForeignDataWrapper(server->fdwid);
14473 
14474  table_close(ftrel, AccessShareLock);
14475  ReleaseSysCache(tuple);
14476 
14477  attrel = table_open(AttributeRelationId, RowExclusiveLock);
14478  tuple = SearchSysCacheAttName(RelationGetRelid(rel), colName);
14479  if (!HeapTupleIsValid(tuple))
14480  ereport(ERROR,
14481  (errcode(ERRCODE_UNDEFINED_COLUMN),
14482  errmsg("column \"%s\" of relation \"%s\" does not exist",
14483  colName, RelationGetRelationName(rel))));
14484 
14485  /* Prevent them from altering a system attribute */
14486  atttableform = (Form_pg_attribute) GETSTRUCT(tuple);
14487  attnum = atttableform->attnum;
14488  if (attnum <= 0)
14489  ereport(ERROR,
14490  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
14491  errmsg("cannot alter system column \"%s\"", colName)));
14492 
14493 
14494  /* Initialize buffers for new tuple values */
14495  memset(repl_val, 0, sizeof(repl_val));
14496  memset(repl_null, false, sizeof(repl_null));
14497  memset(repl_repl, false, sizeof(repl_repl));
14498 
14499  /* Extract the current options */
14500  datum = SysCacheGetAttr(ATTNAME,
14501  tuple,
14502  Anum_pg_attribute_attfdwoptions,
14503  &isnull);
14504  if (isnull)
14505  datum = PointerGetDatum(NULL);
14506 
14507  /* Transform the options */
14508  datum = transformGenericOptions(AttributeRelationId,
14509  datum,
14510  options,
14511  fdw->fdwvalidator);
14512 
14513  if (PointerIsValid(DatumGetPointer(datum)))
14514  repl_val[Anum_pg_attribute_attfdwoptions - 1] = datum;
14515  else
14516  repl_null[Anum_pg_attribute_attfdwoptions - 1] = true;
14517 
14518  repl_repl[Anum_pg_attribute_attfdwoptions - 1] = true;
14519 
14520  /* Everything looks good - update the tuple */
14521 
14522  newtuple = heap_modify_tuple(tuple, RelationGetDescr(attrel),
14523  repl_val, repl_null, repl_repl);
14524 
14525  CatalogTupleUpdate(attrel, &newtuple->t_self, newtuple);
14526 
14527  InvokeObjectPostAlterHook(RelationRelationId,
14528  RelationGetRelid(rel),
14529  atttableform->attnum);
14530  ObjectAddressSubSet(address, RelationRelationId,
14531  RelationGetRelid(rel), attnum);
14532 
14533  ReleaseSysCache(tuple);
14534 
14535  table_close(attrel, RowExclusiveLock);
14536 
14537  heap_freetuple(newtuple);
14538 
14539  return address;
14540 }
14541 
14542 /*
14543  * ALTER TABLE OWNER
14544  *
14545  * recursing is true if we are recursing from a table to its indexes,
14546  * sequences, or toast table. We don't allow the ownership of those things to
14547  * be changed separately from the parent table. Also, we can skip permission
14548  * checks (this is necessary not just an optimization, else we'd fail to
14549  * handle toast tables properly).
14550  *
14551  * recursing is also true if ALTER TYPE OWNER is calling us to fix up a
14552  * free-standing composite type.
14553  */
14554 void
14555 ATExecChangeOwner(Oid relationOid, Oid newOwnerId, bool recursing, LOCKMODE lockmode)
14556 {
14557  Relation target_rel;
14558  Relation class_rel;
14559  HeapTuple tuple;
14560  Form_pg_class tuple_class;
14561 
14562  /*
14563  * Get exclusive lock till end of transaction on the target table. Use
14564  * relation_open so that we can work on indexes and sequences.
14565  */
14566  target_rel = relation_open(relationOid, lockmode);
14567 
14568  /* Get its pg_class tuple, too */
14569  class_rel = table_open(RelationRelationId, RowExclusiveLock);
14570 
14571  tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relationOid));
14572  if (!HeapTupleIsValid(tuple))
14573  elog(ERROR, "cache lookup failed for relation %u", relationOid);
14574  tuple_class = (Form_pg_class) GETSTRUCT(tuple);
14575 
14576  /* Can we change the ownership of this tuple? */
14577  switch (tuple_class->relkind)
14578  {
14579  case RELKIND_RELATION:
14580  case RELKIND_VIEW:
14581  case RELKIND_MATVIEW:
14582  case RELKIND_FOREIGN_TABLE:
14583  case RELKIND_PARTITIONED_TABLE:
14584  /* ok to change owner */
14585  break;
14586  case RELKIND_INDEX:
14587  if (!recursing)
14588  {
14589  /*
14590  * Because ALTER INDEX OWNER used to be allowed, and in fact
14591  * is generated by old versions of pg_dump, we give a warning
14592  * and do nothing rather than erroring out. Also, to avoid
14593  * unnecessary chatter while restoring those old dumps, say
14594  * nothing at all if the command would be a no-op anyway.
14595  */
14596  if (tuple_class->relowner != newOwnerId)
14597  ereport(WARNING,
14598  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
14599  errmsg("cannot change owner of index \"%s\"",
14600  NameStr(tuple_class->relname)),
14601  errhint("Change the ownership of the index's table instead.")));
14602  /* quick hack to exit via the no-op path */
14603  newOwnerId = tuple_class->relowner;
14604  }
14605  break;
14606  case RELKIND_PARTITIONED_INDEX:
14607  if (recursing)
14608  break;
14609  ereport(ERROR,
14610  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
14611  errmsg("cannot change owner of index \"%s\"",
14612  NameStr(tuple_class->relname)),
14613  errhint("Change the ownership of the index's table instead.")));
14614  break;
14615  case RELKIND_SEQUENCE:
14616  if (!recursing &&
14617  tuple_class->relowner != newOwnerId)
14618  {
14619  /* if it's an owned sequence, disallow changing it by itself */
14620  Oid tableId;
14621  int32 colId;
14622 
14623  if (sequenceIsOwned(relationOid, DEPENDENCY_AUTO, &tableId, &colId) ||
14624  sequenceIsOwned(relationOid, DEPENDENCY_INTERNAL, &tableId, &colId))
14625  ereport(ERROR,
14626  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
14627  errmsg("cannot change owner of sequence \"%s\"",
14628  NameStr(tuple_class->relname)),
14629  errdetail("Sequence \"%s\" is linked to table \"%s\".",
14630  NameStr(tuple_class->relname),
14631  get_rel_name(tableId))));
14632  }
14633  break;
14634  case RELKIND_COMPOSITE_TYPE:
14635  if (recursing)
14636  break;
14637  ereport(ERROR,
14638  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
14639  errmsg("\"%s\" is a composite type",
14640  NameStr(tuple_class->relname)),
14641  /* translator: %s is an SQL ALTER command */
14642  errhint("Use %s instead.",
14643  "ALTER TYPE")));
14644  break;
14645  case RELKIND_TOASTVALUE:
14646  if (recursing)
14647  break;
14648  /* FALL THRU */
14649  default:
14650  ereport(ERROR,
14651  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
14652  errmsg("cannot change owner of relation \"%s\"",
14653  NameStr(tuple_class->relname)),
14654  errdetail_relkind_not_supported(tuple_class->relkind)));
14655  }
14656 
14657  /*
14658  * If the new owner is the same as the existing owner, consider the
14659  * command to have succeeded. This is for dump restoration purposes.
14660  */
14661  if (tuple_class->relowner != newOwnerId)
14662  {
14663  Datum repl_val[Natts_pg_class];
14664  bool repl_null[Natts_pg_class];
14665  bool repl_repl[Natts_pg_class];
14666  Acl *newAcl;
14667  Datum aclDatum;
14668  bool isNull;
14669  HeapTuple newtuple;
14670 
14671  /* skip permission checks when recursing to index or toast table */
14672  if (!recursing)
14673  {
14674  /* Superusers can always do it */
14675  if (!superuser())
14676  {
14677  Oid namespaceOid = tuple_class->relnamespace;
14678  AclResult aclresult;
14679 
14680  /* Otherwise, must be owner of the existing object */
14681  if (!object_ownercheck(RelationRelationId, relationOid, GetUserId()))
14683  RelationGetRelationName(target_rel));
14684 
14685  /* Must be able to become new owner */
14686  check_can_set_role(GetUserId(), newOwnerId);
14687 
14688  /* New owner must have CREATE privilege on namespace */
14689  aclresult = object_aclcheck(NamespaceRelationId, namespaceOid, newOwnerId,
14690  ACL_CREATE);
14691  if (aclresult != ACLCHECK_OK)
14692  aclcheck_error(aclresult, OBJECT_SCHEMA,
14693  get_namespace_name(namespaceOid));
14694  }
14695  }
14696 
14697  memset(repl_null, false, sizeof(repl_null));
14698  memset(repl_repl, false, sizeof(repl_repl));
14699 
14700  repl_repl[Anum_pg_class_relowner - 1] = true;
14701  repl_val[Anum_pg_class_relowner - 1] = ObjectIdGetDatum(newOwnerId);
14702 
14703  /*
14704  * Determine the modified ACL for the new owner. This is only
14705  * necessary when the ACL is non-null.
14706  */
14707  aclDatum = SysCacheGetAttr(RELOID, tuple,
14708  Anum_pg_class_relacl,
14709  &isNull);
14710  if (!isNull)
14711  {
14712  newAcl = aclnewowner(DatumGetAclP(aclDatum),
14713  tuple_class->relowner, newOwnerId);
14714  repl_repl[Anum_pg_class_relacl - 1] = true;
14715  repl_val[Anum_pg_class_relacl - 1] = PointerGetDatum(newAcl);
14716  }
14717 
14718  newtuple = heap_modify_tuple(tuple, RelationGetDescr(class_rel), repl_val, repl_null, repl_repl);
14719 
14720  CatalogTupleUpdate(class_rel, &newtuple->t_self, newtuple);
14721 
14722  heap_freetuple(newtuple);
14723 
14724  /*
14725  * We must similarly update any per-column ACLs to reflect the new
14726  * owner; for neatness reasons that's split out as a subroutine.
14727  */
14728  change_owner_fix_column_acls(relationOid,
14729  tuple_class->relowner,
14730  newOwnerId);
14731 
14732  /*
14733  * Update owner dependency reference, if any. A composite type has
14734  * none, because it's tracked for the pg_type entry instead of here;
14735  * indexes and TOAST tables don't have their own entries either.
14736  */
14737  if (tuple_class->relkind != RELKIND_COMPOSITE_TYPE &&
14738  tuple_class->relkind != RELKIND_INDEX &&
14739  tuple_class->relkind != RELKIND_PARTITIONED_INDEX &&
14740  tuple_class->relkind != RELKIND_TOASTVALUE)
14741  changeDependencyOnOwner(RelationRelationId, relationOid,
14742  newOwnerId);
14743 
14744  /*
14745  * Also change the ownership of the table's row type, if it has one
14746  */
14747  if (OidIsValid(tuple_class->reltype))
14748  AlterTypeOwnerInternal(tuple_class->reltype, newOwnerId);
14749 
14750  /*
14751  * If we are operating on a table or materialized view, also change
14752  * the ownership of any indexes and sequences that belong to the
14753  * relation, as well as its toast table (if it has one).
14754  */
14755  if (tuple_class->relkind == RELKIND_RELATION ||
14756  tuple_class->relkind == RELKIND_PARTITIONED_TABLE ||
14757  tuple_class->relkind == RELKIND_MATVIEW ||
14758  tuple_class->relkind == RELKIND_TOASTVALUE)
14759  {
14760  List *index_oid_list;
14761  ListCell *i;
14762 
14763  /* Find all the indexes belonging to this relation */
14764  index_oid_list = RelationGetIndexList(target_rel);
14765 
14766  /* For each index, recursively change its ownership */
14767  foreach(i, index_oid_list)
14768  ATExecChangeOwner(lfirst_oid(i), newOwnerId, true, lockmode);
14769 
14770  list_free(index_oid_list);
14771  }
14772 
14773  /* If it has a toast table, recurse to change its ownership */
14774  if (tuple_class->reltoastrelid != InvalidOid)
14775  ATExecChangeOwner(tuple_class->reltoastrelid, newOwnerId,
14776  true, lockmode);
14777 
14778  /* If it has dependent sequences, recurse to change them too */
14779  change_owner_recurse_to_sequences(relationOid, newOwnerId, lockmode);
14780  }
14781 
14782  InvokeObjectPostAlterHook(RelationRelationId, relationOid, 0);
14783 
14784  ReleaseSysCache(tuple);
14785  table_close(class_rel, RowExclusiveLock);
14786  relation_close(target_rel, NoLock);
14787 }
14788 
14789 /*
14790  * change_owner_fix_column_acls
14791  *
14792  * Helper function for ATExecChangeOwner. Scan the columns of the table
14793  * and fix any non-null column ACLs to reflect the new owner.
14794  */
14795 static void
14796 change_owner_fix_column_acls(Oid relationOid, Oid oldOwnerId, Oid newOwnerId)
14797 {
14798  Relation attRelation;
14799  SysScanDesc scan;
14800  ScanKeyData key[1];
14801  HeapTuple attributeTuple;
14802 
14803  attRelation = table_open(AttributeRelationId, RowExclusiveLock);
14804  ScanKeyInit(&key[0],
14805  Anum_pg_attribute_attrelid,
14806  BTEqualStrategyNumber, F_OIDEQ,
14807  ObjectIdGetDatum(relationOid));
14808  scan = systable_beginscan(attRelation, AttributeRelidNumIndexId,
14809  true, NULL, 1, key);
14810  while (HeapTupleIsValid(attributeTuple = systable_getnext(scan)))
14811  {
14812  Form_pg_attribute att = (Form_pg_attribute) GETSTRUCT(attributeTuple);
14813  Datum repl_val[Natts_pg_attribute];
14814  bool repl_null[Natts_pg_attribute];
14815  bool repl_repl[Natts_pg_attribute];
14816  Acl *newAcl;
14817  Datum aclDatum;
14818  bool isNull;
14819  HeapTuple newtuple;
14820 
14821  /* Ignore dropped columns */
14822  if (att->attisdropped)
14823  continue;
14824 
14825  aclDatum = heap_getattr(attributeTuple,
14826  Anum_pg_attribute_attacl,
14827  RelationGetDescr(attRelation),
14828  &isNull);
14829  /* Null ACLs do not require changes */
14830  if (isNull)
14831  continue;
14832 
14833  memset(repl_null, false, sizeof(repl_null));
14834  memset(repl_repl, false, sizeof(repl_repl));
14835 
14836  newAcl = aclnewowner(DatumGetAclP(aclDatum),
14837  oldOwnerId, newOwnerId);
14838  repl_repl[Anum_pg_attribute_attacl - 1] = true;
14839  repl_val[Anum_pg_attribute_attacl - 1] = PointerGetDatum(newAcl);
14840 
14841  newtuple = heap_modify_tuple(attributeTuple,
14842  RelationGetDescr(attRelation),
14843  repl_val, repl_null, repl_repl);
14844 
14845  CatalogTupleUpdate(attRelation, &newtuple->t_self, newtuple);
14846 
14847  heap_freetuple(newtuple);
14848  }
14849  systable_endscan(scan);
14850  table_close(attRelation, RowExclusiveLock);
14851 }
14852 
14853 /*
14854  * change_owner_recurse_to_sequences
14855  *
14856  * Helper function for ATExecChangeOwner. Examines pg_depend searching
14857  * for sequences that are dependent on serial columns, and changes their
14858  * ownership.
14859  */
14860 static void
14861 change_owner_recurse_to_sequences(Oid relationOid, Oid newOwnerId, LOCKMODE lockmode)
14862 {
14863  Relation depRel;
14864  SysScanDesc scan;
14865  ScanKeyData key[2];
14866  HeapTuple tup;
14867 
14868  /*
14869  * SERIAL sequences are those having an auto dependency on one of the
14870  * table's columns (we don't care *which* column, exactly).
14871  */
14872  depRel = table_open(DependRelationId, AccessShareLock);
14873 
14874  ScanKeyInit(&key[0],
14875  Anum_pg_depend_refclassid,
14876  BTEqualStrategyNumber, F_OIDEQ,
14877  ObjectIdGetDatum(RelationRelationId));
14878  ScanKeyInit(&key[1],
14879  Anum_pg_depend_refobjid,
14880  BTEqualStrategyNumber, F_OIDEQ,
14881  ObjectIdGetDatum(relationOid));
14882  /* we leave refobjsubid unspecified */
14883 
14884  scan = systable_beginscan(depRel, DependReferenceIndexId, true,
14885  NULL, 2, key);
14886 
14887  while (HeapTupleIsValid(tup = systable_getnext(scan)))
14888  {
14889  Form_pg_depend depForm = (Form_pg_depend) GETSTRUCT(tup);
14890  Relation seqRel;
14891 
14892  /* skip dependencies other than auto dependencies on columns */
14893  if (depForm->refobjsubid == 0 ||
14894  depForm->classid != RelationRelationId ||
14895  depForm->objsubid != 0 ||
14896  !(depForm->deptype == DEPENDENCY_AUTO || depForm->deptype == DEPENDENCY_INTERNAL))
14897  continue;
14898 
14899  /* Use relation_open just in case it's an index */
14900  seqRel = relation_open(depForm->objid, lockmode);
14901 
14902  /* skip non-sequence relations */
14903  if (RelationGetForm(seqRel)->relkind != RELKIND_SEQUENCE)
14904  {
14905  /* No need to keep the lock */
14906  relation_close(seqRel, lockmode);
14907  continue;
14908  }
14909 
14910  /* We don't need to close the sequence while we alter it. */
14911  ATExecChangeOwner(depForm->objid, newOwnerId, true, lockmode);
14912 
14913  /* Now we can close it. Keep the lock till end of transaction. */
14914  relation_close(seqRel, NoLock);
14915  }
14916 
14917  systable_endscan(scan);
14918 
14920 }
14921 
14922 /*
14923  * ALTER TABLE CLUSTER ON
14924  *
14925  * The only thing we have to do is to change the indisclustered bits.
14926  *
14927  * Return the address of the new clustering index.
14928  */
14929 static ObjectAddress
14930 ATExecClusterOn(Relation rel, const char *indexName, LOCKMODE lockmode)
14931 {
14932  Oid indexOid;
14933  ObjectAddress address;
14934 
14935  indexOid = get_relname_relid(indexName, rel->rd_rel->relnamespace);
14936 
14937  if (!OidIsValid(indexOid))
14938  ereport(ERROR,
14939  (errcode(ERRCODE_UNDEFINED_OBJECT),
14940  errmsg("index \"%s\" for table \"%s\" does not exist",
14941  indexName, RelationGetRelationName(rel))));
14942 
14943  /* Check index is valid to cluster on */
14944  check_index_is_clusterable(rel, indexOid, lockmode);
14945 
14946  /* And do the work */
14947  mark_index_clustered(rel, indexOid, false);
14948 
14949  ObjectAddressSet(address,
14950  RelationRelationId, indexOid);
14951 
14952  return address;
14953 }
14954 
14955 /*
14956  * ALTER TABLE SET WITHOUT CLUSTER
14957  *
14958  * We have to find any indexes on the table that have indisclustered bit
14959  * set and turn it off.
14960  */
14961 static void
14963 {
14964  mark_index_clustered(rel, InvalidOid, false);
14965 }
14966 
14967 /*
14968  * Preparation phase for SET ACCESS METHOD
14969  *
14970  * Check that the access method exists and determine whether a change is
14971  * actually needed.
14972  */
14973 static void
14974 ATPrepSetAccessMethod(AlteredTableInfo *tab, Relation rel, const char *amname)
14975 {
14976  Oid amoid;
14977 
14978  /*
14979  * Look up the access method name and check that it differs from the
14980  * table's current AM. If DEFAULT was specified for a partitioned table
14981  * (amname is NULL), set it to InvalidOid to reset the catalogued AM.
14982  */
14983  if (amname != NULL)
14984  amoid = get_table_am_oid(amname, false);
14985  else if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
14986  amoid = InvalidOid;
14987  else
14989 
14990  /* if it's a match, phase 3 doesn't need to do anything */
14991  if (rel->rd_rel->relam == amoid)
14992  return;
14993 
14994  /* Save info for Phase 3 to do the real work */
14996  tab->newAccessMethod = amoid;
14997  tab->chgAccessMethod = true;
14998 }
14999 
15000 /*
15001  * Special handling of ALTER TABLE SET ACCESS METHOD for relations with no
15002  * storage that have an interest in preserving AM.
15003  *
15004  * Since these have no storage, setting the access method is a catalog only
15005  * operation.
15006  */
15007 static void
15009 {
15010  Relation pg_class;
15011  Oid oldAccessMethodId;
15012  HeapTuple tuple;
15013  Form_pg_class rd_rel;
15014  Oid reloid = RelationGetRelid(rel);
15015 
15016  /*
15017  * Shouldn't be called on relations having storage; these are processed in
15018  * phase 3.
15019  */
15020  Assert(!RELKIND_HAS_STORAGE(rel->rd_rel->relkind));
15021 
15022  /* Get a modifiable copy of the relation's pg_class row. */
15023  pg_class = table_open(RelationRelationId, RowExclusiveLock);
15024 
15025  tuple = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(reloid));
15026  if (!HeapTupleIsValid(tuple))
15027  elog(ERROR, "cache lookup failed for relation %u", reloid);
15028  rd_rel = (Form_pg_class) GETSTRUCT(tuple);
15029 
15030  /* Update the pg_class row. */
15031  oldAccessMethodId = rd_rel->relam;
15032  rd_rel->relam = newAccessMethodId;
15033 
15034  /* Leave if no update required */
15035  if (rd_rel->relam == oldAccessMethodId)
15036  {
15037  heap_freetuple(tuple);
15038  table_close(pg_class, RowExclusiveLock);
15039  return;
15040  }
15041 
15042  CatalogTupleUpdate(pg_class, &tuple->t_self, tuple);
15043 
15044  /*
15045  * Update the dependency on the new access method. No dependency is added
15046  * if the new access method is InvalidOid (default case). Be very careful
15047  * that this has to compare the previous value stored in pg_class with the
15048  * new one.
15049  */
15050  if (!OidIsValid(oldAccessMethodId) && OidIsValid(rd_rel->relam))
15051  {
15052  ObjectAddress relobj,
15053  referenced;
15054 
15055  /*
15056  * New access method is defined and there was no dependency
15057  * previously, so record a new one.
15058  */
15059  ObjectAddressSet(relobj, RelationRelationId, reloid);
15060  ObjectAddressSet(referenced, AccessMethodRelationId, rd_rel->relam);
15061  recordDependencyOn(&relobj, &referenced, DEPENDENCY_NORMAL);
15062  }
15063  else if (OidIsValid(oldAccessMethodId) &&
15064  !OidIsValid(rd_rel->relam))
15065  {
15066  /*
15067  * There was an access method defined, and no new one, so just remove
15068  * the existing dependency.
15069  */
15070  deleteDependencyRecordsForClass(RelationRelationId, reloid,
15071  AccessMethodRelationId,
15073  }
15074  else
15075  {
15076  Assert(OidIsValid(oldAccessMethodId) &&
15077  OidIsValid(rd_rel->relam));
15078 
15079  /* Both are valid, so update the dependency */
15080  changeDependencyFor(RelationRelationId, reloid,
15081  AccessMethodRelationId,
15082  oldAccessMethodId, rd_rel->relam);
15083  }
15084 
15085  /* make the relam and dependency changes visible */
15087 
15088  InvokeObjectPostAlterHook(RelationRelationId, RelationGetRelid(rel), 0);
15089 
15090  heap_freetuple(tuple);
15091  table_close(pg_class, RowExclusiveLock);
15092 }
15093 
15094 /*
15095  * ALTER TABLE SET TABLESPACE
15096  */
15097 static void
15098 ATPrepSetTableSpace(AlteredTableInfo *tab, Relation rel, const char *tablespacename, LOCKMODE lockmode)
15099 {
15100  Oid tablespaceId;
15101 
15102  /* Check that the tablespace exists */
15103  tablespaceId = get_tablespace_oid(tablespacename, false);
15104 
15105  /* Check permissions except when moving to database's default */
15106  if (OidIsValid(tablespaceId) && tablespaceId != MyDatabaseTableSpace)
15107  {
15108  AclResult aclresult;
15109 
15110  aclresult = object_aclcheck(TableSpaceRelationId, tablespaceId, GetUserId(), ACL_CREATE);
15111  if (aclresult != ACLCHECK_OK)
15112  aclcheck_error(aclresult, OBJECT_TABLESPACE, tablespacename);
15113  }
15114 
15115  /* Save info for Phase 3 to do the real work */
15116  if (OidIsValid(tab->newTableSpace))
15117  ereport(ERROR,
15118  (errcode(ERRCODE_SYNTAX_ERROR),
15119  errmsg("cannot have multiple SET TABLESPACE subcommands")));
15120 
15121  tab->newTableSpace = tablespaceId;
15122 }
15123 
15124 /*
15125  * Set, reset, or replace reloptions.
15126  */
15127 static void
15129  LOCKMODE lockmode)
15130 {
15131  Oid relid;
15132  Relation pgclass;
15133  HeapTuple tuple;
15134  HeapTuple newtuple;
15135  Datum datum;
15136  bool isnull;
15137  Datum newOptions;
15138  Datum repl_val[Natts_pg_class];
15139  bool repl_null[Natts_pg_class];
15140  bool repl_repl[Natts_pg_class];
15141  const char *const validnsps[] = HEAP_RELOPT_NAMESPACES;
15142 
15143  if (defList == NIL && operation != AT_ReplaceRelOptions)
15144  return; /* nothing to do */
15145 
15146  pgclass = table_open(RelationRelationId, RowExclusiveLock);
15147 
15148  /* Fetch heap tuple */
15149  relid = RelationGetRelid(rel);
15150  tuple = SearchSysCacheLocked1(RELOID, ObjectIdGetDatum(relid));
15151  if (!HeapTupleIsValid(tuple))
15152  elog(ERROR, "cache lookup failed for relation %u", relid);
15153 
15154  if (operation == AT_ReplaceRelOptions)
15155  {
15156  /*
15157  * If we're supposed to replace the reloptions list, we just pretend
15158  * there were none before.
15159  */
15160  datum = (Datum) 0;
15161  isnull = true;
15162  }
15163  else
15164  {
15165  /* Get the old reloptions */
15166  datum = SysCacheGetAttr(RELOID, tuple, Anum_pg_class_reloptions,
15167  &isnull);
15168  }
15169 
15170  /* Generate new proposed reloptions (text array) */
15171  newOptions = transformRelOptions(isnull ? (Datum) 0 : datum,
15172  defList, NULL, validnsps, false,
15173  operation == AT_ResetRelOptions);
15174 
15175  /* Validate */
15176  switch (rel->rd_rel->relkind)
15177  {
15178  case RELKIND_RELATION:
15179  case RELKIND_TOASTVALUE:
15180  case RELKIND_MATVIEW:
15181  (void) heap_reloptions(rel->rd_rel->relkind, newOptions, true);
15182  break;
15183  case RELKIND_PARTITIONED_TABLE:
15184  (void) partitioned_table_reloptions(newOptions, true);
15185  break;
15186  case RELKIND_VIEW:
15187  (void) view_reloptions(newOptions, true);
15188  break;
15189  case RELKIND_INDEX:
15190  case RELKIND_PARTITIONED_INDEX:
15191  (void) index_reloptions(rel->rd_indam->amoptions, newOptions, true);
15192  break;
15193  default:
15194  ereport(ERROR,
15195  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
15196  errmsg("cannot set options for relation \"%s\"",
15198  errdetail_relkind_not_supported(rel->rd_rel->relkind)));
15199  break;
15200  }
15201 
15202  /* Special-case validation of view options */
15203  if (rel->rd_rel->relkind == RELKIND_VIEW)
15204  {
15205  Query *view_query = get_view_query(rel);
15206  List *view_options = untransformRelOptions(newOptions);
15207  ListCell *cell;
15208  bool check_option = false;
15209 
15210  foreach(cell, view_options)
15211  {
15212  DefElem *defel = (DefElem *) lfirst(cell);
15213 
15214  if (strcmp(defel->defname, "check_option") == 0)
15215  check_option = true;
15216  }
15217 
15218  /*
15219  * If the check option is specified, look to see if the view is
15220  * actually auto-updatable or not.
15221  */
15222  if (check_option)
15223  {
15224  const char *view_updatable_error =
15225  view_query_is_auto_updatable(view_query, true);
15226 
15227  if (view_updatable_error)
15228  ereport(ERROR,
15229  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
15230  errmsg("WITH CHECK OPTION is supported only on automatically updatable views"),
15231  errhint("%s", _(view_updatable_error))));
15232  }
15233  }
15234 
15235  /*
15236  * All we need do here is update the pg_class row; the new options will be
15237  * propagated into relcaches during post-commit cache inval.
15238  */
15239  memset(repl_val, 0, sizeof(repl_val));
15240  memset(repl_null, false, sizeof(repl_null));
15241  memset(repl_repl, false, sizeof(repl_repl));
15242 
15243  if (newOptions != (Datum) 0)
15244  repl_val[Anum_pg_class_reloptions - 1] = newOptions;
15245  else
15246  repl_null[Anum_pg_class_reloptions - 1] = true;
15247 
15248  repl_repl[Anum_pg_class_reloptions - 1] = true;
15249 
15250  newtuple = heap_modify_tuple(tuple, RelationGetDescr(pgclass),
15251  repl_val, repl_null, repl_repl);
15252 
15253  CatalogTupleUpdate(pgclass, &newtuple->t_self, newtuple);
15254  UnlockTuple(pgclass, &tuple->t_self, InplaceUpdateTupleLock);
15255 
15256  InvokeObjectPostAlterHook(RelationRelationId, RelationGetRelid(rel), 0);
15257 
15258  heap_freetuple(newtuple);
15259 
15260  ReleaseSysCache(tuple);
15261 
15262  /* repeat the whole exercise for the toast table, if there's one */
15263  if (OidIsValid(rel->rd_rel->reltoastrelid))
15264  {
15265  Relation toastrel;
15266  Oid toastid = rel->rd_rel->reltoastrelid;
15267 
15268  toastrel = table_open(toastid, lockmode);
15269 
15270  /* Fetch heap tuple */
15271  tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(toastid));
15272  if (!HeapTupleIsValid(tuple))
15273  elog(ERROR, "cache lookup failed for relation %u", toastid);
15274 
15275  if (operation == AT_ReplaceRelOptions)
15276  {
15277  /*
15278  * If we're supposed to replace the reloptions list, we just
15279  * pretend there were none before.
15280  */
15281  datum = (Datum) 0;
15282  isnull = true;
15283  }
15284  else
15285  {
15286  /* Get the old reloptions */
15287  datum = SysCacheGetAttr(RELOID, tuple, Anum_pg_class_reloptions,
15288  &isnull);
15289  }
15290 
15291  newOptions = transformRelOptions(isnull ? (Datum) 0 : datum,
15292  defList, "toast", validnsps, false,
15293  operation == AT_ResetRelOptions);
15294 
15295  (void) heap_reloptions(RELKIND_TOASTVALUE, newOptions, true);
15296 
15297  memset(repl_val, 0, sizeof(repl_val));
15298  memset(repl_null, false, sizeof(repl_null));
15299  memset(repl_repl, false, sizeof(repl_repl));
15300 
15301  if (newOptions != (Datum) 0)
15302  repl_val[Anum_pg_class_reloptions - 1] = newOptions;
15303  else
15304  repl_null[Anum_pg_class_reloptions - 1] = true;
15305 
15306  repl_repl[Anum_pg_class_reloptions - 1] = true;
15307 
15308  newtuple = heap_modify_tuple(tuple, RelationGetDescr(pgclass),
15309  repl_val, repl_null, repl_repl);
15310 
15311  CatalogTupleUpdate(pgclass, &newtuple->t_self, newtuple);
15312 
15313  InvokeObjectPostAlterHookArg(RelationRelationId,
15314  RelationGetRelid(toastrel), 0,
15315  InvalidOid, true);
15316 
15317  heap_freetuple(newtuple);
15318 
15319  ReleaseSysCache(tuple);
15320 
15321  table_close(toastrel, NoLock);
15322  }
15323 
15324  table_close(pgclass, RowExclusiveLock);
15325 }
15326 
15327 /*
15328  * Execute ALTER TABLE SET TABLESPACE for cases where there is no tuple
15329  * rewriting to be done, so we just want to copy the data as fast as possible.
15330  */
15331 static void
15332 ATExecSetTableSpace(Oid tableOid, Oid newTableSpace, LOCKMODE lockmode)
15333 {
15334  Relation rel;
15335  Oid reltoastrelid;
15336  RelFileNumber newrelfilenumber;
15337  RelFileLocator newrlocator;
15338  List *reltoastidxids = NIL;
15339  ListCell *lc;
15340 
15341  /*
15342  * Need lock here in case we are recursing to toast table or index
15343  */
15344  rel = relation_open(tableOid, lockmode);
15345 
15346  /* Check first if relation can be moved to new tablespace */
15347  if (!CheckRelationTableSpaceMove(rel, newTableSpace))
15348  {
15349  InvokeObjectPostAlterHook(RelationRelationId,
15350  RelationGetRelid(rel), 0);
15351  relation_close(rel, NoLock);
15352  return;
15353  }
15354 
15355  reltoastrelid = rel->rd_rel->reltoastrelid;
15356  /* Fetch the list of indexes on toast relation if necessary */
15357  if (OidIsValid(reltoastrelid))
15358  {
15359  Relation toastRel = relation_open(reltoastrelid, lockmode);
15360 
15361  reltoastidxids = RelationGetIndexList(toastRel);
15362  relation_close(toastRel, lockmode);
15363  }
15364 
15365  /*
15366  * Relfilenumbers are not unique in databases across tablespaces, so we
15367  * need to allocate a new one in the new tablespace.
15368  */
15369  newrelfilenumber = GetNewRelFileNumber(newTableSpace, NULL,
15370  rel->rd_rel->relpersistence);
15371 
15372  /* Open old and new relation */
15373  newrlocator = rel->rd_locator;
15374  newrlocator.relNumber = newrelfilenumber;
15375  newrlocator.spcOid = newTableSpace;
15376 
15377  /* hand off to AM to actually create new rel storage and copy the data */
15378  if (rel->rd_rel->relkind == RELKIND_INDEX)
15379  {
15380  index_copy_data(rel, newrlocator);
15381  }
15382  else
15383  {
15384  Assert(RELKIND_HAS_TABLE_AM(rel->rd_rel->relkind));
15385  table_relation_copy_data(rel, &newrlocator);
15386  }
15387 
15388  /*
15389  * Update the pg_class row.
15390  *
15391  * NB: This wouldn't work if ATExecSetTableSpace() were allowed to be
15392  * executed on pg_class or its indexes (the above copy wouldn't contain
15393  * the updated pg_class entry), but that's forbidden with
15394  * CheckRelationTableSpaceMove().
15395  */
15396  SetRelationTableSpace(rel, newTableSpace, newrelfilenumber);
15397 
15398  InvokeObjectPostAlterHook(RelationRelationId, RelationGetRelid(rel), 0);
15399 
15401 
15402  relation_close(rel, NoLock);
15403 
15404  /* Make sure the reltablespace change is visible */
15406 
15407  /* Move associated toast relation and/or indexes, too */
15408  if (OidIsValid(reltoastrelid))
15409  ATExecSetTableSpace(reltoastrelid, newTableSpace, lockmode);
15410  foreach(lc, reltoastidxids)
15411  ATExecSetTableSpace(lfirst_oid(lc), newTableSpace, lockmode);
15412 
15413  /* Clean up */
15414  list_free(reltoastidxids);
15415 }
15416 
15417 /*
15418  * Special handling of ALTER TABLE SET TABLESPACE for relations with no
15419  * storage that have an interest in preserving tablespace.
15420  *
15421  * Since these have no storage the tablespace can be updated with a simple
15422  * metadata only operation to update the tablespace.
15423  */
15424 static void
15426 {
15427  /*
15428  * Shouldn't be called on relations having storage; these are processed in
15429  * phase 3.
15430  */
15431  Assert(!RELKIND_HAS_STORAGE(rel->rd_rel->relkind));
15432 
15433  /* check if relation can be moved to its new tablespace */
15434  if (!CheckRelationTableSpaceMove(rel, newTableSpace))
15435  {
15436  InvokeObjectPostAlterHook(RelationRelationId,
15437  RelationGetRelid(rel),
15438  0);
15439  return;
15440  }
15441 
15442  /* Update can be done, so change reltablespace */
15443  SetRelationTableSpace(rel, newTableSpace, InvalidOid);
15444 
15445  InvokeObjectPostAlterHook(RelationRelationId, RelationGetRelid(rel), 0);
15446 
15447  /* Make sure the reltablespace change is visible */
15449 }
15450 
15451 /*
15452  * Alter Table ALL ... SET TABLESPACE
15453  *
15454  * Allows a user to move all objects of some type in a given tablespace in the
15455  * current database to another tablespace. Objects can be chosen based on the
15456  * owner of the object also, to allow users to move only their objects.
15457  * The user must have CREATE rights on the new tablespace, as usual. The main
15458  * permissions handling is done by the lower-level table move function.
15459  *
15460  * All to-be-moved objects are locked first. If NOWAIT is specified and the
15461  * lock can't be acquired then we ereport(ERROR).
15462  */
15463 Oid
15465 {
15466  List *relations = NIL;
15467  ListCell *l;
15468  ScanKeyData key[1];
15469  Relation rel;
15470  TableScanDesc scan;
15471  HeapTuple tuple;
15472  Oid orig_tablespaceoid;
15473  Oid new_tablespaceoid;
15474  List *role_oids = roleSpecsToIds(stmt->roles);
15475 
15476  /* Ensure we were not asked to move something we can't */
15477  if (stmt->objtype != OBJECT_TABLE && stmt->objtype != OBJECT_INDEX &&
15478  stmt->objtype != OBJECT_MATVIEW)
15479  ereport(ERROR,
15480  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
15481  errmsg("only tables, indexes, and materialized views exist in tablespaces")));
15482 
15483  /* Get the orig and new tablespace OIDs */
15484  orig_tablespaceoid = get_tablespace_oid(stmt->orig_tablespacename, false);
15485  new_tablespaceoid = get_tablespace_oid(stmt->new_tablespacename, false);
15486 
15487  /* Can't move shared relations in to or out of pg_global */
15488  /* This is also checked by ATExecSetTableSpace, but nice to stop earlier */
15489  if (orig_tablespaceoid == GLOBALTABLESPACE_OID ||
15490  new_tablespaceoid == GLOBALTABLESPACE_OID)
15491  ereport(ERROR,
15492  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
15493  errmsg("cannot move relations in to or out of pg_global tablespace")));
15494 
15495  /*
15496  * Must have CREATE rights on the new tablespace, unless it is the
15497  * database default tablespace (which all users implicitly have CREATE
15498  * rights on).
15499  */
15500  if (OidIsValid(new_tablespaceoid) && new_tablespaceoid != MyDatabaseTableSpace)
15501  {
15502  AclResult aclresult;
15503 
15504  aclresult = object_aclcheck(TableSpaceRelationId, new_tablespaceoid, GetUserId(),
15505  ACL_CREATE);
15506  if (aclresult != ACLCHECK_OK)
15507  aclcheck_error(aclresult, OBJECT_TABLESPACE,
15508  get_tablespace_name(new_tablespaceoid));
15509  }
15510 
15511  /*
15512  * Now that the checks are done, check if we should set either to
15513  * InvalidOid because it is our database's default tablespace.
15514  */
15515  if (orig_tablespaceoid == MyDatabaseTableSpace)
15516  orig_tablespaceoid = InvalidOid;
15517 
15518  if (new_tablespaceoid == MyDatabaseTableSpace)
15519  new_tablespaceoid = InvalidOid;
15520 
15521  /* no-op */
15522  if (orig_tablespaceoid == new_tablespaceoid)
15523  return new_tablespaceoid;
15524 
15525  /*
15526  * Walk the list of objects in the tablespace and move them. This will
15527  * only find objects in our database, of course.
15528  */
15529  ScanKeyInit(&key[0],
15530  Anum_pg_class_reltablespace,
15531  BTEqualStrategyNumber, F_OIDEQ,
15532  ObjectIdGetDatum(orig_tablespaceoid));
15533 
15534  rel = table_open(RelationRelationId, AccessShareLock);
15535  scan = table_beginscan_catalog(rel, 1, key);
15536  while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
15537  {
15538  Form_pg_class relForm = (Form_pg_class) GETSTRUCT(tuple);
15539  Oid relOid = relForm->oid;
15540 
15541  /*
15542  * Do not move objects in pg_catalog as part of this, if an admin
15543  * really wishes to do so, they can issue the individual ALTER
15544  * commands directly.
15545  *
15546  * Also, explicitly avoid any shared tables, temp tables, or TOAST
15547  * (TOAST will be moved with the main table).
15548  */
15549  if (IsCatalogNamespace(relForm->relnamespace) ||
15550  relForm->relisshared ||
15551  isAnyTempNamespace(relForm->relnamespace) ||
15552  IsToastNamespace(relForm->relnamespace))
15553  continue;
15554 
15555  /* Only move the object type requested */
15556  if ((stmt->objtype == OBJECT_TABLE &&
15557  relForm->relkind != RELKIND_RELATION &&
15558  relForm->relkind != RELKIND_PARTITIONED_TABLE) ||
15559  (stmt->objtype == OBJECT_INDEX &&
15560  relForm->relkind != RELKIND_INDEX &&
15561  relForm->relkind != RELKIND_PARTITIONED_INDEX) ||
15562  (stmt->objtype == OBJECT_MATVIEW &&
15563  relForm->relkind != RELKIND_MATVIEW))
15564  continue;
15565 
15566  /* Check if we are only moving objects owned by certain roles */
15567  if (role_oids != NIL && !list_member_oid(role_oids, relForm->relowner))
15568  continue;
15569 
15570  /*
15571  * Handle permissions-checking here since we are locking the tables
15572  * and also to avoid doing a bunch of work only to fail part-way. Note
15573  * that permissions will also be checked by AlterTableInternal().
15574  *
15575  * Caller must be considered an owner on the table to move it.
15576  */
15577  if (!object_ownercheck(RelationRelationId, relOid, GetUserId()))
15579  NameStr(relForm->relname));
15580 
15581  if (stmt->nowait &&
15583  ereport(ERROR,
15584  (errcode(ERRCODE_OBJECT_IN_USE),
15585  errmsg("aborting because lock on relation \"%s.%s\" is not available",
15586  get_namespace_name(relForm->relnamespace),
15587  NameStr(relForm->relname))));
15588  else
15590 
15591  /* Add to our list of objects to move */
15592  relations = lappend_oid(relations, relOid);
15593  }
15594 
15595  table_endscan(scan);
15597 
15598  if (relations == NIL)
15599  ereport(NOTICE,
15600  (errcode(ERRCODE_NO_DATA_FOUND),
15601  errmsg("no matching relations in tablespace \"%s\" found",
15602  orig_tablespaceoid == InvalidOid ? "(database default)" :
15603  get_tablespace_name(orig_tablespaceoid))));
15604 
15605  /* Everything is locked, loop through and move all of the relations. */
15606  foreach(l, relations)
15607  {
15608  List *cmds = NIL;
15610 
15611  cmd->subtype = AT_SetTableSpace;
15612  cmd->name = stmt->new_tablespacename;
15613 
15614  cmds = lappend(cmds, cmd);
15615 
15617  /* OID is set by AlterTableInternal */
15618  AlterTableInternal(lfirst_oid(l), cmds, false);
15620  }
15621 
15622  return new_tablespaceoid;
15623 }
15624 
15625 static void
15627 {
15628  SMgrRelation dstrel;
15629 
15630  /*
15631  * Since we copy the file directly without looking at the shared buffers,
15632  * we'd better first flush out any pages of the source relation that are
15633  * in shared buffers. We assume no new changes will be made while we are
15634  * holding exclusive lock on the rel.
15635  */
15636  FlushRelationBuffers(rel);
15637 
15638  /*
15639  * Create and copy all forks of the relation, and schedule unlinking of
15640  * old physical files.
15641  *
15642  * NOTE: any conflict in relfilenumber value will be caught in
15643  * RelationCreateStorage().
15644  */
15645  dstrel = RelationCreateStorage(newrlocator, rel->rd_rel->relpersistence, true);
15646 
15647  /* copy main fork */
15649  rel->rd_rel->relpersistence);
15650 
15651  /* copy those extra forks that exist */
15652  for (ForkNumber forkNum = MAIN_FORKNUM + 1;
15653  forkNum <= MAX_FORKNUM; forkNum++)
15654  {
15655  if (smgrexists(RelationGetSmgr(rel), forkNum))
15656  {
15657  smgrcreate(dstrel, forkNum, false);
15658 
15659  /*
15660  * WAL log creation if the relation is persistent, or this is the
15661  * init fork of an unlogged relation.
15662  */
15663  if (RelationIsPermanent(rel) ||
15664  (rel->rd_rel->relpersistence == RELPERSISTENCE_UNLOGGED &&
15665  forkNum == INIT_FORKNUM))
15666  log_smgrcreate(&newrlocator, forkNum);
15667  RelationCopyStorage(RelationGetSmgr(rel), dstrel, forkNum,
15668  rel->rd_rel->relpersistence);
15669  }
15670  }
15671 
15672  /* drop old relation, and close new one */
15673  RelationDropStorage(rel);
15674  smgrclose(dstrel);
15675 }
15676 
15677 /*
15678  * ALTER TABLE ENABLE/DISABLE TRIGGER
15679  *
15680  * We just pass this off to trigger.c.
15681  */
15682 static void
15683 ATExecEnableDisableTrigger(Relation rel, const char *trigname,
15684  char fires_when, bool skip_system, bool recurse,
15685  LOCKMODE lockmode)
15686 {
15687  EnableDisableTrigger(rel, trigname, InvalidOid,
15688  fires_when, skip_system, recurse,
15689  lockmode);
15690 
15691  InvokeObjectPostAlterHook(RelationRelationId,
15692  RelationGetRelid(rel), 0);
15693 }
15694 
15695 /*
15696  * ALTER TABLE ENABLE/DISABLE RULE
15697  *
15698  * We just pass this off to rewriteDefine.c.
15699  */
15700 static void
15701 ATExecEnableDisableRule(Relation rel, const char *rulename,
15702  char fires_when, LOCKMODE lockmode)
15703 {
15704  EnableDisableRule(rel, rulename, fires_when);
15705 
15706  InvokeObjectPostAlterHook(RelationRelationId,
15707  RelationGetRelid(rel), 0);
15708 }
15709 
15710 /*
15711  * ALTER TABLE INHERIT
15712  *
15713  * Add a parent to the child's parents. This verifies that all the columns and
15714  * check constraints of the parent appear in the child and that they have the
15715  * same data types and expressions.
15716  */
15717 static void
15719 {
15720  if (child_rel->rd_rel->reloftype)
15721  ereport(ERROR,
15722  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
15723  errmsg("cannot change inheritance of typed table")));
15724 
15725  if (child_rel->rd_rel->relispartition)
15726  ereport(ERROR,
15727  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
15728  errmsg("cannot change inheritance of a partition")));
15729 
15730  if (child_rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
15731  ereport(ERROR,
15732  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
15733  errmsg("cannot change inheritance of partitioned table")));
15734 }
15735 
15736 /*
15737  * Return the address of the new parent relation.
15738  */
15739 static ObjectAddress
15740 ATExecAddInherit(Relation child_rel, RangeVar *parent, LOCKMODE lockmode)
15741 {
15742  Relation parent_rel;
15743  List *children;
15744  ObjectAddress address;
15745  const char *trigger_name;
15746 
15747  /*
15748  * A self-exclusive lock is needed here. See the similar case in
15749  * MergeAttributes() for a full explanation.
15750  */
15751  parent_rel = table_openrv(parent, ShareUpdateExclusiveLock);
15752 
15753  /*
15754  * Must be owner of both parent and child -- child was checked by
15755  * ATSimplePermissions call in ATPrepCmd
15756  */
15757  ATSimplePermissions(AT_AddInherit, parent_rel,
15759 
15760  /* Permanent rels cannot inherit from temporary ones */
15761  if (parent_rel->rd_rel->relpersistence == RELPERSISTENCE_TEMP &&
15762  child_rel->rd_rel->relpersistence != RELPERSISTENCE_TEMP)
15763  ereport(ERROR,
15764  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
15765  errmsg("cannot inherit from temporary relation \"%s\"",
15766  RelationGetRelationName(parent_rel))));
15767 
15768  /* If parent rel is temp, it must belong to this session */
15769  if (parent_rel->rd_rel->relpersistence == RELPERSISTENCE_TEMP &&
15770  !parent_rel->rd_islocaltemp)
15771  ereport(ERROR,
15772  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
15773  errmsg("cannot inherit from temporary relation of another session")));
15774 
15775  /* Ditto for the child */
15776  if (child_rel->rd_rel->relpersistence == RELPERSISTENCE_TEMP &&
15777  !child_rel->rd_islocaltemp)
15778  ereport(ERROR,
15779  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
15780  errmsg("cannot inherit to temporary relation of another session")));
15781 
15782  /* Prevent partitioned tables from becoming inheritance parents */
15783  if (parent_rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
15784  ereport(ERROR,
15785  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
15786  errmsg("cannot inherit from partitioned table \"%s\"",
15787  parent->relname)));
15788 
15789  /* Likewise for partitions */
15790  if (parent_rel->rd_rel->relispartition)
15791  ereport(ERROR,
15792  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
15793  errmsg("cannot inherit from a partition")));
15794 
15795  /*
15796  * Prevent circularity by seeing if proposed parent inherits from child.
15797  * (In particular, this disallows making a rel inherit from itself.)
15798  *
15799  * This is not completely bulletproof because of race conditions: in
15800  * multi-level inheritance trees, someone else could concurrently be
15801  * making another inheritance link that closes the loop but does not join
15802  * either of the rels we have locked. Preventing that seems to require
15803  * exclusive locks on the entire inheritance tree, which is a cure worse
15804  * than the disease. find_all_inheritors() will cope with circularity
15805  * anyway, so don't sweat it too much.
15806  *
15807  * We use weakest lock we can on child's children, namely AccessShareLock.
15808  */
15809  children = find_all_inheritors(RelationGetRelid(child_rel),
15810  AccessShareLock, NULL);
15811 
15812  if (list_member_oid(children, RelationGetRelid(parent_rel)))
15813  ereport(ERROR,
15814  (errcode(ERRCODE_DUPLICATE_TABLE),
15815  errmsg("circular inheritance not allowed"),
15816  errdetail("\"%s\" is already a child of \"%s\".",
15817  parent->relname,
15818  RelationGetRelationName(child_rel))));
15819 
15820  /*
15821  * If child_rel has row-level triggers with transition tables, we
15822  * currently don't allow it to become an inheritance child. See also
15823  * prohibitions in ATExecAttachPartition() and CreateTrigger().
15824  */
15825  trigger_name = FindTriggerIncompatibleWithInheritance(child_rel->trigdesc);
15826  if (trigger_name != NULL)
15827  ereport(ERROR,
15828  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
15829  errmsg("trigger \"%s\" prevents table \"%s\" from becoming an inheritance child",
15830  trigger_name, RelationGetRelationName(child_rel)),
15831  errdetail("ROW triggers with transition tables are not supported in inheritance hierarchies.")));
15832 
15833  /* OK to create inheritance */
15834  CreateInheritance(child_rel, parent_rel, false);
15835 
15836  ObjectAddressSet(address, RelationRelationId,
15837  RelationGetRelid(parent_rel));
15838 
15839  /* keep our lock on the parent relation until commit */
15840  table_close(parent_rel, NoLock);
15841 
15842  return address;
15843 }
15844 
15845 /*
15846  * CreateInheritance
15847  * Catalog manipulation portion of creating inheritance between a child
15848  * table and a parent table.
15849  *
15850  * Common to ATExecAddInherit() and ATExecAttachPartition().
15851  */
15852 static void
15853 CreateInheritance(Relation child_rel, Relation parent_rel, bool ispartition)
15854 {
15855  Relation catalogRelation;
15856  SysScanDesc scan;
15857  ScanKeyData key;
15858  HeapTuple inheritsTuple;
15859  int32 inhseqno;
15860 
15861  /* Note: get RowExclusiveLock because we will write pg_inherits below. */
15862  catalogRelation = table_open(InheritsRelationId, RowExclusiveLock);
15863 
15864  /*
15865  * Check for duplicates in the list of parents, and determine the highest
15866  * inhseqno already present; we'll use the next one for the new parent.
15867  * Also, if proposed child is a partition, it cannot already be
15868  * inheriting.
15869  *
15870  * Note: we do not reject the case where the child already inherits from
15871  * the parent indirectly; CREATE TABLE doesn't reject comparable cases.
15872  */
15873  ScanKeyInit(&key,
15874  Anum_pg_inherits_inhrelid,
15875  BTEqualStrategyNumber, F_OIDEQ,
15876  ObjectIdGetDatum(RelationGetRelid(child_rel)));
15877  scan = systable_beginscan(catalogRelation, InheritsRelidSeqnoIndexId,
15878  true, NULL, 1, &key);
15879 
15880  /* inhseqno sequences start at 1 */
15881  inhseqno = 0;
15882  while (HeapTupleIsValid(inheritsTuple = systable_getnext(scan)))
15883  {
15884  Form_pg_inherits inh = (Form_pg_inherits) GETSTRUCT(inheritsTuple);
15885 
15886  if (inh->inhparent == RelationGetRelid(parent_rel))
15887  ereport(ERROR,
15888  (errcode(ERRCODE_DUPLICATE_TABLE),
15889  errmsg("relation \"%s\" would be inherited from more than once",
15890  RelationGetRelationName(parent_rel))));
15891 
15892  if (inh->inhseqno > inhseqno)
15893  inhseqno = inh->inhseqno;
15894  }
15895  systable_endscan(scan);
15896 
15897  /* Match up the columns and bump attinhcount as needed */
15898  MergeAttributesIntoExisting(child_rel, parent_rel, ispartition);
15899 
15900  /* Match up the constraints and bump coninhcount as needed */
15901  MergeConstraintsIntoExisting(child_rel, parent_rel);
15902 
15903  /*
15904  * OK, it looks valid. Make the catalog entries that show inheritance.
15905  */
15907  RelationGetRelid(parent_rel),
15908  inhseqno + 1,
15909  catalogRelation,
15910  parent_rel->rd_rel->relkind ==
15911  RELKIND_PARTITIONED_TABLE);
15912 
15913  /* Now we're done with pg_inherits */
15914  table_close(catalogRelation, RowExclusiveLock);
15915 }
15916 
15917 /*
15918  * Obtain the source-text form of the constraint expression for a check
15919  * constraint, given its pg_constraint tuple
15920  */
15921 static char *
15923 {
15924  Form_pg_constraint con;
15925  bool isnull;
15926  Datum attr;
15927  Datum expr;
15928 
15929  con = (Form_pg_constraint) GETSTRUCT(contup);
15930  attr = heap_getattr(contup, Anum_pg_constraint_conbin, tupdesc, &isnull);
15931  if (isnull)
15932  elog(ERROR, "null conbin for constraint %u", con->oid);
15933 
15934  expr = DirectFunctionCall2(pg_get_expr, attr,
15935  ObjectIdGetDatum(con->conrelid));
15936  return TextDatumGetCString(expr);
15937 }
15938 
15939 /*
15940  * Determine whether two check constraints are functionally equivalent
15941  *
15942  * The test we apply is to see whether they reverse-compile to the same
15943  * source string. This insulates us from issues like whether attributes
15944  * have the same physical column numbers in parent and child relations.
15945  */
15946 static bool
15948 {
15951 
15952  if (acon->condeferrable != bcon->condeferrable ||
15953  acon->condeferred != bcon->condeferred ||
15954  strcmp(decompile_conbin(a, tupleDesc),
15955  decompile_conbin(b, tupleDesc)) != 0)
15956  return false;
15957  else
15958  return true;
15959 }
15960 
15961 /*
15962  * Check columns in child table match up with columns in parent, and increment
15963  * their attinhcount.
15964  *
15965  * Called by CreateInheritance
15966  *
15967  * Currently all parent columns must be found in child. Missing columns are an
15968  * error. One day we might consider creating new columns like CREATE TABLE
15969  * does. However, that is widely unpopular --- in the common use case of
15970  * partitioned tables it's a foot-gun.
15971  *
15972  * The data type must match exactly. If the parent column is NOT NULL then
15973  * the child must be as well. Defaults are not compared, however.
15974  */
15975 static void
15976 MergeAttributesIntoExisting(Relation child_rel, Relation parent_rel, bool ispartition)
15977 {
15978  Relation attrrel;
15979  TupleDesc parent_desc;
15980 
15981  attrrel = table_open(AttributeRelationId, RowExclusiveLock);
15982  parent_desc = RelationGetDescr(parent_rel);
15983 
15984  for (AttrNumber parent_attno = 1; parent_attno <= parent_desc->natts; parent_attno++)
15985  {
15986  Form_pg_attribute parent_att = TupleDescAttr(parent_desc, parent_attno - 1);
15987  char *parent_attname = NameStr(parent_att->attname);
15988  HeapTuple tuple;
15989 
15990  /* Ignore dropped columns in the parent. */
15991  if (parent_att->attisdropped)
15992  continue;
15993 
15994  /* Find same column in child (matching on column name). */
15995  tuple = SearchSysCacheCopyAttName(RelationGetRelid(child_rel), parent_attname);
15996  if (HeapTupleIsValid(tuple))
15997  {
15998  Form_pg_attribute child_att = (Form_pg_attribute) GETSTRUCT(tuple);
15999 
16000  if (parent_att->atttypid != child_att->atttypid ||
16001  parent_att->atttypmod != child_att->atttypmod)
16002  ereport(ERROR,
16003  (errcode(ERRCODE_DATATYPE_MISMATCH),
16004  errmsg("child table \"%s\" has different type for column \"%s\"",
16005  RelationGetRelationName(child_rel), parent_attname)));
16006 
16007  if (parent_att->attcollation != child_att->attcollation)
16008  ereport(ERROR,
16009  (errcode(ERRCODE_COLLATION_MISMATCH),
16010  errmsg("child table \"%s\" has different collation for column \"%s\"",
16011  RelationGetRelationName(child_rel), parent_attname)));
16012 
16013  /*
16014  * Check child doesn't discard NOT NULL property. (Other
16015  * constraints are checked elsewhere.)
16016  */
16017  if (parent_att->attnotnull && !child_att->attnotnull)
16018  ereport(ERROR,
16019  (errcode(ERRCODE_DATATYPE_MISMATCH),
16020  errmsg("column \"%s\" in child table must be marked NOT NULL",
16021  parent_attname)));
16022 
16023  /*
16024  * Child column must be generated if and only if parent column is.
16025  */
16026  if (parent_att->attgenerated && !child_att->attgenerated)
16027  ereport(ERROR,
16028  (errcode(ERRCODE_DATATYPE_MISMATCH),
16029  errmsg("column \"%s\" in child table must be a generated column", parent_attname)));
16030  if (child_att->attgenerated && !parent_att->attgenerated)
16031  ereport(ERROR,
16032  (errcode(ERRCODE_DATATYPE_MISMATCH),
16033  errmsg("column \"%s\" in child table must not be a generated column", parent_attname)));
16034 
16035  /*
16036  * Regular inheritance children are independent enough not to
16037  * inherit identity columns. But partitions are integral part of
16038  * a partitioned table and inherit identity column.
16039  */
16040  if (ispartition)
16041  child_att->attidentity = parent_att->attidentity;
16042 
16043  /*
16044  * OK, bump the child column's inheritance count. (If we fail
16045  * later on, this change will just roll back.)
16046  */
16047  if (pg_add_s16_overflow(child_att->attinhcount, 1,
16048  &child_att->attinhcount))
16049  ereport(ERROR,
16050  errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
16051  errmsg("too many inheritance parents"));
16052 
16053  /*
16054  * In case of partitions, we must enforce that value of attislocal
16055  * is same in all partitions. (Note: there are only inherited
16056  * attributes in partitions)
16057  */
16058  if (parent_rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
16059  {
16060  Assert(child_att->attinhcount == 1);
16061  child_att->attislocal = false;
16062  }
16063 
16064  CatalogTupleUpdate(attrrel, &tuple->t_self, tuple);
16065  heap_freetuple(tuple);
16066  }
16067  else
16068  {
16069  ereport(ERROR,
16070  (errcode(ERRCODE_DATATYPE_MISMATCH),
16071  errmsg("child table is missing column \"%s\"", parent_attname)));
16072  }
16073  }
16074 
16075  table_close(attrrel, RowExclusiveLock);
16076 }
16077 
16078 /*
16079  * Check constraints in child table match up with constraints in parent,
16080  * and increment their coninhcount.
16081  *
16082  * Constraints that are marked ONLY in the parent are ignored.
16083  *
16084  * Called by CreateInheritance
16085  *
16086  * Currently all constraints in parent must be present in the child. One day we
16087  * may consider adding new constraints like CREATE TABLE does.
16088  *
16089  * XXX This is O(N^2) which may be an issue with tables with hundreds of
16090  * constraints. As long as tables have more like 10 constraints it shouldn't be
16091  * a problem though. Even 100 constraints ought not be the end of the world.
16092  *
16093  * XXX See MergeWithExistingConstraint too if you change this code.
16094  */
16095 static void
16097 {
16098  Relation constraintrel;
16099  SysScanDesc parent_scan;
16100  ScanKeyData parent_key;
16101  HeapTuple parent_tuple;
16102  Oid parent_relid = RelationGetRelid(parent_rel);
16103 
16104  constraintrel = table_open(ConstraintRelationId, RowExclusiveLock);
16105 
16106  /* Outer loop scans through the parent's constraint definitions */
16107  ScanKeyInit(&parent_key,
16108  Anum_pg_constraint_conrelid,
16109  BTEqualStrategyNumber, F_OIDEQ,
16110  ObjectIdGetDatum(parent_relid));
16111  parent_scan = systable_beginscan(constraintrel, ConstraintRelidTypidNameIndexId,
16112  true, NULL, 1, &parent_key);
16113 
16114  while (HeapTupleIsValid(parent_tuple = systable_getnext(parent_scan)))
16115  {
16116  Form_pg_constraint parent_con = (Form_pg_constraint) GETSTRUCT(parent_tuple);
16117  SysScanDesc child_scan;
16118  ScanKeyData child_key;
16119  HeapTuple child_tuple;
16120  bool found = false;
16121 
16122  if (parent_con->contype != CONSTRAINT_CHECK)
16123  continue;
16124 
16125  /* if the parent's constraint is marked NO INHERIT, it's not inherited */
16126  if (parent_con->connoinherit)
16127  continue;
16128 
16129  /* Search for a child constraint matching this one */
16130  ScanKeyInit(&child_key,
16131  Anum_pg_constraint_conrelid,
16132  BTEqualStrategyNumber, F_OIDEQ,
16133  ObjectIdGetDatum(RelationGetRelid(child_rel)));
16134  child_scan = systable_beginscan(constraintrel, ConstraintRelidTypidNameIndexId,
16135  true, NULL, 1, &child_key);
16136 
16137  while (HeapTupleIsValid(child_tuple = systable_getnext(child_scan)))
16138  {
16139  Form_pg_constraint child_con = (Form_pg_constraint) GETSTRUCT(child_tuple);
16140  HeapTuple child_copy;
16141 
16142  if (child_con->contype != CONSTRAINT_CHECK)
16143  continue;
16144 
16145  if (strcmp(NameStr(parent_con->conname),
16146  NameStr(child_con->conname)) != 0)
16147  continue;
16148 
16149  if (!constraints_equivalent(parent_tuple, child_tuple, RelationGetDescr(constraintrel)))
16150  ereport(ERROR,
16151  (errcode(ERRCODE_DATATYPE_MISMATCH),
16152  errmsg("child table \"%s\" has different definition for check constraint \"%s\"",
16153  RelationGetRelationName(child_rel), NameStr(parent_con->conname))));
16154 
16155  /* If the child constraint is "no inherit" then cannot merge */
16156  if (child_con->connoinherit)
16157  ereport(ERROR,
16158  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
16159  errmsg("constraint \"%s\" conflicts with non-inherited constraint on child table \"%s\"",
16160  NameStr(child_con->conname), RelationGetRelationName(child_rel))));
16161 
16162  /*
16163  * If the child constraint is "not valid" then cannot merge with a
16164  * valid parent constraint
16165  */
16166  if (parent_con->convalidated && !child_con->convalidated)
16167  ereport(ERROR,
16168  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
16169  errmsg("constraint \"%s\" conflicts with NOT VALID constraint on child table \"%s\"",
16170  NameStr(child_con->conname), RelationGetRelationName(child_rel))));
16171 
16172  /*
16173  * OK, bump the child constraint's inheritance count. (If we fail
16174  * later on, this change will just roll back.)
16175  */
16176  child_copy = heap_copytuple(child_tuple);
16177  child_con = (Form_pg_constraint) GETSTRUCT(child_copy);
16178 
16179  if (pg_add_s16_overflow(child_con->coninhcount, 1,
16180  &child_con->coninhcount))
16181  ereport(ERROR,
16182  errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
16183  errmsg("too many inheritance parents"));
16184 
16185  /*
16186  * In case of partitions, an inherited constraint must be
16187  * inherited only once since it cannot have multiple parents and
16188  * it is never considered local.
16189  */
16190  if (parent_rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
16191  {
16192  Assert(child_con->coninhcount == 1);
16193  child_con->conislocal = false;
16194  }
16195 
16196  CatalogTupleUpdate(constraintrel, &child_copy->t_self, child_copy);
16197  heap_freetuple(child_copy);
16198 
16199  found = true;
16200  break;
16201  }
16202 
16203  systable_endscan(child_scan);
16204 
16205  if (!found)
16206  ereport(ERROR,
16207  (errcode(ERRCODE_DATATYPE_MISMATCH),
16208  errmsg("child table is missing constraint \"%s\"",
16209  NameStr(parent_con->conname))));
16210  }
16211 
16212  systable_endscan(parent_scan);
16213  table_close(constraintrel, RowExclusiveLock);
16214 }
16215 
16216 /*
16217  * ALTER TABLE NO INHERIT
16218  *
16219  * Return value is the address of the relation that is no longer parent.
16220  */
16221 static ObjectAddress
16223 {
16224  ObjectAddress address;
16225  Relation parent_rel;
16226 
16227  if (rel->rd_rel->relispartition)
16228  ereport(ERROR,
16229  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
16230  errmsg("cannot change inheritance of a partition")));
16231 
16232  /*
16233  * AccessShareLock on the parent is probably enough, seeing that DROP
16234  * TABLE doesn't lock parent tables at all. We need some lock since we'll
16235  * be inspecting the parent's schema.
16236  */
16237  parent_rel = table_openrv(parent, AccessShareLock);
16238 
16239  /*
16240  * We don't bother to check ownership of the parent table --- ownership of
16241  * the child is presumed enough rights.
16242  */
16243 
16244  /* Off to RemoveInheritance() where most of the work happens */
16245  RemoveInheritance(rel, parent_rel, false);
16246 
16247  ObjectAddressSet(address, RelationRelationId,
16248  RelationGetRelid(parent_rel));
16249 
16250  /* keep our lock on the parent relation until commit */
16251  table_close(parent_rel, NoLock);
16252 
16253  return address;
16254 }
16255 
16256 /*
16257  * MarkInheritDetached
16258  *
16259  * Set inhdetachpending for a partition, for ATExecDetachPartition
16260  * in concurrent mode. While at it, verify that no other partition is
16261  * already pending detach.
16262  */
16263 static void
16264 MarkInheritDetached(Relation child_rel, Relation parent_rel)
16265 {
16266  Relation catalogRelation;
16267  SysScanDesc scan;
16268  ScanKeyData key;
16269  HeapTuple inheritsTuple;
16270  bool found = false;
16271 
16272  Assert(parent_rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
16273 
16274  /*
16275  * Find pg_inherits entries by inhparent. (We need to scan them all in
16276  * order to verify that no other partition is pending detach.)
16277  */
16278  catalogRelation = table_open(InheritsRelationId, RowExclusiveLock);
16279  ScanKeyInit(&key,
16280  Anum_pg_inherits_inhparent,
16281  BTEqualStrategyNumber, F_OIDEQ,
16282  ObjectIdGetDatum(RelationGetRelid(parent_rel)));
16283  scan = systable_beginscan(catalogRelation, InheritsParentIndexId,
16284  true, NULL, 1, &key);
16285 
16286  while (HeapTupleIsValid(inheritsTuple = systable_getnext(scan)))
16287  {
16288  Form_pg_inherits inhForm;
16289 
16290  inhForm = (Form_pg_inherits) GETSTRUCT(inheritsTuple);
16291  if (inhForm->inhdetachpending)
16292  ereport(ERROR,
16293  errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
16294  errmsg("partition \"%s\" already pending detach in partitioned table \"%s.%s\"",
16295  get_rel_name(inhForm->inhrelid),
16296  get_namespace_name(parent_rel->rd_rel->relnamespace),
16297  RelationGetRelationName(parent_rel)),
16298  errhint("Use ALTER TABLE ... DETACH PARTITION ... FINALIZE to complete the pending detach operation."));
16299 
16300  if (inhForm->inhrelid == RelationGetRelid(child_rel))
16301  {
16302  HeapTuple newtup;
16303 
16304  newtup = heap_copytuple(inheritsTuple);
16305  ((Form_pg_inherits) GETSTRUCT(newtup))->inhdetachpending = true;
16306 
16307  CatalogTupleUpdate(catalogRelation,
16308  &inheritsTuple->t_self,
16309  newtup);
16310  found = true;
16311  heap_freetuple(newtup);
16312  /* keep looking, to ensure we catch others pending detach */
16313  }
16314  }
16315 
16316  /* Done */
16317  systable_endscan(scan);
16318  table_close(catalogRelation, RowExclusiveLock);
16319 
16320  if (!found)
16321  ereport(ERROR,
16323  errmsg("relation \"%s\" is not a partition of relation \"%s\"",
16324  RelationGetRelationName(child_rel),
16325  RelationGetRelationName(parent_rel))));
16326 }
16327 
16328 /*
16329  * RemoveInheritance
16330  *
16331  * Drop a parent from the child's parents. This just adjusts the attinhcount
16332  * and attislocal of the columns and removes the pg_inherit and pg_depend
16333  * entries. expect_detached is passed down to DeleteInheritsTuple, q.v..
16334  *
16335  * If attinhcount goes to 0 then attislocal gets set to true. If it goes back
16336  * up attislocal stays true, which means if a child is ever removed from a
16337  * parent then its columns will never be automatically dropped which may
16338  * surprise. But at least we'll never surprise by dropping columns someone
16339  * isn't expecting to be dropped which would actually mean data loss.
16340  *
16341  * coninhcount and conislocal for inherited constraints are adjusted in
16342  * exactly the same way.
16343  *
16344  * Common to ATExecDropInherit() and ATExecDetachPartition().
16345  */
16346 static void
16347 RemoveInheritance(Relation child_rel, Relation parent_rel, bool expect_detached)
16348 {
16349  Relation catalogRelation;
16350  SysScanDesc scan;
16351  ScanKeyData key[3];
16352  HeapTuple attributeTuple,
16353  constraintTuple;
16354  List *connames;
16355  bool found;
16356  bool is_partitioning;
16357 
16358  is_partitioning = (parent_rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
16359 
16360  found = DeleteInheritsTuple(RelationGetRelid(child_rel),
16361  RelationGetRelid(parent_rel),
16362  expect_detached,
16363  RelationGetRelationName(child_rel));
16364  if (!found)
16365  {
16366  if (is_partitioning)
16367  ereport(ERROR,
16369  errmsg("relation \"%s\" is not a partition of relation \"%s\"",
16370  RelationGetRelationName(child_rel),
16371  RelationGetRelationName(parent_rel))));
16372  else
16373  ereport(ERROR,
16375  errmsg("relation \"%s\" is not a parent of relation \"%s\"",
16376  RelationGetRelationName(parent_rel),
16377  RelationGetRelationName(child_rel))));
16378  }
16379 
16380  /*
16381  * Search through child columns looking for ones matching parent rel
16382  */
16383  catalogRelation = table_open(AttributeRelationId, RowExclusiveLock);
16384  ScanKeyInit(&key[0],
16385  Anum_pg_attribute_attrelid,
16386  BTEqualStrategyNumber, F_OIDEQ,
16387  ObjectIdGetDatum(RelationGetRelid(child_rel)));
16388  scan = systable_beginscan(catalogRelation, AttributeRelidNumIndexId,
16389  true, NULL, 1, key);
16390  while (HeapTupleIsValid(attributeTuple = systable_getnext(scan)))
16391  {
16392  Form_pg_attribute att = (Form_pg_attribute) GETSTRUCT(attributeTuple);
16393 
16394  /* Ignore if dropped or not inherited */
16395  if (att->attisdropped)
16396  continue;
16397  if (att->attinhcount <= 0)
16398  continue;
16399 
16401  NameStr(att->attname)))
16402  {
16403  /* Decrement inhcount and possibly set islocal to true */
16404  HeapTuple copyTuple = heap_copytuple(attributeTuple);
16405  Form_pg_attribute copy_att = (Form_pg_attribute) GETSTRUCT(copyTuple);
16406 
16407  copy_att->attinhcount--;
16408  if (copy_att->attinhcount == 0)
16409  copy_att->attislocal = true;
16410 
16411  CatalogTupleUpdate(catalogRelation, &copyTuple->t_self, copyTuple);
16412  heap_freetuple(copyTuple);
16413  }
16414  }
16415  systable_endscan(scan);
16416  table_close(catalogRelation, RowExclusiveLock);
16417 
16418  /*
16419  * Likewise, find inherited check constraints and disinherit them. To do
16420  * this, we first need a list of the names of the parent's check
16421  * constraints. (We cheat a bit by only checking for name matches,
16422  * assuming that the expressions will match.)
16423  */
16424  catalogRelation = table_open(ConstraintRelationId, RowExclusiveLock);
16425  ScanKeyInit(&key[0],
16426  Anum_pg_constraint_conrelid,
16427  BTEqualStrategyNumber, F_OIDEQ,
16428  ObjectIdGetDatum(RelationGetRelid(parent_rel)));
16429  scan = systable_beginscan(catalogRelation, ConstraintRelidTypidNameIndexId,
16430  true, NULL, 1, key);
16431 
16432  connames = NIL;
16433 
16434  while (HeapTupleIsValid(constraintTuple = systable_getnext(scan)))
16435  {
16436  Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(constraintTuple);
16437 
16438  if (con->contype == CONSTRAINT_CHECK)
16439  connames = lappend(connames, pstrdup(NameStr(con->conname)));
16440  }
16441 
16442  systable_endscan(scan);
16443 
16444  /* Now scan the child's constraints */
16445  ScanKeyInit(&key[0],
16446  Anum_pg_constraint_conrelid,
16447  BTEqualStrategyNumber, F_OIDEQ,
16448  ObjectIdGetDatum(RelationGetRelid(child_rel)));
16449  scan = systable_beginscan(catalogRelation, ConstraintRelidTypidNameIndexId,
16450  true, NULL, 1, key);
16451 
16452  while (HeapTupleIsValid(constraintTuple = systable_getnext(scan)))
16453  {
16454  Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(constraintTuple);
16455  bool match;
16456 
16457  if (con->contype != CONSTRAINT_CHECK)
16458  continue;
16459 
16460  match = false;
16461  foreach_ptr(char, chkname, connames)
16462  {
16463  if (strcmp(NameStr(con->conname), chkname) == 0)
16464  {
16465  match = true;
16466  break;
16467  }
16468  }
16469 
16470  if (match)
16471  {
16472  /* Decrement inhcount and possibly set islocal to true */
16473  HeapTuple copyTuple = heap_copytuple(constraintTuple);
16474  Form_pg_constraint copy_con = (Form_pg_constraint) GETSTRUCT(copyTuple);
16475 
16476  if (copy_con->coninhcount <= 0) /* shouldn't happen */
16477  elog(ERROR, "relation %u has non-inherited constraint \"%s\"",
16478  RelationGetRelid(child_rel), NameStr(copy_con->conname));
16479 
16480  copy_con->coninhcount--;
16481  if (copy_con->coninhcount == 0)
16482  copy_con->conislocal = true;
16483 
16484  CatalogTupleUpdate(catalogRelation, &copyTuple->t_self, copyTuple);
16485  heap_freetuple(copyTuple);
16486  }
16487  }
16488 
16489  systable_endscan(scan);
16490  table_close(catalogRelation, RowExclusiveLock);
16491 
16493  RelationRelationId,
16494  RelationGetRelid(parent_rel),
16495  child_dependency_type(is_partitioning));
16496 
16497  /*
16498  * Post alter hook of this inherits. Since object_access_hook doesn't take
16499  * multiple object identifiers, we relay oid of parent relation using
16500  * auxiliary_id argument.
16501  */
16502  InvokeObjectPostAlterHookArg(InheritsRelationId,
16503  RelationGetRelid(child_rel), 0,
16504  RelationGetRelid(parent_rel), false);
16505 }
16506 
16507 /*
16508  * Drop the dependency created by StoreCatalogInheritance1 (CREATE TABLE
16509  * INHERITS/ALTER TABLE INHERIT -- refclassid will be RelationRelationId) or
16510  * heap_create_with_catalog (CREATE TABLE OF/ALTER TABLE OF -- refclassid will
16511  * be TypeRelationId). There's no convenient way to do this, so go trawling
16512  * through pg_depend.
16513  */
16514 static void
16515 drop_parent_dependency(Oid relid, Oid refclassid, Oid refobjid,
16516  DependencyType deptype)
16517 {
16518  Relation catalogRelation;
16519  SysScanDesc scan;
16520  ScanKeyData key[3];
16521  HeapTuple depTuple;
16522 
16523  catalogRelation = table_open(DependRelationId, RowExclusiveLock);
16524 
16525  ScanKeyInit(&key[0],
16526  Anum_pg_depend_classid,
16527  BTEqualStrategyNumber, F_OIDEQ,
16528  ObjectIdGetDatum(RelationRelationId));
16529  ScanKeyInit(&key[1],
16530  Anum_pg_depend_objid,
16531  BTEqualStrategyNumber, F_OIDEQ,
16532  ObjectIdGetDatum(relid));
16533  ScanKeyInit(&key[2],
16534  Anum_pg_depend_objsubid,
16535  BTEqualStrategyNumber, F_INT4EQ,
16536  Int32GetDatum(0));
16537 
16538  scan = systable_beginscan(catalogRelation, DependDependerIndexId, true,
16539  NULL, 3, key);
16540 
16541  while (HeapTupleIsValid(depTuple = systable_getnext(scan)))
16542  {
16543  Form_pg_depend dep = (Form_pg_depend) GETSTRUCT(depTuple);
16544 
16545  if (dep->refclassid == refclassid &&
16546  dep->refobjid == refobjid &&
16547  dep->refobjsubid == 0 &&
16548  dep->deptype == deptype)
16549  CatalogTupleDelete(catalogRelation, &depTuple->t_self);
16550  }
16551 
16552  systable_endscan(scan);
16553  table_close(catalogRelation, RowExclusiveLock);
16554 }
16555 
16556 /*
16557  * ALTER TABLE OF
16558  *
16559  * Attach a table to a composite type, as though it had been created with CREATE
16560  * TABLE OF. All attname, atttypid, atttypmod and attcollation must match. The
16561  * subject table must not have inheritance parents. These restrictions ensure
16562  * that you cannot create a configuration impossible with CREATE TABLE OF alone.
16563  *
16564  * The address of the type is returned.
16565  */
16566 static ObjectAddress
16567 ATExecAddOf(Relation rel, const TypeName *ofTypename, LOCKMODE lockmode)
16568 {
16569  Oid relid = RelationGetRelid(rel);
16570  Type typetuple;
16571  Form_pg_type typeform;
16572  Oid typeid;
16573  Relation inheritsRelation,
16574  relationRelation;
16575  SysScanDesc scan;
16576  ScanKeyData key;
16577  AttrNumber table_attno,
16578  type_attno;
16579  TupleDesc typeTupleDesc,
16580  tableTupleDesc;
16581  ObjectAddress tableobj,
16582  typeobj;
16583  HeapTuple classtuple;
16584 
16585  /* Validate the type. */
16586  typetuple = typenameType(NULL, ofTypename, NULL);
16587  check_of_type(typetuple);
16588  typeform = (Form_pg_type) GETSTRUCT(typetuple);
16589  typeid = typeform->oid;
16590 
16591  /* Fail if the table has any inheritance parents. */
16592  inheritsRelation = table_open(InheritsRelationId, AccessShareLock);
16593  ScanKeyInit(&key,
16594  Anum_pg_inherits_inhrelid,
16595  BTEqualStrategyNumber, F_OIDEQ,
16596  ObjectIdGetDatum(relid));
16597  scan = systable_beginscan(inheritsRelation, InheritsRelidSeqnoIndexId,
16598  true, NULL, 1, &key);
16600  ereport(ERROR,
16601  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
16602  errmsg("typed tables cannot inherit")));
16603  systable_endscan(scan);
16604  table_close(inheritsRelation, AccessShareLock);
16605 
16606  /*
16607  * Check the tuple descriptors for compatibility. Unlike inheritance, we
16608  * require that the order also match. However, attnotnull need not match.
16609  */
16610  typeTupleDesc = lookup_rowtype_tupdesc(typeid, -1);
16611  tableTupleDesc = RelationGetDescr(rel);
16612  table_attno = 1;
16613  for (type_attno = 1; type_attno <= typeTupleDesc->natts; type_attno++)
16614  {
16615  Form_pg_attribute type_attr,
16616  table_attr;
16617  const char *type_attname,
16618  *table_attname;
16619 
16620  /* Get the next non-dropped type attribute. */
16621  type_attr = TupleDescAttr(typeTupleDesc, type_attno - 1);
16622  if (type_attr->attisdropped)
16623  continue;
16624  type_attname = NameStr(type_attr->attname);
16625 
16626  /* Get the next non-dropped table attribute. */
16627  do
16628  {
16629  if (table_attno > tableTupleDesc->natts)
16630  ereport(ERROR,
16631  (errcode(ERRCODE_DATATYPE_MISMATCH),
16632  errmsg("table is missing column \"%s\"",
16633  type_attname)));
16634  table_attr = TupleDescAttr(tableTupleDesc, table_attno - 1);
16635  table_attno++;
16636  } while (table_attr->attisdropped);
16637  table_attname = NameStr(table_attr->attname);
16638 
16639  /* Compare name. */
16640  if (strncmp(table_attname, type_attname, NAMEDATALEN) != 0)
16641  ereport(ERROR,
16642  (errcode(ERRCODE_DATATYPE_MISMATCH),
16643  errmsg("table has column \"%s\" where type requires \"%s\"",
16644  table_attname, type_attname)));
16645 
16646  /* Compare type. */
16647  if (table_attr->atttypid != type_attr->atttypid ||
16648  table_attr->atttypmod != type_attr->atttypmod ||
16649  table_attr->attcollation != type_attr->attcollation)
16650  ereport(ERROR,
16651  (errcode(ERRCODE_DATATYPE_MISMATCH),
16652  errmsg("table \"%s\" has different type for column \"%s\"",
16653  RelationGetRelationName(rel), type_attname)));
16654  }
16655  ReleaseTupleDesc(typeTupleDesc);
16656 
16657  /* Any remaining columns at the end of the table had better be dropped. */
16658  for (; table_attno <= tableTupleDesc->natts; table_attno++)
16659  {
16660  Form_pg_attribute table_attr = TupleDescAttr(tableTupleDesc,
16661  table_attno - 1);
16662 
16663  if (!table_attr->attisdropped)
16664  ereport(ERROR,
16665  (errcode(ERRCODE_DATATYPE_MISMATCH),
16666  errmsg("table has extra column \"%s\"",
16667  NameStr(table_attr->attname))));
16668  }
16669 
16670  /* If the table was already typed, drop the existing dependency. */
16671  if (rel->rd_rel->reloftype)
16672  drop_parent_dependency(relid, TypeRelationId, rel->rd_rel->reloftype,
16674 
16675  /* Record a dependency on the new type. */
16676  tableobj.classId = RelationRelationId;
16677  tableobj.objectId = relid;
16678  tableobj.objectSubId = 0;
16679  typeobj.classId = TypeRelationId;
16680  typeobj.objectId = typeid;
16681  typeobj.objectSubId = 0;
16682  recordDependencyOn(&tableobj, &typeobj, DEPENDENCY_NORMAL);
16683 
16684  /* Update pg_class.reloftype */
16685  relationRelation = table_open(RelationRelationId, RowExclusiveLock);
16686  classtuple = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
16687  if (!HeapTupleIsValid(classtuple))
16688  elog(ERROR, "cache lookup failed for relation %u", relid);
16689  ((Form_pg_class) GETSTRUCT(classtuple))->reloftype = typeid;
16690  CatalogTupleUpdate(relationRelation, &classtuple->t_self, classtuple);
16691 
16692  InvokeObjectPostAlterHook(RelationRelationId, relid, 0);
16693 
16694  heap_freetuple(classtuple);
16695  table_close(relationRelation, RowExclusiveLock);
16696 
16697  ReleaseSysCache(typetuple);
16698 
16699  return typeobj;
16700 }
16701 
16702 /*
16703  * ALTER TABLE NOT OF
16704  *
16705  * Detach a typed table from its originating type. Just clear reloftype and
16706  * remove the dependency.
16707  */
16708 static void
16710 {
16711  Oid relid = RelationGetRelid(rel);
16712  Relation relationRelation;
16713  HeapTuple tuple;
16714 
16715  if (!OidIsValid(rel->rd_rel->reloftype))
16716  ereport(ERROR,
16717  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
16718  errmsg("\"%s\" is not a typed table",
16719  RelationGetRelationName(rel))));
16720 
16721  /*
16722  * We don't bother to check ownership of the type --- ownership of the
16723  * table is presumed enough rights. No lock required on the type, either.
16724  */
16725 
16726  drop_parent_dependency(relid, TypeRelationId, rel->rd_rel->reloftype,
16728 
16729  /* Clear pg_class.reloftype */
16730  relationRelation = table_open(RelationRelationId, RowExclusiveLock);
16731  tuple = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
16732  if (!HeapTupleIsValid(tuple))
16733  elog(ERROR, "cache lookup failed for relation %u", relid);
16734  ((Form_pg_class) GETSTRUCT(tuple))->reloftype = InvalidOid;
16735  CatalogTupleUpdate(relationRelation, &tuple->t_self, tuple);
16736 
16737  InvokeObjectPostAlterHook(RelationRelationId, relid, 0);
16738 
16739  heap_freetuple(tuple);
16740  table_close(relationRelation, RowExclusiveLock);
16741 }
16742 
16743 /*
16744  * relation_mark_replica_identity: Update a table's replica identity
16745  *
16746  * Iff ri_type = REPLICA_IDENTITY_INDEX, indexOid must be the Oid of a suitable
16747  * index. Otherwise, it must be InvalidOid.
16748  *
16749  * Caller had better hold an exclusive lock on the relation, as the results
16750  * of running two of these concurrently wouldn't be pretty.
16751  */
16752 static void
16753 relation_mark_replica_identity(Relation rel, char ri_type, Oid indexOid,
16754  bool is_internal)
16755 {
16756  Relation pg_index;
16757  Relation pg_class;
16758  HeapTuple pg_class_tuple;
16759  HeapTuple pg_index_tuple;
16760  Form_pg_class pg_class_form;
16761  Form_pg_index pg_index_form;
16762  ListCell *index;
16763 
16764  /*
16765  * Check whether relreplident has changed, and update it if so.
16766  */
16767  pg_class = table_open(RelationRelationId, RowExclusiveLock);
16768  pg_class_tuple = SearchSysCacheCopy1(RELOID,
16770  if (!HeapTupleIsValid(pg_class_tuple))
16771  elog(ERROR, "cache lookup failed for relation \"%s\"",
16773  pg_class_form = (Form_pg_class) GETSTRUCT(pg_class_tuple);
16774  if (pg_class_form->relreplident != ri_type)
16775  {
16776  pg_class_form->relreplident = ri_type;
16777  CatalogTupleUpdate(pg_class, &pg_class_tuple->t_self, pg_class_tuple);
16778  }
16779  table_close(pg_class, RowExclusiveLock);
16780  heap_freetuple(pg_class_tuple);
16781 
16782  /*
16783  * Update the per-index indisreplident flags correctly.
16784  */
16785  pg_index = table_open(IndexRelationId, RowExclusiveLock);
16786  foreach(index, RelationGetIndexList(rel))
16787  {
16788  Oid thisIndexOid = lfirst_oid(index);
16789  bool dirty = false;
16790 
16791  pg_index_tuple = SearchSysCacheCopy1(INDEXRELID,
16792  ObjectIdGetDatum(thisIndexOid));
16793  if (!HeapTupleIsValid(pg_index_tuple))
16794  elog(ERROR, "cache lookup failed for index %u", thisIndexOid);
16795  pg_index_form = (Form_pg_index) GETSTRUCT(pg_index_tuple);
16796 
16797  if (thisIndexOid == indexOid)
16798  {
16799  /* Set the bit if not already set. */
16800  if (!pg_index_form->indisreplident)
16801  {
16802  dirty = true;
16803  pg_index_form->indisreplident = true;
16804  }
16805  }
16806  else
16807  {
16808  /* Unset the bit if set. */
16809  if (pg_index_form->indisreplident)
16810  {
16811  dirty = true;
16812  pg_index_form->indisreplident = false;
16813  }
16814  }
16815 
16816  if (dirty)
16817  {
16818  CatalogTupleUpdate(pg_index, &pg_index_tuple->t_self, pg_index_tuple);
16819  InvokeObjectPostAlterHookArg(IndexRelationId, thisIndexOid, 0,
16820  InvalidOid, is_internal);
16821 
16822  /*
16823  * Invalidate the relcache for the table, so that after we commit
16824  * all sessions will refresh the table's replica identity index
16825  * before attempting any UPDATE or DELETE on the table. (If we
16826  * changed the table's pg_class row above, then a relcache inval
16827  * is already queued due to that; but we might not have.)
16828  */
16830  }
16831  heap_freetuple(pg_index_tuple);
16832  }
16833 
16834  table_close(pg_index, RowExclusiveLock);
16835 }
16836 
16837 /*
16838  * ALTER TABLE <name> REPLICA IDENTITY ...
16839  */
16840 static void
16842 {
16843  Oid indexOid;
16844  Relation indexRel;
16845  int key;
16846 
16847  if (stmt->identity_type == REPLICA_IDENTITY_DEFAULT)
16848  {
16849  relation_mark_replica_identity(rel, stmt->identity_type, InvalidOid, true);
16850  return;
16851  }
16852  else if (stmt->identity_type == REPLICA_IDENTITY_FULL)
16853  {
16854  relation_mark_replica_identity(rel, stmt->identity_type, InvalidOid, true);
16855  return;
16856  }
16857  else if (stmt->identity_type == REPLICA_IDENTITY_NOTHING)
16858  {
16859  relation_mark_replica_identity(rel, stmt->identity_type, InvalidOid, true);
16860  return;
16861  }
16862  else if (stmt->identity_type == REPLICA_IDENTITY_INDEX)
16863  {
16864  /* fallthrough */ ;
16865  }
16866  else
16867  elog(ERROR, "unexpected identity type %u", stmt->identity_type);
16868 
16869  /* Check that the index exists */
16870  indexOid = get_relname_relid(stmt->name, rel->rd_rel->relnamespace);
16871  if (!OidIsValid(indexOid))
16872  ereport(ERROR,
16873  (errcode(ERRCODE_UNDEFINED_OBJECT),
16874  errmsg("index \"%s\" for table \"%s\" does not exist",
16875  stmt->name, RelationGetRelationName(rel))));
16876 
16877  indexRel = index_open(indexOid, ShareLock);
16878 
16879  /* Check that the index is on the relation we're altering. */
16880  if (indexRel->rd_index == NULL ||
16881  indexRel->rd_index->indrelid != RelationGetRelid(rel))
16882  ereport(ERROR,
16883  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
16884  errmsg("\"%s\" is not an index for table \"%s\"",
16885  RelationGetRelationName(indexRel),
16886  RelationGetRelationName(rel))));
16887  /* The AM must support uniqueness, and the index must in fact be unique. */
16888  if (!indexRel->rd_indam->amcanunique ||
16889  !indexRel->rd_index->indisunique)
16890  ereport(ERROR,
16891  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
16892  errmsg("cannot use non-unique index \"%s\" as replica identity",
16893  RelationGetRelationName(indexRel))));
16894  /* Deferred indexes are not guaranteed to be always unique. */
16895  if (!indexRel->rd_index->indimmediate)
16896  ereport(ERROR,
16897  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
16898  errmsg("cannot use non-immediate index \"%s\" as replica identity",
16899  RelationGetRelationName(indexRel))));
16900  /* Expression indexes aren't supported. */
16901  if (RelationGetIndexExpressions(indexRel) != NIL)
16902  ereport(ERROR,
16903  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
16904  errmsg("cannot use expression index \"%s\" as replica identity",
16905  RelationGetRelationName(indexRel))));
16906  /* Predicate indexes aren't supported. */
16907  if (RelationGetIndexPredicate(indexRel) != NIL)
16908  ereport(ERROR,
16909  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
16910  errmsg("cannot use partial index \"%s\" as replica identity",
16911  RelationGetRelationName(indexRel))));
16912 
16913  /* Check index for nullable columns. */
16914  for (key = 0; key < IndexRelationGetNumberOfKeyAttributes(indexRel); key++)
16915  {
16916  int16 attno = indexRel->rd_index->indkey.values[key];
16917  Form_pg_attribute attr;
16918 
16919  /*
16920  * Reject any other system columns. (Going forward, we'll disallow
16921  * indexes containing such columns in the first place, but they might
16922  * exist in older branches.)
16923  */
16924  if (attno <= 0)
16925  ereport(ERROR,
16926  (errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
16927  errmsg("index \"%s\" cannot be used as replica identity because column %d is a system column",
16928  RelationGetRelationName(indexRel), attno)));
16929 
16930  attr = TupleDescAttr(rel->rd_att, attno - 1);
16931  if (!attr->attnotnull)
16932  ereport(ERROR,
16933  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
16934  errmsg("index \"%s\" cannot be used as replica identity because column \"%s\" is nullable",
16935  RelationGetRelationName(indexRel),
16936  NameStr(attr->attname))));
16937  }
16938 
16939  /* This index is suitable for use as a replica identity. Mark it. */
16940  relation_mark_replica_identity(rel, stmt->identity_type, indexOid, true);
16941 
16942  index_close(indexRel, NoLock);
16943 }
16944 
16945 /*
16946  * ALTER TABLE ENABLE/DISABLE ROW LEVEL SECURITY
16947  */
16948 static void
16950 {
16951  Relation pg_class;
16952  Oid relid;
16953  HeapTuple tuple;
16954 
16955  relid = RelationGetRelid(rel);
16956 
16957  /* Pull the record for this relation and update it */
16958  pg_class = table_open(RelationRelationId, RowExclusiveLock);
16959 
16960  tuple = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
16961 
16962  if (!HeapTupleIsValid(tuple))
16963  elog(ERROR, "cache lookup failed for relation %u", relid);
16964 
16965  ((Form_pg_class) GETSTRUCT(tuple))->relrowsecurity = rls;
16966  CatalogTupleUpdate(pg_class, &tuple->t_self, tuple);
16967 
16968  InvokeObjectPostAlterHook(RelationRelationId,
16969  RelationGetRelid(rel), 0);
16970 
16971  table_close(pg_class, RowExclusiveLock);
16972  heap_freetuple(tuple);
16973 }
16974 
16975 /*
16976  * ALTER TABLE FORCE/NO FORCE ROW LEVEL SECURITY
16977  */
16978 static void
16980 {
16981  Relation pg_class;
16982  Oid relid;
16983  HeapTuple tuple;
16984 
16985  relid = RelationGetRelid(rel);
16986 
16987  pg_class = table_open(RelationRelationId, RowExclusiveLock);
16988 
16989  tuple = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
16990 
16991  if (!HeapTupleIsValid(tuple))
16992  elog(ERROR, "cache lookup failed for relation %u", relid);
16993 
16994  ((Form_pg_class) GETSTRUCT(tuple))->relforcerowsecurity = force_rls;
16995  CatalogTupleUpdate(pg_class, &tuple->t_self, tuple);
16996 
16997  InvokeObjectPostAlterHook(RelationRelationId,
16998  RelationGetRelid(rel), 0);
16999 
17000  table_close(pg_class, RowExclusiveLock);
17001  heap_freetuple(tuple);
17002 }
17003 
17004 /*
17005  * ALTER FOREIGN TABLE <name> OPTIONS (...)
17006  */
17007 static void
17009 {
17010  Relation ftrel;
17011  ForeignServer *server;
17012  ForeignDataWrapper *fdw;
17013  HeapTuple tuple;
17014  bool isnull;
17015  Datum repl_val[Natts_pg_foreign_table];
17016  bool repl_null[Natts_pg_foreign_table];
17017  bool repl_repl[Natts_pg_foreign_table];
17018  Datum datum;
17019  Form_pg_foreign_table tableform;
17020 
17021  if (options == NIL)
17022  return;
17023 
17024  ftrel = table_open(ForeignTableRelationId, RowExclusiveLock);
17025 
17026  tuple = SearchSysCacheCopy1(FOREIGNTABLEREL,
17027  ObjectIdGetDatum(rel->rd_id));
17028  if (!HeapTupleIsValid(tuple))
17029  ereport(ERROR,
17030  (errcode(ERRCODE_UNDEFINED_OBJECT),
17031  errmsg("foreign table \"%s\" does not exist",
17032  RelationGetRelationName(rel))));
17033  tableform = (Form_pg_foreign_table) GETSTRUCT(tuple);
17034  server = GetForeignServer(tableform->ftserver);
17035  fdw = GetForeignDataWrapper(server->fdwid);
17036 
17037  memset(repl_val, 0, sizeof(repl_val));
17038  memset(repl_null, false, sizeof(repl_null));
17039  memset(repl_repl, false, sizeof(repl_repl));
17040 
17041  /* Extract the current options */
17042  datum = SysCacheGetAttr(FOREIGNTABLEREL,
17043  tuple,
17044  Anum_pg_foreign_table_ftoptions,
17045  &isnull);
17046  if (isnull)
17047  datum = PointerGetDatum(NULL);
17048 
17049  /* Transform the options */
17050  datum = transformGenericOptions(ForeignTableRelationId,
17051  datum,
17052  options,
17053  fdw->fdwvalidator);
17054 
17055  if (PointerIsValid(DatumGetPointer(datum)))
17056  repl_val[Anum_pg_foreign_table_ftoptions - 1] = datum;
17057  else
17058  repl_null[Anum_pg_foreign_table_ftoptions - 1] = true;
17059 
17060  repl_repl[Anum_pg_foreign_table_ftoptions - 1] = true;
17061 
17062  /* Everything looks good - update the tuple */
17063 
17064  tuple = heap_modify_tuple(tuple, RelationGetDescr(ftrel),
17065  repl_val, repl_null, repl_repl);
17066 
17067  CatalogTupleUpdate(ftrel, &tuple->t_self, tuple);
17068 
17069  /*
17070  * Invalidate relcache so that all sessions will refresh any cached plans
17071  * that might depend on the old options.
17072  */
17074 
17075  InvokeObjectPostAlterHook(ForeignTableRelationId,
17076  RelationGetRelid(rel), 0);
17077 
17078  table_close(ftrel, RowExclusiveLock);
17079 
17080  heap_freetuple(tuple);
17081 }
17082 
17083 /*
17084  * ALTER TABLE ALTER COLUMN SET COMPRESSION
17085  *
17086  * Return value is the address of the modified column
17087  */
17088 static ObjectAddress
17090  const char *column,
17091  Node *newValue,
17092  LOCKMODE lockmode)
17093 {
17094  Relation attrel;
17095  HeapTuple tuple;
17096  Form_pg_attribute atttableform;
17098  char *compression;
17099  char cmethod;
17100  ObjectAddress address;
17101 
17102  compression = strVal(newValue);
17103 
17104  attrel = table_open(AttributeRelationId, RowExclusiveLock);
17105 
17106  /* copy the cache entry so we can scribble on it below */
17107  tuple = SearchSysCacheCopyAttName(RelationGetRelid(rel), column);
17108  if (!HeapTupleIsValid(tuple))
17109  ereport(ERROR,
17110  (errcode(ERRCODE_UNDEFINED_COLUMN),
17111  errmsg("column \"%s\" of relation \"%s\" does not exist",
17112  column, RelationGetRelationName(rel))));
17113 
17114  /* prevent them from altering a system attribute */
17115  atttableform = (Form_pg_attribute) GETSTRUCT(tuple);
17116  attnum = atttableform->attnum;
17117  if (attnum <= 0)
17118  ereport(ERROR,
17119  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
17120  errmsg("cannot alter system column \"%s\"", column)));
17121 
17122  /*
17123  * Check that column type is compressible, then get the attribute
17124  * compression method code
17125  */
17126  cmethod = GetAttributeCompression(atttableform->atttypid, compression);
17127 
17128  /* update pg_attribute entry */
17129  atttableform->attcompression = cmethod;
17130  CatalogTupleUpdate(attrel, &tuple->t_self, tuple);
17131 
17132  InvokeObjectPostAlterHook(RelationRelationId,
17133  RelationGetRelid(rel),
17134  attnum);
17135 
17136  /*
17137  * Apply the change to indexes as well (only for simple index columns,
17138  * matching behavior of index.c ConstructTupleDescriptor()).
17139  */
17140  SetIndexStorageProperties(rel, attrel, attnum,
17141  false, 0,
17142  true, cmethod,
17143  lockmode);
17144 
17145  heap_freetuple(tuple);
17146 
17147  table_close(attrel, RowExclusiveLock);
17148 
17149  /* make changes visible */
17151 
17152  ObjectAddressSubSet(address, RelationRelationId,
17153  RelationGetRelid(rel), attnum);
17154  return address;
17155 }
17156 
17157 
17158 /*
17159  * Preparation phase for SET LOGGED/UNLOGGED
17160  *
17161  * This verifies that we're not trying to change a temp table. Also,
17162  * existing foreign key constraints are checked to avoid ending up with
17163  * permanent tables referencing unlogged tables.
17164  */
17165 static void
17167 {
17168  Relation pg_constraint;
17169  HeapTuple tuple;
17170  SysScanDesc scan;
17171  ScanKeyData skey[1];
17172 
17173  /*
17174  * Disallow changing status for a temp table. Also verify whether we can
17175  * get away with doing nothing; in such cases we don't need to run the
17176  * checks below, either.
17177  */
17178  switch (rel->rd_rel->relpersistence)
17179  {
17180  case RELPERSISTENCE_TEMP:
17181  ereport(ERROR,
17182  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
17183  errmsg("cannot change logged status of table \"%s\" because it is temporary",
17185  errtable(rel)));
17186  break;
17187  case RELPERSISTENCE_PERMANENT:
17188  if (toLogged)
17189  /* nothing to do */
17190  return;
17191  break;
17192  case RELPERSISTENCE_UNLOGGED:
17193  if (!toLogged)
17194  /* nothing to do */
17195  return;
17196  break;
17197  }
17198 
17199  /*
17200  * Check that the table is not part of any publication when changing to
17201  * UNLOGGED, as UNLOGGED tables can't be published.
17202  */
17203  if (!toLogged &&
17205  ereport(ERROR,
17206  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
17207  errmsg("cannot change table \"%s\" to unlogged because it is part of a publication",
17209  errdetail("Unlogged relations cannot be replicated.")));
17210 
17211  /*
17212  * Check existing foreign key constraints to preserve the invariant that
17213  * permanent tables cannot reference unlogged ones. Self-referencing
17214  * foreign keys can safely be ignored.
17215  */
17216  pg_constraint = table_open(ConstraintRelationId, AccessShareLock);
17217 
17218  /*
17219  * Scan conrelid if changing to permanent, else confrelid. This also
17220  * determines whether a useful index exists.
17221  */
17222  ScanKeyInit(&skey[0],
17223  toLogged ? Anum_pg_constraint_conrelid :
17224  Anum_pg_constraint_confrelid,
17225  BTEqualStrategyNumber, F_OIDEQ,
17227  scan = systable_beginscan(pg_constraint,
17228  toLogged ? ConstraintRelidTypidNameIndexId : InvalidOid,
17229  true, NULL, 1, skey);
17230 
17231  while (HeapTupleIsValid(tuple = systable_getnext(scan)))
17232  {
17234 
17235  if (con->contype == CONSTRAINT_FOREIGN)
17236  {
17237  Oid foreignrelid;
17238  Relation foreignrel;
17239 
17240  /* the opposite end of what we used as scankey */
17241  foreignrelid = toLogged ? con->confrelid : con->conrelid;
17242 
17243  /* ignore if self-referencing */
17244  if (RelationGetRelid(rel) == foreignrelid)
17245  continue;
17246 
17247  foreignrel = relation_open(foreignrelid, AccessShareLock);
17248 
17249  if (toLogged)
17250  {
17251  if (!RelationIsPermanent(foreignrel))
17252  ereport(ERROR,
17253  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
17254  errmsg("could not change table \"%s\" to logged because it references unlogged table \"%s\"",
17256  RelationGetRelationName(foreignrel)),
17257  errtableconstraint(rel, NameStr(con->conname))));
17258  }
17259  else
17260  {
17261  if (RelationIsPermanent(foreignrel))
17262  ereport(ERROR,
17263  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
17264  errmsg("could not change table \"%s\" to unlogged because it references logged table \"%s\"",
17266  RelationGetRelationName(foreignrel)),
17267  errtableconstraint(rel, NameStr(con->conname))));
17268  }
17269 
17270  relation_close(foreignrel, AccessShareLock);
17271  }
17272  }
17273 
17274  systable_endscan(scan);
17275 
17276  table_close(pg_constraint, AccessShareLock);
17277 
17278  /* force rewrite if necessary; see comment in ATRewriteTables */
17280  if (toLogged)
17281  tab->newrelpersistence = RELPERSISTENCE_PERMANENT;
17282  else
17283  tab->newrelpersistence = RELPERSISTENCE_UNLOGGED;
17284  tab->chgPersistence = true;
17285 }
17286 
17287 /*
17288  * Execute ALTER TABLE SET SCHEMA
17289  */
17292 {
17293  Relation rel;
17294  Oid relid;
17295  Oid oldNspOid;
17296  Oid nspOid;
17297  RangeVar *newrv;
17298  ObjectAddresses *objsMoved;
17299  ObjectAddress myself;
17300 
17302  stmt->missing_ok ? RVR_MISSING_OK : 0,
17304  (void *) stmt);
17305 
17306  if (!OidIsValid(relid))
17307  {
17308  ereport(NOTICE,
17309  (errmsg("relation \"%s\" does not exist, skipping",
17310  stmt->relation->relname)));
17311  return InvalidObjectAddress;
17312  }
17313 
17314  rel = relation_open(relid, NoLock);
17315 
17316  oldNspOid = RelationGetNamespace(rel);
17317 
17318  /* If it's an owned sequence, disallow moving it by itself. */
17319  if (rel->rd_rel->relkind == RELKIND_SEQUENCE)
17320  {
17321  Oid tableId;
17322  int32 colId;
17323 
17324  if (sequenceIsOwned(relid, DEPENDENCY_AUTO, &tableId, &colId) ||
17325  sequenceIsOwned(relid, DEPENDENCY_INTERNAL, &tableId, &colId))
17326  ereport(ERROR,
17327  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
17328  errmsg("cannot move an owned sequence into another schema"),
17329  errdetail("Sequence \"%s\" is linked to table \"%s\".",
17331  get_rel_name(tableId))));
17332  }
17333 
17334  /* Get and lock schema OID and check its permissions. */
17335  newrv = makeRangeVar(stmt->newschema, RelationGetRelationName(rel), -1);
17336  nspOid = RangeVarGetAndCheckCreationNamespace(newrv, NoLock, NULL);
17337 
17338  /* common checks on switching namespaces */
17339  CheckSetNamespace(oldNspOid, nspOid);
17340 
17341  objsMoved = new_object_addresses();
17342  AlterTableNamespaceInternal(rel, oldNspOid, nspOid, objsMoved);
17343  free_object_addresses(objsMoved);
17344 
17345  ObjectAddressSet(myself, RelationRelationId, relid);
17346 
17347  if (oldschema)
17348  *oldschema = oldNspOid;
17349 
17350  /* close rel, but keep lock until commit */
17351  relation_close(rel, NoLock);
17352 
17353  return myself;
17354 }
17355 
17356 /*
17357  * The guts of relocating a table or materialized view to another namespace:
17358  * besides moving the relation itself, its dependent objects are relocated to
17359  * the new schema.
17360  */
17361 void
17363  ObjectAddresses *objsMoved)
17364 {
17365  Relation classRel;
17366 
17367  Assert(objsMoved != NULL);
17368 
17369  /* OK, modify the pg_class row and pg_depend entry */
17370  classRel = table_open(RelationRelationId, RowExclusiveLock);
17371 
17372  AlterRelationNamespaceInternal(classRel, RelationGetRelid(rel), oldNspOid,
17373  nspOid, true, objsMoved);
17374 
17375  /* Fix the table's row type too, if it has one */
17376  if (OidIsValid(rel->rd_rel->reltype))
17377  AlterTypeNamespaceInternal(rel->rd_rel->reltype, nspOid,
17378  false, /* isImplicitArray */
17379  false, /* ignoreDependent */
17380  false, /* errorOnTableType */
17381  objsMoved);
17382 
17383  /* Fix other dependent stuff */
17384  AlterIndexNamespaces(classRel, rel, oldNspOid, nspOid, objsMoved);
17385  AlterSeqNamespaces(classRel, rel, oldNspOid, nspOid,
17386  objsMoved, AccessExclusiveLock);
17387  AlterConstraintNamespaces(RelationGetRelid(rel), oldNspOid, nspOid,
17388  false, objsMoved);
17389 
17390  table_close(classRel, RowExclusiveLock);
17391 }
17392 
17393 /*
17394  * The guts of relocating a relation to another namespace: fix the pg_class
17395  * entry, and the pg_depend entry if any. Caller must already have
17396  * opened and write-locked pg_class.
17397  */
17398 void
17400  Oid oldNspOid, Oid newNspOid,
17401  bool hasDependEntry,
17402  ObjectAddresses *objsMoved)
17403 {
17404  HeapTuple classTup;
17405  Form_pg_class classForm;
17406  ObjectAddress thisobj;
17407  bool already_done = false;
17408 
17409  /* no rel lock for relkind=c so use LOCKTAG_TUPLE */
17410  classTup = SearchSysCacheLockedCopy1(RELOID, ObjectIdGetDatum(relOid));
17411  if (!HeapTupleIsValid(classTup))
17412  elog(ERROR, "cache lookup failed for relation %u", relOid);
17413  classForm = (Form_pg_class) GETSTRUCT(classTup);
17414 
17415  Assert(classForm->relnamespace == oldNspOid);
17416 
17417  thisobj.classId = RelationRelationId;
17418  thisobj.objectId = relOid;
17419  thisobj.objectSubId = 0;
17420 
17421  /*
17422  * If the object has already been moved, don't move it again. If it's
17423  * already in the right place, don't move it, but still fire the object
17424  * access hook.
17425  */
17426  already_done = object_address_present(&thisobj, objsMoved);
17427  if (!already_done && oldNspOid != newNspOid)
17428  {
17429  ItemPointerData otid = classTup->t_self;
17430 
17431  /* check for duplicate name (more friendly than unique-index failure) */
17432  if (get_relname_relid(NameStr(classForm->relname),
17433  newNspOid) != InvalidOid)
17434  ereport(ERROR,
17435  (errcode(ERRCODE_DUPLICATE_TABLE),
17436  errmsg("relation \"%s\" already exists in schema \"%s\"",
17437  NameStr(classForm->relname),
17438  get_namespace_name(newNspOid))));
17439 
17440  /* classTup is a copy, so OK to scribble on */
17441  classForm->relnamespace = newNspOid;
17442 
17443  CatalogTupleUpdate(classRel, &otid, classTup);
17444  UnlockTuple(classRel, &otid, InplaceUpdateTupleLock);
17445 
17446 
17447  /* Update dependency on schema if caller said so */
17448  if (hasDependEntry &&
17449  changeDependencyFor(RelationRelationId,
17450  relOid,
17451  NamespaceRelationId,
17452  oldNspOid,
17453  newNspOid) != 1)
17454  elog(ERROR, "could not change schema dependency for relation \"%s\"",
17455  NameStr(classForm->relname));
17456  }
17457  else
17458  UnlockTuple(classRel, &classTup->t_self, InplaceUpdateTupleLock);
17459  if (!already_done)
17460  {
17461  add_exact_object_address(&thisobj, objsMoved);
17462 
17463  InvokeObjectPostAlterHook(RelationRelationId, relOid, 0);
17464  }
17465 
17466  heap_freetuple(classTup);
17467 }
17468 
17469 /*
17470  * Move all indexes for the specified relation to another namespace.
17471  *
17472  * Note: we assume adequate permission checking was done by the caller,
17473  * and that the caller has a suitable lock on the owning relation.
17474  */
17475 static void
17477  Oid oldNspOid, Oid newNspOid, ObjectAddresses *objsMoved)
17478 {
17479  List *indexList;
17480  ListCell *l;
17481 
17482  indexList = RelationGetIndexList(rel);
17483 
17484  foreach(l, indexList)
17485  {
17486  Oid indexOid = lfirst_oid(l);
17487  ObjectAddress thisobj;
17488 
17489  thisobj.classId = RelationRelationId;
17490  thisobj.objectId = indexOid;
17491  thisobj.objectSubId = 0;
17492 
17493  /*
17494  * Note: currently, the index will not have its own dependency on the
17495  * namespace, so we don't need to do changeDependencyFor(). There's no
17496  * row type in pg_type, either.
17497  *
17498  * XXX this objsMoved test may be pointless -- surely we have a single
17499  * dependency link from a relation to each index?
17500  */
17501  if (!object_address_present(&thisobj, objsMoved))
17502  {
17503  AlterRelationNamespaceInternal(classRel, indexOid,
17504  oldNspOid, newNspOid,
17505  false, objsMoved);
17506  add_exact_object_address(&thisobj, objsMoved);
17507  }
17508  }
17509 
17510  list_free(indexList);
17511 }
17512 
17513 /*
17514  * Move all identity and SERIAL-column sequences of the specified relation to another
17515  * namespace.
17516  *
17517  * Note: we assume adequate permission checking was done by the caller,
17518  * and that the caller has a suitable lock on the owning relation.
17519  */
17520 static void
17522  Oid oldNspOid, Oid newNspOid, ObjectAddresses *objsMoved,
17523  LOCKMODE lockmode)
17524 {
17525  Relation depRel;
17526  SysScanDesc scan;
17527  ScanKeyData key[2];
17528  HeapTuple tup;
17529 
17530  /*
17531  * SERIAL sequences are those having an auto dependency on one of the
17532  * table's columns (we don't care *which* column, exactly).
17533  */
17534  depRel = table_open(DependRelationId, AccessShareLock);
17535 
17536  ScanKeyInit(&key[0],
17537  Anum_pg_depend_refclassid,
17538  BTEqualStrategyNumber, F_OIDEQ,
17539  ObjectIdGetDatum(RelationRelationId));
17540  ScanKeyInit(&key[1],
17541  Anum_pg_depend_refobjid,
17542  BTEqualStrategyNumber, F_OIDEQ,
17544  /* we leave refobjsubid unspecified */
17545 
17546  scan = systable_beginscan(depRel, DependReferenceIndexId, true,
17547  NULL, 2, key);
17548 
17549  while (HeapTupleIsValid(tup = systable_getnext(scan)))
17550  {
17551  Form_pg_depend depForm = (Form_pg_depend) GETSTRUCT(tup);
17552  Relation seqRel;
17553 
17554  /* skip dependencies other than auto dependencies on columns */
17555  if (depForm->refobjsubid == 0 ||
17556  depForm->classid != RelationRelationId ||
17557  depForm->objsubid != 0 ||
17558  !(depForm->deptype == DEPENDENCY_AUTO || depForm->deptype == DEPENDENCY_INTERNAL))
17559  continue;
17560 
17561  /* Use relation_open just in case it's an index */
17562  seqRel = relation_open(depForm->objid, lockmode);
17563 
17564  /* skip non-sequence relations */
17565  if (RelationGetForm(seqRel)->relkind != RELKIND_SEQUENCE)
17566  {
17567  /* No need to keep the lock */
17568  relation_close(seqRel, lockmode);
17569  continue;
17570  }
17571 
17572  /* Fix the pg_class and pg_depend entries */
17573  AlterRelationNamespaceInternal(classRel, depForm->objid,
17574  oldNspOid, newNspOid,
17575  true, objsMoved);
17576 
17577  /*
17578  * Sequences used to have entries in pg_type, but no longer do. If we
17579  * ever re-instate that, we'll need to move the pg_type entry to the
17580  * new namespace, too (using AlterTypeNamespaceInternal).
17581  */
17582  Assert(RelationGetForm(seqRel)->reltype == InvalidOid);
17583 
17584  /* Now we can close it. Keep the lock till end of transaction. */
17585  relation_close(seqRel, NoLock);
17586  }
17587 
17588  systable_endscan(scan);
17589 
17591 }
17592 
17593 
17594 /*
17595  * This code supports
17596  * CREATE TEMP TABLE ... ON COMMIT { DROP | PRESERVE ROWS | DELETE ROWS }
17597  *
17598  * Because we only support this for TEMP tables, it's sufficient to remember
17599  * the state in a backend-local data structure.
17600  */
17601 
17602 /*
17603  * Register a newly-created relation's ON COMMIT action.
17604  */
17605 void
17607 {
17608  OnCommitItem *oc;
17609  MemoryContext oldcxt;
17610 
17611  /*
17612  * We needn't bother registering the relation unless there is an ON COMMIT
17613  * action we need to take.
17614  */
17616  return;
17617 
17619 
17620  oc = (OnCommitItem *) palloc(sizeof(OnCommitItem));
17621  oc->relid = relid;
17622  oc->oncommit = action;
17625 
17626  /*
17627  * We use lcons() here so that ON COMMIT actions are processed in reverse
17628  * order of registration. That might not be essential but it seems
17629  * reasonable.
17630  */
17631  on_commits = lcons(oc, on_commits);
17632 
17633  MemoryContextSwitchTo(oldcxt);
17634 }
17635 
17636 /*
17637  * Unregister any ON COMMIT action when a relation is deleted.
17638  *
17639  * Actually, we only mark the OnCommitItem entry as to be deleted after commit.
17640  */
17641 void
17643 {
17644  ListCell *l;
17645 
17646  foreach(l, on_commits)
17647  {
17648  OnCommitItem *oc = (OnCommitItem *) lfirst(l);
17649 
17650  if (oc->relid == relid)
17651  {
17653  break;
17654  }
17655  }
17656 }
17657 
17658 /*
17659  * Perform ON COMMIT actions.
17660  *
17661  * This is invoked just before actually committing, since it's possible
17662  * to encounter errors.
17663  */
17664 void
17666 {
17667  ListCell *l;
17668  List *oids_to_truncate = NIL;
17669  List *oids_to_drop = NIL;
17670 
17671  foreach(l, on_commits)
17672  {
17673  OnCommitItem *oc = (OnCommitItem *) lfirst(l);
17674 
17675  /* Ignore entry if already dropped in this xact */
17677  continue;
17678 
17679  switch (oc->oncommit)
17680  {
17681  case ONCOMMIT_NOOP:
17683  /* Do nothing (there shouldn't be such entries, actually) */
17684  break;
17685  case ONCOMMIT_DELETE_ROWS:
17686 
17687  /*
17688  * If this transaction hasn't accessed any temporary
17689  * relations, we can skip truncating ON COMMIT DELETE ROWS
17690  * tables, as they must still be empty.
17691  */
17693  oids_to_truncate = lappend_oid(oids_to_truncate, oc->relid);
17694  break;
17695  case ONCOMMIT_DROP:
17696  oids_to_drop = lappend_oid(oids_to_drop, oc->relid);
17697  break;
17698  }
17699  }
17700 
17701  /*
17702  * Truncate relations before dropping so that all dependencies between
17703  * relations are removed after they are worked on. Doing it like this
17704  * might be a waste as it is possible that a relation being truncated will
17705  * be dropped anyway due to its parent being dropped, but this makes the
17706  * code more robust because of not having to re-check that the relation
17707  * exists at truncation time.
17708  */
17709  if (oids_to_truncate != NIL)
17710  heap_truncate(oids_to_truncate);
17711 
17712  if (oids_to_drop != NIL)
17713  {
17714  ObjectAddresses *targetObjects = new_object_addresses();
17715 
17716  foreach(l, oids_to_drop)
17717  {
17718  ObjectAddress object;
17719 
17720  object.classId = RelationRelationId;
17721  object.objectId = lfirst_oid(l);
17722  object.objectSubId = 0;
17723 
17724  Assert(!object_address_present(&object, targetObjects));
17725 
17726  add_exact_object_address(&object, targetObjects);
17727  }
17728 
17729  /*
17730  * Object deletion might involve toast table access (to clean up
17731  * toasted catalog entries), so ensure we have a valid snapshot.
17732  */
17734 
17735  /*
17736  * Since this is an automatic drop, rather than one directly initiated
17737  * by the user, we pass the PERFORM_DELETION_INTERNAL flag.
17738  */
17739  performMultipleDeletions(targetObjects, DROP_CASCADE,
17741 
17743 
17744 #ifdef USE_ASSERT_CHECKING
17745 
17746  /*
17747  * Note that table deletion will call remove_on_commit_action, so the
17748  * entry should get marked as deleted.
17749  */
17750  foreach(l, on_commits)
17751  {
17752  OnCommitItem *oc = (OnCommitItem *) lfirst(l);
17753 
17754  if (oc->oncommit != ONCOMMIT_DROP)
17755  continue;
17756 
17758  }
17759 #endif
17760  }
17761 }
17762 
17763 /*
17764  * Post-commit or post-abort cleanup for ON COMMIT management.
17765  *
17766  * All we do here is remove no-longer-needed OnCommitItem entries.
17767  *
17768  * During commit, remove entries that were deleted during this transaction;
17769  * during abort, remove those created during this transaction.
17770  */
17771 void
17773 {
17774  ListCell *cur_item;
17775 
17776  foreach(cur_item, on_commits)
17777  {
17778  OnCommitItem *oc = (OnCommitItem *) lfirst(cur_item);
17779 
17780  if (isCommit ? oc->deleting_subid != InvalidSubTransactionId :
17782  {
17783  /* cur_item must be removed */
17785  pfree(oc);
17786  }
17787  else
17788  {
17789  /* cur_item must be preserved */
17792  }
17793  }
17794 }
17795 
17796 /*
17797  * Post-subcommit or post-subabort cleanup for ON COMMIT management.
17798  *
17799  * During subabort, we can immediately remove entries created during this
17800  * subtransaction. During subcommit, just relabel entries marked during
17801  * this subtransaction as being the parent's responsibility.
17802  */
17803 void
17805  SubTransactionId parentSubid)
17806 {
17807  ListCell *cur_item;
17808 
17809  foreach(cur_item, on_commits)
17810  {
17811  OnCommitItem *oc = (OnCommitItem *) lfirst(cur_item);
17812 
17813  if (!isCommit && oc->creating_subid == mySubid)
17814  {
17815  /* cur_item must be removed */
17817  pfree(oc);
17818  }
17819  else
17820  {
17821  /* cur_item must be preserved */
17822  if (oc->creating_subid == mySubid)
17823  oc->creating_subid = parentSubid;
17824  if (oc->deleting_subid == mySubid)
17825  oc->deleting_subid = isCommit ? parentSubid : InvalidSubTransactionId;
17826  }
17827  }
17828 }
17829 
17830 /*
17831  * This is intended as a callback for RangeVarGetRelidExtended(). It allows
17832  * the relation to be locked only if (1) it's a plain or partitioned table,
17833  * materialized view, or TOAST table and (2) the current user is the owner (or
17834  * the superuser) or has been granted MAINTAIN. This meets the
17835  * permission-checking needs of CLUSTER, REINDEX TABLE, and REFRESH
17836  * MATERIALIZED VIEW; we expose it here so that it can be used by all.
17837  */
17838 void
17840  Oid relId, Oid oldRelId, void *arg)
17841 {
17842  char relkind;
17843  AclResult aclresult;
17844 
17845  /* Nothing to do if the relation was not found. */
17846  if (!OidIsValid(relId))
17847  return;
17848 
17849  /*
17850  * If the relation does exist, check whether it's an index. But note that
17851  * the relation might have been dropped between the time we did the name
17852  * lookup and now. In that case, there's nothing to do.
17853  */
17854  relkind = get_rel_relkind(relId);
17855  if (!relkind)
17856  return;
17857  if (relkind != RELKIND_RELATION && relkind != RELKIND_TOASTVALUE &&
17858  relkind != RELKIND_MATVIEW && relkind != RELKIND_PARTITIONED_TABLE)
17859  ereport(ERROR,
17860  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
17861  errmsg("\"%s\" is not a table or materialized view", relation->relname)));
17862 
17863  /* Check permissions */
17864  aclresult = pg_class_aclcheck(relId, GetUserId(), ACL_MAINTAIN);
17865  if (aclresult != ACLCHECK_OK)
17866  aclcheck_error(aclresult,
17868  relation->relname);
17869 }
17870 
17871 /*
17872  * Callback to RangeVarGetRelidExtended() for TRUNCATE processing.
17873  */
17874 static void
17876  Oid relId, Oid oldRelId, void *arg)
17877 {
17878  HeapTuple tuple;
17879 
17880  /* Nothing to do if the relation was not found. */
17881  if (!OidIsValid(relId))
17882  return;
17883 
17884  tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relId));
17885  if (!HeapTupleIsValid(tuple)) /* should not happen */
17886  elog(ERROR, "cache lookup failed for relation %u", relId);
17887 
17888  truncate_check_rel(relId, (Form_pg_class) GETSTRUCT(tuple));
17889  truncate_check_perms(relId, (Form_pg_class) GETSTRUCT(tuple));
17890 
17891  ReleaseSysCache(tuple);
17892 }
17893 
17894 /*
17895  * Callback for RangeVarGetRelidExtended(). Checks that the current user is
17896  * the owner of the relation, or superuser.
17897  */
17898 void
17900  Oid relId, Oid oldRelId, void *arg)
17901 {
17902  HeapTuple tuple;
17903 
17904  /* Nothing to do if the relation was not found. */
17905  if (!OidIsValid(relId))
17906  return;
17907 
17908  tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relId));
17909  if (!HeapTupleIsValid(tuple)) /* should not happen */
17910  elog(ERROR, "cache lookup failed for relation %u", relId);
17911 
17912  if (!object_ownercheck(RelationRelationId, relId, GetUserId()))
17914  relation->relname);
17915 
17916  if (!allowSystemTableMods &&
17917  IsSystemClass(relId, (Form_pg_class) GETSTRUCT(tuple)))
17918  ereport(ERROR,
17919  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
17920  errmsg("permission denied: \"%s\" is a system catalog",
17921  relation->relname)));
17922 
17923  ReleaseSysCache(tuple);
17924 }
17925 
17926 /*
17927  * Common RangeVarGetRelid callback for rename, set schema, and alter table
17928  * processing.
17929  */
17930 static void
17932  void *arg)
17933 {
17934  Node *stmt = (Node *) arg;
17935  ObjectType reltype;
17936  HeapTuple tuple;
17937  Form_pg_class classform;
17938  AclResult aclresult;
17939  char relkind;
17940 
17941  tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
17942  if (!HeapTupleIsValid(tuple))
17943  return; /* concurrently dropped */
17944  classform = (Form_pg_class) GETSTRUCT(tuple);
17945  relkind = classform->relkind;
17946 
17947  /* Must own relation. */
17948  if (!object_ownercheck(RelationRelationId, relid, GetUserId()))
17950 
17951  /* No system table modifications unless explicitly allowed. */
17952  if (!allowSystemTableMods && IsSystemClass(relid, classform))
17953  ereport(ERROR,
17954  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
17955  errmsg("permission denied: \"%s\" is a system catalog",
17956  rv->relname)));
17957 
17958  /*
17959  * Extract the specified relation type from the statement parse tree.
17960  *
17961  * Also, for ALTER .. RENAME, check permissions: the user must (still)
17962  * have CREATE rights on the containing namespace.
17963  */
17964  if (IsA(stmt, RenameStmt))
17965  {
17966  aclresult = object_aclcheck(NamespaceRelationId, classform->relnamespace,
17967  GetUserId(), ACL_CREATE);
17968  if (aclresult != ACLCHECK_OK)
17969  aclcheck_error(aclresult, OBJECT_SCHEMA,
17970  get_namespace_name(classform->relnamespace));
17971  reltype = ((RenameStmt *) stmt)->renameType;
17972  }
17973  else if (IsA(stmt, AlterObjectSchemaStmt))
17974  reltype = ((AlterObjectSchemaStmt *) stmt)->objectType;
17975 
17976  else if (IsA(stmt, AlterTableStmt))
17977  reltype = ((AlterTableStmt *) stmt)->objtype;
17978  else
17979  {
17980  elog(ERROR, "unrecognized node type: %d", (int) nodeTag(stmt));
17981  reltype = OBJECT_TABLE; /* placate compiler */
17982  }
17983 
17984  /*
17985  * For compatibility with prior releases, we allow ALTER TABLE to be used
17986  * with most other types of relations (but not composite types). We allow
17987  * similar flexibility for ALTER INDEX in the case of RENAME, but not
17988  * otherwise. Otherwise, the user must select the correct form of the
17989  * command for the relation at issue.
17990  */
17991  if (reltype == OBJECT_SEQUENCE && relkind != RELKIND_SEQUENCE)
17992  ereport(ERROR,
17993  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
17994  errmsg("\"%s\" is not a sequence", rv->relname)));
17995 
17996  if (reltype == OBJECT_VIEW && relkind != RELKIND_VIEW)
17997  ereport(ERROR,
17998  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
17999  errmsg("\"%s\" is not a view", rv->relname)));
18000 
18001  if (reltype == OBJECT_MATVIEW && relkind != RELKIND_MATVIEW)
18002  ereport(ERROR,
18003  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
18004  errmsg("\"%s\" is not a materialized view", rv->relname)));
18005 
18006  if (reltype == OBJECT_FOREIGN_TABLE && relkind != RELKIND_FOREIGN_TABLE)
18007  ereport(ERROR,
18008  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
18009  errmsg("\"%s\" is not a foreign table", rv->relname)));
18010 
18011  if (reltype == OBJECT_TYPE && relkind != RELKIND_COMPOSITE_TYPE)
18012  ereport(ERROR,
18013  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
18014  errmsg("\"%s\" is not a composite type", rv->relname)));
18015 
18016  if (reltype == OBJECT_INDEX && relkind != RELKIND_INDEX &&
18017  relkind != RELKIND_PARTITIONED_INDEX
18018  && !IsA(stmt, RenameStmt))
18019  ereport(ERROR,
18020  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
18021  errmsg("\"%s\" is not an index", rv->relname)));
18022 
18023  /*
18024  * Don't allow ALTER TABLE on composite types. We want people to use ALTER
18025  * TYPE for that.
18026  */
18027  if (reltype != OBJECT_TYPE && relkind == RELKIND_COMPOSITE_TYPE)
18028  ereport(ERROR,
18029  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
18030  errmsg("\"%s\" is a composite type", rv->relname),
18031  /* translator: %s is an SQL ALTER command */
18032  errhint("Use %s instead.",
18033  "ALTER TYPE")));
18034 
18035  /*
18036  * Don't allow ALTER TABLE .. SET SCHEMA on relations that can't be moved
18037  * to a different schema, such as indexes and TOAST tables.
18038  */
18040  {
18041  if (relkind == RELKIND_INDEX || relkind == RELKIND_PARTITIONED_INDEX)
18042  ereport(ERROR,
18043  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
18044  errmsg("cannot change schema of index \"%s\"",
18045  rv->relname),
18046  errhint("Change the schema of the table instead.")));
18047  else if (relkind == RELKIND_COMPOSITE_TYPE)
18048  ereport(ERROR,
18049  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
18050  errmsg("cannot change schema of composite type \"%s\"",
18051  rv->relname),
18052  /* translator: %s is an SQL ALTER command */
18053  errhint("Use %s instead.",
18054  "ALTER TYPE")));
18055  else if (relkind == RELKIND_TOASTVALUE)
18056  ereport(ERROR,
18057  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
18058  errmsg("cannot change schema of TOAST table \"%s\"",
18059  rv->relname),
18060  errhint("Change the schema of the table instead.")));
18061  }
18062 
18063  ReleaseSysCache(tuple);
18064 }
18065 
18066 /*
18067  * Transform any expressions present in the partition key
18068  *
18069  * Returns a transformed PartitionSpec.
18070  */
18071 static PartitionSpec *
18073 {
18074  PartitionSpec *newspec;
18075  ParseState *pstate;
18076  ParseNamespaceItem *nsitem;
18077  ListCell *l;
18078 
18079  newspec = makeNode(PartitionSpec);
18080 
18081  newspec->strategy = partspec->strategy;
18082  newspec->partParams = NIL;
18083  newspec->location = partspec->location;
18084 
18085  /* Check valid number of columns for strategy */
18086  if (partspec->strategy == PARTITION_STRATEGY_LIST &&
18087  list_length(partspec->partParams) != 1)
18088  ereport(ERROR,
18089  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
18090  errmsg("cannot use \"list\" partition strategy with more than one column")));
18091 
18092  /*
18093  * Create a dummy ParseState and insert the target relation as its sole
18094  * rangetable entry. We need a ParseState for transformExpr.
18095  */
18096  pstate = make_parsestate(NULL);
18097  nsitem = addRangeTableEntryForRelation(pstate, rel, AccessShareLock,
18098  NULL, false, true);
18099  addNSItemToQuery(pstate, nsitem, true, true, true);
18100 
18101  /* take care of any partition expressions */
18102  foreach(l, partspec->partParams)
18103  {
18105 
18106  if (pelem->expr)
18107  {
18108  /* Copy, to avoid scribbling on the input */
18109  pelem = copyObject(pelem);
18110 
18111  /* Now do parse transformation of the expression */
18112  pelem->expr = transformExpr(pstate, pelem->expr,
18114 
18115  /* we have to fix its collations too */
18116  assign_expr_collations(pstate, pelem->expr);
18117  }
18118 
18119  newspec->partParams = lappend(newspec->partParams, pelem);
18120  }
18121 
18122  return newspec;
18123 }
18124 
18125 /*
18126  * Compute per-partition-column information from a list of PartitionElems.
18127  * Expressions in the PartitionElems must be parse-analyzed already.
18128  */
18129 static void
18130 ComputePartitionAttrs(ParseState *pstate, Relation rel, List *partParams, AttrNumber *partattrs,
18131  List **partexprs, Oid *partopclass, Oid *partcollation,
18132  PartitionStrategy strategy)
18133 {
18134  int attn;
18135  ListCell *lc;
18136  Oid am_oid;
18137 
18138  attn = 0;
18139  foreach(lc, partParams)
18140  {
18141  PartitionElem *pelem = lfirst_node(PartitionElem, lc);
18142  Oid atttype;
18143  Oid attcollation;
18144 
18145  if (pelem->name != NULL)
18146  {
18147  /* Simple attribute reference */
18148  HeapTuple atttuple;
18149  Form_pg_attribute attform;
18150 
18151  atttuple = SearchSysCacheAttName(RelationGetRelid(rel),
18152  pelem->name);
18153  if (!HeapTupleIsValid(atttuple))
18154  ereport(ERROR,
18155  (errcode(ERRCODE_UNDEFINED_COLUMN),
18156  errmsg("column \"%s\" named in partition key does not exist",
18157  pelem->name),
18158  parser_errposition(pstate, pelem->location)));
18159  attform = (Form_pg_attribute) GETSTRUCT(atttuple);
18160 
18161  if (attform->attnum <= 0)
18162  ereport(ERROR,
18163  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
18164  errmsg("cannot use system column \"%s\" in partition key",
18165  pelem->name),
18166  parser_errposition(pstate, pelem->location)));
18167 
18168  /*
18169  * Generated columns cannot work: They are computed after BEFORE
18170  * triggers, but partition routing is done before all triggers.
18171  */
18172  if (attform->attgenerated)
18173  ereport(ERROR,
18174  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
18175  errmsg("cannot use generated column in partition key"),
18176  errdetail("Column \"%s\" is a generated column.",
18177  pelem->name),
18178  parser_errposition(pstate, pelem->location)));
18179 
18180  partattrs[attn] = attform->attnum;
18181  atttype = attform->atttypid;
18182  attcollation = attform->attcollation;
18183  ReleaseSysCache(atttuple);
18184  }
18185  else
18186  {
18187  /* Expression */
18188  Node *expr = pelem->expr;
18189  char partattname[16];
18190 
18191  Assert(expr != NULL);
18192  atttype = exprType(expr);
18193  attcollation = exprCollation(expr);
18194 
18195  /*
18196  * The expression must be of a storable type (e.g., not RECORD).
18197  * The test is the same as for whether a table column is of a safe
18198  * type (which is why we needn't check for the non-expression
18199  * case).
18200  */
18201  snprintf(partattname, sizeof(partattname), "%d", attn + 1);
18202  CheckAttributeType(partattname,
18203  atttype, attcollation,
18205 
18206  /*
18207  * Strip any top-level COLLATE clause. This ensures that we treat
18208  * "x COLLATE y" and "(x COLLATE y)" alike.
18209  */
18210  while (IsA(expr, CollateExpr))
18211  expr = (Node *) ((CollateExpr *) expr)->arg;
18212 
18213  if (IsA(expr, Var) &&
18214  ((Var *) expr)->varattno > 0)
18215  {
18216  /*
18217  * User wrote "(column)" or "(column COLLATE something)".
18218  * Treat it like simple attribute anyway.
18219  */
18220  partattrs[attn] = ((Var *) expr)->varattno;
18221  }
18222  else
18223  {
18224  Bitmapset *expr_attrs = NULL;
18225  int i;
18226 
18227  partattrs[attn] = 0; /* marks the column as expression */
18228  *partexprs = lappend(*partexprs, expr);
18229 
18230  /*
18231  * transformPartitionSpec() should have already rejected
18232  * subqueries, aggregates, window functions, and SRFs, based
18233  * on the EXPR_KIND_ for partition expressions.
18234  */
18235 
18236  /*
18237  * Cannot allow system column references, since that would
18238  * make partition routing impossible: their values won't be
18239  * known yet when we need to do that.
18240  */
18241  pull_varattnos(expr, 1, &expr_attrs);
18242  for (i = FirstLowInvalidHeapAttributeNumber; i < 0; i++)
18243  {
18245  expr_attrs))
18246  ereport(ERROR,
18247  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
18248  errmsg("partition key expressions cannot contain system column references")));
18249  }
18250 
18251  /*
18252  * Generated columns cannot work: They are computed after
18253  * BEFORE triggers, but partition routing is done before all
18254  * triggers.
18255  */
18256  i = -1;
18257  while ((i = bms_next_member(expr_attrs, i)) >= 0)
18258  {
18260 
18261  if (attno > 0 &&
18262  TupleDescAttr(RelationGetDescr(rel), attno - 1)->attgenerated)
18263  ereport(ERROR,
18264  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
18265  errmsg("cannot use generated column in partition key"),
18266  errdetail("Column \"%s\" is a generated column.",
18267  get_attname(RelationGetRelid(rel), attno, false)),
18268  parser_errposition(pstate, pelem->location)));
18269  }
18270 
18271  /*
18272  * Preprocess the expression before checking for mutability.
18273  * This is essential for the reasons described in
18274  * contain_mutable_functions_after_planning. However, we call
18275  * expression_planner for ourselves rather than using that
18276  * function, because if constant-folding reduces the
18277  * expression to a constant, we'd like to know that so we can
18278  * complain below.
18279  *
18280  * Like contain_mutable_functions_after_planning, assume that
18281  * expression_planner won't scribble on its input, so this
18282  * won't affect the partexprs entry we saved above.
18283  */
18284  expr = (Node *) expression_planner((Expr *) expr);
18285 
18286  /*
18287  * Partition expressions cannot contain mutable functions,
18288  * because a given row must always map to the same partition
18289  * as long as there is no change in the partition boundary
18290  * structure.
18291  */
18292  if (contain_mutable_functions(expr))
18293  ereport(ERROR,
18294  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
18295  errmsg("functions in partition key expression must be marked IMMUTABLE")));
18296 
18297  /*
18298  * While it is not exactly *wrong* for a partition expression
18299  * to be a constant, it seems better to reject such keys.
18300  */
18301  if (IsA(expr, Const))
18302  ereport(ERROR,
18303  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
18304  errmsg("cannot use constant expression as partition key")));
18305  }
18306  }
18307 
18308  /*
18309  * Apply collation override if any
18310  */
18311  if (pelem->collation)
18312  attcollation = get_collation_oid(pelem->collation, false);
18313 
18314  /*
18315  * Check we have a collation iff it's a collatable type. The only
18316  * expected failures here are (1) COLLATE applied to a noncollatable
18317  * type, or (2) partition expression had an unresolved collation. But
18318  * we might as well code this to be a complete consistency check.
18319  */
18320  if (type_is_collatable(atttype))
18321  {
18322  if (!OidIsValid(attcollation))
18323  ereport(ERROR,
18324  (errcode(ERRCODE_INDETERMINATE_COLLATION),
18325  errmsg("could not determine which collation to use for partition expression"),
18326  errhint("Use the COLLATE clause to set the collation explicitly.")));
18327  }
18328  else
18329  {
18330  if (OidIsValid(attcollation))
18331  ereport(ERROR,
18332  (errcode(ERRCODE_DATATYPE_MISMATCH),
18333  errmsg("collations are not supported by type %s",
18334  format_type_be(atttype))));
18335  }
18336 
18337  partcollation[attn] = attcollation;
18338 
18339  /*
18340  * Identify the appropriate operator class. For list and range
18341  * partitioning, we use a btree operator class; hash partitioning uses
18342  * a hash operator class.
18343  */
18344  if (strategy == PARTITION_STRATEGY_HASH)
18345  am_oid = HASH_AM_OID;
18346  else
18347  am_oid = BTREE_AM_OID;
18348 
18349  if (!pelem->opclass)
18350  {
18351  partopclass[attn] = GetDefaultOpClass(atttype, am_oid);
18352 
18353  if (!OidIsValid(partopclass[attn]))
18354  {
18355  if (strategy == PARTITION_STRATEGY_HASH)
18356  ereport(ERROR,
18357  (errcode(ERRCODE_UNDEFINED_OBJECT),
18358  errmsg("data type %s has no default operator class for access method \"%s\"",
18359  format_type_be(atttype), "hash"),
18360  errhint("You must specify a hash operator class or define a default hash operator class for the data type.")));
18361  else
18362  ereport(ERROR,
18363  (errcode(ERRCODE_UNDEFINED_OBJECT),
18364  errmsg("data type %s has no default operator class for access method \"%s\"",
18365  format_type_be(atttype), "btree"),
18366  errhint("You must specify a btree operator class or define a default btree operator class for the data type.")));
18367  }
18368  }
18369  else
18370  partopclass[attn] = ResolveOpClass(pelem->opclass,
18371  atttype,
18372  am_oid == HASH_AM_OID ? "hash" : "btree",
18373  am_oid);
18374 
18375  attn++;
18376  }
18377 }
18378 
18379 /*
18380  * PartConstraintImpliedByRelConstraint
18381  * Do scanrel's existing constraints imply the partition constraint?
18382  *
18383  * "Existing constraints" include its check constraints and column-level
18384  * not-null constraints. partConstraint describes the partition constraint,
18385  * in implicit-AND form.
18386  */
18387 bool
18389  List *partConstraint)
18390 {
18391  List *existConstraint = NIL;
18392  TupleConstr *constr = RelationGetDescr(scanrel)->constr;
18393  int i;
18394 
18395  if (constr && constr->has_not_null)
18396  {
18397  int natts = scanrel->rd_att->natts;
18398 
18399  for (i = 1; i <= natts; i++)
18400  {
18401  Form_pg_attribute att = TupleDescAttr(scanrel->rd_att, i - 1);
18402 
18403  if (att->attnotnull && !att->attisdropped)
18404  {
18405  NullTest *ntest = makeNode(NullTest);
18406 
18407  ntest->arg = (Expr *) makeVar(1,
18408  i,
18409  att->atttypid,
18410  att->atttypmod,
18411  att->attcollation,
18412  0);
18413  ntest->nulltesttype = IS_NOT_NULL;
18414 
18415  /*
18416  * argisrow=false is correct even for a composite column,
18417  * because attnotnull does not represent a SQL-spec IS NOT
18418  * NULL test in such a case, just IS DISTINCT FROM NULL.
18419  */
18420  ntest->argisrow = false;
18421  ntest->location = -1;
18422  existConstraint = lappend(existConstraint, ntest);
18423  }
18424  }
18425  }
18426 
18427  return ConstraintImpliedByRelConstraint(scanrel, partConstraint, existConstraint);
18428 }
18429 
18430 /*
18431  * ConstraintImpliedByRelConstraint
18432  * Do scanrel's existing constraints imply the given constraint?
18433  *
18434  * testConstraint is the constraint to validate. provenConstraint is a
18435  * caller-provided list of conditions which this function may assume
18436  * to be true. Both provenConstraint and testConstraint must be in
18437  * implicit-AND form, must only contain immutable clauses, and must
18438  * contain only Vars with varno = 1.
18439  */
18440 bool
18441 ConstraintImpliedByRelConstraint(Relation scanrel, List *testConstraint, List *provenConstraint)
18442 {
18443  List *existConstraint = list_copy(provenConstraint);
18444  TupleConstr *constr = RelationGetDescr(scanrel)->constr;
18445  int num_check,
18446  i;
18447 
18448  num_check = (constr != NULL) ? constr->num_check : 0;
18449  for (i = 0; i < num_check; i++)
18450  {
18451  Node *cexpr;
18452 
18453  /*
18454  * If this constraint hasn't been fully validated yet, we must ignore
18455  * it here.
18456  */
18457  if (!constr->check[i].ccvalid)
18458  continue;
18459 
18460  cexpr = stringToNode(constr->check[i].ccbin);
18461 
18462  /*
18463  * Run each expression through const-simplification and
18464  * canonicalization. It is necessary, because we will be comparing it
18465  * to similarly-processed partition constraint expressions, and may
18466  * fail to detect valid matches without this.
18467  */
18468  cexpr = eval_const_expressions(NULL, cexpr);
18469  cexpr = (Node *) canonicalize_qual((Expr *) cexpr, true);
18470 
18471  existConstraint = list_concat(existConstraint,
18472  make_ands_implicit((Expr *) cexpr));
18473  }
18474 
18475  /*
18476  * Try to make the proof. Since we are comparing CHECK constraints, we
18477  * need to use weak implication, i.e., we assume existConstraint is
18478  * not-false and try to prove the same for testConstraint.
18479  *
18480  * Note that predicate_implied_by assumes its first argument is known
18481  * immutable. That should always be true for both NOT NULL and partition
18482  * constraints, so we don't test it here.
18483  */
18484  return predicate_implied_by(testConstraint, existConstraint, true);
18485 }
18486 
18487 /*
18488  * QueuePartitionConstraintValidation
18489  *
18490  * Add an entry to wqueue to have the given partition constraint validated by
18491  * Phase 3, for the given relation, and all its children.
18492  *
18493  * We first verify whether the given constraint is implied by pre-existing
18494  * relation constraints; if it is, there's no need to scan the table to
18495  * validate, so don't queue in that case.
18496  */
18497 static void
18499  List *partConstraint,
18500  bool validate_default)
18501 {
18502  /*
18503  * Based on the table's existing constraints, determine whether or not we
18504  * may skip scanning the table.
18505  */
18506  if (PartConstraintImpliedByRelConstraint(scanrel, partConstraint))
18507  {
18508  if (!validate_default)
18509  ereport(DEBUG1,
18510  (errmsg_internal("partition constraint for table \"%s\" is implied by existing constraints",
18511  RelationGetRelationName(scanrel))));
18512  else
18513  ereport(DEBUG1,
18514  (errmsg_internal("updated partition constraint for default partition \"%s\" is implied by existing constraints",
18515  RelationGetRelationName(scanrel))));
18516  return;
18517  }
18518 
18519  /*
18520  * Constraints proved insufficient. For plain relations, queue a
18521  * validation item now; for partitioned tables, recurse to process each
18522  * partition.
18523  */
18524  if (scanrel->rd_rel->relkind == RELKIND_RELATION)
18525  {
18526  AlteredTableInfo *tab;
18527 
18528  /* Grab a work queue entry. */
18529  tab = ATGetQueueEntry(wqueue, scanrel);
18530  Assert(tab->partition_constraint == NULL);
18531  tab->partition_constraint = (Expr *) linitial(partConstraint);
18532  tab->validate_default = validate_default;
18533  }
18534  else if (scanrel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
18535  {
18536  PartitionDesc partdesc = RelationGetPartitionDesc(scanrel, true);
18537  int i;
18538 
18539  for (i = 0; i < partdesc->nparts; i++)
18540  {
18541  Relation part_rel;
18542  List *thisPartConstraint;
18543 
18544  /*
18545  * This is the minimum lock we need to prevent deadlocks.
18546  */
18547  part_rel = table_open(partdesc->oids[i], AccessExclusiveLock);
18548 
18549  /*
18550  * Adjust the constraint for scanrel so that it matches this
18551  * partition's attribute numbers.
18552  */
18553  thisPartConstraint =
18554  map_partition_varattnos(partConstraint, 1,
18555  part_rel, scanrel);
18556 
18557  QueuePartitionConstraintValidation(wqueue, part_rel,
18558  thisPartConstraint,
18559  validate_default);
18560  table_close(part_rel, NoLock); /* keep lock till commit */
18561  }
18562  }
18563 }
18564 
18565 /*
18566  * ALTER TABLE <name> ATTACH PARTITION <partition-name> FOR VALUES
18567  *
18568  * Return the address of the newly attached partition.
18569  */
18570 static ObjectAddress
18573 {
18574  Relation attachrel,
18575  catalog;
18576  List *attachrel_children;
18577  List *partConstraint;
18578  SysScanDesc scan;
18579  ScanKeyData skey;
18580  AttrNumber attno;
18581  int natts;
18582  TupleDesc tupleDesc;
18583  ObjectAddress address;
18584  const char *trigger_name;
18585  Oid defaultPartOid;
18586  List *partBoundConstraint;
18587  ParseState *pstate = make_parsestate(NULL);
18588 
18589  pstate->p_sourcetext = context->queryString;
18590 
18591  /*
18592  * We must lock the default partition if one exists, because attaching a
18593  * new partition will change its partition constraint.
18594  */
18595  defaultPartOid =
18597  if (OidIsValid(defaultPartOid))
18598  LockRelationOid(defaultPartOid, AccessExclusiveLock);
18599 
18600  attachrel = table_openrv(cmd->name, AccessExclusiveLock);
18601 
18602  /*
18603  * XXX I think it'd be a good idea to grab locks on all tables referenced
18604  * by FKs at this point also.
18605  */
18606 
18607  /*
18608  * Must be owner of both parent and source table -- parent was checked by
18609  * ATSimplePermissions call in ATPrepCmd
18610  */
18613 
18614  /* A partition can only have one parent */
18615  if (attachrel->rd_rel->relispartition)
18616  ereport(ERROR,
18617  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
18618  errmsg("\"%s\" is already a partition",
18619  RelationGetRelationName(attachrel))));
18620 
18621  if (OidIsValid(attachrel->rd_rel->reloftype))
18622  ereport(ERROR,
18623  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
18624  errmsg("cannot attach a typed table as partition")));
18625 
18626  /*
18627  * Table being attached should not already be part of inheritance; either
18628  * as a child table...
18629  */
18630  catalog = table_open(InheritsRelationId, AccessShareLock);
18631  ScanKeyInit(&skey,
18632  Anum_pg_inherits_inhrelid,
18633  BTEqualStrategyNumber, F_OIDEQ,
18634  ObjectIdGetDatum(RelationGetRelid(attachrel)));
18635  scan = systable_beginscan(catalog, InheritsRelidSeqnoIndexId, true,
18636  NULL, 1, &skey);
18638  ereport(ERROR,
18639  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
18640  errmsg("cannot attach inheritance child as partition")));
18641  systable_endscan(scan);
18642 
18643  /* ...or as a parent table (except the case when it is partitioned) */
18644  ScanKeyInit(&skey,
18645  Anum_pg_inherits_inhparent,
18646  BTEqualStrategyNumber, F_OIDEQ,
18647  ObjectIdGetDatum(RelationGetRelid(attachrel)));
18648  scan = systable_beginscan(catalog, InheritsParentIndexId, true, NULL,
18649  1, &skey);
18650  if (HeapTupleIsValid(systable_getnext(scan)) &&
18651  attachrel->rd_rel->relkind == RELKIND_RELATION)
18652  ereport(ERROR,
18653  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
18654  errmsg("cannot attach inheritance parent as partition")));
18655  systable_endscan(scan);
18656  table_close(catalog, AccessShareLock);
18657 
18658  /*
18659  * Prevent circularity by seeing if rel is a partition of attachrel. (In
18660  * particular, this disallows making a rel a partition of itself.)
18661  *
18662  * We do that by checking if rel is a member of the list of attachrel's
18663  * partitions provided the latter is partitioned at all. We want to avoid
18664  * having to construct this list again, so we request the strongest lock
18665  * on all partitions. We need the strongest lock, because we may decide
18666  * to scan them if we find out that the table being attached (or its leaf
18667  * partitions) may contain rows that violate the partition constraint. If
18668  * the table has a constraint that would prevent such rows, which by
18669  * definition is present in all the partitions, we need not scan the
18670  * table, nor its partitions. But we cannot risk a deadlock by taking a
18671  * weaker lock now and the stronger one only when needed.
18672  */
18673  attachrel_children = find_all_inheritors(RelationGetRelid(attachrel),
18674  AccessExclusiveLock, NULL);
18675  if (list_member_oid(attachrel_children, RelationGetRelid(rel)))
18676  ereport(ERROR,
18677  (errcode(ERRCODE_DUPLICATE_TABLE),
18678  errmsg("circular inheritance not allowed"),
18679  errdetail("\"%s\" is already a child of \"%s\".",
18681  RelationGetRelationName(attachrel))));
18682 
18683  /* If the parent is permanent, so must be all of its partitions. */
18684  if (rel->rd_rel->relpersistence != RELPERSISTENCE_TEMP &&
18685  attachrel->rd_rel->relpersistence == RELPERSISTENCE_TEMP)
18686  ereport(ERROR,
18687  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
18688  errmsg("cannot attach a temporary relation as partition of permanent relation \"%s\"",
18689  RelationGetRelationName(rel))));
18690 
18691  /* Temp parent cannot have a partition that is itself not a temp */
18692  if (rel->rd_rel->relpersistence == RELPERSISTENCE_TEMP &&
18693  attachrel->rd_rel->relpersistence != RELPERSISTENCE_TEMP)
18694  ereport(ERROR,
18695  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
18696  errmsg("cannot attach a permanent relation as partition of temporary relation \"%s\"",
18697  RelationGetRelationName(rel))));
18698 
18699  /* If the parent is temp, it must belong to this session */
18700  if (rel->rd_rel->relpersistence == RELPERSISTENCE_TEMP &&
18701  !rel->rd_islocaltemp)
18702  ereport(ERROR,
18703  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
18704  errmsg("cannot attach as partition of temporary relation of another session")));
18705 
18706  /* Ditto for the partition */
18707  if (attachrel->rd_rel->relpersistence == RELPERSISTENCE_TEMP &&
18708  !attachrel->rd_islocaltemp)
18709  ereport(ERROR,
18710  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
18711  errmsg("cannot attach temporary relation of another session as partition")));
18712 
18713  /*
18714  * Check if attachrel has any identity columns or any columns that aren't
18715  * in the parent.
18716  */
18717  tupleDesc = RelationGetDescr(attachrel);
18718  natts = tupleDesc->natts;
18719  for (attno = 1; attno <= natts; attno++)
18720  {
18721  Form_pg_attribute attribute = TupleDescAttr(tupleDesc, attno - 1);
18722  char *attributeName = NameStr(attribute->attname);
18723 
18724  /* Ignore dropped */
18725  if (attribute->attisdropped)
18726  continue;
18727 
18728  if (attribute->attidentity)
18729  ereport(ERROR,
18730  errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
18731  errmsg("table \"%s\" being attached contains an identity column \"%s\"",
18732  RelationGetRelationName(attachrel), attributeName),
18733  errdetail("The new partition may not contain an identity column."));
18734 
18735  /* Try to find the column in parent (matching on column name) */
18736  if (!SearchSysCacheExists2(ATTNAME,
18738  CStringGetDatum(attributeName)))
18739  ereport(ERROR,
18740  (errcode(ERRCODE_DATATYPE_MISMATCH),
18741  errmsg("table \"%s\" contains column \"%s\" not found in parent \"%s\"",
18742  RelationGetRelationName(attachrel), attributeName,
18744  errdetail("The new partition may contain only the columns present in parent.")));
18745  }
18746 
18747  /*
18748  * If child_rel has row-level triggers with transition tables, we
18749  * currently don't allow it to become a partition. See also prohibitions
18750  * in ATExecAddInherit() and CreateTrigger().
18751  */
18752  trigger_name = FindTriggerIncompatibleWithInheritance(attachrel->trigdesc);
18753  if (trigger_name != NULL)
18754  ereport(ERROR,
18755  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
18756  errmsg("trigger \"%s\" prevents table \"%s\" from becoming a partition",
18757  trigger_name, RelationGetRelationName(attachrel)),
18758  errdetail("ROW triggers with transition tables are not supported on partitions.")));
18759 
18760  /*
18761  * Check that the new partition's bound is valid and does not overlap any
18762  * of existing partitions of the parent - note that it does not return on
18763  * error.
18764  */
18766  cmd->bound, pstate);
18767 
18768  /* OK to create inheritance. Rest of the checks performed there */
18769  CreateInheritance(attachrel, rel, true);
18770 
18771  /* Update the pg_class entry. */
18772  StorePartitionBound(attachrel, rel, cmd->bound);
18773 
18774  /* Ensure there exists a correct set of indexes in the partition. */
18775  AttachPartitionEnsureIndexes(wqueue, rel, attachrel);
18776 
18777  /* and triggers */
18778  CloneRowTriggersToPartition(rel, attachrel);
18779 
18780  /*
18781  * Clone foreign key constraints. Callee is responsible for setting up
18782  * for phase 3 constraint verification.
18783  */
18784  CloneForeignKeyConstraints(wqueue, rel, attachrel);
18785 
18786  /*
18787  * Generate partition constraint from the partition bound specification.
18788  * If the parent itself is a partition, make sure to include its
18789  * constraint as well.
18790  */
18791  partBoundConstraint = get_qual_from_partbound(rel, cmd->bound);
18792 
18793  /*
18794  * Use list_concat_copy() to avoid modifying partBoundConstraint in place,
18795  * since it's needed later to construct the constraint expression for
18796  * validating against the default partition, if any.
18797  */
18798  partConstraint = list_concat_copy(partBoundConstraint,
18800 
18801  /* Skip validation if there are no constraints to validate. */
18802  if (partConstraint)
18803  {
18804  /*
18805  * Run the partition quals through const-simplification similar to
18806  * check constraints. We skip canonicalize_qual, though, because
18807  * partition quals should be in canonical form already.
18808  */
18809  partConstraint =
18810  (List *) eval_const_expressions(NULL,
18811  (Node *) partConstraint);
18812 
18813  /* XXX this sure looks wrong */
18814  partConstraint = list_make1(make_ands_explicit(partConstraint));
18815 
18816  /*
18817  * Adjust the generated constraint to match this partition's attribute
18818  * numbers.
18819  */
18820  partConstraint = map_partition_varattnos(partConstraint, 1, attachrel,
18821  rel);
18822 
18823  /* Validate partition constraints against the table being attached. */
18824  QueuePartitionConstraintValidation(wqueue, attachrel, partConstraint,
18825  false);
18826  }
18827 
18828  /*
18829  * If we're attaching a partition other than the default partition and a
18830  * default one exists, then that partition's partition constraint changes,
18831  * so add an entry to the work queue to validate it, too. (We must not do
18832  * this when the partition being attached is the default one; we already
18833  * did it above!)
18834  */
18835  if (OidIsValid(defaultPartOid))
18836  {
18837  Relation defaultrel;
18838  List *defPartConstraint;
18839 
18840  Assert(!cmd->bound->is_default);
18841 
18842  /* we already hold a lock on the default partition */
18843  defaultrel = table_open(defaultPartOid, NoLock);
18844  defPartConstraint =
18845  get_proposed_default_constraint(partBoundConstraint);
18846 
18847  /*
18848  * Map the Vars in the constraint expression from rel's attnos to
18849  * defaultrel's.
18850  */
18851  defPartConstraint =
18852  map_partition_varattnos(defPartConstraint,
18853  1, defaultrel, rel);
18854  QueuePartitionConstraintValidation(wqueue, defaultrel,
18855  defPartConstraint, true);
18856 
18857  /* keep our lock until commit. */
18858  table_close(defaultrel, NoLock);
18859  }
18860 
18861  ObjectAddressSet(address, RelationRelationId, RelationGetRelid(attachrel));
18862 
18863  /*
18864  * If the partition we just attached is partitioned itself, invalidate
18865  * relcache for all descendent partitions too to ensure that their
18866  * rd_partcheck expression trees are rebuilt; partitions already locked at
18867  * the beginning of this function.
18868  */
18869  if (attachrel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
18870  {
18871  ListCell *l;
18872 
18873  foreach(l, attachrel_children)
18874  {
18876  }
18877  }
18878 
18879  /* keep our lock until commit */
18880  table_close(attachrel, NoLock);
18881 
18882  return address;
18883 }
18884 
18885 /*
18886  * AttachPartitionEnsureIndexes
18887  * subroutine for ATExecAttachPartition to create/match indexes
18888  *
18889  * Enforce the indexing rule for partitioned tables during ALTER TABLE / ATTACH
18890  * PARTITION: every partition must have an index attached to each index on the
18891  * partitioned table.
18892  */
18893 static void
18895 {
18896  List *idxes;
18897  List *attachRelIdxs;
18898  Relation *attachrelIdxRels;
18899  IndexInfo **attachInfos;
18900  ListCell *cell;
18901  MemoryContext cxt;
18902  MemoryContext oldcxt;
18903 
18905  "AttachPartitionEnsureIndexes",
18907  oldcxt = MemoryContextSwitchTo(cxt);
18908 
18909  idxes = RelationGetIndexList(rel);
18910  attachRelIdxs = RelationGetIndexList(attachrel);
18911  attachrelIdxRels = palloc(sizeof(Relation) * list_length(attachRelIdxs));
18912  attachInfos = palloc(sizeof(IndexInfo *) * list_length(attachRelIdxs));
18913 
18914  /* Build arrays of all existing indexes and their IndexInfos */
18915  foreach_oid(cldIdxId, attachRelIdxs)
18916  {
18917  int i = foreach_current_index(cldIdxId);
18918 
18919  attachrelIdxRels[i] = index_open(cldIdxId, AccessShareLock);
18920  attachInfos[i] = BuildIndexInfo(attachrelIdxRels[i]);
18921  }
18922 
18923  /*
18924  * If we're attaching a foreign table, we must fail if any of the indexes
18925  * is a constraint index; otherwise, there's nothing to do here. Do this
18926  * before starting work, to avoid wasting the effort of building a few
18927  * non-unique indexes before coming across a unique one.
18928  */
18929  if (attachrel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
18930  {
18931  foreach(cell, idxes)
18932  {
18933  Oid idx = lfirst_oid(cell);
18935 
18936  if (idxRel->rd_index->indisunique ||
18937  idxRel->rd_index->indisprimary)
18938  ereport(ERROR,
18939  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
18940  errmsg("cannot attach foreign table \"%s\" as partition of partitioned table \"%s\"",
18941  RelationGetRelationName(attachrel),
18943  errdetail("Partitioned table \"%s\" contains unique indexes.",
18944  RelationGetRelationName(rel))));
18945  index_close(idxRel, AccessShareLock);
18946  }
18947 
18948  goto out;
18949  }
18950 
18951  /*
18952  * For each index on the partitioned table, find a matching one in the
18953  * partition-to-be; if one is not found, create one.
18954  */
18955  foreach(cell, idxes)
18956  {
18957  Oid idx = lfirst_oid(cell);
18959  IndexInfo *info;
18960  AttrMap *attmap;
18961  bool found = false;
18962  Oid constraintOid;
18963 
18964  /*
18965  * Ignore indexes in the partitioned table other than partitioned
18966  * indexes.
18967  */
18968  if (idxRel->rd_rel->relkind != RELKIND_PARTITIONED_INDEX)
18969  {
18970  index_close(idxRel, AccessShareLock);
18971  continue;
18972  }
18973 
18974  /* construct an indexinfo to compare existing indexes against */
18975  info = BuildIndexInfo(idxRel);
18976  attmap = build_attrmap_by_name(RelationGetDescr(attachrel),
18977  RelationGetDescr(rel),
18978  false);
18979  constraintOid = get_relation_idx_constraint_oid(RelationGetRelid(rel), idx);
18980 
18981  /*
18982  * Scan the list of existing indexes in the partition-to-be, and mark
18983  * the first matching, valid, unattached one we find, if any, as
18984  * partition of the parent index. If we find one, we're done.
18985  */
18986  for (int i = 0; i < list_length(attachRelIdxs); i++)
18987  {
18988  Oid cldIdxId = RelationGetRelid(attachrelIdxRels[i]);
18989  Oid cldConstrOid = InvalidOid;
18990 
18991  /* does this index have a parent? if so, can't use it */
18992  if (attachrelIdxRels[i]->rd_rel->relispartition)
18993  continue;
18994 
18995  /* If this index is invalid, can't use it */
18996  if (!attachrelIdxRels[i]->rd_index->indisvalid)
18997  continue;
18998 
18999  if (CompareIndexInfo(attachInfos[i], info,
19000  attachrelIdxRels[i]->rd_indcollation,
19001  idxRel->rd_indcollation,
19002  attachrelIdxRels[i]->rd_opfamily,
19003  idxRel->rd_opfamily,
19004  attmap))
19005  {
19006  /*
19007  * If this index is being created in the parent because of a
19008  * constraint, then the child needs to have a constraint also,
19009  * so look for one. If there is no such constraint, this
19010  * index is no good, so keep looking.
19011  */
19012  if (OidIsValid(constraintOid))
19013  {
19014  cldConstrOid =
19016  cldIdxId);
19017  /* no dice */
19018  if (!OidIsValid(cldConstrOid))
19019  continue;
19020 
19021  /* Ensure they're both the same type of constraint */
19022  if (get_constraint_type(constraintOid) !=
19023  get_constraint_type(cldConstrOid))
19024  continue;
19025  }
19026 
19027  /* bingo. */
19028  IndexSetParentIndex(attachrelIdxRels[i], idx);
19029  if (OidIsValid(constraintOid))
19030  ConstraintSetParentConstraint(cldConstrOid, constraintOid,
19031  RelationGetRelid(attachrel));
19032  found = true;
19033 
19035  break;
19036  }
19037  }
19038 
19039  /*
19040  * If no suitable index was found in the partition-to-be, create one
19041  * now.
19042  */
19043  if (!found)
19044  {
19045  IndexStmt *stmt;
19046  Oid conOid;
19047 
19049  idxRel, attmap,
19050  &conOid);
19052  RelationGetRelid(idxRel),
19053  conOid,
19054  -1,
19055  true, false, false, false, false);
19056  }
19057 
19058  index_close(idxRel, AccessShareLock);
19059  }
19060 
19061 out:
19062  /* Clean up. */
19063  for (int i = 0; i < list_length(attachRelIdxs); i++)
19064  index_close(attachrelIdxRels[i], AccessShareLock);
19065  MemoryContextSwitchTo(oldcxt);
19066  MemoryContextDelete(cxt);
19067 }
19068 
19069 /*
19070  * CloneRowTriggersToPartition
19071  * subroutine for ATExecAttachPartition/DefineRelation to create row
19072  * triggers on partitions
19073  */
19074 static void
19076 {
19077  Relation pg_trigger;
19078  ScanKeyData key;
19079  SysScanDesc scan;
19080  HeapTuple tuple;
19081  MemoryContext perTupCxt;
19082 
19083  ScanKeyInit(&key, Anum_pg_trigger_tgrelid, BTEqualStrategyNumber,
19084  F_OIDEQ, ObjectIdGetDatum(RelationGetRelid(parent)));
19085  pg_trigger = table_open(TriggerRelationId, RowExclusiveLock);
19086  scan = systable_beginscan(pg_trigger, TriggerRelidNameIndexId,
19087  true, NULL, 1, &key);
19088 
19090  "clone trig", ALLOCSET_SMALL_SIZES);
19091 
19092  while (HeapTupleIsValid(tuple = systable_getnext(scan)))
19093  {
19094  Form_pg_trigger trigForm = (Form_pg_trigger) GETSTRUCT(tuple);
19095  CreateTrigStmt *trigStmt;
19096  Node *qual = NULL;
19097  Datum value;
19098  bool isnull;
19099  List *cols = NIL;
19100  List *trigargs = NIL;
19101  MemoryContext oldcxt;
19102 
19103  /*
19104  * Ignore statement-level triggers; those are not cloned.
19105  */
19106  if (!TRIGGER_FOR_ROW(trigForm->tgtype))
19107  continue;
19108 
19109  /*
19110  * Don't clone internal triggers, because the constraint cloning code
19111  * will.
19112  */
19113  if (trigForm->tgisinternal)
19114  continue;
19115 
19116  /*
19117  * Complain if we find an unexpected trigger type.
19118  */
19119  if (!TRIGGER_FOR_BEFORE(trigForm->tgtype) &&
19120  !TRIGGER_FOR_AFTER(trigForm->tgtype))
19121  elog(ERROR, "unexpected trigger \"%s\" found",
19122  NameStr(trigForm->tgname));
19123 
19124  /* Use short-lived context for CREATE TRIGGER */
19125  oldcxt = MemoryContextSwitchTo(perTupCxt);
19126 
19127  /*
19128  * If there is a WHEN clause, generate a 'cooked' version of it that's
19129  * appropriate for the partition.
19130  */
19131  value = heap_getattr(tuple, Anum_pg_trigger_tgqual,
19132  RelationGetDescr(pg_trigger), &isnull);
19133  if (!isnull)
19134  {
19136  qual = (Node *) map_partition_varattnos((List *) qual, PRS2_OLD_VARNO,
19137  partition, parent);
19138  qual = (Node *) map_partition_varattnos((List *) qual, PRS2_NEW_VARNO,
19139  partition, parent);
19140  }
19141 
19142  /*
19143  * If there is a column list, transform it to a list of column names.
19144  * Note we don't need to map this list in any way ...
19145  */
19146  if (trigForm->tgattr.dim1 > 0)
19147  {
19148  int i;
19149 
19150  for (i = 0; i < trigForm->tgattr.dim1; i++)
19151  {
19152  Form_pg_attribute col;
19153 
19154  col = TupleDescAttr(parent->rd_att,
19155  trigForm->tgattr.values[i] - 1);
19156  cols = lappend(cols,
19157  makeString(pstrdup(NameStr(col->attname))));
19158  }
19159  }
19160 
19161  /* Reconstruct trigger arguments list. */
19162  if (trigForm->tgnargs > 0)
19163  {
19164  char *p;
19165 
19166  value = heap_getattr(tuple, Anum_pg_trigger_tgargs,
19167  RelationGetDescr(pg_trigger), &isnull);
19168  if (isnull)
19169  elog(ERROR, "tgargs is null for trigger \"%s\" in partition \"%s\"",
19170  NameStr(trigForm->tgname), RelationGetRelationName(partition));
19171 
19172  p = (char *) VARDATA_ANY(DatumGetByteaPP(value));
19173 
19174  for (int i = 0; i < trigForm->tgnargs; i++)
19175  {
19176  trigargs = lappend(trigargs, makeString(pstrdup(p)));
19177  p += strlen(p) + 1;
19178  }
19179  }
19180 
19181  trigStmt = makeNode(CreateTrigStmt);
19182  trigStmt->replace = false;
19183  trigStmt->isconstraint = OidIsValid(trigForm->tgconstraint);
19184  trigStmt->trigname = NameStr(trigForm->tgname);
19185  trigStmt->relation = NULL;
19186  trigStmt->funcname = NULL; /* passed separately */
19187  trigStmt->args = trigargs;
19188  trigStmt->row = true;
19189  trigStmt->timing = trigForm->tgtype & TRIGGER_TYPE_TIMING_MASK;
19190  trigStmt->events = trigForm->tgtype & TRIGGER_TYPE_EVENT_MASK;
19191  trigStmt->columns = cols;
19192  trigStmt->whenClause = NULL; /* passed separately */
19193  trigStmt->transitionRels = NIL; /* not supported at present */
19194  trigStmt->deferrable = trigForm->tgdeferrable;
19195  trigStmt->initdeferred = trigForm->tginitdeferred;
19196  trigStmt->constrrel = NULL; /* passed separately */
19197 
19198  CreateTriggerFiringOn(trigStmt, NULL, RelationGetRelid(partition),
19199  trigForm->tgconstrrelid, InvalidOid, InvalidOid,
19200  trigForm->tgfoid, trigForm->oid, qual,
19201  false, true, trigForm->tgenabled);
19202 
19203  MemoryContextSwitchTo(oldcxt);
19204  MemoryContextReset(perTupCxt);
19205  }
19206 
19207  MemoryContextDelete(perTupCxt);
19208 
19209  systable_endscan(scan);
19210  table_close(pg_trigger, RowExclusiveLock);
19211 }
19212 
19213 /*
19214  * ALTER TABLE DETACH PARTITION
19215  *
19216  * Return the address of the relation that is no longer a partition of rel.
19217  *
19218  * If concurrent mode is requested, we run in two transactions. A side-
19219  * effect is that this command cannot run in a multi-part ALTER TABLE.
19220  * Currently, that's enforced by the grammar.
19221  *
19222  * The strategy for concurrency is to first modify the partition's
19223  * pg_inherit catalog row to make it visible to everyone that the
19224  * partition is detached, lock the partition against writes, and commit
19225  * the transaction; anyone who requests the partition descriptor from
19226  * that point onwards has to ignore such a partition. In a second
19227  * transaction, we wait until all transactions that could have seen the
19228  * partition as attached are gone, then we remove the rest of partition
19229  * metadata (pg_inherits and pg_class.relpartbounds).
19230  */
19231 static ObjectAddress
19233  RangeVar *name, bool concurrent)
19234 {
19235  Relation partRel;
19236  ObjectAddress address;
19237  Oid defaultPartOid;
19238 
19239  /*
19240  * We must lock the default partition, because detaching this partition
19241  * will change its partition constraint.
19242  */
19243  defaultPartOid =
19245  if (OidIsValid(defaultPartOid))
19246  {
19247  /*
19248  * Concurrent detaching when a default partition exists is not
19249  * supported. The main problem is that the default partition
19250  * constraint would change. And there's a definitional problem: what
19251  * should happen to the tuples that are being inserted that belong to
19252  * the partition being detached? Putting them on the partition being
19253  * detached would be wrong, since they'd become "lost" after the
19254  * detaching completes but we cannot put them in the default partition
19255  * either until we alter its partition constraint.
19256  *
19257  * I think we could solve this problem if we effected the constraint
19258  * change before committing the first transaction. But the lock would
19259  * have to remain AEL and it would cause concurrent query planning to
19260  * be blocked, so changing it that way would be even worse.
19261  */
19262  if (concurrent)
19263  ereport(ERROR,
19264  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
19265  errmsg("cannot detach partitions concurrently when a default partition exists")));
19266  LockRelationOid(defaultPartOid, AccessExclusiveLock);
19267  }
19268 
19269  /*
19270  * In concurrent mode, the partition is locked with share-update-exclusive
19271  * in the first transaction. This allows concurrent transactions to be
19272  * doing DML to the partition.
19273  */
19274  partRel = table_openrv(name, concurrent ? ShareUpdateExclusiveLock :
19276 
19277  /*
19278  * Check inheritance conditions and either delete the pg_inherits row (in
19279  * non-concurrent mode) or just set the inhdetachpending flag.
19280  */
19281  if (!concurrent)
19282  RemoveInheritance(partRel, rel, false);
19283  else
19284  MarkInheritDetached(partRel, rel);
19285 
19286  /*
19287  * Ensure that foreign keys still hold after this detach. This keeps
19288  * locks on the referencing tables, which prevents concurrent transactions
19289  * from adding rows that we wouldn't see. For this to work in concurrent
19290  * mode, it is critical that the partition appears as no longer attached
19291  * for the RI queries as soon as the first transaction commits.
19292  */
19294 
19295  /*
19296  * Concurrent mode has to work harder; first we add a new constraint to
19297  * the partition that matches the partition constraint. Then we close our
19298  * existing transaction, and in a new one wait for all processes to catch
19299  * up on the catalog updates we've done so far; at that point we can
19300  * complete the operation.
19301  */
19302  if (concurrent)
19303  {
19304  Oid partrelid,
19305  parentrelid;
19306  LOCKTAG tag;
19307  char *parentrelname;
19308  char *partrelname;
19309 
19310  /*
19311  * Add a new constraint to the partition being detached, which
19312  * supplants the partition constraint (unless there is one already).
19313  */
19314  DetachAddConstraintIfNeeded(wqueue, partRel);
19315 
19316  /*
19317  * We're almost done now; the only traces that remain are the
19318  * pg_inherits tuple and the partition's relpartbounds. Before we can
19319  * remove those, we need to wait until all transactions that know that
19320  * this is a partition are gone.
19321  */
19322 
19323  /*
19324  * Remember relation OIDs to re-acquire them later; and relation names
19325  * too, for error messages if something is dropped in between.
19326  */
19327  partrelid = RelationGetRelid(partRel);
19328  parentrelid = RelationGetRelid(rel);
19329  parentrelname = MemoryContextStrdup(PortalContext,
19331  partrelname = MemoryContextStrdup(PortalContext,
19332  RelationGetRelationName(partRel));
19333 
19334  /* Invalidate relcache entries for the parent -- must be before close */
19336 
19337  table_close(partRel, NoLock);
19338  table_close(rel, NoLock);
19339  tab->rel = NULL;
19340 
19341  /* Make updated catalog entry visible */
19344 
19346 
19347  /*
19348  * Now wait. This ensures that all queries that were planned
19349  * including the partition are finished before we remove the rest of
19350  * catalog entries. We don't need or indeed want to acquire this
19351  * lock, though -- that would block later queries.
19352  *
19353  * We don't need to concern ourselves with waiting for a lock on the
19354  * partition itself, since we will acquire AccessExclusiveLock below.
19355  */
19356  SET_LOCKTAG_RELATION(tag, MyDatabaseId, parentrelid);
19358 
19359  /*
19360  * Now acquire locks in both relations again. Note they may have been
19361  * removed in the meantime, so care is required.
19362  */
19363  rel = try_relation_open(parentrelid, ShareUpdateExclusiveLock);
19364  partRel = try_relation_open(partrelid, AccessExclusiveLock);
19365 
19366  /* If the relations aren't there, something bad happened; bail out */
19367  if (rel == NULL)
19368  {
19369  if (partRel != NULL) /* shouldn't happen */
19370  elog(WARNING, "dangling partition \"%s\" remains, can't fix",
19371  partrelname);
19372  ereport(ERROR,
19373  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
19374  errmsg("partitioned table \"%s\" was removed concurrently",
19375  parentrelname)));
19376  }
19377  if (partRel == NULL)
19378  ereport(ERROR,
19379  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
19380  errmsg("partition \"%s\" was removed concurrently", partrelname)));
19381 
19382  tab->rel = rel;
19383  }
19384 
19385  /* Do the final part of detaching */
19386  DetachPartitionFinalize(rel, partRel, concurrent, defaultPartOid);
19387 
19388  ObjectAddressSet(address, RelationRelationId, RelationGetRelid(partRel));
19389 
19390  /* keep our lock until commit */
19391  table_close(partRel, NoLock);
19392 
19393  return address;
19394 }
19395 
19396 /*
19397  * Second part of ALTER TABLE .. DETACH.
19398  *
19399  * This is separate so that it can be run independently when the second
19400  * transaction of the concurrent algorithm fails (crash or abort).
19401  */
19402 static void
19403 DetachPartitionFinalize(Relation rel, Relation partRel, bool concurrent,
19404  Oid defaultPartOid)
19405 {
19406  Relation classRel;
19407  List *fks;
19408  ListCell *cell;
19409  List *indexes;
19410  Datum new_val[Natts_pg_class];
19411  bool new_null[Natts_pg_class],
19412  new_repl[Natts_pg_class];
19413  HeapTuple tuple,
19414  newtuple;
19415  Relation trigrel = NULL;
19416 
19417  if (concurrent)
19418  {
19419  /*
19420  * We can remove the pg_inherits row now. (In the non-concurrent case,
19421  * this was already done).
19422  */
19423  RemoveInheritance(partRel, rel, true);
19424  }
19425 
19426  /* Drop any triggers that were cloned on creation/attach. */
19428 
19429  /*
19430  * Detach any foreign keys that are inherited. This includes creating
19431  * additional action triggers.
19432  */
19433  fks = copyObject(RelationGetFKeyList(partRel));
19434  if (fks != NIL)
19435  trigrel = table_open(TriggerRelationId, RowExclusiveLock);
19436  foreach(cell, fks)
19437  {
19438  ForeignKeyCacheInfo *fk = lfirst(cell);
19439  HeapTuple contup,
19440  parentConTup;
19441  Form_pg_constraint conform;
19442  Oid insertTriggerOid,
19443  updateTriggerOid;
19444 
19445  contup = SearchSysCache1(CONSTROID, ObjectIdGetDatum(fk->conoid));
19446  if (!HeapTupleIsValid(contup))
19447  elog(ERROR, "cache lookup failed for constraint %u", fk->conoid);
19448  conform = (Form_pg_constraint) GETSTRUCT(contup);
19449 
19450  /* consider only the inherited foreign keys */
19451  if (conform->contype != CONSTRAINT_FOREIGN ||
19452  !OidIsValid(conform->conparentid))
19453  {
19454  ReleaseSysCache(contup);
19455  continue;
19456  }
19457 
19458  Assert(OidIsValid(conform->conparentid));
19459  parentConTup = SearchSysCache1(CONSTROID,
19460  ObjectIdGetDatum(conform->conparentid));
19461  if (!HeapTupleIsValid(parentConTup))
19462  elog(ERROR, "cache lookup failed for constraint %u",
19463  conform->conparentid);
19464 
19465  /*
19466  * The constraint on this table must be marked no longer a child of
19467  * the parent's constraint, as do its check triggers.
19468  */
19470 
19471  /*
19472  * Also, look up the partition's "check" triggers corresponding to the
19473  * constraint being detached and detach them from the parent triggers.
19474  */
19476  fk->conoid, fk->confrelid, fk->conrelid,
19477  &insertTriggerOid, &updateTriggerOid);
19478  Assert(OidIsValid(insertTriggerOid));
19479  TriggerSetParentTrigger(trigrel, insertTriggerOid, InvalidOid,
19480  RelationGetRelid(partRel));
19481  Assert(OidIsValid(updateTriggerOid));
19482  TriggerSetParentTrigger(trigrel, updateTriggerOid, InvalidOid,
19483  RelationGetRelid(partRel));
19484 
19485  /*
19486  * Lastly, create the action triggers on the referenced table, using
19487  * addFkRecurseReferenced, which requires some elaborate setup (so put
19488  * it in a separate block). While at it, if the table is partitioned,
19489  * that function will recurse to create the pg_constraint rows and
19490  * action triggers for each partition.
19491  *
19492  * Note there's no need to do addFkConstraint() here, because the
19493  * pg_constraint row already exists.
19494  */
19495  {
19496  Constraint *fkconstraint;
19497  int numfks;
19498  AttrNumber conkey[INDEX_MAX_KEYS];
19499  AttrNumber confkey[INDEX_MAX_KEYS];
19500  Oid conpfeqop[INDEX_MAX_KEYS];
19501  Oid conppeqop[INDEX_MAX_KEYS];
19502  Oid conffeqop[INDEX_MAX_KEYS];
19503  int numfkdelsetcols;
19504  AttrNumber confdelsetcols[INDEX_MAX_KEYS];
19505  AttrMap *attmap;
19506  Relation refdRel;
19507 
19509  &numfks,
19510  conkey,
19511  confkey,
19512  conpfeqop,
19513  conppeqop,
19514  conffeqop,
19515  &numfkdelsetcols,
19516  confdelsetcols);
19517 
19518  /* Create a synthetic node we'll use throughout */
19519  fkconstraint = makeNode(Constraint);
19520  fkconstraint->contype = CONSTRAINT_FOREIGN;
19521  fkconstraint->conname = pstrdup(NameStr(conform->conname));
19522  fkconstraint->deferrable = conform->condeferrable;
19523  fkconstraint->initdeferred = conform->condeferred;
19524  fkconstraint->skip_validation = true;
19525  fkconstraint->initially_valid = true;
19526  /* a few irrelevant fields omitted here */
19527  fkconstraint->pktable = NULL;
19528  fkconstraint->fk_attrs = NIL;
19529  fkconstraint->pk_attrs = NIL;
19530  fkconstraint->fk_matchtype = conform->confmatchtype;
19531  fkconstraint->fk_upd_action = conform->confupdtype;
19532  fkconstraint->fk_del_action = conform->confdeltype;
19533  fkconstraint->fk_del_set_cols = NIL;
19534  fkconstraint->old_conpfeqop = NIL;
19535  fkconstraint->old_pktable_oid = InvalidOid;
19536  fkconstraint->location = -1;
19537 
19538  attmap = build_attrmap_by_name(RelationGetDescr(partRel),
19539  RelationGetDescr(rel),
19540  false);
19541  for (int i = 0; i < numfks; i++)
19542  {
19543  Form_pg_attribute att;
19544 
19545  att = TupleDescAttr(RelationGetDescr(partRel),
19546  attmap->attnums[conkey[i] - 1] - 1);
19547  fkconstraint->fk_attrs = lappend(fkconstraint->fk_attrs,
19548  makeString(NameStr(att->attname)));
19549  }
19550 
19551  refdRel = table_open(fk->confrelid, AccessShareLock);
19552 
19553  addFkRecurseReferenced(fkconstraint, partRel,
19554  refdRel,
19555  conform->conindid,
19556  fk->conoid,
19557  numfks,
19558  confkey,
19559  conkey,
19560  conpfeqop,
19561  conppeqop,
19562  conffeqop,
19563  numfkdelsetcols,
19564  confdelsetcols,
19565  true,
19567  conform->conperiod);
19568  table_close(refdRel, AccessShareLock);
19569  }
19570 
19571  ReleaseSysCache(contup);
19572  ReleaseSysCache(parentConTup);
19573  }
19574  list_free_deep(fks);
19575  if (trigrel)
19576  table_close(trigrel, RowExclusiveLock);
19577 
19578  /*
19579  * Any sub-constraints that are in the referenced-side of a larger
19580  * constraint have to be removed. This partition is no longer part of the
19581  * key space of the constraint.
19582  */
19583  foreach(cell, GetParentedForeignKeyRefs(partRel))
19584  {
19585  Oid constrOid = lfirst_oid(cell);
19586  ObjectAddress constraint;
19587 
19589  deleteDependencyRecordsForClass(ConstraintRelationId,
19590  constrOid,
19591  ConstraintRelationId,
19594 
19595  ObjectAddressSet(constraint, ConstraintRelationId, constrOid);
19596  performDeletion(&constraint, DROP_RESTRICT, 0);
19597  }
19598 
19599  /* Now we can detach indexes */
19600  indexes = RelationGetIndexList(partRel);
19601  foreach(cell, indexes)
19602  {
19603  Oid idxid = lfirst_oid(cell);
19604  Oid parentidx;
19605  Relation idx;
19606  Oid constrOid;
19607  Oid parentConstrOid;
19608 
19609  if (!has_superclass(idxid))
19610  continue;
19611 
19612  parentidx = get_partition_parent(idxid, false);
19613  Assert((IndexGetRelation(parentidx, false) == RelationGetRelid(rel)));
19614 
19617 
19618  /*
19619  * If there's a constraint associated with the index, detach it too.
19620  * Careful: it is possible for a constraint index in a partition to be
19621  * the child of a non-constraint index, so verify whether the parent
19622  * index does actually have a constraint.
19623  */
19625  idxid);
19626  parentConstrOid = get_relation_idx_constraint_oid(RelationGetRelid(rel),
19627  parentidx);
19628  if (OidIsValid(parentConstrOid) && OidIsValid(constrOid))
19630 
19632  }
19633 
19634  /* Update pg_class tuple */
19635  classRel = table_open(RelationRelationId, RowExclusiveLock);
19636  tuple = SearchSysCacheCopy1(RELOID,
19638  if (!HeapTupleIsValid(tuple))
19639  elog(ERROR, "cache lookup failed for relation %u",
19640  RelationGetRelid(partRel));
19641  Assert(((Form_pg_class) GETSTRUCT(tuple))->relispartition);
19642 
19643  /* Clear relpartbound and reset relispartition */
19644  memset(new_val, 0, sizeof(new_val));
19645  memset(new_null, false, sizeof(new_null));
19646  memset(new_repl, false, sizeof(new_repl));
19647  new_val[Anum_pg_class_relpartbound - 1] = (Datum) 0;
19648  new_null[Anum_pg_class_relpartbound - 1] = true;
19649  new_repl[Anum_pg_class_relpartbound - 1] = true;
19650  newtuple = heap_modify_tuple(tuple, RelationGetDescr(classRel),
19651  new_val, new_null, new_repl);
19652 
19653  ((Form_pg_class) GETSTRUCT(newtuple))->relispartition = false;
19654  CatalogTupleUpdate(classRel, &newtuple->t_self, newtuple);
19655  heap_freetuple(newtuple);
19656  table_close(classRel, RowExclusiveLock);
19657 
19658  /*
19659  * Drop identity property from all identity columns of partition.
19660  */
19661  for (int attno = 0; attno < RelationGetNumberOfAttributes(partRel); attno++)
19662  {
19663  Form_pg_attribute attr = TupleDescAttr(partRel->rd_att, attno);
19664 
19665  if (!attr->attisdropped && attr->attidentity)
19666  ATExecDropIdentity(partRel, NameStr(attr->attname), false,
19667  AccessExclusiveLock, true, true);
19668  }
19669 
19670  if (OidIsValid(defaultPartOid))
19671  {
19672  /*
19673  * If the relation being detached is the default partition itself,
19674  * remove it from the parent's pg_partitioned_table entry.
19675  *
19676  * If not, we must invalidate default partition's relcache entry, as
19677  * in StorePartitionBound: its partition constraint depends on every
19678  * other partition's partition constraint.
19679  */
19680  if (RelationGetRelid(partRel) == defaultPartOid)
19682  else
19683  CacheInvalidateRelcacheByRelid(defaultPartOid);
19684  }
19685 
19686  /*
19687  * Invalidate the parent's relcache so that the partition is no longer
19688  * included in its partition descriptor.
19689  */
19691 
19692  /*
19693  * If the partition we just detached is partitioned itself, invalidate
19694  * relcache for all descendent partitions too to ensure that their
19695  * rd_partcheck expression trees are rebuilt; must lock partitions before
19696  * doing so, using the same lockmode as what partRel has been locked with
19697  * by the caller.
19698  */
19699  if (partRel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
19700  {
19701  List *children;
19702 
19703  children = find_all_inheritors(RelationGetRelid(partRel),
19704  AccessExclusiveLock, NULL);
19705  foreach(cell, children)
19706  {
19708  }
19709  }
19710 }
19711 
19712 /*
19713  * ALTER TABLE ... DETACH PARTITION ... FINALIZE
19714  *
19715  * To use when a DETACH PARTITION command previously did not run to
19716  * completion; this completes the detaching process.
19717  */
19718 static ObjectAddress
19720 {
19721  Relation partRel;
19722  ObjectAddress address;
19723  Snapshot snap = GetActiveSnapshot();
19724 
19726 
19727  /*
19728  * Wait until existing snapshots are gone. This is important if the
19729  * second transaction of DETACH PARTITION CONCURRENTLY is canceled: the
19730  * user could immediately run DETACH FINALIZE without actually waiting for
19731  * existing transactions. We must not complete the detach action until
19732  * all such queries are complete (otherwise we would present them with an
19733  * inconsistent view of catalogs).
19734  */
19735  WaitForOlderSnapshots(snap->xmin, false);
19736 
19737  DetachPartitionFinalize(rel, partRel, true, InvalidOid);
19738 
19739  ObjectAddressSet(address, RelationRelationId, RelationGetRelid(partRel));
19740 
19741  table_close(partRel, NoLock);
19742 
19743  return address;
19744 }
19745 
19746 /*
19747  * DetachAddConstraintIfNeeded
19748  * Subroutine for ATExecDetachPartition. Create a constraint that
19749  * takes the place of the partition constraint, but avoid creating
19750  * a dupe if an constraint already exists which implies the needed
19751  * constraint.
19752  */
19753 static void
19755 {
19756  List *constraintExpr;
19757 
19758  constraintExpr = RelationGetPartitionQual(partRel);
19759  constraintExpr = (List *) eval_const_expressions(NULL, (Node *) constraintExpr);
19760 
19761  /*
19762  * Avoid adding a new constraint if the needed constraint is implied by an
19763  * existing constraint
19764  */
19765  if (!PartConstraintImpliedByRelConstraint(partRel, constraintExpr))
19766  {
19767  AlteredTableInfo *tab;
19768  Constraint *n;
19769 
19770  tab = ATGetQueueEntry(wqueue, partRel);
19771 
19772  /* Add constraint on partition, equivalent to the partition constraint */
19773  n = makeNode(Constraint);
19774  n->contype = CONSTR_CHECK;
19775  n->conname = NULL;
19776  n->location = -1;
19777  n->is_no_inherit = false;
19778  n->raw_expr = NULL;
19779  n->cooked_expr = nodeToString(make_ands_explicit(constraintExpr));
19780  n->initially_valid = true;
19781  n->skip_validation = true;
19782  /* It's a re-add, since it nominally already exists */
19783  ATAddCheckConstraint(wqueue, tab, partRel, n,
19784  true, false, true, ShareUpdateExclusiveLock);
19785  }
19786 }
19787 
19788 /*
19789  * DropClonedTriggersFromPartition
19790  * subroutine for ATExecDetachPartition to remove any triggers that were
19791  * cloned to the partition when it was created-as-partition or attached.
19792  * This undoes what CloneRowTriggersToPartition did.
19793  */
19794 static void
19796 {
19797  ScanKeyData skey;
19798  SysScanDesc scan;
19799  HeapTuple trigtup;
19800  Relation tgrel;
19801  ObjectAddresses *objects;
19802 
19803  objects = new_object_addresses();
19804 
19805  /*
19806  * Scan pg_trigger to search for all triggers on this rel.
19807  */
19808  ScanKeyInit(&skey, Anum_pg_trigger_tgrelid, BTEqualStrategyNumber,
19809  F_OIDEQ, ObjectIdGetDatum(partitionId));
19810  tgrel = table_open(TriggerRelationId, RowExclusiveLock);
19811  scan = systable_beginscan(tgrel, TriggerRelidNameIndexId,
19812  true, NULL, 1, &skey);
19813  while (HeapTupleIsValid(trigtup = systable_getnext(scan)))
19814  {
19815  Form_pg_trigger pg_trigger = (Form_pg_trigger) GETSTRUCT(trigtup);
19816  ObjectAddress trig;
19817 
19818  /* Ignore triggers that weren't cloned */
19819  if (!OidIsValid(pg_trigger->tgparentid))
19820  continue;
19821 
19822  /*
19823  * Ignore internal triggers that are implementation objects of foreign
19824  * keys, because these will be detached when the foreign keys
19825  * themselves are.
19826  */
19827  if (OidIsValid(pg_trigger->tgconstrrelid))
19828  continue;
19829 
19830  /*
19831  * This is ugly, but necessary: remove the dependency markings on the
19832  * trigger so that it can be removed.
19833  */
19834  deleteDependencyRecordsForClass(TriggerRelationId, pg_trigger->oid,
19835  TriggerRelationId,
19837  deleteDependencyRecordsForClass(TriggerRelationId, pg_trigger->oid,
19838  RelationRelationId,
19840 
19841  /* remember this trigger to remove it below */
19842  ObjectAddressSet(trig, TriggerRelationId, pg_trigger->oid);
19843  add_exact_object_address(&trig, objects);
19844  }
19845 
19846  /* make the dependency removal visible to the deletion below */
19849 
19850  /* done */
19851  free_object_addresses(objects);
19852  systable_endscan(scan);
19853  table_close(tgrel, RowExclusiveLock);
19854 }
19855 
19856 /*
19857  * Before acquiring lock on an index, acquire the same lock on the owning
19858  * table.
19859  */
19861 {
19865 };
19866 
19867 static void
19868 RangeVarCallbackForAttachIndex(const RangeVar *rv, Oid relOid, Oid oldRelOid,
19869  void *arg)
19870 {
19872  Form_pg_class classform;
19873  HeapTuple tuple;
19874 
19875  state = (struct AttachIndexCallbackState *) arg;
19876 
19877  if (!state->lockedParentTbl)
19878  {
19879  LockRelationOid(state->parentTblOid, AccessShareLock);
19880  state->lockedParentTbl = true;
19881  }
19882 
19883  /*
19884  * If we previously locked some other heap, and the name we're looking up
19885  * no longer refers to an index on that relation, release the now-useless
19886  * lock. XXX maybe we should do *after* we verify whether the index does
19887  * not actually belong to the same relation ...
19888  */
19889  if (relOid != oldRelOid && OidIsValid(state->partitionOid))
19890  {
19891  UnlockRelationOid(state->partitionOid, AccessShareLock);
19892  state->partitionOid = InvalidOid;
19893  }
19894 
19895  /* Didn't find a relation, so no need for locking or permission checks. */
19896  if (!OidIsValid(relOid))
19897  return;
19898 
19899  tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relOid));
19900  if (!HeapTupleIsValid(tuple))
19901  return; /* concurrently dropped, so nothing to do */
19902  classform = (Form_pg_class) GETSTRUCT(tuple);
19903  if (classform->relkind != RELKIND_PARTITIONED_INDEX &&
19904  classform->relkind != RELKIND_INDEX)
19905  ereport(ERROR,
19906  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
19907  errmsg("\"%s\" is not an index", rv->relname)));
19908  ReleaseSysCache(tuple);
19909 
19910  /*
19911  * Since we need only examine the heap's tupledesc, an access share lock
19912  * on it (preventing any DDL) is sufficient.
19913  */
19914  state->partitionOid = IndexGetRelation(relOid, false);
19915  LockRelationOid(state->partitionOid, AccessShareLock);
19916 }
19917 
19918 /*
19919  * ALTER INDEX i1 ATTACH PARTITION i2
19920  */
19921 static ObjectAddress
19923 {
19924  Relation partIdx;
19925  Relation partTbl;
19926  Relation parentTbl;
19927  ObjectAddress address;
19928  Oid partIdxId;
19929  Oid currParent;
19931 
19932  /*
19933  * We need to obtain lock on the index 'name' to modify it, but we also
19934  * need to read its owning table's tuple descriptor -- so we need to lock
19935  * both. To avoid deadlocks, obtain lock on the table before doing so on
19936  * the index. Furthermore, we need to examine the parent table of the
19937  * partition, so lock that one too.
19938  */
19939  state.partitionOid = InvalidOid;
19940  state.parentTblOid = parentIdx->rd_index->indrelid;
19941  state.lockedParentTbl = false;
19942  partIdxId =
19945  (void *) &state);
19946  /* Not there? */
19947  if (!OidIsValid(partIdxId))
19948  ereport(ERROR,
19949  (errcode(ERRCODE_UNDEFINED_OBJECT),
19950  errmsg("index \"%s\" does not exist", name->relname)));
19951 
19952  /* no deadlock risk: RangeVarGetRelidExtended already acquired the lock */
19953  partIdx = relation_open(partIdxId, AccessExclusiveLock);
19954 
19955  /* we already hold locks on both tables, so this is safe: */
19956  parentTbl = relation_open(parentIdx->rd_index->indrelid, AccessShareLock);
19957  partTbl = relation_open(partIdx->rd_index->indrelid, NoLock);
19958 
19959  ObjectAddressSet(address, RelationRelationId, RelationGetRelid(partIdx));
19960 
19961  /* Silently do nothing if already in the right state */
19962  currParent = partIdx->rd_rel->relispartition ?
19963  get_partition_parent(partIdxId, false) : InvalidOid;
19964  if (currParent != RelationGetRelid(parentIdx))
19965  {
19966  IndexInfo *childInfo;
19967  IndexInfo *parentInfo;
19968  AttrMap *attmap;
19969  bool found;
19970  int i;
19971  PartitionDesc partDesc;
19972  Oid constraintOid,
19973  cldConstrId = InvalidOid;
19974 
19975  /*
19976  * If this partition already has an index attached, refuse the
19977  * operation.
19978  */
19979  refuseDupeIndexAttach(parentIdx, partIdx, partTbl);
19980 
19981  if (OidIsValid(currParent))
19982  ereport(ERROR,
19983  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
19984  errmsg("cannot attach index \"%s\" as a partition of index \"%s\"",
19985  RelationGetRelationName(partIdx),
19986  RelationGetRelationName(parentIdx)),
19987  errdetail("Index \"%s\" is already attached to another index.",
19988  RelationGetRelationName(partIdx))));
19989 
19990  /* Make sure it indexes a partition of the other index's table */
19991  partDesc = RelationGetPartitionDesc(parentTbl, true);
19992  found = false;
19993  for (i = 0; i < partDesc->nparts; i++)
19994  {
19995  if (partDesc->oids[i] == state.partitionOid)
19996  {
19997  found = true;
19998  break;
19999  }
20000  }
20001  if (!found)
20002  ereport(ERROR,
20003  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
20004  errmsg("cannot attach index \"%s\" as a partition of index \"%s\"",
20005  RelationGetRelationName(partIdx),
20006  RelationGetRelationName(parentIdx)),
20007  errdetail("Index \"%s\" is not an index on any partition of table \"%s\".",
20008  RelationGetRelationName(partIdx),
20009  RelationGetRelationName(parentTbl))));
20010 
20011  /* Ensure the indexes are compatible */
20012  childInfo = BuildIndexInfo(partIdx);
20013  parentInfo = BuildIndexInfo(parentIdx);
20014  attmap = build_attrmap_by_name(RelationGetDescr(partTbl),
20015  RelationGetDescr(parentTbl),
20016  false);
20017  if (!CompareIndexInfo(childInfo, parentInfo,
20018  partIdx->rd_indcollation,
20019  parentIdx->rd_indcollation,
20020  partIdx->rd_opfamily,
20021  parentIdx->rd_opfamily,
20022  attmap))
20023  ereport(ERROR,
20024  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
20025  errmsg("cannot attach index \"%s\" as a partition of index \"%s\"",
20026  RelationGetRelationName(partIdx),
20027  RelationGetRelationName(parentIdx)),
20028  errdetail("The index definitions do not match.")));
20029 
20030  /*
20031  * If there is a constraint in the parent, make sure there is one in
20032  * the child too.
20033  */
20034  constraintOid = get_relation_idx_constraint_oid(RelationGetRelid(parentTbl),
20035  RelationGetRelid(parentIdx));
20036 
20037  if (OidIsValid(constraintOid))
20038  {
20039  cldConstrId = get_relation_idx_constraint_oid(RelationGetRelid(partTbl),
20040  partIdxId);
20041  if (!OidIsValid(cldConstrId))
20042  ereport(ERROR,
20043  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
20044  errmsg("cannot attach index \"%s\" as a partition of index \"%s\"",
20045  RelationGetRelationName(partIdx),
20046  RelationGetRelationName(parentIdx)),
20047  errdetail("The index \"%s\" belongs to a constraint in table \"%s\" but no constraint exists for index \"%s\".",
20048  RelationGetRelationName(parentIdx),
20049  RelationGetRelationName(parentTbl),
20050  RelationGetRelationName(partIdx))));
20051  }
20052 
20053  /* All good -- do it */
20054  IndexSetParentIndex(partIdx, RelationGetRelid(parentIdx));
20055  if (OidIsValid(constraintOid))
20056  ConstraintSetParentConstraint(cldConstrId, constraintOid,
20057  RelationGetRelid(partTbl));
20058 
20059  free_attrmap(attmap);
20060 
20061  validatePartitionedIndex(parentIdx, parentTbl);
20062  }
20063 
20064  relation_close(parentTbl, AccessShareLock);
20065  /* keep these locks till commit */
20066  relation_close(partTbl, NoLock);
20067  relation_close(partIdx, NoLock);
20068 
20069  return address;
20070 }
20071 
20072 /*
20073  * Verify whether the given partition already contains an index attached
20074  * to the given partitioned index. If so, raise an error.
20075  */
20076 static void
20077 refuseDupeIndexAttach(Relation parentIdx, Relation partIdx, Relation partitionTbl)
20078 {
20079  Oid existingIdx;
20080 
20081  existingIdx = index_get_partition(partitionTbl,
20082  RelationGetRelid(parentIdx));
20083  if (OidIsValid(existingIdx))
20084  ereport(ERROR,
20085  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
20086  errmsg("cannot attach index \"%s\" as a partition of index \"%s\"",
20087  RelationGetRelationName(partIdx),
20088  RelationGetRelationName(parentIdx)),
20089  errdetail("Another index is already attached for partition \"%s\".",
20090  RelationGetRelationName(partitionTbl))));
20091 }
20092 
20093 /*
20094  * Verify whether the set of attached partition indexes to a parent index on
20095  * a partitioned table is complete. If it is, mark the parent index valid.
20096  *
20097  * This should be called each time a partition index is attached.
20098  */
20099 static void
20101 {
20102  Relation inheritsRel;
20103  SysScanDesc scan;
20104  ScanKeyData key;
20105  int tuples = 0;
20106  HeapTuple inhTup;
20107  bool updated = false;
20108 
20109  Assert(partedIdx->rd_rel->relkind == RELKIND_PARTITIONED_INDEX);
20110 
20111  /*
20112  * Scan pg_inherits for this parent index. Count each valid index we find
20113  * (verifying the pg_index entry for each), and if we reach the total
20114  * amount we expect, we can mark this parent index as valid.
20115  */
20116  inheritsRel = table_open(InheritsRelationId, AccessShareLock);
20117  ScanKeyInit(&key, Anum_pg_inherits_inhparent,
20118  BTEqualStrategyNumber, F_OIDEQ,
20119  ObjectIdGetDatum(RelationGetRelid(partedIdx)));
20120  scan = systable_beginscan(inheritsRel, InheritsParentIndexId, true,
20121  NULL, 1, &key);
20122  while ((inhTup = systable_getnext(scan)) != NULL)
20123  {
20124  Form_pg_inherits inhForm = (Form_pg_inherits) GETSTRUCT(inhTup);
20125  HeapTuple indTup;
20126  Form_pg_index indexForm;
20127 
20128  indTup = SearchSysCache1(INDEXRELID,
20129  ObjectIdGetDatum(inhForm->inhrelid));
20130  if (!HeapTupleIsValid(indTup))
20131  elog(ERROR, "cache lookup failed for index %u", inhForm->inhrelid);
20132  indexForm = (Form_pg_index) GETSTRUCT(indTup);
20133  if (indexForm->indisvalid)
20134  tuples += 1;
20135  ReleaseSysCache(indTup);
20136  }
20137 
20138  /* Done with pg_inherits */
20139  systable_endscan(scan);
20140  table_close(inheritsRel, AccessShareLock);
20141 
20142  /*
20143  * If we found as many inherited indexes as the partitioned table has
20144  * partitions, we're good; update pg_index to set indisvalid.
20145  */
20146  if (tuples == RelationGetPartitionDesc(partedTbl, true)->nparts)
20147  {
20148  Relation idxRel;
20149  HeapTuple indTup;
20150  Form_pg_index indexForm;
20151 
20152  idxRel = table_open(IndexRelationId, RowExclusiveLock);
20153  indTup = SearchSysCacheCopy1(INDEXRELID,
20154  ObjectIdGetDatum(RelationGetRelid(partedIdx)));
20155  if (!HeapTupleIsValid(indTup))
20156  elog(ERROR, "cache lookup failed for index %u",
20157  RelationGetRelid(partedIdx));
20158  indexForm = (Form_pg_index) GETSTRUCT(indTup);
20159 
20160  indexForm->indisvalid = true;
20161  updated = true;
20162 
20163  CatalogTupleUpdate(idxRel, &indTup->t_self, indTup);
20164 
20165  table_close(idxRel, RowExclusiveLock);
20166  heap_freetuple(indTup);
20167  }
20168 
20169  /*
20170  * If this index is in turn a partition of a larger index, validating it
20171  * might cause the parent to become valid also. Try that.
20172  */
20173  if (updated && partedIdx->rd_rel->relispartition)
20174  {
20175  Oid parentIdxId,
20176  parentTblId;
20177  Relation parentIdx,
20178  parentTbl;
20179 
20180  /* make sure we see the validation we just did */
20182 
20183  parentIdxId = get_partition_parent(RelationGetRelid(partedIdx), false);
20184  parentTblId = get_partition_parent(RelationGetRelid(partedTbl), false);
20185  parentIdx = relation_open(parentIdxId, AccessExclusiveLock);
20186  parentTbl = relation_open(parentTblId, AccessExclusiveLock);
20187  Assert(!parentIdx->rd_index->indisvalid);
20188 
20189  validatePartitionedIndex(parentIdx, parentTbl);
20190 
20191  relation_close(parentIdx, AccessExclusiveLock);
20192  relation_close(parentTbl, AccessExclusiveLock);
20193  }
20194 }
20195 
20196 /*
20197  * Return an OID list of constraints that reference the given relation
20198  * that are marked as having a parent constraints.
20199  */
20200 static List *
20202 {
20203  Relation pg_constraint;
20204  HeapTuple tuple;
20205  SysScanDesc scan;
20206  ScanKeyData key[2];
20207  List *constraints = NIL;
20208 
20209  /*
20210  * If no indexes, or no columns are referenceable by FKs, we can avoid the
20211  * scan.
20212  */
20213  if (RelationGetIndexList(partition) == NIL ||
20216  return NIL;
20217 
20218  /* Search for constraints referencing this table */
20219  pg_constraint = table_open(ConstraintRelationId, AccessShareLock);
20220  ScanKeyInit(&key[0],
20221  Anum_pg_constraint_confrelid, BTEqualStrategyNumber,
20222  F_OIDEQ, ObjectIdGetDatum(RelationGetRelid(partition)));
20223  ScanKeyInit(&key[1],
20224  Anum_pg_constraint_contype, BTEqualStrategyNumber,
20225  F_CHAREQ, CharGetDatum(CONSTRAINT_FOREIGN));
20226 
20227  /* XXX This is a seqscan, as we don't have a usable index */
20228  scan = systable_beginscan(pg_constraint, InvalidOid, true, NULL, 2, key);
20229  while ((tuple = systable_getnext(scan)) != NULL)
20230  {
20231  Form_pg_constraint constrForm = (Form_pg_constraint) GETSTRUCT(tuple);
20232 
20233  /*
20234  * We only need to process constraints that are part of larger ones.
20235  */
20236  if (!OidIsValid(constrForm->conparentid))
20237  continue;
20238 
20239  constraints = lappend_oid(constraints, constrForm->oid);
20240  }
20241 
20242  systable_endscan(scan);
20243  table_close(pg_constraint, AccessShareLock);
20244 
20245  return constraints;
20246 }
20247 
20248 /*
20249  * During DETACH PARTITION, verify that any foreign keys pointing to the
20250  * partitioned table would not become invalid. An error is raised if any
20251  * referenced values exist.
20252  */
20253 static void
20255 {
20256  List *constraints;
20257  ListCell *cell;
20258 
20259  constraints = GetParentedForeignKeyRefs(partition);
20260 
20261  foreach(cell, constraints)
20262  {
20263  Oid constrOid = lfirst_oid(cell);
20264  HeapTuple tuple;
20265  Form_pg_constraint constrForm;
20266  Relation rel;
20267  Trigger trig = {0};
20268 
20269  tuple = SearchSysCache1(CONSTROID, ObjectIdGetDatum(constrOid));
20270  if (!HeapTupleIsValid(tuple))
20271  elog(ERROR, "cache lookup failed for constraint %u", constrOid);
20272  constrForm = (Form_pg_constraint) GETSTRUCT(tuple);
20273 
20274  Assert(OidIsValid(constrForm->conparentid));
20275  Assert(constrForm->confrelid == RelationGetRelid(partition));
20276 
20277  /* prevent data changes into the referencing table until commit */
20278  rel = table_open(constrForm->conrelid, ShareLock);
20279 
20280  trig.tgoid = InvalidOid;
20281  trig.tgname = NameStr(constrForm->conname);
20283  trig.tgisinternal = true;
20284  trig.tgconstrrelid = RelationGetRelid(partition);
20285  trig.tgconstrindid = constrForm->conindid;
20286  trig.tgconstraint = constrForm->oid;
20287  trig.tgdeferrable = false;
20288  trig.tginitdeferred = false;
20289  /* we needn't fill in remaining fields */
20290 
20291  RI_PartitionRemove_Check(&trig, rel, partition);
20292 
20293  ReleaseSysCache(tuple);
20294 
20295  table_close(rel, NoLock);
20296  }
20297 }
20298 
20299 /*
20300  * resolve column compression specification to compression method.
20301  */
20302 static char
20303 GetAttributeCompression(Oid atttypid, const char *compression)
20304 {
20305  char cmethod;
20306 
20307  if (compression == NULL || strcmp(compression, "default") == 0)
20308  return InvalidCompressionMethod;
20309 
20310  /*
20311  * To specify a nondefault method, the column data type must be toastable.
20312  * Note this says nothing about whether the column's attstorage setting
20313  * permits compression; we intentionally allow attstorage and
20314  * attcompression to be independent. But with a non-toastable type,
20315  * attstorage could not be set to a value that would permit compression.
20316  *
20317  * We don't actually need to enforce this, since nothing bad would happen
20318  * if attcompression were non-default; it would never be consulted. But
20319  * it seems more user-friendly to complain about a certainly-useless
20320  * attempt to set the property.
20321  */
20322  if (!TypeIsToastable(atttypid))
20323  ereport(ERROR,
20324  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
20325  errmsg("column data type %s does not support compression",
20326  format_type_be(atttypid))));
20327 
20328  cmethod = CompressionNameToMethod(compression);
20329  if (!CompressionMethodIsValid(cmethod))
20330  ereport(ERROR,
20331  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
20332  errmsg("invalid compression method \"%s\"", compression)));
20333 
20334  return cmethod;
20335 }
20336 
20337 /*
20338  * resolve column storage specification
20339  */
20340 static char
20341 GetAttributeStorage(Oid atttypid, const char *storagemode)
20342 {
20343  char cstorage = 0;
20344 
20345  if (pg_strcasecmp(storagemode, "plain") == 0)
20346  cstorage = TYPSTORAGE_PLAIN;
20347  else if (pg_strcasecmp(storagemode, "external") == 0)
20348  cstorage = TYPSTORAGE_EXTERNAL;
20349  else if (pg_strcasecmp(storagemode, "extended") == 0)
20350  cstorage = TYPSTORAGE_EXTENDED;
20351  else if (pg_strcasecmp(storagemode, "main") == 0)
20352  cstorage = TYPSTORAGE_MAIN;
20353  else if (pg_strcasecmp(storagemode, "default") == 0)
20354  cstorage = get_typstorage(atttypid);
20355  else
20356  ereport(ERROR,
20357  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
20358  errmsg("invalid storage type \"%s\"",
20359  storagemode)));
20360 
20361  /*
20362  * safety check: do not allow toasted storage modes unless column datatype
20363  * is TOAST-aware.
20364  */
20365  if (!(cstorage == TYPSTORAGE_PLAIN || TypeIsToastable(atttypid)))
20366  ereport(ERROR,
20367  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
20368  errmsg("column data type %s can only have storage PLAIN",
20369  format_type_be(atttypid))));
20370 
20371  return cstorage;
20372 }
Datum idx(PG_FUNCTION_ARGS)
Definition: _int_op.c:259
Acl * aclnewowner(const Acl *old_acl, Oid oldOwnerId, Oid newOwnerId)
Definition: acl.c:1103
void check_can_set_role(Oid member, Oid role)
Definition: acl.c:5325
Oid get_rolespec_oid(const RoleSpec *role, bool missing_ok)
Definition: acl.c:5588
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:2703
AclResult pg_attribute_aclcheck(Oid table_oid, AttrNumber attnum, Oid roleid, AclMode mode)
Definition: aclchk.c:3923
AclResult object_aclcheck(Oid classid, Oid objectid, Oid roleid, AclMode mode)
Definition: aclchk.c:3891
bool object_ownercheck(Oid classid, Oid objectid, Oid roleid)
Definition: aclchk.c:4145
void aclcheck_error_type(AclResult aclerr, Oid typeOid)
Definition: aclchk.c:3022
AclResult pg_class_aclcheck(Oid table_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4094
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:3361
Datum array_get_element(Datum arraydatum, int nSubscripts, int *indx, int arraytyplen, int elmlen, bool elmbyval, char elmalign, bool *isNull)
Definition: arrayfuncs.c:1820
void free_attrmap(AttrMap *map)
Definition: attmap.c:56
AttrMap * make_attrmap(int maplen)
Definition: attmap.c:40
AttrMap * build_attrmap_by_name_if_req(TupleDesc indesc, TupleDesc outdesc, bool missing_ok)
Definition: attmap.c:263
AttrMap * build_attrmap_by_name(TupleDesc indesc, TupleDesc outdesc, bool missing_ok)
Definition: attmap.c:177
int16 AttrNumber
Definition: attnum.h:21
#define InvalidAttrNumber
Definition: attnum.h:23
char * get_tablespace_name(Oid spc_oid)
Definition: tablespace.c:1472
Oid get_tablespace_oid(const char *tablespacename, bool missing_ok)
Definition: tablespace.c:1426
Oid GetDefaultTablespace(char relpersistence, bool partitioned)
Definition: tablespace.c:1143
List * raw_parser(const char *str, RawParseMode mode)
Definition: parser.c:42
bool TimestampTimestampTzRequiresRewrite(void)
Definition: timestamp.c:6282
int bms_next_member(const Bitmapset *a, int prevbit)
Definition: bitmapset.c:1306
bool bms_is_member(int x, const Bitmapset *a)
Definition: bitmapset.c:510
Bitmapset * bms_make_singleton(int x)
Definition: bitmapset.c:216
#define bms_is_empty(a)
Definition: bitmapset.h:118
void FlushRelationBuffers(Relation rel)
Definition: bufmgr.c:4492
#define TextDatumGetCString(d)
Definition: builtins.h:98
#define NameStr(name)
Definition: c.h:737
uint16 bits16
Definition: c.h:513
signed short int16
Definition: c.h:495
uint32 SubTransactionId
Definition: c.h:647
signed int int32
Definition: c.h:496
#define gettext_noop(x)
Definition: c.h:1187
#define PG_USED_FOR_ASSERTS_ONLY
Definition: c.h:185
#define InvalidSubTransactionId
Definition: c.h:649
#define Assert(condition)
Definition: c.h:849
#define PointerIsValid(pointer)
Definition: c.h:754
#define MemSet(start, val, len)
Definition: c.h:1011
uint32 CommandId
Definition: c.h:657
#define PG_INT16_MAX
Definition: c.h:577
#define OidIsValid(objectId)
Definition: c.h:766
bool IsToastNamespace(Oid namespaceId)
Definition: catalog.c:230
bool IsSystemRelation(Relation relation)
Definition: catalog.c:73
RelFileNumber GetNewRelFileNumber(Oid reltablespace, Relation pg_class, char relpersistence)
Definition: catalog.c:528
bool IsCatalogNamespace(Oid namespaceId)
Definition: catalog.c:212
bool IsSystemClass(Oid relid, Form_pg_class reltuple)
Definition: catalog.c:85
bool contain_mutable_functions(Node *clause)
Definition: clauses.c:370
Node * eval_const_expressions(PlannerInfo *root, Node *node)
Definition: clauses.c:2254
void check_index_is_clusterable(Relation OldHeap, Oid indexOid, LOCKMODE lockmode)
Definition: cluster.c:500
void finish_heap_swap(Oid OIDOldHeap, Oid OIDNewHeap, bool is_system_catalog, bool swap_toast_by_content, bool check_constraints, bool is_internal, TransactionId frozenXid, MultiXactId cutoffMulti, char newrelpersistence)
Definition: cluster.c:1438
Oid make_new_heap(Oid OIDOldHeap, Oid NewTableSpace, Oid NewAccessMethod, char relpersistence, LOCKMODE lockmode)
Definition: cluster.c:688
void mark_index_clustered(Relation rel, Oid indexOid, bool is_internal)
Definition: cluster.c:560
Oid collid
void ResetSequence(Oid seq_relid)
Definition: sequence.c:262
void SequenceChangePersistence(Oid relid, char newrelpersistence)
Definition: sequence.c:541
char * GetComment(Oid oid, Oid classoid, int32 subid)
Definition: comment.c:410
ObjectAddress CommentObject(CommentStmt *stmt)
Definition: comment.c:40
int32 defGetInt32(DefElem *def)
Definition: define.c:162
void performMultipleDeletions(const ObjectAddresses *objects, DropBehavior behavior, int flags)
Definition: dependency.c:332
void performDeletion(const ObjectAddress *object, DropBehavior behavior, int flags)
Definition: dependency.c:273
bool object_address_present(const ObjectAddress *object, const ObjectAddresses *addrs)
Definition: dependency.c:2593
ObjectAddresses * new_object_addresses(void)
Definition: dependency.c:2487
void add_exact_object_address(const ObjectAddress *object, ObjectAddresses *addrs)
Definition: dependency.c:2533
void free_object_addresses(ObjectAddresses *addrs)
Definition: dependency.c:2773
#define PERFORM_DELETION_CONCURRENTLY
Definition: dependency.h:93
DependencyType
Definition: dependency.h:32
@ DEPENDENCY_AUTO
Definition: dependency.h:34
@ DEPENDENCY_INTERNAL
Definition: dependency.h:35
@ DEPENDENCY_PARTITION_PRI
Definition: dependency.h:36
@ DEPENDENCY_PARTITION_SEC
Definition: dependency.h:37
@ DEPENDENCY_NORMAL
Definition: dependency.h:33
#define PERFORM_DELETION_QUIETLY
Definition: dependency.h:94
#define PERFORM_DELETION_INTERNAL
Definition: dependency.h:92
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:1420
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1385
int errmsg_internal(const char *fmt,...)
Definition: elog.c:1157
int errdetail(const char *fmt,...)
Definition: elog.c:1203
int errhint(const char *fmt,...)
Definition: elog.c:1317
int errcode(int sqlerrcode)
Definition: elog.c:853
int errmsg(const char *fmt,...)
Definition: elog.c:1070
#define _(x)
Definition: elog.c:90
#define PG_TRY(...)
Definition: elog.h:371
#define WARNING
Definition: elog.h:36
#define PG_END_TRY(...)
Definition: elog.h:396
#define DEBUG1
Definition: elog.h:30
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:225
#define NOTICE
Definition: elog.h:35
#define PG_FINALLY(...)
Definition: elog.h:388
#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:743
bool ExecCheck(ExprState *state, ExprContext *econtext)
Definition: execExpr.c:850
ExprState * ExecInitExpr(Expr *node, PlanState *parent)
Definition: execExpr.c:138
void InitResultRelInfo(ResultRelInfo *resultRelInfo, Relation resultRelationDesc, Index resultRelationIndex, ResultRelInfo *partition_root_rri, int instrument_options)
Definition: execMain.c:1201
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:191
struct ResultRelInfo ResultRelInfo
#define GetPerTupleExprContext(estate)
Definition: executor.h:561
#define ResetExprContext(econtext)
Definition: executor.h:555
#define GetPerTupleMemoryContext(estate)
Definition: executor.h:566
static Datum ExecEvalExpr(ExprState *state, ExprContext *econtext, bool *isNull)
Definition: executor.h:344
#define palloc0_object(type)
Definition: fe_memutils.h:63
#define DirectFunctionCall2(func, arg1, arg2)
Definition: fmgr.h:643
#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:37
ForeignServer * GetForeignServer(Oid serverid)
Definition: foreign.c:111
Oid GetForeignServerIdByRelId(Oid relid)
Definition: foreign.c:355
FdwRoutine * GetFdwRoutineByServerId(Oid serverid)
Definition: foreign.c:377
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:604
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:511
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:387
StrategyNumber GistTranslateStratnum(Oid opclass, StrategyNumber strat)
Definition: gistutil.c:1081
bool IsBinaryUpgrade
Definition: globals.c:120
bool allowSystemTableMods
Definition: globals.c:129
Oid MyDatabaseTableSpace
Definition: globals.c:95
Oid MyDatabaseId
Definition: globals.c:93
#define newval
for(;;)
void RelationClearMissing(Relation rel)
Definition: heap.c:1945
void StorePartitionKey(Relation rel, char strategy, int16 partnatts, AttrNumber *partattrs, List *partexprs, Oid *partopclass, Oid *partcollation)
Definition: heap.c:3324
List * heap_truncate_find_FKs(List *relationIds)
Definition: heap.c:3197
void RemoveStatistics(Oid relid, AttrNumber attnum)
Definition: heap.c:2922
Oid heap_create_with_catalog(const char *relname, Oid relnamespace, Oid reltablespace, Oid relid, Oid reltypeid, Oid reloftypeid, Oid ownerid, Oid accessmtd, TupleDesc tupdesc, List *cooked_constraints, char relkind, char relpersistence, bool shared_relation, bool mapped_relation, OnCommitAction oncommit, Datum reloptions, bool use_user_acl, bool allow_system_table_mods, bool is_internal, Oid relrewrite, ObjectAddress *typaddress)
Definition: heap.c:1105
void heap_truncate(List *relids)
Definition: heap.c:3017
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:3102
void StorePartitionBound(Relation rel, Relation parent, PartitionBoundSpec *bound)
Definition: heap.c:3480
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:3058
List * AddRelationNewConstraints(Relation rel, List *newColDefaults, List *newConstraints, bool allow_merge, bool is_local, bool is_internal, const char *queryString)
Definition: heap.c:2259
#define CHKATYPE_IS_PARTKEY
Definition: heap.h:25
HeapTuple heap_getnext(TableScanDesc sscan, ScanDirection direction)
Definition: heapam.c:1243
BulkInsertState GetBulkInsertState(void)
Definition: heapam.c:1918
void FreeBulkInsertState(BulkInsertState bistate)
Definition: heapam.c:1935
#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:3534
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:2539
bool reindex_relation(const ReindexStmt *stmt, Oid relid, int flags, const ReindexParams *params)
Definition: index.c:3899
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:1883
IndexInfo * BuildIndexInfo(Relation index)
Definition: index.c:2430
#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:537
void IndexSetParentIndex(Relation partitionIdx, Oid parentOid)
Definition: indexcmds.c:4414
Oid GetDefaultOpClass(Oid type_id, Oid am_id)
Definition: indexcmds.c:2332
bool CheckIndexCompatible(Oid oldId, const char *accessMethodName, const List *attributeList, const List *exclusionOpNames, bool isWithoutOverlaps)
Definition: indexcmds.c:179
void WaitForOlderSnapshots(TransactionId limitXmin, bool progress)
Definition: indexcmds.c:430
Oid ResolveOpClass(const List *opclass, Oid attrType, const char *accessMethodName, Oid accessMethodId)
Definition: indexcmds.c:2247
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:689
static struct @157 value
static bool pg_add_s16_overflow(int16 a, int16 b, int16 *result)
Definition: int.h:67
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_concat_copy(const List *list1, const List *list2)
Definition: list.c:598
List * list_append_unique_oid(List *list, Oid datum)
Definition: list.c:1380
void list_free_deep(List *list)
Definition: list.c:1560
bool ConditionalLockRelationOid(Oid relid, LOCKMODE lockmode)
Definition: lmgr.c:151
void UnlockRelationOid(Oid relid, LOCKMODE lockmode)
Definition: lmgr.c:227
void WaitForLockersMultiple(List *locktags, LOCKMODE lockmode, bool progress)
Definition: lmgr.c:897
void LockRelationOid(Oid relid, LOCKMODE lockmode)
Definition: lmgr.c:108
bool CheckRelationOidLockedByMe(Oid relid, LOCKMODE lockmode, bool orstronger)
Definition: lmgr.c:347
void UnlockTuple(Relation relation, ItemPointer tid, LOCKMODE lockmode)
Definition: lmgr.c:595
#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 InplaceUpdateTupleLock
Definition: lockdefs.h:48
#define ShareUpdateExclusiveLock
Definition: lockdefs.h:39
#define RowShareLock
Definition: lockdefs.h:37
#define ShareLock
Definition: lockdefs.h:40
#define RowExclusiveLock
Definition: lockdefs.h:38
AttrNumber get_attnum(Oid relid, const char *attname)
Definition: lsyscache.c:858
Oid get_constraint_index(Oid conoid)
Definition: lsyscache.c:1113
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3366
char get_typstorage(Oid typid)
Definition: lsyscache.c:2419
bool get_index_isreplident(Oid index_oid)
Definition: lsyscache.c:3555
char get_rel_relkind(Oid relid)
Definition: lsyscache.c:2003
Oid get_typcollation(Oid typid)
Definition: lsyscache.c:3056
char * get_rel_name(Oid relid)
Definition: lsyscache.c:1928
bool get_index_isclustered(Oid index_oid)
Definition: lsyscache.c:3601
Oid get_opfamily_member(Oid opfamily, Oid lefttype, Oid righttype, int16 strategy)
Definition: lsyscache.c:166
char * get_collation_name(Oid colloid)
Definition: lsyscache.c:1035
char * get_constraint_name(Oid conoid)
Definition: lsyscache.c:1081
Oid get_rel_relam(Oid relid)
Definition: lsyscache.c:2100
bool type_is_collatable(Oid typid)
Definition: lsyscache.c:3081
Oid get_rel_tablespace(Oid relid)
Definition: lsyscache.c:2054
Oid get_typ_typrelid(Oid typid)
Definition: lsyscache.c:2731
Oid getBaseTypeAndTypmod(Oid typid, int32 *typmod)
Definition: lsyscache.c:2538
Oid getBaseType(Oid typid)
Definition: lsyscache.c:2521
char get_constraint_type(Oid conoid)
Definition: lsyscache.c:1143
Oid get_relname_relid(const char *relname, Oid relnamespace)
Definition: lsyscache.c:1885
char * get_attname(Oid relid, AttrNumber attnum, bool missing_ok)
Definition: lsyscache.c:827
#define TypeIsToastable(typid)
Definition: lsyscache.h:213
List * make_ands_implicit(Expr *clause)
Definition: makefuncs.c:737
TypeName * makeTypeNameFromNameList(List *names)
Definition: makefuncs.c:458
Const * makeNullConst(Oid consttype, int32 consttypmod, Oid constcollid)
Definition: makefuncs.c:339
RangeVar * makeRangeVar(char *schemaname, char *relname, int location)
Definition: makefuncs.c:424
ColumnDef * makeColumnDef(const char *colname, Oid typeOid, int32 typmod, Oid collOid)
Definition: makefuncs.c:492
Var * makeVar(int varno, AttrNumber varattno, Oid vartype, int32 vartypmod, Oid varcollid, Index varlevelsup)
Definition: makefuncs.c:66
Expr * make_ands_explicit(List *andclauses)
Definition: makefuncs.c:726
void MemoryContextReset(MemoryContext context)
Definition: mcxt.c:383
char * pstrdup(const char *in)
Definition: mcxt.c:1696
void pfree(void *pointer)
Definition: mcxt.c:1521
void * palloc0(Size size)
Definition: mcxt.c:1347
MemoryContext CurrentMemoryContext
Definition: mcxt.c:143
char * MemoryContextStrdup(MemoryContext context, const char *string)
Definition: mcxt.c:1683
MemoryContext CacheMemoryContext
Definition: mcxt.c:152
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:454
void * palloc(Size size)
Definition: mcxt.c:1317
MemoryContext PortalContext
Definition: mcxt.c:158
#define AllocSetContextCreate
Definition: memutils.h:129
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:160
#define ALLOCSET_SMALL_SIZES
Definition: memutils.h:170
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:122
bool InSecurityRestrictedOperation(void)
Definition: miscinit.c:662
Oid GetUserId(void)
Definition: miscinit.c:514
MultiXactId ReadNextMultiXactId(void)
Definition: multixact.c:771
void namestrcpy(Name name, const char *str)
Definition: name.c:233
Oid RangeVarGetAndCheckCreationNamespace(RangeVar *relation, LOCKMODE lockmode, Oid *existing_relation_id)
Definition: namespace.c:739
bool isAnyTempNamespace(Oid namespaceId)
Definition: namespace.c:3687
Oid get_collation_oid(List *collname, bool missing_ok)
Definition: namespace.c:3971
void CheckSetNamespace(Oid oldNspOid, Oid nspOid)
Definition: namespace.c:3459
RangeVar * makeRangeVarFromNameList(const List *names)
Definition: namespace.c:3554
Oid LookupNamespaceNoError(const char *nspname)
Definition: namespace.c:3355
Oid RangeVarGetRelidExtended(const RangeVar *relation, LOCKMODE lockmode, uint32 flags, RangeVarGetRelidCallback callback, void *callback_arg)
Definition: namespace.c:441
@ 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
#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:794
Node * coerce_to_target_type(ParseState *pstate, Node *expr, Oid exprtype, Oid targettype, int32 targettypmod, CoercionContext ccontext, CoercionForm cformat, int location)
Definition: parse_coerce.c:78
CoercionPathType find_coercion_pathway(Oid targetTypeId, Oid sourceTypeId, CoercionContext ccontext, Oid *funcid)
bool can_coerce_type(int nargs, const Oid *input_typeids, const Oid *target_typeids, CoercionContext ccontext)
Definition: parse_coerce.c:556
CoercionPathType
Definition: parse_coerce.h:25
@ COERCION_PATH_NONE
Definition: parse_coerce.h:26
@ COERCION_PATH_RELABELTYPE
Definition: parse_coerce.h:28
void assign_expr_collations(ParseState *pstate, Node *expr)
Node * transformExpr(ParseState *pstate, Node *expr, ParseExprKind exprKind)
Definition: parse_expr.c:120
int parser_errposition(ParseState *pstate, int location)
Definition: parse_node.c:106
ParseState * make_parsestate(ParseState *parentParseState)
Definition: parse_node.c:39
@ EXPR_KIND_PARTITION_EXPRESSION
Definition: parse_node.h:80
ParseNamespaceItem * addRangeTableEntryForRelation(ParseState *pstate, Relation rel, int lockmode, Alias *alias, bool inh, bool inFromCl)
const NameData * attnumAttName(Relation rd, int attid)
void addNSItemToQuery(ParseState *pstate, ParseNamespaceItem *nsitem, bool addToJoinList, bool addToRelNameSpace, bool addToVarNameSpace)
Oid attnumTypeId(Relation rd, int attid)
void typenameTypeIdAndMod(ParseState *pstate, const TypeName *typeName, Oid *typeid_p, int32 *typmod_p)
Definition: parse_type.c:310
Type typenameType(ParseState *pstate, const TypeName *typeName, int32 *typmod_p)
Definition: parse_type.c:264
Oid GetColumnDefCollation(ParseState *pstate, const ColumnDef *coldef, Oid typeOid)
Definition: parse_type.c:540
Oid typenameTypeId(ParseState *pstate, const TypeName *typeName)
Definition: parse_type.c:291
IndexStmt * generateClonedIndexStmt(RangeVar *heapRel, Relation source_idx, const AttrMap *attmap, Oid *constraintOid)
CreateStatsStmt * transformStatsStmt(Oid relid, CreateStatsStmt *stmt, const char *queryString)
AlterTableStmt * transformAlterTableStmt(Oid relid, AlterTableStmt *stmt, const char *queryString, List **beforeStmts, List **afterStmts)
IndexStmt * transformIndexStmt(Oid relid, IndexStmt *stmt, const char *queryString)
PartitionBoundSpec * transformPartitionBound(ParseState *pstate, Relation parent, PartitionBoundSpec *spec)
#define FKCONSTR_ACTION_RESTRICT
Definition: parsenodes.h:2733
#define ACL_MAINTAIN
Definition: parsenodes.h:90
#define ACL_USAGE
Definition: parsenodes.h:84
#define FKCONSTR_ACTION_SETDEFAULT
Definition: parsenodes.h:2736
PartitionStrategy
Definition: parsenodes.h:873
@ PARTITION_STRATEGY_HASH
Definition: parsenodes.h:876
@ PARTITION_STRATEGY_LIST
Definition: parsenodes.h:874
ConstrType
Definition: parsenodes.h:2713
@ CONSTR_FOREIGN
Definition: parsenodes.h:2724
@ CONSTR_UNIQUE
Definition: parsenodes.h:2722
@ CONSTR_DEFAULT
Definition: parsenodes.h:2717
@ CONSTR_CHECK
Definition: parsenodes.h:2720
@ CONSTR_EXCLUSION
Definition: parsenodes.h:2723
@ CONSTR_PRIMARY
Definition: parsenodes.h:2721
DropBehavior
Definition: parsenodes.h:2330
@ DROP_CASCADE
Definition: parsenodes.h:2332
@ DROP_RESTRICT
Definition: parsenodes.h:2331
ObjectType
Definition: parsenodes.h:2257
@ OBJECT_MATVIEW
Definition: parsenodes.h:2281
@ OBJECT_SCHEMA
Definition: parsenodes.h:2294
@ OBJECT_FOREIGN_TABLE
Definition: parsenodes.h:2276
@ OBJECT_TABLESPACE
Definition: parsenodes.h:2300
@ OBJECT_INDEX
Definition: parsenodes.h:2278
@ OBJECT_SEQUENCE
Definition: parsenodes.h:2295
@ OBJECT_TABLE
Definition: parsenodes.h:2299
@ OBJECT_VIEW
Definition: parsenodes.h:2309
@ OBJECT_TYPE
Definition: parsenodes.h:2307
@ OBJECT_TABCONSTRAINT
Definition: parsenodes.h:2298
@ OBJECT_DOMCONSTRAINT
Definition: parsenodes.h:2271
AlterTableType
Definition: parsenodes.h:2349
@ AT_AddIndexConstraint
Definition: parsenodes.h:2372
@ AT_DropOf
Definition: parsenodes.h:2403
@ AT_CheckNotNull
Definition: parsenodes.h:2358
@ AT_SetOptions
Definition: parsenodes.h:2360
@ AT_DropIdentity
Definition: parsenodes.h:2415
@ AT_DisableTrigUser
Definition: parsenodes.h:2395
@ AT_DropNotNull
Definition: parsenodes.h:2354
@ AT_AddOf
Definition: parsenodes.h:2402
@ AT_ResetOptions
Definition: parsenodes.h:2361
@ AT_ReplicaIdentity
Definition: parsenodes.h:2404
@ AT_ReplaceRelOptions
Definition: parsenodes.h:2387
@ AT_EnableRowSecurity
Definition: parsenodes.h:2405
@ AT_AddColumnToView
Definition: parsenodes.h:2351
@ AT_ResetRelOptions
Definition: parsenodes.h:2386
@ AT_EnableReplicaTrig
Definition: parsenodes.h:2390
@ AT_DropOids
Definition: parsenodes.h:2382
@ AT_SetIdentity
Definition: parsenodes.h:2414
@ AT_ReAddStatistics
Definition: parsenodes.h:2416
@ AT_SetUnLogged
Definition: parsenodes.h:2381
@ AT_DisableTrig
Definition: parsenodes.h:2391
@ AT_SetCompression
Definition: parsenodes.h:2363
@ AT_DropExpression
Definition: parsenodes.h:2357
@ AT_AddIndex
Definition: parsenodes.h:2365
@ AT_EnableReplicaRule
Definition: parsenodes.h:2398
@ AT_ReAddIndex
Definition: parsenodes.h:2366
@ AT_DropConstraint
Definition: parsenodes.h:2373
@ AT_SetNotNull
Definition: parsenodes.h:2355
@ AT_ClusterOn
Definition: parsenodes.h:2378
@ AT_AddIdentity
Definition: parsenodes.h:2413
@ AT_ForceRowSecurity
Definition: parsenodes.h:2407
@ AT_EnableAlwaysRule
Definition: parsenodes.h:2397
@ AT_SetAccessMethod
Definition: parsenodes.h:2383
@ AT_AlterColumnType
Definition: parsenodes.h:2375
@ AT_DetachPartitionFinalize
Definition: parsenodes.h:2412
@ AT_AddInherit
Definition: parsenodes.h:2400
@ AT_ReAddDomainConstraint
Definition: parsenodes.h:2369
@ AT_EnableTrig
Definition: parsenodes.h:2388
@ AT_DropColumn
Definition: parsenodes.h:2364
@ AT_ReAddComment
Definition: parsenodes.h:2374
@ AT_AlterColumnGenericOptions
Definition: parsenodes.h:2376
@ AT_DisableTrigAll
Definition: parsenodes.h:2393
@ AT_EnableRule
Definition: parsenodes.h:2396
@ AT_NoForceRowSecurity
Definition: parsenodes.h:2408
@ AT_DetachPartition
Definition: parsenodes.h:2411
@ AT_SetStatistics
Definition: parsenodes.h:2359
@ AT_AttachPartition
Definition: parsenodes.h:2410
@ AT_AddConstraint
Definition: parsenodes.h:2367
@ AT_DropInherit
Definition: parsenodes.h:2401
@ AT_EnableAlwaysTrig
Definition: parsenodes.h:2389
@ AT_SetLogged
Definition: parsenodes.h:2380
@ AT_SetStorage
Definition: parsenodes.h:2362
@ AT_DisableRule
Definition: parsenodes.h:2399
@ AT_DisableRowSecurity
Definition: parsenodes.h:2406
@ AT_SetRelOptions
Definition: parsenodes.h:2385
@ AT_ChangeOwner
Definition: parsenodes.h:2377
@ AT_EnableTrigUser
Definition: parsenodes.h:2394
@ AT_SetExpression
Definition: parsenodes.h:2356
@ AT_ReAddConstraint
Definition: parsenodes.h:2368
@ AT_SetTableSpace
Definition: parsenodes.h:2384
@ AT_GenericOptions
Definition: parsenodes.h:2409
@ AT_ColumnDefault
Definition: parsenodes.h:2352
@ AT_CookedColumnDefault
Definition: parsenodes.h:2353
@ AT_AlterConstraint
Definition: parsenodes.h:2370
@ AT_EnableTrigAll
Definition: parsenodes.h:2392
@ AT_DropCluster
Definition: parsenodes.h:2379
@ AT_ValidateConstraint
Definition: parsenodes.h:2371
@ AT_AddColumn
Definition: parsenodes.h:2350
#define ACL_REFERENCES
Definition: parsenodes.h:81
#define FKCONSTR_ACTION_CASCADE
Definition: parsenodes.h:2734
#define ACL_TRUNCATE
Definition: parsenodes.h:80
#define ACL_CREATE
Definition: parsenodes.h:85
#define FKCONSTR_ACTION_SETNULL
Definition: parsenodes.h:2735
#define FKCONSTR_ACTION_NOACTION
Definition: parsenodes.h:2732
@ 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:3251
List * RelationGetPartitionQual(Relation rel)
Definition: partcache.c:277
PartitionDesc RelationGetPartitionDesc(Relation rel, bool omit_detached)
Definition: partdesc.c:71
Oid get_default_oid_from_partdesc(PartitionDesc partdesc)
Definition: partdesc.c:501
bool has_partition_attrs(Relation rel, Bitmapset *attnums, bool *used_in_expr)
Definition: partition.c:255
List * map_partition_varattnos(List *expr, int fromrel_varno, Relation to_rel, Relation from_rel)
Definition: partition.c:222
List * get_proposed_default_constraint(List *new_part_constraints)
Definition: partition.c:370
void update_default_partition_oid(Oid parentId, Oid defaultPartId)
Definition: partition.c:340
Oid index_get_partition(Relation partition, Oid indexId)
Definition: partition.c:176
Oid get_partition_parent(Oid relid, bool even_if_detached)
Definition: partition.c:53
Oid GetAttrDefaultOid(Oid relid, AttrNumber attnum)
Definition: pg_attrdef.c:339
Oid StoreAttrDefault(Relation rel, AttrNumber attnum, Node *expr, bool is_internal, bool add_column_mode)
Definition: pg_attrdef.c:46
ObjectAddress GetAttrDefaultColumnAddress(Oid attrdefoid)
Definition: pg_attrdef.c:381
void RemoveAttrDefault(Oid relid, AttrNumber attnum, DropBehavior behavior, bool complain, bool internal)
Definition: pg_attrdef.c:213
NameData attname
Definition: pg_attribute.h:41
int16 attnum
Definition: pg_attribute.h:74
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:209
bool attnotnull
Definition: pg_attribute.h:130
void * arg
int errdetail_relkind_not_supported(char relkind)
Definition: pg_class.c:24
NameData relname
Definition: pg_class.h:38
FormData_pg_class * Form_pg_class
Definition: pg_class.h:153
#define PARTITION_MAX_KEYS
#define INDEX_MAX_KEYS
#define NAMEDATALEN
char * ChooseConstraintName(const char *name1, const char *name2, const char *label, Oid namespaceid, List *others)
bool ConstraintNameIsUsed(ConstraintCategory conCat, Oid objId, const char *conname)
void RenameConstraintById(Oid conId, const char *newname)
Oid get_relation_idx_constraint_oid(Oid relationId, Oid indexId)
void ConstraintSetParentConstraint(Oid childConstrId, Oid parentConstrId, Oid childTableId)
void DeconstructFkConstraintRow(HeapTuple tuple, int *numfks, AttrNumber *conkey, AttrNumber *confkey, Oid *pf_eq_oprs, Oid *pp_eq_oprs, Oid *ff_eq_oprs, int *num_fk_del_set_cols, AttrNumber *fk_del_set_cols)
void AlterConstraintNamespaces(Oid ownerId, Oid oldNspId, Oid newNspId, bool isType, ObjectAddresses *objsMoved)
void FindFKPeriodOpers(Oid opclass, Oid *containedbyoperoid, Oid *aggedcontainedbyoperoid)
Oid get_relation_constraint_oid(Oid relid, const char *conname, bool missing_ok)
Oid get_domain_constraint_oid(Oid typid, const char *conname, bool missing_ok)
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, int16 conInhCount, bool conNoInherit, bool conPeriod, bool is_internal)
Definition: pg_constraint.c:50
FormData_pg_constraint * Form_pg_constraint
@ CONSTRAINT_RELATION
void recordDependencyOn(const ObjectAddress *depender, const ObjectAddress *referenced, DependencyType behavior)
Definition: pg_depend.c:46
long changeDependencyFor(Oid classId, Oid objectId, Oid refClassId, Oid oldRefObjectId, Oid newRefObjectId)
Definition: pg_depend.c:458
long deleteDependencyRecordsForClass(Oid classId, Oid objectId, Oid refclassId, char deptype)
Definition: pg_depend.c:352
long deleteDependencyRecordsFor(Oid classId, Oid objectId, bool skipExtensionDeps)
Definition: pg_depend.c:302
long deleteDependencyRecordsForSpecific(Oid classId, Oid objectId, char deptype, Oid refclassId, Oid refobjectId)
Definition: pg_depend.c:399
Oid getIdentitySequence(Relation rel, AttrNumber attnum, bool missing_ok)
Definition: pg_depend.c:946
Oid get_index_constraint(Oid indexId)
Definition: pg_depend.c:989
List * getOwnedSequences(Oid relid)
Definition: pg_depend.c:937
bool sequenceIsOwned(Oid seqId, char deptype, Oid *tableId, int32 *colId)
Definition: pg_depend.c:829
FormData_pg_depend * Form_pg_depend
Definition: pg_depend.h:72
FormData_pg_foreign_table * Form_pg_foreign_table
FormData_pg_index * Form_pg_index
Definition: pg_index.h:70
bool DeleteInheritsTuple(Oid inhrelid, Oid inhparent, bool expect_detach_pending, const char *childname)
Definition: pg_inherits.c:552
List * find_all_inheritors(Oid parentrelId, LOCKMODE lockmode, List **numparents)
Definition: pg_inherits.c:255
void StoreSingleInheritance(Oid relationId, Oid parentOid, int32 seqNumber)
Definition: pg_inherits.c:508
List * find_inheritance_children(Oid parentrelId, LOCKMODE lockmode)
Definition: pg_inherits.c:58
bool has_superclass(Oid relationId)
Definition: pg_inherits.c:377
bool PartitionHasPendingDetach(Oid partoid)
Definition: pg_inherits.c:620
FormData_pg_inherits * Form_pg_inherits
Definition: pg_inherits.h:45
#define lfirst(lc)
Definition: pg_list.h:172
#define lfirst_node(type, lc)
Definition: pg_list.h:176
static int list_length(const List *l)
Definition: pg_list.h:152
#define NIL
Definition: pg_list.h:68
#define forboth(cell1, list1, cell2, list2)
Definition: pg_list.h:518
#define foreach_current_index(var_or_cell)
Definition: pg_list.h:403
#define lfirst_int(lc)
Definition: pg_list.h:173
#define foreach_delete_current(lst, var_or_cell)
Definition: pg_list.h:391
#define list_make1_oid(x1)
Definition: pg_list.h:242
#define list_make1(x1)
Definition: pg_list.h:212
#define foreach_ptr(type, var, lst)
Definition: pg_list.h:469
static ListCell * list_head(const List *l)
Definition: pg_list.h:128
#define for_each_from(cell, lst, N)
Definition: pg_list.h:414
#define linitial(l)
Definition: pg_list.h:178
#define list_make3(x1, x2, x3)
Definition: pg_list.h:216
static void * list_nth(const List *list, int n)
Definition: pg_list.h:299
#define foreach_oid(var, lst)
Definition: pg_list.h:471
#define list_nth_node(type, list, n)
Definition: pg_list.h:327
static ListCell * lnext(const List *l, const ListCell *c)
Definition: pg_list.h:343
#define linitial_oid(l)
Definition: pg_list.h:180
#define lfirst_oid(lc)
Definition: pg_list.h:174
#define list_make2(x1, x2)
Definition: pg_list.h:214
FormData_pg_opclass * Form_pg_opclass
Definition: pg_opclass.h:83
List * GetRelationPublications(Oid relid)
void changeDependencyOnOwner(Oid classId, Oid objectId, Oid newOwnerId)
Definition: pg_shdepend.c:316
void changeDependencyOnTablespace(Oid classId, Oid objectId, Oid newTablespaceId)
Definition: pg_shdepend.c:391
static char * buf
Definition: pg_test_fsync.c:73
FormData_pg_trigger * Form_pg_trigger
Definition: pg_trigger.h:80
void RenameTypeInternal(Oid typeOid, const char *newTypeName, Oid typeNamespace)
Definition: pg_type.c:765
FormData_pg_type * Form_pg_type
Definition: pg_type.h:261
#define ERRCODE_UNDEFINED_TABLE
Definition: pgbench.c:78
void pgstat_count_truncate(Relation rel)
Expr * expression_planner(Expr *expr)
Definition: planner.c:6688
int pg_strcasecmp(const char *s1, const char *s2)
Definition: pgstrcasecmp.c:36
#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:3564
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:4409
void TransferPredicateLocksToHeapRelation(Relation relation)
Definition: predicate.c:3113
bool predicate_implied_by(List *predicate_list, List *clause_list, bool weak)
Definition: predtest.c:152
Expr * canonicalize_qual(Expr *qual, bool is_check)
Definition: prepqual.c:293
char * c
#define PRS2_OLD_VARNO
Definition: primnodes.h:244
#define PRS2_NEW_VARNO
Definition: primnodes.h:245
OnCommitAction
Definition: primnodes.h:56
@ ONCOMMIT_DELETE_ROWS
Definition: primnodes.h:59
@ ONCOMMIT_NOOP
Definition: primnodes.h:57
@ ONCOMMIT_PRESERVE_ROWS
Definition: primnodes.h:58
@ ONCOMMIT_DROP
Definition: primnodes.h:60
@ COERCE_IMPLICIT_CAST
Definition: primnodes.h:736
@ IS_NOT_NULL
Definition: primnodes.h:1952
@ COERCION_ASSIGNMENT
Definition: primnodes.h:715
@ COERCION_IMPLICIT
Definition: primnodes.h:714
tree context
Definition: radixtree.h:1835
MemoryContextSwitchTo(old_ctx)
void * stringToNode(const char *str)
Definition: read.c:90
#define RelationGetForm(relation)
Definition: rel.h:499
#define RelationGetRelid(relation)
Definition: rel.h:505
#define RelationIsLogicallyLogged(relation)
Definition: rel.h:701
#define RelationIsUsedAsCatalogTable(relation)
Definition: rel.h:386
static SMgrRelation RelationGetSmgr(Relation rel)
Definition: rel.h:567
#define RelationGetDescr(relation)
Definition: rel.h:531
#define RelationIsMapped(relation)
Definition: rel.h:554
#define RelationGetNumberOfAttributes(relation)
Definition: rel.h:511
#define RelationGetRelationName(relation)
Definition: rel.h:539
#define RELATION_IS_OTHER_TEMP(relation)
Definition: rel.h:658
#define RelationGetNamespace(relation)
Definition: rel.h:546
#define IndexRelationGetNumberOfKeyAttributes(relation)
Definition: rel.h:524
#define RelationIsPermanent(relation)
Definition: rel.h:617
List * RelationGetIndexList(Relation relation)
Definition: relcache.c:4804
int errtableconstraint(Relation rel, const char *conname)
Definition: relcache.c:6015
int errtablecol(Relation rel, int attnum)
Definition: relcache.c:5978
List * RelationGetIndexPredicate(Relation relation)
Definition: relcache.c:5154
Bitmapset * RelationGetIndexAttrBitmap(Relation relation, IndexAttrBitmapKind attrKind)
Definition: relcache.c:5247
List * RelationGetFKeyList(Relation relation)
Definition: relcache.c:4695
void RelationSetNewRelfilenumber(Relation relation, char persistence)
Definition: relcache.c:3767
void RelationAssumeNewRelfilelocator(Relation relation)
Definition: relcache.c:3969
int errtable(Relation rel)
Definition: relcache.c:5961
List * RelationGetIndexExpressions(Relation relation)
Definition: relcache.c:5041
struct RelationData * Relation
Definition: relcache.h:27
@ INDEX_ATTR_BITMAP_KEY
Definition: relcache.h:61
bytea * index_reloptions(amoptions_function amoptions, Datum reloptions, bool validate)
Definition: reloptions.c:2054
Datum transformRelOptions(Datum oldOptions, List *defList, const char *namspace, const char *const validnsps[], bool acceptOidsOff, bool isReset)
Definition: reloptions.c:1156
List * untransformRelOptions(Datum options)
Definition: reloptions.c:1331
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:56
@ MAIN_FORKNUM
Definition: relpath.h:58
@ INIT_FORKNUM
Definition: relpath.h:61
#define MAX_FORKNUM
Definition: relpath.h:70
#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:470
bool RI_Initial_Check(Trigger *trigger, Relation fk_rel, Relation pk_rel)
Definition: ri_triggers.c:1438
void RI_PartitionRemove_Check(Trigger *trigger, Relation fk_rel, Relation pk_rel)
Definition: ri_triggers.c:1732
int RI_FKey_trigger_type(Oid tgfoid)
Definition: ri_triggers.c:3116
char * pg_get_constraintdef_command(Oid constraintId)
Definition: ruleutils.c:2178
const char * quote_identifier(const char *ident)
Definition: ruleutils.c:12840
char * pg_get_statisticsobjdef_string(Oid statextid)
Definition: ruleutils.c:1621
Datum pg_get_expr(PG_FUNCTION_ARGS)
Definition: ruleutils.c:2643
char * pg_get_indexdef_string(Oid indexrelid)
Definition: ruleutils.c:1219
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:414
void smgrclose(SMgrRelation reln)
Definition: smgr.c:323
bool smgrexists(SMgrRelation reln, ForkNumber forknum)
Definition: smgr.c:401
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:2434
DropBehavior behavior
Definition: parsenodes.h:2437
AlterTableType subtype
Definition: parsenodes.h:2429
RangeVar * relation
Definition: parsenodes.h:2342
ObjectType objtype
Definition: parsenodes.h:2344
List * constraints
Definition: tablecmds.c:187
bool verify_new_notnull
Definition: tablecmds.c:190
List * changedConstraintDefs
Definition: tablecmds.c:203
Expr * partition_constraint
Definition: tablecmds.c:198
char newrelpersistence
Definition: tablecmds.c:197
List * changedStatisticsDefs
Definition: tablecmds.c:209
bool chgAccessMethod
Definition: tablecmds.c:192
List * afterStmts
Definition: tablecmds.c:189
char * clusterOnIndex
Definition: tablecmds.c:207
char * replicaIdentityIndex
Definition: tablecmds.c:206
List * changedStatisticsOids
Definition: tablecmds.c:208
List * changedIndexDefs
Definition: tablecmds.c:205
List * changedIndexOids
Definition: tablecmds.c:204
List * changedConstraintOids
Definition: tablecmds.c:202
bool validate_default
Definition: tablecmds.c:200
List * subcmds[AT_NUM_PASSES]
Definition: tablecmds.c:185
TupleDesc oldDesc
Definition: tablecmds.c:173
Relation rel
Definition: tablecmds.c:182
Definition: attmap.h:35
AttrNumber * attnums
Definition: attmap.h:36
bool is_not_null
Definition: parsenodes.h:733
char identity
Definition: parsenodes.h:739
RangeVar * identitySequence
Definition: parsenodes.h:740
List * constraints
Definition: parsenodes.h:745
Node * cooked_default
Definition: parsenodes.h:738
char * storage_name
Definition: parsenodes.h:736
char * colname
Definition: parsenodes.h:728
TypeName * typeName
Definition: parsenodes.h:729
char generated
Definition: parsenodes.h:742
bool is_from_type
Definition: parsenodes.h:734
Node * raw_default
Definition: parsenodes.h:737
char storage
Definition: parsenodes.h:735
bool is_local
Definition: parsenodes.h:732
int16 inhcount
Definition: parsenodes.h:731
char * compression
Definition: parsenodes.h:730
char * comment
Definition: parsenodes.h:3273
ObjectType objtype
Definition: parsenodes.h:3271
Node * object
Definition: parsenodes.h:3272
char * ccname
Definition: tupdesc.h:30
bool ccvalid
Definition: tupdesc.h:32
char * ccbin
Definition: tupdesc.h:31
bool initdeferred
Definition: parsenodes.h:2749
ParseLoc location
Definition: parsenodes.h:2788
bool reset_default_tblspc
Definition: parsenodes.h:2769
List * pk_attrs
Definition: parsenodes.h:2777
List * fk_del_set_cols
Definition: parsenodes.h:2783
bool fk_with_period
Definition: parsenodes.h:2778
ConstrType contype
Definition: parsenodes.h:2746
Oid old_pktable_oid
Definition: parsenodes.h:2785
bool is_no_inherit
Definition: parsenodes.h:2752
char fk_upd_action
Definition: parsenodes.h:2781
List * old_conpfeqop
Definition: parsenodes.h:2784
char fk_matchtype
Definition: parsenodes.h:2780
bool pk_with_period
Definition: parsenodes.h:2779
char * cooked_expr
Definition: parsenodes.h:2755
bool initially_valid
Definition: parsenodes.h:2751
bool skip_validation
Definition: parsenodes.h:2750
bool deferrable
Definition: parsenodes.h:2748
Node * raw_expr
Definition: parsenodes.h:2753
char * conname
Definition: parsenodes.h:2747
RangeVar * pktable
Definition: parsenodes.h:2775
char fk_del_action
Definition: parsenodes.h:2782
List * fk_attrs
Definition: parsenodes.h:2776
Oid conoid
Definition: heap.h:38
char * name
Definition: heap.h:39
AttrNumber attnum
Definition: heap.h:40
bool skip_validation
Definition: heap.h:42
bool is_no_inherit
Definition: heap.h:45
int16 inhcount
Definition: heap.h:44
bool is_local
Definition: heap.h:43
ConstrType contype
Definition: heap.h:37
Node * expr
Definition: heap.h:41
Node * whenClause
Definition: parsenodes.h:3032
List * transitionRels
Definition: parsenodes.h:3034
RangeVar * constrrel
Definition: parsenodes.h:3038
RangeVar * relation
Definition: parsenodes.h:3023
char * defname
Definition: parsenodes.h:817
bool missing_ok
Definition: parsenodes.h:3248
List * objects
Definition: parsenodes.h:3245
ObjectType removeType
Definition: parsenodes.h:3246
bool concurrent
Definition: parsenodes.h:3249
DropBehavior behavior
Definition: parsenodes.h:3247
List * es_opened_result_relations
Definition: execnodes.h:653
TupleTableSlot * ecxt_scantuple
Definition: execnodes.h:258
ExecForeignTruncate_function ExecForeignTruncate
Definition: fdwapi.h:263
Oid funcid
Definition: primnodes.h:750
List * args
Definition: primnodes.h:768
Size keysize
Definition: hsearch.h:75
Size entrysize
Definition: hsearch.h:76
MemoryContext hcxt
Definition: hsearch.h:86
Definition: dynahash.c:220
ItemPointerData t_self
Definition: htup.h:65
amoptions_function amoptions
Definition: amapi.h:283
bool amcanunique
Definition: amapi.h:237
bool ii_Unique
Definition: execnodes.h:199
bool reset_default_tblspc
Definition: parsenodes.h:3393
char * idxname
Definition: parsenodes.h:3367
char * idxcomment
Definition: parsenodes.h:3377
Definition: lock.h:165
Definition: pg_list.h:54
AttrNumber attnum
Definition: tablecmds.c:236
bool is_generated
Definition: tablecmds.c:239
ExprState * exprstate
Definition: tablecmds.c:238
char * name
Definition: tablecmds.c:216
ConstrType contype
Definition: tablecmds.c:217
bool conwithperiod
Definition: tablecmds.c:220
Node * qual
Definition: tablecmds.c:222
ExprState * qualstate
Definition: tablecmds.c:223
Definition: nodes.h:129
NullTestType nulltesttype
Definition: primnodes.h:1959
ParseLoc location
Definition: primnodes.h:1962
Expr * arg
Definition: primnodes.h:1958
SubTransactionId creating_subid
Definition: tablecmds.c:127
SubTransactionId deleting_subid
Definition: tablecmds.c:128
OnCommitAction oncommit
Definition: tablecmds.c:118
const char * p_sourcetext
Definition: parse_node.h:195
PartitionBoundSpec * bound
Definition: parsenodes.h:949
RangeVar * name
Definition: parsenodes.h:948
List * collation
Definition: parsenodes.h:867
ParseLoc location
Definition: parsenodes.h:869
List * opclass
Definition: parsenodes.h:868
List * partParams
Definition: parsenodes.h:888
ParseLoc location
Definition: parsenodes.h:889
PartitionStrategy strategy
Definition: parsenodes.h:887
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:2022
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:459
TransactionId xmin
Definition: snapshot.h:157
NodeTag type
Definition: trigger.h:33
Relation tg_relation
Definition: trigger.h:35
TriggerEvent tg_event
Definition: trigger.h:34
TupleTableSlot * tg_trigslot
Definition: trigger.h:39
Trigger * tg_trigger
Definition: trigger.h:38
HeapTuple tg_trigtuple
Definition: trigger.h:36
char tgenabled
Definition: reltrigger.h:30
Oid tgoid
Definition: reltrigger.h:25
Oid tgconstrindid
Definition: reltrigger.h:34
Oid tgconstraint
Definition: reltrigger.h:35
Oid tgconstrrelid
Definition: reltrigger.h:33
char * tgname
Definition: reltrigger.h:27
bool tgdeferrable
Definition: reltrigger.h:36
bool tginitdeferred
Definition: reltrigger.h:37
bool tgisinternal
Definition: reltrigger.h:31
bool has_not_null
Definition: tupdesc.h:44
ConstrCheck * check
Definition: tupdesc.h:40
uint16 num_check
Definition: tupdesc.h:43
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:272
List * arrayBounds
Definition: parsenodes.h:276
Definition: primnodes.h:248
const char * skipping_msg
Definition: tablecmds.c:250
int nonexistent_code
Definition: tablecmds.c:248
const char * nonexistent_msg
Definition: tablecmds.c:249
const char * drophint_msg
Definition: tablecmds.c:252
const char * nota_msg
Definition: tablecmds.c:251
Definition: type.h:95
Definition: c.h:717
Oid values[FLEXIBLE_ARRAY_MEMBER]
Definition: c.h:724
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:499
HeapTuple SearchSysCacheCopyAttNum(Oid relid, int16 attnum)
Definition: syscache.c:562
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:269
HeapTuple SearchSysCacheLocked1(int cacheId, Datum key1)
Definition: syscache.c:287
HeapTuple SearchSysCacheLockedCopy1(int cacheId, Datum key1)
Definition: syscache.c:400
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:221
HeapTuple SearchSysCacheAttNum(Oid relid, int16 attnum)
Definition: syscache.c:539
Datum SysCacheGetAttr(int cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition: syscache.c:596
bool SearchSysCacheExistsAttName(Oid relid, const char *attname)
Definition: syscache.c:518
HeapTuple SearchSysCache2(int cacheId, Datum key1, Datum key2)
Definition: syscache.c:232
HeapTuple SearchSysCacheAttName(Oid relid, const char *attname)
Definition: syscache.c:476
Datum SysCacheGetAttrNotNull(int cacheId, HeapTuple tup, AttrNumber attributeNumber)
Definition: syscache.c:627
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:91
#define SearchSysCacheExists2(cacheId, key1, key2)
Definition: syscache.h:102
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:126
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:40
Relation table_openrv(const RangeVar *relation, LOCKMODE lockmode)
Definition: table.c:83
const TupleTableSlotOps * table_slot_callbacks(Relation relation)
Definition: tableam.c:58
TableScanDesc table_beginscan_catalog(Relation relation, int nkeys, struct ScanKeyData *key)
Definition: tableam.c:112
char * default_table_access_method
Definition: tableam.c:48
TupleTableSlot * table_slot_create(Relation relation, List **reglist)
Definition: tableam.c:91
static TableScanDesc table_beginscan(Relation rel, Snapshot snapshot, int nkeys, struct ScanKeyData *key)
Definition: tableam.h:908
static void table_endscan(TableScanDesc scan)
Definition: tableam.h:1019
#define TABLE_INSERT_SKIP_FSM
Definition: tableam.h:260
static void table_finish_bulk_insert(Relation rel, int options)
Definition: tableam.h:1595
static void table_tuple_insert(Relation rel, TupleTableSlot *slot, CommandId cid, int options, struct BulkInsertStateData *bistate)
Definition: tableam.h:1402
static void table_relation_copy_data(Relation rel, const RelFileLocator *newrlocator)
Definition: tableam.h:1651
static bool table_scan_getnextslot(TableScanDesc sscan, ScanDirection direction, TupleTableSlot *slot)
Definition: tableam.h:1055
static AttrNumber renameatt_internal(Oid myrelid, const char *oldattname, const char *newattname, bool recurse, bool recursing, int expected_parents, DropBehavior behavior)
Definition: tablecmds.c:3707
void ResetRelRewrite(Oid myrelid)
Definition: tablecmds.c:4223
static void MergeAttributesIntoExisting(Relation child_rel, Relation parent_rel, bool ispartition)
Definition: tablecmds.c:15976
static ObjectAddress ATExecSetNotNull(AlteredTableInfo *tab, Relation rel, const char *colName, LOCKMODE lockmode)
Definition: tablecmds.c:7731
static void MarkInheritDetached(Relation child_rel, Relation parent_rel)
Definition: tablecmds.c:16264
static ObjectAddress ATExecAlterColumnGenericOptions(Relation rel, const char *colName, List *options, LOCKMODE lockmode)
Definition: tablecmds.c:14438
static void ATRewriteCatalogs(List **wqueue, LOCKMODE lockmode, AlterTableUtilityContext *context)
Definition: tablecmds.c:5171
static ObjectAddress ATExecAddInherit(Relation child_rel, RangeVar *parent, LOCKMODE lockmode)
Definition: tablecmds.c:15740
ObjectAddress RenameRelation(RenameStmt *stmt)
Definition: tablecmds.c:4066
static AlteredTableInfo * ATGetQueueEntry(List **wqueue, Relation rel)
Definition: tablecmds.c:6378
static void ATExecDropOf(Relation rel, LOCKMODE lockmode)
Definition: tablecmds.c:16709
static ColumnDef * MergeInheritedAttribute(List *inh_columns, int exist_attno, const ColumnDef *newdef)
Definition: tablecmds.c:3274
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:10493
#define ATT_TABLE
Definition: tablecmds.c:328
static bool ConstraintImpliedByRelConstraint(Relation scanrel, List *testConstraint, List *provenConstraint)
Definition: tablecmds.c:18441
static const char * storage_name(char c)
Definition: tablecmds.c:2386
static ObjectAddress ATExecDropExpression(Relation rel, const char *colName, bool missing_ok, LOCKMODE lockmode)
Definition: tablecmds.c:8491
void AtEOSubXact_on_commit_actions(bool isCommit, SubTransactionId mySubid, SubTransactionId parentSubid)
Definition: tablecmds.c:17804
static void add_column_datatype_dependency(Oid relid, int32 attnum, Oid typid)
Definition: tablecmds.c:7484
static ObjectAddress ATExecColumnDefault(Relation rel, const char *colName, Node *newDefault, LOCKMODE lockmode)
Definition: tablecmds.c:7880
static void ATPostAlterTypeParse(Oid oldId, Oid oldRelId, Oid refRelId, char *cmd, List **wqueue, LOCKMODE lockmode, bool rewrite)
Definition: tablecmds.c:14109
static void ATExecSetTableSpace(Oid tableOid, Oid newTableSpace, LOCKMODE lockmode)
Definition: tablecmds.c:15332
static void drop_parent_dependency(Oid relid, Oid refclassid, Oid refobjid, DependencyType deptype)
Definition: tablecmds.c:16515
static void RemoveInheritance(Relation child_rel, Relation parent_rel, bool expect_detached)
Definition: tablecmds.c:16347
#define AT_NUM_PASSES
Definition: tablecmds.c:166
void PreCommit_on_commit_actions(void)
Definition: tablecmds.c:17665
static void ATExecDropConstraint(Relation rel, const char *constrName, DropBehavior behavior, bool recurse, bool recursing, bool missing_ok, LOCKMODE lockmode)
Definition: tablecmds.c:12668
static ObjectAddress ATExecDropIdentity(Relation rel, const char *colName, bool missing_ok, LOCKMODE lockmode, bool recurse, bool recursing)
Definition: tablecmds.c:8218
static char GetAttributeCompression(Oid atttypid, const char *compression)
Definition: tablecmds.c:20303
static ObjectAddress ATExecDropNotNull(Relation rel, const char *colName, LOCKMODE lockmode)
Definition: tablecmds.c:7527
static int findAttrByName(const char *attributeName, const List *columns)
Definition: tablecmds.c:3473
static int transformFkeyGetPrimaryKey(Relation pkrel, Oid *indexOid, List **attnamelist, int16 *attnums, Oid *atttypids, Oid *opclasses, bool *pk_has_without_overlaps)
Definition: tablecmds.c:12037
static void RememberIndexForRebuilding(Oid indoid, AlteredTableInfo *tab)
Definition: tablecmds.c:13861
static bool ATColumnChangeRequiresRewrite(Node *expr, AttrNumber varattno)
Definition: tablecmds.c:13200
static char * ChooseForeignKeyConstraintNameAddition(List *colnames)
Definition: tablecmds.c:9401
static ObjectAddress ATExecValidateConstraint(List **wqueue, Relation rel, char *constrName, bool recurse, bool recursing, LOCKMODE lockmode)
Definition: tablecmds.c:11795
void AlterTable(AlterTableStmt *stmt, LOCKMODE lockmode, AlterTableUtilityContext *context)
Definition: tablecmds.c:4394
static void RememberStatisticsForRebuilding(Oid stxoid, AlteredTableInfo *tab)
Definition: tablecmds.c:13912
static CoercionPathType findFkeyCast(Oid targetTypeId, Oid sourceTypeId, Oid *funcid)
Definition: tablecmds.c:12290
static void add_column_collation_dependency(Oid relid, int32 attnum, Oid collid)
Definition: tablecmds.c:7502
static Oid transformFkeyCheckAttrs(Relation pkrel, int numattrs, int16 *attnums, bool with_period, Oid *opclasses, bool *pk_has_without_overlaps)
Definition: tablecmds.c:12139
#define ATT_SEQUENCE
Definition: tablecmds.c:335
void RemoveRelations(DropStmt *drop)
Definition: tablecmds.c:1463
static void ATPrepSetTableSpace(AlteredTableInfo *tab, Relation rel, const char *tablespacename, LOCKMODE lockmode)
Definition: tablecmds.c:15098
static void ATTypedTableRecursion(List **wqueue, Relation rel, AlterTableCmd *cmd, LOCKMODE lockmode, AlterTableUtilityContext *context)
Definition: tablecmds.c:6709
static void RememberReplicaIdentityForRebuilding(Oid indoid, AlteredTableInfo *tab)
Definition: tablecmds.c:13790
static List * MergeAttributes(List *columns, const List *supers, char relpersistence, bool is_partition, List **supconstr)
Definition: tablecmds.c:2465
static List * GetParentedForeignKeyRefs(Relation partition)
Definition: tablecmds.c:20201
void AlterRelationNamespaceInternal(Relation classRel, Oid relOid, Oid oldNspOid, Oid newNspOid, bool hasDependEntry, ObjectAddresses *objsMoved)
Definition: tablecmds.c:17399
static ObjectAddress ATExecAddConstraint(List **wqueue, AlteredTableInfo *tab, Relation rel, Constraint *newConstraint, bool recurse, bool is_readd, LOCKMODE lockmode)
Definition: tablecmds.c:9328
ObjectAddress renameatt(RenameStmt *stmt)
Definition: tablecmds.c:3872
void ATExecChangeOwner(Oid relationOid, Oid newOwnerId, bool recursing, LOCKMODE lockmode)
Definition: tablecmds.c:14555
static void RangeVarCallbackForAlterRelation(const RangeVar *rv, Oid relid, Oid oldrelid, void *arg)
Definition: tablecmds.c:17931
static void CheckAlterTableIsSafe(Relation rel)
Definition: tablecmds.c:4309
static void DropErrorMsgWrongType(const char *relname, char wrongkind, char rightkind)
Definition: tablecmds.c:1436
LOCKMODE AlterTableGetLockLevel(List *cmds)
Definition: tablecmds.c:4468
static int transformColumnNameList(Oid relId, List *colList, int16 *attnums, Oid *atttypids)
Definition: tablecmds.c:11984
struct ForeignTruncateInfo ForeignTruncateInfo
static ObjectAddress ATExecDetachPartition(List **wqueue, AlteredTableInfo *tab, Relation rel, RangeVar *name, bool concurrent)
Definition: tablecmds.c:19232
static bool ATExecAlterConstrRecurse(Constraint *cmdcon, Relation conrel, Relation tgrel, Relation rel, HeapTuple contuple, List **otherrelids, LOCKMODE lockmode)
Definition: tablecmds.c:11644
static void AlterSeqNamespaces(Relation classRel, Relation rel, Oid oldNspOid, Oid newNspOid, ObjectAddresses *objsMoved, LOCKMODE lockmode)
Definition: tablecmds.c:17521
static void RangeVarCallbackForRenameAttribute(const RangeVar *rv, Oid relid, Oid oldrelid, void *arg)
Definition: tablecmds.c:3852
TupleDesc BuildDescForRelation(const List *columns)
Definition: tablecmds.c:1307
static void ATExecForceNoForceRowSecurity(Relation rel, bool force_rls)
Definition: tablecmds.c:16979
void AtEOXact_on_commit_actions(bool isCommit)
Definition: tablecmds.c:17772
static void checkFkeyPermissions(Relation rel, int16 *attnums, int natts)
Definition: tablecmds.c:12319
struct OnCommitItem OnCommitItem
void CheckTableNotInUse(Relation rel, const char *stmt)
Definition: tablecmds.c:4276
static void ATExecEnableDisableTrigger(Relation rel, const char *trigname, char fires_when, bool skip_system, bool recurse, LOCKMODE lockmode)
Definition: tablecmds.c:15683
static void createForeignKeyActionTriggers(Relation rel, Oid refRelOid, Constraint *fkconstraint, Oid constraintOid, Oid indexOid, Oid parentDelTrigger, Oid parentUpdTrigger, Oid *deleteTrigOid, Oid *updateTrigOid)
Definition: tablecmds.c:12511
static void renameatt_check(Oid myrelid, Form_pg_class classform, bool recursing)
Definition: tablecmds.c:3658
static void RangeVarCallbackForAttachIndex(const RangeVar *rv, Oid relOid, Oid oldRelOid, void *arg)
Definition: tablecmds.c:19868
static void ATCheckPartitionsNotInUse(Relation rel, LOCKMODE lockmode)
Definition: tablecmds.c:6679
static void truncate_check_activity(Relation rel)
Definition: tablecmds.c:2363
static void validatePartitionedIndex(Relation partedIdx, Relation partedTbl)
Definition: tablecmds.c:20100
static ObjectAddress ATAddForeignKeyConstraint(List **wqueue, AlteredTableInfo *tab, Relation rel, Constraint *fkconstraint, bool recurse, bool recursing, LOCKMODE lockmode)
Definition: tablecmds.c:9581
static void TryReuseIndex(Oid oldId, IndexStmt *stmt)
Definition: tablecmds.c:14369
static void GetForeignKeyCheckTriggers(Relation trigrel, Oid conoid, Oid confrelid, Oid conrelid, Oid *insertTriggerOid, Oid *updateTriggerOid)
Definition: tablecmds.c:11440
static ObjectAddress addFkConstraint(addFkConstraintSides fkside, char *constraintname, 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 is_internal, bool with_period)
Definition: tablecmds.c:10187
static void ATPrepSetNotNull(List **wqueue, Relation rel, AlterTableCmd *cmd, bool recurse, bool recursing, LOCKMODE lockmode, AlterTableUtilityContext *context)
Definition: tablecmds.c:7662
static void RememberClusterOnForRebuilding(Oid indoid, AlteredTableInfo *tab)
Definition: tablecmds.c:13805
static ObjectAddress ATExecSetOptions(Relation rel, const char *colName, Node *options, bool isReset, LOCKMODE lockmode)
Definition: tablecmds.c:8717
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:8950
static void CloneFkReferencing(List **wqueue, Relation parentRel, Relation partRel)
Definition: tablecmds.c:10917
static void SetIndexStorageProperties(Relation rel, Relation attrelation, AttrNumber attnum, bool setstorage, char newstorage, bool setcompression, char newcompression, LOCKMODE lockmode)
Definition: tablecmds.c:8796
static void ATController(AlterTableStmt *parsetree, Relation rel, List *cmds, bool recurse, LOCKMODE lockmode, AlterTableUtilityContext *context)
Definition: tablecmds.c:4739
bool CheckRelationTableSpaceMove(Relation rel, Oid newTableSpaceId)
Definition: tablecmds.c:3556
static void ATExecSetRowSecurity(Relation rel, bool rls)
Definition: tablecmds.c:16949
static void ATExecCheckNotNull(AlteredTableInfo *tab, Relation rel, const char *colName, LOCKMODE lockmode)
Definition: tablecmds.c:7814
void find_composite_type_dependencies(Oid typeOid, Relation origRelation, const char *origTypeName)
Definition: tablecmds.c:6754
static void truncate_check_perms(Oid relid, Form_pg_class reltuple)
Definition: tablecmds.c:2345
static void truncate_check_rel(Oid relid, Form_pg_class reltuple)
Definition: tablecmds.c:2297
#define ATT_INDEX
Definition: tablecmds.c:331
static void change_owner_recurse_to_sequences(Oid relationOid, Oid newOwnerId, LOCKMODE lockmode)
Definition: tablecmds.c:14861
static void StoreCatalogInheritance1(Oid relationId, Oid parentOid, int32 seqNumber, Relation inhRelation, bool child_is_partition)
Definition: tablecmds.c:3428
static void RememberAllDependentForRebuilding(AlteredTableInfo *tab, AlterTableType subtype, Relation rel, AttrNumber attnum, const char *colName)
Definition: tablecmds.c:13564
static void ATPrepDropExpression(Relation rel, AlterTableCmd *cmd, bool recurse, bool recursing, LOCKMODE lockmode)
Definition: tablecmds.c:8445
static ObjectAddress ATExecCookedColumnDefault(Relation rel, AttrNumber attnum, Node *newDefault)
Definition: tablecmds.c:7966
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:3910
static void DropErrorMsgNonExistent(RangeVar *rel, char rightkind, bool missing_ok)
Definition: tablecmds.c:1388
static void ATPostAlterTypeCleanup(List **wqueue, AlteredTableInfo *tab, LOCKMODE lockmode)
Definition: tablecmds.c:13941
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:11161
static AlterTableCmd * ATParseTransformCmd(List **wqueue, AlteredTableInfo *tab, Relation rel, AlterTableCmd *cmd, bool recurse, LOCKMODE lockmode, AlterTablePass cur_pass, AlterTableUtilityContext *context)
Definition: tablecmds.c:5580
void AlterTableNamespaceInternal(Relation rel, Oid oldNspOid, Oid nspOid, ObjectAddresses *objsMoved)
Definition: tablecmds.c:17362
static void CloneFkReferenced(Relation parentRel, Relation partitionRel)
Definition: tablecmds.c:10702
static void MergeConstraintsIntoExisting(Relation child_rel, Relation parent_rel)
Definition: tablecmds.c:16096
static void ATPrepDropColumn(List **wqueue, Relation rel, bool recurse, bool recursing, AlterTableCmd *cmd, LOCKMODE lockmode, AlterTableUtilityContext *context)
Definition: tablecmds.c:8922
void SetRelationHasSubclass(Oid relationId, bool relhassubclass)
Definition: tablecmds.c:3510
static void MergeChildAttribute(List *inh_columns, int exist_attno, int newcol_attno, const ColumnDef *newdef)
Definition: tablecmds.c:3113
static void ATSimplePermissions(AlterTableType cmdtype, Relation rel, int allowed_targets)
Definition: tablecmds.c:6557
static List * MergeCheckConstraint(List *constraints, const char *name, Node *expr)
Definition: tablecmds.c:3047
static void ATExecSetRelOptions(Relation rel, List *defList, AlterTableType operation, LOCKMODE lockmode)
Definition: tablecmds.c:15128
static ObjectAddress ATExecSetIdentity(Relation rel, const char *colName, Node *def, LOCKMODE lockmode, bool recurse, bool recursing)
Definition: tablecmds.c:8101
ObjectAddress AlterTableNamespace(AlterObjectSchemaStmt *stmt, Oid *oldschema)
Definition: tablecmds.c:17291
static void RememberConstraintForRebuilding(Oid conoid, AlteredTableInfo *tab)
Definition: tablecmds.c:13821
addFkConstraintSides
Definition: tablecmds.c:354
@ addFkReferencingSide
Definition: tablecmds.c:356
@ addFkBothSides
Definition: tablecmds.c:357
@ addFkReferencedSide
Definition: tablecmds.c:355
void ExecuteTruncate(TruncateStmt *stmt)
Definition: tablecmds.c:1786
static void relation_mark_replica_identity(Relation rel, char ri_type, Oid indexOid, bool is_internal)
Definition: tablecmds.c:16753
#define ATT_FOREIGN_TABLE
Definition: tablecmds.c:333
static ObjectAddress ATExecAlterConstraint(Relation rel, AlterTableCmd *cmd, bool recurse, bool recursing, LOCKMODE lockmode)
Definition: tablecmds.c:11506
static void ATPrepAddColumn(List **wqueue, Relation rel, bool recurse, bool recursing, bool is_view, AlterTableCmd *cmd, LOCKMODE lockmode, AlterTableUtilityContext *context)
Definition: tablecmds.c:7011
static void ComputePartitionAttrs(ParseState *pstate, Relation rel, List *partParams, AttrNumber *partattrs, List **partexprs, Oid *partopclass, Oid *partcollation, PartitionStrategy strategy)
Definition: tablecmds.c:18130
static void CloneRowTriggersToPartition(Relation parent, Relation partition)
Definition: tablecmds.c:19075
static void AttachPartitionEnsureIndexes(List **wqueue, Relation rel, Relation attachrel)
Definition: tablecmds.c:18894
static void StoreCatalogInheritance(Oid relationId, List *supers, bool child_is_partition)
Definition: tablecmds.c:3384
static ObjectAddress ATAddCheckConstraint(List **wqueue, AlteredTableInfo *tab, Relation rel, Constraint *constr, bool recurse, bool recursing, bool is_readd, LOCKMODE lockmode)
Definition: tablecmds.c:9443
static void ATExecGenericOptions(Relation rel, List *options)
Definition: tablecmds.c:17008
static void TryReuseForeignKey(Oid oldId, Constraint *con)
Definition: tablecmds.c:14398
struct AlteredTableInfo AlteredTableInfo
static void validateFkOnDeleteSetColumns(int numfks, const int16 *fkattnums, int numfksetcols, const int16 *fksetcolsattnums, List *fksetcols)
Definition: tablecmds.c:10128
Oid AlterTableLookupRelation(AlterTableStmt *stmt, LOCKMODE lockmode)
Definition: tablecmds.c:4335
struct NewConstraint NewConstraint
static ObjectAddress ATExecSetStatistics(Relation rel, const char *colName, int16 colNum, Node *newValue, LOCKMODE lockmode)
Definition: tablecmds.c:8582
static void ATSimpleRecursion(List **wqueue, Relation rel, AlterTableCmd *cmd, bool recurse, LOCKMODE lockmode, AlterTableUtilityContext *context)
Definition: tablecmds.c:6634
static void DetachPartitionFinalize(Relation rel, Relation partRel, bool concurrent, Oid defaultPartOid)
Definition: tablecmds.c:19403
static void RebuildConstraintComment(AlteredTableInfo *tab, AlterTablePass pass, Oid objid, Relation rel, List *domname, const char *conname)
Definition: tablecmds.c:14325
static void CloneForeignKeyConstraints(List **wqueue, Relation parentRel, Relation partitionRel)
Definition: tablecmds.c:10671
static void addFkRecurseReferenced(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:10362
static bool check_for_column_name_collision(Relation rel, const char *colname, bool if_not_exists)
Definition: tablecmds.c:7431
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:7035
AlterTablePass
Definition: tablecmds.c:149
@ AT_PASS_ADD_CONSTR
Definition: tablecmds.c:158
@ AT_PASS_ADD_OTHERCONSTR
Definition: tablecmds.c:162
@ AT_PASS_OLD_CONSTR
Definition: tablecmds.c:156
@ AT_PASS_ADD_COL
Definition: tablecmds.c:153
@ AT_PASS_OLD_INDEX
Definition: tablecmds.c:155
@ AT_PASS_ALTER_TYPE
Definition: tablecmds.c:152
@ AT_PASS_ADD_INDEXCONSTR
Definition: tablecmds.c:160
@ AT_PASS_DROP
Definition: tablecmds.c:151
@ AT_PASS_MISC
Definition: tablecmds.c:163
@ AT_PASS_COL_ATTRS
Definition: tablecmds.c:159
@ AT_PASS_SET_EXPRESSION
Definition: tablecmds.c:154
@ AT_PASS_ADD_INDEX
Definition: tablecmds.c:161
@ AT_PASS_UNSET
Definition: tablecmds.c:150
static ObjectAddress ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel, AlterTableCmd *cmd, LOCKMODE lockmode)
Definition: tablecmds.c:13247
static void validateForeignKeyConstraint(char *conname, Relation rel, Relation pkrel, Oid pkindOid, Oid constraintOid, bool hasperiod)
Definition: tablecmds.c:12348
void SetRelationTableSpace(Relation rel, Oid newTableSpaceId, RelFileNumber newRelFilenumber)
Definition: tablecmds.c:3613
void remove_on_commit_action(Oid relid)
Definition: tablecmds.c:17642
static void DetachAddConstraintIfNeeded(List **wqueue, Relation partRel)
Definition: tablecmds.c:19754
static void ATExecDropCluster(Relation rel, LOCKMODE lockmode)
Definition: tablecmds.c:14962
#define ATT_PARTITIONED_INDEX
Definition: tablecmds.c:334
static void CreateInheritance(Relation child_rel, Relation parent_rel, bool ispartition)
Definition: tablecmds.c:15853
static const struct dropmsgstrings dropmsgstringarray[]
Definition: tablecmds.c:255
static void ATPrepChangePersistence(AlteredTableInfo *tab, Relation rel, bool toLogged)
Definition: tablecmds.c:17166
static ObjectAddress ATExecSetExpression(AlteredTableInfo *tab, Relation rel, const char *colName, Node *newExpr, LOCKMODE lockmode)
Definition: tablecmds.c:8332
ObjectAddress DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId, ObjectAddress *typaddress, const char *queryString)
Definition: tablecmds.c:706
static Oid CreateFKCheckTrigger(Oid myRelOid, Oid refRelOid, Constraint *fkconstraint, Oid constraintOid, Oid indexOid, Oid parentTrigOid, bool on_insert)
Definition: tablecmds.c:12448
static void DropClonedTriggersFromPartition(Oid partitionId)
Definition: tablecmds.c:19795
static void QueuePartitionConstraintValidation(List **wqueue, Relation scanrel, List *partConstraint, bool validate_default)
Definition: tablecmds.c:18498
static ObjectAddress ATExecAddOf(Relation rel, const TypeName *ofTypename, LOCKMODE lockmode)
Definition: tablecmds.c:16567
static void RangeVarCallbackForDropRelation(const RangeVar *rel, Oid relOid, Oid oldRelOid, void *arg)
Definition: tablecmds.c:1627
void AlterTableInternal(Oid relid, List *cmds, bool recurse)
Definition: tablecmds.c:4423
static void GetForeignKeyActionTriggers(Relation trigrel, Oid conoid, Oid confrelid, Oid conrelid, Oid *deleteTriggerOid, Oid *updateTriggerOid)
Definition: tablecmds.c:11379
void check_of_type(HeapTuple typetuple)
Definition: tablecmds.c:6961
static ObjectAddress ATExecDropInherit(Relation rel, RangeVar *parent, LOCKMODE lockmode)
Definition: tablecmds.c:16222
static void ATDetachCheckNoForeignKeyRefs(Relation partition)
Definition: tablecmds.c:20254
static ObjectAddress ATExecAddIndexConstraint(AlteredTableInfo *tab, Relation rel, IndexStmt *stmt, LOCKMODE lockmode)
Definition: tablecmds.c:9236
#define ATT_VIEW
Definition: tablecmds.c:329
static void AlterIndexNamespaces(Relation classRel, Relation rel, Oid oldNspOid, Oid newNspOid, ObjectAddresses *objsMoved)
Definition: tablecmds.c:17476
#define ATT_PARTITIONED_TABLE
Definition: tablecmds.c:336
static char * decompile_conbin(HeapTuple contup, TupleDesc tupdesc)
Definition: tablecmds.c:15922
static void ATExecCmd(List **wqueue, AlteredTableInfo *tab, AlterTableCmd *cmd, LOCKMODE lockmode, AlterTablePass cur_pass, AlterTableUtilityContext *context)
Definition: tablecmds.c:5245
static void ATExecReplicaIdentity(Relation rel, ReplicaIdentityStmt *stmt, LOCKMODE lockmode)
Definition: tablecmds.c:16841
static void createForeignKeyCheckTriggers(Oid myRelOid, Oid refRelOid, Constraint *fkconstraint, Oid constraintOid, Oid indexOid, Oid parentInsTrigger, Oid parentUpdTrigger, Oid *insertTrigOid, Oid *updateTrigOid)
Definition: tablecmds.c:12648
static void ATPrepAddInherit(Relation child_rel)
Definition: tablecmds.c:15718
static ObjectAddress ATExecDetachPartitionFinalize(Relation rel, RangeVar *name)
Definition: tablecmds.c:19719
static ObjectAddress ATExecSetStorage(Relation rel, const char *colName, Node *newValue, LOCKMODE lockmode)
Definition: tablecmds.c:8859
static ObjectAddress ATExecAttachPartition(List **wqueue, Relation rel, PartitionCmd *cmd, AlterTableUtilityContext *context)
Definition: tablecmds.c:18571
static List * find_typed_table_dependencies(Oid typeOid, const char *typeName, DropBehavior behavior)
Definition: tablecmds.c:6912
Oid AlterTableMoveAll(AlterTableMoveAllStmt *stmt)
Definition: tablecmds.c:15464
static ObjectAddress ATExecAddIdentity(Relation rel, const char *colName, Node *def, LOCKMODE lockmode, bool recurse, bool recursing)
Definition: tablecmds.c:7995
static void ATExecSetAccessMethodNoStorage(Relation rel, Oid newAccessMethodId)
Definition: tablecmds.c:15008
static ObjectAddress ATExecAddIndex(AlteredTableInfo *tab, Relation rel, IndexStmt *stmt, bool is_rebuild, LOCKMODE lockmode)
Definition: tablecmds.c:9152
static ObjectAddress ATExecSetCompression(Relation rel, const char *column, Node *newValue, LOCKMODE lockmode)
Definition: tablecmds.c:17089
static PartitionSpec * transformPartitionSpec(Relation rel, PartitionSpec *partspec)
Definition: tablecmds.c:18072
static void ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd, bool recurse, bool recursing, LOCKMODE lockmode, AlterTableUtilityContext *context)
Definition: tablecmds.c:4774
static void ATRewriteTable(AlteredTableInfo *tab, Oid OIDNewHeap, LOCKMODE lockmode)
Definition: tablecmds.c:6002
static void index_copy_data(Relation rel, RelFileLocator newrlocator)
Definition: tablecmds.c:15626
void RenameRelationInternal(Oid myrelid, const char *newrelname, bool is_internal, bool is_index)
Definition: tablecmds.c:4130
static void ATExecSetTableSpaceNoStorage(Relation rel, Oid newTableSpace)
Definition: tablecmds.c:15425
static void ATPrepAlterColumnType(List **wqueue, AlteredTableInfo *tab, Relation rel, bool recurse, bool recursing, AlterTableCmd *cmd, LOCKMODE lockmode, AlterTableUtilityContext *context)
Definition: tablecmds.c:12908
static void change_owner_fix_column_acls(Oid relationOid, Oid oldOwnerId, Oid newOwnerId)
Definition: tablecmds.c:14796
#define ATT_COMPOSITE_TYPE
Definition: tablecmds.c:332
static ObjectAddress ATExecAttachPartitionIdx(List **wqueue, Relation parentIdx, RangeVar *name)
Definition: tablecmds.c:19922
bool PartConstraintImpliedByRelConstraint(Relation scanrel, List *partConstraint)
Definition: tablecmds.c:18388
void RangeVarCallbackMaintainsTable(const RangeVar *relation, Oid relId, Oid oldRelId, void *arg)
Definition: tablecmds.c:17839
static const char * alter_table_type_to_string(AlterTableType cmdtype)
Definition: tablecmds.c:6412
static List * on_commits
Definition: tablecmds.c:131
static bool constraints_equivalent(HeapTuple a, HeapTuple b, TupleDesc tupleDesc)
Definition: tablecmds.c:15947
static ObjectAddress ATExecAddStatistics(AlteredTableInfo *tab, Relation rel, CreateStatsStmt *stmt, bool is_rebuild, LOCKMODE lockmode)
Definition: tablecmds.c:9215
ObjectAddress RenameConstraint(RenameStmt *stmt)
Definition: tablecmds.c:4016
static void ATRewriteTables(AlterTableStmt *parsetree, List **wqueue, LOCKMODE lockmode, AlterTableUtilityContext *context)
Definition: tablecmds.c:5715
void register_on_commit_action(Oid relid, OnCommitAction action)
Definition: tablecmds.c:17606
static void RangeVarCallbackForTruncate(const RangeVar *relation, Oid relId, Oid oldRelId, void *arg)
Definition: tablecmds.c:17875
static ObjectAddress ATExecClusterOn(Relation rel, const char *indexName, LOCKMODE lockmode)
Definition: tablecmds.c:14930
static char GetAttributeStorage(Oid atttypid, const char *storagemode)
Definition: tablecmds.c:20341
void RangeVarCallbackOwnsRelation(const RangeVar *relation, Oid relId, Oid oldRelId, void *arg)
Definition: tablecmds.c:17899
#define ATT_MATVIEW
Definition: tablecmds.c:330
#define child_dependency_type(child_is_partition)
Definition: tablecmds.c:365
static void refuseDupeIndexAttach(Relation parentIdx, Relation partIdx, Relation partitionTbl)
Definition: tablecmds.c:20077
void ExecuteTruncateGuts(List *explicit_rels, List *relids, List *relids_logged, DropBehavior behavior, bool restart_seqs, bool run_as_table_owner)
Definition: tablecmds.c:1910
static void ATExecEnableDisableRule(Relation rel, const char *rulename, char fires_when, LOCKMODE lockmode)
Definition: tablecmds.c:15701
struct NewColumnValue NewColumnValue
static void ATPrepSetAccessMethod(AlteredTableInfo *tab, Relation rel, const char *amname)
Definition: tablecmds.c:14974
static bool NotNullImpliedByRelConstraints(Relation rel, Form_pg_attribute attr)
Definition: tablecmds.c:7843
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:58
void ExecBSTruncateTriggers(EState *estate, ResultRelInfo *relinfo)
Definition: trigger.c:3223
void EnableDisableTrigger(Relation rel, const char *tgname, Oid tgparent, char fires_when, bool skip_system, bool recurse, LOCKMODE lockmode)
Definition: trigger.c:1722
void ExecASTruncateTriggers(EState *estate, ResultRelInfo *relinfo)
Definition: trigger.c:3270
const char * FindTriggerIncompatibleWithInheritance(TriggerDesc *trigdesc)
Definition: trigger.c:2273
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:5980
void AfterTriggerEndQuery(EState *estate)
Definition: trigger.c:5044
void AfterTriggerBeginQuery(void)
Definition: trigger.c:5024
#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
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:1850
bool DomainHasConstraints(Oid type_id)
Definition: typcache.c:1417
void AlterTypeOwnerInternal(Oid typeOid, Oid newOwnerId)
Definition: typecmds.c:3989
ObjectAddress AlterDomainAddConstraint(List *names, Node *newConstraint, ObjectAddress *constrAddr)
Definition: typecmds.c:2897
void checkDomainOwner(HeapTuple tup)
Definition: typecmds.c:3490
Oid AlterTypeNamespaceInternal(Oid typeOid, Oid nspOid, bool isImplicitArray, bool ignoreDependent, bool errorOnTableType, ObjectAddresses *objsMoved)
Definition: typecmds.c:4158
List * roleSpecsToIds(List *memberNames)
Definition: user.c:1652
void SwitchToUntrustedUser(Oid userid, UserContext *context)
Definition: usercontext.c:33
void RestoreUserContext(UserContext *context)
Definition: usercontext.c:87
void ProcessUtilityForAlterTable(Node *stmt, AlterTableUtilityContext *context)
Definition: utility.c:1956
#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:296
#define VARDATA_ANY(PTR)
Definition: varatt.h:324
const char * name
SubTransactionId GetCurrentSubTransactionId(void)
Definition: xact.c:790
void CommandCounterIncrement(void)
Definition: xact.c:1099
void StartTransactionCommand(void)
Definition: xact.c:3039
void CommitTransactionCommand(void)
Definition: xact.c:3137
int MyXactFlags
Definition: xact.c:135
CommandId GetCurrentCommandId(bool used)
Definition: xact.c:828
#define XACT_FLAGS_ACCESSEDTEMPNAMESPACE
Definition: xact.h:102
#define XLogLogicalInfoActive()
Definition: xlog.h:126
#define XLOG_INCLUDE_ORIGIN
Definition: xlog.h:154
XLogRecPtr XLogInsert(RmgrId rmid, uint8 info)
Definition: xloginsert.c:474
void XLogSetRecordFlags(uint8 flags)
Definition: xloginsert.c:456
void XLogRegisterData(const char *data, uint32 len)
Definition: xloginsert.c:364
void XLogBeginInsert(void)
Definition: xloginsert.c:149