PostgreSQL Source Code  git master
tablecmds.c
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------
2  *
3  * tablecmds.c
4  * Commands for creating and altering table structures and settings
5  *
6  * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  *
10  * IDENTIFICATION
11  * src/backend/commands/tablecmds.c
12  *
13  *-------------------------------------------------------------------------
14  */
15 #include "postgres.h"
16 
17 #include "access/attmap.h"
18 #include "access/genam.h"
19 #include "access/heapam.h"
20 #include "access/heapam_xlog.h"
21 #include "access/multixact.h"
22 #include "access/reloptions.h"
23 #include "access/relscan.h"
24 #include "access/sysattr.h"
25 #include "access/tableam.h"
27 #include "access/xact.h"
28 #include "access/xlog.h"
29 #include "access/xloginsert.h"
30 #include "catalog/catalog.h"
31 #include "catalog/heap.h"
32 #include "catalog/index.h"
33 #include "catalog/namespace.h"
34 #include "catalog/objectaccess.h"
35 #include "catalog/partition.h"
36 #include "catalog/pg_am.h"
37 #include "catalog/pg_attrdef.h"
38 #include "catalog/pg_collation.h"
39 #include "catalog/pg_constraint.h"
40 #include "catalog/pg_depend.h"
42 #include "catalog/pg_inherits.h"
43 #include "catalog/pg_largeobject.h"
44 #include "catalog/pg_namespace.h"
45 #include "catalog/pg_opclass.h"
47 #include "catalog/pg_tablespace.h"
48 #include "catalog/pg_trigger.h"
49 #include "catalog/pg_type.h"
50 #include "catalog/storage.h"
51 #include "catalog/storage_xlog.h"
52 #include "catalog/toasting.h"
53 #include "commands/cluster.h"
54 #include "commands/comment.h"
55 #include "commands/defrem.h"
56 #include "commands/event_trigger.h"
57 #include "commands/sequence.h"
58 #include "commands/tablecmds.h"
59 #include "commands/tablespace.h"
60 #include "commands/trigger.h"
61 #include "commands/typecmds.h"
62 #include "commands/user.h"
63 #include "commands/vacuum.h"
64 #include "executor/executor.h"
65 #include "foreign/fdwapi.h"
66 #include "foreign/foreign.h"
67 #include "miscadmin.h"
68 #include "nodes/makefuncs.h"
69 #include "nodes/nodeFuncs.h"
70 #include "nodes/parsenodes.h"
71 #include "optimizer/optimizer.h"
72 #include "parser/parse_coerce.h"
73 #include "parser/parse_collate.h"
74 #include "parser/parse_expr.h"
75 #include "parser/parse_relation.h"
76 #include "parser/parse_type.h"
77 #include "parser/parse_utilcmd.h"
78 #include "parser/parser.h"
80 #include "partitioning/partdesc.h"
81 #include "pgstat.h"
82 #include "rewrite/rewriteDefine.h"
83 #include "rewrite/rewriteHandler.h"
84 #include "rewrite/rewriteManip.h"
85 #include "storage/bufmgr.h"
86 #include "storage/lmgr.h"
87 #include "storage/lock.h"
88 #include "storage/predicate.h"
89 #include "storage/smgr.h"
90 #include "tcop/utility.h"
91 #include "utils/acl.h"
92 #include "utils/builtins.h"
93 #include "utils/fmgroids.h"
94 #include "utils/inval.h"
95 #include "utils/lsyscache.h"
96 #include "utils/memutils.h"
97 #include "utils/partcache.h"
98 #include "utils/relcache.h"
99 #include "utils/ruleutils.h"
100 #include "utils/snapmgr.h"
101 #include "utils/syscache.h"
102 #include "utils/timestamp.h"
103 #include "utils/typcache.h"
104 #include "utils/usercontext.h"
105 
106 /*
107  * ON COMMIT action list
108  */
109 typedef struct OnCommitItem
110 {
111  Oid relid; /* relid of relation */
112  OnCommitAction oncommit; /* what to do at end of xact */
113 
114  /*
115  * If this entry was created during the current transaction,
116  * creating_subid is the ID of the creating subxact; if created in a prior
117  * transaction, creating_subid is zero. If deleted during the current
118  * transaction, deleting_subid is the ID of the deleting subxact; if no
119  * deletion request is pending, deleting_subid is zero.
120  */
124 
125 static List *on_commits = NIL;
126 
127 
128 /*
129  * State information for ALTER TABLE
130  *
131  * The pending-work queue for an ALTER TABLE is a List of AlteredTableInfo
132  * structs, one for each table modified by the operation (the named table
133  * plus any child tables that are affected). We save lists of subcommands
134  * to apply to this table (possibly modified by parse transformation steps);
135  * these lists will be executed in Phase 2. If a Phase 3 step is needed,
136  * necessary information is stored in the constraints and newvals lists.
137  *
138  * Phase 2 is divided into multiple passes; subcommands are executed in
139  * a pass determined by subcommand type.
140  */
141 
142 typedef enum AlterTablePass
143 {
144  AT_PASS_UNSET = -1, /* UNSET will cause ERROR */
145  AT_PASS_DROP, /* DROP (all flavors) */
146  AT_PASS_ALTER_TYPE, /* ALTER COLUMN TYPE */
147  AT_PASS_ADD_COL, /* ADD COLUMN */
148  AT_PASS_SET_EXPRESSION, /* ALTER SET EXPRESSION */
149  AT_PASS_OLD_INDEX, /* re-add existing indexes */
150  AT_PASS_OLD_CONSTR, /* re-add existing constraints */
151  /* We could support a RENAME COLUMN pass here, but not currently used */
152  AT_PASS_ADD_CONSTR, /* ADD constraints (initial examination) */
153  AT_PASS_COL_ATTRS, /* set column attributes, eg NOT NULL */
154  AT_PASS_ADD_INDEXCONSTR, /* ADD index-based constraints */
155  AT_PASS_ADD_INDEX, /* ADD indexes */
156  AT_PASS_ADD_OTHERCONSTR, /* ADD other constraints, defaults */
157  AT_PASS_MISC, /* other stuff */
159 
160 #define AT_NUM_PASSES (AT_PASS_MISC + 1)
161 
162 typedef struct AlteredTableInfo
163 {
164  /* Information saved before any work commences: */
165  Oid relid; /* Relation to work on */
166  char relkind; /* Its relkind */
167  TupleDesc oldDesc; /* Pre-modification tuple descriptor */
168 
169  /*
170  * Transiently set during Phase 2, normally set to NULL.
171  *
172  * ATRewriteCatalogs sets this when it starts, and closes when ATExecCmd
173  * returns control. This can be exploited by ATExecCmd subroutines to
174  * close/reopen across transaction boundaries.
175  */
177 
178  /* Information saved by Phase 1 for Phase 2: */
179  List *subcmds[AT_NUM_PASSES]; /* Lists of AlterTableCmd */
180  /* Information saved by Phases 1/2 for Phase 3: */
181  List *constraints; /* List of NewConstraint */
182  List *newvals; /* List of NewColumnValue */
183  List *afterStmts; /* List of utility command parsetrees */
184  bool verify_new_notnull; /* T if we should recheck NOT NULL */
185  int rewrite; /* Reason for forced rewrite, if any */
186  Oid newAccessMethod; /* new access method; 0 means no change */
187  Oid newTableSpace; /* new tablespace; 0 means no change */
188  bool chgPersistence; /* T if SET LOGGED/UNLOGGED is used */
189  char newrelpersistence; /* if above is true */
190  Expr *partition_constraint; /* for attach partition validation */
191  /* true, if validating default due to some other attach/detach */
193  /* Objects to rebuild after completing ALTER TYPE operations */
194  List *changedConstraintOids; /* OIDs of constraints to rebuild */
195  List *changedConstraintDefs; /* string definitions of same */
196  List *changedIndexOids; /* OIDs of indexes to rebuild */
197  List *changedIndexDefs; /* string definitions of same */
198  char *replicaIdentityIndex; /* index to reset as REPLICA IDENTITY */
199  char *clusterOnIndex; /* index to use for CLUSTER */
200  List *changedStatisticsOids; /* OIDs of statistics to rebuild */
201  List *changedStatisticsDefs; /* string definitions of same */
203 
204 /* Struct describing one new constraint to check in Phase 3 scan */
205 /* Note: new not-null constraints are handled elsewhere */
206 typedef struct NewConstraint
207 {
208  char *name; /* Constraint name, or NULL if none */
209  ConstrType contype; /* CHECK or FOREIGN */
210  Oid refrelid; /* PK rel, if FOREIGN */
211  Oid refindid; /* OID of PK's index, if FOREIGN */
212  Oid conid; /* OID of pg_constraint entry, if FOREIGN */
213  Node *qual; /* Check expr or CONSTR_FOREIGN Constraint */
214  ExprState *qualstate; /* Execution state for CHECK expr */
216 
217 /*
218  * Struct describing one new column value that needs to be computed during
219  * Phase 3 copy (this could be either a new column with a non-null default, or
220  * a column that we're changing the type of). Columns without such an entry
221  * are just copied from the old table during ATRewriteTable. Note that the
222  * expr is an expression over *old* table values, except when is_generated
223  * is true; then it is an expression over columns of the *new* tuple.
224  */
225 typedef struct NewColumnValue
226 {
227  AttrNumber attnum; /* which column */
228  Expr *expr; /* expression to compute */
229  ExprState *exprstate; /* execution state */
230  bool is_generated; /* is it a GENERATED expression? */
232 
233 /*
234  * Error-reporting support for RemoveRelations
235  */
237 {
238  char kind;
240  const char *nonexistent_msg;
241  const char *skipping_msg;
242  const char *nota_msg;
243  const char *drophint_msg;
244 };
245 
246 static const struct dropmsgstrings dropmsgstringarray[] = {
247  {RELKIND_RELATION,
249  gettext_noop("table \"%s\" does not exist"),
250  gettext_noop("table \"%s\" does not exist, skipping"),
251  gettext_noop("\"%s\" is not a table"),
252  gettext_noop("Use DROP TABLE to remove a table.")},
253  {RELKIND_SEQUENCE,
255  gettext_noop("sequence \"%s\" does not exist"),
256  gettext_noop("sequence \"%s\" does not exist, skipping"),
257  gettext_noop("\"%s\" is not a sequence"),
258  gettext_noop("Use DROP SEQUENCE to remove a sequence.")},
259  {RELKIND_VIEW,
261  gettext_noop("view \"%s\" does not exist"),
262  gettext_noop("view \"%s\" does not exist, skipping"),
263  gettext_noop("\"%s\" is not a view"),
264  gettext_noop("Use DROP VIEW to remove a view.")},
265  {RELKIND_MATVIEW,
267  gettext_noop("materialized view \"%s\" does not exist"),
268  gettext_noop("materialized view \"%s\" does not exist, skipping"),
269  gettext_noop("\"%s\" is not a materialized view"),
270  gettext_noop("Use DROP MATERIALIZED VIEW to remove a materialized view.")},
271  {RELKIND_INDEX,
272  ERRCODE_UNDEFINED_OBJECT,
273  gettext_noop("index \"%s\" does not exist"),
274  gettext_noop("index \"%s\" does not exist, skipping"),
275  gettext_noop("\"%s\" is not an index"),
276  gettext_noop("Use DROP INDEX to remove an index.")},
277  {RELKIND_COMPOSITE_TYPE,
278  ERRCODE_UNDEFINED_OBJECT,
279  gettext_noop("type \"%s\" does not exist"),
280  gettext_noop("type \"%s\" does not exist, skipping"),
281  gettext_noop("\"%s\" is not a type"),
282  gettext_noop("Use DROP TYPE to remove a type.")},
283  {RELKIND_FOREIGN_TABLE,
284  ERRCODE_UNDEFINED_OBJECT,
285  gettext_noop("foreign table \"%s\" does not exist"),
286  gettext_noop("foreign table \"%s\" does not exist, skipping"),
287  gettext_noop("\"%s\" is not a foreign table"),
288  gettext_noop("Use DROP FOREIGN TABLE to remove a foreign table.")},
289  {RELKIND_PARTITIONED_TABLE,
291  gettext_noop("table \"%s\" does not exist"),
292  gettext_noop("table \"%s\" does not exist, skipping"),
293  gettext_noop("\"%s\" is not a table"),
294  gettext_noop("Use DROP TABLE to remove a table.")},
295  {RELKIND_PARTITIONED_INDEX,
296  ERRCODE_UNDEFINED_OBJECT,
297  gettext_noop("index \"%s\" does not exist"),
298  gettext_noop("index \"%s\" does not exist, skipping"),
299  gettext_noop("\"%s\" is not an index"),
300  gettext_noop("Use DROP INDEX to remove an index.")},
301  {'\0', 0, NULL, NULL, NULL, NULL}
302 };
303 
304 /* communication between RemoveRelations and RangeVarCallbackForDropRelation */
306 {
307  /* These fields are set by RemoveRelations: */
310  /* These fields are state to track which subsidiary locks are held: */
313  /* These fields are passed back by RangeVarCallbackForDropRelation: */
316 };
317 
318 /* Alter table target-type flags for ATSimplePermissions */
319 #define ATT_TABLE 0x0001
320 #define ATT_VIEW 0x0002
321 #define ATT_MATVIEW 0x0004
322 #define ATT_INDEX 0x0008
323 #define ATT_COMPOSITE_TYPE 0x0010
324 #define ATT_FOREIGN_TABLE 0x0020
325 #define ATT_PARTITIONED_INDEX 0x0040
326 #define ATT_SEQUENCE 0x0080
327 
328 /*
329  * ForeignTruncateInfo
330  *
331  * Information related to truncation of foreign tables. This is used for
332  * the elements in a hash table. It uses the server OID as lookup key,
333  * and includes a per-server list of all foreign tables involved in the
334  * truncation.
335  */
336 typedef struct ForeignTruncateInfo
337 {
341 
342 /*
343  * Partition tables are expected to be dropped when the parent partitioned
344  * table gets dropped. Hence for partitioning we use AUTO dependency.
345  * Otherwise, for regular inheritance use NORMAL dependency.
346  */
347 #define child_dependency_type(child_is_partition) \
348  ((child_is_partition) ? DEPENDENCY_AUTO : DEPENDENCY_NORMAL)
349 
350 static void truncate_check_rel(Oid relid, Form_pg_class reltuple);
351 static void truncate_check_perms(Oid relid, Form_pg_class reltuple);
352 static void truncate_check_activity(Relation rel);
353 static void RangeVarCallbackForTruncate(const RangeVar *relation,
354  Oid relId, Oid oldRelId, void *arg);
355 static List *MergeAttributes(List *columns, const List *supers, char relpersistence,
356  bool is_partition, List **supconstr,
357  List **supnotnulls);
358 static List *MergeCheckConstraint(List *constraints, const char *name, Node *expr);
359 static void MergeChildAttribute(List *inh_columns, int exist_attno, int newcol_attno, const ColumnDef *newdef);
360 static ColumnDef *MergeInheritedAttribute(List *inh_columns, int exist_attno, const ColumnDef *newdef);
361 static void MergeAttributesIntoExisting(Relation child_rel, Relation parent_rel, bool ispartition);
362 static void MergeConstraintsIntoExisting(Relation child_rel, Relation parent_rel);
363 static void StoreCatalogInheritance(Oid relationId, List *supers,
364  bool child_is_partition);
365 static void StoreCatalogInheritance1(Oid relationId, Oid parentOid,
366  int32 seqNumber, Relation inhRelation,
367  bool child_is_partition);
368 static int findAttrByName(const char *attributeName, const List *columns);
369 static void AlterIndexNamespaces(Relation classRel, Relation rel,
370  Oid oldNspOid, Oid newNspOid, ObjectAddresses *objsMoved);
371 static void AlterSeqNamespaces(Relation classRel, Relation rel,
372  Oid oldNspOid, Oid newNspOid, ObjectAddresses *objsMoved,
373  LOCKMODE lockmode);
375  bool recurse, bool recursing, LOCKMODE lockmode);
376 static bool ATExecAlterConstrRecurse(Constraint *cmdcon, Relation conrel, Relation tgrel,
377  Relation rel, HeapTuple contuple, List **otherrelids,
378  LOCKMODE lockmode);
380  Relation rel, char *constrName,
381  bool recurse, bool recursing, LOCKMODE lockmode);
382 static int transformColumnNameList(Oid relId, List *colList,
383  int16 *attnums, Oid *atttypids);
384 static int transformFkeyGetPrimaryKey(Relation pkrel, Oid *indexOid,
385  List **attnamelist,
386  int16 *attnums, Oid *atttypids,
387  Oid *opclasses);
389  int numattrs, int16 *attnums,
390  Oid *opclasses);
391 static void checkFkeyPermissions(Relation rel, int16 *attnums, int natts);
392 static CoercionPathType findFkeyCast(Oid targetTypeId, Oid sourceTypeId,
393  Oid *funcid);
394 static void validateForeignKeyConstraint(char *conname,
395  Relation rel, Relation pkrel,
396  Oid pkindOid, Oid constraintOid);
397 static void ATController(AlterTableStmt *parsetree,
398  Relation rel, List *cmds, bool recurse, LOCKMODE lockmode,
399  AlterTableUtilityContext *context);
400 static void ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd,
401  bool recurse, bool recursing, LOCKMODE lockmode,
402  AlterTableUtilityContext *context);
403 static void ATRewriteCatalogs(List **wqueue, LOCKMODE lockmode,
404  AlterTableUtilityContext *context);
405 static void ATExecCmd(List **wqueue, AlteredTableInfo *tab,
406  AlterTableCmd *cmd, LOCKMODE lockmode, AlterTablePass cur_pass,
407  AlterTableUtilityContext *context);
409  Relation rel, AlterTableCmd *cmd,
410  bool recurse, LOCKMODE lockmode,
411  AlterTablePass cur_pass,
412  AlterTableUtilityContext *context);
413 static void ATRewriteTables(AlterTableStmt *parsetree,
414  List **wqueue, LOCKMODE lockmode,
415  AlterTableUtilityContext *context);
416 static void ATRewriteTable(AlteredTableInfo *tab, Oid OIDNewHeap, LOCKMODE lockmode);
417 static AlteredTableInfo *ATGetQueueEntry(List **wqueue, Relation rel);
418 static void ATSimplePermissions(AlterTableType cmdtype, Relation rel, int allowed_targets);
419 static void ATSimpleRecursion(List **wqueue, Relation rel,
420  AlterTableCmd *cmd, bool recurse, LOCKMODE lockmode,
421  AlterTableUtilityContext *context);
422 static void ATCheckPartitionsNotInUse(Relation rel, LOCKMODE lockmode);
423 static void ATTypedTableRecursion(List **wqueue, Relation rel, AlterTableCmd *cmd,
424  LOCKMODE lockmode,
425  AlterTableUtilityContext *context);
426 static List *find_typed_table_dependencies(Oid typeOid, const char *typeName,
427  DropBehavior behavior);
428 static void ATPrepAddColumn(List **wqueue, Relation rel, bool recurse, bool recursing,
429  bool is_view, AlterTableCmd *cmd, LOCKMODE lockmode,
430  AlterTableUtilityContext *context);
431 static ObjectAddress ATExecAddColumn(List **wqueue, AlteredTableInfo *tab,
432  Relation rel, AlterTableCmd **cmd,
433  bool recurse, bool recursing,
434  LOCKMODE lockmode, AlterTablePass cur_pass,
435  AlterTableUtilityContext *context);
436 static bool check_for_column_name_collision(Relation rel, const char *colname,
437  bool if_not_exists);
438 static void add_column_datatype_dependency(Oid relid, int32 attnum, Oid typid);
440 static ObjectAddress ATExecDropNotNull(Relation rel, const char *colName, bool recurse,
441  LOCKMODE lockmode);
442 static bool set_attnotnull(List **wqueue, Relation rel,
443  AttrNumber attnum, bool recurse, LOCKMODE lockmode);
444 static ObjectAddress ATExecSetNotNull(List **wqueue, Relation rel,
445  char *constrname, char *colName,
446  bool recurse, bool recursing,
447  List **readyRels, LOCKMODE lockmode);
448 static ObjectAddress ATExecSetAttNotNull(List **wqueue, Relation rel,
449  const char *colName, LOCKMODE lockmode);
451 static bool ConstraintImpliedByRelConstraint(Relation scanrel,
452  List *testConstraint, List *provenConstraint);
453 static ObjectAddress ATExecColumnDefault(Relation rel, const char *colName,
454  Node *newDefault, LOCKMODE lockmode);
456  Node *newDefault);
457 static ObjectAddress ATExecAddIdentity(Relation rel, const char *colName,
458  Node *def, LOCKMODE lockmode, bool recurse, bool recursing);
459 static ObjectAddress ATExecSetIdentity(Relation rel, const char *colName,
460  Node *def, LOCKMODE lockmode, bool recurse, bool recursing);
461 static ObjectAddress ATExecDropIdentity(Relation rel, const char *colName, bool missing_ok, LOCKMODE lockmode,
462  bool recurse, bool recursing);
463 static ObjectAddress ATExecSetExpression(AlteredTableInfo *tab, Relation rel, const char *colName,
464  Node *newExpr, LOCKMODE lockmode);
465 static void ATPrepDropExpression(Relation rel, AlterTableCmd *cmd, bool recurse, bool recursing, LOCKMODE lockmode);
466 static ObjectAddress ATExecDropExpression(Relation rel, const char *colName, bool missing_ok, LOCKMODE lockmode);
467 static ObjectAddress ATExecSetStatistics(Relation rel, const char *colName, int16 colNum,
468  Node *newValue, LOCKMODE lockmode);
469 static ObjectAddress ATExecSetOptions(Relation rel, const char *colName,
470  Node *options, bool isReset, LOCKMODE lockmode);
471 static ObjectAddress ATExecSetStorage(Relation rel, const char *colName,
472  Node *newValue, LOCKMODE lockmode);
473 static void ATPrepDropColumn(List **wqueue, Relation rel, bool recurse, bool recursing,
474  AlterTableCmd *cmd, LOCKMODE lockmode,
475  AlterTableUtilityContext *context);
476 static ObjectAddress ATExecDropColumn(List **wqueue, Relation rel, const char *colName,
477  DropBehavior behavior,
478  bool recurse, bool recursing,
479  bool missing_ok, LOCKMODE lockmode,
480  ObjectAddresses *addrs);
481 static void ATPrepAddPrimaryKey(List **wqueue, Relation rel, AlterTableCmd *cmd,
482  LOCKMODE lockmode, AlterTableUtilityContext *context);
484  IndexStmt *stmt, bool is_rebuild, LOCKMODE lockmode);
486  CreateStatsStmt *stmt, bool is_rebuild, LOCKMODE lockmode);
487 static ObjectAddress ATExecAddConstraint(List **wqueue,
488  AlteredTableInfo *tab, Relation rel,
489  Constraint *newConstraint, bool recurse, bool is_readd,
490  LOCKMODE lockmode);
491 static char *ChooseForeignKeyConstraintNameAddition(List *colnames);
493  IndexStmt *stmt, LOCKMODE lockmode);
495  AlteredTableInfo *tab, Relation rel,
496  Constraint *constr,
497  bool recurse, bool recursing, bool is_readd,
498  LOCKMODE lockmode);
500  Relation rel, Constraint *fkconstraint,
501  bool recurse, bool recursing,
502  LOCKMODE lockmode);
503 static ObjectAddress addFkRecurseReferenced(List **wqueue, Constraint *fkconstraint,
504  Relation rel, Relation pkrel, Oid indexOid, Oid parentConstr,
505  int numfks, int16 *pkattnum, int16 *fkattnum,
506  Oid *pfeqoperators, Oid *ppeqoperators, Oid *ffeqoperators,
507  int numfkdelsetcols, int16 *fkdelsetcols,
508  bool old_check_ok,
509  Oid parentDelTrigger, Oid parentUpdTrigger);
510 static void validateFkOnDeleteSetColumns(int numfks, const int16 *fkattnums,
511  int numfksetcols, const int16 *fksetcolsattnums,
512  List *fksetcols);
513 static void addFkRecurseReferencing(List **wqueue, Constraint *fkconstraint,
514  Relation rel, Relation pkrel, Oid indexOid, Oid parentConstr,
515  int numfks, int16 *pkattnum, int16 *fkattnum,
516  Oid *pfeqoperators, Oid *ppeqoperators, Oid *ffeqoperators,
517  int numfkdelsetcols, int16 *fkdelsetcols,
518  bool old_check_ok, LOCKMODE lockmode,
519  Oid parentInsTrigger, Oid parentUpdTrigger);
520 static void CloneForeignKeyConstraints(List **wqueue, Relation parentRel,
521  Relation partitionRel);
522 static void CloneFkReferenced(Relation parentRel, Relation partitionRel);
523 static void CloneFkReferencing(List **wqueue, Relation parentRel,
524  Relation partRel);
525 static void createForeignKeyCheckTriggers(Oid myRelOid, Oid refRelOid,
526  Constraint *fkconstraint, Oid constraintOid,
527  Oid indexOid,
528  Oid parentInsTrigger, Oid parentUpdTrigger,
529  Oid *insertTrigOid, Oid *updateTrigOid);
530 static void createForeignKeyActionTriggers(Relation rel, Oid refRelOid,
531  Constraint *fkconstraint, Oid constraintOid,
532  Oid indexOid,
533  Oid parentDelTrigger, Oid parentUpdTrigger,
534  Oid *deleteTrigOid, Oid *updateTrigOid);
536  Oid partRelid,
537  Oid parentConstrOid, int numfks,
538  AttrNumber *mapped_conkey, AttrNumber *confkey,
539  Oid *conpfeqop,
540  Oid parentInsTrigger,
541  Oid parentUpdTrigger,
542  Relation trigrel);
543 static void GetForeignKeyActionTriggers(Relation trigrel,
544  Oid conoid, Oid confrelid, Oid conrelid,
545  Oid *deleteTriggerOid,
546  Oid *updateTriggerOid);
547 static void GetForeignKeyCheckTriggers(Relation trigrel,
548  Oid conoid, Oid confrelid, Oid conrelid,
549  Oid *insertTriggerOid,
550  Oid *updateTriggerOid);
551 static void ATExecDropConstraint(Relation rel, const char *constrName,
552  DropBehavior behavior, bool recurse,
553  bool missing_ok, LOCKMODE lockmode);
555  HeapTuple constraintTup, DropBehavior behavior,
556  bool recurse, bool recursing,
557  bool missing_ok, List **readyRels,
558  LOCKMODE lockmode);
559 static void ATPrepAlterColumnType(List **wqueue,
560  AlteredTableInfo *tab, Relation rel,
561  bool recurse, bool recursing,
562  AlterTableCmd *cmd, LOCKMODE lockmode,
563  AlterTableUtilityContext *context);
564 static bool ATColumnChangeRequiresRewrite(Node *expr, AttrNumber varattno);
566  AlterTableCmd *cmd, LOCKMODE lockmode);
568  Relation rel, AttrNumber attnum, const char *colName);
569 static void RememberConstraintForRebuilding(Oid conoid, AlteredTableInfo *tab);
570 static void RememberIndexForRebuilding(Oid indoid, AlteredTableInfo *tab);
571 static void RememberStatisticsForRebuilding(Oid stxoid, AlteredTableInfo *tab);
572 static void ATPostAlterTypeCleanup(List **wqueue, AlteredTableInfo *tab,
573  LOCKMODE lockmode);
574 static void ATPostAlterTypeParse(Oid oldId, Oid oldRelId, Oid refRelId,
575  char *cmd, List **wqueue, LOCKMODE lockmode,
576  bool rewrite);
578  Oid objid, Relation rel, List *domname,
579  const char *conname);
580 static void TryReuseIndex(Oid oldId, IndexStmt *stmt);
581 static void TryReuseForeignKey(Oid oldId, Constraint *con);
582 static ObjectAddress ATExecAlterColumnGenericOptions(Relation rel, const char *colName,
583  List *options, LOCKMODE lockmode);
584 static void change_owner_fix_column_acls(Oid relationOid,
585  Oid oldOwnerId, Oid newOwnerId);
586 static void change_owner_recurse_to_sequences(Oid relationOid,
587  Oid newOwnerId, LOCKMODE lockmode);
588 static ObjectAddress ATExecClusterOn(Relation rel, const char *indexName,
589  LOCKMODE lockmode);
590 static void ATExecDropCluster(Relation rel, LOCKMODE lockmode);
591 static void ATPrepSetAccessMethod(AlteredTableInfo *tab, Relation rel, const char *amname);
592 static bool ATPrepChangePersistence(Relation rel, bool toLogged);
593 static void ATPrepSetTableSpace(AlteredTableInfo *tab, Relation rel,
594  const char *tablespacename, LOCKMODE lockmode);
595 static void ATExecSetTableSpace(Oid tableOid, Oid newTableSpace, LOCKMODE lockmode);
596 static void ATExecSetTableSpaceNoStorage(Relation rel, Oid newTableSpace);
597 static void ATExecSetRelOptions(Relation rel, List *defList,
598  AlterTableType operation,
599  LOCKMODE lockmode);
600 static void ATExecEnableDisableTrigger(Relation rel, const char *trigname,
601  char fires_when, bool skip_system, bool recurse,
602  LOCKMODE lockmode);
603 static void ATExecEnableDisableRule(Relation rel, const char *rulename,
604  char fires_when, LOCKMODE lockmode);
605 static void ATPrepAddInherit(Relation child_rel);
606 static ObjectAddress ATExecAddInherit(Relation child_rel, RangeVar *parent, LOCKMODE lockmode);
607 static ObjectAddress ATExecDropInherit(Relation rel, RangeVar *parent, LOCKMODE lockmode);
608 static void drop_parent_dependency(Oid relid, Oid refclassid, Oid refobjid,
609  DependencyType deptype);
610 static ObjectAddress ATExecAddOf(Relation rel, const TypeName *ofTypename, LOCKMODE lockmode);
611 static void ATExecDropOf(Relation rel, LOCKMODE lockmode);
612 static void ATExecReplicaIdentity(Relation rel, ReplicaIdentityStmt *stmt, LOCKMODE lockmode);
613 static void ATExecGenericOptions(Relation rel, List *options);
614 static void ATExecSetRowSecurity(Relation rel, bool rls);
615 static void ATExecForceNoForceRowSecurity(Relation rel, bool force_rls);
617  const char *column, Node *newValue, LOCKMODE lockmode);
618 
619 static void index_copy_data(Relation rel, RelFileLocator newrlocator);
620 static const char *storage_name(char c);
621 
622 static void RangeVarCallbackForDropRelation(const RangeVar *rel, Oid relOid,
623  Oid oldRelOid, void *arg);
624 static void RangeVarCallbackForAlterRelation(const RangeVar *rv, Oid relid,
625  Oid oldrelid, void *arg);
627 static void ComputePartitionAttrs(ParseState *pstate, Relation rel, List *partParams, AttrNumber *partattrs,
628  List **partexprs, Oid *partopclass, Oid *partcollation,
629  PartitionStrategy strategy);
630 static void CreateInheritance(Relation child_rel, Relation parent_rel, bool ispartition);
631 static void RemoveInheritance(Relation child_rel, Relation parent_rel,
632  bool expect_detached);
633 static void ATInheritAdjustNotNulls(Relation parent_rel, Relation child_rel,
634  int inhcount);
635 static ObjectAddress ATExecAttachPartition(List **wqueue, Relation rel,
636  PartitionCmd *cmd,
637  AlterTableUtilityContext *context);
638 static void AttachPartitionEnsureIndexes(List **wqueue, Relation rel, Relation attachrel);
639 static void QueuePartitionConstraintValidation(List **wqueue, Relation scanrel,
640  List *partConstraint,
641  bool validate_default);
642 static void CloneRowTriggersToPartition(Relation parent, Relation partition);
643 static void DetachAddConstraintIfNeeded(List **wqueue, Relation partRel);
644 static void DropClonedTriggersFromPartition(Oid partitionId);
646  Relation rel, RangeVar *name,
647  bool concurrent);
648 static void DetachPartitionFinalize(Relation rel, Relation partRel,
649  bool concurrent, Oid defaultPartOid);
651 static ObjectAddress ATExecAttachPartitionIdx(List **wqueue, Relation parentIdx,
652  RangeVar *name);
653 static void validatePartitionedIndex(Relation partedIdx, Relation partedTbl);
654 static void refuseDupeIndexAttach(Relation parentIdx, Relation partIdx,
655  Relation partitionTbl);
656 static void verifyPartitionIndexNotNull(IndexInfo *iinfo, Relation partIdx);
657 static List *GetParentedForeignKeyRefs(Relation partition);
658 static void ATDetachCheckNoForeignKeyRefs(Relation partition);
659 static char GetAttributeCompression(Oid atttypid, const char *compression);
660 static char GetAttributeStorage(Oid atttypid, const char *storagemode);
661 
662 
663 /* ----------------------------------------------------------------
664  * DefineRelation
665  * Creates a new relation.
666  *
667  * stmt carries parsetree information from an ordinary CREATE TABLE statement.
668  * The other arguments are used to extend the behavior for other cases:
669  * relkind: relkind to assign to the new relation
670  * ownerId: if not InvalidOid, use this as the new relation's owner.
671  * typaddress: if not null, it's set to the pg_type entry's address.
672  * queryString: for error reporting
673  *
674  * Note that permissions checks are done against current user regardless of
675  * ownerId. A nonzero ownerId is used when someone is creating a relation
676  * "on behalf of" someone else, so we still want to see that the current user
677  * has permissions to do it.
678  *
679  * If successful, returns the address of the new relation.
680  * ----------------------------------------------------------------
681  */
683 DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId,
684  ObjectAddress *typaddress, const char *queryString)
685 {
686  char relname[NAMEDATALEN];
687  Oid namespaceId;
688  Oid relationId;
689  Oid tablespaceId;
690  Relation rel;
692  List *inheritOids;
693  List *old_constraints;
694  List *old_notnulls;
695  List *rawDefaults;
696  List *cookedDefaults;
697  List *nncols;
698  Datum reloptions;
699  ListCell *listptr;
701  bool partitioned;
702  static char *validnsps[] = HEAP_RELOPT_NAMESPACES;
703  Oid ofTypeId;
704  ObjectAddress address;
705  LOCKMODE parentLockmode;
706  const char *accessMethod = NULL;
707  Oid accessMethodId = InvalidOid;
708 
709  /*
710  * Truncate relname to appropriate length (probably a waste of time, as
711  * parser should have done this already).
712  */
713  strlcpy(relname, stmt->relation->relname, NAMEDATALEN);
714 
715  /*
716  * Check consistency of arguments
717  */
718  if (stmt->oncommit != ONCOMMIT_NOOP
719  && stmt->relation->relpersistence != RELPERSISTENCE_TEMP)
720  ereport(ERROR,
721  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
722  errmsg("ON COMMIT can only be used on temporary tables")));
723 
724  if (stmt->partspec != NULL)
725  {
726  if (relkind != RELKIND_RELATION)
727  elog(ERROR, "unexpected relkind: %d", (int) relkind);
728 
729  relkind = RELKIND_PARTITIONED_TABLE;
730  partitioned = true;
731  }
732  else
733  partitioned = false;
734 
735  /*
736  * Look up the namespace in which we are supposed to create the relation,
737  * check we have permission to create there, lock it against concurrent
738  * drop, and mark stmt->relation as RELPERSISTENCE_TEMP if a temporary
739  * namespace is selected.
740  */
741  namespaceId =
743 
744  /*
745  * Security check: disallow creating temp tables from security-restricted
746  * code. This is needed because calling code might not expect untrusted
747  * tables to appear in pg_temp at the front of its search path.
748  */
749  if (stmt->relation->relpersistence == RELPERSISTENCE_TEMP
751  ereport(ERROR,
752  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
753  errmsg("cannot create temporary table within security-restricted operation")));
754 
755  /*
756  * Determine the lockmode to use when scanning parents. A self-exclusive
757  * lock is needed here.
758  *
759  * For regular inheritance, if two backends attempt to add children to the
760  * same parent simultaneously, and that parent has no pre-existing
761  * children, then both will attempt to update the parent's relhassubclass
762  * field, leading to a "tuple concurrently updated" error. Also, this
763  * interlocks against a concurrent ANALYZE on the parent table, which
764  * might otherwise be attempting to clear the parent's relhassubclass
765  * field, if its previous children were recently dropped.
766  *
767  * If the child table is a partition, then we instead grab an exclusive
768  * lock on the parent because its partition descriptor will be changed by
769  * addition of the new partition.
770  */
771  parentLockmode = (stmt->partbound != NULL ? AccessExclusiveLock :
773 
774  /* Determine the list of OIDs of the parents. */
775  inheritOids = NIL;
776  foreach(listptr, stmt->inhRelations)
777  {
778  RangeVar *rv = (RangeVar *) lfirst(listptr);
779  Oid parentOid;
780 
781  parentOid = RangeVarGetRelid(rv, parentLockmode, false);
782 
783  /*
784  * Reject duplications in the list of parents.
785  */
786  if (list_member_oid(inheritOids, parentOid))
787  ereport(ERROR,
788  (errcode(ERRCODE_DUPLICATE_TABLE),
789  errmsg("relation \"%s\" would be inherited from more than once",
790  get_rel_name(parentOid))));
791 
792  inheritOids = lappend_oid(inheritOids, parentOid);
793  }
794 
795  /*
796  * Select tablespace to use: an explicitly indicated one, or (in the case
797  * of a partitioned table) the parent's, if it has one.
798  */
799  if (stmt->tablespacename)
800  {
801  tablespaceId = get_tablespace_oid(stmt->tablespacename, false);
802 
803  if (partitioned && tablespaceId == MyDatabaseTableSpace)
804  ereport(ERROR,
805  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
806  errmsg("cannot specify default tablespace for partitioned relations")));
807  }
808  else if (stmt->partbound)
809  {
810  /*
811  * For partitions, when no other tablespace is specified, we default
812  * the tablespace to the parent partitioned table's.
813  */
814  Assert(list_length(inheritOids) == 1);
815  tablespaceId = get_rel_tablespace(linitial_oid(inheritOids));
816  }
817  else
818  tablespaceId = InvalidOid;
819 
820  /* still nothing? use the default */
821  if (!OidIsValid(tablespaceId))
822  tablespaceId = GetDefaultTablespace(stmt->relation->relpersistence,
823  partitioned);
824 
825  /* Check permissions except when using database's default */
826  if (OidIsValid(tablespaceId) && tablespaceId != MyDatabaseTableSpace)
827  {
828  AclResult aclresult;
829 
830  aclresult = object_aclcheck(TableSpaceRelationId, tablespaceId, GetUserId(),
831  ACL_CREATE);
832  if (aclresult != ACLCHECK_OK)
834  get_tablespace_name(tablespaceId));
835  }
836 
837  /* In all cases disallow placing user relations in pg_global */
838  if (tablespaceId == GLOBALTABLESPACE_OID)
839  ereport(ERROR,
840  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
841  errmsg("only shared relations can be placed in pg_global tablespace")));
842 
843  /* Identify user ID that will own the table */
844  if (!OidIsValid(ownerId))
845  ownerId = GetUserId();
846 
847  /*
848  * Parse and validate reloptions, if any.
849  */
850  reloptions = transformRelOptions((Datum) 0, stmt->options, NULL, validnsps,
851  true, false);
852 
853  switch (relkind)
854  {
855  case RELKIND_VIEW:
856  (void) view_reloptions(reloptions, true);
857  break;
858  case RELKIND_PARTITIONED_TABLE:
859  (void) partitioned_table_reloptions(reloptions, true);
860  break;
861  default:
862  (void) heap_reloptions(relkind, reloptions, true);
863  }
864 
865  if (stmt->ofTypename)
866  {
867  AclResult aclresult;
868 
869  ofTypeId = typenameTypeId(NULL, stmt->ofTypename);
870 
871  aclresult = object_aclcheck(TypeRelationId, ofTypeId, GetUserId(), ACL_USAGE);
872  if (aclresult != ACLCHECK_OK)
873  aclcheck_error_type(aclresult, ofTypeId);
874  }
875  else
876  ofTypeId = InvalidOid;
877 
878  /*
879  * Look up inheritance ancestors and generate relation schema, including
880  * inherited attributes. (Note that stmt->tableElts is destructively
881  * modified by MergeAttributes.)
882  */
883  stmt->tableElts =
884  MergeAttributes(stmt->tableElts, inheritOids,
885  stmt->relation->relpersistence,
886  stmt->partbound != NULL,
887  &old_constraints, &old_notnulls);
888 
889  /*
890  * Create a tuple descriptor from the relation schema. Note that this
891  * deals with column names, types, and in-descriptor NOT NULL flags, but
892  * not default values, NOT NULL or CHECK constraints; we handle those
893  * below.
894  */
895  descriptor = BuildDescForRelation(stmt->tableElts);
896 
897  /*
898  * Find columns with default values and prepare for insertion of the
899  * defaults. Pre-cooked (that is, inherited) defaults go into a list of
900  * CookedConstraint structs that we'll pass to heap_create_with_catalog,
901  * while raw defaults go into a list of RawColumnDefault structs that will
902  * be processed by AddRelationNewConstraints. (We can't deal with raw
903  * expressions until we can do transformExpr.)
904  *
905  * We can set the atthasdef flags now in the tuple descriptor; this just
906  * saves StoreAttrDefault from having to do an immediate update of the
907  * pg_attribute rows.
908  */
909  rawDefaults = NIL;
910  cookedDefaults = NIL;
911  attnum = 0;
912 
913  foreach(listptr, stmt->tableElts)
914  {
915  ColumnDef *colDef = lfirst(listptr);
916  Form_pg_attribute attr;
917 
918  attnum++;
919  attr = TupleDescAttr(descriptor, attnum - 1);
920 
921  if (colDef->raw_default != NULL)
922  {
923  RawColumnDefault *rawEnt;
924 
925  Assert(colDef->cooked_default == NULL);
926 
927  rawEnt = (RawColumnDefault *) palloc(sizeof(RawColumnDefault));
928  rawEnt->attnum = attnum;
929  rawEnt->raw_default = colDef->raw_default;
930  rawEnt->missingMode = false;
931  rawEnt->generated = colDef->generated;
932  rawDefaults = lappend(rawDefaults, rawEnt);
933  attr->atthasdef = true;
934  }
935  else if (colDef->cooked_default != NULL)
936  {
937  CookedConstraint *cooked;
938 
939  cooked = (CookedConstraint *) palloc(sizeof(CookedConstraint));
940  cooked->contype = CONSTR_DEFAULT;
941  cooked->conoid = InvalidOid; /* until created */
942  cooked->name = NULL;
943  cooked->attnum = attnum;
944  cooked->expr = colDef->cooked_default;
945  cooked->skip_validation = false;
946  cooked->is_local = true; /* not used for defaults */
947  cooked->inhcount = 0; /* ditto */
948  cooked->is_no_inherit = false;
949  cookedDefaults = lappend(cookedDefaults, cooked);
950  attr->atthasdef = true;
951  }
952  }
953 
954  /*
955  * If the statement hasn't specified an access method, but we're defining
956  * a type of relation that needs one, use the default.
957  */
958  if (stmt->accessMethod != NULL)
959  {
960  accessMethod = stmt->accessMethod;
961 
962  if (partitioned)
963  ereport(ERROR,
964  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
965  errmsg("specifying a table access method is not supported on a partitioned table")));
966  }
967  else if (RELKIND_HAS_TABLE_AM(relkind))
968  accessMethod = default_table_access_method;
969 
970  /* look up the access method, verify it is for a table */
971  if (accessMethod != NULL)
972  accessMethodId = get_table_am_oid(accessMethod, false);
973 
974  /*
975  * Create the relation. Inherited defaults and constraints are passed in
976  * for immediate handling --- since they don't need parsing, they can be
977  * stored immediately.
978  */
979  relationId = heap_create_with_catalog(relname,
980  namespaceId,
981  tablespaceId,
982  InvalidOid,
983  InvalidOid,
984  ofTypeId,
985  ownerId,
986  accessMethodId,
987  descriptor,
988  list_concat(cookedDefaults,
989  old_constraints),
990  relkind,
991  stmt->relation->relpersistence,
992  false,
993  false,
994  stmt->oncommit,
995  reloptions,
996  true,
998  false,
999  InvalidOid,
1000  typaddress);
1001 
1002  /*
1003  * We must bump the command counter to make the newly-created relation
1004  * tuple visible for opening.
1005  */
1007 
1008  /*
1009  * Open the new relation and acquire exclusive lock on it. This isn't
1010  * really necessary for locking out other backends (since they can't see
1011  * the new rel anyway until we commit), but it keeps the lock manager from
1012  * complaining about deadlock risks.
1013  */
1014  rel = relation_open(relationId, AccessExclusiveLock);
1015 
1016  /*
1017  * Now add any newly specified column default and generation expressions
1018  * to the new relation. These are passed to us in the form of raw
1019  * parsetrees; we need to transform them to executable expression trees
1020  * before they can be added. The most convenient way to do that is to
1021  * apply the parser's transformExpr routine, but transformExpr doesn't
1022  * work unless we have a pre-existing relation. So, the transformation has
1023  * to be postponed to this final step of CREATE TABLE.
1024  *
1025  * This needs to be before processing the partitioning clauses because
1026  * those could refer to generated columns.
1027  */
1028  if (rawDefaults)
1029  AddRelationNewConstraints(rel, rawDefaults, NIL,
1030  true, true, false, queryString);
1031 
1032  /*
1033  * Make column generation expressions visible for use by partitioning.
1034  */
1036 
1037  /* Process and store partition bound, if any. */
1038  if (stmt->partbound)
1039  {
1040  PartitionBoundSpec *bound;
1041  ParseState *pstate;
1042  Oid parentId = linitial_oid(inheritOids),
1043  defaultPartOid;
1044  Relation parent,
1045  defaultRel = NULL;
1046  ParseNamespaceItem *nsitem;
1047 
1048  /* Already have strong enough lock on the parent */
1049  parent = table_open(parentId, NoLock);
1050 
1051  /*
1052  * We are going to try to validate the partition bound specification
1053  * against the partition key of parentRel, so it better have one.
1054  */
1055  if (parent->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
1056  ereport(ERROR,
1057  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1058  errmsg("\"%s\" is not partitioned",
1059  RelationGetRelationName(parent))));
1060 
1061  /*
1062  * The partition constraint of the default partition depends on the
1063  * partition bounds of every other partition. It is possible that
1064  * another backend might be about to execute a query on the default
1065  * partition table, and that the query relies on previously cached
1066  * default partition constraints. We must therefore take a table lock
1067  * strong enough to prevent all queries on the default partition from
1068  * proceeding until we commit and send out a shared-cache-inval notice
1069  * that will make them update their index lists.
1070  *
1071  * Order of locking: The relation being added won't be visible to
1072  * other backends until it is committed, hence here in
1073  * DefineRelation() the order of locking the default partition and the
1074  * relation being added does not matter. But at all other places we
1075  * need to lock the default relation before we lock the relation being
1076  * added or removed i.e. we should take the lock in same order at all
1077  * the places such that lock parent, lock default partition and then
1078  * lock the partition so as to avoid a deadlock.
1079  */
1080  defaultPartOid =
1082  true));
1083  if (OidIsValid(defaultPartOid))
1084  defaultRel = table_open(defaultPartOid, AccessExclusiveLock);
1085 
1086  /* Transform the bound values */
1087  pstate = make_parsestate(NULL);
1088  pstate->p_sourcetext = queryString;
1089 
1090  /*
1091  * Add an nsitem containing this relation, so that transformExpr
1092  * called on partition bound expressions is able to report errors
1093  * using a proper context.
1094  */
1095  nsitem = addRangeTableEntryForRelation(pstate, rel, AccessShareLock,
1096  NULL, false, false);
1097  addNSItemToQuery(pstate, nsitem, false, true, true);
1098 
1099  bound = transformPartitionBound(pstate, parent, stmt->partbound);
1100 
1101  /*
1102  * Check first that the new partition's bound is valid and does not
1103  * overlap with any of existing partitions of the parent.
1104  */
1105  check_new_partition_bound(relname, parent, bound, pstate);
1106 
1107  /*
1108  * If the default partition exists, its partition constraints will
1109  * change after the addition of this new partition such that it won't
1110  * allow any row that qualifies for this new partition. So, check that
1111  * the existing data in the default partition satisfies the constraint
1112  * as it will exist after adding this partition.
1113  */
1114  if (OidIsValid(defaultPartOid))
1115  {
1116  check_default_partition_contents(parent, defaultRel, bound);
1117  /* Keep the lock until commit. */
1118  table_close(defaultRel, NoLock);
1119  }
1120 
1121  /* Update the pg_class entry. */
1122  StorePartitionBound(rel, parent, bound);
1123 
1124  table_close(parent, NoLock);
1125  }
1126 
1127  /* Store inheritance information for new rel. */
1128  StoreCatalogInheritance(relationId, inheritOids, stmt->partbound != NULL);
1129 
1130  /*
1131  * Process the partitioning specification (if any) and store the partition
1132  * key information into the catalog.
1133  */
1134  if (partitioned)
1135  {
1136  ParseState *pstate;
1137  int partnatts;
1138  AttrNumber partattrs[PARTITION_MAX_KEYS];
1139  Oid partopclass[PARTITION_MAX_KEYS];
1140  Oid partcollation[PARTITION_MAX_KEYS];
1141  List *partexprs = NIL;
1142 
1143  pstate = make_parsestate(NULL);
1144  pstate->p_sourcetext = queryString;
1145 
1146  partnatts = list_length(stmt->partspec->partParams);
1147 
1148  /* Protect fixed-size arrays here and in executor */
1149  if (partnatts > PARTITION_MAX_KEYS)
1150  ereport(ERROR,
1151  (errcode(ERRCODE_TOO_MANY_COLUMNS),
1152  errmsg("cannot partition using more than %d columns",
1153  PARTITION_MAX_KEYS)));
1154 
1155  /*
1156  * We need to transform the raw parsetrees corresponding to partition
1157  * expressions into executable expression trees. Like column defaults
1158  * and CHECK constraints, we could not have done the transformation
1159  * earlier.
1160  */
1161  stmt->partspec = transformPartitionSpec(rel, stmt->partspec);
1162 
1163  ComputePartitionAttrs(pstate, rel, stmt->partspec->partParams,
1164  partattrs, &partexprs, partopclass,
1165  partcollation, stmt->partspec->strategy);
1166 
1167  StorePartitionKey(rel, stmt->partspec->strategy, partnatts, partattrs,
1168  partexprs,
1169  partopclass, partcollation);
1170 
1171  /* make it all visible */
1173  }
1174 
1175  /*
1176  * If we're creating a partition, create now all the indexes, triggers,
1177  * FKs defined in the parent.
1178  *
1179  * We can't do it earlier, because DefineIndex wants to know the partition
1180  * key which we just stored.
1181  */
1182  if (stmt->partbound)
1183  {
1184  Oid parentId = linitial_oid(inheritOids);
1185  Relation parent;
1186  List *idxlist;
1187  ListCell *cell;
1188 
1189  /* Already have strong enough lock on the parent */
1190  parent = table_open(parentId, NoLock);
1191  idxlist = RelationGetIndexList(parent);
1192 
1193  /*
1194  * For each index in the parent table, create one in the partition
1195  */
1196  foreach(cell, idxlist)
1197  {
1198  Relation idxRel = index_open(lfirst_oid(cell), AccessShareLock);
1199  AttrMap *attmap;
1200  IndexStmt *idxstmt;
1201  Oid constraintOid;
1202 
1203  if (rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
1204  {
1205  if (idxRel->rd_index->indisunique)
1206  ereport(ERROR,
1207  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1208  errmsg("cannot create foreign partition of partitioned table \"%s\"",
1209  RelationGetRelationName(parent)),
1210  errdetail("Table \"%s\" contains indexes that are unique.",
1211  RelationGetRelationName(parent))));
1212  else
1213  {
1214  index_close(idxRel, AccessShareLock);
1215  continue;
1216  }
1217  }
1218 
1220  RelationGetDescr(parent),
1221  false);
1222  idxstmt =
1223  generateClonedIndexStmt(NULL, idxRel,
1224  attmap, &constraintOid);
1226  idxstmt,
1227  InvalidOid,
1228  RelationGetRelid(idxRel),
1229  constraintOid,
1230  -1,
1231  false, false, false, false, false);
1232 
1233  index_close(idxRel, AccessShareLock);
1234  }
1235 
1236  list_free(idxlist);
1237 
1238  /*
1239  * If there are any row-level triggers, clone them to the new
1240  * partition.
1241  */
1242  if (parent->trigdesc != NULL)
1243  CloneRowTriggersToPartition(parent, rel);
1244 
1245  /*
1246  * And foreign keys too. Note that because we're freshly creating the
1247  * table, there is no need to verify these new constraints.
1248  */
1249  CloneForeignKeyConstraints(NULL, parent, rel);
1250 
1251  table_close(parent, NoLock);
1252  }
1253 
1254  /*
1255  * Now add any newly specified CHECK constraints to the new relation. Same
1256  * as for defaults above, but these need to come after partitioning is set
1257  * up.
1258  */
1259  if (stmt->constraints)
1260  AddRelationNewConstraints(rel, NIL, stmt->constraints,
1261  true, true, false, queryString);
1262 
1263  /*
1264  * Finally, merge the not-null constraints that are declared directly with
1265  * those that come from parent relations (making sure to count inheritance
1266  * appropriately for each), create them, and set the attnotnull flag on
1267  * columns that don't yet have it.
1268  */
1269  nncols = AddRelationNotNullConstraints(rel, stmt->nnconstraints,
1270  old_notnulls);
1271  foreach(listptr, nncols)
1272  set_attnotnull(NULL, rel, lfirst_int(listptr), false, NoLock);
1273 
1274  ObjectAddressSet(address, RelationRelationId, relationId);
1275 
1276  /*
1277  * Clean up. We keep lock on new relation (although it shouldn't be
1278  * visible to anyone else anyway, until commit).
1279  */
1280  relation_close(rel, NoLock);
1281 
1282  return address;
1283 }
1284 
1285 /*
1286  * BuildDescForRelation
1287  *
1288  * Given a list of ColumnDef nodes, build a TupleDesc.
1289  *
1290  * Note: tdtypeid will need to be filled in later on.
1291  */
1292 TupleDesc
1294 {
1295  int natts;
1297  ListCell *l;
1298  TupleDesc desc;
1299  bool has_not_null;
1300  char *attname;
1301  Oid atttypid;
1302  int32 atttypmod;
1303  Oid attcollation;
1304  int attdim;
1305 
1306  /*
1307  * allocate a new tuple descriptor
1308  */
1309  natts = list_length(columns);
1310  desc = CreateTemplateTupleDesc(natts);
1311  has_not_null = false;
1312 
1313  attnum = 0;
1314 
1315  foreach(l, columns)
1316  {
1317  ColumnDef *entry = lfirst(l);
1318  AclResult aclresult;
1319  Form_pg_attribute att;
1320 
1321  /*
1322  * for each entry in the list, get the name and type information from
1323  * the list and have TupleDescInitEntry fill in the attribute
1324  * information we need.
1325  */
1326  attnum++;
1327 
1328  attname = entry->colname;
1329  typenameTypeIdAndMod(NULL, entry->typeName, &atttypid, &atttypmod);
1330 
1331  aclresult = object_aclcheck(TypeRelationId, atttypid, GetUserId(), ACL_USAGE);
1332  if (aclresult != ACLCHECK_OK)
1333  aclcheck_error_type(aclresult, atttypid);
1334 
1335  attcollation = GetColumnDefCollation(NULL, entry, atttypid);
1336  attdim = list_length(entry->typeName->arrayBounds);
1337  if (attdim > PG_INT16_MAX)
1338  ereport(ERROR,
1339  errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
1340  errmsg("too many array dimensions"));
1341 
1342  if (entry->typeName->setof)
1343  ereport(ERROR,
1344  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
1345  errmsg("column \"%s\" cannot be declared SETOF",
1346  attname)));
1347 
1349  atttypid, atttypmod, attdim);
1350  att = TupleDescAttr(desc, attnum - 1);
1351 
1352  /* Override TupleDescInitEntry's settings as requested */
1353  TupleDescInitEntryCollation(desc, attnum, attcollation);
1354 
1355  /* Fill in additional stuff not handled by TupleDescInitEntry */
1356  att->attnotnull = entry->is_not_null;
1357  has_not_null |= entry->is_not_null;
1358  att->attislocal = entry->is_local;
1359  att->attinhcount = entry->inhcount;
1360  att->attidentity = entry->identity;
1361  att->attgenerated = entry->generated;
1362  att->attcompression = GetAttributeCompression(att->atttypid, entry->compression);
1363  if (entry->storage)
1364  att->attstorage = entry->storage;
1365  else if (entry->storage_name)
1366  att->attstorage = GetAttributeStorage(att->atttypid, entry->storage_name);
1367  }
1368 
1369  if (has_not_null)
1370  {
1371  TupleConstr *constr = (TupleConstr *) palloc0(sizeof(TupleConstr));
1372 
1373  constr->has_not_null = true;
1374  constr->has_generated_stored = false;
1375  constr->defval = NULL;
1376  constr->missing = NULL;
1377  constr->num_defval = 0;
1378  constr->check = NULL;
1379  constr->num_check = 0;
1380  desc->constr = constr;
1381  }
1382  else
1383  {
1384  desc->constr = NULL;
1385  }
1386 
1387  return desc;
1388 }
1389 
1390 /*
1391  * Emit the right error or warning message for a "DROP" command issued on a
1392  * non-existent relation
1393  */
1394 static void
1395 DropErrorMsgNonExistent(RangeVar *rel, char rightkind, bool missing_ok)
1396 {
1397  const struct dropmsgstrings *rentry;
1398 
1399  if (rel->schemaname != NULL &&
1401  {
1402  if (!missing_ok)
1403  {
1404  ereport(ERROR,
1405  (errcode(ERRCODE_UNDEFINED_SCHEMA),
1406  errmsg("schema \"%s\" does not exist", rel->schemaname)));
1407  }
1408  else
1409  {
1410  ereport(NOTICE,
1411  (errmsg("schema \"%s\" does not exist, skipping",
1412  rel->schemaname)));
1413  }
1414  return;
1415  }
1416 
1417  for (rentry = dropmsgstringarray; rentry->kind != '\0'; rentry++)
1418  {
1419  if (rentry->kind == rightkind)
1420  {
1421  if (!missing_ok)
1422  {
1423  ereport(ERROR,
1424  (errcode(rentry->nonexistent_code),
1425  errmsg(rentry->nonexistent_msg, rel->relname)));
1426  }
1427  else
1428  {
1429  ereport(NOTICE, (errmsg(rentry->skipping_msg, rel->relname)));
1430  break;
1431  }
1432  }
1433  }
1434 
1435  Assert(rentry->kind != '\0'); /* Should be impossible */
1436 }
1437 
1438 /*
1439  * Emit the right error message for a "DROP" command issued on a
1440  * relation of the wrong type
1441  */
1442 static void
1443 DropErrorMsgWrongType(const char *relname, char wrongkind, char rightkind)
1444 {
1445  const struct dropmsgstrings *rentry;
1446  const struct dropmsgstrings *wentry;
1447 
1448  for (rentry = dropmsgstringarray; rentry->kind != '\0'; rentry++)
1449  if (rentry->kind == rightkind)
1450  break;
1451  Assert(rentry->kind != '\0');
1452 
1453  for (wentry = dropmsgstringarray; wentry->kind != '\0'; wentry++)
1454  if (wentry->kind == wrongkind)
1455  break;
1456  /* wrongkind could be something we don't have in our table... */
1457 
1458  ereport(ERROR,
1459  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1460  errmsg(rentry->nota_msg, relname),
1461  (wentry->kind != '\0') ? errhint("%s", _(wentry->drophint_msg)) : 0));
1462 }
1463 
1464 /*
1465  * RemoveRelations
1466  * Implements DROP TABLE, DROP INDEX, DROP SEQUENCE, DROP VIEW,
1467  * DROP MATERIALIZED VIEW, DROP FOREIGN TABLE
1468  */
1469 void
1471 {
1472  ObjectAddresses *objects;
1473  char relkind;
1474  ListCell *cell;
1475  int flags = 0;
1476  LOCKMODE lockmode = AccessExclusiveLock;
1477 
1478  /* DROP CONCURRENTLY uses a weaker lock, and has some restrictions */
1479  if (drop->concurrent)
1480  {
1481  /*
1482  * Note that for temporary relations this lock may get upgraded later
1483  * on, but as no other session can access a temporary relation, this
1484  * is actually fine.
1485  */
1486  lockmode = ShareUpdateExclusiveLock;
1487  Assert(drop->removeType == OBJECT_INDEX);
1488  if (list_length(drop->objects) != 1)
1489  ereport(ERROR,
1490  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1491  errmsg("DROP INDEX CONCURRENTLY does not support dropping multiple objects")));
1492  if (drop->behavior == DROP_CASCADE)
1493  ereport(ERROR,
1494  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1495  errmsg("DROP INDEX CONCURRENTLY does not support CASCADE")));
1496  }
1497 
1498  /*
1499  * First we identify all the relations, then we delete them in a single
1500  * performMultipleDeletions() call. This is to avoid unwanted DROP
1501  * RESTRICT errors if one of the relations depends on another.
1502  */
1503 
1504  /* Determine required relkind */
1505  switch (drop->removeType)
1506  {
1507  case OBJECT_TABLE:
1508  relkind = RELKIND_RELATION;
1509  break;
1510 
1511  case OBJECT_INDEX:
1512  relkind = RELKIND_INDEX;
1513  break;
1514 
1515  case OBJECT_SEQUENCE:
1516  relkind = RELKIND_SEQUENCE;
1517  break;
1518 
1519  case OBJECT_VIEW:
1520  relkind = RELKIND_VIEW;
1521  break;
1522 
1523  case OBJECT_MATVIEW:
1524  relkind = RELKIND_MATVIEW;
1525  break;
1526 
1527  case OBJECT_FOREIGN_TABLE:
1528  relkind = RELKIND_FOREIGN_TABLE;
1529  break;
1530 
1531  default:
1532  elog(ERROR, "unrecognized drop object type: %d",
1533  (int) drop->removeType);
1534  relkind = 0; /* keep compiler quiet */
1535  break;
1536  }
1537 
1538  /* Lock and validate each relation; build a list of object addresses */
1539  objects = new_object_addresses();
1540 
1541  foreach(cell, drop->objects)
1542  {
1543  RangeVar *rel = makeRangeVarFromNameList((List *) lfirst(cell));
1544  Oid relOid;
1545  ObjectAddress obj;
1547 
1548  /*
1549  * These next few steps are a great deal like relation_openrv, but we
1550  * don't bother building a relcache entry since we don't need it.
1551  *
1552  * Check for shared-cache-inval messages before trying to access the
1553  * relation. This is needed to cover the case where the name
1554  * identifies a rel that has been dropped and recreated since the
1555  * start of our transaction: if we don't flush the old syscache entry,
1556  * then we'll latch onto that entry and suffer an error later.
1557  */
1559 
1560  /* Look up the appropriate relation using namespace search. */
1561  state.expected_relkind = relkind;
1562  state.heap_lockmode = drop->concurrent ?
1564  /* We must initialize these fields to show that no locks are held: */
1565  state.heapOid = InvalidOid;
1566  state.partParentOid = InvalidOid;
1567 
1568  relOid = RangeVarGetRelidExtended(rel, lockmode, RVR_MISSING_OK,
1570  (void *) &state);
1571 
1572  /* Not there? */
1573  if (!OidIsValid(relOid))
1574  {
1575  DropErrorMsgNonExistent(rel, relkind, drop->missing_ok);
1576  continue;
1577  }
1578 
1579  /*
1580  * Decide if concurrent mode needs to be used here or not. The
1581  * callback retrieved the rel's persistence for us.
1582  */
1583  if (drop->concurrent &&
1584  state.actual_relpersistence != RELPERSISTENCE_TEMP)
1585  {
1586  Assert(list_length(drop->objects) == 1 &&
1587  drop->removeType == OBJECT_INDEX);
1589  }
1590 
1591  /*
1592  * Concurrent index drop cannot be used with partitioned indexes,
1593  * either.
1594  */
1595  if ((flags & PERFORM_DELETION_CONCURRENTLY) != 0 &&
1596  state.actual_relkind == RELKIND_PARTITIONED_INDEX)
1597  ereport(ERROR,
1598  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1599  errmsg("cannot drop partitioned index \"%s\" concurrently",
1600  rel->relname)));
1601 
1602  /*
1603  * If we're told to drop a partitioned index, we must acquire lock on
1604  * all the children of its parent partitioned table before proceeding.
1605  * Otherwise we'd try to lock the child index partitions before their
1606  * tables, leading to potential deadlock against other sessions that
1607  * will lock those objects in the other order.
1608  */
1609  if (state.actual_relkind == RELKIND_PARTITIONED_INDEX)
1610  (void) find_all_inheritors(state.heapOid,
1611  state.heap_lockmode,
1612  NULL);
1613 
1614  /* OK, we're ready to delete this one */
1615  obj.classId = RelationRelationId;
1616  obj.objectId = relOid;
1617  obj.objectSubId = 0;
1618 
1619  add_exact_object_address(&obj, objects);
1620  }
1621 
1622  performMultipleDeletions(objects, drop->behavior, flags);
1623 
1624  free_object_addresses(objects);
1625 }
1626 
1627 /*
1628  * Before acquiring a table lock, check whether we have sufficient rights.
1629  * In the case of DROP INDEX, also try to lock the table before the index.
1630  * Also, if the table to be dropped is a partition, we try to lock the parent
1631  * first.
1632  */
1633 static void
1634 RangeVarCallbackForDropRelation(const RangeVar *rel, Oid relOid, Oid oldRelOid,
1635  void *arg)
1636 {
1637  HeapTuple tuple;
1639  char expected_relkind;
1640  bool is_partition;
1641  Form_pg_class classform;
1643  bool invalid_system_index = false;
1644 
1645  state = (struct DropRelationCallbackState *) arg;
1646  heap_lockmode = state->heap_lockmode;
1647 
1648  /*
1649  * If we previously locked some other index's heap, and the name we're
1650  * looking up no longer refers to that relation, release the now-useless
1651  * lock.
1652  */
1653  if (relOid != oldRelOid && OidIsValid(state->heapOid))
1654  {
1656  state->heapOid = InvalidOid;
1657  }
1658 
1659  /*
1660  * Similarly, if we previously locked some other partition's heap, and the
1661  * name we're looking up no longer refers to that relation, release the
1662  * now-useless lock.
1663  */
1664  if (relOid != oldRelOid && OidIsValid(state->partParentOid))
1665  {
1666  UnlockRelationOid(state->partParentOid, AccessExclusiveLock);
1667  state->partParentOid = InvalidOid;
1668  }
1669 
1670  /* Didn't find a relation, so no need for locking or permission checks. */
1671  if (!OidIsValid(relOid))
1672  return;
1673 
1674  tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relOid));
1675  if (!HeapTupleIsValid(tuple))
1676  return; /* concurrently dropped, so nothing to do */
1677  classform = (Form_pg_class) GETSTRUCT(tuple);
1678  is_partition = classform->relispartition;
1679 
1680  /* Pass back some data to save lookups in RemoveRelations */
1681  state->actual_relkind = classform->relkind;
1682  state->actual_relpersistence = classform->relpersistence;
1683 
1684  /*
1685  * Both RELKIND_RELATION and RELKIND_PARTITIONED_TABLE are OBJECT_TABLE,
1686  * but RemoveRelations() can only pass one relkind for a given relation.
1687  * It chooses RELKIND_RELATION for both regular and partitioned tables.
1688  * That means we must be careful before giving the wrong type error when
1689  * the relation is RELKIND_PARTITIONED_TABLE. An equivalent problem
1690  * exists with indexes.
1691  */
1692  if (classform->relkind == RELKIND_PARTITIONED_TABLE)
1693  expected_relkind = RELKIND_RELATION;
1694  else if (classform->relkind == RELKIND_PARTITIONED_INDEX)
1695  expected_relkind = RELKIND_INDEX;
1696  else
1697  expected_relkind = classform->relkind;
1698 
1699  if (state->expected_relkind != expected_relkind)
1700  DropErrorMsgWrongType(rel->relname, classform->relkind,
1701  state->expected_relkind);
1702 
1703  /* Allow DROP to either table owner or schema owner */
1704  if (!object_ownercheck(RelationRelationId, relOid, GetUserId()) &&
1705  !object_ownercheck(NamespaceRelationId, classform->relnamespace, GetUserId()))
1707  get_relkind_objtype(classform->relkind),
1708  rel->relname);
1709 
1710  /*
1711  * Check the case of a system index that might have been invalidated by a
1712  * failed concurrent process and allow its drop. For the time being, this
1713  * only concerns indexes of toast relations that became invalid during a
1714  * REINDEX CONCURRENTLY process.
1715  */
1716  if (IsSystemClass(relOid, classform) && classform->relkind == RELKIND_INDEX)
1717  {
1718  HeapTuple locTuple;
1719  Form_pg_index indexform;
1720  bool indisvalid;
1721 
1722  locTuple = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(relOid));
1723  if (!HeapTupleIsValid(locTuple))
1724  {
1725  ReleaseSysCache(tuple);
1726  return;
1727  }
1728 
1729  indexform = (Form_pg_index) GETSTRUCT(locTuple);
1730  indisvalid = indexform->indisvalid;
1731  ReleaseSysCache(locTuple);
1732 
1733  /* Mark object as being an invalid index of system catalogs */
1734  if (!indisvalid)
1735  invalid_system_index = true;
1736  }
1737 
1738  /* In the case of an invalid index, it is fine to bypass this check */
1739  if (!invalid_system_index && !allowSystemTableMods && IsSystemClass(relOid, classform))
1740  ereport(ERROR,
1741  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1742  errmsg("permission denied: \"%s\" is a system catalog",
1743  rel->relname)));
1744 
1745  ReleaseSysCache(tuple);
1746 
1747  /*
1748  * In DROP INDEX, attempt to acquire lock on the parent table before
1749  * locking the index. index_drop() will need this anyway, and since
1750  * regular queries lock tables before their indexes, we risk deadlock if
1751  * we do it the other way around. No error if we don't find a pg_index
1752  * entry, though --- the relation may have been dropped. Note that this
1753  * code will execute for either plain or partitioned indexes.
1754  */
1755  if (expected_relkind == RELKIND_INDEX &&
1756  relOid != oldRelOid)
1757  {
1758  state->heapOid = IndexGetRelation(relOid, true);
1759  if (OidIsValid(state->heapOid))
1760  LockRelationOid(state->heapOid, heap_lockmode);
1761  }
1762 
1763  /*
1764  * Similarly, if the relation is a partition, we must acquire lock on its
1765  * parent before locking the partition. That's because queries lock the
1766  * parent before its partitions, so we risk deadlock if we do it the other
1767  * way around.
1768  */
1769  if (is_partition && relOid != oldRelOid)
1770  {
1771  state->partParentOid = get_partition_parent(relOid, true);
1772  if (OidIsValid(state->partParentOid))
1773  LockRelationOid(state->partParentOid, AccessExclusiveLock);
1774  }
1775 }
1776 
1777 /*
1778  * ExecuteTruncate
1779  * Executes a TRUNCATE command.
1780  *
1781  * This is a multi-relation truncate. We first open and grab exclusive
1782  * lock on all relations involved, checking permissions and otherwise
1783  * verifying that the relation is OK for truncation. Note that if relations
1784  * are foreign tables, at this stage, we have not yet checked that their
1785  * foreign data in external data sources are OK for truncation. These are
1786  * checked when foreign data are actually truncated later. In CASCADE mode,
1787  * relations having FK references to the targeted relations are automatically
1788  * added to the group; in RESTRICT mode, we check that all FK references are
1789  * internal to the group that's being truncated. Finally all the relations
1790  * are truncated and reindexed.
1791  */
1792 void
1794 {
1795  List *rels = NIL;
1796  List *relids = NIL;
1797  List *relids_logged = NIL;
1798  ListCell *cell;
1799 
1800  /*
1801  * Open, exclusive-lock, and check all the explicitly-specified relations
1802  */
1803  foreach(cell, stmt->relations)
1804  {
1805  RangeVar *rv = lfirst(cell);
1806  Relation rel;
1807  bool recurse = rv->inh;
1808  Oid myrelid;
1809  LOCKMODE lockmode = AccessExclusiveLock;
1810 
1811  myrelid = RangeVarGetRelidExtended(rv, lockmode,
1813  NULL);
1814 
1815  /* don't throw error for "TRUNCATE foo, foo" */
1816  if (list_member_oid(relids, myrelid))
1817  continue;
1818 
1819  /* open the relation, we already hold a lock on it */
1820  rel = table_open(myrelid, NoLock);
1821 
1822  /*
1823  * RangeVarGetRelidExtended() has done most checks with its callback,
1824  * but other checks with the now-opened Relation remain.
1825  */
1827 
1828  rels = lappend(rels, rel);
1829  relids = lappend_oid(relids, myrelid);
1830 
1831  /* Log this relation only if needed for logical decoding */
1832  if (RelationIsLogicallyLogged(rel))
1833  relids_logged = lappend_oid(relids_logged, myrelid);
1834 
1835  if (recurse)
1836  {
1837  ListCell *child;
1838  List *children;
1839 
1840  children = find_all_inheritors(myrelid, lockmode, NULL);
1841 
1842  foreach(child, children)
1843  {
1844  Oid childrelid = lfirst_oid(child);
1845 
1846  if (list_member_oid(relids, childrelid))
1847  continue;
1848 
1849  /* find_all_inheritors already got lock */
1850  rel = table_open(childrelid, NoLock);
1851 
1852  /*
1853  * It is possible that the parent table has children that are
1854  * temp tables of other backends. We cannot safely access
1855  * such tables (because of buffering issues), and the best
1856  * thing to do is to silently ignore them. Note that this
1857  * check is the same as one of the checks done in
1858  * truncate_check_activity() called below, still it is kept
1859  * here for simplicity.
1860  */
1861  if (RELATION_IS_OTHER_TEMP(rel))
1862  {
1863  table_close(rel, lockmode);
1864  continue;
1865  }
1866 
1867  /*
1868  * Inherited TRUNCATE commands perform access permission
1869  * checks on the parent table only. So we skip checking the
1870  * children's permissions and don't call
1871  * truncate_check_perms() here.
1872  */
1875 
1876  rels = lappend(rels, rel);
1877  relids = lappend_oid(relids, childrelid);
1878 
1879  /* Log this relation only if needed for logical decoding */
1880  if (RelationIsLogicallyLogged(rel))
1881  relids_logged = lappend_oid(relids_logged, childrelid);
1882  }
1883  }
1884  else if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
1885  ereport(ERROR,
1886  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1887  errmsg("cannot truncate only a partitioned table"),
1888  errhint("Do not specify the ONLY keyword, or use TRUNCATE ONLY on the partitions directly.")));
1889  }
1890 
1891  ExecuteTruncateGuts(rels, relids, relids_logged,
1892  stmt->behavior, stmt->restart_seqs, false);
1893 
1894  /* And close the rels */
1895  foreach(cell, rels)
1896  {
1897  Relation rel = (Relation) lfirst(cell);
1898 
1899  table_close(rel, NoLock);
1900  }
1901 }
1902 
1903 /*
1904  * ExecuteTruncateGuts
1905  *
1906  * Internal implementation of TRUNCATE. This is called by the actual TRUNCATE
1907  * command (see above) as well as replication subscribers that execute a
1908  * replicated TRUNCATE action.
1909  *
1910  * explicit_rels is the list of Relations to truncate that the command
1911  * specified. relids is the list of Oids corresponding to explicit_rels.
1912  * relids_logged is the list of Oids (a subset of relids) that require
1913  * WAL-logging. This is all a bit redundant, but the existing callers have
1914  * this information handy in this form.
1915  */
1916 void
1917 ExecuteTruncateGuts(List *explicit_rels,
1918  List *relids,
1919  List *relids_logged,
1920  DropBehavior behavior, bool restart_seqs,
1921  bool run_as_table_owner)
1922 {
1923  List *rels;
1924  List *seq_relids = NIL;
1925  HTAB *ft_htab = NULL;
1926  EState *estate;
1927  ResultRelInfo *resultRelInfos;
1928  ResultRelInfo *resultRelInfo;
1929  SubTransactionId mySubid;
1930  ListCell *cell;
1931  Oid *logrelids;
1932 
1933  /*
1934  * Check the explicitly-specified relations.
1935  *
1936  * In CASCADE mode, suck in all referencing relations as well. This
1937  * requires multiple iterations to find indirectly-dependent relations. At
1938  * each phase, we need to exclusive-lock new rels before looking for their
1939  * dependencies, else we might miss something. Also, we check each rel as
1940  * soon as we open it, to avoid a faux pas such as holding lock for a long
1941  * time on a rel we have no permissions for.
1942  */
1943  rels = list_copy(explicit_rels);
1944  if (behavior == DROP_CASCADE)
1945  {
1946  for (;;)
1947  {
1948  List *newrelids;
1949 
1950  newrelids = heap_truncate_find_FKs(relids);
1951  if (newrelids == NIL)
1952  break; /* nothing else to add */
1953 
1954  foreach(cell, newrelids)
1955  {
1956  Oid relid = lfirst_oid(cell);
1957  Relation rel;
1958 
1959  rel = table_open(relid, AccessExclusiveLock);
1960  ereport(NOTICE,
1961  (errmsg("truncate cascades to table \"%s\"",
1962  RelationGetRelationName(rel))));
1963  truncate_check_rel(relid, rel->rd_rel);
1964  truncate_check_perms(relid, rel->rd_rel);
1966  rels = lappend(rels, rel);
1967  relids = lappend_oid(relids, relid);
1968 
1969  /* Log this relation only if needed for logical decoding */
1970  if (RelationIsLogicallyLogged(rel))
1971  relids_logged = lappend_oid(relids_logged, relid);
1972  }
1973  }
1974  }
1975 
1976  /*
1977  * Check foreign key references. In CASCADE mode, this should be
1978  * unnecessary since we just pulled in all the references; but as a
1979  * cross-check, do it anyway if in an Assert-enabled build.
1980  */
1981 #ifdef USE_ASSERT_CHECKING
1982  heap_truncate_check_FKs(rels, false);
1983 #else
1984  if (behavior == DROP_RESTRICT)
1985  heap_truncate_check_FKs(rels, false);
1986 #endif
1987 
1988  /*
1989  * If we are asked to restart sequences, find all the sequences, lock them
1990  * (we need AccessExclusiveLock for ResetSequence), and check permissions.
1991  * We want to do this early since it's pointless to do all the truncation
1992  * work only to fail on sequence permissions.
1993  */
1994  if (restart_seqs)
1995  {
1996  foreach(cell, rels)
1997  {
1998  Relation rel = (Relation) lfirst(cell);
1999  List *seqlist = getOwnedSequences(RelationGetRelid(rel));
2000  ListCell *seqcell;
2001 
2002  foreach(seqcell, seqlist)
2003  {
2004  Oid seq_relid = lfirst_oid(seqcell);
2005  Relation seq_rel;
2006 
2007  seq_rel = relation_open(seq_relid, AccessExclusiveLock);
2008 
2009  /* This check must match AlterSequence! */
2010  if (!object_ownercheck(RelationRelationId, seq_relid, GetUserId()))
2012  RelationGetRelationName(seq_rel));
2013 
2014  seq_relids = lappend_oid(seq_relids, seq_relid);
2015 
2016  relation_close(seq_rel, NoLock);
2017  }
2018  }
2019  }
2020 
2021  /* Prepare to catch AFTER triggers. */
2023 
2024  /*
2025  * To fire triggers, we'll need an EState as well as a ResultRelInfo for
2026  * each relation. We don't need to call ExecOpenIndices, though.
2027  *
2028  * We put the ResultRelInfos in the es_opened_result_relations list, even
2029  * though we don't have a range table and don't populate the
2030  * es_result_relations array. That's a bit bogus, but it's enough to make
2031  * ExecGetTriggerResultRel() find them.
2032  */
2033  estate = CreateExecutorState();
2034  resultRelInfos = (ResultRelInfo *)
2035  palloc(list_length(rels) * sizeof(ResultRelInfo));
2036  resultRelInfo = resultRelInfos;
2037  foreach(cell, rels)
2038  {
2039  Relation rel = (Relation) lfirst(cell);
2040 
2041  InitResultRelInfo(resultRelInfo,
2042  rel,
2043  0, /* dummy rangetable index */
2044  NULL,
2045  0);
2046  estate->es_opened_result_relations =
2047  lappend(estate->es_opened_result_relations, resultRelInfo);
2048  resultRelInfo++;
2049  }
2050 
2051  /*
2052  * Process all BEFORE STATEMENT TRUNCATE triggers before we begin
2053  * truncating (this is because one of them might throw an error). Also, if
2054  * we were to allow them to prevent statement execution, that would need
2055  * to be handled here.
2056  */
2057  resultRelInfo = resultRelInfos;
2058  foreach(cell, rels)
2059  {
2060  UserContext ucxt;
2061 
2062  if (run_as_table_owner)
2063  SwitchToUntrustedUser(resultRelInfo->ri_RelationDesc->rd_rel->relowner,
2064  &ucxt);
2065  ExecBSTruncateTriggers(estate, resultRelInfo);
2066  if (run_as_table_owner)
2067  RestoreUserContext(&ucxt);
2068  resultRelInfo++;
2069  }
2070 
2071  /*
2072  * OK, truncate each table.
2073  */
2074  mySubid = GetCurrentSubTransactionId();
2075 
2076  foreach(cell, rels)
2077  {
2078  Relation rel = (Relation) lfirst(cell);
2079 
2080  /* Skip partitioned tables as there is nothing to do */
2081  if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
2082  continue;
2083 
2084  /*
2085  * Build the lists of foreign tables belonging to each foreign server
2086  * and pass each list to the foreign data wrapper's callback function,
2087  * so that each server can truncate its all foreign tables in bulk.
2088  * Each list is saved as a single entry in a hash table that uses the
2089  * server OID as lookup key.
2090  */
2091  if (rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
2092  {
2094  bool found;
2095  ForeignTruncateInfo *ft_info;
2096 
2097  /* First time through, initialize hashtable for foreign tables */
2098  if (!ft_htab)
2099  {
2100  HASHCTL hctl;
2101 
2102  memset(&hctl, 0, sizeof(HASHCTL));
2103  hctl.keysize = sizeof(Oid);
2104  hctl.entrysize = sizeof(ForeignTruncateInfo);
2105  hctl.hcxt = CurrentMemoryContext;
2106 
2107  ft_htab = hash_create("TRUNCATE for Foreign Tables",
2108  32, /* start small and extend */
2109  &hctl,
2111  }
2112 
2113  /* Find or create cached entry for the foreign table */
2114  ft_info = hash_search(ft_htab, &serverid, HASH_ENTER, &found);
2115  if (!found)
2116  ft_info->rels = NIL;
2117 
2118  /*
2119  * Save the foreign table in the entry of the server that the
2120  * foreign table belongs to.
2121  */
2122  ft_info->rels = lappend(ft_info->rels, rel);
2123  continue;
2124  }
2125 
2126  /*
2127  * Normally, we need a transaction-safe truncation here. However, if
2128  * the table was either created in the current (sub)transaction or has
2129  * a new relfilenumber in the current (sub)transaction, then we can
2130  * just truncate it in-place, because a rollback would cause the whole
2131  * table or the current physical file to be thrown away anyway.
2132  */
2133  if (rel->rd_createSubid == mySubid ||
2134  rel->rd_newRelfilelocatorSubid == mySubid)
2135  {
2136  /* Immediate, non-rollbackable truncation is OK */
2137  heap_truncate_one_rel(rel);
2138  }
2139  else
2140  {
2141  Oid heap_relid;
2142  Oid toast_relid;
2143  ReindexParams reindex_params = {0};
2144 
2145  /*
2146  * This effectively deletes all rows in the table, and may be done
2147  * in a serializable transaction. In that case we must record a
2148  * rw-conflict in to this transaction from each transaction
2149  * holding a predicate lock on the table.
2150  */
2152 
2153  /*
2154  * Need the full transaction-safe pushups.
2155  *
2156  * Create a new empty storage file for the relation, and assign it
2157  * as the relfilenumber value. The old storage file is scheduled
2158  * for deletion at commit.
2159  */
2160  RelationSetNewRelfilenumber(rel, rel->rd_rel->relpersistence);
2161 
2162  heap_relid = RelationGetRelid(rel);
2163 
2164  /*
2165  * The same for the toast table, if any.
2166  */
2167  toast_relid = rel->rd_rel->reltoastrelid;
2168  if (OidIsValid(toast_relid))
2169  {
2170  Relation toastrel = relation_open(toast_relid,
2172 
2173  RelationSetNewRelfilenumber(toastrel,
2174  toastrel->rd_rel->relpersistence);
2175  table_close(toastrel, NoLock);
2176  }
2177 
2178  /*
2179  * Reconstruct the indexes to match, and we're done.
2180  */
2181  reindex_relation(NULL, heap_relid, REINDEX_REL_PROCESS_TOAST,
2182  &reindex_params);
2183  }
2184 
2185  pgstat_count_truncate(rel);
2186  }
2187 
2188  /* Now go through the hash table, and truncate foreign tables */
2189  if (ft_htab)
2190  {
2191  ForeignTruncateInfo *ft_info;
2192  HASH_SEQ_STATUS seq;
2193 
2194  hash_seq_init(&seq, ft_htab);
2195 
2196  PG_TRY();
2197  {
2198  while ((ft_info = hash_seq_search(&seq)) != NULL)
2199  {
2200  FdwRoutine *routine = GetFdwRoutineByServerId(ft_info->serverid);
2201 
2202  /* truncate_check_rel() has checked that already */
2203  Assert(routine->ExecForeignTruncate != NULL);
2204 
2205  routine->ExecForeignTruncate(ft_info->rels,
2206  behavior,
2207  restart_seqs);
2208  }
2209  }
2210  PG_FINALLY();
2211  {
2212  hash_destroy(ft_htab);
2213  }
2214  PG_END_TRY();
2215  }
2216 
2217  /*
2218  * Restart owned sequences if we were asked to.
2219  */
2220  foreach(cell, seq_relids)
2221  {
2222  Oid seq_relid = lfirst_oid(cell);
2223 
2224  ResetSequence(seq_relid);
2225  }
2226 
2227  /*
2228  * Write a WAL record to allow this set of actions to be logically
2229  * decoded.
2230  *
2231  * Assemble an array of relids so we can write a single WAL record for the
2232  * whole action.
2233  */
2234  if (relids_logged != NIL)
2235  {
2236  xl_heap_truncate xlrec;
2237  int i = 0;
2238 
2239  /* should only get here if wal_level >= logical */
2241 
2242  logrelids = palloc(list_length(relids_logged) * sizeof(Oid));
2243  foreach(cell, relids_logged)
2244  logrelids[i++] = lfirst_oid(cell);
2245 
2246  xlrec.dbId = MyDatabaseId;
2247  xlrec.nrelids = list_length(relids_logged);
2248  xlrec.flags = 0;
2249  if (behavior == DROP_CASCADE)
2250  xlrec.flags |= XLH_TRUNCATE_CASCADE;
2251  if (restart_seqs)
2253 
2254  XLogBeginInsert();
2255  XLogRegisterData((char *) &xlrec, SizeOfHeapTruncate);
2256  XLogRegisterData((char *) logrelids, list_length(relids_logged) * sizeof(Oid));
2257 
2259 
2260  (void) XLogInsert(RM_HEAP_ID, XLOG_HEAP_TRUNCATE);
2261  }
2262 
2263  /*
2264  * Process all AFTER STATEMENT TRUNCATE triggers.
2265  */
2266  resultRelInfo = resultRelInfos;
2267  foreach(cell, rels)
2268  {
2269  UserContext ucxt;
2270 
2271  if (run_as_table_owner)
2272  SwitchToUntrustedUser(resultRelInfo->ri_RelationDesc->rd_rel->relowner,
2273  &ucxt);
2274  ExecASTruncateTriggers(estate, resultRelInfo);
2275  if (run_as_table_owner)
2276  RestoreUserContext(&ucxt);
2277  resultRelInfo++;
2278  }
2279 
2280  /* Handle queued AFTER triggers */
2281  AfterTriggerEndQuery(estate);
2282 
2283  /* We can clean up the EState now */
2284  FreeExecutorState(estate);
2285 
2286  /*
2287  * Close any rels opened by CASCADE (can't do this while EState still
2288  * holds refs)
2289  */
2290  rels = list_difference_ptr(rels, explicit_rels);
2291  foreach(cell, rels)
2292  {
2293  Relation rel = (Relation) lfirst(cell);
2294 
2295  table_close(rel, NoLock);
2296  }
2297 }
2298 
2299 /*
2300  * Check that a given relation is safe to truncate. Subroutine for
2301  * ExecuteTruncate() and RangeVarCallbackForTruncate().
2302  */
2303 static void
2305 {
2306  char *relname = NameStr(reltuple->relname);
2307 
2308  /*
2309  * Only allow truncate on regular tables, foreign tables using foreign
2310  * data wrappers supporting TRUNCATE and partitioned tables (although, the
2311  * latter are only being included here for the following checks; no
2312  * physical truncation will occur in their case.).
2313  */
2314  if (reltuple->relkind == RELKIND_FOREIGN_TABLE)
2315  {
2316  Oid serverid = GetForeignServerIdByRelId(relid);
2317  FdwRoutine *fdwroutine = GetFdwRoutineByServerId(serverid);
2318 
2319  if (!fdwroutine->ExecForeignTruncate)
2320  ereport(ERROR,
2321  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2322  errmsg("cannot truncate foreign table \"%s\"",
2323  relname)));
2324  }
2325  else if (reltuple->relkind != RELKIND_RELATION &&
2326  reltuple->relkind != RELKIND_PARTITIONED_TABLE)
2327  ereport(ERROR,
2328  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2329  errmsg("\"%s\" is not a table", relname)));
2330 
2331  /*
2332  * Most system catalogs can't be truncated at all, or at least not unless
2333  * allow_system_table_mods=on. As an exception, however, we allow
2334  * pg_largeobject to be truncated as part of pg_upgrade, because we need
2335  * to change its relfilenode to match the old cluster, and allowing a
2336  * TRUNCATE command to be executed is the easiest way of doing that.
2337  */
2338  if (!allowSystemTableMods && IsSystemClass(relid, reltuple)
2339  && (!IsBinaryUpgrade || relid != LargeObjectRelationId))
2340  ereport(ERROR,
2341  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
2342  errmsg("permission denied: \"%s\" is a system catalog",
2343  relname)));
2344 
2345  InvokeObjectTruncateHook(relid);
2346 }
2347 
2348 /*
2349  * Check that current user has the permission to truncate given relation.
2350  */
2351 static void
2353 {
2354  char *relname = NameStr(reltuple->relname);
2355  AclResult aclresult;
2356 
2357  /* Permissions checks */
2358  aclresult = pg_class_aclcheck(relid, GetUserId(), ACL_TRUNCATE);
2359  if (aclresult != ACLCHECK_OK)
2360  aclcheck_error(aclresult, get_relkind_objtype(reltuple->relkind),
2361  relname);
2362 }
2363 
2364 /*
2365  * Set of extra sanity checks to check if a given relation is safe to
2366  * truncate. This is split with truncate_check_rel() as
2367  * RangeVarCallbackForTruncate() cannot open a Relation yet.
2368  */
2369 static void
2371 {
2372  /*
2373  * Don't allow truncate on temp tables of other backends ... their local
2374  * buffer manager is not going to cope.
2375  */
2376  if (RELATION_IS_OTHER_TEMP(rel))
2377  ereport(ERROR,
2378  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2379  errmsg("cannot truncate temporary tables of other sessions")));
2380 
2381  /*
2382  * Also check for active uses of the relation in the current transaction,
2383  * including open scans and pending AFTER trigger events.
2384  */
2385  CheckTableNotInUse(rel, "TRUNCATE");
2386 }
2387 
2388 /*
2389  * storage_name
2390  * returns the name corresponding to a typstorage/attstorage enum value
2391  */
2392 static const char *
2394 {
2395  switch (c)
2396  {
2397  case TYPSTORAGE_PLAIN:
2398  return "PLAIN";
2399  case TYPSTORAGE_EXTERNAL:
2400  return "EXTERNAL";
2401  case TYPSTORAGE_EXTENDED:
2402  return "EXTENDED";
2403  case TYPSTORAGE_MAIN:
2404  return "MAIN";
2405  default:
2406  return "???";
2407  }
2408 }
2409 
2410 /*----------
2411  * MergeAttributes
2412  * Returns new schema given initial schema and superclasses.
2413  *
2414  * Input arguments:
2415  * 'columns' is the column/attribute definition for the table. (It's a list
2416  * of ColumnDef's.) It is destructively changed.
2417  * 'supers' is a list of OIDs of parent relations, already locked by caller.
2418  * 'relpersistence' is the persistence type of the table.
2419  * 'is_partition' tells if the table is a partition.
2420  *
2421  * Output arguments:
2422  * 'supconstr' receives a list of constraints belonging to the parents,
2423  * updated as necessary to be valid for the child.
2424  * 'supnotnulls' receives a list of CookedConstraints that corresponds to
2425  * constraints coming from inheritance parents.
2426  *
2427  * Return value:
2428  * Completed schema list.
2429  *
2430  * Notes:
2431  * The order in which the attributes are inherited is very important.
2432  * Intuitively, the inherited attributes should come first. If a table
2433  * inherits from multiple parents, the order of those attributes are
2434  * according to the order of the parents specified in CREATE TABLE.
2435  *
2436  * Here's an example:
2437  *
2438  * create table person (name text, age int4, location point);
2439  * create table emp (salary int4, manager text) inherits(person);
2440  * create table student (gpa float8) inherits (person);
2441  * create table stud_emp (percent int4) inherits (emp, student);
2442  *
2443  * The order of the attributes of stud_emp is:
2444  *
2445  * person {1:name, 2:age, 3:location}
2446  * / \
2447  * {6:gpa} student emp {4:salary, 5:manager}
2448  * \ /
2449  * stud_emp {7:percent}
2450  *
2451  * If the same attribute name appears multiple times, then it appears
2452  * in the result table in the proper location for its first appearance.
2453  *
2454  * Constraints (including not-null constraints) for the child table
2455  * are the union of all relevant constraints, from both the child schema
2456  * and parent tables. In addition, in legacy inheritance, each column that
2457  * appears in a primary key in any of the parents also gets a NOT NULL
2458  * constraint (partitioning doesn't need this, because the PK itself gets
2459  * inherited.)
2460  *
2461  * The default value for a child column is defined as:
2462  * (1) If the child schema specifies a default, that value is used.
2463  * (2) If neither the child nor any parent specifies a default, then
2464  * the column will not have a default.
2465  * (3) If conflicting defaults are inherited from different parents
2466  * (and not overridden by the child), an error is raised.
2467  * (4) Otherwise the inherited default is used.
2468  *
2469  * Note that the default-value infrastructure is used for generated
2470  * columns' expressions too, so most of the preceding paragraph applies
2471  * to generation expressions too. We insist that a child column be
2472  * generated if and only if its parent(s) are, but it need not have
2473  * the same generation expression.
2474  *----------
2475  */
2476 static List *
2477 MergeAttributes(List *columns, const List *supers, char relpersistence,
2478  bool is_partition, List **supconstr, List **supnotnulls)
2479 {
2480  List *inh_columns = NIL;
2481  List *constraints = NIL;
2482  List *nnconstraints = NIL;
2483  bool have_bogus_defaults = false;
2484  int child_attno;
2485  static Node bogus_marker = {0}; /* marks conflicting defaults */
2486  List *saved_columns = NIL;
2487  ListCell *lc;
2488 
2489  /*
2490  * Check for and reject tables with too many columns. We perform this
2491  * check relatively early for two reasons: (a) we don't run the risk of
2492  * overflowing an AttrNumber in subsequent code (b) an O(n^2) algorithm is
2493  * okay if we're processing <= 1600 columns, but could take minutes to
2494  * execute if the user attempts to create a table with hundreds of
2495  * thousands of columns.
2496  *
2497  * Note that we also need to check that we do not exceed this figure after
2498  * including columns from inherited relations.
2499  */
2500  if (list_length(columns) > MaxHeapAttributeNumber)
2501  ereport(ERROR,
2502  (errcode(ERRCODE_TOO_MANY_COLUMNS),
2503  errmsg("tables can have at most %d columns",
2505 
2506  /*
2507  * Check for duplicate names in the explicit list of attributes.
2508  *
2509  * Although we might consider merging such entries in the same way that we
2510  * handle name conflicts for inherited attributes, it seems to make more
2511  * sense to assume such conflicts are errors.
2512  *
2513  * We don't use foreach() here because we have two nested loops over the
2514  * columns list, with possible element deletions in the inner one. If we
2515  * used foreach_delete_current() it could only fix up the state of one of
2516  * the loops, so it seems cleaner to use looping over list indexes for
2517  * both loops. Note that any deletion will happen beyond where the outer
2518  * loop is, so its index never needs adjustment.
2519  */
2520  for (int coldefpos = 0; coldefpos < list_length(columns); coldefpos++)
2521  {
2522  ColumnDef *coldef = list_nth_node(ColumnDef, columns, coldefpos);
2523 
2524  if (!is_partition && coldef->typeName == NULL)
2525  {
2526  /*
2527  * Typed table column option that does not belong to a column from
2528  * the type. This works because the columns from the type come
2529  * first in the list. (We omit this check for partition column
2530  * lists; those are processed separately below.)
2531  */
2532  ereport(ERROR,
2533  (errcode(ERRCODE_UNDEFINED_COLUMN),
2534  errmsg("column \"%s\" does not exist",
2535  coldef->colname)));
2536  }
2537 
2538  /* restpos scans all entries beyond coldef; incr is in loop body */
2539  for (int restpos = coldefpos + 1; restpos < list_length(columns);)
2540  {
2541  ColumnDef *restdef = list_nth_node(ColumnDef, columns, restpos);
2542 
2543  if (strcmp(coldef->colname, restdef->colname) == 0)
2544  {
2545  if (coldef->is_from_type)
2546  {
2547  /*
2548  * merge the column options into the column from the type
2549  */
2550  coldef->is_not_null = restdef->is_not_null;
2551  coldef->raw_default = restdef->raw_default;
2552  coldef->cooked_default = restdef->cooked_default;
2553  coldef->constraints = restdef->constraints;
2554  coldef->is_from_type = false;
2555  columns = list_delete_nth_cell(columns, restpos);
2556  }
2557  else
2558  ereport(ERROR,
2559  (errcode(ERRCODE_DUPLICATE_COLUMN),
2560  errmsg("column \"%s\" specified more than once",
2561  coldef->colname)));
2562  }
2563  else
2564  restpos++;
2565  }
2566  }
2567 
2568  /*
2569  * In case of a partition, there are no new column definitions, only dummy
2570  * ColumnDefs created for column constraints. Set them aside for now and
2571  * process them at the end.
2572  */
2573  if (is_partition)
2574  {
2575  saved_columns = columns;
2576  columns = NIL;
2577  }
2578 
2579  /*
2580  * Scan the parents left-to-right, and merge their attributes to form a
2581  * list of inherited columns (inh_columns).
2582  */
2583  child_attno = 0;
2584  foreach(lc, supers)
2585  {
2586  Oid parent = lfirst_oid(lc);
2587  Relation relation;
2588  TupleDesc tupleDesc;
2589  TupleConstr *constr;
2590  AttrMap *newattmap;
2591  List *inherited_defaults;
2592  List *cols_with_defaults;
2593  List *nnconstrs;
2594  ListCell *lc1;
2595  ListCell *lc2;
2596  Bitmapset *pkattrs;
2597  Bitmapset *nncols = NULL;
2598 
2599  /* caller already got lock */
2600  relation = table_open(parent, NoLock);
2601 
2602  /*
2603  * Check for active uses of the parent partitioned table in the
2604  * current transaction, such as being used in some manner by an
2605  * enclosing command.
2606  */
2607  if (is_partition)
2608  CheckTableNotInUse(relation, "CREATE TABLE .. PARTITION OF");
2609 
2610  /*
2611  * We do not allow partitioned tables and partitions to participate in
2612  * regular inheritance.
2613  */
2614  if (relation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE && !is_partition)
2615  ereport(ERROR,
2616  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2617  errmsg("cannot inherit from partitioned table \"%s\"",
2618  RelationGetRelationName(relation))));
2619  if (relation->rd_rel->relispartition && !is_partition)
2620  ereport(ERROR,
2621  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2622  errmsg("cannot inherit from partition \"%s\"",
2623  RelationGetRelationName(relation))));
2624 
2625  if (relation->rd_rel->relkind != RELKIND_RELATION &&
2626  relation->rd_rel->relkind != RELKIND_FOREIGN_TABLE &&
2627  relation->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
2628  ereport(ERROR,
2629  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2630  errmsg("inherited relation \"%s\" is not a table or foreign table",
2631  RelationGetRelationName(relation))));
2632 
2633  /*
2634  * If the parent is permanent, so must be all of its partitions. Note
2635  * that inheritance allows that case.
2636  */
2637  if (is_partition &&
2638  relation->rd_rel->relpersistence != RELPERSISTENCE_TEMP &&
2639  relpersistence == RELPERSISTENCE_TEMP)
2640  ereport(ERROR,
2641  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2642  errmsg("cannot create a temporary relation as partition of permanent relation \"%s\"",
2643  RelationGetRelationName(relation))));
2644 
2645  /* Permanent rels cannot inherit from temporary ones */
2646  if (relpersistence != RELPERSISTENCE_TEMP &&
2647  relation->rd_rel->relpersistence == RELPERSISTENCE_TEMP)
2648  ereport(ERROR,
2649  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2650  errmsg(!is_partition
2651  ? "cannot inherit from temporary relation \"%s\""
2652  : "cannot create a permanent relation as partition of temporary relation \"%s\"",
2653  RelationGetRelationName(relation))));
2654 
2655  /* If existing rel is temp, it must belong to this session */
2656  if (relation->rd_rel->relpersistence == RELPERSISTENCE_TEMP &&
2657  !relation->rd_islocaltemp)
2658  ereport(ERROR,
2659  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2660  errmsg(!is_partition
2661  ? "cannot inherit from temporary relation of another session"
2662  : "cannot create as partition of temporary relation of another session")));
2663 
2664  /*
2665  * We should have an UNDER permission flag for this, but for now,
2666  * demand that creator of a child table own the parent.
2667  */
2668  if (!object_ownercheck(RelationRelationId, RelationGetRelid(relation), GetUserId()))
2670  RelationGetRelationName(relation));
2671 
2672  tupleDesc = RelationGetDescr(relation);
2673  constr = tupleDesc->constr;
2674 
2675  /*
2676  * newattmap->attnums[] will contain the child-table attribute numbers
2677  * for the attributes of this parent table. (They are not the same
2678  * for parents after the first one, nor if we have dropped columns.)
2679  */
2680  newattmap = make_attrmap(tupleDesc->natts);
2681 
2682  /* We can't process inherited defaults until newattmap is complete. */
2683  inherited_defaults = cols_with_defaults = NIL;
2684 
2685  /*
2686  * All columns that are part of the parent's primary key need to be
2687  * NOT NULL; if partition just the attnotnull bit, otherwise a full
2688  * constraint (if they don't have one already). Also, we request
2689  * attnotnull on columns that have a not-null constraint that's not
2690  * marked NO INHERIT.
2691  */
2692  pkattrs = RelationGetIndexAttrBitmap(relation,
2694  nnconstrs = RelationGetNotNullConstraints(RelationGetRelid(relation), true);
2695  foreach(lc1, nnconstrs)
2696  nncols = bms_add_member(nncols,
2697  ((CookedConstraint *) lfirst(lc1))->attnum);
2698 
2699  for (AttrNumber parent_attno = 1; parent_attno <= tupleDesc->natts;
2700  parent_attno++)
2701  {
2702  Form_pg_attribute attribute = TupleDescAttr(tupleDesc,
2703  parent_attno - 1);
2704  char *attributeName = NameStr(attribute->attname);
2705  int exist_attno;
2706  ColumnDef *newdef;
2707  ColumnDef *mergeddef;
2708 
2709  /*
2710  * Ignore dropped columns in the parent.
2711  */
2712  if (attribute->attisdropped)
2713  continue; /* leave newattmap->attnums entry as zero */
2714 
2715  /*
2716  * Create new column definition
2717  */
2718  newdef = makeColumnDef(attributeName, attribute->atttypid,
2719  attribute->atttypmod, attribute->attcollation);
2720  newdef->storage = attribute->attstorage;
2721  newdef->generated = attribute->attgenerated;
2722  if (CompressionMethodIsValid(attribute->attcompression))
2723  newdef->compression =
2724  pstrdup(GetCompressionMethodName(attribute->attcompression));
2725 
2726  /*
2727  * Regular inheritance children are independent enough not to
2728  * inherit identity columns. But partitions are integral part of
2729  * a partitioned table and inherit identity column.
2730  */
2731  if (is_partition)
2732  newdef->identity = attribute->attidentity;
2733 
2734  /*
2735  * Does it match some previously considered column from another
2736  * parent?
2737  */
2738  exist_attno = findAttrByName(attributeName, inh_columns);
2739  if (exist_attno > 0)
2740  {
2741  /*
2742  * Yes, try to merge the two column definitions.
2743  */
2744  mergeddef = MergeInheritedAttribute(inh_columns, exist_attno, newdef);
2745 
2746  newattmap->attnums[parent_attno - 1] = exist_attno;
2747 
2748  /*
2749  * Partitions have only one parent, so conflict should never
2750  * occur.
2751  */
2752  Assert(!is_partition);
2753  }
2754  else
2755  {
2756  /*
2757  * No, create a new inherited column
2758  */
2759  newdef->inhcount = 1;
2760  newdef->is_local = false;
2761  inh_columns = lappend(inh_columns, newdef);
2762 
2763  newattmap->attnums[parent_attno - 1] = ++child_attno;
2764 
2765  mergeddef = newdef;
2766  }
2767 
2768  /*
2769  * mark attnotnull if parent has it and it's not NO INHERIT
2770  */
2771  if (bms_is_member(parent_attno, nncols) ||
2773  pkattrs))
2774  mergeddef->is_not_null = true;
2775 
2776  /*
2777  * In regular inheritance, columns in the parent's primary key get
2778  * an extra not-null constraint. Partitioning doesn't need this,
2779  * because the PK itself is going to be cloned to the partition.
2780  */
2781  if (!is_partition &&
2782  bms_is_member(parent_attno -
2784  pkattrs))
2785  {
2786  CookedConstraint *nn;
2787 
2788  nn = palloc(sizeof(CookedConstraint));
2789  nn->contype = CONSTR_NOTNULL;
2790  nn->conoid = InvalidOid;
2791  nn->name = NULL;
2792  nn->attnum = newattmap->attnums[parent_attno - 1];
2793  nn->expr = NULL;
2794  nn->skip_validation = false;
2795  nn->is_local = false;
2796  nn->inhcount = 1;
2797  nn->is_no_inherit = false;
2798 
2799  nnconstraints = lappend(nnconstraints, nn);
2800  }
2801 
2802  /*
2803  * Locate default/generation expression if any
2804  */
2805  if (attribute->atthasdef)
2806  {
2807  Node *this_default;
2808 
2809  this_default = TupleDescGetDefault(tupleDesc, parent_attno);
2810  if (this_default == NULL)
2811  elog(ERROR, "default expression not found for attribute %d of relation \"%s\"",
2812  parent_attno, RelationGetRelationName(relation));
2813 
2814  /*
2815  * If it's a GENERATED default, it might contain Vars that
2816  * need to be mapped to the inherited column(s)' new numbers.
2817  * We can't do that till newattmap is ready, so just remember
2818  * all the inherited default expressions for the moment.
2819  */
2820  inherited_defaults = lappend(inherited_defaults, this_default);
2821  cols_with_defaults = lappend(cols_with_defaults, mergeddef);
2822  }
2823  }
2824 
2825  /*
2826  * Now process any inherited default expressions, adjusting attnos
2827  * using the completed newattmap map.
2828  */
2829  forboth(lc1, inherited_defaults, lc2, cols_with_defaults)
2830  {
2831  Node *this_default = (Node *) lfirst(lc1);
2832  ColumnDef *def = (ColumnDef *) lfirst(lc2);
2833  bool found_whole_row;
2834 
2835  /* Adjust Vars to match new table's column numbering */
2836  this_default = map_variable_attnos(this_default,
2837  1, 0,
2838  newattmap,
2839  InvalidOid, &found_whole_row);
2840 
2841  /*
2842  * For the moment we have to reject whole-row variables. We could
2843  * convert them, if we knew the new table's rowtype OID, but that
2844  * hasn't been assigned yet. (A variable could only appear in a
2845  * generation expression, so the error message is correct.)
2846  */
2847  if (found_whole_row)
2848  ereport(ERROR,
2849  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2850  errmsg("cannot convert whole-row table reference"),
2851  errdetail("Generation expression for column \"%s\" contains a whole-row reference to table \"%s\".",
2852  def->colname,
2853  RelationGetRelationName(relation))));
2854 
2855  /*
2856  * If we already had a default from some prior parent, check to
2857  * see if they are the same. If so, no problem; if not, mark the
2858  * column as having a bogus default. Below, we will complain if
2859  * the bogus default isn't overridden by the child columns.
2860  */
2861  Assert(def->raw_default == NULL);
2862  if (def->cooked_default == NULL)
2863  def->cooked_default = this_default;
2864  else if (!equal(def->cooked_default, this_default))
2865  {
2866  def->cooked_default = &bogus_marker;
2867  have_bogus_defaults = true;
2868  }
2869  }
2870 
2871  /*
2872  * Now copy the CHECK constraints of this parent, adjusting attnos
2873  * using the completed newattmap map. Identically named constraints
2874  * are merged if possible, else we throw error.
2875  */
2876  if (constr && constr->num_check > 0)
2877  {
2878  ConstrCheck *check = constr->check;
2879 
2880  for (int i = 0; i < constr->num_check; i++)
2881  {
2882  char *name = check[i].ccname;
2883  Node *expr;
2884  bool found_whole_row;
2885 
2886  /* ignore if the constraint is non-inheritable */
2887  if (check[i].ccnoinherit)
2888  continue;
2889 
2890  /* Adjust Vars to match new table's column numbering */
2891  expr = map_variable_attnos(stringToNode(check[i].ccbin),
2892  1, 0,
2893  newattmap,
2894  InvalidOid, &found_whole_row);
2895 
2896  /*
2897  * For the moment we have to reject whole-row variables. We
2898  * could convert them, if we knew the new table's rowtype OID,
2899  * but that hasn't been assigned yet.
2900  */
2901  if (found_whole_row)
2902  ereport(ERROR,
2903  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2904  errmsg("cannot convert whole-row table reference"),
2905  errdetail("Constraint \"%s\" contains a whole-row reference to table \"%s\".",
2906  name,
2907  RelationGetRelationName(relation))));
2908 
2909  constraints = MergeCheckConstraint(constraints, name, expr);
2910  }
2911  }
2912 
2913  /*
2914  * Also copy the not-null constraints from this parent. The
2915  * attnotnull markings were already installed above.
2916  */
2917  foreach(lc1, nnconstrs)
2918  {
2919  CookedConstraint *nn = lfirst(lc1);
2920 
2921  Assert(nn->contype == CONSTR_NOTNULL);
2922 
2923  nn->attnum = newattmap->attnums[nn->attnum - 1];
2924  nn->is_local = false;
2925  nn->inhcount = 1;
2926 
2927  nnconstraints = lappend(nnconstraints, nn);
2928  }
2929 
2930  free_attrmap(newattmap);
2931 
2932  /*
2933  * Close the parent rel, but keep our lock on it until xact commit.
2934  * That will prevent someone else from deleting or ALTERing the parent
2935  * before the child is committed.
2936  */
2937  table_close(relation, NoLock);
2938  }
2939 
2940  /*
2941  * If we had no inherited attributes, the result columns are just the
2942  * explicitly declared columns. Otherwise, we need to merge the declared
2943  * columns into the inherited column list. Although, we never have any
2944  * explicitly declared columns if the table is a partition.
2945  */
2946  if (inh_columns != NIL)
2947  {
2948  int newcol_attno = 0;
2949 
2950  foreach(lc, columns)
2951  {
2952  ColumnDef *newdef = lfirst_node(ColumnDef, lc);
2953  char *attributeName = newdef->colname;
2954  int exist_attno;
2955 
2956  /*
2957  * Partitions have only one parent and have no column definitions
2958  * of their own, so conflict should never occur.
2959  */
2960  Assert(!is_partition);
2961 
2962  newcol_attno++;
2963 
2964  /*
2965  * Does it match some inherited column?
2966  */
2967  exist_attno = findAttrByName(attributeName, inh_columns);
2968  if (exist_attno > 0)
2969  {
2970  /*
2971  * Yes, try to merge the two column definitions.
2972  */
2973  MergeChildAttribute(inh_columns, exist_attno, newcol_attno, newdef);
2974  }
2975  else
2976  {
2977  /*
2978  * No, attach new column unchanged to result columns.
2979  */
2980  inh_columns = lappend(inh_columns, newdef);
2981  }
2982  }
2983 
2984  columns = inh_columns;
2985 
2986  /*
2987  * Check that we haven't exceeded the legal # of columns after merging
2988  * in inherited columns.
2989  */
2990  if (list_length(columns) > MaxHeapAttributeNumber)
2991  ereport(ERROR,
2992  (errcode(ERRCODE_TOO_MANY_COLUMNS),
2993  errmsg("tables can have at most %d columns",
2995  }
2996 
2997  /*
2998  * Now that we have the column definition list for a partition, we can
2999  * check whether the columns referenced in the column constraint specs
3000  * actually exist. Also, merge column defaults.
3001  */
3002  if (is_partition)
3003  {
3004  foreach(lc, saved_columns)
3005  {
3006  ColumnDef *restdef = lfirst(lc);
3007  bool found = false;
3008  ListCell *l;
3009 
3010  foreach(l, columns)
3011  {
3012  ColumnDef *coldef = lfirst(l);
3013 
3014  if (strcmp(coldef->colname, restdef->colname) == 0)
3015  {
3016  found = true;
3017 
3018  /*
3019  * Check for conflicts related to generated columns.
3020  *
3021  * Same rules as above: generated-ness has to match the
3022  * parent, but the contents of the generation expression
3023  * can be different.
3024  */
3025  if (coldef->generated)
3026  {
3027  if (restdef->raw_default && !restdef->generated)
3028  ereport(ERROR,
3029  (errcode(ERRCODE_INVALID_COLUMN_DEFINITION),
3030  errmsg("column \"%s\" inherits from generated column but specifies default",
3031  restdef->colname)));
3032  if (restdef->identity)
3033  ereport(ERROR,
3034  (errcode(ERRCODE_INVALID_COLUMN_DEFINITION),
3035  errmsg("column \"%s\" inherits from generated column but specifies identity",
3036  restdef->colname)));
3037  }
3038  else
3039  {
3040  if (restdef->generated)
3041  ereport(ERROR,
3042  (errcode(ERRCODE_INVALID_COLUMN_DEFINITION),
3043  errmsg("child column \"%s\" specifies generation expression",
3044  restdef->colname),
3045  errhint("A child table column cannot be generated unless its parent column is.")));
3046  }
3047 
3048  /*
3049  * Override the parent's default value for this column
3050  * (coldef->cooked_default) with the partition's local
3051  * definition (restdef->raw_default), if there's one. It
3052  * should be physically impossible to get a cooked default
3053  * in the local definition or a raw default in the
3054  * inherited definition, but make sure they're nulls, for
3055  * future-proofing.
3056  */
3057  Assert(restdef->cooked_default == NULL);
3058  Assert(coldef->raw_default == NULL);
3059  if (restdef->raw_default)
3060  {
3061  coldef->raw_default = restdef->raw_default;
3062  coldef->cooked_default = NULL;
3063  }
3064  }
3065  }
3066 
3067  /* complain for constraints on columns not in parent */
3068  if (!found)
3069  ereport(ERROR,
3070  (errcode(ERRCODE_UNDEFINED_COLUMN),
3071  errmsg("column \"%s\" does not exist",
3072  restdef->colname)));
3073  }
3074  }
3075 
3076  /*
3077  * If we found any conflicting parent default values, check to make sure
3078  * they were overridden by the child.
3079  */
3080  if (have_bogus_defaults)
3081  {
3082  foreach(lc, columns)
3083  {
3084  ColumnDef *def = lfirst(lc);
3085 
3086  if (def->cooked_default == &bogus_marker)
3087  {
3088  if (def->generated)
3089  ereport(ERROR,
3090  (errcode(ERRCODE_INVALID_COLUMN_DEFINITION),
3091  errmsg("column \"%s\" inherits conflicting generation expressions",
3092  def->colname),
3093  errhint("To resolve the conflict, specify a generation expression explicitly.")));
3094  else
3095  ereport(ERROR,
3096  (errcode(ERRCODE_INVALID_COLUMN_DEFINITION),
3097  errmsg("column \"%s\" inherits conflicting default values",
3098  def->colname),
3099  errhint("To resolve the conflict, specify a default explicitly.")));
3100  }
3101  }
3102  }
3103 
3104  *supconstr = constraints;
3105  *supnotnulls = nnconstraints;
3106 
3107  return columns;
3108 }
3109 
3110 
3111 /*
3112  * MergeCheckConstraint
3113  * Try to merge an inherited CHECK constraint with previous ones
3114  *
3115  * If we inherit identically-named constraints from multiple parents, we must
3116  * merge them, or throw an error if they don't have identical definitions.
3117  *
3118  * constraints is a list of CookedConstraint structs for previous constraints.
3119  *
3120  * If the new constraint matches an existing one, then the existing
3121  * constraint's inheritance count is updated. If there is a conflict (same
3122  * name but different expression), throw an error. If the constraint neither
3123  * matches nor conflicts with an existing one, a new constraint is appended to
3124  * the list.
3125  */
3126 static List *
3127 MergeCheckConstraint(List *constraints, const char *name, Node *expr)
3128 {
3129  ListCell *lc;
3130  CookedConstraint *newcon;
3131 
3132  foreach(lc, constraints)
3133  {
3134  CookedConstraint *ccon = (CookedConstraint *) lfirst(lc);
3135 
3136  Assert(ccon->contype == CONSTR_CHECK);
3137 
3138  /* Non-matching names never conflict */
3139  if (strcmp(ccon->name, name) != 0)
3140  continue;
3141 
3142  if (equal(expr, ccon->expr))
3143  {
3144  /* OK to merge constraint with existing */
3145  ccon->inhcount++;
3146  if (ccon->inhcount < 0)
3147  ereport(ERROR,
3148  errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
3149  errmsg("too many inheritance parents"));
3150  return constraints;
3151  }
3152 
3153  ereport(ERROR,
3155  errmsg("check constraint name \"%s\" appears multiple times but with different expressions",
3156  name)));
3157  }
3158 
3159  /*
3160  * Constraint couldn't be merged with an existing one and also didn't
3161  * conflict with an existing one, so add it as a new one to the list.
3162  */
3163  newcon = palloc0_object(CookedConstraint);
3164  newcon->contype = CONSTR_CHECK;
3165  newcon->name = pstrdup(name);
3166  newcon->expr = expr;
3167  newcon->inhcount = 1;
3168  return lappend(constraints, newcon);
3169 }
3170 
3171 /*
3172  * MergeChildAttribute
3173  * Merge given child attribute definition into given inherited attribute.
3174  *
3175  * Input arguments:
3176  * 'inh_columns' is the list of inherited ColumnDefs.
3177  * 'exist_attno' is the number of the inherited attribute in inh_columns
3178  * 'newcol_attno' is the attribute number in child table's schema definition
3179  * 'newdef' is the column/attribute definition from the child table.
3180  *
3181  * The ColumnDef in 'inh_columns' list is modified. The child attribute's
3182  * ColumnDef remains unchanged.
3183  *
3184  * Notes:
3185  * - The attribute is merged according to the rules laid out in the prologue
3186  * of MergeAttributes().
3187  * - If matching inherited attribute exists but the child attribute can not be
3188  * merged into it, the function throws respective errors.
3189  * - A partition can not have its own column definitions. Hence this function
3190  * is applicable only to a regular inheritance child.
3191  */
3192 static void
3193 MergeChildAttribute(List *inh_columns, int exist_attno, int newcol_attno, const ColumnDef *newdef)
3194 {
3195  char *attributeName = newdef->colname;
3196  ColumnDef *inhdef;
3197  Oid inhtypeid,
3198  newtypeid;
3199  int32 inhtypmod,
3200  newtypmod;
3201  Oid inhcollid,
3202  newcollid;
3203 
3204  if (exist_attno == newcol_attno)
3205  ereport(NOTICE,
3206  (errmsg("merging column \"%s\" with inherited definition",
3207  attributeName)));
3208  else
3209  ereport(NOTICE,
3210  (errmsg("moving and merging column \"%s\" with inherited definition", attributeName),
3211  errdetail("User-specified column moved to the position of the inherited column.")));
3212 
3213  inhdef = list_nth_node(ColumnDef, inh_columns, exist_attno - 1);
3214 
3215  /*
3216  * Must have the same type and typmod
3217  */
3218  typenameTypeIdAndMod(NULL, inhdef->typeName, &inhtypeid, &inhtypmod);
3219  typenameTypeIdAndMod(NULL, newdef->typeName, &newtypeid, &newtypmod);
3220  if (inhtypeid != newtypeid || inhtypmod != newtypmod)
3221  ereport(ERROR,
3222  (errcode(ERRCODE_DATATYPE_MISMATCH),
3223  errmsg("column \"%s\" has a type conflict",
3224  attributeName),
3225  errdetail("%s versus %s",
3226  format_type_with_typemod(inhtypeid, inhtypmod),
3227  format_type_with_typemod(newtypeid, newtypmod))));
3228 
3229  /*
3230  * Must have the same collation
3231  */
3232  inhcollid = GetColumnDefCollation(NULL, inhdef, inhtypeid);
3233  newcollid = GetColumnDefCollation(NULL, newdef, newtypeid);
3234  if (inhcollid != newcollid)
3235  ereport(ERROR,
3236  (errcode(ERRCODE_COLLATION_MISMATCH),
3237  errmsg("column \"%s\" has a collation conflict",
3238  attributeName),
3239  errdetail("\"%s\" versus \"%s\"",
3240  get_collation_name(inhcollid),
3241  get_collation_name(newcollid))));
3242 
3243  /*
3244  * Identity is never inherited by a regular inheritance child. Pick
3245  * child's identity definition if there's one.
3246  */
3247  inhdef->identity = newdef->identity;
3248 
3249  /*
3250  * Copy storage parameter
3251  */
3252  if (inhdef->storage == 0)
3253  inhdef->storage = newdef->storage;
3254  else if (newdef->storage != 0 && inhdef->storage != newdef->storage)
3255  ereport(ERROR,
3256  (errcode(ERRCODE_DATATYPE_MISMATCH),
3257  errmsg("column \"%s\" has a storage parameter conflict",
3258  attributeName),
3259  errdetail("%s versus %s",
3260  storage_name(inhdef->storage),
3261  storage_name(newdef->storage))));
3262 
3263  /*
3264  * Copy compression parameter
3265  */
3266  if (inhdef->compression == NULL)
3267  inhdef->compression = newdef->compression;
3268  else if (newdef->compression != NULL)
3269  {
3270  if (strcmp(inhdef->compression, newdef->compression) != 0)
3271  ereport(ERROR,
3272  (errcode(ERRCODE_DATATYPE_MISMATCH),
3273  errmsg("column \"%s\" has a compression method conflict",
3274  attributeName),
3275  errdetail("%s versus %s", inhdef->compression, newdef->compression)));
3276  }
3277 
3278  /*
3279  * Merge of not-null constraints = OR 'em together
3280  */
3281  inhdef->is_not_null |= newdef->is_not_null;
3282 
3283  /*
3284  * Check for conflicts related to generated columns.
3285  *
3286  * If the parent column is generated, the child column will be made a
3287  * generated column if it isn't already. If it is a generated column,
3288  * we'll take its generation expression in preference to the parent's. We
3289  * must check that the child column doesn't specify a default value or
3290  * identity, which matches the rules for a single column in
3291  * parse_utilcmd.c.
3292  *
3293  * Conversely, if the parent column is not generated, the child column
3294  * can't be either. (We used to allow that, but it results in being able
3295  * to override the generation expression via UPDATEs through the parent.)
3296  */
3297  if (inhdef->generated)
3298  {
3299  if (newdef->raw_default && !newdef->generated)
3300  ereport(ERROR,
3301  (errcode(ERRCODE_INVALID_COLUMN_DEFINITION),
3302  errmsg("column \"%s\" inherits from generated column but specifies default",
3303  inhdef->colname)));
3304  if (newdef->identity)
3305  ereport(ERROR,
3306  (errcode(ERRCODE_INVALID_COLUMN_DEFINITION),
3307  errmsg("column \"%s\" inherits from generated column but specifies identity",
3308  inhdef->colname)));
3309  }
3310  else
3311  {
3312  if (newdef->generated)
3313  ereport(ERROR,
3314  (errcode(ERRCODE_INVALID_COLUMN_DEFINITION),
3315  errmsg("child column \"%s\" specifies generation expression",
3316  inhdef->colname),
3317  errhint("A child table column cannot be generated unless its parent column is.")));
3318  }
3319 
3320  /*
3321  * If new def has a default, override previous default
3322  */
3323  if (newdef->raw_default != NULL)
3324  {
3325  inhdef->raw_default = newdef->raw_default;
3326  inhdef->cooked_default = newdef->cooked_default;
3327  }
3328 
3329  /* Mark the column as locally defined */
3330  inhdef->is_local = true;
3331 }
3332 
3333 /*
3334  * MergeInheritedAttribute
3335  * Merge given parent attribute definition into specified attribute
3336  * inherited from the previous parents.
3337  *
3338  * Input arguments:
3339  * 'inh_columns' is the list of previously inherited ColumnDefs.
3340  * 'exist_attno' is the number the existing matching attribute in inh_columns.
3341  * 'newdef' is the new parent column/attribute definition to be merged.
3342  *
3343  * The matching ColumnDef in 'inh_columns' list is modified and returned.
3344  *
3345  * Notes:
3346  * - The attribute is merged according to the rules laid out in the prologue
3347  * of MergeAttributes().
3348  * - If matching inherited attribute exists but the new attribute can not be
3349  * merged into it, the function throws respective errors.
3350  * - A partition inherits from only a single parent. Hence this function is
3351  * applicable only to a regular inheritance.
3352  */
3353 static ColumnDef *
3355  int exist_attno,
3356  const ColumnDef *newdef)
3357 {
3358  char *attributeName = newdef->colname;
3359  ColumnDef *prevdef;
3360  Oid prevtypeid,
3361  newtypeid;
3362  int32 prevtypmod,
3363  newtypmod;
3364  Oid prevcollid,
3365  newcollid;
3366 
3367  ereport(NOTICE,
3368  (errmsg("merging multiple inherited definitions of column \"%s\"",
3369  attributeName)));
3370  prevdef = list_nth_node(ColumnDef, inh_columns, exist_attno - 1);
3371 
3372  /*
3373  * Must have the same type and typmod
3374  */
3375  typenameTypeIdAndMod(NULL, prevdef->typeName, &prevtypeid, &prevtypmod);
3376  typenameTypeIdAndMod(NULL, newdef->typeName, &newtypeid, &newtypmod);
3377  if (prevtypeid != newtypeid || prevtypmod != newtypmod)
3378  ereport(ERROR,
3379  (errcode(ERRCODE_DATATYPE_MISMATCH),
3380  errmsg("inherited column \"%s\" has a type conflict",
3381  attributeName),
3382  errdetail("%s versus %s",
3383  format_type_with_typemod(prevtypeid, prevtypmod),
3384  format_type_with_typemod(newtypeid, newtypmod))));
3385 
3386  /*
3387  * Must have the same collation
3388  */
3389  prevcollid = GetColumnDefCollation(NULL, prevdef, prevtypeid);
3390  newcollid = GetColumnDefCollation(NULL, newdef, newtypeid);
3391  if (prevcollid != newcollid)
3392  ereport(ERROR,
3393  (errcode(ERRCODE_COLLATION_MISMATCH),
3394  errmsg("inherited column \"%s\" has a collation conflict",
3395  attributeName),
3396  errdetail("\"%s\" versus \"%s\"",
3397  get_collation_name(prevcollid),
3398  get_collation_name(newcollid))));
3399 
3400  /*
3401  * Copy/check storage parameter
3402  */
3403  if (prevdef->storage == 0)
3404  prevdef->storage = newdef->storage;
3405  else if (prevdef->storage != newdef->storage)
3406  ereport(ERROR,
3407  (errcode(ERRCODE_DATATYPE_MISMATCH),
3408  errmsg("inherited column \"%s\" has a storage parameter conflict",
3409  attributeName),
3410  errdetail("%s versus %s",
3411  storage_name(prevdef->storage),
3412  storage_name(newdef->storage))));
3413 
3414  /*
3415  * Copy/check compression parameter
3416  */
3417  if (prevdef->compression == NULL)
3418  prevdef->compression = newdef->compression;
3419  else if (strcmp(prevdef->compression, newdef->compression) != 0)
3420  ereport(ERROR,
3421  (errcode(ERRCODE_DATATYPE_MISMATCH),
3422  errmsg("column \"%s\" has a compression method conflict",
3423  attributeName),
3424  errdetail("%s versus %s", prevdef->compression, newdef->compression)));
3425 
3426  /*
3427  * Check for GENERATED conflicts
3428  */
3429  if (prevdef->generated != newdef->generated)
3430  ereport(ERROR,
3431  (errcode(ERRCODE_DATATYPE_MISMATCH),
3432  errmsg("inherited column \"%s\" has a generation conflict",
3433  attributeName)));
3434 
3435  /*
3436  * Default and other constraints are handled by the caller.
3437  */
3438 
3439  prevdef->inhcount++;
3440  if (prevdef->inhcount < 0)
3441  ereport(ERROR,
3442  errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
3443  errmsg("too many inheritance parents"));
3444 
3445  return prevdef;
3446 }
3447 
3448 /*
3449  * StoreCatalogInheritance
3450  * Updates the system catalogs with proper inheritance information.
3451  *
3452  * supers is a list of the OIDs of the new relation's direct ancestors.
3453  */
3454 static void
3455 StoreCatalogInheritance(Oid relationId, List *supers,
3456  bool child_is_partition)
3457 {
3458  Relation relation;
3459  int32 seqNumber;
3460  ListCell *entry;
3461 
3462  /*
3463  * sanity checks
3464  */
3465  Assert(OidIsValid(relationId));
3466 
3467  if (supers == NIL)
3468  return;
3469 
3470  /*
3471  * Store INHERITS information in pg_inherits using direct ancestors only.
3472  * Also enter dependencies on the direct ancestors, and make sure they are
3473  * marked with relhassubclass = true.
3474  *
3475  * (Once upon a time, both direct and indirect ancestors were found here
3476  * and then entered into pg_ipl. Since that catalog doesn't exist
3477  * anymore, there's no need to look for indirect ancestors.)
3478  */
3479  relation = table_open(InheritsRelationId, RowExclusiveLock);
3480 
3481  seqNumber = 1;
3482  foreach(entry, supers)
3483  {
3484  Oid parentOid = lfirst_oid(entry);
3485 
3486  StoreCatalogInheritance1(relationId, parentOid, seqNumber, relation,
3487  child_is_partition);
3488  seqNumber++;
3489  }
3490 
3491  table_close(relation, RowExclusiveLock);
3492 }
3493 
3494 /*
3495  * Make catalog entries showing relationId as being an inheritance child
3496  * of parentOid. inhRelation is the already-opened pg_inherits catalog.
3497  */
3498 static void
3499 StoreCatalogInheritance1(Oid relationId, Oid parentOid,
3500  int32 seqNumber, Relation inhRelation,
3501  bool child_is_partition)
3502 {
3503  ObjectAddress childobject,
3504  parentobject;
3505 
3506  /* store the pg_inherits row */
3507  StoreSingleInheritance(relationId, parentOid, seqNumber);
3508 
3509  /*
3510  * Store a dependency too
3511  */
3512  parentobject.classId = RelationRelationId;
3513  parentobject.objectId = parentOid;
3514  parentobject.objectSubId = 0;
3515  childobject.classId = RelationRelationId;
3516  childobject.objectId = relationId;
3517  childobject.objectSubId = 0;
3518 
3519  recordDependencyOn(&childobject, &parentobject,
3520  child_dependency_type(child_is_partition));
3521 
3522  /*
3523  * Post creation hook of this inheritance. Since object_access_hook
3524  * doesn't take multiple object identifiers, we relay oid of parent
3525  * relation using auxiliary_id argument.
3526  */
3527  InvokeObjectPostAlterHookArg(InheritsRelationId,
3528  relationId, 0,
3529  parentOid, false);
3530 
3531  /*
3532  * Mark the parent as having subclasses.
3533  */
3534  SetRelationHasSubclass(parentOid, true);
3535 }
3536 
3537 /*
3538  * Look for an existing column entry with the given name.
3539  *
3540  * Returns the index (starting with 1) if attribute already exists in columns,
3541  * 0 if it doesn't.
3542  */
3543 static int
3544 findAttrByName(const char *attributeName, const List *columns)
3545 {
3546  ListCell *lc;
3547  int i = 1;
3548 
3549  foreach(lc, columns)
3550  {
3551  if (strcmp(attributeName, lfirst_node(ColumnDef, lc)->colname) == 0)
3552  return i;
3553 
3554  i++;
3555  }
3556  return 0;
3557 }
3558 
3559 
3560 /*
3561  * SetRelationHasSubclass
3562  * Set the value of the relation's relhassubclass field in pg_class.
3563  *
3564  * NOTE: caller must be holding an appropriate lock on the relation.
3565  * ShareUpdateExclusiveLock is sufficient.
3566  *
3567  * NOTE: an important side-effect of this operation is that an SI invalidation
3568  * message is sent out to all backends --- including me --- causing plans
3569  * referencing the relation to be rebuilt with the new list of children.
3570  * This must happen even if we find that no change is needed in the pg_class
3571  * row.
3572  */
3573 void
3574 SetRelationHasSubclass(Oid relationId, bool relhassubclass)
3575 {
3576  Relation relationRelation;
3577  HeapTuple tuple;
3578  Form_pg_class classtuple;
3579 
3580  /*
3581  * Fetch a modifiable copy of the tuple, modify it, update pg_class.
3582  */
3583  relationRelation = table_open(RelationRelationId, RowExclusiveLock);
3584  tuple = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relationId));
3585  if (!HeapTupleIsValid(tuple))
3586  elog(ERROR, "cache lookup failed for relation %u", relationId);
3587  classtuple = (Form_pg_class) GETSTRUCT(tuple);
3588 
3589  if (classtuple->relhassubclass != relhassubclass)
3590  {
3591  classtuple->relhassubclass = relhassubclass;
3592  CatalogTupleUpdate(relationRelation, &tuple->t_self, tuple);
3593  }
3594  else
3595  {
3596  /* no need to change tuple, but force relcache rebuild anyway */
3598  }
3599 
3600  heap_freetuple(tuple);
3601  table_close(relationRelation, RowExclusiveLock);
3602 }
3603 
3604 /*
3605  * CheckRelationTableSpaceMove
3606  * Check if relation can be moved to new tablespace.
3607  *
3608  * NOTE: The caller must hold AccessExclusiveLock on the relation.
3609  *
3610  * Returns true if the relation can be moved to the new tablespace; raises
3611  * an error if it is not possible to do the move; returns false if the move
3612  * would have no effect.
3613  */
3614 bool
3616 {
3617  Oid oldTableSpaceId;
3618 
3619  /*
3620  * No work if no change in tablespace. Note that MyDatabaseTableSpace is
3621  * stored as 0.
3622  */
3623  oldTableSpaceId = rel->rd_rel->reltablespace;
3624  if (newTableSpaceId == oldTableSpaceId ||
3625  (newTableSpaceId == MyDatabaseTableSpace && oldTableSpaceId == 0))
3626  return false;
3627 
3628  /*
3629  * We cannot support moving mapped relations into different tablespaces.
3630  * (In particular this eliminates all shared catalogs.)
3631  */
3632  if (RelationIsMapped(rel))
3633  ereport(ERROR,
3634  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3635  errmsg("cannot move system relation \"%s\"",
3636  RelationGetRelationName(rel))));
3637 
3638  /* Cannot move a non-shared relation into pg_global */
3639  if (newTableSpaceId == GLOBALTABLESPACE_OID)
3640  ereport(ERROR,
3641  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
3642  errmsg("only shared relations can be placed in pg_global tablespace")));
3643 
3644  /*
3645  * Do not allow moving temp tables of other backends ... their local
3646  * buffer manager is not going to cope.
3647  */
3648  if (RELATION_IS_OTHER_TEMP(rel))
3649  ereport(ERROR,
3650  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3651  errmsg("cannot move temporary tables of other sessions")));
3652 
3653  return true;
3654 }
3655 
3656 /*
3657  * SetRelationTableSpace
3658  * Set new reltablespace and relfilenumber in pg_class entry.
3659  *
3660  * newTableSpaceId is the new tablespace for the relation, and
3661  * newRelFilenumber its new filenumber. If newRelFilenumber is
3662  * InvalidRelFileNumber, this field is not updated.
3663  *
3664  * NOTE: The caller must hold AccessExclusiveLock on the relation.
3665  *
3666  * The caller of this routine had better check if a relation can be
3667  * moved to this new tablespace by calling CheckRelationTableSpaceMove()
3668  * first, and is responsible for making the change visible with
3669  * CommandCounterIncrement().
3670  */
3671 void
3673  Oid newTableSpaceId,
3674  RelFileNumber newRelFilenumber)
3675 {
3676  Relation pg_class;
3677  HeapTuple tuple;
3678  Form_pg_class rd_rel;
3679  Oid reloid = RelationGetRelid(rel);
3680 
3681  Assert(CheckRelationTableSpaceMove(rel, newTableSpaceId));
3682 
3683  /* Get a modifiable copy of the relation's pg_class row. */
3684  pg_class = table_open(RelationRelationId, RowExclusiveLock);
3685 
3686  tuple = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(reloid));
3687  if (!HeapTupleIsValid(tuple))
3688  elog(ERROR, "cache lookup failed for relation %u", reloid);
3689  rd_rel = (Form_pg_class) GETSTRUCT(tuple);
3690 
3691  /* Update the pg_class row. */
3692  rd_rel->reltablespace = (newTableSpaceId == MyDatabaseTableSpace) ?
3693  InvalidOid : newTableSpaceId;
3694  if (RelFileNumberIsValid(newRelFilenumber))
3695  rd_rel->relfilenode = newRelFilenumber;
3696  CatalogTupleUpdate(pg_class, &tuple->t_self, tuple);
3697 
3698  /*
3699  * Record dependency on tablespace. This is only required for relations
3700  * that have no physical storage.
3701  */
3702  if (!RELKIND_HAS_STORAGE(rel->rd_rel->relkind))
3703  changeDependencyOnTablespace(RelationRelationId, reloid,
3704  rd_rel->reltablespace);
3705 
3706  heap_freetuple(tuple);
3707  table_close(pg_class, RowExclusiveLock);
3708 }
3709 
3710 /*
3711  * renameatt_check - basic sanity checks before attribute rename
3712  */
3713 static void
3714 renameatt_check(Oid myrelid, Form_pg_class classform, bool recursing)
3715 {
3716  char relkind = classform->relkind;
3717 
3718  if (classform->reloftype && !recursing)
3719  ereport(ERROR,
3720  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3721  errmsg("cannot rename column of typed table")));
3722 
3723  /*
3724  * Renaming the columns of sequences or toast tables doesn't actually
3725  * break anything from the system's point of view, since internal
3726  * references are by attnum. But it doesn't seem right to allow users to
3727  * change names that are hardcoded into the system, hence the following
3728  * restriction.
3729  */
3730  if (relkind != RELKIND_RELATION &&
3731  relkind != RELKIND_VIEW &&
3732  relkind != RELKIND_MATVIEW &&
3733  relkind != RELKIND_COMPOSITE_TYPE &&
3734  relkind != RELKIND_INDEX &&
3735  relkind != RELKIND_PARTITIONED_INDEX &&
3736  relkind != RELKIND_FOREIGN_TABLE &&
3737  relkind != RELKIND_PARTITIONED_TABLE)
3738  ereport(ERROR,
3739  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3740  errmsg("cannot rename columns of relation \"%s\"",
3741  NameStr(classform->relname)),
3743 
3744  /*
3745  * permissions checking. only the owner of a class can change its schema.
3746  */
3747  if (!object_ownercheck(RelationRelationId, myrelid, GetUserId()))
3749  NameStr(classform->relname));
3750  if (!allowSystemTableMods && IsSystemClass(myrelid, classform))
3751  ereport(ERROR,
3752  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
3753  errmsg("permission denied: \"%s\" is a system catalog",
3754  NameStr(classform->relname))));
3755 }
3756 
3757 /*
3758  * renameatt_internal - workhorse for renameatt
3759  *
3760  * Return value is the attribute number in the 'myrelid' relation.
3761  */
3762 static AttrNumber
3764  const char *oldattname,
3765  const char *newattname,
3766  bool recurse,
3767  bool recursing,
3768  int expected_parents,
3769  DropBehavior behavior)
3770 {
3771  Relation targetrelation;
3772  Relation attrelation;
3773  HeapTuple atttup;
3774  Form_pg_attribute attform;
3776 
3777  /*
3778  * Grab an exclusive lock on the target table, which we will NOT release
3779  * until end of transaction.
3780  */
3781  targetrelation = relation_open(myrelid, AccessExclusiveLock);
3782  renameatt_check(myrelid, RelationGetForm(targetrelation), recursing);
3783 
3784  /*
3785  * if the 'recurse' flag is set then we are supposed to rename this
3786  * attribute in all classes that inherit from 'relname' (as well as in
3787  * 'relname').
3788  *
3789  * any permissions or problems with duplicate attributes will cause the
3790  * whole transaction to abort, which is what we want -- all or nothing.
3791  */
3792  if (recurse)
3793  {
3794  List *child_oids,
3795  *child_numparents;
3796  ListCell *lo,
3797  *li;
3798 
3799  /*
3800  * we need the number of parents for each child so that the recursive
3801  * calls to renameatt() can determine whether there are any parents
3802  * outside the inheritance hierarchy being processed.
3803  */
3804  child_oids = find_all_inheritors(myrelid, AccessExclusiveLock,
3805  &child_numparents);
3806 
3807  /*
3808  * find_all_inheritors does the recursive search of the inheritance
3809  * hierarchy, so all we have to do is process all of the relids in the
3810  * list that it returns.
3811  */
3812  forboth(lo, child_oids, li, child_numparents)
3813  {
3814  Oid childrelid = lfirst_oid(lo);
3815  int numparents = lfirst_int(li);
3816 
3817  if (childrelid == myrelid)
3818  continue;
3819  /* note we need not recurse again */
3820  renameatt_internal(childrelid, oldattname, newattname, false, true, numparents, behavior);
3821  }
3822  }
3823  else
3824  {
3825  /*
3826  * If we are told not to recurse, there had better not be any child
3827  * tables; else the rename would put them out of step.
3828  *
3829  * expected_parents will only be 0 if we are not already recursing.
3830  */
3831  if (expected_parents == 0 &&
3832  find_inheritance_children(myrelid, NoLock) != NIL)
3833  ereport(ERROR,
3834  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
3835  errmsg("inherited column \"%s\" must be renamed in child tables too",
3836  oldattname)));
3837  }
3838 
3839  /* rename attributes in typed tables of composite type */
3840  if (targetrelation->rd_rel->relkind == RELKIND_COMPOSITE_TYPE)
3841  {
3842  List *child_oids;
3843  ListCell *lo;
3844 
3845  child_oids = find_typed_table_dependencies(targetrelation->rd_rel->reltype,
3846  RelationGetRelationName(targetrelation),
3847  behavior);
3848 
3849  foreach(lo, child_oids)
3850  renameatt_internal(lfirst_oid(lo), oldattname, newattname, true, true, 0, behavior);
3851  }
3852 
3853  attrelation = table_open(AttributeRelationId, RowExclusiveLock);
3854 
3855  atttup = SearchSysCacheCopyAttName(myrelid, oldattname);
3856  if (!HeapTupleIsValid(atttup))
3857  ereport(ERROR,
3858  (errcode(ERRCODE_UNDEFINED_COLUMN),
3859  errmsg("column \"%s\" does not exist",
3860  oldattname)));
3861  attform = (Form_pg_attribute) GETSTRUCT(atttup);
3862 
3863  attnum = attform->attnum;
3864  if (attnum <= 0)
3865  ereport(ERROR,
3866  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3867  errmsg("cannot rename system column \"%s\"",
3868  oldattname)));
3869 
3870  /*
3871  * if the attribute is inherited, forbid the renaming. if this is a
3872  * top-level call to renameatt(), then expected_parents will be 0, so the
3873  * effect of this code will be to prohibit the renaming if the attribute
3874  * is inherited at all. if this is a recursive call to renameatt(),
3875  * expected_parents will be the number of parents the current relation has
3876  * within the inheritance hierarchy being processed, so we'll prohibit the
3877  * renaming only if there are additional parents from elsewhere.
3878  */
3879  if (attform->attinhcount > expected_parents)
3880  ereport(ERROR,
3881  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
3882  errmsg("cannot rename inherited column \"%s\"",
3883  oldattname)));
3884 
3885  /* new name should not already exist */
3886  (void) check_for_column_name_collision(targetrelation, newattname, false);
3887 
3888  /* apply the update */
3889  namestrcpy(&(attform->attname), newattname);
3890 
3891  CatalogTupleUpdate(attrelation, &atttup->t_self, atttup);
3892 
3893  InvokeObjectPostAlterHook(RelationRelationId, myrelid, attnum);
3894 
3895  heap_freetuple(atttup);
3896 
3897  table_close(attrelation, RowExclusiveLock);
3898 
3899  relation_close(targetrelation, NoLock); /* close rel but keep lock */
3900 
3901  return attnum;
3902 }
3903 
3904 /*
3905  * Perform permissions and integrity checks before acquiring a relation lock.
3906  */
3907 static void
3909  void *arg)
3910 {
3911  HeapTuple tuple;
3912  Form_pg_class form;
3913 
3914  tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
3915  if (!HeapTupleIsValid(tuple))
3916  return; /* concurrently dropped */
3917  form = (Form_pg_class) GETSTRUCT(tuple);
3918  renameatt_check(relid, form, false);
3919  ReleaseSysCache(tuple);
3920 }
3921 
3922 /*
3923  * renameatt - changes the name of an attribute in a relation
3924  *
3925  * The returned ObjectAddress is that of the renamed column.
3926  */
3929 {
3930  Oid relid;
3932  ObjectAddress address;
3933 
3934  /* lock level taken here should match renameatt_internal */
3936  stmt->missing_ok ? RVR_MISSING_OK : 0,
3938  NULL);
3939 
3940  if (!OidIsValid(relid))
3941  {
3942  ereport(NOTICE,
3943  (errmsg("relation \"%s\" does not exist, skipping",
3944  stmt->relation->relname)));
3945  return InvalidObjectAddress;
3946  }
3947 
3948  attnum =
3949  renameatt_internal(relid,
3950  stmt->subname, /* old att name */
3951  stmt->newname, /* new att name */
3952  stmt->relation->inh, /* recursive? */
3953  false, /* recursing? */
3954  0, /* expected inhcount */
3955  stmt->behavior);
3956 
3957  ObjectAddressSubSet(address, RelationRelationId, relid, attnum);
3958 
3959  return address;
3960 }
3961 
3962 /*
3963  * same logic as renameatt_internal
3964  */
3965 static ObjectAddress
3967  Oid mytypid,
3968  const char *oldconname,
3969  const char *newconname,
3970  bool recurse,
3971  bool recursing,
3972  int expected_parents)
3973 {
3974  Relation targetrelation = NULL;
3975  Oid constraintOid;
3976  HeapTuple tuple;
3977  Form_pg_constraint con;
3978  ObjectAddress address;
3979 
3980  Assert(!myrelid || !mytypid);
3981 
3982  if (mytypid)
3983  {
3984  constraintOid = get_domain_constraint_oid(mytypid, oldconname, false);
3985  }
3986  else
3987  {
3988  targetrelation = relation_open(myrelid, AccessExclusiveLock);
3989 
3990  /*
3991  * don't tell it whether we're recursing; we allow changing typed
3992  * tables here
3993  */
3994  renameatt_check(myrelid, RelationGetForm(targetrelation), false);
3995 
3996  constraintOid = get_relation_constraint_oid(myrelid, oldconname, false);
3997  }
3998 
3999  tuple = SearchSysCache1(CONSTROID, ObjectIdGetDatum(constraintOid));
4000  if (!HeapTupleIsValid(tuple))
4001  elog(ERROR, "cache lookup failed for constraint %u",
4002  constraintOid);
4003  con = (Form_pg_constraint) GETSTRUCT(tuple);
4004 
4005  if (myrelid &&
4006  (con->contype == CONSTRAINT_CHECK ||
4007  con->contype == CONSTRAINT_NOTNULL) &&
4008  !con->connoinherit)
4009  {
4010  if (recurse)
4011  {
4012  List *child_oids,
4013  *child_numparents;
4014  ListCell *lo,
4015  *li;
4016 
4017  child_oids = find_all_inheritors(myrelid, AccessExclusiveLock,
4018  &child_numparents);
4019 
4020  forboth(lo, child_oids, li, child_numparents)
4021  {
4022  Oid childrelid = lfirst_oid(lo);
4023  int numparents = lfirst_int(li);
4024 
4025  if (childrelid == myrelid)
4026  continue;
4027 
4028  rename_constraint_internal(childrelid, InvalidOid, oldconname, newconname, false, true, numparents);
4029  }
4030  }
4031  else
4032  {
4033  if (expected_parents == 0 &&
4034  find_inheritance_children(myrelid, NoLock) != NIL)
4035  ereport(ERROR,
4036  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
4037  errmsg("inherited constraint \"%s\" must be renamed in child tables too",
4038  oldconname)));
4039  }
4040 
4041  if (con->coninhcount > expected_parents)
4042  ereport(ERROR,
4043  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
4044  errmsg("cannot rename inherited constraint \"%s\"",
4045  oldconname)));
4046  }
4047 
4048  if (con->conindid
4049  && (con->contype == CONSTRAINT_PRIMARY
4050  || con->contype == CONSTRAINT_UNIQUE
4051  || con->contype == CONSTRAINT_EXCLUSION))
4052  /* rename the index; this renames the constraint as well */
4053  RenameRelationInternal(con->conindid, newconname, false, true);
4054  else
4055  RenameConstraintById(constraintOid, newconname);
4056 
4057  ObjectAddressSet(address, ConstraintRelationId, constraintOid);
4058 
4059  ReleaseSysCache(tuple);
4060 
4061  if (targetrelation)
4062  {
4063  /*
4064  * Invalidate relcache so as others can see the new constraint name.
4065  */
4066  CacheInvalidateRelcache(targetrelation);
4067 
4068  relation_close(targetrelation, NoLock); /* close rel but keep lock */
4069  }
4070 
4071  return address;
4072 }
4073 
4076 {
4077  Oid relid = InvalidOid;
4078  Oid typid = InvalidOid;
4079 
4080  if (stmt->renameType == OBJECT_DOMCONSTRAINT)
4081  {
4082  Relation rel;
4083  HeapTuple tup;
4084 
4085  typid = typenameTypeId(NULL, makeTypeNameFromNameList(castNode(List, stmt->object)));
4086  rel = table_open(TypeRelationId, RowExclusiveLock);
4087  tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
4088  if (!HeapTupleIsValid(tup))
4089  elog(ERROR, "cache lookup failed for type %u", typid);
4090  checkDomainOwner(tup);
4091  ReleaseSysCache(tup);
4092  table_close(rel, NoLock);
4093  }
4094  else
4095  {
4096  /* lock level taken here should match rename_constraint_internal */
4098  stmt->missing_ok ? RVR_MISSING_OK : 0,
4100  NULL);
4101  if (!OidIsValid(relid))
4102  {
4103  ereport(NOTICE,
4104  (errmsg("relation \"%s\" does not exist, skipping",
4105  stmt->relation->relname)));
4106  return InvalidObjectAddress;
4107  }
4108  }
4109 
4110  return
4111  rename_constraint_internal(relid, typid,
4112  stmt->subname,
4113  stmt->newname,
4114  (stmt->relation &&
4115  stmt->relation->inh), /* recursive? */
4116  false, /* recursing? */
4117  0 /* expected inhcount */ );
4118 }
4119 
4120 /*
4121  * Execute ALTER TABLE/INDEX/SEQUENCE/VIEW/MATERIALIZED VIEW/FOREIGN TABLE
4122  * RENAME
4123  */
4126 {
4127  bool is_index_stmt = stmt->renameType == OBJECT_INDEX;
4128  Oid relid;
4129  ObjectAddress address;
4130 
4131  /*
4132  * Grab an exclusive lock on the target table, index, sequence, view,
4133  * materialized view, or foreign table, which we will NOT release until
4134  * end of transaction.
4135  *
4136  * Lock level used here should match RenameRelationInternal, to avoid lock
4137  * escalation. However, because ALTER INDEX can be used with any relation
4138  * type, we mustn't believe without verification.
4139  */
4140  for (;;)
4141  {
4142  LOCKMODE lockmode;
4143  char relkind;
4144  bool obj_is_index;
4145 
4146  lockmode = is_index_stmt ? ShareUpdateExclusiveLock : AccessExclusiveLock;
4147 
4148  relid = RangeVarGetRelidExtended(stmt->relation, lockmode,
4149  stmt->missing_ok ? RVR_MISSING_OK : 0,
4151  (void *) stmt);
4152 
4153  if (!OidIsValid(relid))
4154  {
4155  ereport(NOTICE,
4156  (errmsg("relation \"%s\" does not exist, skipping",
4157  stmt->relation->relname)));
4158  return InvalidObjectAddress;
4159  }
4160 
4161  /*
4162  * We allow mismatched statement and object types (e.g., ALTER INDEX
4163  * to rename a table), but we might've used the wrong lock level. If
4164  * that happens, retry with the correct lock level. We don't bother
4165  * if we already acquired AccessExclusiveLock with an index, however.
4166  */
4167  relkind = get_rel_relkind(relid);
4168  obj_is_index = (relkind == RELKIND_INDEX ||
4169  relkind == RELKIND_PARTITIONED_INDEX);
4170  if (obj_is_index || is_index_stmt == obj_is_index)
4171  break;
4172 
4173  UnlockRelationOid(relid, lockmode);
4174  is_index_stmt = obj_is_index;
4175  }
4176 
4177  /* Do the work */
4178  RenameRelationInternal(relid, stmt->newname, false, is_index_stmt);
4179 
4180  ObjectAddressSet(address, RelationRelationId, relid);
4181 
4182  return address;
4183 }
4184 
4185 /*
4186  * RenameRelationInternal - change the name of a relation
4187  */
4188 void
4189 RenameRelationInternal(Oid myrelid, const char *newrelname, bool is_internal, bool is_index)
4190 {
4191  Relation targetrelation;
4192  Relation relrelation; /* for RELATION relation */
4193  HeapTuple reltup;
4194  Form_pg_class relform;
4195  Oid namespaceId;
4196 
4197  /*
4198  * Grab a lock on the target relation, which we will NOT release until end
4199  * of transaction. We need at least a self-exclusive lock so that
4200  * concurrent DDL doesn't overwrite the rename if they start updating
4201  * while still seeing the old version. The lock also guards against
4202  * triggering relcache reloads in concurrent sessions, which might not
4203  * handle this information changing under them. For indexes, we can use a
4204  * reduced lock level because RelationReloadIndexInfo() handles indexes
4205  * specially.
4206  */
4207  targetrelation = relation_open(myrelid, is_index ? ShareUpdateExclusiveLock : AccessExclusiveLock);
4208  namespaceId = RelationGetNamespace(targetrelation);
4209 
4210  /*
4211  * Find relation's pg_class tuple, and make sure newrelname isn't in use.
4212  */
4213  relrelation = table_open(RelationRelationId, RowExclusiveLock);
4214 
4215  reltup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(myrelid));
4216  if (!HeapTupleIsValid(reltup)) /* shouldn't happen */
4217  elog(ERROR, "cache lookup failed for relation %u", myrelid);
4218  relform = (Form_pg_class) GETSTRUCT(reltup);
4219 
4220  if (get_relname_relid(newrelname, namespaceId) != InvalidOid)
4221  ereport(ERROR,
4222  (errcode(ERRCODE_DUPLICATE_TABLE),
4223  errmsg("relation \"%s\" already exists",
4224  newrelname)));
4225 
4226  /*
4227  * RenameRelation is careful not to believe the caller's idea of the
4228  * relation kind being handled. We don't have to worry about this, but
4229  * let's not be totally oblivious to it. We can process an index as
4230  * not-an-index, but not the other way around.
4231  */
4232  Assert(!is_index ||
4233  is_index == (targetrelation->rd_rel->relkind == RELKIND_INDEX ||
4234  targetrelation->rd_rel->relkind == RELKIND_PARTITIONED_INDEX));
4235 
4236  /*
4237  * Update pg_class tuple with new relname. (Scribbling on reltup is OK
4238  * because it's a copy...)
4239  */
4240  namestrcpy(&(relform->relname), newrelname);
4241 
4242  CatalogTupleUpdate(relrelation, &reltup->t_self, reltup);
4243 
4244  InvokeObjectPostAlterHookArg(RelationRelationId, myrelid, 0,
4245  InvalidOid, is_internal);
4246 
4247  heap_freetuple(reltup);
4248  table_close(relrelation, RowExclusiveLock);
4249 
4250  /*
4251  * Also rename the associated type, if any.
4252  */
4253  if (OidIsValid(targetrelation->rd_rel->reltype))
4254  RenameTypeInternal(targetrelation->rd_rel->reltype,
4255  newrelname, namespaceId);
4256 
4257  /*
4258  * Also rename the associated constraint, if any.
4259  */
4260  if (targetrelation->rd_rel->relkind == RELKIND_INDEX ||
4261  targetrelation->rd_rel->relkind == RELKIND_PARTITIONED_INDEX)
4262  {
4263  Oid constraintId = get_index_constraint(myrelid);
4264 
4265  if (OidIsValid(constraintId))
4266  RenameConstraintById(constraintId, newrelname);
4267  }
4268 
4269  /*
4270  * Close rel, but keep lock!
4271  */
4272  relation_close(targetrelation, NoLock);
4273 }
4274 
4275 /*
4276  * ResetRelRewrite - reset relrewrite
4277  */
4278 void
4280 {
4281  Relation relrelation; /* for RELATION relation */
4282  HeapTuple reltup;
4283  Form_pg_class relform;
4284 
4285  /*
4286  * Find relation's pg_class tuple.
4287  */
4288  relrelation = table_open(RelationRelationId, RowExclusiveLock);
4289 
4290  reltup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(myrelid));
4291  if (!HeapTupleIsValid(reltup)) /* shouldn't happen */
4292  elog(ERROR, "cache lookup failed for relation %u", myrelid);
4293  relform = (Form_pg_class) GETSTRUCT(reltup);
4294 
4295  /*
4296  * Update pg_class tuple.
4297  */
4298  relform->relrewrite = InvalidOid;
4299 
4300  CatalogTupleUpdate(relrelation, &reltup->t_self, reltup);
4301 
4302  heap_freetuple(reltup);
4303  table_close(relrelation, RowExclusiveLock);
4304 }
4305 
4306 /*
4307  * Disallow ALTER TABLE (and similar commands) when the current backend has
4308  * any open reference to the target table besides the one just acquired by
4309  * the calling command; this implies there's an open cursor or active plan.
4310  * We need this check because our lock doesn't protect us against stomping
4311  * on our own foot, only other people's feet!
4312  *
4313  * For ALTER TABLE, the only case known to cause serious trouble is ALTER
4314  * COLUMN TYPE, and some changes are obviously pretty benign, so this could
4315  * possibly be relaxed to only error out for certain types of alterations.
4316  * But the use-case for allowing any of these things is not obvious, so we
4317  * won't work hard at it for now.
4318  *
4319  * We also reject these commands if there are any pending AFTER trigger events
4320  * for the rel. This is certainly necessary for the rewriting variants of
4321  * ALTER TABLE, because they don't preserve tuple TIDs and so the pending
4322  * events would try to fetch the wrong tuples. It might be overly cautious
4323  * in other cases, but again it seems better to err on the side of paranoia.
4324  *
4325  * REINDEX calls this with "rel" referencing the index to be rebuilt; here
4326  * we are worried about active indexscans on the index. The trigger-event
4327  * check can be skipped, since we are doing no damage to the parent table.
4328  *
4329  * The statement name (eg, "ALTER TABLE") is passed for use in error messages.
4330  */
4331 void
4333 {
4334  int expected_refcnt;
4335 
4336  expected_refcnt = rel->rd_isnailed ? 2 : 1;
4337  if (rel->rd_refcnt != expected_refcnt)
4338  ereport(ERROR,
4339  (errcode(ERRCODE_OBJECT_IN_USE),
4340  /* translator: first %s is a SQL command, eg ALTER TABLE */
4341  errmsg("cannot %s \"%s\" because it is being used by active queries in this session",
4342  stmt, RelationGetRelationName(rel))));
4343 
4344  if (rel->rd_rel->relkind != RELKIND_INDEX &&
4345  rel->rd_rel->relkind != RELKIND_PARTITIONED_INDEX &&
4347  ereport(ERROR,
4348  (errcode(ERRCODE_OBJECT_IN_USE),
4349  /* translator: first %s is a SQL command, eg ALTER TABLE */
4350  errmsg("cannot %s \"%s\" because it has pending trigger events",
4351  stmt, RelationGetRelationName(rel))));
4352 }
4353 
4354 /*
4355  * AlterTableLookupRelation
4356  * Look up, and lock, the OID for the relation named by an alter table
4357  * statement.
4358  */
4359 Oid
4361 {
4362  return RangeVarGetRelidExtended(stmt->relation, lockmode,
4363  stmt->missing_ok ? RVR_MISSING_OK : 0,
4365  (void *) stmt);
4366 }
4367 
4368 /*
4369  * AlterTable
4370  * Execute ALTER TABLE, which can be a list of subcommands
4371  *
4372  * ALTER TABLE is performed in three phases:
4373  * 1. Examine subcommands and perform pre-transformation checking.
4374  * 2. Validate and transform subcommands, and update system catalogs.
4375  * 3. Scan table(s) to check new constraints, and optionally recopy
4376  * the data into new table(s).
4377  * Phase 3 is not performed unless one or more of the subcommands requires
4378  * it. The intention of this design is to allow multiple independent
4379  * updates of the table schema to be performed with only one pass over the
4380  * data.
4381  *
4382  * ATPrepCmd performs phase 1. A "work queue" entry is created for
4383  * each table to be affected (there may be multiple affected tables if the
4384  * commands traverse a table inheritance hierarchy). Also we do preliminary
4385  * validation of the subcommands. Because earlier subcommands may change
4386  * the catalog state seen by later commands, there are limits to what can
4387  * be done in this phase. Generally, this phase acquires table locks,
4388  * checks permissions and relkind, and recurses to find child tables.
4389  *
4390  * ATRewriteCatalogs performs phase 2 for each affected table.
4391  * Certain subcommands need to be performed before others to avoid
4392  * unnecessary conflicts; for example, DROP COLUMN should come before
4393  * ADD COLUMN. Therefore phase 1 divides the subcommands into multiple
4394  * lists, one for each logical "pass" of phase 2.
4395  *
4396  * ATRewriteTables performs phase 3 for those tables that need it.
4397  *
4398  * For most subcommand types, phases 2 and 3 do no explicit recursion,
4399  * since phase 1 already does it. However, for certain subcommand types
4400  * it is only possible to determine how to recurse at phase 2 time; for
4401  * those cases, phase 1 sets the cmd->recurse flag.
4402  *
4403  * Thanks to the magic of MVCC, an error anywhere along the way rolls back
4404  * the whole operation; we don't have to do anything special to clean up.
4405  *
4406  * The caller must lock the relation, with an appropriate lock level
4407  * for the subcommands requested, using AlterTableGetLockLevel(stmt->cmds)
4408  * or higher. We pass the lock level down
4409  * so that we can apply it recursively to inherited tables. Note that the
4410  * lock level we want as we recurse might well be higher than required for
4411  * that specific subcommand. So we pass down the overall lock requirement,
4412  * rather than reassess it at lower levels.
4413  *
4414  * The caller also provides a "context" which is to be passed back to
4415  * utility.c when we need to execute a subcommand such as CREATE INDEX.
4416  * Some of the fields therein, such as the relid, are used here as well.
4417  */
4418 void
4420  AlterTableUtilityContext *context)
4421 {
4422  Relation rel;
4423 
4424  /* Caller is required to provide an adequate lock. */
4425  rel = relation_open(context->relid, NoLock);
4426 
4427  CheckTableNotInUse(rel, "ALTER TABLE");
4428 
4429  ATController(stmt, rel, stmt->cmds, stmt->relation->inh, lockmode, context);
4430 }
4431 
4432 /*
4433  * AlterTableInternal
4434  *
4435  * ALTER TABLE with target specified by OID
4436  *
4437  * We do not reject if the relation is already open, because it's quite
4438  * likely that one or more layers of caller have it open. That means it
4439  * is unsafe to use this entry point for alterations that could break
4440  * existing query plans. On the assumption it's not used for such, we
4441  * don't have to reject pending AFTER triggers, either.
4442  *
4443  * Also, since we don't have an AlterTableUtilityContext, this cannot be
4444  * used for any subcommand types that require parse transformation or
4445  * could generate subcommands that have to be passed to ProcessUtility.
4446  */
4447 void
4448 AlterTableInternal(Oid relid, List *cmds, bool recurse)
4449 {
4450  Relation rel;
4451  LOCKMODE lockmode = AlterTableGetLockLevel(cmds);
4452 
4453  rel = relation_open(relid, lockmode);
4454 
4456 
4457  ATController(NULL, rel, cmds, recurse, lockmode, NULL);
4458 }
4459 
4460 /*
4461  * AlterTableGetLockLevel
4462  *
4463  * Sets the overall lock level required for the supplied list of subcommands.
4464  * Policy for doing this set according to needs of AlterTable(), see
4465  * comments there for overall explanation.
4466  *
4467  * Function is called before and after parsing, so it must give same
4468  * answer each time it is called. Some subcommands are transformed
4469  * into other subcommand types, so the transform must never be made to a
4470  * lower lock level than previously assigned. All transforms are noted below.
4471  *
4472  * Since this is called before we lock the table we cannot use table metadata
4473  * to influence the type of lock we acquire.
4474  *
4475  * There should be no lockmodes hardcoded into the subcommand functions. All
4476  * lockmode decisions for ALTER TABLE are made here only. The one exception is
4477  * ALTER TABLE RENAME which is treated as a different statement type T_RenameStmt
4478  * and does not travel through this section of code and cannot be combined with
4479  * any of the subcommands given here.
4480  *
4481  * Note that Hot Standby only knows about AccessExclusiveLocks on the primary
4482  * so any changes that might affect SELECTs running on standbys need to use
4483  * AccessExclusiveLocks even if you think a lesser lock would do, unless you
4484  * have a solution for that also.
4485  *
4486  * Also note that pg_dump uses only an AccessShareLock, meaning that anything
4487  * that takes a lock less than AccessExclusiveLock can change object definitions
4488  * while pg_dump is running. Be careful to check that the appropriate data is
4489  * derived by pg_dump using an MVCC snapshot, rather than syscache lookups,
4490  * otherwise we might end up with an inconsistent dump that can't restore.
4491  */
4492 LOCKMODE
4494 {
4495  /*
4496  * This only works if we read catalog tables using MVCC snapshots.
4497  */
4498  ListCell *lcmd;
4500 
4501  foreach(lcmd, cmds)
4502  {
4503  AlterTableCmd *cmd = (AlterTableCmd *) lfirst(lcmd);
4504  LOCKMODE cmd_lockmode = AccessExclusiveLock; /* default for compiler */
4505 
4506  switch (cmd->subtype)
4507  {
4508  /*
4509  * These subcommands rewrite the heap, so require full locks.
4510  */
4511  case AT_AddColumn: /* may rewrite heap, in some cases and visible
4512  * to SELECT */
4513  case AT_SetAccessMethod: /* must rewrite heap */
4514  case AT_SetTableSpace: /* must rewrite heap */
4515  case AT_AlterColumnType: /* must rewrite heap */
4516  cmd_lockmode = AccessExclusiveLock;
4517  break;
4518 
4519  /*
4520  * These subcommands may require addition of toast tables. If
4521  * we add a toast table to a table currently being scanned, we
4522  * might miss data added to the new toast table by concurrent
4523  * insert transactions.
4524  */
4525  case AT_SetStorage: /* may add toast tables, see
4526  * ATRewriteCatalogs() */
4527  cmd_lockmode = AccessExclusiveLock;
4528  break;
4529 
4530  /*
4531  * Removing constraints can affect SELECTs that have been
4532  * optimized assuming the constraint holds true. See also
4533  * CloneFkReferenced.
4534  */
4535  case AT_DropConstraint: /* as DROP INDEX */
4536  case AT_DropNotNull: /* may change some SQL plans */
4537  cmd_lockmode = AccessExclusiveLock;
4538  break;
4539 
4540  /*
4541  * Subcommands that may be visible to concurrent SELECTs
4542  */
4543  case AT_DropColumn: /* change visible to SELECT */
4544  case AT_AddColumnToView: /* CREATE VIEW */
4545  case AT_DropOids: /* used to equiv to DropColumn */
4546  case AT_EnableAlwaysRule: /* may change SELECT rules */
4547  case AT_EnableReplicaRule: /* may change SELECT rules */
4548  case AT_EnableRule: /* may change SELECT rules */
4549  case AT_DisableRule: /* may change SELECT rules */
4550  cmd_lockmode = AccessExclusiveLock;
4551  break;
4552 
4553  /*
4554  * Changing owner may remove implicit SELECT privileges
4555  */
4556  case AT_ChangeOwner: /* change visible to SELECT */
4557  cmd_lockmode = AccessExclusiveLock;
4558  break;
4559 
4560  /*
4561  * Changing foreign table options may affect optimization.
4562  */
4563  case AT_GenericOptions:
4565  cmd_lockmode = AccessExclusiveLock;
4566  break;
4567 
4568  /*
4569  * These subcommands affect write operations only.
4570  */
4571  case AT_EnableTrig:
4572  case AT_EnableAlwaysTrig:
4573  case AT_EnableReplicaTrig:
4574  case AT_EnableTrigAll:
4575  case AT_EnableTrigUser:
4576  case AT_DisableTrig:
4577  case AT_DisableTrigAll:
4578  case AT_DisableTrigUser:
4579  cmd_lockmode = ShareRowExclusiveLock;
4580  break;
4581 
4582  /*
4583  * These subcommands affect write operations only. XXX
4584  * Theoretically, these could be ShareRowExclusiveLock.
4585  */
4586  case AT_ColumnDefault:
4588  case AT_AlterConstraint:
4589  case AT_AddIndex: /* from ADD CONSTRAINT */
4590  case AT_AddIndexConstraint:
4591  case AT_ReplicaIdentity:
4592  case AT_SetNotNull:
4593  case AT_SetAttNotNull:
4594  case AT_EnableRowSecurity:
4595  case AT_DisableRowSecurity:
4596  case AT_ForceRowSecurity:
4597  case AT_NoForceRowSecurity:
4598  case AT_AddIdentity:
4599  case AT_DropIdentity:
4600  case AT_SetIdentity:
4601  case AT_SetExpression:
4602  case AT_DropExpression:
4603  case AT_SetCompression:
4604  cmd_lockmode = AccessExclusiveLock;
4605  break;
4606 
4607  case AT_AddConstraint:
4608  case AT_ReAddConstraint: /* becomes AT_AddConstraint */
4609  case AT_ReAddDomainConstraint: /* becomes AT_AddConstraint */
4610  if (IsA(cmd->def, Constraint))
4611  {
4612  Constraint *con = (Constraint *) cmd->def;
4613 
4614  switch (con->contype)
4615  {
4616  case CONSTR_EXCLUSION:
4617  case CONSTR_PRIMARY:
4618  case CONSTR_UNIQUE:
4619 
4620  /*
4621  * Cases essentially the same as CREATE INDEX. We
4622  * could reduce the lock strength to ShareLock if
4623  * we can work out how to allow concurrent catalog
4624  * updates. XXX Might be set down to
4625  * ShareRowExclusiveLock but requires further
4626  * analysis.
4627  */
4628  cmd_lockmode = AccessExclusiveLock;
4629  break;
4630  case CONSTR_FOREIGN:
4631 
4632  /*
4633  * We add triggers to both tables when we add a
4634  * Foreign Key, so the lock level must be at least
4635  * as strong as CREATE TRIGGER.
4636  */
4637  cmd_lockmode = ShareRowExclusiveLock;
4638  break;
4639 
4640  default:
4641  cmd_lockmode = AccessExclusiveLock;
4642  }
4643  }
4644  break;
4645 
4646  /*
4647  * These subcommands affect inheritance behaviour. Queries
4648  * started before us will continue to see the old inheritance
4649  * behaviour, while queries started after we commit will see
4650  * new behaviour. No need to prevent reads or writes to the
4651  * subtable while we hook it up though. Changing the TupDesc
4652  * may be a problem, so keep highest lock.
4653  */
4654  case AT_AddInherit:
4655  case AT_DropInherit:
4656  cmd_lockmode = AccessExclusiveLock;
4657  break;
4658 
4659  /*
4660  * These subcommands affect implicit row type conversion. They
4661  * have affects similar to CREATE/DROP CAST on queries. don't
4662  * provide for invalidating parse trees as a result of such
4663  * changes, so we keep these at AccessExclusiveLock.
4664  */
4665  case AT_AddOf:
4666  case AT_DropOf:
4667  cmd_lockmode = AccessExclusiveLock;
4668  break;
4669 
4670  /*
4671  * Only used by CREATE OR REPLACE VIEW which must conflict
4672  * with an SELECTs currently using the view.
4673  */
4674  case AT_ReplaceRelOptions:
4675  cmd_lockmode = AccessExclusiveLock;
4676  break;
4677 
4678  /*
4679  * These subcommands affect general strategies for performance
4680  * and maintenance, though don't change the semantic results
4681  * from normal data reads and writes. Delaying an ALTER TABLE
4682  * behind currently active writes only delays the point where
4683  * the new strategy begins to take effect, so there is no
4684  * benefit in waiting. In this case the minimum restriction
4685  * applies: we don't currently allow concurrent catalog
4686  * updates.
4687  */
4688  case AT_SetStatistics: /* Uses MVCC in getTableAttrs() */
4689  case AT_ClusterOn: /* Uses MVCC in getIndexes() */
4690  case AT_DropCluster: /* Uses MVCC in getIndexes() */
4691  case AT_SetOptions: /* Uses MVCC in getTableAttrs() */
4692  case AT_ResetOptions: /* Uses MVCC in getTableAttrs() */
4693  cmd_lockmode = ShareUpdateExclusiveLock;
4694  break;
4695 
4696  case AT_SetLogged:
4697  case AT_SetUnLogged:
4698  cmd_lockmode = AccessExclusiveLock;
4699  break;
4700 
4701  case AT_ValidateConstraint: /* Uses MVCC in getConstraints() */
4702  cmd_lockmode = ShareUpdateExclusiveLock;
4703  break;
4704 
4705  /*
4706  * Rel options are more complex than first appears. Options
4707  * are set here for tables, views and indexes; for historical
4708  * reasons these can all be used with ALTER TABLE, so we can't
4709  * decide between them using the basic grammar.
4710  */
4711  case AT_SetRelOptions: /* Uses MVCC in getIndexes() and
4712  * getTables() */
4713  case AT_ResetRelOptions: /* Uses MVCC in getIndexes() and
4714  * getTables() */
4715  cmd_lockmode = AlterTableGetRelOptionsLockLevel((List *) cmd->def);
4716  break;
4717 
4718  case AT_AttachPartition:
4719  cmd_lockmode = ShareUpdateExclusiveLock;
4720  break;
4721 
4722  case AT_DetachPartition:
4723  if (((PartitionCmd *) cmd->def)->concurrent)
4724  cmd_lockmode = ShareUpdateExclusiveLock;
4725  else
4726  cmd_lockmode = AccessExclusiveLock;
4727  break;
4728 
4730  cmd_lockmode = ShareUpdateExclusiveLock;
4731  break;
4732 
4733  default: /* oops */
4734  elog(ERROR, "unrecognized alter table type: %d",
4735  (int) cmd->subtype);
4736  break;
4737  }
4738 
4739  /*
4740  * Take the greatest lockmode from any subcommand
4741  */
4742  if (cmd_lockmode > lockmode)
4743  lockmode = cmd_lockmode;
4744  }
4745 
4746  return lockmode;
4747 }
4748 
4749 /*
4750  * ATController provides top level control over the phases.
4751  *
4752  * parsetree is passed in to allow it to be passed to event triggers
4753  * when requested.
4754  */
4755 static void
4757  Relation rel, List *cmds, bool recurse, LOCKMODE lockmode,
4758  AlterTableUtilityContext *context)
4759 {
4760  List *wqueue = NIL;
4761  ListCell *lcmd;
4762 
4763  /* Phase 1: preliminary examination of commands, create work queue */
4764  foreach(lcmd, cmds)
4765  {
4766  AlterTableCmd *cmd = (AlterTableCmd *) lfirst(lcmd);
4767 
4768  ATPrepCmd(&wqueue, rel, cmd, recurse, false, lockmode, context);
4769  }
4770 
4771  /* Close the relation, but keep lock until commit */
4772  relation_close(rel, NoLock);
4773 
4774  /* Phase 2: update system catalogs */
4775  ATRewriteCatalogs(&wqueue, lockmode, context);
4776 
4777  /* Phase 3: scan/rewrite tables as needed, and run afterStmts */
4778  ATRewriteTables(parsetree, &wqueue, lockmode, context);
4779 }
4780 
4781 /*
4782  * ATPrepCmd
4783  *
4784  * Traffic cop for ALTER TABLE Phase 1 operations, including simple
4785  * recursion and permission checks.
4786  *
4787  * Caller must have acquired appropriate lock type on relation already.
4788  * This lock should be held until commit.
4789  */
4790 static void
4791 ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd,
4792  bool recurse, bool recursing, LOCKMODE lockmode,
4793  AlterTableUtilityContext *context)
4794 {
4795  AlteredTableInfo *tab;
4797 
4798  /* Find or create work queue entry for this table */
4799  tab = ATGetQueueEntry(wqueue, rel);
4800 
4801  /*
4802  * Disallow any ALTER TABLE other than ALTER TABLE DETACH FINALIZE on
4803  * partitions that are pending detach.
4804  */
4805  if (rel->rd_rel->relispartition &&
4808  ereport(ERROR,
4809  errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
4810  errmsg("cannot alter partition \"%s\" with an incomplete detach",
4812  errhint("Use ALTER TABLE ... DETACH PARTITION ... FINALIZE to complete the pending detach operation."));
4813 
4814  /*
4815  * Copy the original subcommand for each table, so we can scribble on it.
4816  * This avoids conflicts when different child tables need to make
4817  * different parse transformations (for example, the same column may have
4818  * different column numbers in different children).
4819  */
4820  cmd = copyObject(cmd);
4821 
4822  /*
4823  * Do permissions and relkind checking, recursion to child tables if
4824  * needed, and any additional phase-1 processing needed. (But beware of
4825  * adding any processing that looks at table details that another
4826  * subcommand could change. In some cases we reject multiple subcommands
4827  * that could try to change the same state in contrary ways.)
4828  */
4829  switch (cmd->subtype)
4830  {
4831  case AT_AddColumn: /* ADD COLUMN */
4832  ATSimplePermissions(cmd->subtype, rel,
4834  ATPrepAddColumn(wqueue, rel, recurse, recursing, false, cmd,
4835  lockmode, context);
4836  /* Recursion occurs during execution phase */
4837  pass = AT_PASS_ADD_COL;
4838  break;
4839  case AT_AddColumnToView: /* add column via CREATE OR REPLACE VIEW */
4840  ATSimplePermissions(cmd->subtype, rel, ATT_VIEW);
4841  ATPrepAddColumn(wqueue, rel, recurse, recursing, true, cmd,
4842  lockmode, context);
4843  /* Recursion occurs during execution phase */
4844  pass = AT_PASS_ADD_COL;
4845  break;
4846  case AT_ColumnDefault: /* ALTER COLUMN DEFAULT */
4847 
4848  /*
4849  * We allow defaults on views so that INSERT into a view can have
4850  * default-ish behavior. This works because the rewriter
4851  * substitutes default values into INSERTs before it expands
4852  * rules.
4853  */
4855  ATSimpleRecursion(wqueue, rel, cmd, recurse, lockmode, context);
4856  /* No command-specific prep needed */
4857  pass = cmd->def ? AT_PASS_ADD_OTHERCONSTR : AT_PASS_DROP;
4858  break;
4859  case AT_CookedColumnDefault: /* add a pre-cooked default */
4860  /* This is currently used only in CREATE TABLE */
4861  /* (so the permission check really isn't necessary) */
4863  /* This command never recurses */
4864  pass = AT_PASS_ADD_OTHERCONSTR;
4865  break;
4866  case AT_AddIdentity:
4868  /* Set up recursion for phase 2; no other prep needed */
4869  if (recurse)
4870  cmd->recurse = true;
4871  pass = AT_PASS_ADD_OTHERCONSTR;
4872  break;
4873  case AT_SetIdentity:
4875  /* Set up recursion for phase 2; no other prep needed */
4876  if (recurse)
4877  cmd->recurse = true;
4878  /* This should run after AddIdentity, so do it in MISC pass */
4879  pass = AT_PASS_MISC;
4880  break;
4881  case AT_DropIdentity:
4883  /* Set up recursion for phase 2; no other prep needed */
4884  if (recurse)
4885  cmd->recurse = true;
4886  pass = AT_PASS_DROP;
4887  break;
4888  case AT_DropNotNull: /* ALTER COLUMN DROP NOT NULL */
4890  /* Set up recursion for phase 2; no other prep needed */
4891  if (recurse)
4892  cmd->recurse = true;
4893  pass = AT_PASS_DROP;
4894  break;
4895  case AT_SetNotNull: /* ALTER COLUMN SET NOT NULL */
4897  /* Set up recursion for phase 2; no other prep needed */
4898  if (recurse)
4899  cmd->recurse = true;
4900  pass = AT_PASS_COL_ATTRS;
4901  break;
4902  case AT_SetAttNotNull: /* set pg_attribute.attnotnull without adding
4903  * a constraint */
4905  /* Need command-specific recursion decision */
4906  ATSimpleRecursion(wqueue, rel, cmd, recurse, lockmode, context);
4907  pass = AT_PASS_COL_ATTRS;
4908  break;
4909  case AT_SetExpression: /* ALTER COLUMN SET EXPRESSION */
4911  ATSimpleRecursion(wqueue, rel, cmd, recurse, lockmode, context);
4912  pass = AT_PASS_SET_EXPRESSION;
4913  break;
4914  case AT_DropExpression: /* ALTER COLUMN DROP EXPRESSION */
4916  ATSimpleRecursion(wqueue, rel, cmd, recurse, lockmode, context);
4917  ATPrepDropExpression(rel, cmd, recurse, recursing, lockmode);
4918  pass = AT_PASS_DROP;
4919  break;
4920  case AT_SetStatistics: /* ALTER COLUMN SET STATISTICS */
4922  ATSimpleRecursion(wqueue, rel, cmd, recurse, lockmode, context);
4923  /* No command-specific prep needed */
4924  pass = AT_PASS_MISC;
4925  break;
4926  case AT_SetOptions: /* ALTER COLUMN SET ( options ) */
4927  case AT_ResetOptions: /* ALTER COLUMN RESET ( options ) */
4929  /* This command never recurses */
4930  pass = AT_PASS_MISC;
4931  break;
4932  case AT_SetStorage: /* ALTER COLUMN SET STORAGE */
4934  ATSimpleRecursion(wqueue, rel, cmd, recurse, lockmode, context);
4935  /* No command-specific prep needed */
4936  pass = AT_PASS_MISC;
4937  break;
4938  case AT_SetCompression: /* ALTER COLUMN SET COMPRESSION */
4940  /* This command never recurses */
4941  /* No command-specific prep needed */
4942  pass = AT_PASS_MISC;
4943  break;
4944  case AT_DropColumn: /* DROP COLUMN */
4945  ATSimplePermissions(cmd->subtype, rel,
4947  ATPrepDropColumn(wqueue, rel, recurse, recursing, cmd,
4948  lockmode, context);
4949  /* Recursion occurs during execution phase */
4950  pass = AT_PASS_DROP;
4951  break;
4952  case AT_AddIndex: /* ADD INDEX */
4954  /* This command never recurses */
4955  /* No command-specific prep needed */
4956  pass = AT_PASS_ADD_INDEX;
4957  break;
4958  case AT_AddConstraint: /* ADD CONSTRAINT */
4960  /* Recursion occurs during execution phase */
4961  /* No command-specific prep needed except saving recurse flag */
4962  if (recurse)
4963  cmd->recurse = true;
4964  pass = AT_PASS_ADD_CONSTR;
4965  break;
4966  case AT_AddIndexConstraint: /* ADD CONSTRAINT USING INDEX */
4968  /* This command never recurses */
4969  /* No command-specific prep needed */
4970  pass = AT_PASS_ADD_INDEXCONSTR;
4971  break;
4972  case AT_DropConstraint: /* DROP CONSTRAINT */
4974  ATCheckPartitionsNotInUse(rel, lockmode);
4975  /* Other recursion occurs during execution phase */
4976  /* No command-specific prep needed except saving recurse flag */
4977  if (recurse)
4978  cmd->recurse = true;
4979  pass = AT_PASS_DROP;
4980  break;
4981  case AT_AlterColumnType: /* ALTER COLUMN TYPE */
4982  ATSimplePermissions(cmd->subtype, rel,
4984  /* See comments for ATPrepAlterColumnType */
4985  cmd = ATParseTransformCmd(wqueue, tab, rel, cmd, recurse, lockmode,
4986  AT_PASS_UNSET, context);
4987  Assert(cmd != NULL);
4988  /* Performs own recursion */
4989  ATPrepAlterColumnType(wqueue, tab, rel, recurse, recursing, cmd,
4990  lockmode, context);
4991  pass = AT_PASS_ALTER_TYPE;
4992  break;
4995  /* This command never recurses */
4996  /* No command-specific prep needed */
4997  pass = AT_PASS_MISC;
4998  break;
4999  case AT_ChangeOwner: /* ALTER OWNER */
5000  /* This command never recurses */
5001  /* No command-specific prep needed */
5002  pass = AT_PASS_MISC;
5003  break;
5004  case AT_ClusterOn: /* CLUSTER ON */
5005  case AT_DropCluster: /* SET WITHOUT CLUSTER */
5007  /* These commands never recurse */
5008  /* No command-specific prep needed */
5009  pass = AT_PASS_MISC;
5010  break;
5011  case AT_SetLogged: /* SET LOGGED */
5013  if (tab->chgPersistence)
5014  ereport(ERROR,
5015  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
5016  errmsg("cannot change persistence setting twice")));
5017  tab->chgPersistence = ATPrepChangePersistence(rel, true);
5018  /* force rewrite if necessary; see comment in ATRewriteTables */
5019  if (tab->chgPersistence)
5020  {
5022  tab->newrelpersistence = RELPERSISTENCE_PERMANENT;
5023  }
5024  pass = AT_PASS_MISC;
5025  break;
5026  case AT_SetUnLogged: /* SET UNLOGGED */
5028  if (tab->chgPersistence)
5029  ereport(ERROR,
5030  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
5031  errmsg("cannot change persistence setting twice")));
5032  tab->chgPersistence = ATPrepChangePersistence(rel, false);
5033  /* force rewrite if necessary; see comment in ATRewriteTables */
5034  if (tab->chgPersistence)
5035  {
5037  tab->newrelpersistence = RELPERSISTENCE_UNLOGGED;
5038  }
5039  pass = AT_PASS_MISC;
5040  break;
5041  case AT_DropOids: /* SET WITHOUT OIDS */
5043  pass = AT_PASS_DROP;
5044  break;
5045  case AT_SetAccessMethod: /* SET ACCESS METHOD */
5047 
5048  /* partitioned tables don't have an access method */
5049  if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
5050  ereport(ERROR,
5051  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
5052  errmsg("cannot change access method of a partitioned table")));
5053 
5054  /* check if another access method change was already requested */
5055  if (OidIsValid(tab->newAccessMethod))
5056  ereport(ERROR,
5057  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
5058  errmsg("cannot have multiple SET ACCESS METHOD subcommands")));
5059 
5060  ATPrepSetAccessMethod(tab, rel, cmd->name);
5061  pass = AT_PASS_MISC; /* does not matter; no work in Phase 2 */
5062  break;
5063  case AT_SetTableSpace: /* SET TABLESPACE */
5066  /* This command never recurses */
5067  ATPrepSetTableSpace(tab, rel, cmd->name, lockmode);
5068  pass = AT_PASS_MISC; /* doesn't actually matter */
5069  break;
5070  case AT_SetRelOptions: /* SET (...) */
5071  case AT_ResetRelOptions: /* RESET (...) */
5072  case AT_ReplaceRelOptions: /* reset them all, then set just these */
5074  /* This command never recurses */
5075  /* No command-specific prep needed */
5076  pass = AT_PASS_MISC;
5077  break;
5078  case AT_AddInherit: /* INHERIT */
5080  /* This command never recurses */
5081  ATPrepAddInherit(rel);
5082  pass = AT_PASS_MISC;
5083  break;
5084  case AT_DropInherit: /* NO INHERIT */
5086  /* This command never recurses */
5087  /* No command-specific prep needed */
5088  pass = AT_PASS_MISC;
5089  break;
5090  case AT_AlterConstraint: /* ALTER CONSTRAINT */
5092  /* Recursion occurs during execution phase */
5093  pass = AT_PASS_MISC;
5094  break;
5095  case AT_ValidateConstraint: /* VALIDATE CONSTRAINT */
5097  /* Recursion occurs during execution phase */
5098  /* No command-specific prep needed except saving recurse flag */
5099  if (recurse)
5100  cmd->recurse = true;
5101  pass = AT_PASS_MISC;
5102  break;
5103  case AT_ReplicaIdentity: /* REPLICA IDENTITY ... */
5105  pass = AT_PASS_MISC;
5106  /* This command never recurses */
5107  /* No command-specific prep needed */
5108  break;
5109  case AT_EnableTrig: /* ENABLE TRIGGER variants */
5110  case AT_EnableAlwaysTrig:
5111  case AT_EnableReplicaTrig:
5112  case AT_EnableTrigAll:
5113  case AT_EnableTrigUser:
5114  case AT_DisableTrig: /* DISABLE TRIGGER variants */
5115  case AT_DisableTrigAll:
5116  case AT_DisableTrigUser:
5118  /* Set up recursion for phase 2; no other prep needed */
5119  if (recurse)
5120  cmd->recurse = true;
5121  pass = AT_PASS_MISC;
5122  break;
5123  case AT_EnableRule: /* ENABLE/DISABLE RULE variants */
5124  case AT_EnableAlwaysRule:
5125  case AT_EnableReplicaRule:
5126  case AT_DisableRule:
5127  case AT_AddOf: /* OF */
5128  case AT_DropOf: /* NOT OF */
5129  case AT_EnableRowSecurity:
5130  case AT_DisableRowSecurity:
5131  case AT_ForceRowSecurity:
5132  case AT_NoForceRowSecurity:
5134  /* These commands never recurse */
5135  /* No command-specific prep needed */
5136  pass = AT_PASS_MISC;
5137  break;
5138  case AT_GenericOptions:
5140  /* No command-specific prep needed */
5141  pass = AT_PASS_MISC;
5142  break;
5143  case AT_AttachPartition:
5145  /* No command-specific prep needed */
5146  pass = AT_PASS_MISC;
5147  break;
5148  case AT_DetachPartition:
5150  /* No command-specific prep needed */
5151  pass = AT_PASS_MISC;
5152  break;
5155  /* No command-specific prep needed */
5156  pass = AT_PASS_MISC;
5157  break;
5158  default: /* oops */
5159  elog(ERROR, "unrecognized alter table type: %d",
5160  (int) cmd->subtype);
5161  pass = AT_PASS_UNSET; /* keep compiler quiet */
5162  break;
5163  }
5164  Assert(pass > AT_PASS_UNSET);
5165 
5166  /* Add the subcommand to the appropriate list for phase 2 */
5167  tab->subcmds[pass] = lappend(tab->subcmds[pass], cmd);
5168 }
5169 
5170 /*
5171  * ATRewriteCatalogs
5172  *
5173  * Traffic cop for ALTER TABLE Phase 2 operations. Subcommands are
5174  * dispatched in a "safe" execution order (designed to avoid unnecessary
5175  * conflicts).
5176  */
5177 static void
5178 ATRewriteCatalogs(List **wqueue, LOCKMODE lockmode,
5179  AlterTableUtilityContext *context)
5180 {
5181  ListCell *ltab;
5182 
5183  /*
5184  * We process all the tables "in parallel", one pass at a time. This is
5185  * needed because we may have to propagate work from one table to another
5186  * (specifically, ALTER TYPE on a foreign key's PK has to dispatch the
5187  * re-adding of the foreign key constraint to the other table). Work can
5188  * only be propagated into later passes, however.
5189  */
5190  for (AlterTablePass pass = 0; pass < AT_NUM_PASSES; pass++)
5191  {
5192  /* Go through each table that needs to be processed */
5193  foreach(ltab, *wqueue)
5194  {
5195  AlteredTableInfo *tab = (AlteredTableInfo *) lfirst(ltab);
5196  List *subcmds = tab->subcmds[pass];
5197  ListCell *lcmd;
5198 
5199  if (subcmds == NIL)
5200  continue;
5201 
5202  /*
5203  * Open the relation and store it in tab. This allows subroutines
5204  * close and reopen, if necessary. Appropriate lock was obtained
5205  * by phase 1, needn't get it again.
5206  */
5207  tab->rel = relation_open(tab->relid, NoLock);
5208 
5209  foreach(lcmd, subcmds)
5210  ATExecCmd(wqueue, tab,
5211  lfirst_node(AlterTableCmd, lcmd),
5212  lockmode, pass, context);
5213 
5214  /*
5215  * After the ALTER TYPE or SET EXPRESSION pass, do cleanup work
5216  * (this is not done in ATExecAlterColumnType since it should be
5217  * done only once if multiple columns of a table are altered).
5218  */
5219  if (pass == AT_PASS_ALTER_TYPE || pass == AT_PASS_SET_EXPRESSION)
5220  ATPostAlterTypeCleanup(wqueue, tab, lockmode);
5221 
5222  if (tab->rel)
5223  {
5224  relation_close(tab->rel, NoLock);
5225  tab->rel = NULL;
5226  }
5227  }
5228  }
5229 
5230  /* Check to see if a toast table must be added. */
5231  foreach(ltab, *wqueue)
5232  {
5233  AlteredTableInfo *tab = (AlteredTableInfo *) lfirst(ltab);
5234 
5235  /*
5236  * If the table is source table of ATTACH PARTITION command, we did
5237  * not modify anything about it that will change its toasting
5238  * requirement, so no need to check.
5239  */
5240  if (((tab->relkind == RELKIND_RELATION ||
5241  tab->relkind == RELKIND_PARTITIONED_TABLE) &&
5242  tab->partition_constraint == NULL) ||
5243  tab->relkind == RELKIND_MATVIEW)
5244  AlterTableCreateToastTable(tab->relid, (Datum) 0, lockmode);
5245  }
5246 }
5247 
5248 /*
5249  * ATExecCmd: dispatch a subcommand to appropriate execution routine
5250  */
5251 static void
5253  AlterTableCmd *cmd, LOCKMODE lockmode, AlterTablePass cur_pass,
5254  AlterTableUtilityContext *context)
5255 {
5257  Relation rel = tab->rel;
5258 
5259  switch (cmd->subtype)
5260  {
5261  case AT_AddColumn: /* ADD COLUMN */
5262  case AT_AddColumnToView: /* add column via CREATE OR REPLACE VIEW */
5263  address = ATExecAddColumn(wqueue, tab, rel, &cmd,
5264  cmd->recurse, false,
5265  lockmode, cur_pass, context);
5266  break;
5267  case AT_ColumnDefault: /* ALTER COLUMN DEFAULT */
5268  address = ATExecColumnDefault(rel, cmd->name, cmd->def, lockmode);
5269  break;
5270  case AT_CookedColumnDefault: /* add a pre-cooked default */
5271  address = ATExecCookedColumnDefault(rel, cmd->num, cmd->def);
5272  break;
5273  case AT_AddIdentity:
5274  cmd = ATParseTransformCmd(wqueue, tab, rel, cmd, false, lockmode,
5275  cur_pass, context);
5276  Assert(cmd != NULL);
5277  address = ATExecAddIdentity(rel, cmd->name, cmd->def, lockmode, cmd->recurse, false);
5278  break;
5279  case AT_SetIdentity:
5280  cmd = ATParseTransformCmd(wqueue, tab, rel, cmd, false, lockmode,
5281  cur_pass, context);
5282  Assert(cmd != NULL);
5283  address = ATExecSetIdentity(rel, cmd->name, cmd->def, lockmode, cmd->recurse, false);
5284  break;
5285  case AT_DropIdentity:
5286  address = ATExecDropIdentity(rel, cmd->name, cmd->missing_ok, lockmode, cmd->recurse, false);
5287  break;
5288  case AT_DropNotNull: /* ALTER COLUMN DROP NOT NULL */
5289  address = ATExecDropNotNull(rel, cmd->name, cmd->recurse, lockmode);
5290  break;
5291  case AT_SetNotNull: /* ALTER COLUMN SET NOT NULL */
5292  address = ATExecSetNotNull(wqueue, rel, NULL, cmd->name,
5293  cmd->recurse, false, NULL, lockmode);
5294  break;
5295  case AT_SetAttNotNull: /* set pg_attribute.attnotnull */
5296  address = ATExecSetAttNotNull(wqueue, rel, cmd->name, lockmode);
5297  break;
5298  case AT_SetExpression:
5299  address = ATExecSetExpression(tab, rel, cmd->name, cmd->def, lockmode);
5300  break;
5301  case AT_DropExpression:
5302  address = ATExecDropExpression(rel, cmd->name, cmd->missing_ok, lockmode);
5303  break;
5304  case AT_SetStatistics: /* ALTER COLUMN SET STATISTICS */
5305  address = ATExecSetStatistics(rel, cmd->name, cmd->num, cmd->def, lockmode);
5306  break;
5307  case AT_SetOptions: /* ALTER COLUMN SET ( options ) */
5308  address = ATExecSetOptions(rel, cmd->name, cmd->def, false, lockmode);
5309  break;
5310  case AT_ResetOptions: /* ALTER COLUMN RESET ( options ) */
5311  address = ATExecSetOptions(rel, cmd->name, cmd->def, true, lockmode);
5312  break;
5313  case AT_SetStorage: /* ALTER COLUMN SET STORAGE */
5314  address = ATExecSetStorage(rel, cmd->name, cmd->def, lockmode);
5315  break;
5316  case AT_SetCompression: /* ALTER COLUMN SET COMPRESSION */
5317  address = ATExecSetCompression(rel, cmd->name, cmd->def,
5318  lockmode);
5319  break;
5320  case AT_DropColumn: /* DROP COLUMN */
5321  address = ATExecDropColumn(wqueue, rel, cmd->name,
5322  cmd->behavior, cmd->recurse, false,
5323  cmd->missing_ok, lockmode,
5324  NULL);
5325  break;
5326  case AT_AddIndex: /* ADD INDEX */
5327  address = ATExecAddIndex(tab, rel, (IndexStmt *) cmd->def, false,
5328  lockmode);
5329  break;
5330  case AT_ReAddIndex: /* ADD INDEX */
5331  address = ATExecAddIndex(tab, rel, (IndexStmt *) cmd->def, true,
5332  lockmode);
5333  break;
5334  case AT_ReAddStatistics: /* ADD STATISTICS */
5335  address = ATExecAddStatistics(tab, rel, (CreateStatsStmt *) cmd->def,
5336  true, lockmode);
5337  break;
5338  case AT_AddConstraint: /* ADD CONSTRAINT */
5339  /* Transform the command only during initial examination */
5340  if (cur_pass == AT_PASS_ADD_CONSTR)
5341  cmd = ATParseTransformCmd(wqueue, tab, rel, cmd,
5342  cmd->recurse, lockmode,
5343  cur_pass, context);
5344  /* Depending on constraint type, might be no more work to do now */
5345  if (cmd != NULL)
5346  address =
5347  ATExecAddConstraint(wqueue, tab, rel,
5348  (Constraint *) cmd->def,
5349  cmd->recurse, false, lockmode);
5350  break;
5351  case AT_ReAddConstraint: /* Re-add pre-existing check constraint */
5352  address =
5353  ATExecAddConstraint(wqueue, tab, rel, (Constraint *) cmd->def,
5354  true, true, lockmode);
5355  break;
5356  case AT_ReAddDomainConstraint: /* Re-add pre-existing domain check
5357  * constraint */
5358  address =
5359  AlterDomainAddConstraint(((AlterDomainStmt *) cmd->def)->typeName,
5360  ((AlterDomainStmt *) cmd->def)->def,
5361  NULL);
5362  break;
5363  case AT_ReAddComment: /* Re-add existing comment */
5364  address = CommentObject((CommentStmt *) cmd->def);
5365  break;
5366  case AT_AddIndexConstraint: /* ADD CONSTRAINT USING INDEX */
5367  address = ATExecAddIndexConstraint(tab, rel, (IndexStmt *) cmd->def,
5368  lockmode);
5369  break;
5370  case AT_AlterConstraint: /* ALTER CONSTRAINT */
5371  address = ATExecAlterConstraint(rel, cmd, false, false, lockmode);
5372  break;
5373  case AT_ValidateConstraint: /* VALIDATE CONSTRAINT */
5374  address = ATExecValidateConstraint(wqueue, rel, cmd->name, cmd->recurse,
5375  false, lockmode);
5376  break;
5377  case AT_DropConstraint: /* DROP CONSTRAINT */
5378  ATExecDropConstraint(rel, cmd->name, cmd->behavior,
5379  cmd->recurse,
5380  cmd->missing_ok, lockmode);
5381  break;
5382  case AT_AlterColumnType: /* ALTER COLUMN TYPE */
5383  /* parse transformation was done earlier */
5384  address = ATExecAlterColumnType(tab, rel, cmd, lockmode);
5385  break;
5386  case AT_AlterColumnGenericOptions: /* ALTER COLUMN OPTIONS */
5387  address =
5389  (List *) cmd->def, lockmode);
5390  break;
5391  case AT_ChangeOwner: /* ALTER OWNER */
5393  get_rolespec_oid(cmd->newowner, false),
5394  false, lockmode);
5395  break;
5396  case AT_ClusterOn: /* CLUSTER ON */
5397  address = ATExecClusterOn(rel, cmd->name, lockmode);
5398  break;
5399  case AT_DropCluster: /* SET WITHOUT CLUSTER */
5400  ATExecDropCluster(rel, lockmode);
5401  break;
5402  case AT_SetLogged: /* SET LOGGED */
5403  case AT_SetUnLogged: /* SET UNLOGGED */
5404  break;
5405  case AT_DropOids: /* SET WITHOUT OIDS */
5406  /* nothing to do here, oid columns don't exist anymore */
5407  break;
5408  case AT_SetAccessMethod: /* SET ACCESS METHOD */
5409  /* handled specially in Phase 3 */
5410  break;
5411  case AT_SetTableSpace: /* SET TABLESPACE */
5412 
5413  /*
5414  * Only do this for partitioned tables and indexes, for which this
5415  * is just a catalog change. Other relation types which have
5416  * storage are handled by Phase 3.
5417  */
5418  if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE ||
5419  rel->rd_rel->relkind == RELKIND_PARTITIONED_INDEX)
5421 
5422  break;
5423  case AT_SetRelOptions: /* SET (...) */
5424  case AT_ResetRelOptions: /* RESET (...) */
5425  case AT_ReplaceRelOptions: /* replace entire option list */
5426  ATExecSetRelOptions(rel, (List *) cmd->def, cmd->subtype, lockmode);
5427  break;
5428  case AT_EnableTrig: /* ENABLE TRIGGER name */
5429  ATExecEnableDisableTrigger(rel, cmd->name,
5430  TRIGGER_FIRES_ON_ORIGIN, false,
5431  cmd->recurse,
5432  lockmode);
5433  break;
5434  case AT_EnableAlwaysTrig: /* ENABLE ALWAYS TRIGGER name */
5435  ATExecEnableDisableTrigger(rel, cmd->name,
5436  TRIGGER_FIRES_ALWAYS, false,
5437  cmd->recurse,
5438  lockmode);
5439  break;
5440  case AT_EnableReplicaTrig: /* ENABLE REPLICA TRIGGER name */
5441  ATExecEnableDisableTrigger(rel, cmd->name,
5442  TRIGGER_FIRES_ON_REPLICA, false,
5443  cmd->recurse,
5444  lockmode);
5445  break;
5446  case AT_DisableTrig: /* DISABLE TRIGGER name */
5447  ATExecEnableDisableTrigger(rel, cmd->name,
5448  TRIGGER_DISABLED, false,
5449  cmd->recurse,
5450  lockmode);
5451  break;
5452  case AT_EnableTrigAll: /* ENABLE TRIGGER ALL */
5453  ATExecEnableDisableTrigger(rel, NULL,
5454  TRIGGER_FIRES_ON_ORIGIN, false,
5455  cmd->recurse,
5456  lockmode);
5457  break;
5458  case AT_DisableTrigAll: /* DISABLE TRIGGER ALL */
5459  ATExecEnableDisableTrigger(rel, NULL,
5460  TRIGGER_DISABLED, false,
5461  cmd->recurse,
5462  lockmode);
5463  break;
5464  case AT_EnableTrigUser: /* ENABLE TRIGGER USER */
5465  ATExecEnableDisableTrigger(rel, NULL,
5467  cmd->recurse,
5468  lockmode);
5469  break;
5470  case AT_DisableTrigUser: /* DISABLE TRIGGER USER */
5471  ATExecEnableDisableTrigger(rel, NULL,
5472  TRIGGER_DISABLED, true,
5473  cmd->recurse,
5474  lockmode);
5475  break;
5476 
5477  case AT_EnableRule: /* ENABLE RULE name */
5478  ATExecEnableDisableRule(rel, cmd->name,
5479  RULE_FIRES_ON_ORIGIN, lockmode);
5480  break;
5481  case AT_EnableAlwaysRule: /* ENABLE ALWAYS RULE name */
5482  ATExecEnableDisableRule(rel, cmd->name,
5483  RULE_FIRES_ALWAYS, lockmode);
5484  break;
5485  case AT_EnableReplicaRule: /* ENABLE REPLICA RULE name */
5486  ATExecEnableDisableRule(rel, cmd->name,
5487  RULE_FIRES_ON_REPLICA, lockmode);
5488  break;
5489  case AT_DisableRule: /* DISABLE RULE name */
5490  ATExecEnableDisableRule(rel, cmd->name,
5491  RULE_DISABLED, lockmode);
5492  break;
5493 
5494  case AT_AddInherit:
5495  address = ATExecAddInherit(rel, (RangeVar *) cmd->def, lockmode);
5496  break;
5497  case AT_DropInherit:
5498  address = ATExecDropInherit(rel, (RangeVar *) cmd->def, lockmode);
5499  break;
5500  case AT_AddOf:
5501  address = ATExecAddOf(rel, (TypeName *) cmd->def, lockmode);
5502  break;
5503  case AT_DropOf:
5504  ATExecDropOf(rel, lockmode);
5505  break;
5506  case AT_ReplicaIdentity:
5507  ATExecReplicaIdentity(rel, (ReplicaIdentityStmt *) cmd->def, lockmode);
5508  break;
5509  case AT_EnableRowSecurity:
5510  ATExecSetRowSecurity(rel, true);
5511  break;
5512  case AT_DisableRowSecurity:
5513  ATExecSetRowSecurity(rel, false);
5514  break;
5515  case AT_ForceRowSecurity:
5516  ATExecForceNoForceRowSecurity(rel, true);
5517  break;
5518  case AT_NoForceRowSecurity:
5519  ATExecForceNoForceRowSecurity(rel, false);
5520  break;
5521  case AT_GenericOptions:
5522  ATExecGenericOptions(rel, (List *) cmd->def);
5523  break;
5524  case AT_AttachPartition:
5525  cmd = ATParseTransformCmd(wqueue, tab, rel, cmd, false, lockmode,
5526  cur_pass, context);
5527  Assert(cmd != NULL);
5528  if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
5529  address = ATExecAttachPartition(wqueue, rel, (PartitionCmd *) cmd->def,
5530  context);
5531  else
5532  address = ATExecAttachPartitionIdx(wqueue, rel,
5533  ((PartitionCmd *) cmd->def)->name);
5534  break;
5535  case AT_DetachPartition:
5536  cmd = ATParseTransformCmd(wqueue, tab, rel, cmd, false, lockmode,
5537  cur_pass, context);
5538  Assert(cmd != NULL);
5539  /* ATPrepCmd ensures it must be a table */
5540  Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
5541  address = ATExecDetachPartition(wqueue, tab, rel,
5542  ((PartitionCmd *) cmd->def)->name,
5543  ((PartitionCmd *) cmd->def)->concurrent);
5544  break;
5546  address = ATExecDetachPartitionFinalize(rel, ((PartitionCmd *) cmd->def)->name);
5547  break;
5548  default: /* oops */
5549  elog(ERROR, "unrecognized alter table type: %d",
5550  (int) cmd->subtype);
5551  break;
5552  }
5553 
5554  /*
5555  * Report the subcommand to interested event triggers.
5556  */
5557  if (cmd)
5558  EventTriggerCollectAlterTableSubcmd((Node *) cmd, address);
5559 
5560  /*
5561  * Bump the command counter to ensure the next subcommand in the sequence
5562  * can see the changes so far
5563  */
5565 }
5566 
5567 /*
5568  * ATParseTransformCmd: perform parse transformation for one subcommand
5569  *
5570  * Returns the transformed subcommand tree, if there is one, else NULL.
5571  *
5572  * The parser may hand back additional AlterTableCmd(s) and/or other
5573  * utility statements, either before or after the original subcommand.
5574  * Other AlterTableCmds are scheduled into the appropriate slot of the
5575  * AlteredTableInfo (they had better be for later passes than the current one).
5576  * Utility statements that are supposed to happen before the AlterTableCmd
5577  * are executed immediately. Those that are supposed to happen afterwards
5578  * are added to the tab->afterStmts list to be done at the very end.
5579  */
5580 static AlterTableCmd *
5582  AlterTableCmd *cmd, bool recurse, LOCKMODE lockmode,
5583  AlterTablePass cur_pass, AlterTableUtilityContext *context)
5584 {
5585  AlterTableCmd *newcmd = NULL;
5587  List *beforeStmts;
5588  List *afterStmts;
5589  ListCell *lc;
5590 
5591  /* Gin up an AlterTableStmt with just this subcommand and this table */
5592  atstmt->relation =
5595  -1);
5596  atstmt->relation->inh = recurse;
5597  atstmt->cmds = list_make1(cmd);
5598  atstmt->objtype = OBJECT_TABLE; /* needn't be picky here */
5599  atstmt->missing_ok = false;
5600 
5601  /* Transform the AlterTableStmt */
5603  atstmt,
5604  context->queryString,
5605  &beforeStmts,
5606  &afterStmts);
5607 
5608  /* Execute any statements that should happen before these subcommand(s) */
5609  foreach(lc, beforeStmts)
5610  {
5611  Node *stmt = (Node *) lfirst(lc);
5612 
5615  }
5616 
5617  /* Examine the transformed subcommands and schedule them appropriately */
5618  foreach(lc, atstmt->cmds)
5619  {
5621  AlterTablePass pass;
5622 
5623  /*
5624  * This switch need only cover the subcommand types that can be added
5625  * by parse_utilcmd.c; otherwise, we'll use the default strategy of
5626  * executing the subcommand immediately, as a substitute for the
5627  * original subcommand. (Note, however, that this does cause
5628  * AT_AddConstraint subcommands to be rescheduled into later passes,
5629  * which is important for index and foreign key constraints.)
5630  *
5631  * We assume we needn't do any phase-1 checks for added subcommands.
5632  */
5633  switch (cmd2->subtype)
5634  {
5635  case AT_SetAttNotNull:
5636  ATSimpleRecursion(wqueue, rel, cmd2, recurse, lockmode, context);
5637  pass = AT_PASS_COL_ATTRS;
5638  break;
5639  case AT_AddIndex:
5640 
5641  /*
5642  * A primary key on a inheritance parent needs supporting NOT
5643  * NULL constraint on its children; enqueue commands to create
5644  * those or mark them inherited if they already exist.
5645  */
5646  ATPrepAddPrimaryKey(wqueue, rel, cmd2, lockmode, context);
5647  pass = AT_PASS_ADD_INDEX;
5648  break;
5649  case AT_AddIndexConstraint:
5650  /* as above */
5651  ATPrepAddPrimaryKey(wqueue, rel, cmd2, lockmode, context);
5652  pass = AT_PASS_ADD_INDEXCONSTR;
5653  break;
5654  case AT_AddConstraint:
5655  /* Recursion occurs during execution phase */
5656  if (recurse)
5657  cmd2->recurse = true;
5658  switch (castNode(Constraint, cmd2->def)->contype)
5659  {
5660  case CONSTR_PRIMARY:
5661  case CONSTR_UNIQUE:
5662  case CONSTR_EXCLUSION:
5663  pass = AT_PASS_ADD_INDEXCONSTR;
5664  break;
5665  default:
5666  pass = AT_PASS_ADD_OTHERCONSTR;
5667  break;
5668  }
5669  break;
5671  /* This command never recurses */
5672  /* No command-specific prep needed */
5673  pass = AT_PASS_MISC;
5674  break;
5675  default:
5676  pass = cur_pass;
5677  break;
5678  }
5679 
5680  if (pass < cur_pass)
5681  {
5682  /* Cannot schedule into a pass we already finished */
5683  elog(ERROR, "ALTER TABLE scheduling failure: too late for pass %d",
5684  pass);
5685  }
5686  else if (pass > cur_pass)
5687  {
5688  /* OK, queue it up for later */
5689  tab->subcmds[pass] = lappend(tab->subcmds[pass], cmd2);
5690  }
5691  else
5692  {
5693  /*
5694  * We should see at most one subcommand for the current pass,
5695  * which is the transformed version of the original subcommand.
5696  */
5697  if (newcmd == NULL && cmd->subtype == cmd2->subtype)
5698  {
5699  /* Found the transformed version of our subcommand */
5700  newcmd = cmd2;
5701  }
5702  else
5703  elog(ERROR, "ALTER TABLE scheduling failure: bogus item for pass %d",
5704  pass);
5705  }
5706  }
5707 
5708  /* Queue up any after-statements to happen at the end */
5709  tab->afterStmts = list_concat(tab->afterStmts, afterStmts);
5710 
5711  return newcmd;
5712 }
5713 
5714 /*
5715  * ATRewriteTables: ALTER TABLE phase 3
5716  */
5717 static void
5718 ATRewriteTables(AlterTableStmt *parsetree, List **wqueue, LOCKMODE lockmode,
5719  AlterTableUtilityContext *context)
5720 {
5721  ListCell *ltab;
5722 
5723  /* Go through each table that needs to be checked or rewritten */
5724  foreach(ltab, *wqueue)
5725  {
5726  AlteredTableInfo *tab = (AlteredTableInfo *) lfirst(ltab);
5727 
5728  /* Relations without storage may be ignored here */
5729  if (!RELKIND_HAS_STORAGE(tab->relkind))
5730  continue;
5731 
5732  /*
5733  * If we change column data types, the operation has to be propagated
5734  * to tables that use this table's rowtype as a column type.
5735  * tab->newvals will also be non-NULL in the case where we're adding a
5736  * column with a default. We choose to forbid that case as well,
5737  * since composite types might eventually support defaults.
5738  *
5739  * (Eventually we'll probably need to check for composite type
5740  * dependencies even when we're just scanning the table without a
5741  * rewrite, but at the moment a composite type does not enforce any
5742  * constraints, so it's not necessary/appropriate to enforce them just
5743  * during ALTER.)
5744  */
5745  if (tab->newvals != NIL || tab->rewrite > 0)
5746  {
5747  Relation rel;
5748 
5749  rel = table_open(tab->relid, NoLock);
5750  find_composite_type_dependencies(rel->rd_rel->reltype, rel, NULL);
5751  table_close(rel, NoLock);
5752  }
5753 
5754  /*
5755  * We only need to rewrite the table if at least one column needs to
5756  * be recomputed, or we are changing its persistence or access method.
5757  *
5758  * There are two reasons for requiring a rewrite when changing
5759  * persistence: on one hand, we need to ensure that the buffers
5760  * belonging to each of the two relations are marked with or without
5761  * BM_PERMANENT properly. On the other hand, since rewriting creates
5762  * and assigns a new relfilenumber, we automatically create or drop an
5763  * init fork for the relation as appropriate.
5764  */
5765  if (tab->rewrite > 0 && tab->relkind != RELKIND_SEQUENCE)
5766  {
5767  /* Build a temporary relation and copy data */
5768  Relation OldHeap;
5769  Oid OIDNewHeap;
5770  Oid NewAccessMethod;
5771  Oid NewTableSpace;
5772  char persistence;
5773 
5774  OldHeap = table_open(tab->relid, NoLock);
5775 
5776  /*
5777  * We don't support rewriting of system catalogs; there are too
5778  * many corner cases and too little benefit. In particular this
5779  * is certainly not going to work for mapped catalogs.
5780  */
5781  if (IsSystemRelation(OldHeap))
5782  ereport(ERROR,
5783  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
5784  errmsg("cannot rewrite system relation \"%s\"",
5785  RelationGetRelationName(OldHeap))));
5786 
5787  if (RelationIsUsedAsCatalogTable(OldHeap))
5788  ereport(ERROR,
5789  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
5790  errmsg("cannot rewrite table \"%s\" used as a catalog table",
5791  RelationGetRelationName(OldHeap))));
5792 
5793  /*
5794  * Don't allow rewrite on temp tables of other backends ... their
5795  * local buffer manager is not going to cope.
5796  */
5797  if (RELATION_IS_OTHER_TEMP(OldHeap))
5798  ereport(ERROR,
5799  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
5800  errmsg("cannot rewrite temporary tables of other sessions")));
5801 
5802  /*
5803  * Select destination tablespace (same as original unless user
5804  * requested a change)
5805  */
5806  if (tab->newTableSpace)
5807  NewTableSpace = tab->newTableSpace;
5808  else
5809  NewTableSpace = OldHeap->rd_rel->reltablespace;
5810 
5811  /*
5812  * Select destination access method (same as original unless user
5813  * requested a change)
5814  */
5815  if (OidIsValid(tab->newAccessMethod))
5816  NewAccessMethod = tab->newAccessMethod;
5817  else
5818  NewAccessMethod = OldHeap->rd_rel->relam;
5819 
5820  /*
5821  * Select persistence of transient table (same as original unless
5822  * user requested a change)
5823  */
5824  persistence = tab->chgPersistence ?
5825  tab->newrelpersistence : OldHeap->rd_rel->relpersistence;
5826 
5827  table_close(OldHeap, NoLock);
5828 
5829  /*
5830  * Fire off an Event Trigger now, before actually rewriting the
5831  * table.
5832  *
5833  * We don't support Event Trigger for nested commands anywhere,
5834  * here included, and parsetree is given NULL when coming from
5835  * AlterTableInternal.
5836  *
5837  * And fire it only once.
5838  */
5839  if (parsetree)
5840  EventTriggerTableRewrite((Node *) parsetree,
5841  tab->relid,
5842  tab->rewrite);
5843 
5844  /*
5845  * Create transient table that will receive the modified data.
5846  *
5847  * Ensure it is marked correctly as logged or unlogged. We have
5848  * to do this here so that buffers for the new relfilenumber will
5849  * have the right persistence set, and at the same time ensure
5850  * that the original filenumbers's buffers will get read in with
5851  * the correct setting (i.e. the original one). Otherwise a
5852  * rollback after the rewrite would possibly result with buffers
5853  * for the original filenumbers having the wrong persistence
5854  * setting.
5855  *
5856  * NB: This relies on swap_relation_files() also swapping the
5857  * persistence. That wouldn't work for pg_class, but that can't be
5858  * unlogged anyway.
5859  */
5860  OIDNewHeap = make_new_heap(tab->relid, NewTableSpace, NewAccessMethod,
5861  persistence, lockmode);
5862 
5863  /*
5864  * Copy the heap data into the new table with the desired
5865  * modifications, and test the current data within the table
5866  * against new constraints generated by ALTER TABLE commands.
5867  */
5868  ATRewriteTable(tab, OIDNewHeap, lockmode);
5869 
5870  /*
5871  * Swap the physical files of the old and new heaps, then rebuild
5872  * indexes and discard the old heap. We can use RecentXmin for
5873  * the table's new relfrozenxid because we rewrote all the tuples
5874  * in ATRewriteTable, so no older Xid remains in the table. Also,
5875  * we never try to swap toast tables by content, since we have no
5876  * interest in letting this code work on system catalogs.
5877  */
5878  finish_heap_swap(tab->relid, OIDNewHeap,
5879  false, false, true,
5880  !OidIsValid(tab->newTableSpace),
5881  RecentXmin,
5883  persistence);
5884 
5885  InvokeObjectPostAlterHook(RelationRelationId, tab->relid, 0);
5886  }
5887  else if (tab->rewrite > 0 && tab->relkind == RELKIND_SEQUENCE)
5888  {
5889  if (tab->chgPersistence)
5891  }
5892  else
5893  {
5894  /*
5895  * If required, test the current data within the table against new
5896  * constraints generated by ALTER TABLE commands, but don't
5897  * rebuild data.
5898  */
5899  if (tab->constraints != NIL || tab->verify_new_notnull ||
5900  tab->partition_constraint != NULL)
5901  ATRewriteTable(tab, InvalidOid, lockmode);
5902 
5903  /*
5904  * If we had SET TABLESPACE but no reason to reconstruct tuples,
5905  * just do a block-by-block copy.
5906  */
5907  if (tab->newTableSpace)
5908  ATExecSetTableSpace(tab->relid, tab->newTableSpace, lockmode);
5909  }
5910 
5911  /*
5912  * Also change persistence of owned sequences, so that it matches the
5913  * table persistence.
5914  */
5915  if (tab->chgPersistence)
5916  {
5917  List *seqlist = getOwnedSequences(tab->relid);
5918  ListCell *lc;
5919 
5920  foreach(lc, seqlist)
5921  {
5922  Oid seq_relid = lfirst_oid(lc);
5923 
5925  }
5926  }
5927  }
5928 
5929  /*
5930  * Foreign key constraints are checked in a final pass, since (a) it's
5931  * generally best to examine each one separately, and (b) it's at least
5932  * theoretically possible that we have changed both relations of the
5933  * foreign key, and we'd better have finished both rewrites before we try
5934  * to read the tables.
5935  */
5936  foreach(ltab, *wqueue)
5937  {
5938  AlteredTableInfo *tab = (AlteredTableInfo *) lfirst(ltab);
5939  Relation rel = NULL;
5940  ListCell *lcon;
5941 
5942  /* Relations without storage may be ignored here too */
5943  if (!RELKIND_HAS_STORAGE(tab->relkind))
5944  continue;
5945 
5946  foreach(lcon, tab->constraints)
5947  {
5948  NewConstraint *con = lfirst(lcon);
5949 
5950  if (con->contype == CONSTR_FOREIGN)
5951  {
5952  Constraint *fkconstraint = (Constraint *) con->qual;
5953  Relation refrel;
5954 
5955  if (rel == NULL)
5956  {
5957  /* Long since locked, no need for another */
5958  rel = table_open(tab->relid, NoLock);
5959  }
5960 
5961  refrel = table_open(con->refrelid, RowShareLock);
5962 
5963  validateForeignKeyConstraint(fkconstraint->conname, rel, refrel,
5964  con->refindid,
5965  con->conid);
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_NOTNULL:
6318  case CONSTR_FOREIGN:
6319  /* Nothing to do here */
6320  break;
6321  default:
6322  elog(ERROR, "unrecognized constraint type: %d",
6323  (int) con->contype);
6324  }
6325  }
6326 
6327  if (partqualstate && !ExecCheck(partqualstate, econtext))
6328  {
6329  if (tab->validate_default)
6330  ereport(ERROR,
6331  (errcode(ERRCODE_CHECK_VIOLATION),
6332  errmsg("updated partition constraint for default partition \"%s\" would be violated by some row",
6333  RelationGetRelationName(oldrel)),
6334  errtable(oldrel)));
6335  else
6336  ereport(ERROR,
6337  (errcode(ERRCODE_CHECK_VIOLATION),
6338  errmsg("partition constraint of relation \"%s\" is violated by some row",
6339  RelationGetRelationName(oldrel)),
6340  errtable(oldrel)));
6341  }
6342 
6343  /* Write the tuple out to the new relation */
6344  if (newrel)
6345  table_tuple_insert(newrel, insertslot, mycid,
6346  ti_options, bistate);
6347 
6348  ResetExprContext(econtext);
6349 
6351  }
6352 
6353  MemoryContextSwitchTo(oldCxt);
6354  table_endscan(scan);
6355  UnregisterSnapshot(snapshot);
6356 
6358  if (newslot)
6360  }
6361 
6362  FreeExecutorState(estate);
6363 
6364  table_close(oldrel, NoLock);
6365  if (newrel)
6366  {
6367  FreeBulkInsertState(bistate);
6368 
6369  table_finish_bulk_insert(newrel, ti_options);
6370 
6371  table_close(newrel, NoLock);
6372  }
6373 }
6374 
6375 /*
6376  * ATGetQueueEntry: find or create an entry in the ALTER TABLE work queue
6377  */
6378 static AlteredTableInfo *
6380 {
6381  Oid relid = RelationGetRelid(rel);
6382  AlteredTableInfo *tab;
6383  ListCell *ltab;
6384 
6385  foreach(ltab, *wqueue)
6386  {
6387  tab = (AlteredTableInfo *) lfirst(ltab);
6388  if (tab->relid == relid)
6389  return tab;
6390  }
6391 
6392  /*
6393  * Not there, so add it. Note that we make a copy of the relation's
6394  * existing descriptor before anything interesting can happen to it.
6395  */
6396  tab = (AlteredTableInfo *) palloc0(sizeof(AlteredTableInfo));
6397  tab->relid = relid;
6398  tab->rel = NULL; /* set later */
6399  tab->relkind = rel->rd_rel->relkind;
6401  tab->newAccessMethod = InvalidOid;
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_SetAttNotNull:
6427  return NULL; /* not real grammar */
6428  case AT_SetExpression:
6429  return "ALTER COLUMN ... SET EXPRESSION";
6430  case AT_DropExpression:
6431  return "ALTER COLUMN ... DROP EXPRESSION";
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  case RELKIND_PARTITIONED_TABLE:
6565  actual_target = ATT_TABLE;
6566  break;
6567  case RELKIND_VIEW:
6568  actual_target = ATT_VIEW;
6569  break;
6570  case RELKIND_MATVIEW:
6571  actual_target = ATT_MATVIEW;
6572  break;
6573  case RELKIND_INDEX:
6574  actual_target = ATT_INDEX;
6575  break;
6576  case RELKIND_PARTITIONED_INDEX:
6577  actual_target = ATT_PARTITIONED_INDEX;
6578  break;
6579  case RELKIND_COMPOSITE_TYPE:
6580  actual_target = ATT_COMPOSITE_TYPE;
6581  break;
6582  case RELKIND_FOREIGN_TABLE:
6583  actual_target = ATT_FOREIGN_TABLE;
6584  break;
6585  case RELKIND_SEQUENCE:
6586  actual_target = ATT_SEQUENCE;
6587  break;
6588  default:
6589  actual_target = 0;
6590  break;
6591  }
6592 
6593  /* Wrong target type? */
6594  if ((actual_target & allowed_targets) == 0)
6595  {
6596  const char *action_str = alter_table_type_to_string(cmdtype);
6597 
6598  if (action_str)
6599  ereport(ERROR,
6600  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
6601  /* translator: %s is a group of some SQL keywords */
6602  errmsg("ALTER action %s cannot be performed on relation \"%s\"",
6603  action_str, RelationGetRelationName(rel)),
6604  errdetail_relkind_not_supported(rel->rd_rel->relkind)));
6605  else
6606  /* internal error? */
6607  elog(ERROR, "invalid ALTER action attempted on relation \"%s\"",
6609  }
6610 
6611  /* Permissions checks */
6612  if (!object_ownercheck(RelationRelationId, RelationGetRelid(rel), GetUserId()))
6615 
6617  ereport(ERROR,
6618  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
6619  errmsg("permission denied: \"%s\" is a system catalog",
6620  RelationGetRelationName(rel))));
6621 }
6622 
6623 /*
6624  * ATSimpleRecursion
6625  *
6626  * Simple table recursion sufficient for most ALTER TABLE operations.
6627  * All direct and indirect children are processed in an unspecified order.
6628  * Note that if a child inherits from the original table via multiple
6629  * inheritance paths, it will be visited just once.
6630  */
6631 static void
6633  AlterTableCmd *cmd, bool recurse, LOCKMODE lockmode,
6634  AlterTableUtilityContext *context)
6635 {
6636  /*
6637  * Propagate to children, if desired and if there are (or might be) any
6638  * children.
6639  */
6640  if (recurse && rel->rd_rel->relhassubclass)
6641  {
6642  Oid relid = RelationGetRelid(rel);
6643  ListCell *child;
6644  List *children;
6645 
6646  children = find_all_inheritors(relid, lockmode, NULL);
6647 
6648  /*
6649  * find_all_inheritors does the recursive search of the inheritance
6650  * hierarchy, so all we have to do is process all of the relids in the
6651  * list that it returns.
6652  */
6653  foreach(child, children)
6654  {
6655  Oid childrelid = lfirst_oid(child);
6656  Relation childrel;
6657 
6658  if (childrelid == relid)
6659  continue;
6660  /* find_all_inheritors already got lock */
6661  childrel = relation_open(childrelid, NoLock);
6662  CheckTableNotInUse(childrel, "ALTER TABLE");
6663  ATPrepCmd(wqueue, childrel, cmd, false, true, lockmode, context);
6664  relation_close(childrel, NoLock);
6665  }
6666  }
6667 }
6668 
6669 /*
6670  * Obtain list of partitions of the given table, locking them all at the given
6671  * lockmode and ensuring that they all pass CheckTableNotInUse.
6672  *
6673  * This function is a no-op if the given relation is not a partitioned table;
6674  * in particular, nothing is done if it's a legacy inheritance parent.
6675  */
6676 static void
6678 {
6679  if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
6680  {
6681  List *inh;
6682  ListCell *cell;
6683 
6684  inh = find_all_inheritors(RelationGetRelid(rel), lockmode, NULL);
6685  /* first element is the parent rel; must ignore it */
6686  for_each_from(cell, inh, 1)
6687  {
6688  Relation childrel;
6689 
6690  /* find_all_inheritors already got lock */
6691  childrel = table_open(lfirst_oid(cell), NoLock);
6692  CheckTableNotInUse(childrel, "ALTER TABLE");
6693  table_close(childrel, NoLock);
6694  }
6695  list_free(inh);
6696  }
6697 }
6698 
6699 /*
6700  * ATTypedTableRecursion
6701  *
6702  * Propagate ALTER TYPE operations to the typed tables of that type.
6703  * Also check the RESTRICT/CASCADE behavior. Given CASCADE, also permit
6704  * recursion to inheritance children of the typed tables.
6705  */
6706 static void
6708  LOCKMODE lockmode, AlterTableUtilityContext *context)
6709 {
6710  ListCell *child;
6711  List *children;
6712 
6713  Assert(rel->rd_rel->relkind == RELKIND_COMPOSITE_TYPE);
6714 
6715  children = find_typed_table_dependencies(rel->rd_rel->reltype,
6717  cmd->behavior);
6718 
6719  foreach(child, children)
6720  {
6721  Oid childrelid = lfirst_oid(child);
6722  Relation childrel;
6723 
6724  childrel = relation_open(childrelid, lockmode);
6725  CheckTableNotInUse(childrel, "ALTER TABLE");
6726  ATPrepCmd(wqueue, childrel, cmd, true, true, lockmode, context);
6727  relation_close(childrel, NoLock);
6728  }
6729 }
6730 
6731 
6732 /*
6733  * find_composite_type_dependencies
6734  *
6735  * Check to see if the type "typeOid" is being used as a column in some table
6736  * (possibly nested several levels deep in composite types, arrays, etc!).
6737  * Eventually, we'd like to propagate the check or rewrite operation
6738  * into such tables, but for now, just error out if we find any.
6739  *
6740  * Caller should provide either the associated relation of a rowtype,
6741  * or a type name (not both) for use in the error message, if any.
6742  *
6743  * Note that "typeOid" is not necessarily a composite type; it could also be
6744  * another container type such as an array or range, or a domain over one of
6745  * these things. The name of this function is therefore somewhat historical,
6746  * but it's not worth changing.
6747  *
6748  * We assume that functions and views depending on the type are not reasons
6749  * to reject the ALTER. (How safe is this really?)
6750  */
6751 void
6753  const char *origTypeName)
6754 {
6755  Relation depRel;
6756  ScanKeyData key[2];
6757  SysScanDesc depScan;
6758  HeapTuple depTup;
6759 
6760  /* since this function recurses, it could be driven to stack overflow */
6762 
6763  /*
6764  * We scan pg_depend to find those things that depend on the given type.
6765  * (We assume we can ignore refobjsubid for a type.)
6766  */
6767  depRel = table_open(DependRelationId, AccessShareLock);
6768 
6769  ScanKeyInit(&key[0],
6770  Anum_pg_depend_refclassid,
6771  BTEqualStrategyNumber, F_OIDEQ,
6772  ObjectIdGetDatum(TypeRelationId));
6773  ScanKeyInit(&key[1],
6774  Anum_pg_depend_refobjid,
6775  BTEqualStrategyNumber, F_OIDEQ,
6776  ObjectIdGetDatum(typeOid));
6777 
6778  depScan = systable_beginscan(depRel, DependReferenceIndexId, true,
6779  NULL, 2, key);
6780 
6781  while (HeapTupleIsValid(depTup = systable_getnext(depScan)))
6782  {
6783  Form_pg_depend pg_depend = (Form_pg_depend) GETSTRUCT(depTup);
6784  Relation rel;
6785  TupleDesc tupleDesc;
6786  Form_pg_attribute att;
6787 
6788  /* Check for directly dependent types */
6789  if (pg_depend->classid == TypeRelationId)
6790  {
6791  /*
6792  * This must be an array, domain, or range containing the given
6793  * type, so recursively check for uses of this type. Note that
6794  * any error message will mention the original type not the
6795  * container; this is intentional.
6796  */
6797  find_composite_type_dependencies(pg_depend->objid,
6798  origRelation, origTypeName);
6799  continue;
6800  }
6801 
6802  /* Else, ignore dependees that aren't relations */
6803  if (pg_depend->classid != RelationRelationId)
6804  continue;
6805 
6806  rel = relation_open(pg_depend->objid, AccessShareLock);
6807  tupleDesc = RelationGetDescr(rel);
6808 
6809  /*
6810  * If objsubid identifies a specific column, refer to that in error
6811  * messages. Otherwise, search to see if there's a user column of the
6812  * type. (We assume system columns are never of interesting types.)
6813  * The search is needed because an index containing an expression
6814  * column of the target type will just be recorded as a whole-relation
6815  * dependency. If we do not find a column of the type, the dependency
6816  * must indicate that the type is transiently referenced in an index
6817  * expression but not stored on disk, which we assume is OK, just as
6818  * we do for references in views. (It could also be that the target
6819  * type is embedded in some container type that is stored in an index
6820  * column, but the previous recursion should catch such cases.)
6821  */
6822  if (pg_depend->objsubid > 0 && pg_depend->objsubid <= tupleDesc->natts)
6823  att = TupleDescAttr(tupleDesc, pg_depend->objsubid - 1);
6824  else
6825  {
6826  att = NULL;
6827  for (int attno = 1; attno <= tupleDesc->natts; attno++)
6828  {
6829  att = TupleDescAttr(tupleDesc, attno - 1);
6830  if (att->atttypid == typeOid && !att->attisdropped)
6831  break;
6832  att = NULL;
6833  }
6834  if (att == NULL)
6835  {
6836  /* No such column, so assume OK */
6838  continue;
6839  }
6840  }
6841 
6842  /*
6843  * We definitely should reject if the relation has storage. If it's
6844  * partitioned, then perhaps we don't have to reject: if there are
6845  * partitions then we'll fail when we find one, else there is no
6846  * stored data to worry about. However, it's possible that the type
6847  * change would affect conclusions about whether the type is sortable
6848  * or hashable and thus (if it's a partitioning column) break the
6849  * partitioning rule. For now, reject for partitioned rels too.
6850  */
6851  if (RELKIND_HAS_STORAGE(rel->rd_rel->relkind) ||
6852  RELKIND_HAS_PARTITIONS(rel->rd_rel->relkind))
6853  {
6854  if (origTypeName)
6855  ereport(ERROR,
6856  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
6857  errmsg("cannot alter type \"%s\" because column \"%s.%s\" uses it",
6858  origTypeName,
6860  NameStr(att->attname))));
6861  else if (origRelation->rd_rel->relkind == RELKIND_COMPOSITE_TYPE)
6862  ereport(ERROR,
6863  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
6864  errmsg("cannot alter type \"%s\" because column \"%s.%s\" uses it",
6865  RelationGetRelationName(origRelation),
6867  NameStr(att->attname))));
6868  else if (origRelation->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
6869  ereport(ERROR,
6870  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
6871  errmsg("cannot alter foreign table \"%s\" because column \"%s.%s\" uses its row type",
6872  RelationGetRelationName(origRelation),
6874  NameStr(att->attname))));
6875  else
6876  ereport(ERROR,
6877  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
6878  errmsg("cannot alter table \"%s\" because column \"%s.%s\" uses its row type",
6879  RelationGetRelationName(origRelation),
6881  NameStr(att->attname))));
6882  }
6883  else if (OidIsValid(rel->rd_rel->reltype))
6884  {
6885  /*
6886  * A view or composite type itself isn't a problem, but we must
6887  * recursively check for indirect dependencies via its rowtype.
6888  */
6890  origRelation, origTypeName);
6891  }
6892 
6894  }
6895 
6896  systable_endscan(depScan);
6897 
6899 }
6900 
6901 
6902 /*
6903  * find_typed_table_dependencies
6904  *
6905  * Check to see if a composite type is being used as the type of a
6906  * typed table. Abort if any are found and behavior is RESTRICT.
6907  * Else return the list of tables.
6908  */
6909 static List *
6910 find_typed_table_dependencies(Oid typeOid, const char *typeName, DropBehavior behavior)
6911 {
6912  Relation classRel;
6913  ScanKeyData key[1];
6914  TableScanDesc scan;
6915  HeapTuple tuple;
6916  List *result = NIL;
6917 
6918  classRel = table_open(RelationRelationId, AccessShareLock);
6919 
6920  ScanKeyInit(&key[0],
6921  Anum_pg_class_reloftype,
6922  BTEqualStrategyNumber, F_OIDEQ,
6923  ObjectIdGetDatum(typeOid));
6924 
6925  scan = table_beginscan_catalog(classRel, 1, key);
6926 
6927  while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
6928  {
6929  Form_pg_class classform = (Form_pg_class) GETSTRUCT(tuple);
6930 
6931  if (behavior == DROP_RESTRICT)
6932  ereport(ERROR,
6933  (errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
6934  errmsg("cannot alter type \"%s\" because it is the type of a typed table",
6935  typeName),
6936  errhint("Use ALTER ... CASCADE to alter the typed tables too.")));
6937  else
6938  result = lappend_oid(result, classform->oid);
6939  }
6940 
6941  table_endscan(scan);
6942  table_close(classRel, AccessShareLock);
6943 
6944  return result;
6945 }
6946 
6947 
6948 /*
6949  * check_of_type
6950  *
6951  * Check whether a type is suitable for CREATE TABLE OF/ALTER TABLE OF. If it
6952  * isn't suitable, throw an error. Currently, we require that the type
6953  * originated with CREATE TYPE AS. We could support any row type, but doing so
6954  * would require handling a number of extra corner cases in the DDL commands.
6955  * (Also, allowing domain-over-composite would open up a can of worms about
6956  * whether and how the domain's constraints should apply to derived tables.)
6957  */
6958 void
6960 {
6961  Form_pg_type typ = (Form_pg_type) GETSTRUCT(typetuple);
6962  bool typeOk = false;
6963 
6964  if (typ->typtype == TYPTYPE_COMPOSITE)
6965  {
6966  Relation typeRelation;
6967 
6968  Assert(OidIsValid(typ->typrelid));
6969  typeRelation = relation_open(typ->typrelid, AccessShareLock);
6970  typeOk = (typeRelation->rd_rel->relkind == RELKIND_COMPOSITE_TYPE);
6971 
6972  /*
6973  * Close the parent rel, but keep our AccessShareLock on it until xact
6974  * commit. That will prevent someone else from deleting or ALTERing
6975  * the type before the typed table creation/conversion commits.
6976  */
6977  relation_close(typeRelation, NoLock);
6978  }
6979  if (!typeOk)
6980  ereport(ERROR,
6981  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
6982  errmsg("type %s is not a composite type",
6983  format_type_be(typ->oid))));
6984 }
6985 
6986 
6987 /*
6988  * ALTER TABLE ADD COLUMN
6989  *
6990  * Adds an additional attribute to a relation making the assumption that
6991  * CHECK, NOT NULL, and FOREIGN KEY constraints will be removed from the
6992  * AT_AddColumn AlterTableCmd by parse_utilcmd.c and added as independent
6993  * AlterTableCmd's.
6994  *
6995  * ADD COLUMN cannot use the normal ALTER TABLE recursion mechanism, because we
6996  * have to decide at runtime whether to recurse or not depending on whether we
6997  * actually add a column or merely merge with an existing column. (We can't
6998  * check this in a static pre-pass because it won't handle multiple inheritance
6999  * situations correctly.)
7000  */
7001 static void
7002 ATPrepAddColumn(List **wqueue, Relation rel, bool recurse, bool recursing,
7003  bool is_view, AlterTableCmd *cmd, LOCKMODE lockmode,
7004  AlterTableUtilityContext *context)
7005 {
7006  if (rel->rd_rel->reloftype && !recursing)
7007  ereport(ERROR,
7008  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
7009  errmsg("cannot add column to typed table")));
7010 
7011  if (rel->rd_rel->relkind == RELKIND_COMPOSITE_TYPE)
7012  ATTypedTableRecursion(wqueue, rel, cmd, lockmode, context);
7013 
7014  if (recurse && !is_view)
7015  cmd->recurse = true;
7016 }
7017 
7018 /*
7019  * Add a column to a table. The return value is the address of the
7020  * new column in the parent relation.
7021  *
7022  * cmd is pass-by-ref so that we can replace it with the parse-transformed
7023  * copy (but that happens only after we check for IF NOT EXISTS).
7024  */
7025 static ObjectAddress
7027  AlterTableCmd **cmd, bool recurse, bool recursing,
7028  LOCKMODE lockmode, AlterTablePass cur_pass,
7029  AlterTableUtilityContext *context)
7030 {
7031  Oid myrelid = RelationGetRelid(rel);
7032  ColumnDef *colDef = castNode(ColumnDef, (*cmd)->def);
7033  bool if_not_exists = (*cmd)->missing_ok;
7034  Relation pgclass,
7035  attrdesc;
7036  HeapTuple reltup;
7037  Form_pg_attribute attribute;
7038  int newattnum;
7039  char relkind;
7040  Expr *defval;
7041  List *children;
7042  ListCell *child;
7043  AlterTableCmd *childcmd;
7044  ObjectAddress address;
7045  TupleDesc tupdesc;
7046 
7047  /* since this function recurses, it could be driven to stack overflow */
7049 
7050  /* At top level, permission check was done in ATPrepCmd, else do it */
7051  if (recursing)
7052  ATSimplePermissions((*cmd)->subtype, rel, ATT_TABLE | ATT_FOREIGN_TABLE);
7053 
7054  if (rel->rd_rel->relispartition && !recursing)
7055  ereport(ERROR,
7056  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
7057  errmsg("cannot add column to a partition")));
7058 
7059  attrdesc = table_open(AttributeRelationId, RowExclusiveLock);
7060 
7061  /*
7062  * Are we adding the column to a recursion child? If so, check whether to
7063  * merge with an existing definition for the column. If we do merge, we
7064  * must not recurse. Children will already have the column, and recursing
7065  * into them would mess up attinhcount.
7066  */
7067  if (colDef->inhcount > 0)
7068  {
7069  HeapTuple tuple;
7070 
7071  /* Does child already have a column by this name? */
7072  tuple = SearchSysCacheCopyAttName(myrelid, colDef->colname);
7073  if (HeapTupleIsValid(tuple))
7074  {
7075  Form_pg_attribute childatt = (Form_pg_attribute) GETSTRUCT(tuple);
7076  Oid ctypeId;
7077  int32 ctypmod;
7078  Oid ccollid;
7079 
7080  /* Child column must match on type, typmod, and collation */
7081  typenameTypeIdAndMod(NULL, colDef->typeName, &ctypeId, &ctypmod);
7082  if (ctypeId != childatt->atttypid ||
7083  ctypmod != childatt->atttypmod)
7084  ereport(ERROR,
7085  (errcode(ERRCODE_DATATYPE_MISMATCH),
7086  errmsg("child table \"%s\" has different type for column \"%s\"",
7087  RelationGetRelationName(rel), colDef->colname)));
7088  ccollid = GetColumnDefCollation(NULL, colDef, ctypeId);
7089  if (ccollid != childatt->attcollation)
7090  ereport(ERROR,
7091  (errcode(ERRCODE_COLLATION_MISMATCH),
7092  errmsg("child table \"%s\" has different collation for column \"%s\"",
7093  RelationGetRelationName(rel), colDef->colname),
7094  errdetail("\"%s\" versus \"%s\"",
7095  get_collation_name(ccollid),
7096  get_collation_name(childatt->attcollation))));
7097 
7098  /* Bump the existing child att's inhcount */
7099  childatt->attinhcount++;
7100  if (childatt->attinhcount < 0)
7101  ereport(ERROR,
7102  errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
7103  errmsg("too many inheritance parents"));
7104  CatalogTupleUpdate(attrdesc, &tuple->t_self, tuple);
7105 
7106  heap_freetuple(tuple);
7107 
7108  /* Inform the user about the merge */
7109  ereport(NOTICE,
7110  (errmsg("merging definition of column \"%s\" for child \"%s\"",
7111  colDef->colname, RelationGetRelationName(rel))));
7112 
7113  table_close(attrdesc, RowExclusiveLock);
7114 
7115  /* Make the child column change visible */
7117 
7118  return InvalidObjectAddress;
7119  }
7120  }
7121 
7122  /* skip if the name already exists and if_not_exists is true */
7123  if (!check_for_column_name_collision(rel, colDef->colname, if_not_exists))
7124  {
7125  table_close(attrdesc, RowExclusiveLock);
7126  return InvalidObjectAddress;
7127  }
7128 
7129  /*
7130  * Okay, we need to add the column, so go ahead and do parse
7131  * transformation. This can result in queueing up, or even immediately
7132  * executing, subsidiary operations (such as creation of unique indexes);
7133  * so we mustn't do it until we have made the if_not_exists check.
7134  *
7135  * When recursing, the command was already transformed and we needn't do
7136  * so again. Also, if context isn't given we can't transform. (That
7137  * currently happens only for AT_AddColumnToView; we expect that view.c
7138  * passed us a ColumnDef that doesn't need work.)
7139  */
7140  if (context != NULL && !recursing)
7141  {
7142  *cmd = ATParseTransformCmd(wqueue, tab, rel, *cmd, recurse, lockmode,
7143  cur_pass, context);
7144  Assert(*cmd != NULL);
7145  colDef = castNode(ColumnDef, (*cmd)->def);
7146  }
7147 
7148  /*
7149  * Regular inheritance children are independent enough not to inherit the
7150  * identity column from parent hence cannot recursively add identity
7151  * column if the table has inheritance children.
7152  *
7153  * Partitions, on the other hand, are integral part of a partitioned table
7154  * and inherit identity column. Hence propagate identity column down the
7155  * partition hierarchy.
7156  */
7157  if (colDef->identity &&
7158  recurse &&
7159  rel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE &&
7160  find_inheritance_children(myrelid, NoLock) != NIL)
7161  ereport(ERROR,
7162  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
7163  errmsg("cannot recursively add identity column to table that has child tables")));
7164 
7165  pgclass = table_open(RelationRelationId, RowExclusiveLock);
7166 
7167  reltup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(myrelid));
7168  if (!HeapTupleIsValid(reltup))
7169  elog(ERROR, "cache lookup failed for relation %u", myrelid);
7170  relkind = ((Form_pg_class) GETSTRUCT(reltup))->relkind;
7171 
7172  /* Determine the new attribute's number */
7173  newattnum = ((Form_pg_class) GETSTRUCT(reltup))->relnatts + 1;
7174  if (newattnum > MaxHeapAttributeNumber)
7175  ereport(ERROR,
7176  (errcode(ERRCODE_TOO_MANY_COLUMNS),
7177  errmsg("tables can have at most %d columns",
7179 
7180  /*
7181  * Construct new attribute's pg_attribute entry.
7182  */
7183  tupdesc = BuildDescForRelation(list_make1(colDef));
7184 
7185  attribute = TupleDescAttr(tupdesc, 0);
7186 
7187  /* Fix up attribute number */
7188  attribute->attnum = newattnum;
7189 
7190  /* make sure datatype is legal for a column */
7191  CheckAttributeType(NameStr(attribute->attname), attribute->atttypid, attribute->attcollation,
7192  list_make1_oid(rel->rd_rel->reltype),
7193  0);
7194 
7195  InsertPgAttributeTuples(attrdesc, tupdesc, myrelid, NULL, NULL);
7196 
7197  table_close(attrdesc, RowExclusiveLock);
7198 
7199  /*
7200  * Update pg_class tuple as appropriate
7201  */
7202  ((Form_pg_class) GETSTRUCT(reltup))->relnatts = newattnum;
7203 
7204  CatalogTupleUpdate(pgclass, &reltup->t_self, reltup);
7205 
7206  heap_freetuple(reltup);
7207 
7208  /* Post creation hook for new attribute */
7209  InvokeObjectPostCreateHook(RelationRelationId, myrelid, newattnum);
7210 
7211  table_close(pgclass, RowExclusiveLock);
7212 
7213  /* Make the attribute's catalog entry visible */
7215 
7216  /*
7217  * Store the DEFAULT, if any, in the catalogs
7218  */
7219  if (colDef->raw_default)
7220  {
7221  RawColumnDefault *rawEnt;
7222 
7223  rawEnt = (RawColumnDefault *) palloc(sizeof(RawColumnDefault));
7224  rawEnt->attnum = attribute->attnum;
7225  rawEnt->raw_default = copyObject(colDef->raw_default);
7226 
7227  /*
7228  * Attempt to skip a complete table rewrite by storing the specified
7229  * DEFAULT value outside of the heap. This may be disabled inside
7230  * AddRelationNewConstraints if the optimization cannot be applied.
7231  */
7232  rawEnt->missingMode = (!colDef->generated);
7233 
7234  rawEnt->generated = colDef->generated;
7235 
7236  /*
7237  * This function is intended for CREATE TABLE, so it processes a
7238  * _list_ of defaults, but we just do one.
7239  */
7241  false, true, false, NULL);
7242 
7243  /* Make the additional catalog changes visible */
7245 
7246  /*
7247  * Did the request for a missing value work? If not we'll have to do a
7248  * rewrite
7249  */
7250  if (!rawEnt->missingMode)
7252  }
7253 
7254  /*
7255  * Tell Phase 3 to fill in the default expression, if there is one.
7256  *
7257  * If there is no default, Phase 3 doesn't have to do anything, because
7258  * that effectively means that the default is NULL. The heap tuple access
7259  * routines always check for attnum > # of attributes in tuple, and return
7260  * NULL if so, so without any modification of the tuple data we will get
7261  * the effect of NULL values in the new column.
7262  *
7263  * An exception occurs when the new column is of a domain type: the domain
7264  * might have a not-null constraint, or a check constraint that indirectly
7265  * rejects nulls. If there are any domain constraints then we construct
7266  * an explicit NULL default value that will be passed through
7267  * CoerceToDomain processing. (This is a tad inefficient, since it causes
7268  * rewriting the table which we really don't have to do, but the present
7269  * design of domain processing doesn't offer any simple way of checking
7270  * the constraints more directly.)
7271  *
7272  * Note: we use build_column_default, and not just the cooked default
7273  * returned by AddRelationNewConstraints, so that the right thing happens
7274  * when a datatype's default applies.
7275  *
7276  * Note: it might seem that this should happen at the end of Phase 2, so
7277  * that the effects of subsequent subcommands can be taken into account.
7278  * It's intentional that we do it now, though. The new column should be
7279  * filled according to what is said in the ADD COLUMN subcommand, so that
7280  * the effects are the same as if this subcommand had been run by itself
7281  * and the later subcommands had been issued in new ALTER TABLE commands.
7282  *
7283  * We can skip this entirely for relations without storage, since Phase 3
7284  * is certainly not going to touch them. System attributes don't have
7285  * interesting defaults, either.
7286  */
7287  if (RELKIND_HAS_STORAGE(relkind))
7288  {
7289  /*
7290  * For an identity column, we can't use build_column_default(),
7291  * because the sequence ownership isn't set yet. So do it manually.
7292  */
7293  if (colDef->identity)
7294  {
7296 
7297  nve->seqid = RangeVarGetRelid(colDef->identitySequence, NoLock, false);
7298  nve->typeId = attribute->atttypid;
7299 
7300  defval = (Expr *) nve;
7301 
7302  /* must do a rewrite for identity columns */
7304  }
7305  else
7306  defval = (Expr *) build_column_default(rel, attribute->attnum);
7307 
7308  if (!defval && DomainHasConstraints(attribute->atttypid))
7309  {
7310  Oid baseTypeId;
7311  int32 baseTypeMod;
7312  Oid baseTypeColl;
7313 
7314  baseTypeMod = attribute->atttypmod;
7315  baseTypeId = getBaseTypeAndTypmod(attribute->atttypid, &baseTypeMod);
7316  baseTypeColl = get_typcollation(baseTypeId);
7317  defval = (Expr *) makeNullConst(baseTypeId, baseTypeMod, baseTypeColl);
7318  defval = (Expr *) coerce_to_target_type(NULL,
7319  (Node *) defval,
7320  baseTypeId,
7321  attribute->atttypid,
7322  attribute->atttypmod,
7325  -1);
7326  if (defval == NULL) /* should not happen */
7327  elog(ERROR, "failed to coerce base type to domain");
7328  }
7329 
7330  if (defval)
7331  {
7333 
7335  newval->attnum = attribute->attnum;
7336  newval->expr = expression_planner(defval);
7337  newval->is_generated = (colDef->generated != '\0');
7338 
7339  tab->newvals = lappend(tab->newvals, newval);
7340  }
7341 
7342  if (DomainHasConstraints(attribute->atttypid))
7344 
7345  if (!TupleDescAttr(rel->rd_att, attribute->attnum - 1)->atthasmissing)
7346  {
7347  /*
7348  * If the new column is NOT NULL, and there is no missing value,
7349  * tell Phase 3 it needs to check for NULLs.
7350  */
7351  tab->verify_new_notnull |= colDef->is_not_null;
7352  }
7353  }
7354 
7355  /*
7356  * Add needed dependency entries for the new column.
7357  */
7358  add_column_datatype_dependency(myrelid, newattnum, attribute->atttypid);
7359  add_column_collation_dependency(myrelid, newattnum, attribute->attcollation);
7360 
7361  /*
7362  * Propagate to children as appropriate. Unlike most other ALTER
7363  * routines, we have to do this one level of recursion at a time; we can't
7364  * use find_all_inheritors to do it in one pass.
7365  */
7366  children =
7368 
7369  /*
7370  * If we are told not to recurse, there had better not be any child
7371  * tables; else the addition would put them out of step.
7372  */
7373  if (children && !recurse)
7374  ereport(ERROR,
7375  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
7376  errmsg("column must be added to child tables too")));
7377 
7378  /* Children should see column as singly inherited */
7379  if (!recursing)
7380  {
7381  childcmd = copyObject(*cmd);
7382  colDef = castNode(ColumnDef, childcmd->def);
7383  colDef->inhcount = 1;
7384  colDef->is_local = false;
7385  }
7386  else
7387  childcmd = *cmd; /* no need to copy again */
7388 
7389  foreach(child, children)
7390  {
7391  Oid childrelid = lfirst_oid(child);
7392  Relation childrel;
7393  AlteredTableInfo *childtab;
7394 
7395  /* find_inheritance_children already got lock */
7396  childrel = table_open(childrelid, NoLock);
7397  CheckTableNotInUse(childrel, "ALTER TABLE");
7398 
7399  /* Find or create work queue entry for this table */
7400  childtab = ATGetQueueEntry(wqueue, childrel);
7401 
7402  /* Recurse to child; return value is ignored */
7403  ATExecAddColumn(wqueue, childtab, childrel,
7404  &childcmd, recurse, true,
7405  lockmode, cur_pass, context);
7406 
7407  table_close(childrel, NoLock);
7408  }
7409 
7410  ObjectAddressSubSet(address, RelationRelationId, myrelid, newattnum);
7411  return address;
7412 }
7413 
7414 /*
7415  * If a new or renamed column will collide with the name of an existing
7416  * column and if_not_exists is false then error out, else do nothing.
7417  */
7418 static bool
7420  bool if_not_exists)
7421 {
7422  HeapTuple attTuple;
7423  int attnum;
7424 
7425  /*
7426  * this test is deliberately not attisdropped-aware, since if one tries to
7427  * add a column matching a dropped column name, it's gonna fail anyway.
7428  */
7429  attTuple = SearchSysCache2(ATTNAME,
7431  PointerGetDatum(colname));
7432  if (!HeapTupleIsValid(attTuple))
7433  return true;
7434 
7435  attnum = ((Form_pg_attribute) GETSTRUCT(attTuple))->attnum;
7436  ReleaseSysCache(attTuple);
7437 
7438  /*
7439  * We throw a different error message for conflicts with system column
7440  * names, since they are normally not shown and the user might otherwise
7441  * be confused about the reason for the conflict.
7442  */
7443  if (attnum <= 0)
7444  ereport(ERROR,
7445  (errcode(ERRCODE_DUPLICATE_COLUMN),
7446  errmsg("column name \"%s\" conflicts with a system column name",
7447  colname)));
7448  else
7449  {
7450  if (if_not_exists)
7451  {
7452  ereport(NOTICE,
7453  (errcode(ERRCODE_DUPLICATE_COLUMN),
7454  errmsg("column \"%s\" of relation \"%s\" already exists, skipping",
7455  colname, RelationGetRelationName(rel))));
7456  return false;
7457  }
7458 
7459  ereport(ERROR,
7460  (errcode(ERRCODE_DUPLICATE_COLUMN),
7461  errmsg("column \"%s\" of relation \"%s\" already exists",
7462  colname, RelationGetRelationName(rel))));
7463  }
7464 
7465  return true;
7466 }
7467 
7468 /*
7469  * Install a column's dependency on its datatype.
7470  */
7471 static void
7473 {
7474  ObjectAddress myself,
7475  referenced;
7476 
7477  myself.classId = RelationRelationId;
7478  myself.objectId = relid;
7479  myself.objectSubId = attnum;
7480  referenced.classId = TypeRelationId;
7481  referenced.objectId = typid;
7482  referenced.objectSubId = 0;
7483  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
7484 }
7485 
7486 /*
7487  * Install a column's dependency on its collation.
7488  */
7489 static void
7491 {
7492  ObjectAddress myself,
7493  referenced;
7494 
7495  /* We know the default collation is pinned, so don't bother recording it */
7496  if (OidIsValid(collid) && collid != DEFAULT_COLLATION_OID)
7497  {
7498  myself.classId = RelationRelationId;
7499  myself.objectId = relid;
7500  myself.objectSubId = attnum;
7501  referenced.classId = CollationRelationId;
7502  referenced.objectId = collid;
7503  referenced.objectSubId = 0;
7504  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
7505  }
7506 }
7507 
7508 /*
7509  * ALTER TABLE ALTER COLUMN DROP NOT NULL
7510  *
7511  * Return the address of the modified column. If the column was already
7512  * nullable, InvalidObjectAddress is returned.
7513  */
7514 static ObjectAddress
7515 ATExecDropNotNull(Relation rel, const char *colName, bool recurse,
7516  LOCKMODE lockmode)
7517 {
7518  HeapTuple tuple;
7519  HeapTuple conTup;
7520  Form_pg_attribute attTup;
7522  Relation attr_rel;
7523  ObjectAddress address;
7524  List *readyRels;
7525 
7526  /*
7527  * lookup the attribute
7528  */
7529  attr_rel = table_open(AttributeRelationId, RowExclusiveLock);
7530 
7531  tuple = SearchSysCacheCopyAttName(RelationGetRelid(rel), colName);
7532  if (!HeapTupleIsValid(tuple))
7533  ereport(ERROR,
7534  (errcode(ERRCODE_UNDEFINED_COLUMN),
7535  errmsg("column \"%s\" of relation \"%s\" does not exist",
7536  colName, RelationGetRelationName(rel))));
7537  attTup = (Form_pg_attribute) GETSTRUCT(tuple);
7538  attnum = attTup->attnum;
7539  ObjectAddressSubSet(address, RelationRelationId,
7540  RelationGetRelid(rel), attnum);
7541 
7542  /* If the column is already nullable there's nothing to do. */
7543  if (!attTup->attnotnull)
7544  {
7545  table_close(attr_rel, RowExclusiveLock);
7546  return InvalidObjectAddress;
7547  }
7548 
7549  /* Prevent them from altering a system attribute */
7550  if (attnum <= 0)
7551  ereport(ERROR,
7552  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
7553  errmsg("cannot alter system column \"%s\"",
7554  colName)));
7555 
7556  if (attTup->attidentity)
7557  ereport(ERROR,
7558  (errcode(ERRCODE_SYNTAX_ERROR),
7559  errmsg("column \"%s\" of relation \"%s\" is an identity column",
7560  colName, RelationGetRelationName(rel))));
7561 
7562  /*
7563  * It's not OK to remove a constraint only for the parent and leave it in
7564  * the children, so disallow that.
7565  */
7566  if (!recurse)
7567  {
7568  if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
7569  {
7570  PartitionDesc partdesc;
7571 
7572  partdesc = RelationGetPartitionDesc(rel, true);
7573 
7574  if (partdesc->nparts > 0)
7575  ereport(ERROR,
7576  errcode(ERRCODE_INVALID_TABLE_DEFINITION),
7577  errmsg("cannot remove constraint from only the partitioned table when partitions exist"),
7578  errhint("Do not specify the ONLY keyword."));
7579  }
7580  else if (rel->rd_rel->relhassubclass &&
7582  {
7583  ereport(ERROR,
7584  errcode(ERRCODE_INVALID_TABLE_DEFINITION),
7585  errmsg("not-null constraint on column \"%s\" must be removed in child tables too",
7586  colName),
7587  errhint("Do not specify the ONLY keyword."));
7588  }
7589  }
7590 
7591  /*
7592  * If rel is partition, shouldn't drop NOT NULL if parent has the same.
7593  */
7594  if (rel->rd_rel->relispartition)
7595  {
7596  Oid parentId = get_partition_parent(RelationGetRelid(rel), false);
7597  Relation parent = table_open(parentId, AccessShareLock);
7598  TupleDesc tupDesc = RelationGetDescr(parent);
7599  AttrNumber parent_attnum;
7600 
7601  parent_attnum = get_attnum(parentId, colName);
7602  if (TupleDescAttr(tupDesc, parent_attnum - 1)->attnotnull)
7603  ereport(ERROR,
7604  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
7605  errmsg("column \"%s\" is marked NOT NULL in parent table",
7606  colName)));
7607  table_close(parent, AccessShareLock);
7608  }
7609 
7610  /*
7611  * Find the constraint that makes this column NOT NULL.
7612  */
7613  conTup = findNotNullConstraint(RelationGetRelid(rel), colName);
7614  if (conTup == NULL)
7615  {
7616  Bitmapset *pkcols;
7617 
7618  /*
7619  * There's no not-null constraint, so throw an error. If the column
7620  * is in a primary key, we can throw a specific error. Otherwise,
7621  * this is unexpected.
7622  */
7625  pkcols))
7626  ereport(ERROR,
7627  errcode(ERRCODE_INVALID_TABLE_DEFINITION),
7628  errmsg("column \"%s\" is in a primary key", colName));
7629 
7630  /* this shouldn't happen */
7631  elog(ERROR, "could not find not-null constraint on column \"%s\", relation \"%s\"",
7632  colName, RelationGetRelationName(rel));
7633  }
7634 
7635  readyRels = NIL;
7636  dropconstraint_internal(rel, conTup, DROP_RESTRICT, recurse, false,
7637  false, &readyRels, lockmode);
7638 
7639  heap_freetuple(conTup);
7640 
7641  InvokeObjectPostAlterHook(RelationRelationId,
7642  RelationGetRelid(rel), attnum);
7643 
7644  table_close(attr_rel, RowExclusiveLock);
7645 
7646  return address;
7647 }
7648 
7649 /*
7650  * Helper to set pg_attribute.attnotnull if it isn't set, and to tell phase 3
7651  * to verify it; recurses to apply the same to children.
7652  *
7653  * When called to alter an existing table, 'wqueue' must be given so that we can
7654  * queue a check that existing tuples pass the constraint. When called from
7655  * table creation, 'wqueue' should be passed as NULL.
7656  *
7657  * Returns true if the flag was set in any table, otherwise false.
7658  */
7659 static bool
7660 set_attnotnull(List **wqueue, Relation rel, AttrNumber attnum, bool recurse,
7661  LOCKMODE lockmode)
7662 {
7663  HeapTuple tuple;
7664  Form_pg_attribute attForm;
7665  bool retval = false;
7666 
7667  /* Guard against stack overflow due to overly deep inheritance tree. */
7669 
7671  if (!HeapTupleIsValid(tuple))
7672  elog(ERROR, "cache lookup failed for attribute %d of relation %u",
7673  attnum, RelationGetRelid(rel));
7674  attForm = (Form_pg_attribute) GETSTRUCT(tuple);
7675  if (!attForm->attnotnull)
7676  {
7677  Relation attr_rel;
7678 
7679  attr_rel = table_open(AttributeRelationId, RowExclusiveLock);
7680 
7681  attForm->attnotnull = true;
7682  CatalogTupleUpdate(attr_rel, &tuple->t_self, tuple);
7683 
7684  table_close(attr_rel, RowExclusiveLock);
7685 
7686  /*
7687  * And set up for existing values to be checked, unless another
7688  * constraint already proves this.
7689  */
7690  if (wqueue && !NotNullImpliedByRelConstraints(rel, attForm))
7691  {
7692  AlteredTableInfo *tab;
7693 
7694  tab = ATGetQueueEntry(wqueue, rel);
7695  tab->verify_new_notnull = true;
7696  }
7697 
7698  retval = true;
7699  }
7700 
7701  if (recurse)
7702  {
7703  List *children;
7704  ListCell *lc;
7705 
7706  children = find_inheritance_children(RelationGetRelid(rel), lockmode);
7707  foreach(lc, children)
7708  {
7709  Oid childrelid = lfirst_oid(lc);
7710  Relation childrel;
7711  AttrNumber childattno;
7712 
7713  /* find_inheritance_children already got lock */
7714  childrel = table_open(childrelid, NoLock);
7715  CheckTableNotInUse(childrel, "ALTER TABLE");
7716 
7717  childattno = get_attnum(RelationGetRelid(childrel),
7719  false));
7720  retval |= set_attnotnull(wqueue, childrel, childattno,
7721  recurse, lockmode);
7722  table_close(childrel, NoLock);
7723  }
7724  }
7725 
7726  return retval;
7727 }
7728 
7729 /*
7730  * ALTER TABLE ALTER COLUMN SET NOT NULL
7731  *
7732  * Add a not-null constraint to a single table and its children. Returns
7733  * the address of the constraint added to the parent relation, if one gets
7734  * added, or InvalidObjectAddress otherwise.
7735  *
7736  * We must recurse to child tables during execution, rather than using
7737  * ALTER TABLE's normal prep-time recursion.
7738  */
7739 static ObjectAddress
7740 ATExecSetNotNull(List **wqueue, Relation rel, char *conName, char *colName,
7741  bool recurse, bool recursing, List **readyRels,
7742  LOCKMODE lockmode)
7743 {
7744  HeapTuple tuple;
7745  Relation constr_rel;
7746  ScanKeyData skey;
7747  SysScanDesc conscan;
7749  ObjectAddress address;
7750  Constraint *constraint;
7751  CookedConstraint *ccon;
7752  List *cooked;
7753  bool is_no_inherit = false;
7754  List *ready = NIL;
7755 
7756  /* Guard against stack overflow due to overly deep inheritance tree. */
7758 
7759  /*
7760  * In cases of multiple inheritance, we might visit the same child more
7761  * than once. In the topmost call, set up a list that we fill with all
7762  * visited relations, to skip those.
7763  */
7764  if (readyRels == NULL)
7765  {
7766  Assert(!recursing);
7767  readyRels = &ready;
7768  }
7769  if (list_member_oid(*readyRels, RelationGetRelid(rel)))
7770  return InvalidObjectAddress;
7771  *readyRels = lappend_oid(*readyRels, RelationGetRelid(rel));
7772 
7773  /* At top level, permission check was done in ATPrepCmd, else do it */
7774  if (recursing)
7775  {
7777  Assert(conName != NULL);
7778  }
7779 
7780  attnum = get_attnum(RelationGetRelid(rel), colName);
7781  if (attnum == InvalidAttrNumber)
7782  ereport(ERROR,
7783  (errcode(ERRCODE_UNDEFINED_COLUMN),
7784  errmsg("column \"%s\" of relation \"%s\" does not exist",
7785  colName, RelationGetRelationName(rel))));
7786 
7787  /* Prevent them from altering a system attribute */
7788  if (attnum <= 0)
7789  ereport(ERROR,
7790  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
7791  errmsg("cannot alter system column \"%s\"",
7792  colName)));
7793 
7794  /* See if there's already a constraint */
7795  constr_rel = table_open(ConstraintRelationId, RowExclusiveLock);
7796  ScanKeyInit(&skey,
7797  Anum_pg_constraint_conrelid,
7798  BTEqualStrategyNumber, F_OIDEQ,
7800  conscan = systable_beginscan(constr_rel, ConstraintRelidTypidNameIndexId, true,
7801  NULL, 1, &skey);
7802 
7803  while (HeapTupleIsValid(tuple = systable_getnext(conscan)))
7804  {
7805  Form_pg_constraint conForm = (Form_pg_constraint) GETSTRUCT(tuple);
7806  bool changed = false;
7807  HeapTuple copytup;
7808 
7809  if (conForm->contype != CONSTRAINT_NOTNULL)
7810  continue;
7811 
7812  if (extractNotNullColumn(tuple) != attnum)
7813  continue;
7814 
7815  copytup = heap_copytuple(tuple);
7816  conForm = (Form_pg_constraint) GETSTRUCT(copytup);
7817 
7818  /*
7819  * If we find an appropriate constraint, we're almost done, but just
7820  * need to change some properties on it: if we're recursing, increment
7821  * coninhcount; if not, set conislocal if not already set.
7822  */
7823  if (recursing)
7824  {
7825  conForm->coninhcount++;
7826  changed = true;
7827  }
7828  else if (!conForm->conislocal)
7829  {
7830  conForm->conislocal = true;
7831  changed = true;
7832  }
7833 
7834  if (changed)
7835  {
7836  CatalogTupleUpdate(constr_rel, &copytup->t_self, copytup);
7837  ObjectAddressSet(address, ConstraintRelationId, conForm->oid);
7838  }
7839 
7840  systable_endscan(conscan);
7841  table_close(constr_rel, RowExclusiveLock);
7842 
7843  if (changed)
7844  return address;
7845  else
7846  return InvalidObjectAddress;
7847  }
7848 
7849  systable_endscan(conscan);
7850  table_close(constr_rel, RowExclusiveLock);
7851 
7852  /*
7853  * If we're asked not to recurse, and children exist, raise an error for
7854  * partitioned tables. For inheritance, we act as if NO INHERIT had been
7855  * specified.
7856  */
7857  if (!recurse &&
7859  NoLock) != NIL)
7860  {
7861  if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
7862  ereport(ERROR,
7863  errcode(ERRCODE_INVALID_TABLE_DEFINITION),
7864  errmsg("constraint must be added to child tables too"),
7865  errhint("Do not specify the ONLY keyword."));
7866  else
7867  is_no_inherit = true;
7868  }
7869 
7870  /*
7871  * No constraint exists; we must add one. First determine a name to use,
7872  * if we haven't already.
7873  */
7874  if (!recursing)
7875  {
7876  Assert(conName == NULL);
7878  colName, "not_null",
7879  RelationGetNamespace(rel),
7880  NIL);
7881  }
7882  constraint = makeNode(Constraint);
7883  constraint->contype = CONSTR_NOTNULL;
7884  constraint->conname = conName;
7885  constraint->deferrable = false;
7886  constraint->initdeferred = false;
7887  constraint->location = -1;
7888  constraint->keys = list_make1(makeString(colName));
7889  constraint->is_no_inherit = is_no_inherit;
7890  constraint->inhcount = recursing ? 1 : 0;
7891  constraint->skip_validation = false;
7892  constraint->initially_valid = true;
7893 
7894  /* and do it */
7895  cooked = AddRelationNewConstraints(rel, NIL, list_make1(constraint),
7896  false, !recursing, false, NULL);
7897  ccon = linitial(cooked);
7898  ObjectAddressSet(address, ConstraintRelationId, ccon->conoid);
7899 
7900  InvokeObjectPostAlterHook(RelationRelationId,
7901  RelationGetRelid(rel), attnum);
7902 
7903  /*
7904  * Mark pg_attribute.attnotnull for the column. Tell that function not to
7905  * recurse, because we're going to do it here.
7906  */
7907  set_attnotnull(wqueue, rel, attnum, false, lockmode);
7908 
7909  /*
7910  * Recurse to propagate the constraint to children that don't have one.
7911  */
7912  if (recurse)
7913  {
7914  List *children;
7915  ListCell *lc;
7916 
7918  lockmode);
7919 
7920  foreach(lc, children)
7921  {
7922  Relation childrel;
7923 
7924  childrel = table_open(lfirst_oid(lc), NoLock);
7925 
7926  ATExecSetNotNull(wqueue, childrel,
7927  conName, colName, recurse, true,
7928  readyRels, lockmode);
7929 
7930  table_close(childrel, NoLock);
7931  }
7932  }
7933 
7934  return address;
7935 }
7936 
7937 /*
7938  * ALTER TABLE ALTER COLUMN SET ATTNOTNULL
7939  *
7940  * This doesn't exist in the grammar; it's used when creating a
7941  * primary key and the column is not already marked attnotnull.
7942  */
7943 static ObjectAddress
7945  const char *colName, LOCKMODE lockmode)
7946 {
7949 
7950  attnum = get_attnum(RelationGetRelid(rel), colName);
7951  if (attnum == InvalidAttrNumber)
7952  ereport(ERROR,
7953  errcode(ERRCODE_UNDEFINED_COLUMN),
7954  errmsg("column \"%s\" of relation \"%s\" does not exist",
7955  colName, RelationGetRelationName(rel)));
7956 
7957  /*
7958  * Make the change, if necessary, and only if so report the column as
7959  * changed
7960  */
7961  if (set_attnotnull(wqueue, rel, attnum, false, lockmode))
7962  ObjectAddressSubSet(address, RelationRelationId,
7963  RelationGetRelid(rel), attnum);
7964 
7965  return address;
7966 }
7967 
7968 /*
7969  * NotNullImpliedByRelConstraints
7970  * Does rel's existing constraints imply NOT NULL for the given attribute?
7971  */
7972 static bool
7974 {
7975  NullTest *nnulltest = makeNode(NullTest);
7976 
7977  nnulltest->arg = (Expr *) makeVar(1,
7978  attr->attnum,
7979  attr->atttypid,
7980  attr->atttypmod,
7981  attr->attcollation,
7982  0);
7983  nnulltest->nulltesttype = IS_NOT_NULL;
7984 
7985  /*
7986  * argisrow = false is correct even for a composite column, because
7987  * attnotnull does not represent a SQL-spec IS NOT NULL test in such a
7988  * case, just IS DISTINCT FROM NULL.
7989  */
7990  nnulltest->argisrow = false;
7991  nnulltest->location = -1;
7992 
7993  if (ConstraintImpliedByRelConstraint(rel, list_make1(nnulltest), NIL))
7994  {
7995  ereport(DEBUG1,
7996  (errmsg_internal("existing constraints on column \"%s.%s\" are sufficient to prove that it does not contain nulls",
7997  RelationGetRelationName(rel), NameStr(attr->attname))));
7998  return true;
7999  }
8000 
8001  return false;
8002 }
8003 
8004 /*
8005  * ALTER TABLE ALTER COLUMN SET/DROP DEFAULT
8006  *
8007  * Return the address of the affected column.
8008  */
8009 static ObjectAddress
8010 ATExecColumnDefault(Relation rel, const char *colName,
8011  Node *newDefault, LOCKMODE lockmode)
8012 {
8013  TupleDesc tupdesc = RelationGetDescr(rel);
8015  ObjectAddress address;
8016 
8017  /*
8018  * get the number of the attribute
8019  */
8020  attnum = get_attnum(RelationGetRelid(rel), colName);
8021  if (attnum == InvalidAttrNumber)
8022  ereport(ERROR,
8023  (errcode(ERRCODE_UNDEFINED_COLUMN),
8024  errmsg("column \"%s\" of relation \"%s\" does not exist",
8025  colName, RelationGetRelationName(rel))));
8026 
8027  /* Prevent them from altering a system attribute */
8028  if (attnum <= 0)
8029  ereport(ERROR,
8030  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
8031  errmsg("cannot alter system column \"%s\"",
8032  colName)));
8033 
8034  if (TupleDescAttr(tupdesc, attnum - 1)->attidentity)
8035  ereport(ERROR,
8036  (errcode(ERRCODE_SYNTAX_ERROR),
8037  errmsg("column \"%s\" of relation \"%s\" is an identity column",
8038  colName, RelationGetRelationName(rel)),
8039  /* translator: %s is an SQL ALTER command */
8040  newDefault ? 0 : errhint("Use %s instead.",
8041  "ALTER TABLE ... ALTER COLUMN ... DROP IDENTITY")));
8042 
8043  if (TupleDescAttr(tupdesc, attnum - 1)->attgenerated)
8044  ereport(ERROR,
8045  (errcode(ERRCODE_SYNTAX_ERROR),
8046  errmsg("column \"%s\" of relation \"%s\" is a generated column",
8047  colName, RelationGetRelationName(rel)),
8048  newDefault ?
8049  /* translator: %s is an SQL ALTER command */
8050  errhint("Use %s instead.", "ALTER TABLE ... ALTER COLUMN ... SET EXPRESSION") :
8051  (TupleDescAttr(tupdesc, attnum - 1)->attgenerated == ATTRIBUTE_GENERATED_STORED ?
8052  errhint("Use %s instead.", "ALTER TABLE ... ALTER COLUMN ... DROP EXPRESSION") : 0)));
8053 
8054  /*
8055  * Remove any old default for the column. We use RESTRICT here for
8056  * safety, but at present we do not expect anything to depend on the
8057  * default.
8058  *
8059  * We treat removing the existing default as an internal operation when it
8060  * is preparatory to adding a new default, but as a user-initiated
8061  * operation when the user asked for a drop.
8062  */
8064  newDefault != NULL);
8065 
8066  if (newDefault)
8067  {
8068  /* SET DEFAULT */
8069  RawColumnDefault *rawEnt;
8070 
8071  rawEnt = (RawColumnDefault *) palloc(sizeof(RawColumnDefault));
8072  rawEnt->attnum = attnum;
8073  rawEnt->raw_default = newDefault;
8074  rawEnt->missingMode = false;
8075  rawEnt->generated = '\0';
8076 
8077  /*
8078  * This function is intended for CREATE TABLE, so it processes a
8079  * _list_ of defaults, but we just do one.
8080  */
8082  false, true, false, NULL);
8083  }
8084 
8085  ObjectAddressSubSet(address, RelationRelationId,
8086  RelationGetRelid(rel), attnum);
8087  return address;
8088 }
8089 
8090 /*
8091  * Add a pre-cooked default expression.
8092  *
8093  * Return the address of the affected column.
8094  */
8095 static ObjectAddress
8097  Node *newDefault)
8098 {
8099  ObjectAddress address;
8100 
8101  /* We assume no checking is required */
8102 
8103  /*
8104  * Remove any old default for the column. We use RESTRICT here for
8105  * safety, but at present we do not expect anything to depend on the
8106  * default. (In ordinary cases, there could not be a default in place
8107  * anyway, but it's possible when combining LIKE with inheritance.)
8108  */
8110  true);
8111 
8112  (void) StoreAttrDefault(rel, attnum, newDefault, true, false);
8113 
8114  ObjectAddressSubSet(address, RelationRelationId,
8115  RelationGetRelid(rel), attnum);
8116  return address;
8117 }
8118 
8119 /*
8120  * ALTER TABLE ALTER COLUMN ADD IDENTITY
8121  *
8122  * Return the address of the affected column.
8123  */
8124 static ObjectAddress
8125 ATExecAddIdentity(Relation rel, const char *colName,
8126  Node *def, LOCKMODE lockmode, bool recurse, bool recursing)
8127 {
8128  Relation attrelation;
8129  HeapTuple tuple;
8130  Form_pg_attribute attTup;
8132  ObjectAddress address;
8133  ColumnDef *cdef = castNode(ColumnDef, def);
8134  bool ispartitioned;
8135 
8136  ispartitioned = (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
8137  if (ispartitioned && !recurse)
8138  ereport(ERROR,
8139  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
8140  errmsg("cannot add identity to a column of only the partitioned table"),
8141  errhint("Do not specify the ONLY keyword.")));
8142 
8143  if (rel->rd_rel->relispartition && !recursing)
8144  ereport(ERROR,
8145  errcode(ERRCODE_INVALID_TABLE_DEFINITION),
8146  errmsg("cannot add identity to a column of a partition"));
8147 
8148  attrelation = table_open(AttributeRelationId, RowExclusiveLock);
8149 
8150  tuple = SearchSysCacheCopyAttName(RelationGetRelid(rel), colName);
8151  if (!HeapTupleIsValid(tuple))
8152  ereport(ERROR,
8153  (errcode(ERRCODE_UNDEFINED_COLUMN),
8154  errmsg("column \"%s\" of relation \"%s\" does not exist",
8155  colName, RelationGetRelationName(rel))));
8156  attTup = (Form_pg_attribute) GETSTRUCT(tuple);
8157  attnum = attTup->attnum;
8158 
8159  /* Can't alter a system attribute */
8160  if (attnum <= 0)
8161  ereport(ERROR,
8162  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
8163  errmsg("cannot alter system column \"%s\"",
8164  colName)));
8165 
8166  /*
8167  * Creating a column as identity implies NOT NULL, so adding the identity
8168  * to an existing column that is not NOT NULL would create a state that
8169  * cannot be reproduced without contortions.
8170  */
8171  if (!attTup->attnotnull)
8172  ereport(ERROR,
8173  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
8174  errmsg("column \"%s\" of relation \"%s\" must be declared NOT NULL before identity can be added",
8175  colName, RelationGetRelationName(rel))));
8176 
8177  if (attTup->attidentity)
8178  ereport(ERROR,
8179  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
8180  errmsg("column \"%s\" of relation \"%s\" is already an identity column",
8181  colName, RelationGetRelationName(rel))));
8182 
8183  if (attTup->atthasdef)
8184  ereport(ERROR,
8185  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
8186  errmsg("column \"%s\" of relation \"%s\" already has a default value",
8187  colName, RelationGetRelationName(rel))));
8188 
8189  attTup->attidentity = cdef->identity;
8190  CatalogTupleUpdate(attrelation, &tuple->t_self, tuple);
8191 
8192  InvokeObjectPostAlterHook(RelationRelationId,
8193  RelationGetRelid(rel),
8194  attTup->attnum);
8195  ObjectAddressSubSet(address, RelationRelationId,
8196  RelationGetRelid(rel), attnum);
8197  heap_freetuple(tuple);
8198 
8199  table_close(attrelation, RowExclusiveLock);
8200 
8201  /*
8202  * Recurse to propagate the identity column to partitions. Identity is
8203  * not inherited in regular inheritance children.
8204  */
8205  if (recurse && ispartitioned)
8206  {
8207  List *children;
8208  ListCell *lc;
8209 
8210  children = find_inheritance_children(RelationGetRelid(rel), lockmode);
8211 
8212  foreach(lc, children)
8213  {
8214  Relation childrel;
8215 
8216  childrel = table_open(lfirst_oid(lc), NoLock);
8217  ATExecAddIdentity(childrel, colName, def, lockmode, recurse, true);
8218  table_close(childrel, NoLock);
8219  }
8220  }
8221 
8222  return address;
8223 }
8224 
8225 /*
8226  * ALTER TABLE ALTER COLUMN SET { GENERATED or sequence options }
8227  *
8228  * Return the address of the affected column.
8229  */
8230 static ObjectAddress
8231 ATExecSetIdentity(Relation rel, const char *colName, Node *def,
8232  LOCKMODE lockmode, bool recurse, bool recursing)
8233 {
8234  ListCell *option;
8235  DefElem *generatedEl = NULL;
8236  HeapTuple tuple;
8237  Form_pg_attribute attTup;
8239  Relation attrelation;
8240  ObjectAddress address;
8241  bool ispartitioned;
8242 
8243  ispartitioned = (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
8244  if (ispartitioned && !recurse)
8245  ereport(ERROR,
8246  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
8247  errmsg("cannot change identity column of only the partitioned table"),
8248  errhint("Do not specify the ONLY keyword.")));
8249 
8250  if (rel->rd_rel->relispartition && !recursing)
8251  ereport(ERROR,
8252  errcode(ERRCODE_INVALID_TABLE_DEFINITION),
8253  errmsg("cannot change identity column of a partition"));
8254 
8255  foreach(option, castNode(List, def))
8256  {
8257  DefElem *defel = lfirst_node(DefElem, option);
8258 
8259  if (strcmp(defel->defname, "generated") == 0)
8260  {
8261  if (generatedEl)
8262  ereport(ERROR,
8263  (errcode(ERRCODE_SYNTAX_ERROR),
8264  errmsg("conflicting or redundant options")));
8265  generatedEl = defel;
8266  }
8267  else
8268  elog(ERROR, "option \"%s\" not recognized",
8269  defel->defname);
8270  }
8271 
8272  /*
8273  * Even if there is nothing to change here, we run all the checks. There
8274  * will be a subsequent ALTER SEQUENCE that relies on everything being
8275  * there.
8276  */
8277 
8278  attrelation = table_open(AttributeRelationId, RowExclusiveLock);
8279  tuple = SearchSysCacheCopyAttName(RelationGetRelid(rel), colName);
8280  if (!HeapTupleIsValid(tuple))
8281  ereport(ERROR,
8282  (errcode(ERRCODE_UNDEFINED_COLUMN),
8283  errmsg("column \"%s\" of relation \"%s\" does not exist",
8284  colName, RelationGetRelationName(rel))));
8285 
8286  attTup = (Form_pg_attribute) GETSTRUCT(tuple);
8287  attnum = attTup->attnum;
8288 
8289  if (attnum <= 0)
8290  ereport(ERROR,
8291  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
8292  errmsg("cannot alter system column \"%s\"",
8293  colName)));
8294 
8295  if (!attTup->attidentity)
8296  ereport(ERROR,
8297  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
8298  errmsg("column \"%s\" of relation \"%s\" is not an identity column",
8299  colName, RelationGetRelationName(rel))));
8300 
8301  if (generatedEl)
8302  {
8303  attTup->attidentity = defGetInt32(generatedEl);
8304  CatalogTupleUpdate(attrelation, &tuple->t_self, tuple);
8305 
8306  InvokeObjectPostAlterHook(RelationRelationId,
8307  RelationGetRelid(rel),
8308  attTup->attnum);
8309  ObjectAddressSubSet(address, RelationRelationId,
8310  RelationGetRelid(rel), attnum);
8311  }
8312  else
8313  address = InvalidObjectAddress;
8314 
8315  heap_freetuple(tuple);
8316  table_close(attrelation, RowExclusiveLock);
8317 
8318  /*
8319  * Recurse to propagate the identity change to partitions. Identity is not
8320  * inherited in regular inheritance children.
8321  */
8322  if (generatedEl && recurse && ispartitioned)
8323  {
8324  List *children;
8325  ListCell *lc;
8326 
8327  children = find_inheritance_children(RelationGetRelid(rel), lockmode);
8328 
8329  foreach(lc, children)
8330  {
8331  Relation childrel;
8332 
8333  childrel = table_open(lfirst_oid(lc), NoLock);
8334  ATExecSetIdentity(childrel, colName, def, lockmode, recurse, true);
8335  table_close(childrel, NoLock);
8336  }
8337  }
8338 
8339  return address;
8340 }
8341 
8342 /*
8343  * ALTER TABLE ALTER COLUMN DROP IDENTITY
8344  *
8345  * Return the address of the affected column.
8346  */
8347 static ObjectAddress
8348 ATExecDropIdentity(Relation rel, const char *colName, bool missing_ok, LOCKMODE lockmode,
8349  bool recurse, bool recursing)
8350 {
8351  HeapTuple tuple;
8352  Form_pg_attribute attTup;
8354  Relation attrelation;
8355  ObjectAddress address;
8356  Oid seqid;
8357  ObjectAddress seqaddress;
8358  bool ispartitioned;
8359 
8360  ispartitioned = (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
8361  if (ispartitioned && !recurse)
8362  ereport(ERROR,
8363  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
8364  errmsg("cannot drop identity from a column of only the partitioned table"),
8365  errhint("Do not specify the ONLY keyword.")));
8366 
8367  if (rel->rd_rel->relispartition && !recursing)
8368  ereport(ERROR,
8369  errcode(ERRCODE_INVALID_TABLE_DEFINITION),
8370  errmsg("cannot drop identity from a column of a partition"));
8371 
8372  attrelation = table_open(AttributeRelationId, RowExclusiveLock);
8373  tuple = SearchSysCacheCopyAttName(RelationGetRelid(rel), colName);
8374  if (!HeapTupleIsValid(tuple))
8375  ereport(ERROR,
8376  (errcode(ERRCODE_UNDEFINED_COLUMN),
8377  errmsg("column \"%s\" of relation \"%s\" does not exist",
8378  colName, RelationGetRelationName(rel))));
8379 
8380  attTup = (Form_pg_attribute) GETSTRUCT(tuple);
8381  attnum = attTup->attnum;
8382 
8383  if (attnum <= 0)
8384  ereport(ERROR,
8385  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
8386  errmsg("cannot alter system column \"%s\"",
8387  colName)));
8388 
8389  if (!attTup->attidentity)
8390  {
8391  if (!missing_ok)
8392  ereport(ERROR,
8393  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
8394  errmsg("column \"%s\" of relation \"%s\" is not an identity column",
8395  colName, RelationGetRelationName(rel))));
8396  else
8397  {
8398  ereport(NOTICE,
8399  (errmsg("column \"%s\" of relation \"%s\" is not an identity column, skipping",
8400  colName, RelationGetRelationName(rel))));
8401  heap_freetuple(tuple);
8402  table_close(attrelation, RowExclusiveLock);
8403  return InvalidObjectAddress;
8404  }
8405  }
8406 
8407  attTup->attidentity = '\0';
8408  CatalogTupleUpdate(attrelation, &tuple->t_self, tuple);
8409 
8410  InvokeObjectPostAlterHook(RelationRelationId,
8411  RelationGetRelid(rel),
8412  attTup->attnum);
8413  ObjectAddressSubSet(address, RelationRelationId,
8414  RelationGetRelid(rel), attnum);
8415  heap_freetuple(tuple);
8416 
8417  table_close(attrelation, RowExclusiveLock);
8418 
8419  /*
8420  * Recurse to drop the identity from column in partitions. Identity is
8421  * not inherited in regular inheritance children so ignore them.
8422  */
8423  if (recurse && ispartitioned)
8424  {
8425  List *children;
8426  ListCell *lc;
8427 
8428  children = find_inheritance_children(RelationGetRelid(rel), lockmode);
8429 
8430  foreach(lc, children)
8431  {
8432  Relation childrel;
8433 
8434  childrel = table_open(lfirst_oid(lc), NoLock);
8435  ATExecDropIdentity(childrel, colName, false, lockmode, recurse, true);
8436  table_close(childrel, NoLock);
8437  }
8438  }
8439 
8440  if (!recursing)
8441  {
8442  /* drop the internal sequence */
8443  seqid = getIdentitySequence(RelationGetRelid(rel), attnum, false);
8444  deleteDependencyRecordsForClass(RelationRelationId, seqid,
8445  RelationRelationId, DEPENDENCY_INTERNAL);
8447  seqaddress.classId = RelationRelationId;
8448  seqaddress.objectId = seqid;
8449  seqaddress.objectSubId = 0;
8451  }
8452 
8453  return address;
8454 }
8455 
8456 /*
8457  * ALTER TABLE ALTER COLUMN SET EXPRESSION
8458  *
8459  * Return the address of the affected column.
8460  */
8461 static ObjectAddress
8462 ATExecSetExpression(AlteredTableInfo *tab, Relation rel, const char *colName,
8463  Node *newExpr, LOCKMODE lockmode)
8464 {
8465  HeapTuple tuple;
8466  Form_pg_attribute attTup;
8468  Oid attrdefoid;
8469  ObjectAddress address;
8470  Expr *defval;
8472  RawColumnDefault *rawEnt;
8473 
8474  tuple = SearchSysCacheAttName(RelationGetRelid(rel), colName);
8475  if (!HeapTupleIsValid(tuple))
8476  ereport(ERROR,
8477  (errcode(ERRCODE_UNDEFINED_COLUMN),
8478  errmsg("column \"%s\" of relation \"%s\" does not exist",
8479  colName, RelationGetRelationName(rel))));
8480 
8481  attTup = (Form_pg_attribute) GETSTRUCT(tuple);
8482  attnum = attTup->attnum;
8483 
8484  if (attnum <= 0)
8485  ereport(ERROR,
8486  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
8487  errmsg("cannot alter system column \"%s\"",
8488  colName)));
8489 
8490  if (attTup->attgenerated != ATTRIBUTE_GENERATED_STORED)
8491  ereport(ERROR,
8492  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
8493  errmsg("column \"%s\" of relation \"%s\" is not a generated column",
8494  colName, RelationGetRelationName(rel))));
8495  ReleaseSysCache(tuple);
8496 
8497  /*
8498  * Clear all the missing values if we're rewriting the table, since this
8499  * renders them pointless.
8500  */
8501  RelationClearMissing(rel);
8502 
8503  /* make sure we don't conflict with later attribute modifications */
8505 
8506  /*
8507  * Find everything that depends on the column (constraints, indexes, etc),
8508  * and record enough information to let us recreate the objects after
8509  * rewrite.
8510  */
8512 
8513  /*
8514  * Drop the dependency records of the GENERATED expression, in particular
8515  * its INTERNAL dependency on the column, which would otherwise cause
8516  * dependency.c to refuse to perform the deletion.
8517  */
8518  attrdefoid = GetAttrDefaultOid(RelationGetRelid(rel), attnum);
8519  if (!OidIsValid(attrdefoid))
8520  elog(ERROR, "could not find attrdef tuple for relation %u attnum %d",
8521  RelationGetRelid(rel), attnum);
8522  (void) deleteDependencyRecordsFor(AttrDefaultRelationId, attrdefoid, false);
8523 
8524  /* Make above changes visible */
8526 
8527  /*
8528  * Get rid of the GENERATED expression itself. We use RESTRICT here for
8529  * safety, but at present we do not expect anything to depend on the
8530  * expression.
8531  */
8533  false, false);
8534 
8535  /* Prepare to store the new expression, in the catalogs */
8536  rawEnt = (RawColumnDefault *) palloc(sizeof(RawColumnDefault));
8537  rawEnt->attnum = attnum;
8538  rawEnt->raw_default = newExpr;
8539  rawEnt->missingMode = false;
8540  rawEnt->generated = ATTRIBUTE_GENERATED_STORED;
8541 
8542  /* Store the generated expression */
8544  false, true, false, NULL);
8545 
8546  /* Make above new expression visible */
8548 
8549  /* Prepare for table rewrite */
8550  defval = (Expr *) build_column_default(rel, attnum);
8551 
8553  newval->attnum = attnum;
8554  newval->expr = expression_planner(defval);
8555  newval->is_generated = true;
8556 
8557  tab->newvals = lappend(tab->newvals, newval);
8559 
8560  /* Drop any pg_statistic entry for the column */
8562 
8563  InvokeObjectPostAlterHook(RelationRelationId,
8564  RelationGetRelid(rel), attnum);
8565 
8566  ObjectAddressSubSet(address, RelationRelationId,
8567  RelationGetRelid(rel), attnum);
8568  return address;
8569 }
8570 
8571 /*
8572  * ALTER TABLE ALTER COLUMN DROP EXPRESSION
8573  */
8574 static void
8575 ATPrepDropExpression(Relation rel, AlterTableCmd *cmd, bool recurse, bool recursing, LOCKMODE lockmode)
8576 {
8577  /*
8578  * Reject ONLY if there are child tables. We could implement this, but it
8579  * is a bit complicated. GENERATED clauses must be attached to the column
8580  * definition and cannot be added later like DEFAULT, so if a child table
8581  * has a generation expression that the parent does not have, the child
8582  * column will necessarily be an attislocal column. So to implement ONLY
8583  * here, we'd need extra code to update attislocal of the direct child
8584  * tables, somewhat similar to how DROP COLUMN does it, so that the
8585  * resulting state can be properly dumped and restored.
8586  */
8587  if (!recurse &&
8589  ereport(ERROR,
8590  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
8591  errmsg("ALTER TABLE / DROP EXPRESSION must be applied to child tables too")));
8592 
8593  /*
8594  * Cannot drop generation expression from inherited columns.
8595  */
8596  if (!recursing)
8597  {
8598  HeapTuple tuple;
8599  Form_pg_attribute attTup;
8600 
8601  tuple = SearchSysCacheCopyAttName(RelationGetRelid(rel), cmd->name);
8602  if (!HeapTupleIsValid(tuple))
8603  ereport(ERROR,
8604  (errcode(ERRCODE_UNDEFINED_COLUMN),
8605  errmsg("column \"%s\" of relation \"%s\" does not exist",
8606  cmd->name, RelationGetRelationName(rel))));
8607 
8608  attTup = (Form_pg_attribute) GETSTRUCT(tuple);
8609 
8610  if (attTup->attinhcount > 0)
8611  ereport(ERROR,
8612  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
8613  errmsg("cannot drop generation expression from inherited column")));
8614  }
8615 }
8616 
8617 /*
8618  * Return the address of the affected column.
8619  */
8620 static ObjectAddress
8621 ATExecDropExpression(Relation rel, const char *colName, bool missing_ok, LOCKMODE lockmode)
8622 {
8623  HeapTuple tuple;
8624  Form_pg_attribute attTup;
8626  Relation attrelation;
8627  Oid attrdefoid;
8628  ObjectAddress address;
8629 
8630  attrelation = table_open(AttributeRelationId, RowExclusiveLock);
8631  tuple = SearchSysCacheCopyAttName(RelationGetRelid(rel), colName);
8632  if (!HeapTupleIsValid(tuple))
8633  ereport(ERROR,
8634  (errcode(ERRCODE_UNDEFINED_COLUMN),
8635  errmsg("column \"%s\" of relation \"%s\" does not exist",
8636  colName, RelationGetRelationName(rel))));
8637 
8638  attTup = (Form_pg_attribute) GETSTRUCT(tuple);
8639  attnum = attTup->attnum;
8640 
8641  if (attnum <= 0)
8642  ereport(ERROR,
8643  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
8644  errmsg("cannot alter system column \"%s\"",
8645  colName)));
8646 
8647  if (attTup->attgenerated != ATTRIBUTE_GENERATED_STORED)
8648  {
8649  if (!missing_ok)
8650  ereport(ERROR,
8651  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
8652  errmsg("column \"%s\" of relation \"%s\" is not a stored generated column",
8653  colName, RelationGetRelationName(rel))));
8654  else
8655  {
8656  ereport(NOTICE,
8657  (errmsg("column \"%s\" of relation \"%s\" is not a stored generated column, skipping",
8658  colName, RelationGetRelationName(rel))));
8659  heap_freetuple(tuple);
8660  table_close(attrelation, RowExclusiveLock);
8661  return InvalidObjectAddress;
8662  }
8663  }
8664 
8665  /*
8666  * Mark the column as no longer generated. (The atthasdef flag needs to
8667  * get cleared too, but RemoveAttrDefault will handle that.)
8668  */
8669  attTup->attgenerated = '\0';
8670  CatalogTupleUpdate(attrelation, &tuple->t_self, tuple);
8671 
8672  InvokeObjectPostAlterHook(RelationRelationId,
8673  RelationGetRelid(rel),
8674  attnum);
8675  heap_freetuple(tuple);
8676 
8677  table_close(attrelation, RowExclusiveLock);
8678 
8679  /*
8680  * Drop the dependency records of the GENERATED expression, in particular
8681  * its INTERNAL dependency on the column, which would otherwise cause
8682  * dependency.c to refuse to perform the deletion.
8683  */
8684  attrdefoid = GetAttrDefaultOid(RelationGetRelid(rel), attnum);
8685  if (!OidIsValid(attrdefoid))
8686  elog(ERROR, "could not find attrdef tuple for relation %u attnum %d",
8687  RelationGetRelid(rel), attnum);
8688  (void) deleteDependencyRecordsFor(AttrDefaultRelationId, attrdefoid, false);
8689 
8690  /* Make above changes visible */
8692 
8693  /*
8694  * Get rid of the GENERATED expression itself. We use RESTRICT here for
8695  * safety, but at present we do not expect anything to depend on the
8696  * default.
8697  */
8699  false, false);
8700 
8701  ObjectAddressSubSet(address, RelationRelationId,
8702  RelationGetRelid(rel), attnum);
8703  return address;
8704 }
8705 
8706 /*
8707  * ALTER TABLE ALTER COLUMN SET STATISTICS
8708  *
8709  * Return value is the address of the modified column
8710  */
8711 static ObjectAddress
8712 ATExecSetStatistics(Relation rel, const char *colName, int16 colNum, Node *newValue, LOCKMODE lockmode)
8713 {
8714  int newtarget = 0;
8715  bool newtarget_default;
8716  Relation attrelation;
8717  HeapTuple tuple,
8718  newtuple;
8719  Form_pg_attribute attrtuple;
8721  ObjectAddress address;
8722  Datum repl_val[Natts_pg_attribute];
8723  bool repl_null[Natts_pg_attribute];
8724  bool repl_repl[Natts_pg_attribute];
8725 
8726  /*
8727  * We allow referencing columns by numbers only for indexes, since table
8728  * column numbers could contain gaps if columns are later dropped.
8729  */
8730  if (rel->rd_rel->relkind != RELKIND_INDEX &&
8731  rel->rd_rel->relkind != RELKIND_PARTITIONED_INDEX &&
8732  !colName)
8733  ereport(ERROR,
8734  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
8735  errmsg("cannot refer to non-index column by number")));
8736 
8737  /* -1 was used in previous versions for the default setting */
8738  if (newValue && intVal(newValue) != -1)
8739  {
8740  newtarget = intVal(newValue);
8741  newtarget_default = false;
8742  }
8743  else
8744  newtarget_default = true;
8745 
8746  if (!newtarget_default)
8747  {
8748  /*
8749  * Limit target to a sane range
8750  */
8751  if (newtarget < 0)
8752  {
8753  ereport(ERROR,
8754  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
8755  errmsg("statistics target %d is too low",
8756  newtarget)));
8757  }
8758  else if (newtarget > MAX_STATISTICS_TARGET)
8759  {
8760  newtarget = MAX_STATISTICS_TARGET;
8761  ereport(WARNING,
8762  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
8763  errmsg("lowering statistics target to %d",
8764  newtarget)));
8765  }
8766  }
8767 
8768  attrelation = table_open(AttributeRelationId, RowExclusiveLock);
8769 
8770  if (colName)
8771  {
8772  tuple = SearchSysCacheAttName(RelationGetRelid(rel), colName);
8773 
8774  if (!HeapTupleIsValid(tuple))
8775  ereport(ERROR,
8776  (errcode(ERRCODE_UNDEFINED_COLUMN),
8777  errmsg("column \"%s\" of relation \"%s\" does not exist",
8778  colName, RelationGetRelationName(rel))));
8779  }
8780  else
8781  {
8782  tuple = SearchSysCacheAttNum(RelationGetRelid(rel), colNum);
8783 
8784  if (!HeapTupleIsValid(tuple))
8785  ereport(ERROR,
8786  (errcode(ERRCODE_UNDEFINED_COLUMN),
8787  errmsg("column number %d of relation \"%s\" does not exist",
8788  colNum, RelationGetRelationName(rel))));
8789  }
8790 
8791  attrtuple = (Form_pg_attribute) GETSTRUCT(tuple);
8792 
8793  attnum = attrtuple->attnum;
8794  if (attnum <= 0)
8795  ereport(ERROR,
8796  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
8797  errmsg("cannot alter system column \"%s\"",
8798  colName)));
8799 
8800  if (rel->rd_rel->relkind == RELKIND_INDEX ||
8801  rel->rd_rel->relkind == RELKIND_PARTITIONED_INDEX)
8802  {
8803  if (attnum > rel->rd_index->indnkeyatts)
8804  ereport(ERROR,
8805  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
8806  errmsg("cannot alter statistics on included column \"%s\" of index \"%s\"",
8807  NameStr(attrtuple->attname), RelationGetRelationName(rel))));
8808  else if (rel->rd_index->indkey.values[attnum - 1] != 0)
8809  ereport(ERROR,
8810  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
8811  errmsg("cannot alter statistics on non-expression column \"%s\" of index \"%s\"",
8812  NameStr(attrtuple->attname), RelationGetRelationName(rel)),
8813  errhint("Alter statistics on table column instead.")));
8814  }
8815 
8816  /* Build new tuple. */
8817  memset(repl_null, false, sizeof(repl_null));
8818  memset(repl_repl, false, sizeof(repl_repl));
8819  if (!newtarget_default)
8820  repl_val[Anum_pg_attribute_attstattarget - 1] = newtarget;
8821  else
8822  repl_null[Anum_pg_attribute_attstattarget - 1] = true;
8823  repl_repl[Anum_pg_attribute_attstattarget - 1] = true;
8824  newtuple = heap_modify_tuple(tuple, RelationGetDescr(attrelation),
8825  repl_val, repl_null, repl_repl);
8826  CatalogTupleUpdate(attrelation, &tuple->t_self, newtuple);
8827 
8828  InvokeObjectPostAlterHook(RelationRelationId,
8829  RelationGetRelid(rel),
8830  attrtuple->attnum);
8831  ObjectAddressSubSet(address, RelationRelationId,
8832  RelationGetRelid(rel), attnum);
8833 
8834  heap_freetuple(newtuple);
8835 
8836  ReleaseSysCache(tuple);
8837 
8838  table_close(attrelation, RowExclusiveLock);
8839 
8840  return address;
8841 }
8842 
8843 /*
8844  * Return value is the address of the modified column
8845  */
8846 static ObjectAddress
8847 ATExecSetOptions(Relation rel, const char *colName, Node *options,
8848  bool isReset, LOCKMODE lockmode)
8849 {
8850  Relation attrelation;
8851  HeapTuple tuple,
8852  newtuple;
8853  Form_pg_attribute attrtuple;
8855  Datum datum,
8856  newOptions;
8857  bool isnull;
8858  ObjectAddress address;
8859  Datum repl_val[Natts_pg_attribute];
8860  bool repl_null[Natts_pg_attribute];
8861  bool repl_repl[Natts_pg_attribute];
8862 
8863  attrelation = table_open(AttributeRelationId, RowExclusiveLock);
8864 
8865  tuple = SearchSysCacheAttName(RelationGetRelid(rel), colName);
8866 
8867  if (!HeapTupleIsValid(tuple))
8868  ereport(ERROR,
8869  (errcode(ERRCODE_UNDEFINED_COLUMN),
8870  errmsg("column \"%s\" of relation \"%s\" does not exist",
8871  colName, RelationGetRelationName(rel))));
8872  attrtuple = (Form_pg_attribute) GETSTRUCT(tuple);
8873 
8874  attnum = attrtuple->attnum;
8875  if (attnum <= 0)
8876  ereport(ERROR,
8877  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
8878  errmsg("cannot alter system column \"%s\"",
8879  colName)));
8880 
8881  /* Generate new proposed attoptions (text array) */
8882  datum = SysCacheGetAttr(ATTNAME, tuple, Anum_pg_attribute_attoptions,
8883  &isnull);
8884  newOptions = transformRelOptions(isnull ? (Datum) 0 : datum,
8885  castNode(List, options), NULL, NULL,
8886  false, isReset);
8887  /* Validate new options */
8888  (void) attribute_reloptions(newOptions, true);
8889 
8890  /* Build new tuple. */
8891  memset(repl_null, false, sizeof(repl_null));
8892  memset(repl_repl, false, sizeof(repl_repl));
8893  if (newOptions != (Datum) 0)
8894  repl_val[Anum_pg_attribute_attoptions - 1] = newOptions;
8895  else
8896  repl_null[Anum_pg_attribute_attoptions - 1] = true;
8897  repl_repl[Anum_pg_attribute_attoptions - 1] = true;
8898  newtuple = heap_modify_tuple(tuple, RelationGetDescr(attrelation),
8899  repl_val, repl_null, repl_repl);
8900 
8901  /* Update system catalog. */
8902  CatalogTupleUpdate(attrelation, &newtuple->t_self, newtuple);
8903 
8904  InvokeObjectPostAlterHook(RelationRelationId,
8905  RelationGetRelid(rel),
8906  attrtuple->attnum);
8907  ObjectAddressSubSet(address, RelationRelationId,
8908  RelationGetRelid(rel), attnum);
8909 
8910  heap_freetuple(newtuple);
8911 
8912  ReleaseSysCache(tuple);
8913 
8914  table_close(attrelation, RowExclusiveLock);
8915 
8916  return address;
8917 }
8918 
8919 /*
8920  * Helper function for ATExecSetStorage and ATExecSetCompression
8921  *
8922  * Set the attstorage and/or attcompression fields for index columns
8923  * associated with the specified table column.
8924  */
8925 static void
8928  bool setstorage, char newstorage,
8929  bool setcompression, char newcompression,
8930  LOCKMODE lockmode)
8931 {
8932  ListCell *lc;
8933 
8934  foreach(lc, RelationGetIndexList(rel))
8935  {
8936  Oid indexoid = lfirst_oid(lc);
8937  Relation indrel;
8938  AttrNumber indattnum = 0;
8939  HeapTuple tuple;
8940 
8941  indrel = index_open(indexoid, lockmode);
8942 
8943  for (int i = 0; i < indrel->rd_index->indnatts; i++)
8944  {
8945  if (indrel->rd_index->indkey.values[i] == attnum)
8946  {
8947  indattnum = i + 1;
8948  break;
8949  }
8950  }
8951 
8952  if (indattnum == 0)
8953  {
8954  index_close(indrel, lockmode);
8955  continue;
8956  }
8957 
8958  tuple = SearchSysCacheCopyAttNum(RelationGetRelid(indrel), indattnum);
8959 
8960  if (HeapTupleIsValid(tuple))
8961  {
8962  Form_pg_attribute attrtuple = (Form_pg_attribute) GETSTRUCT(tuple);
8963 
8964  if (setstorage)
8965  attrtuple->attstorage = newstorage;
8966 
8967  if (setcompression)
8968  attrtuple->attcompression = newcompression;
8969 
8970  CatalogTupleUpdate(attrelation, &tuple->t_self, tuple);
8971 
8972  InvokeObjectPostAlterHook(RelationRelationId,
8973  RelationGetRelid(rel),
8974  attrtuple->attnum);
8975 
8976  heap_freetuple(tuple);
8977  }
8978 
8979  index_close(indrel, lockmode);
8980  }
8981 }
8982 
8983 /*
8984  * ALTER TABLE ALTER COLUMN SET STORAGE
8985  *
8986  * Return value is the address of the modified column
8987  */
8988 static ObjectAddress
8989 ATExecSetStorage(Relation rel, const char *colName, Node *newValue, LOCKMODE lockmode)
8990 {
8991  Relation attrelation;
8992  HeapTuple tuple;
8993  Form_pg_attribute attrtuple;
8995  ObjectAddress address;
8996 
8997  attrelation = table_open(AttributeRelationId, RowExclusiveLock);
8998 
8999  tuple = SearchSysCacheCopyAttName(RelationGetRelid(rel), colName);
9000 
9001  if (!HeapTupleIsValid(tuple))
9002  ereport(ERROR,
9003  (errcode(ERRCODE_UNDEFINED_COLUMN),
9004  errmsg("column \"%s\" of relation \"%s\" does not exist",
9005  colName, RelationGetRelationName(rel))));
9006  attrtuple = (Form_pg_attribute) GETSTRUCT(tuple);
9007 
9008  attnum = attrtuple->attnum;
9009  if (attnum <= 0)
9010  ereport(ERROR,
9011  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
9012  errmsg("cannot alter system column \"%s\"",
9013  colName)));
9014 
9015  attrtuple->attstorage = GetAttributeStorage(attrtuple->atttypid, strVal(newValue));
9016 
9017  CatalogTupleUpdate(attrelation, &tuple->t_self, tuple);
9018 
9019  InvokeObjectPostAlterHook(RelationRelationId,
9020  RelationGetRelid(rel),
9021  attrtuple->attnum);
9022 
9023  /*
9024  * Apply the change to indexes as well (only for simple index columns,
9025  * matching behavior of index.c ConstructTupleDescriptor()).
9026  */
9027  SetIndexStorageProperties(rel, attrelation, attnum,
9028  true, attrtuple->attstorage,
9029  false, 0,
9030  lockmode);
9031 
9032  heap_freetuple(tuple);
9033 
9034  table_close(attrelation, RowExclusiveLock);
9035 
9036  ObjectAddressSubSet(address, RelationRelationId,
9037  RelationGetRelid(rel), attnum);
9038  return address;
9039 }
9040 
9041 
9042 /*
9043  * ALTER TABLE DROP COLUMN
9044  *
9045  * DROP COLUMN cannot use the normal ALTER TABLE recursion mechanism,
9046  * because we have to decide at runtime whether to recurse or not depending
9047  * on whether attinhcount goes to zero or not. (We can't check this in a
9048  * static pre-pass because it won't handle multiple inheritance situations
9049  * correctly.)
9050  */
9051 static void
9052 ATPrepDropColumn(List **wqueue, Relation rel, bool recurse, bool recursing,
9053  AlterTableCmd *cmd, LOCKMODE lockmode,
9054  AlterTableUtilityContext *context)
9055 {
9056  if (rel->rd_rel->reloftype && !recursing)
9057  ereport(ERROR,
9058  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
9059  errmsg("cannot drop column from typed table")));
9060 
9061  if (rel->rd_rel->relkind == RELKIND_COMPOSITE_TYPE)
9062  ATTypedTableRecursion(wqueue, rel, cmd, lockmode, context);
9063 
9064  if (recurse)
9065  cmd->recurse = true;
9066 }
9067 
9068 /*
9069  * Drops column 'colName' from relation 'rel' and returns the address of the
9070  * dropped column. The column is also dropped (or marked as no longer
9071  * inherited from relation) from the relation's inheritance children, if any.
9072  *
9073  * In the recursive invocations for inheritance child relations, instead of
9074  * dropping the column directly (if to be dropped at all), its object address
9075  * is added to 'addrs', which must be non-NULL in such invocations. All
9076  * columns are dropped at the same time after all the children have been
9077  * checked recursively.
9078  */
9079 static ObjectAddress
9080 ATExecDropColumn(List **wqueue, Relation rel, const char *colName,
9081  DropBehavior behavior,
9082  bool recurse, bool recursing,
9083  bool missing_ok, LOCKMODE lockmode,
9084  ObjectAddresses *addrs)
9085 {
9086  HeapTuple tuple;
9087  Form_pg_attribute targetatt;
9089  List *children;
9090  ObjectAddress object;
9091  bool is_expr;
9092 
9093  /* At top level, permission check was done in ATPrepCmd, else do it */
9094  if (recursing)
9096 
9097  /* Initialize addrs on the first invocation */
9098  Assert(!recursing || addrs != NULL);
9099 
9100  /* since this function recurses, it could be driven to stack overflow */
9102 
9103  if (!recursing)
9104  addrs = new_object_addresses();
9105 
9106  /*
9107  * get the number of the attribute
9108  */
9109  tuple = SearchSysCacheAttName(RelationGetRelid(rel), colName);
9110  if (!HeapTupleIsValid(tuple))
9111  {
9112  if (!missing_ok)
9113  {
9114  ereport(ERROR,
9115  (errcode(ERRCODE_UNDEFINED_COLUMN),
9116  errmsg("column \"%s\" of relation \"%s\" does not exist",
9117  colName, RelationGetRelationName(rel))));
9118  }
9119  else
9120  {
9121  ereport(NOTICE,
9122  (errmsg("column \"%s\" of relation \"%s\" does not exist, skipping",
9123  colName, RelationGetRelationName(rel))));
9124  return InvalidObjectAddress;
9125  }
9126  }
9127  targetatt = (Form_pg_attribute) GETSTRUCT(tuple);
9128 
9129  attnum = targetatt->attnum;
9130 
9131  /* Can't drop a system attribute */
9132  if (attnum <= 0)
9133  ereport(ERROR,
9134  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
9135  errmsg("cannot drop system column \"%s\"",
9136  colName)));
9137 
9138  /*
9139  * Don't drop inherited columns, unless recursing (presumably from a drop
9140  * of the parent column)
9141  */
9142  if (targetatt->attinhcount > 0 && !recursing)
9143  ereport(ERROR,
9144  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
9145  errmsg("cannot drop inherited column \"%s\"",
9146  colName)));
9147 
9148  /*
9149  * Don't drop columns used in the partition key, either. (If we let this
9150  * go through, the key column's dependencies would cause a cascaded drop
9151  * of the whole table, which is surely not what the user expected.)
9152  */
9153  if (has_partition_attrs(rel,
9155  &is_expr))
9156  ereport(ERROR,
9157  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
9158  errmsg("cannot drop column \"%s\" because it is part of the partition key of relation \"%s\"",
9159  colName, RelationGetRelationName(rel))));
9160 
9161  ReleaseSysCache(tuple);
9162 
9163  /*
9164  * Propagate to children as appropriate. Unlike most other ALTER
9165  * routines, we have to do this one level of recursion at a time; we can't
9166  * use find_all_inheritors to do it in one pass.
9167  */
9168  children =
9170 
9171  if (children)
9172  {
9173  Relation attr_rel;
9174  ListCell *child;
9175 
9176  /*
9177  * In case of a partitioned table, the column must be dropped from the
9178  * partitions as well.
9179  */
9180  if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE && !recurse)
9181  ereport(ERROR,
9182  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
9183  errmsg("cannot drop column from only the partitioned table when partitions exist"),
9184  errhint("Do not specify the ONLY keyword.")));
9185 
9186  attr_rel = table_open(AttributeRelationId, RowExclusiveLock);
9187  foreach(child, children)
9188  {
9189  Oid childrelid = lfirst_oid(child);
9190  Relation childrel;
9191  Form_pg_attribute childatt;
9192 
9193  /* find_inheritance_children already got lock */
9194  childrel = table_open(childrelid, NoLock);
9195  CheckTableNotInUse(childrel, "ALTER TABLE");
9196 
9197  tuple = SearchSysCacheCopyAttName(childrelid, colName);
9198  if (!HeapTupleIsValid(tuple)) /* shouldn't happen */
9199  elog(ERROR, "cache lookup failed for attribute \"%s\" of relation %u",
9200  colName, childrelid);
9201  childatt = (Form_pg_attribute) GETSTRUCT(tuple);
9202 
9203  if (childatt->attinhcount <= 0) /* shouldn't happen */
9204  elog(ERROR, "relation %u has non-inherited attribute \"%s\"",
9205  childrelid, colName);
9206 
9207  if (recurse)
9208  {
9209  /*
9210  * If the child column has other definition sources, just
9211  * decrement its inheritance count; if not, recurse to delete
9212  * it.
9213  */
9214  if (childatt->attinhcount == 1 && !childatt->attislocal)
9215  {
9216  /* Time to delete this child column, too */
9217  ATExecDropColumn(wqueue, childrel, colName,
9218  behavior, true, true,
9219  false, lockmode, addrs);
9220  }
9221  else
9222  {
9223  /* Child column must survive my deletion */
9224  childatt->attinhcount--;
9225 
9226  CatalogTupleUpdate(attr_rel, &tuple->t_self, tuple);
9227 
9228  /* Make update visible */
9230  }
9231  }
9232  else
9233  {
9234  /*
9235  * If we were told to drop ONLY in this table (no recursion),
9236  * we need to mark the inheritors' attributes as locally
9237  * defined rather than inherited.
9238  */
9239  childatt->attinhcount--;
9240  childatt->attislocal = true;
9241 
9242  CatalogTupleUpdate(attr_rel, &tuple->t_self, tuple);
9243 
9244  /* Make update visible */
9246  }
9247 
9248  heap_freetuple(tuple);
9249 
9250  table_close(childrel, NoLock);
9251  }
9252  table_close(attr_rel, RowExclusiveLock);
9253  }
9254 
9255  /* Add object to delete */
9256  object.classId = RelationRelationId;
9257  object.objectId = RelationGetRelid(rel);
9258  object.objectSubId = attnum;
9259  add_exact_object_address(&object, addrs);
9260 
9261  if (!recursing)
9262  {
9263  /* Recursion has ended, drop everything that was collected */
9264  performMultipleDeletions(addrs, behavior, 0);
9265  free_object_addresses(addrs);
9266  }
9267 
9268  return object;
9269 }
9270 
9271 /*
9272  * Prepare to add a primary key on an inheritance parent, by adding NOT NULL
9273  * constraint on its children.
9274  */
9275 static void
9277  LOCKMODE lockmode, AlterTableUtilityContext *context)
9278 {
9279  List *children;
9280  List *newconstrs = NIL;
9281  ListCell *lc;
9282  IndexStmt *indexstmt;
9283 
9284  /* No work if not creating a primary key */
9285  if (!IsA(cmd->def, IndexStmt))
9286  return;
9287  indexstmt = castNode(IndexStmt, cmd->def);
9288  if (!indexstmt->primary)
9289  return;
9290 
9291  /* No work if no legacy inheritance children are present */
9292  if (rel->rd_rel->relkind != RELKIND_RELATION ||
9293  !rel->rd_rel->relhassubclass)
9294  return;
9295 
9296  children = find_inheritance_children(RelationGetRelid(rel), lockmode);
9297 
9298  foreach(lc, indexstmt->indexParams)
9299  {
9300  IndexElem *elem = lfirst_node(IndexElem, lc);
9301  Constraint *nnconstr;
9302 
9303  Assert(elem->expr == NULL);
9304 
9305  nnconstr = makeNode(Constraint);
9306  nnconstr->contype = CONSTR_NOTNULL;
9307  nnconstr->conname = NULL; /* XXX use PK name? */
9308  nnconstr->inhcount = 1;
9309  nnconstr->deferrable = false;
9310  nnconstr->initdeferred = false;
9311  nnconstr->location = -1;
9312  nnconstr->keys = list_make1(makeString(elem->name));
9313  nnconstr->skip_validation = false;
9314  nnconstr->initially_valid = true;
9315 
9316  newconstrs = lappend(newconstrs, nnconstr);
9317  }
9318 
9319  foreach(lc, children)
9320  {
9321  Oid childrelid = lfirst_oid(lc);
9322  Relation childrel = table_open(childrelid, NoLock);
9324  ListCell *lc2;
9325 
9326  newcmd->subtype = AT_AddConstraint;
9327  newcmd->recurse = true;
9328 
9329  foreach(lc2, newconstrs)
9330  {
9331  /* ATPrepCmd copies newcmd, so we can scribble on it here */
9332  newcmd->def = lfirst(lc2);
9333 
9334  ATPrepCmd(wqueue, childrel, newcmd,
9335  true, false, lockmode, context);
9336  }
9337 
9338  table_close(childrel, NoLock);
9339  }
9340 }
9341 
9342 /*
9343  * ALTER TABLE ADD INDEX
9344  *
9345  * There is no such command in the grammar, but parse_utilcmd.c converts
9346  * UNIQUE and PRIMARY KEY constraints into AT_AddIndex subcommands. This lets
9347  * us schedule creation of the index at the appropriate time during ALTER.
9348  *
9349  * Return value is the address of the new index.
9350  */
9351 static ObjectAddress
9353  IndexStmt *stmt, bool is_rebuild, LOCKMODE lockmode)
9354 {
9355  bool check_rights;
9356  bool skip_build;
9357  bool quiet;
9358  ObjectAddress address;
9359 
9360  Assert(IsA(stmt, IndexStmt));
9361  Assert(!stmt->concurrent);
9362 
9363  /* The IndexStmt has already been through transformIndexStmt */
9364  Assert(stmt->transformed);
9365 
9366  /* suppress schema rights check when rebuilding existing index */
9367  check_rights = !is_rebuild;
9368  /* skip index build if phase 3 will do it or we're reusing an old one */
9369  skip_build = tab->rewrite > 0 || RelFileNumberIsValid(stmt->oldNumber);
9370  /* suppress notices when rebuilding existing index */
9371  quiet = is_rebuild;
9372 
9373  address = DefineIndex(RelationGetRelid(rel),
9374  stmt,
9375  InvalidOid, /* no predefined OID */
9376  InvalidOid, /* no parent index */
9377  InvalidOid, /* no parent constraint */
9378  -1, /* total_parts unknown */
9379  true, /* is_alter_table */
9380  check_rights,
9381  false, /* check_not_in_use - we did it already */
9382  skip_build,
9383  quiet);
9384 
9385  /*
9386  * If TryReuseIndex() stashed a relfilenumber for us, we used it for the
9387  * new index instead of building from scratch. Restore associated fields.
9388  * This may store InvalidSubTransactionId in both fields, in which case
9389  * relcache.c will assume it can rebuild the relcache entry. Hence, do
9390  * this after the CCI that made catalog rows visible to any rebuild. The
9391  * DROP of the old edition of this index will have scheduled the storage
9392  * for deletion at commit, so cancel that pending deletion.
9393  */
9394  if (RelFileNumberIsValid(stmt->oldNumber))
9395  {
9396  Relation irel = index_open(address.objectId, NoLock);
9397 
9398  irel->rd_createSubid = stmt->oldCreateSubid;
9399  irel->rd_firstRelfilelocatorSubid = stmt->oldFirstRelfilelocatorSubid;
9400  RelationPreserveStorage(irel->rd_locator, true);
9401  index_close(irel, NoLock);
9402  }
9403 
9404  return address;
9405 }
9406 
9407 /*
9408  * ALTER TABLE ADD STATISTICS
9409  *
9410  * This is no such command in the grammar, but we use this internally to add
9411  * AT_ReAddStatistics subcommands to rebuild extended statistics after a table
9412  * column type change.
9413  */
9414 static ObjectAddress
9416  CreateStatsStmt *stmt, bool is_rebuild, LOCKMODE lockmode)
9417 {
9418  ObjectAddress address;
9419 
9421 
9422  /* The CreateStatsStmt has already been through transformStatsStmt */
9423  Assert(stmt->transformed);
9424 
9425  address = CreateStatistics(stmt);
9426 
9427  return address;
9428 }
9429 
9430 /*
9431  * ALTER TABLE ADD CONSTRAINT USING INDEX
9432  *
9433  * Returns the address of the new constraint.
9434  */
9435 static ObjectAddress
9437  IndexStmt *stmt, LOCKMODE lockmode)
9438 {
9439  Oid index_oid = stmt->indexOid;
9440  Relation indexRel;
9441  char *indexName;
9442  IndexInfo *indexInfo;
9443  char *constraintName;
9444  char constraintType;
9445  ObjectAddress address;
9446  bits16 flags;
9447 
9448  Assert(IsA(stmt, IndexStmt));
9449  Assert(OidIsValid(index_oid));
9450  Assert(stmt->isconstraint);
9451 
9452  /*
9453  * Doing this on partitioned tables is not a simple feature to implement,
9454  * so let's punt for now.
9455  */
9456  if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
9457  ereport(ERROR,
9458  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
9459  errmsg("ALTER TABLE / ADD CONSTRAINT USING INDEX is not supported on partitioned tables")));
9460 
9461  indexRel = index_open(index_oid, AccessShareLock);
9462 
9463  indexName = pstrdup(RelationGetRelationName(indexRel));
9464 
9465  indexInfo = BuildIndexInfo(indexRel);
9466 
9467  /* this should have been checked at parse time */
9468  if (!indexInfo->ii_Unique)
9469  elog(ERROR, "index \"%s\" is not unique", indexName);
9470 
9471  /*
9472  * Determine name to assign to constraint. We require a constraint to
9473  * have the same name as the underlying index; therefore, use the index's
9474  * existing name as the default constraint name, and if the user
9475  * explicitly gives some other name for the constraint, rename the index
9476  * to match.
9477  */
9478  constraintName = stmt->idxname;
9479  if (constraintName == NULL)
9480  constraintName = indexName;
9481  else if (strcmp(constraintName, indexName) != 0)
9482  {
9483  ereport(NOTICE,
9484  (errmsg("ALTER TABLE / ADD CONSTRAINT USING INDEX will rename index \"%s\" to \"%s\"",
9485  indexName, constraintName)));
9486  RenameRelationInternal(index_oid, constraintName, false, true);
9487  }
9488 
9489  /* Extra checks needed if making primary key */
9490  if (stmt->primary)
9491  index_check_primary_key(rel, indexInfo, true, stmt);
9492 
9493  /* Note we currently don't support EXCLUSION constraints here */
9494  if (stmt->primary)
9495  constraintType = CONSTRAINT_PRIMARY;
9496  else
9497  constraintType = CONSTRAINT_UNIQUE;
9498 
9499  /* Create the catalog entries for the constraint */
9502  (stmt->initdeferred ? INDEX_CONSTR_CREATE_INIT_DEFERRED : 0) |
9503  (stmt->deferrable ? INDEX_CONSTR_CREATE_DEFERRABLE : 0) |
9504  (stmt->primary ? INDEX_CONSTR_CREATE_MARK_AS_PRIMARY : 0);
9505 
9506  address = index_constraint_create(rel,
9507  index_oid,
9508  InvalidOid,
9509  indexInfo,
9510  constraintName,
9511  constraintType,
9512  flags,
9514  false); /* is_internal */
9515 
9516  index_close(indexRel, NoLock);
9517 
9518  return address;
9519 }
9520 
9521 /*
9522  * ALTER TABLE ADD CONSTRAINT
9523  *
9524  * Return value is the address of the new constraint; if no constraint was
9525  * added, InvalidObjectAddress is returned.
9526  */
9527 static ObjectAddress
9529  Constraint *newConstraint, bool recurse, bool is_readd,
9530  LOCKMODE lockmode)
9531 {
9533 
9534  Assert(IsA(newConstraint, Constraint));
9535 
9536  /*
9537  * Currently, we only expect to see CONSTR_CHECK, CONSTR_NOTNULL and
9538  * CONSTR_FOREIGN nodes arriving here (see the preprocessing done in
9539  * parse_utilcmd.c).
9540  */
9541  switch (newConstraint->contype)
9542  {
9543  case CONSTR_CHECK:
9544  case CONSTR_NOTNULL:
9545  address =
9546  ATAddCheckNNConstraint(wqueue, tab, rel,
9547  newConstraint, recurse, false, is_readd,
9548  lockmode);
9549  break;
9550 
9551  case CONSTR_FOREIGN:
9552 
9553  /*
9554  * Assign or validate constraint name
9555  */
9556  if (newConstraint->conname)
9557  {
9559  RelationGetRelid(rel),
9560  newConstraint->conname))
9561  ereport(ERROR,
9563  errmsg("constraint \"%s\" for relation \"%s\" already exists",
9564  newConstraint->conname,
9565  RelationGetRelationName(rel))));
9566  }
9567  else
9568  newConstraint->conname =
9571  "fkey",
9572  RelationGetNamespace(rel),
9573  NIL);
9574 
9575  address = ATAddForeignKeyConstraint(wqueue, tab, rel,
9576  newConstraint,
9577  recurse, false,
9578  lockmode);
9579  break;
9580 
9581  default:
9582  elog(ERROR, "unrecognized constraint type: %d",
9583  (int) newConstraint->contype);
9584  }
9585 
9586  return address;
9587 }
9588 
9589 /*
9590  * Generate the column-name portion of the constraint name for a new foreign
9591  * key given the list of column names that reference the referenced
9592  * table. This will be passed to ChooseConstraintName along with the parent
9593  * table name and the "fkey" suffix.
9594  *
9595  * We know that less than NAMEDATALEN characters will actually be used, so we
9596  * can truncate the result once we've generated that many.
9597  *
9598  * XXX see also ChooseExtendedStatisticNameAddition and
9599  * ChooseIndexNameAddition.
9600  */
9601 static char *
9603 {
9604  char buf[NAMEDATALEN * 2];
9605  int buflen = 0;
9606  ListCell *lc;
9607 
9608  buf[0] = '\0';
9609  foreach(lc, colnames)
9610  {
9611  const char *name = strVal(lfirst(lc));
9612 
9613  if (buflen > 0)
9614  buf[buflen++] = '_'; /* insert _ between names */
9615 
9616  /*
9617  * At this point we have buflen <= NAMEDATALEN. name should be less
9618  * than NAMEDATALEN already, but use strlcpy for paranoia.
9619  */
9620  strlcpy(buf + buflen, name, NAMEDATALEN);
9621  buflen += strlen(buf + buflen);
9622  if (buflen >= NAMEDATALEN)
9623  break;
9624  }
9625  return pstrdup(buf);
9626 }
9627 
9628 /*
9629  * Add a check or not-null constraint to a single table and its children.
9630  * Returns the address of the constraint added to the parent relation,
9631  * if one gets added, or InvalidObjectAddress otherwise.
9632  *
9633  * Subroutine for ATExecAddConstraint.
9634  *
9635  * We must recurse to child tables during execution, rather than using
9636  * ALTER TABLE's normal prep-time recursion. The reason is that all the
9637  * constraints *must* be given the same name, else they won't be seen as
9638  * related later. If the user didn't explicitly specify a name, then
9639  * AddRelationNewConstraints would normally assign different names to the
9640  * child constraints. To fix that, we must capture the name assigned at
9641  * the parent table and pass that down.
9642  */
9643 static ObjectAddress
9645  Constraint *constr, bool recurse, bool recursing,
9646  bool is_readd, LOCKMODE lockmode)
9647 {
9648  List *newcons;
9649  ListCell *lcon;
9650  List *children;
9651  ListCell *child;
9653 
9654  /* Guard against stack overflow due to overly deep inheritance tree. */
9656 
9657  /* At top level, permission check was done in ATPrepCmd, else do it */
9658  if (recursing)
9660 
9661  /*
9662  * Call AddRelationNewConstraints to do the work, making sure it works on
9663  * a copy of the Constraint so transformExpr can't modify the original. It
9664  * returns a list of cooked constraints.
9665  *
9666  * If the constraint ends up getting merged with a pre-existing one, it's
9667  * omitted from the returned list, which is what we want: we do not need
9668  * to do any validation work. That can only happen at child tables,
9669  * though, since we disallow merging at the top level.
9670  */
9671  newcons = AddRelationNewConstraints(rel, NIL,
9672  list_make1(copyObject(constr)),
9673  recursing || is_readd, /* allow_merge */
9674  !recursing, /* is_local */
9675  is_readd, /* is_internal */
9676  NULL); /* queryString not available
9677  * here */
9678 
9679  /* we don't expect more than one constraint here */
9680  Assert(list_length(newcons) <= 1);
9681 
9682  /* Add each to-be-validated constraint to Phase 3's queue */
9683  foreach(lcon, newcons)
9684  {
9685  CookedConstraint *ccon = (CookedConstraint *) lfirst(lcon);
9686 
9687  if (!ccon->skip_validation && ccon->contype != CONSTR_NOTNULL)
9688  {
9689  NewConstraint *newcon;
9690 
9691  newcon = (NewConstraint *) palloc0(sizeof(NewConstraint));
9692  newcon->name = ccon->name;
9693  newcon->contype = ccon->contype;
9694  newcon->qual = ccon->expr;
9695 
9696  tab->constraints = lappend(tab->constraints, newcon);
9697  }
9698 
9699  /* Save the actually assigned name if it was defaulted */
9700  if (constr->conname == NULL)
9701  constr->conname = ccon->name;
9702 
9703  /*
9704  * If adding a not-null constraint, set the pg_attribute flag and tell
9705  * phase 3 to verify existing rows, if needed.
9706  */
9707  if (constr->contype == CONSTR_NOTNULL)
9708  set_attnotnull(wqueue, rel, ccon->attnum,
9709  !ccon->is_no_inherit, lockmode);
9710 
9711  ObjectAddressSet(address, ConstraintRelationId, ccon->conoid);
9712  }
9713 
9714  /* At this point we must have a locked-down name to use */
9715  Assert(newcons == NIL || constr->conname != NULL);
9716 
9717  /* Advance command counter in case same table is visited multiple times */
9719 
9720  /*
9721  * If the constraint got merged with an existing constraint, we're done.
9722  * We mustn't recurse to child tables in this case, because they've
9723  * already got the constraint, and visiting them again would lead to an
9724  * incorrect value for coninhcount.
9725  */
9726  if (newcons == NIL)
9727  return address;
9728 
9729  /*
9730  * If adding a NO INHERIT constraint, no need to find our children.
9731  */
9732  if (constr->is_no_inherit)
9733  return address;
9734 
9735  /*
9736  * Propagate to children as appropriate. Unlike most other ALTER
9737  * routines, we have to do this one level of recursion at a time; we can't
9738  * use find_all_inheritors to do it in one pass.
9739  */
9740  children =
9742 
9743  /*
9744  * Check if ONLY was specified with ALTER TABLE. If so, allow the
9745  * constraint creation only if there are no children currently. Error out
9746  * otherwise.
9747  */
9748  if (!recurse && children != NIL)
9749  ereport(ERROR,
9750  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
9751  errmsg("constraint must be added to child tables too")));
9752 
9753  /*
9754  * The constraint must appear as inherited in children, so create a
9755  * modified constraint object to use.
9756  */
9757  constr = copyObject(constr);
9758  constr->inhcount = 1;
9759  foreach(child, children)
9760  {
9761  Oid childrelid = lfirst_oid(child);
9762  Relation childrel;
9763  AlteredTableInfo *childtab;
9764 
9765  /* find_inheritance_children already got lock */
9766  childrel = table_open(childrelid, NoLock);
9767  CheckTableNotInUse(childrel, "ALTER TABLE");
9768 
9769  /* Find or create work queue entry for this table */
9770  childtab = ATGetQueueEntry(wqueue, childrel);
9771 
9772  /*
9773  * Recurse to child. XXX if we didn't create a constraint on the
9774  * parent because it already existed, and we do create one on a child,
9775  * should we return that child's constraint ObjectAddress here?
9776  */
9777  ATAddCheckNNConstraint(wqueue, childtab, childrel,
9778  constr, recurse, true, is_readd, lockmode);
9779 
9780  table_close(childrel, NoLock);
9781  }
9782 
9783  return address;
9784 }
9785 
9786 /*
9787  * Add a foreign-key constraint to a single table; return the new constraint's
9788  * address.
9789  *
9790  * Subroutine for ATExecAddConstraint. Must already hold exclusive
9791  * lock on the rel, and have done appropriate validity checks for it.
9792  * We do permissions checks here, however.
9793  *
9794  * When the referenced or referencing tables (or both) are partitioned,
9795  * multiple pg_constraint rows are required -- one for each partitioned table
9796  * and each partition on each side (fortunately, not one for every combination
9797  * thereof). We also need action triggers on each leaf partition on the
9798  * referenced side, and check triggers on each leaf partition on the
9799  * referencing side.
9800  */
9801 static ObjectAddress
9803  Constraint *fkconstraint,
9804  bool recurse, bool recursing, LOCKMODE lockmode)
9805 {
9806  Relation pkrel;
9807  int16 pkattnum[INDEX_MAX_KEYS] = {0};
9808  int16 fkattnum[INDEX_MAX_KEYS] = {0};
9809  Oid pktypoid[INDEX_MAX_KEYS] = {0};
9810  Oid fktypoid[INDEX_MAX_KEYS] = {0};
9811  Oid opclasses[INDEX_MAX_KEYS] = {0};
9812  Oid pfeqoperators[INDEX_MAX_KEYS] = {0};
9813  Oid ppeqoperators[INDEX_MAX_KEYS] = {0};
9814  Oid ffeqoperators[INDEX_MAX_KEYS] = {0};
9815  int16 fkdelsetcols[INDEX_MAX_KEYS] = {0};
9816  int i;
9817  int numfks,
9818  numpks,
9819  numfkdelsetcols;
9820  Oid indexOid;
9821  bool old_check_ok;
9822  ObjectAddress address;
9823  ListCell *old_pfeqop_item = list_head(fkconstraint->old_conpfeqop);
9824 
9825  /*
9826  * Grab ShareRowExclusiveLock on the pk table, so that someone doesn't
9827  * delete rows out from under us.
9828  */
9829  if (OidIsValid(fkconstraint->old_pktable_oid))
9830  pkrel = table_open(fkconstraint->old_pktable_oid, ShareRowExclusiveLock);
9831  else
9832  pkrel = table_openrv(fkconstraint->pktable, ShareRowExclusiveLock);
9833 
9834  /*
9835  * Validity checks (permission checks wait till we have the column
9836  * numbers)
9837  */
9838  if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
9839  {
9840  if (!recurse)
9841  ereport(ERROR,
9842  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
9843  errmsg("cannot use ONLY for foreign key on partitioned table \"%s\" referencing relation \"%s\"",
9845  RelationGetRelationName(pkrel))));
9846  if (fkconstraint->skip_validation && !fkconstraint->initially_valid)
9847  ereport(ERROR,
9848  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
9849  errmsg("cannot add NOT VALID foreign key on partitioned table \"%s\" referencing relation \"%s\"",
9851  RelationGetRelationName(pkrel)),
9852  errdetail("This feature is not yet supported on partitioned tables.")));
9853  }
9854 
9855  if (pkrel->rd_rel->relkind != RELKIND_RELATION &&
9856  pkrel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
9857  ereport(ERROR,
9858  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
9859  errmsg("referenced relation \"%s\" is not a table",
9860  RelationGetRelationName(pkrel))));
9861 
9862  if (!allowSystemTableMods && IsSystemRelation(pkrel))
9863  ereport(ERROR,
9864  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
9865  errmsg("permission denied: \"%s\" is a system catalog",
9866  RelationGetRelationName(pkrel))));
9867 
9868  /*
9869  * References from permanent or unlogged tables to temp tables, and from
9870  * permanent tables to unlogged tables, are disallowed because the
9871  * referenced data can vanish out from under us. References from temp
9872  * tables to any other table type are also disallowed, because other
9873  * backends might need to run the RI triggers on the perm table, but they
9874  * can't reliably see tuples in the local buffers of other backends.
9875  */
9876  switch (rel->rd_rel->relpersistence)
9877  {
9878  case RELPERSISTENCE_PERMANENT:
9879  if (!RelationIsPermanent(pkrel))
9880  ereport(ERROR,
9881  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
9882  errmsg("constraints on permanent tables may reference only permanent tables")));
9883  break;
9884  case RELPERSISTENCE_UNLOGGED:
9885  if (!RelationIsPermanent(pkrel)
9886  && pkrel->rd_rel->relpersistence != RELPERSISTENCE_UNLOGGED)
9887  ereport(ERROR,
9888  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
9889  errmsg("constraints on unlogged tables may reference only permanent or unlogged tables")));
9890  break;
9891  case RELPERSISTENCE_TEMP:
9892  if (pkrel->rd_rel->relpersistence != RELPERSISTENCE_TEMP)
9893  ereport(ERROR,
9894  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
9895  errmsg("constraints on temporary tables may reference only temporary tables")));
9896  if (!pkrel->rd_islocaltemp || !rel->rd_islocaltemp)
9897  ereport(ERROR,
9898  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
9899  errmsg("constraints on temporary tables must involve temporary tables of this session")));
9900  break;
9901  }
9902 
9903  /*
9904  * Look up the referencing attributes to make sure they exist, and record
9905  * their attnums and type OIDs.
9906  */
9908  fkconstraint->fk_attrs,
9909  fkattnum, fktypoid);
9910 
9911  numfkdelsetcols = transformColumnNameList(RelationGetRelid(rel),
9912  fkconstraint->fk_del_set_cols,
9913  fkdelsetcols, NULL);
9914  validateFkOnDeleteSetColumns(numfks, fkattnum,
9915  numfkdelsetcols, fkdelsetcols,
9916  fkconstraint->fk_del_set_cols);
9917 
9918  /*
9919  * If the attribute list for the referenced table was omitted, lookup the
9920  * definition of the primary key and use it. Otherwise, validate the
9921  * supplied attribute list. In either case, discover the index OID and
9922  * index opclasses, and the attnums and type OIDs of the attributes.
9923  */
9924  if (fkconstraint->pk_attrs == NIL)
9925  {
9926  numpks = transformFkeyGetPrimaryKey(pkrel, &indexOid,
9927  &fkconstraint->pk_attrs,
9928  pkattnum, pktypoid,
9929  opclasses);
9930  }
9931  else
9932  {
9933  numpks = transformColumnNameList(RelationGetRelid(pkrel),
9934  fkconstraint->pk_attrs,
9935  pkattnum, pktypoid);
9936  /* Look for an index matching the column list */
9937  indexOid = transformFkeyCheckAttrs(pkrel, numpks, pkattnum,
9938  opclasses);
9939  }
9940 
9941  /*
9942  * Now we can check permissions.
9943  */
9944  checkFkeyPermissions(pkrel, pkattnum, numpks);
9945 
9946  /*
9947  * Check some things for generated columns.
9948  */
9949  for (i = 0; i < numfks; i++)
9950  {
9951  char attgenerated = TupleDescAttr(RelationGetDescr(rel), fkattnum[i] - 1)->attgenerated;
9952 
9953  if (attgenerated)
9954  {
9955  /*
9956  * Check restrictions on UPDATE/DELETE actions, per SQL standard
9957  */
9958  if (fkconstraint->fk_upd_action == FKCONSTR_ACTION_SETNULL ||
9959  fkconstraint->fk_upd_action == FKCONSTR_ACTION_SETDEFAULT ||
9960  fkconstraint->fk_upd_action == FKCONSTR_ACTION_CASCADE)
9961  ereport(ERROR,
9962  (errcode(ERRCODE_SYNTAX_ERROR),
9963  errmsg("invalid %s action for foreign key constraint containing generated column",
9964  "ON UPDATE")));
9965  if (fkconstraint->fk_del_action == FKCONSTR_ACTION_SETNULL ||
9966  fkconstraint->fk_del_action == FKCONSTR_ACTION_SETDEFAULT)
9967  ereport(ERROR,
9968  (errcode(ERRCODE_SYNTAX_ERROR),
9969  errmsg("invalid %s action for foreign key constraint containing generated column",
9970  "ON DELETE")));
9971  }
9972  }
9973 
9974  /*
9975  * Look up the equality operators to use in the constraint.
9976  *
9977  * Note that we have to be careful about the difference between the actual
9978  * PK column type and the opclass' declared input type, which might be
9979  * only binary-compatible with it. The declared opcintype is the right
9980  * thing to probe pg_amop with.
9981  */
9982  if (numfks != numpks)
9983  ereport(ERROR,
9984  (errcode(ERRCODE_INVALID_FOREIGN_KEY),
9985  errmsg("number of referencing and referenced columns for foreign key disagree")));
9986 
9987  /*
9988  * On the strength of a previous constraint, we might avoid scanning
9989  * tables to validate this one. See below.
9990  */
9991  old_check_ok = (fkconstraint->old_conpfeqop != NIL);
9992  Assert(!old_check_ok || numfks == list_length(fkconstraint->old_conpfeqop));
9993 
9994  for (i = 0; i < numpks; i++)
9995  {
9996  Oid pktype = pktypoid[i];
9997  Oid fktype = fktypoid[i];
9998  Oid fktyped;
9999  HeapTuple cla_ht;
10000  Form_pg_opclass cla_tup;
10001  Oid amid;
10002  Oid opfamily;
10003  Oid opcintype;
10004  Oid pfeqop;
10005  Oid ppeqop;
10006  Oid ffeqop;
10007  int16 eqstrategy;
10008  Oid pfeqop_right;
10009 
10010  /* We need several fields out of the pg_opclass entry */
10011  cla_ht = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclasses[i]));
10012  if (!HeapTupleIsValid(cla_ht))
10013  elog(ERROR, "cache lookup failed for opclass %u", opclasses[i]);
10014  cla_tup = (Form_pg_opclass) GETSTRUCT(cla_ht);
10015  amid = cla_tup->opcmethod;
10016  opfamily = cla_tup->opcfamily;
10017  opcintype = cla_tup->opcintype;
10018  ReleaseSysCache(cla_ht);
10019 
10020  /*
10021  * Check it's a btree; currently this can never fail since no other
10022  * index AMs support unique indexes. If we ever did have other types
10023  * of unique indexes, we'd need a way to determine which operator
10024  * strategy number is equality. (Is it reasonable to insist that
10025  * every such index AM use btree's number for equality?)
10026  */
10027  if (amid != BTREE_AM_OID)
10028  elog(ERROR, "only b-tree indexes are supported for foreign keys");
10029  eqstrategy = BTEqualStrategyNumber;
10030 
10031  /*
10032  * There had better be a primary equality operator for the index.
10033  * We'll use it for PK = PK comparisons.
10034  */
10035  ppeqop = get_opfamily_member(opfamily, opcintype, opcintype,
10036  eqstrategy);
10037 
10038  if (!OidIsValid(ppeqop))
10039  elog(ERROR, "missing operator %d(%u,%u) in opfamily %u",
10040  eqstrategy, opcintype, opcintype, opfamily);
10041 
10042  /*
10043  * Are there equality operators that take exactly the FK type? Assume
10044  * we should look through any domain here.
10045  */
10046  fktyped = getBaseType(fktype);
10047 
10048  pfeqop = get_opfamily_member(opfamily, opcintype, fktyped,
10049  eqstrategy);
10050  if (OidIsValid(pfeqop))
10051  {
10052  pfeqop_right = fktyped;
10053  ffeqop = get_opfamily_member(opfamily, fktyped, fktyped,
10054  eqstrategy);
10055  }
10056  else
10057  {
10058  /* keep compiler quiet */
10059  pfeqop_right = InvalidOid;
10060  ffeqop = InvalidOid;
10061  }
10062 
10063  if (!(OidIsValid(pfeqop) && OidIsValid(ffeqop)))
10064  {
10065  /*
10066  * Otherwise, look for an implicit cast from the FK type to the
10067  * opcintype, and if found, use the primary equality operator.
10068  * This is a bit tricky because opcintype might be a polymorphic
10069  * type such as ANYARRAY or ANYENUM; so what we have to test is
10070  * whether the two actual column types can be concurrently cast to
10071  * that type. (Otherwise, we'd fail to reject combinations such
10072  * as int[] and point[].)
10073  */
10074  Oid input_typeids[2];
10075  Oid target_typeids[2];
10076 
10077  input_typeids[0] = pktype;
10078  input_typeids[1] = fktype;
10079  target_typeids[0] = opcintype;
10080  target_typeids[1] = opcintype;
10081  if (can_coerce_type(2, input_typeids, target_typeids,
10083  {
10084  pfeqop = ffeqop = ppeqop;
10085  pfeqop_right = opcintype;
10086  }
10087  }
10088 
10089  if (!(OidIsValid(pfeqop) && OidIsValid(ffeqop)))
10090  ereport(ERROR,
10091  (errcode(ERRCODE_DATATYPE_MISMATCH),
10092  errmsg("foreign key constraint \"%s\" cannot be implemented",
10093  fkconstraint->conname),
10094  errdetail("Key columns \"%s\" and \"%s\" "
10095  "are of incompatible types: %s and %s.",
10096  strVal(list_nth(fkconstraint->fk_attrs, i)),
10097  strVal(list_nth(fkconstraint->pk_attrs, i)),
10098  format_type_be(fktype),
10099  format_type_be(pktype))));
10100 
10101  if (old_check_ok)
10102  {
10103  /*
10104  * When a pfeqop changes, revalidate the constraint. We could
10105  * permit intra-opfamily changes, but that adds subtle complexity
10106  * without any concrete benefit for core types. We need not
10107  * assess ppeqop or ffeqop, which RI_Initial_Check() does not use.
10108  */
10109  old_check_ok = (pfeqop == lfirst_oid(old_pfeqop_item));
10110  old_pfeqop_item = lnext(fkconstraint->old_conpfeqop,
10111  old_pfeqop_item);
10112  }
10113  if (old_check_ok)
10114  {
10115  Oid old_fktype;
10116  Oid new_fktype;
10117  CoercionPathType old_pathtype;
10118  CoercionPathType new_pathtype;
10119  Oid old_castfunc;
10120  Oid new_castfunc;
10122  fkattnum[i] - 1);
10123 
10124  /*
10125  * Identify coercion pathways from each of the old and new FK-side
10126  * column types to the right (foreign) operand type of the pfeqop.
10127  * We may assume that pg_constraint.conkey is not changing.
10128  */
10129  old_fktype = attr->atttypid;
10130  new_fktype = fktype;
10131  old_pathtype = findFkeyCast(pfeqop_right, old_fktype,
10132  &old_castfunc);
10133  new_pathtype = findFkeyCast(pfeqop_right, new_fktype,
10134  &new_castfunc);
10135 
10136  /*
10137  * Upon a change to the cast from the FK column to its pfeqop
10138  * operand, revalidate the constraint. For this evaluation, a
10139  * binary coercion cast is equivalent to no cast at all. While
10140  * type implementors should design implicit casts with an eye
10141  * toward consistency of operations like equality, we cannot
10142  * assume here that they have done so.
10143  *
10144  * A function with a polymorphic argument could change behavior
10145  * arbitrarily in response to get_fn_expr_argtype(). Therefore,
10146  * when the cast destination is polymorphic, we only avoid
10147  * revalidation if the input type has not changed at all. Given
10148  * just the core data types and operator classes, this requirement
10149  * prevents no would-be optimizations.
10150  *
10151  * If the cast converts from a base type to a domain thereon, then
10152  * that domain type must be the opcintype of the unique index.
10153  * Necessarily, the primary key column must then be of the domain
10154  * type. Since the constraint was previously valid, all values on
10155  * the foreign side necessarily exist on the primary side and in
10156  * turn conform to the domain. Consequently, we need not treat
10157  * domains specially here.
10158  *
10159  * Since we require that all collations share the same notion of
10160  * equality (which they do, because texteq reduces to bitwise
10161  * equality), we don't compare collation here.
10162  *
10163  * We need not directly consider the PK type. It's necessarily
10164  * binary coercible to the opcintype of the unique index column,
10165  * and ri_triggers.c will only deal with PK datums in terms of
10166  * that opcintype. Changing the opcintype also changes pfeqop.
10167  */
10168  old_check_ok = (new_pathtype == old_pathtype &&
10169  new_castfunc == old_castfunc &&
10170  (!IsPolymorphicType(pfeqop_right) ||
10171  new_fktype == old_fktype));
10172  }
10173 
10174  pfeqoperators[i] = pfeqop;
10175  ppeqoperators[i] = ppeqop;
10176  ffeqoperators[i] = ffeqop;
10177  }
10178 
10179  /*
10180  * Create all the constraint and trigger objects, recursing to partitions
10181  * as necessary. First handle the referenced side.
10182  */
10183  address = addFkRecurseReferenced(wqueue, fkconstraint, rel, pkrel,
10184  indexOid,
10185  InvalidOid, /* no parent constraint */
10186  numfks,
10187  pkattnum,
10188  fkattnum,
10189  pfeqoperators,
10190  ppeqoperators,
10191  ffeqoperators,
10192  numfkdelsetcols,
10193  fkdelsetcols,
10194  old_check_ok,
10196 
10197  /* Now handle the referencing side. */
10198  addFkRecurseReferencing(wqueue, fkconstraint, rel, pkrel,
10199  indexOid,
10200  address.objectId,
10201  numfks,
10202  pkattnum,
10203  fkattnum,
10204  pfeqoperators,
10205  ppeqoperators,
10206  ffeqoperators,
10207  numfkdelsetcols,
10208  fkdelsetcols,
10209  old_check_ok,
10210  lockmode,
10212 
10213  /*
10214  * Done. Close pk table, but keep lock until we've committed.
10215  */
10216  table_close(pkrel, NoLock);
10217 
10218  return address;
10219 }
10220 
10221 /*
10222  * validateFkOnDeleteSetColumns
10223  * Verifies that columns used in ON DELETE SET NULL/DEFAULT (...)
10224  * column lists are valid.
10225  */
10226 void
10227 validateFkOnDeleteSetColumns(int numfks, const int16 *fkattnums,
10228  int numfksetcols, const int16 *fksetcolsattnums,
10229  List *fksetcols)
10230 {
10231  for (int i = 0; i < numfksetcols; i++)
10232  {
10233  int16 setcol_attnum = fksetcolsattnums[i];
10234  bool seen = false;
10235 
10236  for (int j = 0; j < numfks; j++)
10237  {
10238  if (fkattnums[j] == setcol_attnum)
10239  {
10240  seen = true;
10241  break;
10242  }
10243  }
10244 
10245  if (!seen)
10246  {
10247  char *col = strVal(list_nth(fksetcols, i));
10248 
10249  ereport(ERROR,
10250  (errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
10251  errmsg("column \"%s\" referenced in ON DELETE SET action must be part of foreign key", col)));
10252  }
10253  }
10254 }
10255 
10256 /*
10257  * addFkRecurseReferenced
10258  * subroutine for ATAddForeignKeyConstraint; recurses on the referenced
10259  * side of the constraint
10260  *
10261  * Create pg_constraint rows for the referenced side of the constraint,
10262  * referencing the parent of the referencing side; also create action triggers
10263  * on leaf partitions. If the table is partitioned, recurse to handle each
10264  * partition.
10265  *
10266  * wqueue is the ALTER TABLE work queue; can be NULL when not running as part
10267  * of an ALTER TABLE sequence.
10268  * fkconstraint is the constraint being added.
10269  * rel is the root referencing relation.
10270  * pkrel is the referenced relation; might be a partition, if recursing.
10271  * indexOid is the OID of the index (on pkrel) implementing this constraint.
10272  * parentConstr is the OID of a parent constraint; InvalidOid if this is a
10273  * top-level constraint.
10274  * numfks is the number of columns in the foreign key
10275  * pkattnum is the attnum array of referenced attributes.
10276  * fkattnum is the attnum array of referencing attributes.
10277  * numfkdelsetcols is the number of columns in the ON DELETE SET NULL/DEFAULT
10278  * (...) clause
10279  * fkdelsetcols is the attnum array of the columns in the ON DELETE SET
10280  * NULL/DEFAULT clause
10281  * pf/pp/ffeqoperators are OID array of operators between columns.
10282  * old_check_ok signals that this constraint replaces an existing one that
10283  * was already validated (thus this one doesn't need validation).
10284  * parentDelTrigger and parentUpdTrigger, when being recursively called on
10285  * a partition, are the OIDs of the parent action triggers for DELETE and
10286  * UPDATE respectively.
10287  */
10288 static ObjectAddress
10289 addFkRecurseReferenced(List **wqueue, Constraint *fkconstraint, Relation rel,
10290  Relation pkrel, Oid indexOid, Oid parentConstr,
10291  int numfks,
10292  int16 *pkattnum, int16 *fkattnum, Oid *pfeqoperators,
10293  Oid *ppeqoperators, Oid *ffeqoperators,
10294  int numfkdelsetcols, int16 *fkdelsetcols,
10295  bool old_check_ok,
10296  Oid parentDelTrigger, Oid parentUpdTrigger)
10297 {
10298  ObjectAddress address;
10299  Oid constrOid;
10300  char *conname;
10301  bool conislocal;
10302  int coninhcount;
10303  bool connoinherit;
10304  Oid deleteTriggerOid,
10305  updateTriggerOid;
10306 
10307  /*
10308  * Verify relkind for each referenced partition. At the top level, this
10309  * is redundant with a previous check, but we need it when recursing.
10310  */
10311  if (pkrel->rd_rel->relkind != RELKIND_RELATION &&
10312  pkrel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
10313  ereport(ERROR,
10314  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
10315  errmsg("referenced relation \"%s\" is not a table",
10316  RelationGetRelationName(pkrel))));
10317 
10318  /*
10319  * Caller supplies us with a constraint name; however, it may be used in
10320  * this partition, so come up with a different one in that case.
10321  */
10323  RelationGetRelid(rel),
10324  fkconstraint->conname))
10327  "fkey",
10328  RelationGetNamespace(rel), NIL);
10329  else
10330  conname = fkconstraint->conname;
10331 
10332  if (OidIsValid(parentConstr))
10333  {
10334  conislocal = false;
10335  coninhcount = 1;
10336  connoinherit = false;
10337  }
10338  else
10339  {
10340  conislocal = true;
10341  coninhcount = 0;
10342 
10343  /*
10344  * always inherit for partitioned tables, never for legacy inheritance
10345  */
10346  connoinherit = rel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE;
10347  }
10348 
10349  /*
10350  * Record the FK constraint in pg_constraint.
10351  */
10352  constrOid = CreateConstraintEntry(conname,
10353  RelationGetNamespace(rel),
10354  CONSTRAINT_FOREIGN,
10355  fkconstraint->deferrable,
10356  fkconstraint->initdeferred,
10357  fkconstraint->initially_valid,
10358  parentConstr,
10359  RelationGetRelid(rel),
10360  fkattnum,
10361  numfks,
10362  numfks,
10363  InvalidOid, /* not a domain constraint */
10364  indexOid,
10365  RelationGetRelid(pkrel),
10366  pkattnum,
10367  pfeqoperators,
10368  ppeqoperators,
10369  ffeqoperators,
10370  numfks,
10371  fkconstraint->fk_upd_action,
10372  fkconstraint->fk_del_action,
10373  fkdelsetcols,
10374  numfkdelsetcols,
10375  fkconstraint->fk_matchtype,
10376  NULL, /* no exclusion constraint */
10377  NULL, /* no check constraint */
10378  NULL,
10379  conislocal, /* islocal */
10380  coninhcount, /* inhcount */
10381  connoinherit, /* conNoInherit */
10382  false, /* conPeriod */
10383  false); /* is_internal */
10384 
10385  ObjectAddressSet(address, ConstraintRelationId, constrOid);
10386 
10387  /*
10388  * Mark the child constraint as part of the parent constraint; it must not
10389  * be dropped on its own. (This constraint is deleted when the partition
10390  * is detached, but a special check needs to occur that the partition
10391  * contains no referenced values.)
10392  */
10393  if (OidIsValid(parentConstr))
10394  {
10395  ObjectAddress referenced;
10396 
10397  ObjectAddressSet(referenced, ConstraintRelationId, parentConstr);
10398  recordDependencyOn(&address, &referenced, DEPENDENCY_INTERNAL);
10399  }
10400 
10401  /* make new constraint visible, in case we add more */
10403 
10404  /*
10405  * Create the action triggers that enforce the constraint.
10406  */
10408  fkconstraint,
10409  constrOid, indexOid,
10410  parentDelTrigger, parentUpdTrigger,
10411  &deleteTriggerOid, &updateTriggerOid);
10412 
10413  /*
10414  * If the referenced table is partitioned, recurse on ourselves to handle
10415  * each partition. We need one pg_constraint row created for each
10416  * partition in addition to the pg_constraint row for the parent table.
10417  */
10418  if (pkrel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
10419  {
10420  PartitionDesc pd = RelationGetPartitionDesc(pkrel, true);
10421 
10422  for (int i = 0; i < pd->nparts; i++)
10423  {
10424  Relation partRel;
10425  AttrMap *map;
10426  AttrNumber *mapped_pkattnum;
10427  Oid partIndexId;
10428 
10429  partRel = table_open(pd->oids[i], ShareRowExclusiveLock);
10430 
10431  /*
10432  * Map the attribute numbers in the referenced side of the FK
10433  * definition to match the partition's column layout.
10434  */
10436  RelationGetDescr(pkrel),
10437  false);
10438  if (map)
10439  {
10440  mapped_pkattnum = palloc(sizeof(AttrNumber) * numfks);
10441  for (int j = 0; j < numfks; j++)
10442  mapped_pkattnum[j] = map->attnums[pkattnum[j] - 1];
10443  }
10444  else
10445  mapped_pkattnum = pkattnum;
10446 
10447  /* do the deed */
10448  partIndexId = index_get_partition(partRel, indexOid);
10449  if (!OidIsValid(partIndexId))
10450  elog(ERROR, "index for %u not found in partition %s",
10451  indexOid, RelationGetRelationName(partRel));
10452  addFkRecurseReferenced(wqueue, fkconstraint, rel, partRel,
10453  partIndexId, constrOid, numfks,
10454  mapped_pkattnum, fkattnum,
10455  pfeqoperators, ppeqoperators, ffeqoperators,
10456  numfkdelsetcols, fkdelsetcols,
10457  old_check_ok,
10458  deleteTriggerOid, updateTriggerOid);
10459 
10460  /* Done -- clean up (but keep the lock) */
10461  table_close(partRel, NoLock);
10462  if (map)
10463  {
10464  pfree(mapped_pkattnum);
10465  free_attrmap(map);
10466  }
10467  }
10468  }
10469 
10470  return address;
10471 }
10472 
10473 /*
10474  * addFkRecurseReferencing
10475  * subroutine for ATAddForeignKeyConstraint and CloneFkReferencing
10476  *
10477  * If the referencing relation is a plain relation, create the necessary check
10478  * triggers that implement the constraint, and set up for Phase 3 constraint
10479  * verification. If the referencing relation is a partitioned table, then
10480  * we create a pg_constraint row for it and recurse on this routine for each
10481  * partition.
10482  *
10483  * We assume that the referenced relation is locked against concurrent
10484  * deletions. If it's a partitioned relation, every partition must be so
10485  * locked.
10486  *
10487  * wqueue is the ALTER TABLE work queue; can be NULL when not running as part
10488  * of an ALTER TABLE sequence.
10489  * fkconstraint is the constraint being added.
10490  * rel is the referencing relation; might be a partition, if recursing.
10491  * pkrel is the root referenced relation.
10492  * indexOid is the OID of the index (on pkrel) implementing this constraint.
10493  * parentConstr is the OID of the parent constraint (there is always one).
10494  * numfks is the number of columns in the foreign key
10495  * pkattnum is the attnum array of referenced attributes.
10496  * fkattnum is the attnum array of referencing attributes.
10497  * pf/pp/ffeqoperators are OID array of operators between columns.
10498  * numfkdelsetcols is the number of columns in the ON DELETE SET NULL/DEFAULT
10499  * (...) clause
10500  * fkdelsetcols is the attnum array of the columns in the ON DELETE SET
10501  * NULL/DEFAULT clause
10502  * old_check_ok signals that this constraint replaces an existing one that
10503  * was already validated (thus this one doesn't need validation).
10504  * lockmode is the lockmode to acquire on partitions when recursing.
10505  * parentInsTrigger and parentUpdTrigger, when being recursively called on
10506  * a partition, are the OIDs of the parent check triggers for INSERT and
10507  * UPDATE respectively.
10508  */
10509 static void
10510 addFkRecurseReferencing(List **wqueue, Constraint *fkconstraint, Relation rel,
10511  Relation pkrel, Oid indexOid, Oid parentConstr,
10512  int numfks, int16 *pkattnum, int16 *fkattnum,
10513  Oid *pfeqoperators, Oid *ppeqoperators, Oid *ffeqoperators,
10514  int numfkdelsetcols, int16 *fkdelsetcols,
10515  bool old_check_ok, LOCKMODE lockmode,
10516  Oid parentInsTrigger, Oid parentUpdTrigger)
10517 {
10518  Oid insertTriggerOid,
10519  updateTriggerOid;
10520 
10521  Assert(OidIsValid(parentConstr));
10522 
10523  if (rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
10524  ereport(ERROR,
10525  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
10526  errmsg("foreign key constraints are not supported on foreign tables")));
10527 
10528  /*
10529  * Add the check triggers to it and, if necessary, schedule it to be
10530  * checked in Phase 3.
10531  *
10532  * If the relation is partitioned, drill down to do it to its partitions.
10533  */
10535  RelationGetRelid(pkrel),
10536  fkconstraint,
10537  parentConstr,
10538  indexOid,
10539  parentInsTrigger, parentUpdTrigger,
10540  &insertTriggerOid, &updateTriggerOid);
10541 
10542  if (rel->rd_rel->relkind == RELKIND_RELATION)
10543  {
10544  /*
10545  * Tell Phase 3 to check that the constraint is satisfied by existing
10546  * rows. We can skip this during table creation, when requested
10547  * explicitly by specifying NOT VALID in an ADD FOREIGN KEY command,
10548  * and when we're recreating a constraint following a SET DATA TYPE
10549  * operation that did not impugn its validity.
10550  */
10551  if (wqueue && !old_check_ok && !fkconstraint->skip_validation)
10552  {
10553  NewConstraint *newcon;
10554  AlteredTableInfo *tab;
10555 
10556  tab = ATGetQueueEntry(wqueue, rel);
10557 
10558  newcon = (NewConstraint *) palloc0(sizeof(NewConstraint));
10559  newcon->name = get_constraint_name(parentConstr);
10560  newcon->contype = CONSTR_FOREIGN;
10561  newcon->refrelid = RelationGetRelid(pkrel);
10562  newcon->refindid = indexOid;
10563  newcon->conid = parentConstr;
10564  newcon->qual = (Node *) fkconstraint;
10565 
10566  tab->constraints = lappend(tab->constraints, newcon);
10567  }
10568  }
10569  else if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
10570  {
10571  PartitionDesc pd = RelationGetPartitionDesc(rel, true);
10572  Relation trigrel;
10573 
10574  /*
10575  * Triggers of the foreign keys will be manipulated a bunch of times
10576  * in the loop below. To avoid repeatedly opening/closing the trigger
10577  * catalog relation, we open it here and pass it to the subroutines
10578  * called below.
10579  */
10580  trigrel = table_open(TriggerRelationId, RowExclusiveLock);
10581 
10582  /*
10583  * Recurse to take appropriate action on each partition; either we
10584  * find an existing constraint to reparent to ours, or we create a new
10585  * one.
10586  */
10587  for (int i = 0; i < pd->nparts; i++)
10588  {
10589  Oid partitionId = pd->oids[i];
10590  Relation partition = table_open(partitionId, lockmode);
10591  List *partFKs;
10592  AttrMap *attmap;
10593  AttrNumber mapped_fkattnum[INDEX_MAX_KEYS];
10594  bool attached;
10595  char *conname;
10596  Oid constrOid;
10597  ObjectAddress address,
10598  referenced;
10599  ListCell *cell;
10600 
10601  CheckTableNotInUse(partition, "ALTER TABLE");
10602 
10603  attmap = build_attrmap_by_name(RelationGetDescr(partition),
10604  RelationGetDescr(rel),
10605  false);
10606  for (int j = 0; j < numfks; j++)
10607  mapped_fkattnum[j] = attmap->attnums[fkattnum[j] - 1];
10608 
10609  /* Check whether an existing constraint can be repurposed */
10610  partFKs = copyObject(RelationGetFKeyList(partition));
10611  attached = false;
10612  foreach(cell, partFKs)
10613  {
10614  ForeignKeyCacheInfo *fk;
10615 
10616  fk = lfirst_node(ForeignKeyCacheInfo, cell);
10618  partitionId,
10619  parentConstr,
10620  numfks,
10621  mapped_fkattnum,
10622  pkattnum,
10623  pfeqoperators,
10624  insertTriggerOid,
10625  updateTriggerOid,
10626  trigrel))
10627  {
10628  attached = true;
10629  break;
10630  }
10631  }
10632  if (attached)
10633  {
10634  table_close(partition, NoLock);
10635  continue;
10636  }
10637 
10638  /*
10639  * No luck finding a good constraint to reuse; create our own.
10640  */
10642  RelationGetRelid(partition),
10643  fkconstraint->conname))
10644  conname = ChooseConstraintName(RelationGetRelationName(partition),
10646  "fkey",
10647  RelationGetNamespace(partition), NIL);
10648  else
10649  conname = fkconstraint->conname;
10650  constrOid =
10651  CreateConstraintEntry(conname,
10652  RelationGetNamespace(partition),
10653  CONSTRAINT_FOREIGN,
10654  fkconstraint->deferrable,
10655  fkconstraint->initdeferred,
10656  fkconstraint->initially_valid,
10657  parentConstr,
10658  partitionId,
10659  mapped_fkattnum,
10660  numfks,
10661  numfks,
10662  InvalidOid,
10663  indexOid,
10664  RelationGetRelid(pkrel),
10665  pkattnum,
10666  pfeqoperators,
10667  ppeqoperators,
10668  ffeqoperators,
10669  numfks,
10670  fkconstraint->fk_upd_action,
10671  fkconstraint->fk_del_action,
10672  fkdelsetcols,
10673  numfkdelsetcols,
10674  fkconstraint->fk_matchtype,
10675  NULL,
10676  NULL,
10677  NULL,
10678  false,
10679  1,
10680  false,
10681  false, /* conPeriod */
10682  false);
10683 
10684  /*
10685  * Give this constraint partition-type dependencies on the parent
10686  * constraint as well as the table.
10687  */
10688  ObjectAddressSet(address, ConstraintRelationId, constrOid);
10689  ObjectAddressSet(referenced, ConstraintRelationId, parentConstr);
10690  recordDependencyOn(&address, &referenced, DEPENDENCY_PARTITION_PRI);
10691  ObjectAddressSet(referenced, RelationRelationId, partitionId);
10692  recordDependencyOn(&address, &referenced, DEPENDENCY_PARTITION_SEC);
10693 
10694  /* Make all this visible before recursing */
10696 
10697  /* call ourselves to finalize the creation and we're done */
10698  addFkRecurseReferencing(wqueue, fkconstraint, partition, pkrel,
10699  indexOid,
10700  constrOid,
10701  numfks,
10702  pkattnum,
10703  mapped_fkattnum,
10704  pfeqoperators,
10705  ppeqoperators,
10706  ffeqoperators,
10707  numfkdelsetcols,
10708  fkdelsetcols,
10709  old_check_ok,
10710  lockmode,
10711  insertTriggerOid,
10712  updateTriggerOid);
10713 
10714  table_close(partition, NoLock);
10715  }
10716 
10717  table_close(trigrel, RowExclusiveLock);
10718  }
10719 }
10720 
10721 /*
10722  * CloneForeignKeyConstraints
10723  * Clone foreign keys from a partitioned table to a newly acquired
10724  * partition.
10725  *
10726  * partitionRel is a partition of parentRel, so we can be certain that it has
10727  * the same columns with the same datatypes. The columns may be in different
10728  * order, though.
10729  *
10730  * wqueue must be passed to set up phase 3 constraint checking, unless the
10731  * referencing-side partition is known to be empty (such as in CREATE TABLE /
10732  * PARTITION OF).
10733  */
10734 static void
10736  Relation partitionRel)
10737 {
10738  /* This only works for declarative partitioning */
10739  Assert(parentRel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
10740 
10741  /*
10742  * Clone constraints for which the parent is on the referenced side.
10743  */
10744  CloneFkReferenced(parentRel, partitionRel);
10745 
10746  /*
10747  * Now clone constraints where the parent is on the referencing side.
10748  */
10749  CloneFkReferencing(wqueue, parentRel, partitionRel);
10750 }
10751 
10752 /*
10753  * CloneFkReferenced
10754  * Subroutine for CloneForeignKeyConstraints
10755  *
10756  * Find all the FKs that have the parent relation on the referenced side;
10757  * clone those constraints to the given partition. This is to be called
10758  * when the partition is being created or attached.
10759  *
10760  * This ignores self-referencing FKs; those are handled by CloneFkReferencing.
10761  *
10762  * This recurses to partitions, if the relation being attached is partitioned.
10763  * Recursion is done by calling addFkRecurseReferenced.
10764  */
10765 static void
10766 CloneFkReferenced(Relation parentRel, Relation partitionRel)
10767 {
10768  Relation pg_constraint;
10769  AttrMap *attmap;
10770  ListCell *cell;
10771  SysScanDesc scan;
10772  ScanKeyData key[2];
10773  HeapTuple tuple;
10774  List *clone = NIL;
10775  Relation trigrel;
10776 
10777  /*
10778  * Search for any constraints where this partition's parent is in the
10779  * referenced side. However, we must not clone any constraint whose
10780  * parent constraint is also going to be cloned, to avoid duplicates. So
10781  * do it in two steps: first construct the list of constraints to clone,
10782  * then go over that list cloning those whose parents are not in the list.
10783  * (We must not rely on the parent being seen first, since the catalog
10784  * scan could return children first.)
10785  */
10786  pg_constraint = table_open(ConstraintRelationId, RowShareLock);
10787  ScanKeyInit(&key[0],
10788  Anum_pg_constraint_confrelid, BTEqualStrategyNumber,
10789  F_OIDEQ, ObjectIdGetDatum(RelationGetRelid(parentRel)));
10790  ScanKeyInit(&key[1],
10791  Anum_pg_constraint_contype, BTEqualStrategyNumber,
10792  F_CHAREQ, CharGetDatum(CONSTRAINT_FOREIGN));
10793  /* This is a seqscan, as we don't have a usable index ... */
10794  scan = systable_beginscan(pg_constraint, InvalidOid, true,
10795  NULL, 2, key);
10796  while ((tuple = systable_getnext(scan)) != NULL)
10797  {
10798  Form_pg_constraint constrForm = (Form_pg_constraint) GETSTRUCT(tuple);
10799 
10800  clone = lappend_oid(clone, constrForm->oid);
10801  }
10802  systable_endscan(scan);
10803  table_close(pg_constraint, RowShareLock);
10804 
10805  /*
10806  * Triggers of the foreign keys will be manipulated a bunch of times in
10807  * the loop below. To avoid repeatedly opening/closing the trigger
10808  * catalog relation, we open it here and pass it to the subroutines called
10809  * below.
10810  */
10811  trigrel = table_open(TriggerRelationId, RowExclusiveLock);
10812 
10813  attmap = build_attrmap_by_name(RelationGetDescr(partitionRel),
10814  RelationGetDescr(parentRel),
10815  false);
10816  foreach(cell, clone)
10817  {
10818  Oid constrOid = lfirst_oid(cell);
10819  Form_pg_constraint constrForm;
10820  Relation fkRel;
10821  Oid indexOid;
10822  Oid partIndexId;
10823  int numfks;
10824  AttrNumber conkey[INDEX_MAX_KEYS];
10825  AttrNumber mapped_confkey[INDEX_MAX_KEYS];
10826  AttrNumber confkey[INDEX_MAX_KEYS];
10827  Oid conpfeqop[INDEX_MAX_KEYS];
10828  Oid conppeqop[INDEX_MAX_KEYS];
10829  Oid conffeqop[INDEX_MAX_KEYS];
10830  int numfkdelsetcols;
10831  AttrNumber confdelsetcols[INDEX_MAX_KEYS];
10832  Constraint *fkconstraint;
10833  Oid deleteTriggerOid,
10834  updateTriggerOid;
10835 
10836  tuple = SearchSysCache1(CONSTROID, ObjectIdGetDatum(constrOid));
10837  if (!HeapTupleIsValid(tuple))
10838  elog(ERROR, "cache lookup failed for constraint %u", constrOid);
10839  constrForm = (Form_pg_constraint) GETSTRUCT(tuple);
10840 
10841  /*
10842  * As explained above: don't try to clone a constraint for which we're
10843  * going to clone the parent.
10844  */
10845  if (list_member_oid(clone, constrForm->conparentid))
10846  {
10847  ReleaseSysCache(tuple);
10848  continue;
10849  }
10850 
10851  /*
10852  * Don't clone self-referencing foreign keys, which can be in the
10853  * partitioned table or in the partition-to-be.
10854  */
10855  if (constrForm->conrelid == RelationGetRelid(parentRel) ||
10856  constrForm->conrelid == RelationGetRelid(partitionRel))
10857  {
10858  ReleaseSysCache(tuple);
10859  continue;
10860  }
10861 
10862  /*
10863  * Because we're only expanding the key space at the referenced side,
10864  * we don't need to prevent any operation in the referencing table, so
10865  * AccessShareLock suffices (assumes that dropping the constraint
10866  * acquires AEL).
10867  */
10868  fkRel = table_open(constrForm->conrelid, AccessShareLock);
10869 
10870  indexOid = constrForm->conindid;
10872  &numfks,
10873  conkey,
10874  confkey,
10875  conpfeqop,
10876  conppeqop,
10877  conffeqop,
10878  &numfkdelsetcols,
10879  confdelsetcols);
10880 
10881  for (int i = 0; i < numfks; i++)
10882  mapped_confkey[i] = attmap->attnums[confkey[i] - 1];
10883 
10884  fkconstraint = makeNode(Constraint);
10885  fkconstraint->contype = CONSTRAINT_FOREIGN;
10886  fkconstraint->conname = NameStr(constrForm->conname);
10887  fkconstraint->deferrable = constrForm->condeferrable;
10888  fkconstraint->initdeferred = constrForm->condeferred;
10889  fkconstraint->location = -1;
10890  fkconstraint->pktable = NULL;
10891  /* ->fk_attrs determined below */
10892  fkconstraint->pk_attrs = NIL;
10893  fkconstraint->fk_matchtype = constrForm->confmatchtype;
10894  fkconstraint->fk_upd_action = constrForm->confupdtype;
10895  fkconstraint->fk_del_action = constrForm->confdeltype;
10896  fkconstraint->fk_del_set_cols = NIL;
10897  fkconstraint->old_conpfeqop = NIL;
10898  fkconstraint->old_pktable_oid = InvalidOid;
10899  fkconstraint->skip_validation = false;
10900  fkconstraint->initially_valid = true;
10901 
10902  /* set up colnames that are used to generate the constraint name */
10903  for (int i = 0; i < numfks; i++)
10904  {
10905  Form_pg_attribute att;
10906 
10907  att = TupleDescAttr(RelationGetDescr(fkRel),
10908  conkey[i] - 1);
10909  fkconstraint->fk_attrs = lappend(fkconstraint->fk_attrs,
10910  makeString(NameStr(att->attname)));
10911  }
10912 
10913  /*
10914  * Add the new foreign key constraint pointing to the new partition.
10915  * Because this new partition appears in the referenced side of the
10916  * constraint, we don't need to set up for Phase 3 check.
10917  */
10918  partIndexId = index_get_partition(partitionRel, indexOid);
10919  if (!OidIsValid(partIndexId))
10920  elog(ERROR, "index for %u not found in partition %s",
10921  indexOid, RelationGetRelationName(partitionRel));
10922 
10923  /*
10924  * Get the "action" triggers belonging to the constraint to pass as
10925  * parent OIDs for similar triggers that will be created on the
10926  * partition in addFkRecurseReferenced().
10927  */
10928  GetForeignKeyActionTriggers(trigrel, constrOid,
10929  constrForm->confrelid, constrForm->conrelid,
10930  &deleteTriggerOid, &updateTriggerOid);
10931 
10933  fkconstraint,
10934  fkRel,
10935  partitionRel,
10936  partIndexId,
10937  constrOid,
10938  numfks,
10939  mapped_confkey,
10940  conkey,
10941  conpfeqop,
10942  conppeqop,
10943  conffeqop,
10944  numfkdelsetcols,
10945  confdelsetcols,
10946  true,
10947  deleteTriggerOid,
10948  updateTriggerOid);
10949 
10950  table_close(fkRel, NoLock);
10951  ReleaseSysCache(tuple);
10952  }
10953 
10954  table_close(trigrel, RowExclusiveLock);
10955 }
10956 
10957 /*
10958  * CloneFkReferencing
10959  * Subroutine for CloneForeignKeyConstraints
10960  *
10961  * For each FK constraint of the parent relation in the given list, find an
10962  * equivalent constraint in its partition relation that can be reparented;
10963  * if one cannot be found, create a new constraint in the partition as its
10964  * child.
10965  *
10966  * If wqueue is given, it is used to set up phase-3 verification for each
10967  * cloned constraint; if omitted, we assume that such verification is not
10968  * needed (example: the partition is being created anew).
10969  */
10970 static void
10971 CloneFkReferencing(List **wqueue, Relation parentRel, Relation partRel)
10972 {
10973  AttrMap *attmap;
10974  List *partFKs;
10975  List *clone = NIL;
10976  ListCell *cell;
10977  Relation trigrel;
10978 
10979  /* obtain a list of constraints that we need to clone */
10980  foreach(cell, RelationGetFKeyList(parentRel))
10981  {
10982  ForeignKeyCacheInfo *fk = lfirst(cell);
10983 
10984  clone = lappend_oid(clone, fk->conoid);
10985  }
10986 
10987  /*
10988  * Silently do nothing if there's nothing to do. In particular, this
10989  * avoids throwing a spurious error for foreign tables.
10990  */
10991  if (clone == NIL)
10992  return;
10993 
10994  if (partRel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
10995  ereport(ERROR,
10996  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
10997  errmsg("foreign key constraints are not supported on foreign tables")));
10998 
10999  /*
11000  * Triggers of the foreign keys will be manipulated a bunch of times in
11001  * the loop below. To avoid repeatedly opening/closing the trigger
11002  * catalog relation, we open it here and pass it to the subroutines called
11003  * below.
11004  */
11005  trigrel = table_open(TriggerRelationId, RowExclusiveLock);
11006 
11007  /*
11008  * The constraint key may differ, if the columns in the partition are
11009  * different. This map is used to convert them.
11010  */
11011  attmap = build_attrmap_by_name(RelationGetDescr(partRel),
11012  RelationGetDescr(parentRel),
11013  false);
11014 
11015  partFKs = copyObject(RelationGetFKeyList(partRel));
11016 
11017  foreach(cell, clone)
11018  {
11019  Oid parentConstrOid = lfirst_oid(cell);
11020  Form_pg_constraint constrForm;
11021  Relation pkrel;
11022  HeapTuple tuple;
11023  int numfks;
11024  AttrNumber conkey[INDEX_MAX_KEYS];
11025  AttrNumber mapped_conkey[INDEX_MAX_KEYS];
11026  AttrNumber confkey[INDEX_MAX_KEYS];
11027  Oid conpfeqop[INDEX_MAX_KEYS];
11028  Oid conppeqop[INDEX_MAX_KEYS];
11029  Oid conffeqop[INDEX_MAX_KEYS];
11030  int numfkdelsetcols;
11031  AttrNumber confdelsetcols[INDEX_MAX_KEYS];
11032  Constraint *fkconstraint;
11033  bool attached;
11034  Oid indexOid;
11035  Oid constrOid;
11036  ObjectAddress address,
11037  referenced;
11038  ListCell *lc;
11039  Oid insertTriggerOid,
11040  updateTriggerOid;
11041 
11042  tuple = SearchSysCache1(CONSTROID, ObjectIdGetDatum(parentConstrOid));
11043  if (!HeapTupleIsValid(tuple))
11044  elog(ERROR, "cache lookup failed for constraint %u",
11045  parentConstrOid);
11046  constrForm = (Form_pg_constraint) GETSTRUCT(tuple);
11047 
11048  /* Don't clone constraints whose parents are being cloned */
11049  if (list_member_oid(clone, constrForm->conparentid))
11050  {
11051  ReleaseSysCache(tuple);
11052  continue;
11053  }
11054 
11055  /*
11056  * Need to prevent concurrent deletions. If pkrel is a partitioned
11057  * relation, that means to lock all partitions.
11058  */
11059  pkrel = table_open(constrForm->confrelid, ShareRowExclusiveLock);
11060  if (pkrel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
11061  (void) find_all_inheritors(RelationGetRelid(pkrel),
11062  ShareRowExclusiveLock, NULL);
11063 
11064  DeconstructFkConstraintRow(tuple, &numfks, conkey, confkey,
11065  conpfeqop, conppeqop, conffeqop,
11066  &numfkdelsetcols, confdelsetcols);
11067  for (int i = 0; i < numfks; i++)
11068  mapped_conkey[i] = attmap->attnums[conkey[i] - 1];
11069 
11070  /*
11071  * Get the "check" triggers belonging to the constraint to pass as
11072  * parent OIDs for similar triggers that will be created on the
11073  * partition in addFkRecurseReferencing(). They are also passed to
11074  * tryAttachPartitionForeignKey() below to simply assign as parents to
11075  * the partition's existing "check" triggers, that is, if the
11076  * corresponding constraints is deemed attachable to the parent
11077  * constraint.
11078  */
11079  GetForeignKeyCheckTriggers(trigrel, constrForm->oid,
11080  constrForm->confrelid, constrForm->conrelid,
11081  &insertTriggerOid, &updateTriggerOid);
11082 
11083  /*
11084  * Before creating a new constraint, see whether any existing FKs are
11085  * fit for the purpose. If one is, attach the parent constraint to
11086  * it, and don't clone anything. This way we avoid the expensive
11087  * verification step and don't end up with a duplicate FK, and we
11088  * don't need to recurse to partitions for this constraint.
11089  */
11090  attached = false;
11091  foreach(lc, partFKs)
11092  {
11094 
11096  RelationGetRelid(partRel),
11097  parentConstrOid,
11098  numfks,
11099  mapped_conkey,
11100  confkey,
11101  conpfeqop,
11102  insertTriggerOid,
11103  updateTriggerOid,
11104  trigrel))
11105  {
11106  attached = true;
11107  table_close(pkrel, NoLock);
11108  break;
11109  }
11110  }
11111  if (attached)
11112  {
11113  ReleaseSysCache(tuple);
11114  continue;
11115  }
11116 
11117  /* No dice. Set up to create our own constraint */
11118  fkconstraint = makeNode(Constraint);
11119  fkconstraint->contype = CONSTRAINT_FOREIGN;
11120  /* ->conname determined below */
11121  fkconstraint->deferrable = constrForm->condeferrable;
11122  fkconstraint->initdeferred = constrForm->condeferred;
11123  fkconstraint->location = -1;
11124  fkconstraint->pktable = NULL;
11125  /* ->fk_attrs determined below */
11126  fkconstraint->pk_attrs = NIL;
11127  fkconstraint->fk_matchtype = constrForm->confmatchtype;
11128  fkconstraint->fk_upd_action = constrForm->confupdtype;
11129  fkconstraint->fk_del_action = constrForm->confdeltype;
11130  fkconstraint->fk_del_set_cols = NIL;
11131  fkconstraint->old_conpfeqop = NIL;
11132  fkconstraint->old_pktable_oid = InvalidOid;
11133  fkconstraint->skip_validation = false;
11134  fkconstraint->initially_valid = true;
11135  for (int i = 0; i < numfks; i++)
11136  {
11137  Form_pg_attribute att;
11138 
11139  att = TupleDescAttr(RelationGetDescr(partRel),
11140  mapped_conkey[i] - 1);
11141  fkconstraint->fk_attrs = lappend(fkconstraint->fk_attrs,
11142  makeString(NameStr(att->attname)));
11143  }
11145  RelationGetRelid(partRel),
11146  NameStr(constrForm->conname)))
11147  fkconstraint->conname =
11150  "fkey",
11151  RelationGetNamespace(partRel), NIL);
11152  else
11153  fkconstraint->conname = pstrdup(NameStr(constrForm->conname));
11154 
11155  indexOid = constrForm->conindid;
11156  constrOid =
11157  CreateConstraintEntry(fkconstraint->conname,
11158  constrForm->connamespace,
11159  CONSTRAINT_FOREIGN,
11160  fkconstraint->deferrable,
11161  fkconstraint->initdeferred,
11162  constrForm->convalidated,
11163  parentConstrOid,
11164  RelationGetRelid(partRel),
11165  mapped_conkey,
11166  numfks,
11167  numfks,
11168  InvalidOid, /* not a domain constraint */
11169  indexOid,
11170  constrForm->confrelid, /* same foreign rel */
11171  confkey,
11172  conpfeqop,
11173  conppeqop,
11174  conffeqop,
11175  numfks,
11176  fkconstraint->fk_upd_action,
11177  fkconstraint->fk_del_action,
11178  confdelsetcols,
11179  numfkdelsetcols,
11180  fkconstraint->fk_matchtype,
11181  NULL,
11182  NULL,
11183  NULL,
11184  false, /* islocal */
11185  1, /* inhcount */
11186  false, /* conNoInherit */
11187  false, /* conPeriod */
11188  true);
11189 
11190  /* Set up partition dependencies for the new constraint */
11191  ObjectAddressSet(address, ConstraintRelationId, constrOid);
11192  ObjectAddressSet(referenced, ConstraintRelationId, parentConstrOid);
11193  recordDependencyOn(&address, &referenced, DEPENDENCY_PARTITION_PRI);
11194  ObjectAddressSet(referenced, RelationRelationId,
11195  RelationGetRelid(partRel));
11196  recordDependencyOn(&address, &referenced, DEPENDENCY_PARTITION_SEC);
11197 
11198  /* Done with the cloned constraint's tuple */
11199  ReleaseSysCache(tuple);
11200 
11201  /* Make all this visible before recursing */
11203 
11204  addFkRecurseReferencing(wqueue,
11205  fkconstraint,
11206  partRel,
11207  pkrel,
11208  indexOid,
11209  constrOid,
11210  numfks,
11211  confkey,
11212  mapped_conkey,
11213  conpfeqop,
11214  conppeqop,
11215  conffeqop,
11216  numfkdelsetcols,
11217  confdelsetcols,
11218  false, /* no old check exists */
11220  insertTriggerOid,
11221  updateTriggerOid);
11222  table_close(pkrel, NoLock);
11223  }
11224 
11225  table_close(trigrel, RowExclusiveLock);
11226 }
11227 
11228 /*
11229  * When the parent of a partition receives [the referencing side of] a foreign
11230  * key, we must propagate that foreign key to the partition. However, the
11231  * partition might already have an equivalent foreign key; this routine
11232  * compares the given ForeignKeyCacheInfo (in the partition) to the FK defined
11233  * by the other parameters. If they are equivalent, create the link between
11234  * the two constraints and return true.
11235  *
11236  * If the given FK does not match the one defined by rest of the params,
11237  * return false.
11238  */
11239 static bool
11241  Oid partRelid,
11242  Oid parentConstrOid,
11243  int numfks,
11244  AttrNumber *mapped_conkey,
11245  AttrNumber *confkey,
11246  Oid *conpfeqop,
11247  Oid parentInsTrigger,
11248  Oid parentUpdTrigger,
11249  Relation trigrel)
11250 {
11251  HeapTuple parentConstrTup;
11252  Form_pg_constraint parentConstr;
11253  HeapTuple partcontup;
11254  Form_pg_constraint partConstr;
11255  ScanKeyData key;
11256  SysScanDesc scan;
11257  HeapTuple trigtup;
11258  Oid insertTriggerOid,
11259  updateTriggerOid;
11260 
11261  parentConstrTup = SearchSysCache1(CONSTROID,
11262  ObjectIdGetDatum(parentConstrOid));
11263  if (!HeapTupleIsValid(parentConstrTup))
11264  elog(ERROR, "cache lookup failed for constraint %u", parentConstrOid);
11265  parentConstr = (Form_pg_constraint) GETSTRUCT(parentConstrTup);
11266 
11267  /*
11268  * Do some quick & easy initial checks. If any of these fail, we cannot
11269  * use this constraint.
11270  */
11271  if (fk->confrelid != parentConstr->confrelid || fk->nkeys != numfks)
11272  {
11273  ReleaseSysCache(parentConstrTup);
11274  return false;
11275  }
11276  for (int i = 0; i < numfks; i++)
11277  {
11278  if (fk->conkey[i] != mapped_conkey[i] ||
11279  fk->confkey[i] != confkey[i] ||
11280  fk->conpfeqop[i] != conpfeqop[i])
11281  {
11282  ReleaseSysCache(parentConstrTup);
11283  return false;
11284  }
11285  }
11286 
11287  /*
11288  * Looks good so far; do some more extensive checks. Presumably the check
11289  * for 'convalidated' could be dropped, since we don't really care about
11290  * that, but let's be careful for now.
11291  */
11292  partcontup = SearchSysCache1(CONSTROID,
11293  ObjectIdGetDatum(fk->conoid));
11294  if (!HeapTupleIsValid(partcontup))
11295  elog(ERROR, "cache lookup failed for constraint %u", fk->conoid);
11296  partConstr = (Form_pg_constraint) GETSTRUCT(partcontup);
11297  if (OidIsValid(partConstr->conparentid) ||
11298  !partConstr->convalidated ||
11299  partConstr->condeferrable != parentConstr->condeferrable ||
11300  partConstr->condeferred != parentConstr->condeferred ||
11301  partConstr->confupdtype != parentConstr->confupdtype ||
11302  partConstr->confdeltype != parentConstr->confdeltype ||
11303  partConstr->confmatchtype != parentConstr->confmatchtype)
11304  {
11305  ReleaseSysCache(parentConstrTup);
11306  ReleaseSysCache(partcontup);
11307  return false;
11308  }
11309 
11310  ReleaseSysCache(partcontup);
11311  ReleaseSysCache(parentConstrTup);
11312 
11313  /*
11314  * Looks good! Attach this constraint. The action triggers in the new
11315  * partition become redundant -- the parent table already has equivalent
11316  * ones, and those will be able to reach the partition. Remove the ones
11317  * in the partition. We identify them because they have our constraint
11318  * OID, as well as being on the referenced rel.
11319  */
11320  ScanKeyInit(&key,
11321  Anum_pg_trigger_tgconstraint,
11322  BTEqualStrategyNumber, F_OIDEQ,
11323  ObjectIdGetDatum(fk->conoid));
11324  scan = systable_beginscan(trigrel, TriggerConstraintIndexId, true,
11325  NULL, 1, &key);
11326  while ((trigtup = systable_getnext(scan)) != NULL)
11327  {
11328  Form_pg_trigger trgform = (Form_pg_trigger) GETSTRUCT(trigtup);
11329  ObjectAddress trigger;
11330 
11331  if (trgform->tgconstrrelid != fk->conrelid)
11332  continue;
11333  if (trgform->tgrelid != fk->confrelid)
11334  continue;
11335 
11336  /*
11337  * The constraint is originally set up to contain this trigger as an
11338  * implementation object, so there's a dependency record that links
11339  * the two; however, since the trigger is no longer needed, we remove
11340  * the dependency link in order to be able to drop the trigger while
11341  * keeping the constraint intact.
11342  */
11343  deleteDependencyRecordsFor(TriggerRelationId,
11344  trgform->oid,
11345  false);
11346  /* make dependency deletion visible to performDeletion */
11348  ObjectAddressSet(trigger, TriggerRelationId,
11349  trgform->oid);
11350  performDeletion(&trigger, DROP_RESTRICT, 0);
11351  /* make trigger drop visible, in case the loop iterates */
11353  }
11354 
11355  systable_endscan(scan);
11356 
11357  ConstraintSetParentConstraint(fk->conoid, parentConstrOid, partRelid);
11358 
11359  /*
11360  * Like the constraint, attach partition's "check" triggers to the
11361  * corresponding parent triggers.
11362  */
11364  fk->conoid, fk->confrelid, fk->conrelid,
11365  &insertTriggerOid, &updateTriggerOid);
11366  Assert(OidIsValid(insertTriggerOid) && OidIsValid(parentInsTrigger));
11367  TriggerSetParentTrigger(trigrel, insertTriggerOid, parentInsTrigger,
11368  partRelid);
11369  Assert(OidIsValid(updateTriggerOid) && OidIsValid(parentUpdTrigger));
11370  TriggerSetParentTrigger(trigrel, updateTriggerOid, parentUpdTrigger,
11371  partRelid);
11372 
11374  return true;
11375 }
11376 
11377 /*
11378  * GetForeignKeyActionTriggers
11379  * Returns delete and update "action" triggers of the given relation
11380  * belonging to the given constraint
11381  */
11382 static void
11384  Oid conoid, Oid confrelid, Oid conrelid,
11385  Oid *deleteTriggerOid,
11386  Oid *updateTriggerOid)
11387 {
11388  ScanKeyData key;
11389  SysScanDesc scan;
11390  HeapTuple trigtup;
11391 
11392  *deleteTriggerOid = *updateTriggerOid = InvalidOid;
11393  ScanKeyInit(&key,
11394  Anum_pg_trigger_tgconstraint,
11395  BTEqualStrategyNumber, F_OIDEQ,
11396  ObjectIdGetDatum(conoid));
11397 
11398  scan = systable_beginscan(trigrel, TriggerConstraintIndexId, true,
11399  NULL, 1, &key);
11400  while ((trigtup = systable_getnext(scan)) != NULL)
11401  {
11402  Form_pg_trigger trgform = (Form_pg_trigger) GETSTRUCT(trigtup);
11403 
11404  if (trgform->tgconstrrelid != conrelid)
11405  continue;
11406  if (trgform->tgrelid != confrelid)
11407  continue;
11408  /* Only ever look at "action" triggers on the PK side. */
11409  if (RI_FKey_trigger_type(trgform->tgfoid) != RI_TRIGGER_PK)
11410  continue;
11411  if (TRIGGER_FOR_DELETE(trgform->tgtype))
11412  {
11413  Assert(*deleteTriggerOid == InvalidOid);
11414  *deleteTriggerOid = trgform->oid;
11415  }
11416  else if (TRIGGER_FOR_UPDATE(trgform->tgtype))
11417  {
11418  Assert(*updateTriggerOid == InvalidOid);
11419  *updateTriggerOid = trgform->oid;
11420  }
11421 #ifndef USE_ASSERT_CHECKING
11422  /* In an assert-enabled build, continue looking to find duplicates */
11423  if (OidIsValid(*deleteTriggerOid) && OidIsValid(*updateTriggerOid))
11424  break;
11425 #endif
11426  }
11427 
11428  if (!OidIsValid(*deleteTriggerOid))
11429  elog(ERROR, "could not find ON DELETE action trigger of foreign key constraint %u",
11430  conoid);
11431  if (!OidIsValid(*updateTriggerOid))
11432  elog(ERROR, "could not find ON UPDATE action trigger of foreign key constraint %u",
11433  conoid);
11434 
11435  systable_endscan(scan);
11436 }
11437 
11438 /*
11439  * GetForeignKeyCheckTriggers
11440  * Returns insert and update "check" triggers of the given relation
11441  * belonging to the given constraint
11442  */
11443 static void
11445  Oid conoid, Oid confrelid, Oid conrelid,
11446  Oid *insertTriggerOid,
11447  Oid *updateTriggerOid)
11448 {
11449  ScanKeyData key;
11450  SysScanDesc scan;
11451  HeapTuple trigtup;
11452 
11453  *insertTriggerOid = *updateTriggerOid = InvalidOid;
11454  ScanKeyInit(&key,
11455  Anum_pg_trigger_tgconstraint,
11456  BTEqualStrategyNumber, F_OIDEQ,
11457  ObjectIdGetDatum(conoid));
11458 
11459  scan = systable_beginscan(trigrel, TriggerConstraintIndexId, true,
11460  NULL, 1, &key);
11461  while ((trigtup = systable_getnext(scan)) != NULL)
11462  {
11463  Form_pg_trigger trgform = (Form_pg_trigger) GETSTRUCT(trigtup);
11464 
11465  if (trgform->tgconstrrelid != confrelid)
11466  continue;
11467  if (trgform->tgrelid != conrelid)
11468  continue;
11469  /* Only ever look at "check" triggers on the FK side. */
11470  if (RI_FKey_trigger_type(trgform->tgfoid) != RI_TRIGGER_FK)
11471  continue;
11472  if (TRIGGER_FOR_INSERT(trgform->tgtype))
11473  {
11474  Assert(*insertTriggerOid == InvalidOid);
11475  *insertTriggerOid = trgform->oid;
11476  }
11477  else if (TRIGGER_FOR_UPDATE(trgform->tgtype))
11478  {
11479  Assert(*updateTriggerOid == InvalidOid);
11480  *updateTriggerOid = trgform->oid;
11481  }
11482 #ifndef USE_ASSERT_CHECKING
11483  /* In an assert-enabled build, continue looking to find duplicates. */
11484  if (OidIsValid(*insertTriggerOid) && OidIsValid(*updateTriggerOid))
11485  break;
11486 #endif
11487  }
11488 
11489  if (!OidIsValid(*insertTriggerOid))
11490  elog(ERROR, "could not find ON INSERT check triggers of foreign key constraint %u",
11491  conoid);
11492  if (!OidIsValid(*updateTriggerOid))
11493  elog(ERROR, "could not find ON UPDATE check triggers of foreign key constraint %u",
11494  conoid);
11495 
11496  systable_endscan(scan);
11497 }
11498 
11499 /*
11500  * ALTER TABLE ALTER CONSTRAINT
11501  *
11502  * Update the attributes of a constraint.
11503  *
11504  * Currently only works for Foreign Key constraints.
11505  *
11506  * If the constraint is modified, returns its address; otherwise, return
11507  * InvalidObjectAddress.
11508  */
11509 static ObjectAddress
11511  bool recursing, LOCKMODE lockmode)
11512 {
11513  Constraint *cmdcon;
11514  Relation conrel;
11515  Relation tgrel;
11516  SysScanDesc scan;
11517  ScanKeyData skey[3];
11518  HeapTuple contuple;
11519  Form_pg_constraint currcon;
11520  ObjectAddress address;
11521  List *otherrelids = NIL;
11522  ListCell *lc;
11523 
11524  cmdcon = castNode(Constraint, cmd->def);
11525 
11526  conrel = table_open(ConstraintRelationId, RowExclusiveLock);
11527  tgrel = table_open(TriggerRelationId, RowExclusiveLock);
11528 
11529  /*
11530  * Find and check the target constraint
11531  */
11532  ScanKeyInit(&skey[0],
11533  Anum_pg_constraint_conrelid,
11534  BTEqualStrategyNumber, F_OIDEQ,
11536  ScanKeyInit(&skey[1],
11537  Anum_pg_constraint_contypid,
11538  BTEqualStrategyNumber, F_OIDEQ,
11540  ScanKeyInit(&skey[2],
11541  Anum_pg_constraint_conname,
11542  BTEqualStrategyNumber, F_NAMEEQ,
11543  CStringGetDatum(cmdcon->conname));
11544  scan = systable_beginscan(conrel, ConstraintRelidTypidNameIndexId,
11545  true, NULL, 3, skey);
11546 
11547  /* There can be at most one matching row */
11548  if (!HeapTupleIsValid(contuple = systable_getnext(scan)))
11549  ereport(ERROR,
11550  (errcode(ERRCODE_UNDEFINED_OBJECT),
11551  errmsg("constraint \"%s\" of relation \"%s\" does not exist",
11552  cmdcon->conname, RelationGetRelationName(rel))));
11553 
11554  currcon = (Form_pg_constraint) GETSTRUCT(contuple);
11555  if (currcon->contype != CONSTRAINT_FOREIGN)
11556  ereport(ERROR,
11557  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
11558  errmsg("constraint \"%s\" of relation \"%s\" is not a foreign key constraint",
11559  cmdcon->conname, RelationGetRelationName(rel))));
11560 
11561  /*
11562  * If it's not the topmost constraint, raise an error.
11563  *
11564  * Altering a non-topmost constraint leaves some triggers untouched, since
11565  * they are not directly connected to this constraint; also, pg_dump would
11566  * ignore the deferrability status of the individual constraint, since it
11567  * only dumps topmost constraints. Avoid these problems by refusing this
11568  * operation and telling the user to alter the parent constraint instead.
11569  */
11570  if (OidIsValid(currcon->conparentid))
11571  {
11572  HeapTuple tp;
11573  Oid parent = currcon->conparentid;
11574  char *ancestorname = NULL;
11575  char *ancestortable = NULL;
11576 
11577  /* Loop to find the topmost constraint */
11578  while (HeapTupleIsValid(tp = SearchSysCache1(CONSTROID, ObjectIdGetDatum(parent))))
11579  {
11581 
11582  /* If no parent, this is the constraint we want */
11583  if (!OidIsValid(contup->conparentid))
11584  {
11585  ancestorname = pstrdup(NameStr(contup->conname));
11586  ancestortable = get_rel_name(contup->conrelid);
11587  ReleaseSysCache(tp);
11588  break;
11589  }
11590 
11591  parent = contup->conparentid;
11592  ReleaseSysCache(tp);
11593  }
11594 
11595  ereport(ERROR,
11596  (errmsg("cannot alter constraint \"%s\" on relation \"%s\"",
11597  cmdcon->conname, RelationGetRelationName(rel)),
11598  ancestorname && ancestortable ?
11599  errdetail("Constraint \"%s\" is derived from constraint \"%s\" of relation \"%s\".",
11600  cmdcon->conname, ancestorname, ancestortable) : 0,
11601  errhint("You may alter the constraint it derives from instead.")));
11602  }
11603 
11604  /*
11605  * Do the actual catalog work. We can skip changing if already in the
11606  * desired state, but not if a partitioned table: partitions need to be
11607  * processed regardless, in case they had the constraint locally changed.
11608  */
11609  address = InvalidObjectAddress;
11610  if (currcon->condeferrable != cmdcon->deferrable ||
11611  currcon->condeferred != cmdcon->initdeferred ||
11612  rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
11613  {
11614  if (ATExecAlterConstrRecurse(cmdcon, conrel, tgrel, rel, contuple,
11615  &otherrelids, lockmode))
11616  ObjectAddressSet(address, ConstraintRelationId, currcon->oid);
11617  }
11618 
11619  /*
11620  * ATExecAlterConstrRecurse already invalidated relcache for the relations
11621  * having the constraint itself; here we also invalidate for relations
11622  * that have any triggers that are part of the constraint.
11623  */
11624  foreach(lc, otherrelids)
11626 
11627  systable_endscan(scan);
11628 
11629  table_close(tgrel, RowExclusiveLock);
11630  table_close(conrel, RowExclusiveLock);
11631 
11632  return address;
11633 }
11634 
11635 /*
11636  * Recursive subroutine of ATExecAlterConstraint. Returns true if the
11637  * constraint is altered.
11638  *
11639  * *otherrelids is appended OIDs of relations containing affected triggers.
11640  *
11641  * Note that we must recurse even when the values are correct, in case
11642  * indirect descendants have had their constraints altered locally.
11643  * (This could be avoided if we forbade altering constraints in partitions
11644  * but existing releases don't do that.)
11645  */
11646 static bool
11648  Relation rel, HeapTuple contuple, List **otherrelids,
11649  LOCKMODE lockmode)
11650 {
11651  Form_pg_constraint currcon;
11652  Oid conoid;
11653  Oid refrelid;
11654  bool changed = false;
11655 
11656  /* since this function recurses, it could be driven to stack overflow */
11658 
11659  currcon = (Form_pg_constraint) GETSTRUCT(contuple);
11660  conoid = currcon->oid;
11661  refrelid = currcon->confrelid;
11662 
11663  /*
11664  * Update pg_constraint with the flags from cmdcon.
11665  *
11666  * If called to modify a constraint that's already in the desired state,
11667  * silently do nothing.
11668  */
11669  if (currcon->condeferrable != cmdcon->deferrable ||
11670  currcon->condeferred != cmdcon->initdeferred)
11671  {
11672  HeapTuple copyTuple;
11673  Form_pg_constraint copy_con;
11674  HeapTuple tgtuple;
11675  ScanKeyData tgkey;
11676  SysScanDesc tgscan;
11677 
11678  copyTuple = heap_copytuple(contuple);
11679  copy_con = (Form_pg_constraint) GETSTRUCT(copyTuple);
11680  copy_con->condeferrable = cmdcon->deferrable;
11681  copy_con->condeferred = cmdcon->initdeferred;
11682  CatalogTupleUpdate(conrel, &copyTuple->t_self, copyTuple);
11683 
11684  InvokeObjectPostAlterHook(ConstraintRelationId,
11685  conoid, 0);
11686 
11687  heap_freetuple(copyTuple);
11688  changed = true;
11689 
11690  /* Make new constraint flags visible to others */
11692 
11693  /*
11694  * Now we need to update the multiple entries in pg_trigger that
11695  * implement the constraint.
11696  */
11697  ScanKeyInit(&tgkey,
11698  Anum_pg_trigger_tgconstraint,
11699  BTEqualStrategyNumber, F_OIDEQ,
11700  ObjectIdGetDatum(conoid));
11701  tgscan = systable_beginscan(tgrel, TriggerConstraintIndexId, true,
11702  NULL, 1, &tgkey);
11703  while (HeapTupleIsValid(tgtuple = systable_getnext(tgscan)))
11704  {
11705  Form_pg_trigger tgform = (Form_pg_trigger) GETSTRUCT(tgtuple);
11706  Form_pg_trigger copy_tg;
11707  HeapTuple tgCopyTuple;
11708 
11709  /*
11710  * Remember OIDs of other relation(s) involved in FK constraint.
11711  * (Note: it's likely that we could skip forcing a relcache inval
11712  * for other rels that don't have a trigger whose properties
11713  * change, but let's be conservative.)
11714  */
11715  if (tgform->tgrelid != RelationGetRelid(rel))
11716  *otherrelids = list_append_unique_oid(*otherrelids,
11717  tgform->tgrelid);
11718 
11719  /*
11720  * Update deferrability of RI_FKey_noaction_del,
11721  * RI_FKey_noaction_upd, RI_FKey_check_ins and RI_FKey_check_upd
11722  * triggers, but not others; see createForeignKeyActionTriggers
11723  * and CreateFKCheckTrigger.
11724  */
11725  if (tgform->tgfoid != F_RI_FKEY_NOACTION_DEL &&
11726  tgform->tgfoid != F_RI_FKEY_NOACTION_UPD &&
11727  tgform->tgfoid != F_RI_FKEY_CHECK_INS &&
11728  tgform->tgfoid != F_RI_FKEY_CHECK_UPD)
11729  continue;
11730 
11731  tgCopyTuple = heap_copytuple(tgtuple);
11732  copy_tg = (Form_pg_trigger) GETSTRUCT(tgCopyTuple);
11733 
11734  copy_tg->tgdeferrable = cmdcon->deferrable;
11735  copy_tg->tginitdeferred = cmdcon->initdeferred;
11736  CatalogTupleUpdate(tgrel, &tgCopyTuple->t_self, tgCopyTuple);
11737 
11738  InvokeObjectPostAlterHook(TriggerRelationId, tgform->oid, 0);
11739 
11740  heap_freetuple(tgCopyTuple);
11741  }
11742 
11743  systable_endscan(tgscan);
11744  }
11745 
11746  /*
11747  * If the table at either end of the constraint is partitioned, we need to
11748  * recurse and handle every constraint that is a child of this one.
11749  *
11750  * (This assumes that the recurse flag is forcibly set for partitioned
11751  * tables, and not set for legacy inheritance, though we don't check for
11752  * that here.)
11753  */
11754  if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE ||
11755  get_rel_relkind(refrelid) == RELKIND_PARTITIONED_TABLE)
11756  {
11757  ScanKeyData pkey;
11758  SysScanDesc pscan;
11759  HeapTuple childtup;
11760 
11761  ScanKeyInit(&pkey,
11762  Anum_pg_constraint_conparentid,
11763  BTEqualStrategyNumber, F_OIDEQ,
11764  ObjectIdGetDatum(conoid));
11765 
11766  pscan = systable_beginscan(conrel, ConstraintParentIndexId,
11767  true, NULL, 1, &pkey);
11768 
11769  while (HeapTupleIsValid(childtup = systable_getnext(pscan)))
11770  {
11771  Form_pg_constraint childcon = (Form_pg_constraint) GETSTRUCT(childtup);
11772  Relation childrel;
11773 
11774  childrel = table_open(childcon->conrelid, lockmode);
11775  ATExecAlterConstrRecurse(cmdcon, conrel, tgrel, childrel, childtup,
11776  otherrelids, lockmode);
11777  table_close(childrel, NoLock);
11778  }
11779 
11780  systable_endscan(pscan);
11781  }
11782 
11783  return changed;
11784 }
11785 
11786 /*
11787  * ALTER TABLE VALIDATE CONSTRAINT
11788  *
11789  * XXX The reason we handle recursion here rather than at Phase 1 is because
11790  * there's no good way to skip recursing when handling foreign keys: there is
11791  * no need to lock children in that case, yet we wouldn't be able to avoid
11792  * doing so at that level.
11793  *
11794  * Return value is the address of the validated constraint. If the constraint
11795  * was already validated, InvalidObjectAddress is returned.
11796  */
11797 static ObjectAddress
11798 ATExecValidateConstraint(List **wqueue, Relation rel, char *constrName,
11799  bool recurse, bool recursing, LOCKMODE lockmode)
11800 {
11801  Relation conrel;
11802  SysScanDesc scan;
11803  ScanKeyData skey[3];
11804  HeapTuple tuple;
11805  Form_pg_constraint con;
11806  ObjectAddress address;
11807 
11808  conrel = table_open(ConstraintRelationId, RowExclusiveLock);
11809 
11810  /*
11811  * Find and check the target constraint
11812  */
11813  ScanKeyInit(&skey[0],
11814  Anum_pg_constraint_conrelid,
11815  BTEqualStrategyNumber, F_OIDEQ,
11817  ScanKeyInit(&skey[1],
11818  Anum_pg_constraint_contypid,
11819  BTEqualStrategyNumber, F_OIDEQ,
11821  ScanKeyInit(&skey[2],
11822  Anum_pg_constraint_conname,
11823  BTEqualStrategyNumber, F_NAMEEQ,
11824  CStringGetDatum(constrName));
11825  scan = systable_beginscan(conrel, ConstraintRelidTypidNameIndexId,
11826  true, NULL, 3, skey);
11827 
11828  /* There can be at most one matching row */
11829  if (!HeapTupleIsValid(tuple = systable_getnext(scan)))
11830  ereport(ERROR,
11831  (errcode(ERRCODE_UNDEFINED_OBJECT),
11832  errmsg("constraint \"%s\" of relation \"%s\" does not exist",
11833  constrName, RelationGetRelationName(rel))));
11834 
11835  con = (Form_pg_constraint) GETSTRUCT(tuple);
11836  if (con->contype != CONSTRAINT_FOREIGN &&
11837  con->contype != CONSTRAINT_CHECK)
11838  ereport(ERROR,
11839  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
11840  errmsg("constraint \"%s\" of relation \"%s\" is not a foreign key or check constraint",
11841  constrName, RelationGetRelationName(rel))));
11842 
11843  if (!con->convalidated)
11844  {
11845  AlteredTableInfo *tab;
11846  HeapTuple copyTuple;
11847  Form_pg_constraint copy_con;
11848 
11849  if (con->contype == CONSTRAINT_FOREIGN)
11850  {
11851  NewConstraint *newcon;
11852  Constraint *fkconstraint;
11853 
11854  /* Queue validation for phase 3 */
11855  fkconstraint = makeNode(Constraint);
11856  /* for now this is all we need */
11857  fkconstraint->conname = constrName;
11858 
11859  newcon = (NewConstraint *) palloc0(sizeof(NewConstraint));
11860  newcon->name = constrName;
11861  newcon->contype = CONSTR_FOREIGN;
11862  newcon->refrelid = con->confrelid;
11863  newcon->refindid = con->conindid;
11864  newcon->conid = con->oid;
11865  newcon->qual = (Node *) fkconstraint;
11866 
11867  /* Find or create work queue entry for this table */
11868  tab = ATGetQueueEntry(wqueue, rel);
11869  tab->constraints = lappend(tab->constraints, newcon);
11870 
11871  /*
11872  * We disallow creating invalid foreign keys to or from
11873  * partitioned tables, so ignoring the recursion bit is okay.
11874  */
11875  }
11876  else if (con->contype == CONSTRAINT_CHECK)
11877  {
11878  List *children = NIL;
11879  ListCell *child;
11880  NewConstraint *newcon;
11881  Datum val;
11882  char *conbin;
11883 
11884  /*
11885  * If we're recursing, the parent has already done this, so skip
11886  * it. Also, if the constraint is a NO INHERIT constraint, we
11887  * shouldn't try to look for it in the children.
11888  */
11889  if (!recursing && !con->connoinherit)
11890  children = find_all_inheritors(RelationGetRelid(rel),
11891  lockmode, NULL);
11892 
11893  /*
11894  * For CHECK constraints, we must ensure that we only mark the
11895  * constraint as validated on the parent if it's already validated
11896  * on the children.
11897  *
11898  * We recurse before validating on the parent, to reduce risk of
11899  * deadlocks.
11900  */
11901  foreach(child, children)
11902  {
11903  Oid childoid = lfirst_oid(child);
11904  Relation childrel;
11905 
11906  if (childoid == RelationGetRelid(rel))
11907  continue;
11908 
11909  /*
11910  * If we are told not to recurse, there had better not be any
11911  * child tables, because we can't mark the constraint on the
11912  * parent valid unless it is valid for all child tables.
11913  */
11914  if (!recurse)
11915  ereport(ERROR,
11916  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
11917  errmsg("constraint must be validated on child tables too")));
11918 
11919  /* find_all_inheritors already got lock */
11920  childrel = table_open(childoid, NoLock);
11921 
11922  ATExecValidateConstraint(wqueue, childrel, constrName, false,
11923  true, lockmode);
11924  table_close(childrel, NoLock);
11925  }
11926 
11927  /* Queue validation for phase 3 */
11928  newcon = (NewConstraint *) palloc0(sizeof(NewConstraint));
11929  newcon->name = constrName;
11930  newcon->contype = CONSTR_CHECK;
11931  newcon->refrelid = InvalidOid;
11932  newcon->refindid = InvalidOid;
11933  newcon->conid = con->oid;
11934 
11935  val = SysCacheGetAttrNotNull(CONSTROID, tuple,
11936  Anum_pg_constraint_conbin);
11937  conbin = TextDatumGetCString(val);
11938  newcon->qual = (Node *) stringToNode(conbin);
11939 
11940  /* Find or create work queue entry for this table */
11941  tab = ATGetQueueEntry(wqueue, rel);
11942  tab->constraints = lappend(tab->constraints, newcon);
11943 
11944  /*
11945  * Invalidate relcache so that others see the new validated
11946  * constraint.
11947  */
11949  }
11950 
11951  /*
11952  * Now update the catalog, while we have the door open.
11953  */
11954  copyTuple = heap_copytuple(tuple);
11955  copy_con = (Form_pg_constraint) GETSTRUCT(copyTuple);
11956  copy_con->convalidated = true;
11957  CatalogTupleUpdate(conrel, &copyTuple->t_self, copyTuple);
11958 
11959  InvokeObjectPostAlterHook(ConstraintRelationId, con->oid, 0);
11960 
11961  heap_freetuple(copyTuple);
11962 
11963  ObjectAddressSet(address, ConstraintRelationId, con->oid);
11964  }
11965  else
11966  address = InvalidObjectAddress; /* already validated */
11967 
11968  systable_endscan(scan);
11969 
11970  table_close(conrel, RowExclusiveLock);
11971 
11972  return address;
11973 }
11974 
11975 
11976 /*
11977  * transformColumnNameList - transform list of column names
11978  *
11979  * Lookup each name and return its attnum and, optionally, type OID
11980  *
11981  * Note: the name of this function suggests that it's general-purpose,
11982  * but actually it's only used to look up names appearing in foreign-key
11983  * clauses. The error messages would need work to use it in other cases,
11984  * and perhaps the validity checks as well.
11985  */
11986 static int
11988  int16 *attnums, Oid *atttypids)
11989 {
11990  ListCell *l;
11991  int attnum;
11992 
11993  attnum = 0;
11994  foreach(l, colList)
11995  {
11996  char *attname = strVal(lfirst(l));
11997  HeapTuple atttuple;
11998  Form_pg_attribute attform;
11999 
12000  atttuple = SearchSysCacheAttName(relId, attname);
12001  if (!HeapTupleIsValid(atttuple))
12002  ereport(ERROR,
12003  (errcode(ERRCODE_UNDEFINED_COLUMN),
12004  errmsg("column \"%s\" referenced in foreign key constraint does not exist",
12005  attname)));
12006  attform = (Form_pg_attribute) GETSTRUCT(atttuple);
12007  if (attform->attnum < 0)
12008  ereport(ERROR,
12009  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
12010  errmsg("system columns cannot be used in foreign keys")));
12011  if (attnum >= INDEX_MAX_KEYS)
12012  ereport(ERROR,
12013  (errcode(ERRCODE_TOO_MANY_COLUMNS),
12014  errmsg("cannot have more than %d keys in a foreign key",
12015  INDEX_MAX_KEYS)));
12016  attnums[attnum] = attform->attnum;
12017  if (atttypids != NULL)
12018  atttypids[attnum] = attform->atttypid;
12019  ReleaseSysCache(atttuple);
12020  attnum++;
12021  }
12022 
12023  return attnum;
12024 }
12025 
12026 /*
12027  * transformFkeyGetPrimaryKey -
12028  *
12029  * Look up the names, attnums, and types of the primary key attributes
12030  * for the pkrel. Also return the index OID and index opclasses of the
12031  * index supporting the primary key.
12032  *
12033  * All parameters except pkrel are output parameters. Also, the function
12034  * return value is the number of attributes in the primary key.
12035  *
12036  * Used when the column list in the REFERENCES specification is omitted.
12037  */
12038 static int
12040  List **attnamelist,
12041  int16 *attnums, Oid *atttypids,
12042  Oid *opclasses)
12043 {
12044  List *indexoidlist;
12045  ListCell *indexoidscan;
12046  HeapTuple indexTuple = NULL;
12047  Form_pg_index indexStruct = NULL;
12048  Datum indclassDatum;
12049  oidvector *indclass;
12050  int i;
12051 
12052  /*
12053  * Get the list of index OIDs for the table from the relcache, and look up
12054  * each one in the pg_index syscache until we find one marked primary key
12055  * (hopefully there isn't more than one such). Insist it's valid, too.
12056  */
12057  *indexOid = InvalidOid;
12058 
12059  indexoidlist = RelationGetIndexList(pkrel);
12060 
12061  foreach(indexoidscan, indexoidlist)
12062  {
12063  Oid indexoid = lfirst_oid(indexoidscan);
12064 
12065  indexTuple = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(indexoid));
12066  if (!HeapTupleIsValid(indexTuple))
12067  elog(ERROR, "cache lookup failed for index %u", indexoid);
12068  indexStruct = (Form_pg_index) GETSTRUCT(indexTuple);
12069  if (indexStruct->indisprimary && indexStruct->indisvalid)
12070  {
12071  /*
12072  * Refuse to use a deferrable primary key. This is per SQL spec,
12073  * and there would be a lot of interesting semantic problems if we
12074  * tried to allow it.
12075  */
12076  if (!indexStruct->indimmediate)
12077  ereport(ERROR,
12078  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
12079  errmsg("cannot use a deferrable primary key for referenced table \"%s\"",
12080  RelationGetRelationName(pkrel))));
12081 
12082  *indexOid = indexoid;
12083  break;
12084  }
12085  ReleaseSysCache(indexTuple);
12086  }
12087 
12088  list_free(indexoidlist);
12089 
12090  /*
12091  * Check that we found it
12092  */
12093  if (!OidIsValid(*indexOid))
12094  ereport(ERROR,
12095  (errcode(ERRCODE_UNDEFINED_OBJECT),
12096  errmsg("there is no primary key for referenced table \"%s\"",
12097  RelationGetRelationName(pkrel))));
12098 
12099  /* Must get indclass the hard way */
12100  indclassDatum = SysCacheGetAttrNotNull(INDEXRELID, indexTuple,
12101  Anum_pg_index_indclass);
12102  indclass = (oidvector *) DatumGetPointer(indclassDatum);
12103 
12104  /*
12105  * Now build the list of PK attributes from the indkey definition (we
12106  * assume a primary key cannot have expressional elements)
12107  */
12108  *attnamelist = NIL;
12109  for (i = 0; i < indexStruct->indnkeyatts; i++)
12110  {
12111  int pkattno = indexStruct->indkey.values[i];
12112 
12113  attnums[i] = pkattno;
12114  atttypids[i] = attnumTypeId(pkrel, pkattno);
12115  opclasses[i] = indclass->values[i];
12116  *attnamelist = lappend(*attnamelist,
12117  makeString(pstrdup(NameStr(*attnumAttName(pkrel, pkattno)))));
12118  }
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.
12134  *
12135  * Raises an ERROR on validation failure.
12136  */
12137 static Oid
12139  int numattrs, int16 *attnums,
12140  Oid *opclasses)
12141 {
12142  Oid indexoid = InvalidOid;
12143  bool found = false;
12144  bool found_deferrable = false;
12145  List *indexoidlist;
12146  ListCell *indexoidscan;
12147  int i,
12148  j;
12149 
12150  /*
12151  * Reject duplicate appearances of columns in the referenced-columns list.
12152  * Such a case is forbidden by the SQL standard, and even if we thought it
12153  * useful to allow it, there would be ambiguity about how to match the
12154  * list to unique indexes (in particular, it'd be unclear which index
12155  * opclass goes with which FK column).
12156  */
12157  for (i = 0; i < numattrs; i++)
12158  {
12159  for (j = i + 1; j < numattrs; j++)
12160  {
12161  if (attnums[i] == attnums[j])
12162  ereport(ERROR,
12163  (errcode(ERRCODE_INVALID_FOREIGN_KEY),
12164  errmsg("foreign key referenced-columns list must not contain duplicates")));
12165  }
12166  }
12167 
12168  /*
12169  * Get the list of index OIDs for the table from the relcache, and look up
12170  * each one in the pg_index syscache, and match unique indexes to the list
12171  * of attnums we are given.
12172  */
12173  indexoidlist = RelationGetIndexList(pkrel);
12174 
12175  foreach(indexoidscan, indexoidlist)
12176  {
12177  HeapTuple indexTuple;
12178  Form_pg_index indexStruct;
12179 
12180  indexoid = lfirst_oid(indexoidscan);
12181  indexTuple = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(indexoid));
12182  if (!HeapTupleIsValid(indexTuple))
12183  elog(ERROR, "cache lookup failed for index %u", indexoid);
12184  indexStruct = (Form_pg_index) GETSTRUCT(indexTuple);
12185 
12186  /*
12187  * Must have the right number of columns; must be unique and not a
12188  * partial index; forget it if there are any expressions, too. Invalid
12189  * indexes are out as well.
12190  */
12191  if (indexStruct->indnkeyatts == numattrs &&
12192  indexStruct->indisunique &&
12193  indexStruct->indisvalid &&
12194  heap_attisnull(indexTuple, Anum_pg_index_indpred, NULL) &&
12195  heap_attisnull(indexTuple, Anum_pg_index_indexprs, NULL))
12196  {
12197  Datum indclassDatum;
12198  oidvector *indclass;
12199 
12200  /* Must get indclass the hard way */
12201  indclassDatum = SysCacheGetAttrNotNull(INDEXRELID, indexTuple,
12202  Anum_pg_index_indclass);
12203  indclass = (oidvector *) DatumGetPointer(indclassDatum);
12204 
12205  /*
12206  * The given attnum list may match the index columns in any order.
12207  * Check for a match, and extract the appropriate opclasses while
12208  * we're at it.
12209  *
12210  * We know that attnums[] is duplicate-free per the test at the
12211  * start of this function, and we checked above that the number of
12212  * index columns agrees, so if we find a match for each attnums[]
12213  * entry then we must have a one-to-one match in some order.
12214  */
12215  for (i = 0; i < numattrs; i++)
12216  {
12217  found = false;
12218  for (j = 0; j < numattrs; j++)
12219  {
12220  if (attnums[i] == indexStruct->indkey.values[j])
12221  {
12222  opclasses[i] = indclass->values[j];
12223  found = true;
12224  break;
12225  }
12226  }
12227  if (!found)
12228  break;
12229  }
12230 
12231  /*
12232  * Refuse to use a deferrable unique/primary key. This is per SQL
12233  * spec, and there would be a lot of interesting semantic problems
12234  * if we tried to allow it.
12235  */
12236  if (found && !indexStruct->indimmediate)
12237  {
12238  /*
12239  * Remember that we found an otherwise matching index, so that
12240  * we can generate a more appropriate error message.
12241  */
12242  found_deferrable = true;
12243  found = false;
12244  }
12245  }
12246  ReleaseSysCache(indexTuple);
12247  if (found)
12248  break;
12249  }
12250 
12251  if (!found)
12252  {
12253  if (found_deferrable)
12254  ereport(ERROR,
12255  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
12256  errmsg("cannot use a deferrable unique constraint for referenced table \"%s\"",
12257  RelationGetRelationName(pkrel))));
12258  else
12259  ereport(ERROR,
12260  (errcode(ERRCODE_INVALID_FOREIGN_KEY),
12261  errmsg("there is no unique constraint matching given keys for referenced table \"%s\"",
12262  RelationGetRelationName(pkrel))));
12263  }
12264 
12265  list_free(indexoidlist);
12266 
12267  return indexoid;
12268 }
12269 
12270 /*
12271  * findFkeyCast -
12272  *
12273  * Wrapper around find_coercion_pathway() for ATAddForeignKeyConstraint().
12274  * Caller has equal regard for binary coercibility and for an exact match.
12275 */
12276 static CoercionPathType
12277 findFkeyCast(Oid targetTypeId, Oid sourceTypeId, Oid *funcid)
12278 {
12279  CoercionPathType ret;
12280 
12281  if (targetTypeId == sourceTypeId)
12282  {
12284  *funcid = InvalidOid;
12285  }
12286  else
12287  {
12288  ret = find_coercion_pathway(targetTypeId, sourceTypeId,
12289  COERCION_IMPLICIT, funcid);
12290  if (ret == COERCION_PATH_NONE)
12291  /* A previously-relied-upon cast is now gone. */
12292  elog(ERROR, "could not find cast from %u to %u",
12293  sourceTypeId, targetTypeId);
12294  }
12295 
12296  return ret;
12297 }
12298 
12299 /*
12300  * Permissions checks on the referenced table for ADD FOREIGN KEY
12301  *
12302  * Note: we have already checked that the user owns the referencing table,
12303  * else we'd have failed much earlier; no additional checks are needed for it.
12304  */
12305 static void
12306 checkFkeyPermissions(Relation rel, int16 *attnums, int natts)
12307 {
12308  Oid roleid = GetUserId();
12309  AclResult aclresult;
12310  int i;
12311 
12312  /* Okay if we have relation-level REFERENCES permission */
12313  aclresult = pg_class_aclcheck(RelationGetRelid(rel), roleid,
12314  ACL_REFERENCES);
12315  if (aclresult == ACLCHECK_OK)
12316  return;
12317  /* Else we must have REFERENCES on each column */
12318  for (i = 0; i < natts; i++)
12319  {
12320  aclresult = pg_attribute_aclcheck(RelationGetRelid(rel), attnums[i],
12321  roleid, ACL_REFERENCES);
12322  if (aclresult != ACLCHECK_OK)
12323  aclcheck_error(aclresult, get_relkind_objtype(rel->rd_rel->relkind),
12325  }
12326 }
12327 
12328 /*
12329  * Scan the existing rows in a table to verify they meet a proposed FK
12330  * constraint.
12331  *
12332  * Caller must have opened and locked both relations appropriately.
12333  */
12334 static void
12336  Relation rel,
12337  Relation pkrel,
12338  Oid pkindOid,
12339  Oid constraintOid)
12340 {
12341  TupleTableSlot *slot;
12342  TableScanDesc scan;
12343  Trigger trig = {0};
12344  Snapshot snapshot;
12345  MemoryContext oldcxt;
12346  MemoryContext perTupCxt;
12347 
12348  ereport(DEBUG1,
12349  (errmsg_internal("validating foreign key constraint \"%s\"", conname)));
12350 
12351  /*
12352  * Build a trigger call structure; we'll need it either way.
12353  */
12354  trig.tgoid = InvalidOid;
12355  trig.tgname = conname;
12357  trig.tgisinternal = true;
12358  trig.tgconstrrelid = RelationGetRelid(pkrel);
12359  trig.tgconstrindid = pkindOid;
12360  trig.tgconstraint = constraintOid;
12361  trig.tgdeferrable = false;
12362  trig.tginitdeferred = false;
12363  /* we needn't fill in remaining fields */
12364 
12365  /*
12366  * See if we can do it with a single LEFT JOIN query. A false result
12367  * indicates we must proceed with the fire-the-trigger method.
12368  */
12369  if (RI_Initial_Check(&trig, rel, pkrel))
12370  return;
12371 
12372  /*
12373  * Scan through each tuple, calling RI_FKey_check_ins (insert trigger) as
12374  * if that tuple had just been inserted. If any of those fail, it should
12375  * ereport(ERROR) and that's that.
12376  */
12377  snapshot = RegisterSnapshot(GetLatestSnapshot());
12378  slot = table_slot_create(rel, NULL);
12379  scan = table_beginscan(rel, snapshot, 0, NULL);
12380 
12382  "validateForeignKeyConstraint",
12384  oldcxt = MemoryContextSwitchTo(perTupCxt);
12385 
12386  while (table_scan_getnextslot(scan, ForwardScanDirection, slot))
12387  {
12388  LOCAL_FCINFO(fcinfo, 0);
12389  TriggerData trigdata = {0};
12390 
12392 
12393  /*
12394  * Make a call to the trigger function
12395  *
12396  * No parameters are passed, but we do set a context
12397  */
12398  MemSet(fcinfo, 0, SizeForFunctionCallInfo(0));
12399 
12400  /*
12401  * We assume RI_FKey_check_ins won't look at flinfo...
12402  */
12403  trigdata.type = T_TriggerData;
12405  trigdata.tg_relation = rel;
12406  trigdata.tg_trigtuple = ExecFetchSlotHeapTuple(slot, false, NULL);
12407  trigdata.tg_trigslot = slot;
12408  trigdata.tg_trigger = &trig;
12409 
12410  fcinfo->context = (Node *) &trigdata;
12411 
12412  RI_FKey_check_ins(fcinfo);
12413 
12414  MemoryContextReset(perTupCxt);
12415  }
12416 
12417  MemoryContextSwitchTo(oldcxt);
12418  MemoryContextDelete(perTupCxt);
12419  table_endscan(scan);
12420  UnregisterSnapshot(snapshot);
12422 }
12423 
12424 /*
12425  * CreateFKCheckTrigger
12426  * Creates the insert (on_insert=true) or update "check" trigger that
12427  * implements a given foreign key
12428  *
12429  * Returns the OID of the so created trigger.
12430  */
12431 static Oid
12432 CreateFKCheckTrigger(Oid myRelOid, Oid refRelOid, Constraint *fkconstraint,
12433  Oid constraintOid, Oid indexOid, Oid parentTrigOid,
12434  bool on_insert)
12435 {
12436  ObjectAddress trigAddress;
12437  CreateTrigStmt *fk_trigger;
12438 
12439  /*
12440  * Note: for a self-referential FK (referencing and referenced tables are
12441  * the same), it is important that the ON UPDATE action fires before the
12442  * CHECK action, since both triggers will fire on the same row during an
12443  * UPDATE event; otherwise the CHECK trigger will be checking a non-final
12444  * state of the row. Triggers fire in name order, so we ensure this by
12445  * using names like "RI_ConstraintTrigger_a_NNNN" for the action triggers
12446  * and "RI_ConstraintTrigger_c_NNNN" for the check triggers.
12447  */
12448  fk_trigger = makeNode(CreateTrigStmt);
12449  fk_trigger->replace = false;
12450  fk_trigger->isconstraint = true;
12451  fk_trigger->trigname = "RI_ConstraintTrigger_c";
12452  fk_trigger->relation = NULL;
12453 
12454  /* Either ON INSERT or ON UPDATE */
12455  if (on_insert)
12456  {
12457  fk_trigger->funcname = SystemFuncName("RI_FKey_check_ins");
12458  fk_trigger->events = TRIGGER_TYPE_INSERT;
12459  }
12460  else
12461  {
12462  fk_trigger->funcname = SystemFuncName("RI_FKey_check_upd");
12463  fk_trigger->events = TRIGGER_TYPE_UPDATE;
12464  }
12465 
12466  fk_trigger->args = NIL;
12467  fk_trigger->row = true;
12468  fk_trigger->timing = TRIGGER_TYPE_AFTER;
12469  fk_trigger->columns = NIL;
12470  fk_trigger->whenClause = NULL;
12471  fk_trigger->transitionRels = NIL;
12472  fk_trigger->deferrable = fkconstraint->deferrable;
12473  fk_trigger->initdeferred = fkconstraint->initdeferred;
12474  fk_trigger->constrrel = NULL;
12475 
12476  trigAddress = CreateTrigger(fk_trigger, NULL, myRelOid, refRelOid,
12477  constraintOid, indexOid, InvalidOid,
12478  parentTrigOid, NULL, true, false);
12479 
12480  /* Make changes-so-far visible */
12482 
12483  return trigAddress.objectId;
12484 }
12485 
12486 /*
12487  * createForeignKeyActionTriggers
12488  * Create the referenced-side "action" triggers that implement a foreign
12489  * key.
12490  *
12491  * Returns the OIDs of the so created triggers in *deleteTrigOid and
12492  * *updateTrigOid.
12493  */
12494 static void
12496  Oid constraintOid, Oid indexOid,
12497  Oid parentDelTrigger, Oid parentUpdTrigger,
12498  Oid *deleteTrigOid, Oid *updateTrigOid)
12499 {
12500  CreateTrigStmt *fk_trigger;
12501  ObjectAddress trigAddress;
12502 
12503  /*
12504  * Build and execute a CREATE CONSTRAINT TRIGGER statement for the ON
12505  * DELETE action on the referenced table.
12506  */
12507  fk_trigger = makeNode(CreateTrigStmt);
12508  fk_trigger->replace = false;
12509  fk_trigger->isconstraint = true;
12510  fk_trigger->trigname = "RI_ConstraintTrigger_a";
12511  fk_trigger->relation = NULL;
12512  fk_trigger->args = NIL;
12513  fk_trigger->row = true;
12514  fk_trigger->timing = TRIGGER_TYPE_AFTER;
12515  fk_trigger->events = TRIGGER_TYPE_DELETE;
12516  fk_trigger->columns = NIL;
12517  fk_trigger->whenClause = NULL;
12518  fk_trigger->transitionRels = NIL;
12519  fk_trigger->constrrel = NULL;
12520  switch (fkconstraint->fk_del_action)
12521  {
12523  fk_trigger->deferrable = fkconstraint->deferrable;
12524  fk_trigger->initdeferred = fkconstraint->initdeferred;
12525  fk_trigger->funcname = SystemFuncName("RI_FKey_noaction_del");
12526  break;
12528  fk_trigger->deferrable = false;
12529  fk_trigger->initdeferred = false;
12530  fk_trigger->funcname = SystemFuncName("RI_FKey_restrict_del");
12531  break;
12533  fk_trigger->deferrable = false;
12534  fk_trigger->initdeferred = false;
12535  fk_trigger->funcname = SystemFuncName("RI_FKey_cascade_del");
12536  break;
12538  fk_trigger->deferrable = false;
12539  fk_trigger->initdeferred = false;
12540  fk_trigger->funcname = SystemFuncName("RI_FKey_setnull_del");
12541  break;
12543  fk_trigger->deferrable = false;
12544  fk_trigger->initdeferred = false;
12545  fk_trigger->funcname = SystemFuncName("RI_FKey_setdefault_del");
12546  break;
12547  default:
12548  elog(ERROR, "unrecognized FK action type: %d",
12549  (int) fkconstraint->fk_del_action);
12550  break;
12551  }
12552 
12553  trigAddress = CreateTrigger(fk_trigger, NULL, refRelOid,
12554  RelationGetRelid(rel),
12555  constraintOid, indexOid, InvalidOid,
12556  parentDelTrigger, NULL, true, false);
12557  if (deleteTrigOid)
12558  *deleteTrigOid = trigAddress.objectId;
12559 
12560  /* Make changes-so-far visible */
12562 
12563  /*
12564  * Build and execute a CREATE CONSTRAINT TRIGGER statement for the ON
12565  * UPDATE action on the referenced table.
12566  */
12567  fk_trigger = makeNode(CreateTrigStmt);
12568  fk_trigger->replace = false;
12569  fk_trigger->isconstraint = true;
12570  fk_trigger->trigname = "RI_ConstraintTrigger_a";
12571  fk_trigger->relation = NULL;
12572  fk_trigger->args = NIL;
12573  fk_trigger->row = true;
12574  fk_trigger->timing = TRIGGER_TYPE_AFTER;
12575  fk_trigger->events = TRIGGER_TYPE_UPDATE;
12576  fk_trigger->columns = NIL;
12577  fk_trigger->whenClause = NULL;
12578  fk_trigger->transitionRels = NIL;
12579  fk_trigger->constrrel = NULL;
12580  switch (fkconstraint->fk_upd_action)
12581  {
12583  fk_trigger->deferrable = fkconstraint->deferrable;
12584  fk_trigger->initdeferred = fkconstraint->initdeferred;
12585  fk_trigger->funcname = SystemFuncName("RI_FKey_noaction_upd");
12586  break;
12588  fk_trigger->deferrable = false;
12589  fk_trigger->initdeferred = false;
12590  fk_trigger->funcname = SystemFuncName("RI_FKey_restrict_upd");
12591  break;
12593  fk_trigger->deferrable = false;
12594  fk_trigger->initdeferred = false;
12595  fk_trigger->funcname = SystemFuncName("RI_FKey_cascade_upd");
12596  break;
12598  fk_trigger->deferrable = false;
12599  fk_trigger->initdeferred = false;
12600  fk_trigger->funcname = SystemFuncName("RI_FKey_setnull_upd");
12601  break;
12603  fk_trigger->deferrable = false;
12604  fk_trigger->initdeferred = false;
12605  fk_trigger->funcname = SystemFuncName("RI_FKey_setdefault_upd");
12606  break;
12607  default:
12608  elog(ERROR, "unrecognized FK action type: %d",
12609  (int) fkconstraint->fk_upd_action);
12610  break;
12611  }
12612 
12613  trigAddress = CreateTrigger(fk_trigger, NULL, refRelOid,
12614  RelationGetRelid(rel),
12615  constraintOid, indexOid, InvalidOid,
12616  parentUpdTrigger, NULL, true, false);
12617  if (updateTrigOid)
12618  *updateTrigOid = trigAddress.objectId;
12619 }
12620 
12621 /*
12622  * createForeignKeyCheckTriggers
12623  * Create the referencing-side "check" triggers that implement a foreign
12624  * key.
12625  *
12626  * Returns the OIDs of the so created triggers in *insertTrigOid and
12627  * *updateTrigOid.
12628  */
12629 static void
12631  Constraint *fkconstraint, Oid constraintOid,
12632  Oid indexOid,
12633  Oid parentInsTrigger, Oid parentUpdTrigger,
12634  Oid *insertTrigOid, Oid *updateTrigOid)
12635 {
12636  *insertTrigOid = CreateFKCheckTrigger(myRelOid, refRelOid, fkconstraint,
12637  constraintOid, indexOid,
12638  parentInsTrigger, true);
12639  *updateTrigOid = CreateFKCheckTrigger(myRelOid, refRelOid, fkconstraint,
12640  constraintOid, indexOid,
12641  parentUpdTrigger, false);
12642 }
12643 
12644 /*
12645  * ALTER TABLE DROP CONSTRAINT
12646  *
12647  * Like DROP COLUMN, we can't use the normal ALTER TABLE recursion mechanism.
12648  */
12649 static void
12650 ATExecDropConstraint(Relation rel, const char *constrName,
12651  DropBehavior behavior, bool recurse,
12652  bool missing_ok, LOCKMODE lockmode)
12653 {
12654  Relation conrel;
12655  SysScanDesc scan;
12656  ScanKeyData skey[3];
12657  HeapTuple tuple;
12658  bool found = false;
12659 
12660  conrel = table_open(ConstraintRelationId, RowExclusiveLock);
12661 
12662  /*
12663  * Find and drop the target constraint
12664  */
12665  ScanKeyInit(&skey[0],
12666  Anum_pg_constraint_conrelid,
12667  BTEqualStrategyNumber, F_OIDEQ,
12669  ScanKeyInit(&skey[1],
12670  Anum_pg_constraint_contypid,
12671  BTEqualStrategyNumber, F_OIDEQ,
12673  ScanKeyInit(&skey[2],
12674  Anum_pg_constraint_conname,
12675  BTEqualStrategyNumber, F_NAMEEQ,
12676  CStringGetDatum(constrName));
12677  scan = systable_beginscan(conrel, ConstraintRelidTypidNameIndexId,
12678  true, NULL, 3, skey);
12679 
12680  /* There can be at most one matching row */
12681  if (HeapTupleIsValid(tuple = systable_getnext(scan)))
12682  {
12683  List *readyRels = NIL;
12684 
12685  dropconstraint_internal(rel, tuple, behavior, recurse, false,
12686  missing_ok, &readyRels, lockmode);
12687  found = true;
12688  }
12689 
12690  systable_endscan(scan);
12691 
12692  if (!found)
12693  {
12694  if (!missing_ok)
12695  ereport(ERROR,
12696  errcode(ERRCODE_UNDEFINED_OBJECT),
12697  errmsg("constraint \"%s\" of relation \"%s\" does not exist",
12698  constrName, RelationGetRelationName(rel)));
12699  else
12700  ereport(NOTICE,
12701  errmsg("constraint \"%s\" of relation \"%s\" does not exist, skipping",
12702  constrName, RelationGetRelationName(rel)));
12703  }
12704 
12705  table_close(conrel, RowExclusiveLock);
12706 }
12707 
12708 /*
12709  * Remove a constraint, using its pg_constraint tuple
12710  *
12711  * Implementation for ALTER TABLE DROP CONSTRAINT and ALTER TABLE ALTER COLUMN
12712  * DROP NOT NULL.
12713  *
12714  * Returns the address of the constraint being removed.
12715  */
12716 static ObjectAddress
12718  bool recurse, bool recursing, bool missing_ok, List **readyRels,
12719  LOCKMODE lockmode)
12720 {
12721  Relation conrel;
12722  Form_pg_constraint con;
12723  ObjectAddress conobj;
12724  List *children;
12725  ListCell *child;
12726  bool is_no_inherit_constraint = false;
12727  bool dropping_pk = false;
12728  char *constrName;
12729  List *unconstrained_cols = NIL;
12730  char *colname;
12731 
12732  if (list_member_oid(*readyRels, RelationGetRelid(rel)))
12733  return InvalidObjectAddress;
12734  *readyRels = lappend_oid(*readyRels, RelationGetRelid(rel));
12735 
12736  /* Guard against stack overflow due to overly deep inheritance tree. */
12738 
12739  /* At top level, permission check was done in ATPrepCmd, else do it */
12740  if (recursing)
12742 
12743  conrel = table_open(ConstraintRelationId, RowExclusiveLock);
12744 
12745  con = (Form_pg_constraint) GETSTRUCT(constraintTup);
12746  constrName = NameStr(con->conname);
12747 
12748  /* Don't allow drop of inherited constraints */
12749  if (con->coninhcount > 0 && !recursing)
12750  ereport(ERROR,
12751  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
12752  errmsg("cannot drop inherited constraint \"%s\" of relation \"%s\"",
12753  constrName, RelationGetRelationName(rel))));
12754 
12755  /*
12756  * See if we have a not-null constraint or a PRIMARY KEY. If so, we have
12757  * more checks and actions below, so obtain the list of columns that are
12758  * constrained by the constraint being dropped.
12759  */
12760  if (con->contype == CONSTRAINT_NOTNULL)
12761  {
12762  AttrNumber colnum = extractNotNullColumn(constraintTup);
12763 
12764  if (colnum != InvalidAttrNumber)
12765  unconstrained_cols = list_make1_int(colnum);
12766  }
12767  else if (con->contype == CONSTRAINT_PRIMARY)
12768  {
12769  Datum adatum;
12770  ArrayType *arr;
12771  int numkeys;
12772  bool isNull;
12773  int16 *attnums;
12774 
12775  dropping_pk = true;
12776 
12777  adatum = heap_getattr(constraintTup, Anum_pg_constraint_conkey,
12778  RelationGetDescr(conrel), &isNull);
12779  if (isNull)
12780  elog(ERROR, "null conkey for constraint %u", con->oid);
12781  arr = DatumGetArrayTypeP(adatum); /* ensure not toasted */
12782  numkeys = ARR_DIMS(arr)[0];
12783  if (ARR_NDIM(arr) != 1 ||
12784  numkeys < 0 ||
12785  ARR_HASNULL(arr) ||
12786  ARR_ELEMTYPE(arr) != INT2OID)
12787  elog(ERROR, "conkey is not a 1-D smallint array");
12788  attnums = (int16 *) ARR_DATA_PTR(arr);
12789 
12790  for (int i = 0; i < numkeys; i++)
12791  unconstrained_cols = lappend_int(unconstrained_cols, attnums[i]);
12792  }
12793 
12794  is_no_inherit_constraint = con->connoinherit;
12795 
12796  /*
12797  * If it's a foreign-key constraint, we'd better lock the referenced table
12798  * and check that that's not in use, just as we've already done for the
12799  * constrained table (else we might, eg, be dropping a trigger that has
12800  * unfired events). But we can/must skip that in the self-referential
12801  * case.
12802  */
12803  if (con->contype == CONSTRAINT_FOREIGN &&
12804  con->confrelid != RelationGetRelid(rel))
12805  {
12806  Relation frel;
12807 
12808  /* Must match lock taken by RemoveTriggerById: */
12809  frel = table_open(con->confrelid, AccessExclusiveLock);
12810  CheckTableNotInUse(frel, "ALTER TABLE");
12811  table_close(frel, NoLock);
12812  }
12813 
12814  /*
12815  * Perform the actual constraint deletion
12816  */
12817  ObjectAddressSet(conobj, ConstraintRelationId, con->oid);
12818  performDeletion(&conobj, behavior, 0);
12819 
12820  /*
12821  * If this was a NOT NULL or the primary key, the constrained columns must
12822  * have had pg_attribute.attnotnull set. See if we need to reset it, and
12823  * do so.
12824  */
12825  if (unconstrained_cols)
12826  {
12827  Relation attrel;
12828  Bitmapset *pkcols;
12829  Bitmapset *ircols;
12830  ListCell *lc;
12831 
12832  /* Make the above deletion visible */
12834 
12835  attrel = table_open(AttributeRelationId, RowExclusiveLock);
12836 
12837  /*
12838  * We want to test columns for their presence in the primary key, but
12839  * only if we're not dropping it.
12840  */
12841  pkcols = dropping_pk ? NULL :
12845 
12846  foreach(lc, unconstrained_cols)
12847  {
12849  HeapTuple atttup;
12850  HeapTuple contup;
12851  Form_pg_attribute attForm;
12852 
12853  /*
12854  * Obtain pg_attribute tuple and verify conditions on it. We use
12855  * a copy we can scribble on.
12856  */
12858  if (!HeapTupleIsValid(atttup))
12859  elog(ERROR, "cache lookup failed for attribute %d of relation %u",
12860  attnum, RelationGetRelid(rel));
12861  attForm = (Form_pg_attribute) GETSTRUCT(atttup);
12862 
12863  /*
12864  * Since the above deletion has been made visible, we can now
12865  * search for any remaining constraints on this column (or these
12866  * columns, in the case we're dropping a multicol primary key.)
12867  * Then, verify whether any further NOT NULL or primary key
12868  * exists, and reset attnotnull if none.
12869  *
12870  * However, if this is a generated identity column, abort the
12871  * whole thing with a specific error message, because the
12872  * constraint is required in that case.
12873  */
12875  if (contup ||
12877  pkcols))
12878  continue;
12879 
12880  /*
12881  * It's not valid to drop the not-null constraint for a GENERATED
12882  * AS IDENTITY column.
12883  */
12884  if (attForm->attidentity)
12885  ereport(ERROR,
12886  errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
12887  errmsg("column \"%s\" of relation \"%s\" is an identity column",
12889  false),
12890  RelationGetRelationName(rel)));
12891 
12892  /*
12893  * It's not valid to drop the not-null constraint for a column in
12894  * the replica identity index, either. (FULL is not affected.)
12895  */
12897  ereport(ERROR,
12898  errcode(ERRCODE_INVALID_TABLE_DEFINITION),
12899  errmsg("column \"%s\" is in index used as replica identity",
12900  get_attname(RelationGetRelid(rel), lfirst_int(lc), false)));
12901 
12902  /* Reset attnotnull */
12903  if (attForm->attnotnull)
12904  {
12905  attForm->attnotnull = false;
12906  CatalogTupleUpdate(attrel, &atttup->t_self, atttup);
12907  }
12908  }
12909  table_close(attrel, RowExclusiveLock);
12910  }
12911 
12912  /*
12913  * For partitioned tables, non-CHECK, non-NOT-NULL inherited constraints
12914  * are dropped via the dependency mechanism, so we're done here.
12915  */
12916  if (con->contype != CONSTRAINT_CHECK &&
12917  con->contype != CONSTRAINT_NOTNULL &&
12918  rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
12919  {
12920  table_close(conrel, RowExclusiveLock);
12921  return conobj;
12922  }
12923 
12924  /*
12925  * Propagate to children as appropriate. Unlike most other ALTER
12926  * routines, we have to do this one level of recursion at a time; we can't
12927  * use find_all_inheritors to do it in one pass.
12928  */
12929  if (!is_no_inherit_constraint)
12930  children = find_inheritance_children(RelationGetRelid(rel), lockmode);
12931  else
12932  children = NIL;
12933 
12934  /*
12935  * For a partitioned table, if partitions exist and we are told not to
12936  * recurse, it's a user error. It doesn't make sense to have a constraint
12937  * be defined only on the parent, especially if it's a partitioned table.
12938  */
12939  if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE &&
12940  children != NIL && !recurse)
12941  ereport(ERROR,
12942  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
12943  errmsg("cannot remove constraint from only the partitioned table when partitions exist"),
12944  errhint("Do not specify the ONLY keyword.")));
12945 
12946  /* For not-null constraints we recurse by column name */
12947  if (con->contype == CONSTRAINT_NOTNULL)
12948  colname = NameStr(TupleDescAttr(RelationGetDescr(rel),
12949  linitial_int(unconstrained_cols) - 1)->attname);
12950  else
12951  colname = NULL; /* keep compiler quiet */
12952 
12953  foreach(child, children)
12954  {
12955  Oid childrelid = lfirst_oid(child);
12956  Relation childrel;
12957  HeapTuple tuple;
12958  Form_pg_constraint childcon;
12959 
12960  if (list_member_oid(*readyRels, childrelid))
12961  continue; /* child already processed */
12962 
12963  /* find_inheritance_children already got lock */
12964  childrel = table_open(childrelid, NoLock);
12965  CheckTableNotInUse(childrel, "ALTER TABLE");
12966 
12967  /*
12968  * We search for not-null constraint by column number, and other
12969  * constraints by name.
12970  */
12971  if (con->contype == CONSTRAINT_NOTNULL)
12972  {
12973  tuple = findNotNullConstraint(childrelid, colname);
12974  if (!HeapTupleIsValid(tuple))
12975  elog(ERROR, "cache lookup failed for not-null constraint on column \"%s\" of relation %u",
12976  colname, RelationGetRelid(childrel));
12977  }
12978  else
12979  {
12980  SysScanDesc scan;
12981  ScanKeyData skey[3];
12982 
12983  ScanKeyInit(&skey[0],
12984  Anum_pg_constraint_conrelid,
12985  BTEqualStrategyNumber, F_OIDEQ,
12986  ObjectIdGetDatum(childrelid));
12987  ScanKeyInit(&skey[1],
12988  Anum_pg_constraint_contypid,
12989  BTEqualStrategyNumber, F_OIDEQ,
12991  ScanKeyInit(&skey[2],
12992  Anum_pg_constraint_conname,
12993  BTEqualStrategyNumber, F_NAMEEQ,
12994  CStringGetDatum(constrName));
12995  scan = systable_beginscan(conrel, ConstraintRelidTypidNameIndexId,
12996  true, NULL, 3, skey);
12997  /* There can only be one, so no need to loop */
12998  tuple = systable_getnext(scan);
12999  if (!HeapTupleIsValid(tuple))
13000  ereport(ERROR,
13001  (errcode(ERRCODE_UNDEFINED_OBJECT),
13002  errmsg("constraint \"%s\" of relation \"%s\" does not exist",
13003  constrName,
13004  RelationGetRelationName(childrel))));
13005  tuple = heap_copytuple(tuple);
13006  systable_endscan(scan);
13007  }
13008 
13009  childcon = (Form_pg_constraint) GETSTRUCT(tuple);
13010 
13011  /* Right now only CHECK and not-null constraints can be inherited */
13012  if (childcon->contype != CONSTRAINT_CHECK &&
13013  childcon->contype != CONSTRAINT_NOTNULL)
13014  elog(ERROR, "inherited constraint is not a CHECK or not-null constraint");
13015 
13016  if (childcon->coninhcount <= 0) /* shouldn't happen */
13017  elog(ERROR, "relation %u has non-inherited constraint \"%s\"",
13018  childrelid, NameStr(childcon->conname));
13019 
13020  if (recurse)
13021  {
13022  /*
13023  * If the child constraint has other definition sources, just
13024  * decrement its inheritance count; if not, recurse to delete it.
13025  */
13026  if (childcon->coninhcount == 1 && !childcon->conislocal)
13027  {
13028  /* Time to delete this child constraint, too */
13029  dropconstraint_internal(childrel, tuple, behavior,
13030  recurse, true, missing_ok, readyRels,
13031  lockmode);
13032  }
13033  else
13034  {
13035  /* Child constraint must survive my deletion */
13036  childcon->coninhcount--;
13037  CatalogTupleUpdate(conrel, &tuple->t_self, tuple);
13038 
13039  /* Make update visible */
13041  }
13042  }
13043  else
13044  {
13045  /*
13046  * If we were told to drop ONLY in this table (no recursion) and
13047  * there are no further parents for this constraint, we need to
13048  * mark the inheritors' constraints as locally defined rather than
13049  * inherited.
13050  */
13051  childcon->coninhcount--;
13052  if (childcon->coninhcount == 0)
13053  childcon->conislocal = true;
13054 
13055  CatalogTupleUpdate(conrel, &tuple->t_self, tuple);
13056 
13057  /* Make update visible */
13059  }
13060 
13061  heap_freetuple(tuple);
13062 
13063  table_close(childrel, NoLock);
13064  }
13065 
13066  /*
13067  * In addition, when dropping a primary key from a legacy-inheritance
13068  * parent table, we must recurse to children to mark the corresponding NOT
13069  * NULL constraint as no longer inherited, or drop it if this its last
13070  * reference.
13071  */
13072  if (con->contype == CONSTRAINT_PRIMARY &&
13073  rel->rd_rel->relkind == RELKIND_RELATION &&
13074  rel->rd_rel->relhassubclass)
13075  {
13076  List *colnames = NIL;
13077  ListCell *lc;
13078  List *pkready = NIL;
13079 
13080  /*
13081  * Because primary keys are always marked as NO INHERIT, we don't have
13082  * a list of children yet, so obtain one now.
13083  */
13084  children = find_inheritance_children(RelationGetRelid(rel), lockmode);
13085 
13086  /*
13087  * Find out the list of column names to process. Fortunately, we
13088  * already have the list of column numbers.
13089  */
13090  foreach(lc, unconstrained_cols)
13091  {
13092  colnames = lappend(colnames, get_attname(RelationGetRelid(rel),
13093  lfirst_int(lc), false));
13094  }
13095 
13096  foreach(child, children)
13097  {
13098  Oid childrelid = lfirst_oid(child);
13099  Relation childrel;
13100 
13101  if (list_member_oid(pkready, childrelid))
13102  continue; /* child already processed */
13103 
13104  /* find_inheritance_children already got lock */
13105  childrel = table_open(childrelid, NoLock);
13106  CheckTableNotInUse(childrel, "ALTER TABLE");
13107 
13108  foreach(lc, colnames)
13109  {
13110  HeapTuple contup;
13111  char *colName = lfirst(lc);
13112 
13113  contup = findNotNullConstraint(childrelid, colName);
13114  if (contup == NULL)
13115  elog(ERROR, "cache lookup failed for not-null constraint on column \"%s\", relation \"%s\"",
13116  colName, RelationGetRelationName(childrel));
13117 
13118  dropconstraint_internal(childrel, contup,
13119  DROP_RESTRICT, true, true,
13120  false, &pkready,
13121  lockmode);
13122  pkready = NIL;
13123  }
13124 
13125  table_close(childrel, NoLock);
13126 
13127  pkready = lappend_oid(pkready, childrelid);
13128  }
13129  }
13130 
13131  table_close(conrel, RowExclusiveLock);
13132 
13133  return conobj;
13134 }
13135 
13136 /*
13137  * ALTER COLUMN TYPE
13138  *
13139  * Unlike other subcommand types, we do parse transformation for ALTER COLUMN
13140  * TYPE during phase 1 --- the AlterTableCmd passed in here is already
13141  * transformed (and must be, because we rely on some transformed fields).
13142  *
13143  * The point of this is that the execution of all ALTER COLUMN TYPEs for a
13144  * table will be done "in parallel" during phase 3, so all the USING
13145  * expressions should be parsed assuming the original column types. Also,
13146  * this allows a USING expression to refer to a field that will be dropped.
13147  *
13148  * To make this work safely, AT_PASS_DROP then AT_PASS_ALTER_TYPE must be
13149  * the first two execution steps in phase 2; they must not see the effects
13150  * of any other subcommand types, since the USING expressions are parsed
13151  * against the unmodified table's state.
13152  */
13153 static void
13155  AlteredTableInfo *tab, Relation rel,
13156  bool recurse, bool recursing,
13157  AlterTableCmd *cmd, LOCKMODE lockmode,
13158  AlterTableUtilityContext *context)
13159 {
13160  char *colName = cmd->name;
13161  ColumnDef *def = (ColumnDef *) cmd->def;
13162  TypeName *typeName = def->typeName;
13163  Node *transform = def->cooked_default;
13164  HeapTuple tuple;
13165  Form_pg_attribute attTup;
13167  Oid targettype;
13168  int32 targettypmod;
13169  Oid targetcollid;
13171  ParseState *pstate = make_parsestate(NULL);
13172  AclResult aclresult;
13173  bool is_expr;
13174 
13175  if (rel->rd_rel->reloftype && !recursing)
13176  ereport(ERROR,
13177  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
13178  errmsg("cannot alter column type of typed table")));
13179 
13180  /* lookup the attribute so we can check inheritance status */
13181  tuple = SearchSysCacheAttName(RelationGetRelid(rel), colName);
13182  if (!HeapTupleIsValid(tuple))
13183  ereport(ERROR,
13184  (errcode(ERRCODE_UNDEFINED_COLUMN),
13185  errmsg("column \"%s\" of relation \"%s\" does not exist",
13186  colName, RelationGetRelationName(rel))));
13187  attTup = (Form_pg_attribute) GETSTRUCT(tuple);
13188  attnum = attTup->attnum;
13189 
13190  /* Can't alter a system attribute */
13191  if (attnum <= 0)
13192  ereport(ERROR,
13193  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
13194  errmsg("cannot alter system column \"%s\"",
13195  colName)));
13196 
13197  /*
13198  * Don't alter inherited columns. At outer level, there had better not be
13199  * any inherited definition; when recursing, we assume this was checked at
13200  * the parent level (see below).
13201  */
13202  if (attTup->attinhcount > 0 && !recursing)
13203  ereport(ERROR,
13204  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
13205  errmsg("cannot alter inherited column \"%s\"",
13206  colName)));
13207 
13208  /* Don't alter columns used in the partition key */
13209  if (has_partition_attrs(rel,
13211  &is_expr))
13212  ereport(ERROR,
13213  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
13214  errmsg("cannot alter column \"%s\" because it is part of the partition key of relation \"%s\"",
13215  colName, RelationGetRelationName(rel))));
13216 
13217  /* Look up the target type */
13218  typenameTypeIdAndMod(NULL, typeName, &targettype, &targettypmod);
13219 
13220  aclresult = object_aclcheck(TypeRelationId, targettype, GetUserId(), ACL_USAGE);
13221  if (aclresult != ACLCHECK_OK)
13222  aclcheck_error_type(aclresult, targettype);
13223 
13224  /* And the collation */
13225  targetcollid = GetColumnDefCollation(NULL, def, targettype);
13226 
13227  /* make sure datatype is legal for a column */
13228  CheckAttributeType(colName, targettype, targetcollid,
13229  list_make1_oid(rel->rd_rel->reltype),
13230  0);
13231 
13232  if (tab->relkind == RELKIND_RELATION ||
13233  tab->relkind == RELKIND_PARTITIONED_TABLE)
13234  {
13235  /*
13236  * Set up an expression to transform the old data value to the new
13237  * type. If a USING option was given, use the expression as
13238  * transformed by transformAlterTableStmt, else just take the old
13239  * value and try to coerce it. We do this first so that type
13240  * incompatibility can be detected before we waste effort, and because
13241  * we need the expression to be parsed against the original table row
13242  * type.
13243  */
13244  if (!transform)
13245  {
13246  transform = (Node *) makeVar(1, attnum,
13247  attTup->atttypid, attTup->atttypmod,
13248  attTup->attcollation,
13249  0);
13250  }
13251 
13252  transform = coerce_to_target_type(pstate,
13253  transform, exprType(transform),
13254  targettype, targettypmod,
13257  -1);
13258  if (transform == NULL)
13259  {
13260  /* error text depends on whether USING was specified or not */
13261  if (def->cooked_default != NULL)
13262  ereport(ERROR,
13263  (errcode(ERRCODE_DATATYPE_MISMATCH),
13264  errmsg("result of USING clause for column \"%s\""
13265  " cannot be cast automatically to type %s",
13266  colName, format_type_be(targettype)),
13267  errhint("You might need to add an explicit cast.")));
13268  else
13269  ereport(ERROR,
13270  (errcode(ERRCODE_DATATYPE_MISMATCH),
13271  errmsg("column \"%s\" cannot be cast automatically to type %s",
13272  colName, format_type_be(targettype)),
13273  /* translator: USING is SQL, don't translate it */
13274  errhint("You might need to specify \"USING %s::%s\".",
13275  quote_identifier(colName),
13276  format_type_with_typemod(targettype,
13277  targettypmod))));
13278  }
13279 
13280  /* Fix collations after all else */
13281  assign_expr_collations(pstate, transform);
13282 
13283  /* Plan the expr now so we can accurately assess the need to rewrite. */
13284  transform = (Node *) expression_planner((Expr *) transform);
13285 
13286  /*
13287  * Add a work queue item to make ATRewriteTable update the column
13288  * contents.
13289  */
13291  newval->attnum = attnum;
13292  newval->expr = (Expr *) transform;
13293  newval->is_generated = false;
13294 
13295  tab->newvals = lappend(tab->newvals, newval);
13296  if (ATColumnChangeRequiresRewrite(transform, attnum))
13298  }
13299  else if (transform)
13300  ereport(ERROR,
13301  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
13302  errmsg("\"%s\" is not a table",
13303  RelationGetRelationName(rel))));
13304 
13305  if (!RELKIND_HAS_STORAGE(tab->relkind))
13306  {
13307  /*
13308  * For relations without storage, do this check now. Regular tables
13309  * will check it later when the table is being rewritten.
13310  */
13311  find_composite_type_dependencies(rel->rd_rel->reltype, rel, NULL);
13312  }
13313 
13314  ReleaseSysCache(tuple);
13315 
13316  /*
13317  * Recurse manually by queueing a new command for each child, if
13318  * necessary. We cannot apply ATSimpleRecursion here because we need to
13319  * remap attribute numbers in the USING expression, if any.
13320  *
13321  * If we are told not to recurse, there had better not be any child
13322  * tables; else the alter would put them out of step.
13323  */
13324  if (recurse)
13325  {
13326  Oid relid = RelationGetRelid(rel);
13327  List *child_oids,
13328  *child_numparents;
13329  ListCell *lo,
13330  *li;
13331 
13332  child_oids = find_all_inheritors(relid, lockmode,
13333  &child_numparents);
13334 
13335  /*
13336  * find_all_inheritors does the recursive search of the inheritance
13337  * hierarchy, so all we have to do is process all of the relids in the
13338  * list that it returns.
13339  */
13340  forboth(lo, child_oids, li, child_numparents)
13341  {
13342  Oid childrelid = lfirst_oid(lo);
13343  int numparents = lfirst_int(li);
13344  Relation childrel;
13345  HeapTuple childtuple;
13346  Form_pg_attribute childattTup;
13347 
13348  if (childrelid == relid)
13349  continue;
13350 
13351  /* find_all_inheritors already got lock */
13352  childrel = relation_open(childrelid, NoLock);
13353  CheckTableNotInUse(childrel, "ALTER TABLE");
13354 
13355  /*
13356  * Verify that the child doesn't have any inherited definitions of
13357  * this column that came from outside this inheritance hierarchy.
13358  * (renameatt makes a similar test, though in a different way
13359  * because of its different recursion mechanism.)
13360  */
13361  childtuple = SearchSysCacheAttName(RelationGetRelid(childrel),
13362  colName);
13363  if (!HeapTupleIsValid(childtuple))
13364  ereport(ERROR,
13365  (errcode(ERRCODE_UNDEFINED_COLUMN),
13366  errmsg("column \"%s\" of relation \"%s\" does not exist",
13367  colName, RelationGetRelationName(childrel))));
13368  childattTup = (Form_pg_attribute) GETSTRUCT(childtuple);
13369 
13370  if (childattTup->attinhcount > numparents)
13371  ereport(ERROR,
13372  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
13373  errmsg("cannot alter inherited column \"%s\" of relation \"%s\"",
13374  colName, RelationGetRelationName(childrel))));
13375 
13376  ReleaseSysCache(childtuple);
13377 
13378  /*
13379  * Remap the attribute numbers. If no USING expression was
13380  * specified, there is no need for this step.
13381  */
13382  if (def->cooked_default)
13383  {
13384  AttrMap *attmap;
13385  bool found_whole_row;
13386 
13387  /* create a copy to scribble on */
13388  cmd = copyObject(cmd);
13389 
13390  attmap = build_attrmap_by_name(RelationGetDescr(childrel),
13391  RelationGetDescr(rel),
13392  false);
13393  ((ColumnDef *) cmd->def)->cooked_default =
13395  1, 0,
13396  attmap,
13397  InvalidOid, &found_whole_row);
13398  if (found_whole_row)
13399  ereport(ERROR,
13400  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
13401  errmsg("cannot convert whole-row table reference"),
13402  errdetail("USING expression contains a whole-row table reference.")));
13403  pfree(attmap);
13404  }
13405  ATPrepCmd(wqueue, childrel, cmd, false, true, lockmode, context);
13406  relation_close(childrel, NoLock);
13407  }
13408  }
13409  else if (!recursing &&
13411  ereport(ERROR,
13412  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
13413  errmsg("type of inherited column \"%s\" must be changed in child tables too",
13414  colName)));
13415 
13416  if (tab->relkind == RELKIND_COMPOSITE_TYPE)
13417  ATTypedTableRecursion(wqueue, rel, cmd, lockmode, context);
13418 }
13419 
13420 /*
13421  * When the data type of a column is changed, a rewrite might not be required
13422  * if the new type is sufficiently identical to the old one, and the USING
13423  * clause isn't trying to insert some other value. It's safe to skip the
13424  * rewrite in these cases:
13425  *
13426  * - the old type is binary coercible to the new type
13427  * - the new type is an unconstrained domain over the old type
13428  * - {NEW,OLD} or {OLD,NEW} is {timestamptz,timestamp} and the timezone is UTC
13429  *
13430  * In the case of a constrained domain, we could get by with scanning the
13431  * table and checking the constraint rather than actually rewriting it, but we
13432  * don't currently try to do that.
13433  */
13434 static bool
13436 {
13437  Assert(expr != NULL);
13438 
13439  for (;;)
13440  {
13441  /* only one varno, so no need to check that */
13442  if (IsA(expr, Var) && ((Var *) expr)->varattno == varattno)
13443  return false;
13444  else if (IsA(expr, RelabelType))
13445  expr = (Node *) ((RelabelType *) expr)->arg;
13446  else if (IsA(expr, CoerceToDomain))
13447  {
13448  CoerceToDomain *d = (CoerceToDomain *) expr;
13449 
13451  return true;
13452  expr = (Node *) d->arg;
13453  }
13454  else if (IsA(expr, FuncExpr))
13455  {
13456  FuncExpr *f = (FuncExpr *) expr;
13457 
13458  switch (f->funcid)
13459  {
13460  case F_TIMESTAMPTZ_TIMESTAMP:
13461  case F_TIMESTAMP_TIMESTAMPTZ:
13463  return true;
13464  else
13465  expr = linitial(f->args);
13466  break;
13467  default:
13468  return true;
13469  }
13470  }
13471  else
13472  return true;
13473  }
13474 }
13475 
13476 /*
13477  * ALTER COLUMN .. SET DATA TYPE
13478  *
13479  * Return the address of the modified column.
13480  */
13481 static ObjectAddress
13483  AlterTableCmd *cmd, LOCKMODE lockmode)
13484 {
13485  char *colName = cmd->name;
13486  ColumnDef *def = (ColumnDef *) cmd->def;
13487  TypeName *typeName = def->typeName;
13488  HeapTuple heapTup;
13489  Form_pg_attribute attTup,
13490  attOldTup;
13492  HeapTuple typeTuple;
13493  Form_pg_type tform;
13494  Oid targettype;
13495  int32 targettypmod;
13496  Oid targetcollid;
13497  Node *defaultexpr;
13498  Relation attrelation;
13499  Relation depRel;
13500  ScanKeyData key[3];
13501  SysScanDesc scan;
13502  HeapTuple depTup;
13503  ObjectAddress address;
13504 
13505  /*
13506  * Clear all the missing values if we're rewriting the table, since this
13507  * renders them pointless.
13508  */
13509  if (tab->rewrite)
13510  {
13511  Relation newrel;
13512 
13513  newrel = table_open(RelationGetRelid(rel), NoLock);
13514  RelationClearMissing(newrel);
13515  relation_close(newrel, NoLock);
13516  /* make sure we don't conflict with later attribute modifications */
13518  }
13519 
13520  attrelation = table_open(AttributeRelationId, RowExclusiveLock);
13521 
13522  /* Look up the target column */
13523  heapTup = SearchSysCacheCopyAttName(RelationGetRelid(rel), colName);
13524  if (!HeapTupleIsValid(heapTup)) /* shouldn't happen */
13525  ereport(ERROR,
13526  (errcode(ERRCODE_UNDEFINED_COLUMN),
13527  errmsg("column \"%s\" of relation \"%s\" does not exist",
13528  colName, RelationGetRelationName(rel))));
13529  attTup = (Form_pg_attribute) GETSTRUCT(heapTup);
13530  attnum = attTup->attnum;
13531  attOldTup = TupleDescAttr(tab->oldDesc, attnum - 1);
13532 
13533  /* Check for multiple ALTER TYPE on same column --- can't cope */
13534  if (attTup->atttypid != attOldTup->atttypid ||
13535  attTup->atttypmod != attOldTup->atttypmod)
13536  ereport(ERROR,
13537  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
13538  errmsg("cannot alter type of column \"%s\" twice",
13539  colName)));
13540 
13541  /* Look up the target type (should not fail, since prep found it) */
13542  typeTuple = typenameType(NULL, typeName, &targettypmod);
13543  tform = (Form_pg_type) GETSTRUCT(typeTuple);
13544  targettype = tform->oid;
13545  /* And the collation */
13546  targetcollid = GetColumnDefCollation(NULL, def, targettype);
13547 
13548  /*
13549  * If there is a default expression for the column, get it and ensure we
13550  * can coerce it to the new datatype. (We must do this before changing
13551  * the column type, because build_column_default itself will try to
13552  * coerce, and will not issue the error message we want if it fails.)
13553  *
13554  * We remove any implicit coercion steps at the top level of the old
13555  * default expression; this has been agreed to satisfy the principle of
13556  * least surprise. (The conversion to the new column type should act like
13557  * it started from what the user sees as the stored expression, and the
13558  * implicit coercions aren't going to be shown.)
13559  */
13560  if (attTup->atthasdef)
13561  {
13562  defaultexpr = build_column_default(rel, attnum);
13563  Assert(defaultexpr);
13564  defaultexpr = strip_implicit_coercions(defaultexpr);
13565  defaultexpr = coerce_to_target_type(NULL, /* no UNKNOWN params */
13566  defaultexpr, exprType(defaultexpr),
13567  targettype, targettypmod,
13570  -1);
13571  if (defaultexpr == NULL)
13572  {
13573  if (attTup->attgenerated)
13574  ereport(ERROR,
13575  (errcode(ERRCODE_DATATYPE_MISMATCH),
13576  errmsg("generation expression for column \"%s\" cannot be cast automatically to type %s",
13577  colName, format_type_be(targettype))));
13578  else
13579  ereport(ERROR,
13580  (errcode(ERRCODE_DATATYPE_MISMATCH),
13581  errmsg("default for column \"%s\" cannot be cast automatically to type %s",
13582  colName, format_type_be(targettype))));
13583  }
13584  }
13585  else
13586  defaultexpr = NULL;
13587 
13588  /*
13589  * Find everything that depends on the column (constraints, indexes, etc),
13590  * and record enough information to let us recreate the objects.
13591  *
13592  * The actual recreation does not happen here, but only after we have
13593  * performed all the individual ALTER TYPE operations. We have to save
13594  * the info before executing ALTER TYPE, though, else the deparser will
13595  * get confused.
13596  */
13598 
13599  /*
13600  * Now scan for dependencies of this column on other things. The only
13601  * things we should find are the dependency on the column datatype and
13602  * possibly a collation dependency. Those can be removed.
13603  */
13604  depRel = table_open(DependRelationId, RowExclusiveLock);
13605 
13606  ScanKeyInit(&key[0],
13607  Anum_pg_depend_classid,
13608  BTEqualStrategyNumber, F_OIDEQ,
13609  ObjectIdGetDatum(RelationRelationId));
13610  ScanKeyInit(&key[1],
13611  Anum_pg_depend_objid,
13612  BTEqualStrategyNumber, F_OIDEQ,
13614  ScanKeyInit(&key[2],
13615  Anum_pg_depend_objsubid,
13616  BTEqualStrategyNumber, F_INT4EQ,
13618 
13619  scan = systable_beginscan(depRel, DependDependerIndexId, true,
13620  NULL, 3, key);
13621 
13622  while (HeapTupleIsValid(depTup = systable_getnext(scan)))
13623  {
13624  Form_pg_depend foundDep = (Form_pg_depend) GETSTRUCT(depTup);
13625  ObjectAddress foundObject;
13626 
13627  foundObject.classId = foundDep->refclassid;
13628  foundObject.objectId = foundDep->refobjid;
13629  foundObject.objectSubId = foundDep->refobjsubid;
13630 
13631  if (foundDep->deptype != DEPENDENCY_NORMAL)
13632  elog(ERROR, "found unexpected dependency type '%c'",
13633  foundDep->deptype);
13634  if (!(foundDep->refclassid == TypeRelationId &&
13635  foundDep->refobjid == attTup->atttypid) &&
13636  !(foundDep->refclassid == CollationRelationId &&
13637  foundDep->refobjid == attTup->attcollation))
13638  elog(ERROR, "found unexpected dependency for column: %s",
13639  getObjectDescription(&foundObject, false));
13640 
13641  CatalogTupleDelete(depRel, &depTup->t_self);
13642  }
13643 
13644  systable_endscan(scan);
13645 
13646  table_close(depRel, RowExclusiveLock);
13647 
13648  /*
13649  * Here we go --- change the recorded column type and collation. (Note
13650  * heapTup is a copy of the syscache entry, so okay to scribble on.) First
13651  * fix up the missing value if any.
13652  */
13653  if (attTup->atthasmissing)
13654  {
13655  Datum missingval;
13656  bool missingNull;
13657 
13658  /* if rewrite is true the missing value should already be cleared */
13659  Assert(tab->rewrite == 0);
13660 
13661  /* Get the missing value datum */
13662  missingval = heap_getattr(heapTup,
13663  Anum_pg_attribute_attmissingval,
13664  attrelation->rd_att,
13665  &missingNull);
13666 
13667  /* if it's a null array there is nothing to do */
13668 
13669  if (!missingNull)
13670  {
13671  /*
13672  * Get the datum out of the array and repack it in a new array
13673  * built with the new type data. We assume that since the table
13674  * doesn't need rewriting, the actual Datum doesn't need to be
13675  * changed, only the array metadata.
13676  */
13677 
13678  int one = 1;
13679  bool isNull;
13680  Datum valuesAtt[Natts_pg_attribute] = {0};
13681  bool nullsAtt[Natts_pg_attribute] = {0};
13682  bool replacesAtt[Natts_pg_attribute] = {0};
13683  HeapTuple newTup;
13684 
13685  missingval = array_get_element(missingval,
13686  1,
13687  &one,
13688  0,
13689  attTup->attlen,
13690  attTup->attbyval,
13691  attTup->attalign,
13692  &isNull);
13693  missingval = PointerGetDatum(construct_array(&missingval,
13694  1,
13695  targettype,
13696  tform->typlen,
13697  tform->typbyval,
13698  tform->typalign));
13699 
13700  valuesAtt[Anum_pg_attribute_attmissingval - 1] = missingval;
13701  replacesAtt[Anum_pg_attribute_attmissingval - 1] = true;
13702  nullsAtt[Anum_pg_attribute_attmissingval - 1] = false;
13703 
13704  newTup = heap_modify_tuple(heapTup, RelationGetDescr(attrelation),
13705  valuesAtt, nullsAtt, replacesAtt);
13706  heap_freetuple(heapTup);
13707  heapTup = newTup;
13708  attTup = (Form_pg_attribute) GETSTRUCT(heapTup);
13709  }
13710  }
13711 
13712  attTup->atttypid = targettype;
13713  attTup->atttypmod = targettypmod;
13714  attTup->attcollation = targetcollid;
13715  if (list_length(typeName->arrayBounds) > PG_INT16_MAX)
13716  ereport(ERROR,
13717  errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
13718  errmsg("too many array dimensions"));
13719  attTup->attndims = list_length(typeName->arrayBounds);
13720  attTup->attlen = tform->typlen;
13721  attTup->attbyval = tform->typbyval;
13722  attTup->attalign = tform->typalign;
13723  attTup->attstorage = tform->typstorage;
13724  attTup->attcompression = InvalidCompressionMethod;
13725 
13726  ReleaseSysCache(typeTuple);
13727 
13728  CatalogTupleUpdate(attrelation, &heapTup->t_self, heapTup);
13729 
13730  table_close(attrelation, RowExclusiveLock);
13731 
13732  /* Install dependencies on new datatype and collation */
13735 
13736  /*
13737  * Drop any pg_statistic entry for the column, since it's now wrong type
13738  */
13740 
13741  InvokeObjectPostAlterHook(RelationRelationId,
13742  RelationGetRelid(rel), attnum);
13743 
13744  /*
13745  * Update the default, if present, by brute force --- remove and re-add
13746  * the default. Probably unsafe to take shortcuts, since the new version
13747  * may well have additional dependencies. (It's okay to do this now,
13748  * rather than after other ALTER TYPE commands, since the default won't
13749  * depend on other column types.)
13750  */
13751  if (defaultexpr)
13752  {
13753  /*
13754  * If it's a GENERATED default, drop its dependency records, in
13755  * particular its INTERNAL dependency on the column, which would
13756  * otherwise cause dependency.c to refuse to perform the deletion.
13757  */
13758  if (attTup->attgenerated)
13759  {
13760  Oid attrdefoid = GetAttrDefaultOid(RelationGetRelid(rel), attnum);
13761 
13762  if (!OidIsValid(attrdefoid))
13763  elog(ERROR, "could not find attrdef tuple for relation %u attnum %d",
13764  RelationGetRelid(rel), attnum);
13765  (void) deleteDependencyRecordsFor(AttrDefaultRelationId, attrdefoid, false);
13766  }
13767 
13768  /*
13769  * Make updates-so-far visible, particularly the new pg_attribute row
13770  * which will be updated again.
13771  */
13773 
13774  /*
13775  * We use RESTRICT here for safety, but at present we do not expect
13776  * anything to depend on the default.
13777  */
13779  true);
13780 
13781  StoreAttrDefault(rel, attnum, defaultexpr, true, false);
13782  }
13783 
13784  ObjectAddressSubSet(address, RelationRelationId,
13785  RelationGetRelid(rel), attnum);
13786 
13787  /* Cleanup */
13788  heap_freetuple(heapTup);
13789 
13790  return address;
13791 }
13792 
13793 /*
13794  * Subroutine for ATExecAlterColumnType and ATExecSetExpression: Find everything
13795  * that depends on the column (constraints, indexes, etc), and record enough
13796  * information to let us recreate the objects.
13797  */
13798 static void
13800  Relation rel, AttrNumber attnum, const char *colName)
13801 {
13802  Relation depRel;
13803  ScanKeyData key[3];
13804  SysScanDesc scan;
13805  HeapTuple depTup;
13806 
13807  Assert(subtype == AT_AlterColumnType || subtype == AT_SetExpression);
13808 
13809  depRel = table_open(DependRelationId, RowExclusiveLock);
13810 
13811  ScanKeyInit(&key[0],
13812  Anum_pg_depend_refclassid,
13813  BTEqualStrategyNumber, F_OIDEQ,
13814  ObjectIdGetDatum(RelationRelationId));
13815  ScanKeyInit(&key[1],
13816  Anum_pg_depend_refobjid,
13817  BTEqualStrategyNumber, F_OIDEQ,
13819  ScanKeyInit(&key[2],
13820  Anum_pg_depend_refobjsubid,
13821  BTEqualStrategyNumber, F_INT4EQ,
13823 
13824  scan = systable_beginscan(depRel, DependReferenceIndexId, true,
13825  NULL, 3, key);
13826 
13827  while (HeapTupleIsValid(depTup = systable_getnext(scan)))
13828  {
13829  Form_pg_depend foundDep = (Form_pg_depend) GETSTRUCT(depTup);
13830  ObjectAddress foundObject;
13831 
13832  foundObject.classId = foundDep->classid;
13833  foundObject.objectId = foundDep->objid;
13834  foundObject.objectSubId = foundDep->objsubid;
13835 
13836  switch (getObjectClass(&foundObject))
13837  {
13838  case OCLASS_CLASS:
13839  {
13840  char relKind = get_rel_relkind(foundObject.objectId);
13841 
13842  if (relKind == RELKIND_INDEX ||
13843  relKind == RELKIND_PARTITIONED_INDEX)
13844  {
13845  Assert(foundObject.objectSubId == 0);
13846  RememberIndexForRebuilding(foundObject.objectId, tab);
13847  }
13848  else if (relKind == RELKIND_SEQUENCE)
13849  {
13850  /*
13851  * This must be a SERIAL column's sequence. We need
13852  * not do anything to it.
13853  */
13854  Assert(foundObject.objectSubId == 0);
13855  }
13856  else
13857  {
13858  /* Not expecting any other direct dependencies... */
13859  elog(ERROR, "unexpected object depending on column: %s",
13860  getObjectDescription(&foundObject, false));
13861  }
13862  break;
13863  }
13864 
13865  case OCLASS_CONSTRAINT:
13866  Assert(foundObject.objectSubId == 0);
13867  RememberConstraintForRebuilding(foundObject.objectId, tab);
13868  break;
13869 
13870  case OCLASS_REWRITE:
13871  /* XXX someday see if we can cope with revising views */
13872  if (subtype == AT_AlterColumnType)
13873  ereport(ERROR,
13874  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
13875  errmsg("cannot alter type of a column used by a view or rule"),
13876  errdetail("%s depends on column \"%s\"",
13877  getObjectDescription(&foundObject, false),
13878  colName)));
13879  break;
13880 
13881  case OCLASS_TRIGGER:
13882 
13883  /*
13884  * A trigger can depend on a column because the column is
13885  * specified as an update target, or because the column is
13886  * used in the trigger's WHEN condition. The first case would
13887  * not require any extra work, but the second case would
13888  * require updating the WHEN expression, which will take a
13889  * significant amount of new code. Since we can't easily tell
13890  * which case applies, we punt for both. FIXME someday.
13891  */
13892  if (subtype == AT_AlterColumnType)
13893  ereport(ERROR,
13894  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
13895  errmsg("cannot alter type of a column used in a trigger definition"),
13896  errdetail("%s depends on column \"%s\"",
13897  getObjectDescription(&foundObject, false),
13898  colName)));
13899  break;
13900 
13901  case OCLASS_POLICY:
13902 
13903  /*
13904  * A policy can depend on a column because the column is
13905  * specified in the policy's USING or WITH CHECK qual
13906  * expressions. It might be possible to rewrite and recheck
13907  * the policy expression, but punt for now. It's certainly
13908  * easy enough to remove and recreate the policy; still, FIXME
13909  * someday.
13910  */
13911  if (subtype == AT_AlterColumnType)
13912  ereport(ERROR,
13913  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
13914  errmsg("cannot alter type of a column used in a policy definition"),
13915  errdetail("%s depends on column \"%s\"",
13916  getObjectDescription(&foundObject, false),
13917  colName)));
13918  break;
13919 
13920  case OCLASS_DEFAULT:
13921  {
13923 
13924  if (col.objectId == RelationGetRelid(rel) &&
13925  col.objectSubId == attnum)
13926  {
13927  /*
13928  * Ignore the column's own default expression. The
13929  * caller deals with it.
13930  */
13931  }
13932  else
13933  {
13934  /*
13935  * This must be a reference from the expression of a
13936  * generated column elsewhere in the same table.
13937  * Changing the type/generated expression of a column
13938  * that is used by a generated column is not allowed
13939  * by SQL standard, so just punt for now. It might be
13940  * doable with some thinking and effort.
13941  */
13942  if (subtype == AT_AlterColumnType)
13943  ereport(ERROR,
13944  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
13945  errmsg("cannot alter type of a column used by a generated column"),
13946  errdetail("Column \"%s\" is used by generated column \"%s\".",
13947  colName,
13948  get_attname(col.objectId,
13949  col.objectSubId,
13950  false))));
13951  }
13952  break;
13953  }
13954 
13955  case OCLASS_STATISTIC_EXT:
13956 
13957  /*
13958  * Give the extended-stats machinery a chance to fix anything
13959  * that this column type change would break.
13960  */
13961  RememberStatisticsForRebuilding(foundObject.objectId, tab);
13962  break;
13963 
13964  case OCLASS_PROC:
13965  case OCLASS_TYPE:
13966  case OCLASS_CAST:
13967  case OCLASS_COLLATION:
13968  case OCLASS_CONVERSION:
13969  case OCLASS_LANGUAGE:
13970  case OCLASS_LARGEOBJECT:
13971  case OCLASS_OPERATOR:
13972  case OCLASS_OPCLASS:
13973  case OCLASS_OPFAMILY:
13974  case OCLASS_AM:
13975  case OCLASS_AMOP:
13976  case OCLASS_AMPROC:
13977  case OCLASS_SCHEMA:
13978  case OCLASS_TSPARSER:
13979  case OCLASS_TSDICT:
13980  case OCLASS_TSTEMPLATE:
13981  case OCLASS_TSCONFIG:
13982  case OCLASS_ROLE:
13984  case OCLASS_DATABASE:
13985  case OCLASS_TBLSPACE:
13986  case OCLASS_FDW:
13987  case OCLASS_FOREIGN_SERVER:
13988  case OCLASS_USER_MAPPING:
13989  case OCLASS_DEFACL:
13990  case OCLASS_EXTENSION:
13991  case OCLASS_EVENT_TRIGGER:
13992  case OCLASS_PARAMETER_ACL:
13993  case OCLASS_PUBLICATION:
13996  case OCLASS_SUBSCRIPTION:
13997  case OCLASS_TRANSFORM:
13998 
13999  /*
14000  * We don't expect any of these sorts of objects to depend on
14001  * a column.
14002  */
14003  elog(ERROR, "unexpected object depending on column: %s",
14004  getObjectDescription(&foundObject, false));
14005  break;
14006 
14007  /*
14008  * There's intentionally no default: case here; we want the
14009  * compiler to warn if a new OCLASS hasn't been handled above.
14010  */
14011  }
14012  }
14013 
14014  systable_endscan(scan);
14015  table_close(depRel, NoLock);
14016 }
14017 
14018 /*
14019  * Subroutine for ATExecAlterColumnType: remember that a replica identity
14020  * needs to be reset.
14021  */
14022 static void
14024 {
14025  if (!get_index_isreplident(indoid))
14026  return;
14027 
14028  if (tab->replicaIdentityIndex)
14029  elog(ERROR, "relation %u has multiple indexes marked as replica identity", tab->relid);
14030 
14031  tab->replicaIdentityIndex = get_rel_name(indoid);
14032 }
14033 
14034 /*
14035  * Subroutine for ATExecAlterColumnType: remember any clustered index.
14036  */
14037 static void
14039 {
14040  if (!get_index_isclustered(indoid))
14041  return;
14042 
14043  if (tab->clusterOnIndex)
14044  elog(ERROR, "relation %u has multiple clustered indexes", tab->relid);
14045 
14046  tab->clusterOnIndex = get_rel_name(indoid);
14047 }
14048 
14049 /*
14050  * Subroutine for ATExecAlterColumnType: remember that a constraint needs
14051  * to be rebuilt (which we might already know).
14052  */
14053 static void
14055 {
14056  /*
14057  * This de-duplication check is critical for two independent reasons: we
14058  * mustn't try to recreate the same constraint twice, and if a constraint
14059  * depends on more than one column whose type is to be altered, we must
14060  * capture its definition string before applying any of the column type
14061  * changes. ruleutils.c will get confused if we ask again later.
14062  */
14063  if (!list_member_oid(tab->changedConstraintOids, conoid))
14064  {
14065  /* OK, capture the constraint's existing definition string */
14066  char *defstring = pg_get_constraintdef_command(conoid);
14067  Oid indoid;
14068 
14070  conoid);
14072  defstring);
14073 
14074  /*
14075  * For the index of a constraint, if any, remember if it is used for
14076  * the table's replica identity or if it is a clustered index, so that
14077  * ATPostAlterTypeCleanup() can queue up commands necessary to restore
14078  * those properties.
14079  */
14080  indoid = get_constraint_index(conoid);
14081  if (OidIsValid(indoid))
14082  {
14084  RememberClusterOnForRebuilding(indoid, tab);
14085  }
14086  }
14087 }
14088 
14089 /*
14090  * Subroutine for ATExecAlterColumnType: remember that an index needs
14091  * to be rebuilt (which we might already know).
14092  */
14093 static void
14095 {
14096  /*
14097  * This de-duplication check is critical for two independent reasons: we
14098  * mustn't try to recreate the same index twice, and if an index depends
14099  * on more than one column whose type is to be altered, we must capture
14100  * its definition string before applying any of the column type changes.
14101  * ruleutils.c will get confused if we ask again later.
14102  */
14103  if (!list_member_oid(tab->changedIndexOids, indoid))
14104  {
14105  /*
14106  * Before adding it as an index-to-rebuild, we'd better see if it
14107  * belongs to a constraint, and if so rebuild the constraint instead.
14108  * Typically this check fails, because constraint indexes normally
14109  * have only dependencies on their constraint. But it's possible for
14110  * such an index to also have direct dependencies on table columns,
14111  * for example with a partial exclusion constraint.
14112  */
14113  Oid conoid = get_index_constraint(indoid);
14114 
14115  if (OidIsValid(conoid))
14116  {
14117  RememberConstraintForRebuilding(conoid, tab);
14118  }
14119  else
14120  {
14121  /* OK, capture the index's existing definition string */
14122  char *defstring = pg_get_indexdef_string(indoid);
14123 
14125  indoid);
14127  defstring);
14128 
14129  /*
14130  * Remember if this index is used for the table's replica identity
14131  * or if it is a clustered index, so that ATPostAlterTypeCleanup()
14132  * can queue up commands necessary to restore those properties.
14133  */
14135  RememberClusterOnForRebuilding(indoid, tab);
14136  }
14137  }
14138 }
14139 
14140 /*
14141  * Subroutine for ATExecAlterColumnType: remember that a statistics object
14142  * needs to be rebuilt (which we might already know).
14143  */
14144 static void
14146 {
14147  /*
14148  * This de-duplication check is critical for two independent reasons: we
14149  * mustn't try to recreate the same statistics object twice, and if the
14150  * statistics object depends on more than one column whose type is to be
14151  * altered, we must capture its definition string before applying any of
14152  * the type changes. ruleutils.c will get confused if we ask again later.
14153  */
14154  if (!list_member_oid(tab->changedStatisticsOids, stxoid))
14155  {
14156  /* OK, capture the statistics object's existing definition string */
14157  char *defstring = pg_get_statisticsobjdef_string(stxoid);
14158 
14160  stxoid);
14162  defstring);
14163  }
14164 }
14165 
14166 /*
14167  * Cleanup after we've finished all the ALTER TYPE or SET EXPRESSION
14168  * operations for a particular relation. We have to drop and recreate all the
14169  * indexes and constraints that depend on the altered columns. We do the
14170  * actual dropping here, but re-creation is managed by adding work queue
14171  * entries to do those steps later.
14172  */
14173 static void
14175 {
14176  ObjectAddress obj;
14177  ObjectAddresses *objects;
14178  ListCell *def_item;
14179  ListCell *oid_item;
14180 
14181  /*
14182  * Collect all the constraints and indexes to drop so we can process them
14183  * in a single call. That way we don't have to worry about dependencies
14184  * among them.
14185  */
14186  objects = new_object_addresses();
14187 
14188  /*
14189  * Re-parse the index and constraint definitions, and attach them to the
14190  * appropriate work queue entries. We do this before dropping because in
14191  * the case of a FOREIGN KEY constraint, we might not yet have exclusive
14192  * lock on the table the constraint is attached to, and we need to get
14193  * that before reparsing/dropping.
14194  *
14195  * We can't rely on the output of deparsing to tell us which relation to
14196  * operate on, because concurrent activity might have made the name
14197  * resolve differently. Instead, we've got to use the OID of the
14198  * constraint or index we're processing to figure out which relation to
14199  * operate on.
14200  */
14201  forboth(oid_item, tab->changedConstraintOids,
14202  def_item, tab->changedConstraintDefs)
14203  {
14204  Oid oldId = lfirst_oid(oid_item);
14205  HeapTuple tup;
14206  Form_pg_constraint con;
14207  Oid relid;
14208  Oid confrelid;
14209  char contype;
14210  bool conislocal;
14211 
14212  tup = SearchSysCache1(CONSTROID, ObjectIdGetDatum(oldId));
14213  if (!HeapTupleIsValid(tup)) /* should not happen */
14214  elog(ERROR, "cache lookup failed for constraint %u", oldId);
14215  con = (Form_pg_constraint) GETSTRUCT(tup);
14216  if (OidIsValid(con->conrelid))
14217  relid = con->conrelid;
14218  else
14219  {
14220  /* must be a domain constraint */
14221  relid = get_typ_typrelid(getBaseType(con->contypid));
14222  if (!OidIsValid(relid))
14223  elog(ERROR, "could not identify relation associated with constraint %u", oldId);
14224  }
14225  confrelid = con->confrelid;
14226  contype = con->contype;
14227  conislocal = con->conislocal;
14228  ReleaseSysCache(tup);
14229 
14230  ObjectAddressSet(obj, ConstraintRelationId, oldId);
14231  add_exact_object_address(&obj, objects);
14232 
14233  /*
14234  * If the constraint is inherited (only), we don't want to inject a
14235  * new definition here; it'll get recreated when
14236  * ATAddCheckNNConstraint recurses from adding the parent table's
14237  * constraint. But we had to carry the info this far so that we can
14238  * drop the constraint below.
14239  */
14240  if (!conislocal)
14241  continue;
14242 
14243  /*
14244  * When rebuilding an FK constraint that references the table we're
14245  * modifying, we might not yet have any lock on the FK's table, so get
14246  * one now. We'll need AccessExclusiveLock for the DROP CONSTRAINT
14247  * step, so there's no value in asking for anything weaker.
14248  */
14249  if (relid != tab->relid && contype == CONSTRAINT_FOREIGN)
14251 
14252  ATPostAlterTypeParse(oldId, relid, confrelid,
14253  (char *) lfirst(def_item),
14254  wqueue, lockmode, tab->rewrite);
14255  }
14256  forboth(oid_item, tab->changedIndexOids,
14257  def_item, tab->changedIndexDefs)
14258  {
14259  Oid oldId = lfirst_oid(oid_item);
14260  Oid relid;
14261 
14262  relid = IndexGetRelation(oldId, false);
14263  ATPostAlterTypeParse(oldId, relid, InvalidOid,
14264  (char *) lfirst(def_item),
14265  wqueue, lockmode, tab->rewrite);
14266 
14267  ObjectAddressSet(obj, RelationRelationId, oldId);
14268  add_exact_object_address(&obj, objects);
14269  }
14270 
14271  /* add dependencies for new statistics */
14272  forboth(oid_item, tab->changedStatisticsOids,
14273  def_item, tab->changedStatisticsDefs)
14274  {
14275  Oid oldId = lfirst_oid(oid_item);
14276  Oid relid;
14277 
14278  relid = StatisticsGetRelation(oldId, false);
14279  ATPostAlterTypeParse(oldId, relid, InvalidOid,
14280  (char *) lfirst(def_item),
14281  wqueue, lockmode, tab->rewrite);
14282 
14283  ObjectAddressSet(obj, StatisticExtRelationId, oldId);
14284  add_exact_object_address(&obj, objects);
14285  }
14286 
14287  /*
14288  * Queue up command to restore replica identity index marking
14289  */
14290  if (tab->replicaIdentityIndex)
14291  {
14294 
14295  subcmd->identity_type = REPLICA_IDENTITY_INDEX;
14296  subcmd->name = tab->replicaIdentityIndex;
14297  cmd->subtype = AT_ReplicaIdentity;
14298  cmd->def = (Node *) subcmd;
14299 
14300  /* do it after indexes and constraints */
14301  tab->subcmds[AT_PASS_OLD_CONSTR] =
14302  lappend(tab->subcmds[AT_PASS_OLD_CONSTR], cmd);
14303  }
14304 
14305  /*
14306  * Queue up command to restore marking of index used for cluster.
14307  */
14308  if (tab->clusterOnIndex)
14309  {
14311 
14312  cmd->subtype = AT_ClusterOn;
14313  cmd->name = tab->clusterOnIndex;
14314 
14315  /* do it after indexes and constraints */
14316  tab->subcmds[AT_PASS_OLD_CONSTR] =
14317  lappend(tab->subcmds[AT_PASS_OLD_CONSTR], cmd);
14318  }
14319 
14320  /*
14321  * It should be okay to use DROP_RESTRICT here, since nothing else should
14322  * be depending on these objects.
14323  */
14325 
14326  free_object_addresses(objects);
14327 
14328  /*
14329  * The objects will get recreated during subsequent passes over the work
14330  * queue.
14331  */
14332 }
14333 
14334 /*
14335  * Parse the previously-saved definition string for a constraint, index or
14336  * statistics object against the newly-established column data type(s), and
14337  * queue up the resulting command parsetrees for execution.
14338  *
14339  * This might fail if, for example, you have a WHERE clause that uses an
14340  * operator that's not available for the new column type.
14341  */
14342 static void
14343 ATPostAlterTypeParse(Oid oldId, Oid oldRelId, Oid refRelId, char *cmd,
14344  List **wqueue, LOCKMODE lockmode, bool rewrite)
14345 {
14346  List *raw_parsetree_list;
14347  List *querytree_list;
14348  ListCell *list_item;
14349  Relation rel;
14350 
14351  /*
14352  * We expect that we will get only ALTER TABLE and CREATE INDEX
14353  * statements. Hence, there is no need to pass them through
14354  * parse_analyze_*() or the rewriter, but instead we need to pass them
14355  * through parse_utilcmd.c to make them ready for execution.
14356  */
14357  raw_parsetree_list = raw_parser(cmd, RAW_PARSE_DEFAULT);
14358  querytree_list = NIL;
14359  foreach(list_item, raw_parsetree_list)
14360  {
14361  RawStmt *rs = lfirst_node(RawStmt, list_item);
14362  Node *stmt = rs->stmt;
14363 
14364  if (IsA(stmt, IndexStmt))
14365  querytree_list = lappend(querytree_list,
14366  transformIndexStmt(oldRelId,
14367  (IndexStmt *) stmt,
14368  cmd));
14369  else if (IsA(stmt, AlterTableStmt))
14370  {
14371  List *beforeStmts;
14372  List *afterStmts;
14373 
14374  stmt = (Node *) transformAlterTableStmt(oldRelId,
14375  (AlterTableStmt *) stmt,
14376  cmd,
14377  &beforeStmts,
14378  &afterStmts);
14379  querytree_list = list_concat(querytree_list, beforeStmts);
14380  querytree_list = lappend(querytree_list, stmt);
14381  querytree_list = list_concat(querytree_list, afterStmts);
14382  }
14383  else if (IsA(stmt, CreateStatsStmt))
14384  querytree_list = lappend(querytree_list,
14385  transformStatsStmt(oldRelId,
14386  (CreateStatsStmt *) stmt,
14387  cmd));
14388  else
14389  querytree_list = lappend(querytree_list, stmt);
14390  }
14391 
14392  /* Caller should already have acquired whatever lock we need. */
14393  rel = relation_open(oldRelId, NoLock);
14394 
14395  /*
14396  * Attach each generated command to the proper place in the work queue.
14397  * Note this could result in creation of entirely new work-queue entries.
14398  *
14399  * Also note that we have to tweak the command subtypes, because it turns
14400  * out that re-creation of indexes and constraints has to act a bit
14401  * differently from initial creation.
14402  */
14403  foreach(list_item, querytree_list)
14404  {
14405  Node *stm = (Node *) lfirst(list_item);
14406  AlteredTableInfo *tab;
14407 
14408  tab = ATGetQueueEntry(wqueue, rel);
14409 
14410  if (IsA(stm, IndexStmt))
14411  {
14412  IndexStmt *stmt = (IndexStmt *) stm;
14413  AlterTableCmd *newcmd;
14414 
14415  if (!rewrite)
14416  TryReuseIndex(oldId, stmt);
14417  stmt->reset_default_tblspc = true;
14418  /* keep the index's comment */
14419  stmt->idxcomment = GetComment(oldId, RelationRelationId, 0);
14420 
14421  newcmd = makeNode(AlterTableCmd);
14422  newcmd->subtype = AT_ReAddIndex;
14423  newcmd->def = (Node *) stmt;
14424  tab->subcmds[AT_PASS_OLD_INDEX] =
14425  lappend(tab->subcmds[AT_PASS_OLD_INDEX], newcmd);
14426  }
14427  else if (IsA(stm, AlterTableStmt))
14428  {
14429  AlterTableStmt *stmt = (AlterTableStmt *) stm;
14430  ListCell *lcmd;
14431 
14432  foreach(lcmd, stmt->cmds)
14433  {
14434  AlterTableCmd *cmd = lfirst_node(AlterTableCmd, lcmd);
14435 
14436  if (cmd->subtype == AT_AddIndex)
14437  {
14438  IndexStmt *indstmt;
14439  Oid indoid;
14440 
14441  indstmt = castNode(IndexStmt, cmd->def);
14442  indoid = get_constraint_index(oldId);
14443 
14444  if (!rewrite)
14445  TryReuseIndex(indoid, indstmt);
14446  /* keep any comment on the index */
14447  indstmt->idxcomment = GetComment(indoid,
14448  RelationRelationId, 0);
14449  indstmt->reset_default_tblspc = true;
14450 
14451  cmd->subtype = AT_ReAddIndex;
14452  tab->subcmds[AT_PASS_OLD_INDEX] =
14453  lappend(tab->subcmds[AT_PASS_OLD_INDEX], cmd);
14454 
14455  /* recreate any comment on the constraint */
14458  oldId,
14459  rel,
14460  NIL,
14461  indstmt->idxname);
14462  }
14463  else if (cmd->subtype == AT_AddConstraint)
14464  {
14465  Constraint *con = castNode(Constraint, cmd->def);
14466 
14467  con->old_pktable_oid = refRelId;
14468  /* rewriting neither side of a FK */
14469  if (con->contype == CONSTR_FOREIGN &&
14470  !rewrite && tab->rewrite == 0)
14471  TryReuseForeignKey(oldId, con);
14472  con->reset_default_tblspc = true;
14473  cmd->subtype = AT_ReAddConstraint;
14474  tab->subcmds[AT_PASS_OLD_CONSTR] =
14475  lappend(tab->subcmds[AT_PASS_OLD_CONSTR], cmd);
14476 
14477  /* recreate any comment on the constraint */
14480  oldId,
14481  rel,
14482  NIL,
14483  con->conname);
14484  }
14485  else if (cmd->subtype == AT_SetAttNotNull)
14486  {
14487  /*
14488  * The parser will create AT_AttSetNotNull subcommands for
14489  * columns of PRIMARY KEY indexes/constraints, but we need
14490  * not do anything with them here, because the columns'
14491  * NOT NULL marks will already have been propagated into
14492  * the new table definition.
14493  */
14494  }
14495  else
14496  elog(ERROR, "unexpected statement subtype: %d",
14497  (int) cmd->subtype);
14498  }
14499  }
14500  else if (IsA(stm, AlterDomainStmt))
14501  {
14503 
14504  if (stmt->subtype == 'C') /* ADD CONSTRAINT */
14505  {
14506  Constraint *con = castNode(Constraint, stmt->def);
14508 
14510  cmd->def = (Node *) stmt;
14511  tab->subcmds[AT_PASS_OLD_CONSTR] =
14512  lappend(tab->subcmds[AT_PASS_OLD_CONSTR], cmd);
14513 
14514  /* recreate any comment on the constraint */
14517  oldId,
14518  NULL,
14519  stmt->typeName,
14520  con->conname);
14521  }
14522  else
14523  elog(ERROR, "unexpected statement subtype: %d",
14524  (int) stmt->subtype);
14525  }
14526  else if (IsA(stm, CreateStatsStmt))
14527  {
14529  AlterTableCmd *newcmd;
14530 
14531  /* keep the statistics object's comment */
14532  stmt->stxcomment = GetComment(oldId, StatisticExtRelationId, 0);
14533 
14534  newcmd = makeNode(AlterTableCmd);
14535  newcmd->subtype = AT_ReAddStatistics;
14536  newcmd->def = (Node *) stmt;
14537  tab->subcmds[AT_PASS_MISC] =
14538  lappend(tab->subcmds[AT_PASS_MISC], newcmd);
14539  }
14540  else
14541  elog(ERROR, "unexpected statement type: %d",
14542  (int) nodeTag(stm));
14543  }
14544 
14545  relation_close(rel, NoLock);
14546 }
14547 
14548 /*
14549  * Subroutine for ATPostAlterTypeParse() to recreate any existing comment
14550  * for a table or domain constraint that is being rebuilt.
14551  *
14552  * objid is the OID of the constraint.
14553  * Pass "rel" for a table constraint, or "domname" (domain's qualified name
14554  * as a string list) for a domain constraint.
14555  * (We could dig that info, as well as the conname, out of the pg_constraint
14556  * entry; but callers already have them so might as well pass them.)
14557  */
14558 static void
14560  Relation rel, List *domname,
14561  const char *conname)
14562 {
14563  CommentStmt *cmd;
14564  char *comment_str;
14565  AlterTableCmd *newcmd;
14566 
14567  /* Look for comment for object wanted, and leave if none */
14568  comment_str = GetComment(objid, ConstraintRelationId, 0);
14569  if (comment_str == NULL)
14570  return;
14571 
14572  /* Build CommentStmt node, copying all input data for safety */
14573  cmd = makeNode(CommentStmt);
14574  if (rel)
14575  {
14577  cmd->object = (Node *)
14580  makeString(pstrdup(conname)));
14581  }
14582  else
14583  {
14585  cmd->object = (Node *)
14587  makeString(pstrdup(conname)));
14588  }
14589  cmd->comment = comment_str;
14590 
14591  /* Append it to list of commands */
14592  newcmd = makeNode(AlterTableCmd);
14593  newcmd->subtype = AT_ReAddComment;
14594  newcmd->def = (Node *) cmd;
14595  tab->subcmds[pass] = lappend(tab->subcmds[pass], newcmd);
14596 }
14597 
14598 /*
14599  * Subroutine for ATPostAlterTypeParse(). Calls out to CheckIndexCompatible()
14600  * for the real analysis, then mutates the IndexStmt based on that verdict.
14601  */
14602 static void
14604 {
14605  if (CheckIndexCompatible(oldId,
14606  stmt->accessMethod,
14607  stmt->indexParams,
14608  stmt->excludeOpNames,
14609  stmt->iswithoutoverlaps))
14610  {
14611  Relation irel = index_open(oldId, NoLock);
14612 
14613  /* If it's a partitioned index, there is no storage to share. */
14614  if (irel->rd_rel->relkind != RELKIND_PARTITIONED_INDEX)
14615  {
14616  stmt->oldNumber = irel->rd_locator.relNumber;
14617  stmt->oldCreateSubid = irel->rd_createSubid;
14618  stmt->oldFirstRelfilelocatorSubid = irel->rd_firstRelfilelocatorSubid;
14619  }
14620  index_close(irel, NoLock);
14621  }
14622 }
14623 
14624 /*
14625  * Subroutine for ATPostAlterTypeParse().
14626  *
14627  * Stash the old P-F equality operator into the Constraint node, for possible
14628  * use by ATAddForeignKeyConstraint() in determining whether revalidation of
14629  * this constraint can be skipped.
14630  */
14631 static void
14633 {
14634  HeapTuple tup;
14635  Datum adatum;
14636  ArrayType *arr;
14637  Oid *rawarr;
14638  int numkeys;
14639  int i;
14640 
14641  Assert(con->contype == CONSTR_FOREIGN);
14642  Assert(con->old_conpfeqop == NIL); /* already prepared this node */
14643 
14644  tup = SearchSysCache1(CONSTROID, ObjectIdGetDatum(oldId));
14645  if (!HeapTupleIsValid(tup)) /* should not happen */
14646  elog(ERROR, "cache lookup failed for constraint %u", oldId);
14647 
14648  adatum = SysCacheGetAttrNotNull(CONSTROID, tup,
14649  Anum_pg_constraint_conpfeqop);
14650  arr = DatumGetArrayTypeP(adatum); /* ensure not toasted */
14651  numkeys = ARR_DIMS(arr)[0];
14652  /* test follows the one in ri_FetchConstraintInfo() */
14653  if (ARR_NDIM(arr) != 1 ||
14654  ARR_HASNULL(arr) ||
14655  ARR_ELEMTYPE(arr) != OIDOID)
14656  elog(ERROR, "conpfeqop is not a 1-D Oid array");
14657  rawarr = (Oid *) ARR_DATA_PTR(arr);
14658 
14659  /* stash a List of the operator Oids in our Constraint node */
14660  for (i = 0; i < numkeys; i++)
14661  con->old_conpfeqop = lappend_oid(con->old_conpfeqop, rawarr[i]);
14662 
14663  ReleaseSysCache(tup);
14664 }
14665 
14666 /*
14667  * ALTER COLUMN .. OPTIONS ( ... )
14668  *
14669  * Returns the address of the modified column
14670  */
14671 static ObjectAddress
14673  const char *colName,
14674  List *options,
14675  LOCKMODE lockmode)
14676 {
14677  Relation ftrel;
14678  Relation attrel;
14679  ForeignServer *server;
14680  ForeignDataWrapper *fdw;
14681  HeapTuple tuple;
14682  HeapTuple newtuple;
14683  bool isnull;
14684  Datum repl_val[Natts_pg_attribute];
14685  bool repl_null[Natts_pg_attribute];
14686  bool repl_repl[Natts_pg_attribute];
14687  Datum datum;
14688  Form_pg_foreign_table fttableform;
14689  Form_pg_attribute atttableform;
14691  ObjectAddress address;
14692 
14693  if (options == NIL)
14694  return InvalidObjectAddress;
14695 
14696  /* First, determine FDW validator associated to the foreign table. */
14697  ftrel = table_open(ForeignTableRelationId, AccessShareLock);
14698  tuple = SearchSysCache1(FOREIGNTABLEREL, ObjectIdGetDatum(rel->rd_id));
14699  if (!HeapTupleIsValid(tuple))
14700  ereport(ERROR,
14701  (errcode(ERRCODE_UNDEFINED_OBJECT),
14702  errmsg("foreign table \"%s\" does not exist",
14703  RelationGetRelationName(rel))));
14704  fttableform = (Form_pg_foreign_table) GETSTRUCT(tuple);
14705  server = GetForeignServer(fttableform->ftserver);
14706  fdw = GetForeignDataWrapper(server->fdwid);
14707 
14708  table_close(ftrel, AccessShareLock);
14709  ReleaseSysCache(tuple);
14710 
14711  attrel = table_open(AttributeRelationId, RowExclusiveLock);
14712  tuple = SearchSysCacheAttName(RelationGetRelid(rel), colName);
14713  if (!HeapTupleIsValid(tuple))
14714  ereport(ERROR,
14715  (errcode(ERRCODE_UNDEFINED_COLUMN),
14716  errmsg("column \"%s\" of relation \"%s\" does not exist",
14717  colName, RelationGetRelationName(rel))));
14718 
14719  /* Prevent them from altering a system attribute */
14720  atttableform = (Form_pg_attribute) GETSTRUCT(tuple);
14721  attnum = atttableform->attnum;
14722  if (attnum <= 0)
14723  ereport(ERROR,
14724  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
14725  errmsg("cannot alter system column \"%s\"", colName)));
14726 
14727 
14728  /* Initialize buffers for new tuple values */
14729  memset(repl_val, 0, sizeof(repl_val));
14730  memset(repl_null, false, sizeof(repl_null));
14731  memset(repl_repl, false, sizeof(repl_repl));
14732 
14733  /* Extract the current options */
14734  datum = SysCacheGetAttr(ATTNAME,
14735  tuple,
14736  Anum_pg_attribute_attfdwoptions,
14737  &isnull);
14738  if (isnull)
14739  datum = PointerGetDatum(NULL);
14740 
14741  /* Transform the options */
14742  datum = transformGenericOptions(AttributeRelationId,
14743  datum,
14744  options,
14745  fdw->fdwvalidator);
14746 
14747  if (PointerIsValid(DatumGetPointer(datum)))
14748  repl_val[Anum_pg_attribute_attfdwoptions - 1] = datum;
14749  else
14750  repl_null[Anum_pg_attribute_attfdwoptions - 1] = true;
14751 
14752  repl_repl[Anum_pg_attribute_attfdwoptions - 1] = true;
14753 
14754  /* Everything looks good - update the tuple */
14755 
14756  newtuple = heap_modify_tuple(tuple, RelationGetDescr(attrel),
14757  repl_val, repl_null, repl_repl);
14758 
14759  CatalogTupleUpdate(attrel, &newtuple->t_self, newtuple);
14760 
14761  InvokeObjectPostAlterHook(RelationRelationId,
14762  RelationGetRelid(rel),
14763  atttableform->attnum);
14764  ObjectAddressSubSet(address, RelationRelationId,
14765  RelationGetRelid(rel), attnum);
14766 
14767  ReleaseSysCache(tuple);
14768 
14769  table_close(attrel, RowExclusiveLock);
14770 
14771  heap_freetuple(newtuple);
14772 
14773  return address;
14774 }
14775 
14776 /*
14777  * ALTER TABLE OWNER
14778  *
14779  * recursing is true if we are recursing from a table to its indexes,
14780  * sequences, or toast table. We don't allow the ownership of those things to
14781  * be changed separately from the parent table. Also, we can skip permission
14782  * checks (this is necessary not just an optimization, else we'd fail to
14783  * handle toast tables properly).
14784  *
14785  * recursing is also true if ALTER TYPE OWNER is calling us to fix up a
14786  * free-standing composite type.
14787  */
14788 void
14789 ATExecChangeOwner(Oid relationOid, Oid newOwnerId, bool recursing, LOCKMODE lockmode)
14790 {
14791  Relation target_rel;
14792  Relation class_rel;
14793  HeapTuple tuple;
14794  Form_pg_class tuple_class;
14795 
14796  /*
14797  * Get exclusive lock till end of transaction on the target table. Use
14798  * relation_open so that we can work on indexes and sequences.
14799  */
14800  target_rel = relation_open(relationOid, lockmode);
14801 
14802  /* Get its pg_class tuple, too */
14803  class_rel = table_open(RelationRelationId, RowExclusiveLock);
14804 
14805  tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relationOid));
14806  if (!HeapTupleIsValid(tuple))
14807  elog(ERROR, "cache lookup failed for relation %u", relationOid);
14808  tuple_class = (Form_pg_class) GETSTRUCT(tuple);
14809 
14810  /* Can we change the ownership of this tuple? */
14811  switch (tuple_class->relkind)
14812  {
14813  case RELKIND_RELATION:
14814  case RELKIND_VIEW:
14815  case RELKIND_MATVIEW:
14816  case RELKIND_FOREIGN_TABLE:
14817  case RELKIND_PARTITIONED_TABLE:
14818  /* ok to change owner */
14819  break;
14820  case RELKIND_INDEX:
14821  if (!recursing)
14822  {
14823  /*
14824  * Because ALTER INDEX OWNER used to be allowed, and in fact
14825  * is generated by old versions of pg_dump, we give a warning
14826  * and do nothing rather than erroring out. Also, to avoid
14827  * unnecessary chatter while restoring those old dumps, say
14828  * nothing at all if the command would be a no-op anyway.
14829  */
14830  if (tuple_class->relowner != newOwnerId)
14831  ereport(WARNING,
14832  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
14833  errmsg("cannot change owner of index \"%s\"",
14834  NameStr(tuple_class->relname)),
14835  errhint("Change the ownership of the index's table instead.")));
14836  /* quick hack to exit via the no-op path */
14837  newOwnerId = tuple_class->relowner;
14838  }
14839  break;
14840  case RELKIND_PARTITIONED_INDEX:
14841  if (recursing)
14842  break;
14843  ereport(ERROR,
14844  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
14845  errmsg("cannot change owner of index \"%s\"",
14846  NameStr(tuple_class->relname)),
14847  errhint("Change the ownership of the index's table instead.")));
14848  break;
14849  case RELKIND_SEQUENCE:
14850  if (!recursing &&
14851  tuple_class->relowner != newOwnerId)
14852  {
14853  /* if it's an owned sequence, disallow changing it by itself */
14854  Oid tableId;
14855  int32 colId;
14856 
14857  if (sequenceIsOwned(relationOid, DEPENDENCY_AUTO, &tableId, &colId) ||
14858  sequenceIsOwned(relationOid, DEPENDENCY_INTERNAL, &tableId, &colId))
14859  ereport(ERROR,
14860  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
14861  errmsg("cannot change owner of sequence \"%s\"",
14862  NameStr(tuple_class->relname)),
14863  errdetail("Sequence \"%s\" is linked to table \"%s\".",
14864  NameStr(tuple_class->relname),
14865  get_rel_name(tableId))));
14866  }
14867  break;
14868  case RELKIND_COMPOSITE_TYPE:
14869  if (recursing)
14870  break;
14871  ereport(ERROR,
14872  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
14873  errmsg("\"%s\" is a composite type",
14874  NameStr(tuple_class->relname)),
14875  /* translator: %s is an SQL ALTER command */
14876  errhint("Use %s instead.",
14877  "ALTER TYPE")));
14878  break;
14879  case RELKIND_TOASTVALUE:
14880  if (recursing)
14881  break;
14882  /* FALL THRU */
14883  default:
14884  ereport(ERROR,
14885  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
14886  errmsg("cannot change owner of relation \"%s\"",
14887  NameStr(tuple_class->relname)),
14888  errdetail_relkind_not_supported(tuple_class->relkind)));
14889  }
14890 
14891  /*
14892  * If the new owner is the same as the existing owner, consider the
14893  * command to have succeeded. This is for dump restoration purposes.
14894  */
14895  if (tuple_class->relowner != newOwnerId)
14896  {
14897  Datum repl_val[Natts_pg_class];
14898  bool repl_null[Natts_pg_class];
14899  bool repl_repl[Natts_pg_class];
14900  Acl *newAcl;
14901  Datum aclDatum;
14902  bool isNull;
14903  HeapTuple newtuple;
14904 
14905  /* skip permission checks when recursing to index or toast table */
14906  if (!recursing)
14907  {
14908  /* Superusers can always do it */
14909  if (!superuser())
14910  {
14911  Oid namespaceOid = tuple_class->relnamespace;
14912  AclResult aclresult;
14913 
14914  /* Otherwise, must be owner of the existing object */
14915  if (!object_ownercheck(RelationRelationId, relationOid, GetUserId()))
14917  RelationGetRelationName(target_rel));
14918 
14919  /* Must be able to become new owner */
14920  check_can_set_role(GetUserId(), newOwnerId);
14921 
14922  /* New owner must have CREATE privilege on namespace */
14923  aclresult = object_aclcheck(NamespaceRelationId, namespaceOid, newOwnerId,
14924  ACL_CREATE);
14925  if (aclresult != ACLCHECK_OK)
14926  aclcheck_error(aclresult, OBJECT_SCHEMA,
14927  get_namespace_name(namespaceOid));
14928  }
14929  }
14930 
14931  memset(repl_null, false, sizeof(repl_null));
14932  memset(repl_repl, false, sizeof(repl_repl));
14933 
14934  repl_repl[Anum_pg_class_relowner - 1] = true;
14935  repl_val[Anum_pg_class_relowner - 1] = ObjectIdGetDatum(newOwnerId);
14936 
14937  /*
14938  * Determine the modified ACL for the new owner. This is only
14939  * necessary when the ACL is non-null.
14940  */
14941  aclDatum = SysCacheGetAttr(RELOID, tuple,
14942  Anum_pg_class_relacl,
14943  &isNull);
14944  if (!isNull)
14945  {
14946  newAcl = aclnewowner(DatumGetAclP(aclDatum),
14947  tuple_class->relowner, newOwnerId);
14948  repl_repl[Anum_pg_class_relacl - 1] = true;
14949  repl_val[Anum_pg_class_relacl - 1] = PointerGetDatum(newAcl);
14950  }
14951 
14952  newtuple = heap_modify_tuple(tuple, RelationGetDescr(class_rel), repl_val, repl_null, repl_repl);
14953 
14954  CatalogTupleUpdate(class_rel, &newtuple->t_self, newtuple);
14955 
14956  heap_freetuple(newtuple);
14957 
14958  /*
14959  * We must similarly update any per-column ACLs to reflect the new
14960  * owner; for neatness reasons that's split out as a subroutine.
14961  */
14962  change_owner_fix_column_acls(relationOid,
14963  tuple_class->relowner,
14964  newOwnerId);
14965 
14966  /*
14967  * Update owner dependency reference, if any. A composite type has
14968  * none, because it's tracked for the pg_type entry instead of here;
14969  * indexes and TOAST tables don't have their own entries either.
14970  */
14971  if (tuple_class->relkind != RELKIND_COMPOSITE_TYPE &&
14972  tuple_class->relkind != RELKIND_INDEX &&
14973  tuple_class->relkind != RELKIND_PARTITIONED_INDEX &&
14974  tuple_class->relkind != RELKIND_TOASTVALUE)
14975  changeDependencyOnOwner(RelationRelationId, relationOid,
14976  newOwnerId);
14977 
14978  /*
14979  * Also change the ownership of the table's row type, if it has one
14980  */
14981  if (OidIsValid(tuple_class->reltype))
14982  AlterTypeOwnerInternal(tuple_class->reltype, newOwnerId);
14983 
14984  /*
14985  * If we are operating on a table or materialized view, also change
14986  * the ownership of any indexes and sequences that belong to the
14987  * relation, as well as its toast table (if it has one).
14988  */
14989  if (tuple_class->relkind == RELKIND_RELATION ||
14990  tuple_class->relkind == RELKIND_PARTITIONED_TABLE ||
14991  tuple_class->relkind == RELKIND_MATVIEW ||
14992  tuple_class->relkind == RELKIND_TOASTVALUE)
14993  {
14994  List *index_oid_list;
14995  ListCell *i;
14996 
14997  /* Find all the indexes belonging to this relation */
14998  index_oid_list = RelationGetIndexList(target_rel);
14999 
15000  /* For each index, recursively change its ownership */
15001  foreach(i, index_oid_list)
15002  ATExecChangeOwner(lfirst_oid(i), newOwnerId, true, lockmode);
15003 
15004  list_free(index_oid_list);
15005  }
15006 
15007  /* If it has a toast table, recurse to change its ownership */
15008  if (tuple_class->reltoastrelid != InvalidOid)
15009  ATExecChangeOwner(tuple_class->reltoastrelid, newOwnerId,
15010  true, lockmode);
15011 
15012  /* If it has dependent sequences, recurse to change them too */
15013  change_owner_recurse_to_sequences(relationOid, newOwnerId, lockmode);
15014  }
15015 
15016  InvokeObjectPostAlterHook(RelationRelationId, relationOid, 0);
15017 
15018  ReleaseSysCache(tuple);
15019  table_close(class_rel, RowExclusiveLock);
15020  relation_close(target_rel, NoLock);
15021 }
15022 
15023 /*
15024  * change_owner_fix_column_acls
15025  *
15026  * Helper function for ATExecChangeOwner. Scan the columns of the table
15027  * and fix any non-null column ACLs to reflect the new owner.
15028  */
15029 static void
15030 change_owner_fix_column_acls(Oid relationOid, Oid oldOwnerId, Oid newOwnerId)
15031 {
15032  Relation attRelation;
15033  SysScanDesc scan;
15034  ScanKeyData key[1];
15035  HeapTuple attributeTuple;
15036 
15037  attRelation = table_open(AttributeRelationId, RowExclusiveLock);
15038  ScanKeyInit(&key[0],
15039  Anum_pg_attribute_attrelid,
15040  BTEqualStrategyNumber, F_OIDEQ,
15041  ObjectIdGetDatum(relationOid));
15042  scan = systable_beginscan(attRelation, AttributeRelidNumIndexId,
15043  true, NULL, 1, key);
15044  while (HeapTupleIsValid(attributeTuple = systable_getnext(scan)))
15045  {
15046  Form_pg_attribute att = (Form_pg_attribute) GETSTRUCT(attributeTuple);
15047  Datum repl_val[Natts_pg_attribute];
15048  bool repl_null[Natts_pg_attribute];
15049  bool repl_repl[Natts_pg_attribute];
15050  Acl *newAcl;
15051  Datum aclDatum;
15052  bool isNull;
15053  HeapTuple newtuple;
15054 
15055  /* Ignore dropped columns */
15056  if (att->attisdropped)
15057  continue;
15058 
15059  aclDatum = heap_getattr(attributeTuple,
15060  Anum_pg_attribute_attacl,
15061  RelationGetDescr(attRelation),
15062  &isNull);
15063  /* Null ACLs do not require changes */
15064  if (isNull)
15065  continue;
15066 
15067  memset(repl_null, false, sizeof(repl_null));
15068  memset(repl_repl, false, sizeof(repl_repl));
15069 
15070  newAcl = aclnewowner(DatumGetAclP(aclDatum),
15071  oldOwnerId, newOwnerId);
15072  repl_repl[Anum_pg_attribute_attacl - 1] = true;
15073  repl_val[Anum_pg_attribute_attacl - 1] = PointerGetDatum(newAcl);
15074 
15075  newtuple = heap_modify_tuple(attributeTuple,
15076  RelationGetDescr(attRelation),
15077  repl_val, repl_null, repl_repl);
15078 
15079  CatalogTupleUpdate(attRelation, &newtuple->t_self, newtuple);
15080 
15081  heap_freetuple(newtuple);
15082  }
15083  systable_endscan(scan);
15084  table_close(attRelation, RowExclusiveLock);
15085 }
15086 
15087 /*
15088  * change_owner_recurse_to_sequences
15089  *
15090  * Helper function for ATExecChangeOwner. Examines pg_depend searching
15091  * for sequences that are dependent on serial columns, and changes their
15092  * ownership.
15093  */
15094 static void
15095 change_owner_recurse_to_sequences(Oid relationOid, Oid newOwnerId, LOCKMODE lockmode)
15096 {
15097  Relation depRel;
15098  SysScanDesc scan;
15099  ScanKeyData key[2];
15100  HeapTuple tup;
15101 
15102  /*
15103  * SERIAL sequences are those having an auto dependency on one of the
15104  * table's columns (we don't care *which* column, exactly).
15105  */
15106  depRel = table_open(DependRelationId, AccessShareLock);
15107 
15108  ScanKeyInit(&key[0],
15109  Anum_pg_depend_refclassid,
15110  BTEqualStrategyNumber, F_OIDEQ,
15111  ObjectIdGetDatum(RelationRelationId));
15112  ScanKeyInit(&key[1],
15113  Anum_pg_depend_refobjid,
15114  BTEqualStrategyNumber, F_OIDEQ,
15115  ObjectIdGetDatum(relationOid));
15116  /* we leave refobjsubid unspecified */
15117 
15118  scan = systable_beginscan(depRel, DependReferenceIndexId, true,
15119  NULL, 2, key);
15120 
15121  while (HeapTupleIsValid(tup = systable_getnext(scan)))
15122  {
15123  Form_pg_depend depForm = (Form_pg_depend) GETSTRUCT(tup);
15124  Relation seqRel;
15125 
15126  /* skip dependencies other than auto dependencies on columns */
15127  if (depForm->refobjsubid == 0 ||
15128  depForm->classid != RelationRelationId ||
15129  depForm->objsubid != 0 ||
15130  !(depForm->deptype == DEPENDENCY_AUTO || depForm->deptype == DEPENDENCY_INTERNAL))
15131  continue;
15132 
15133  /* Use relation_open just in case it's an index */
15134  seqRel = relation_open(depForm->objid, lockmode);
15135 
15136  /* skip non-sequence relations */
15137  if (RelationGetForm(seqRel)->relkind != RELKIND_SEQUENCE)
15138  {
15139  /* No need to keep the lock */
15140  relation_close(seqRel, lockmode);
15141  continue;
15142  }
15143 
15144  /* We don't need to close the sequence while we alter it. */
15145  ATExecChangeOwner(depForm->objid, newOwnerId, true, lockmode);
15146 
15147  /* Now we can close it. Keep the lock till end of transaction. */
15148  relation_close(seqRel, NoLock);
15149  }
15150 
15151  systable_endscan(scan);
15152 
15154 }
15155 
15156 /*
15157  * ALTER TABLE CLUSTER ON
15158  *
15159  * The only thing we have to do is to change the indisclustered bits.
15160  *
15161  * Return the address of the new clustering index.
15162  */
15163 static ObjectAddress
15164 ATExecClusterOn(Relation rel, const char *indexName, LOCKMODE lockmode)
15165 {
15166  Oid indexOid;
15167  ObjectAddress address;
15168 
15169  indexOid = get_relname_relid(indexName, rel->rd_rel->relnamespace);
15170 
15171  if (!OidIsValid(indexOid))
15172  ereport(ERROR,
15173  (errcode(ERRCODE_UNDEFINED_OBJECT),
15174  errmsg("index \"%s\" for table \"%s\" does not exist",
15175  indexName, RelationGetRelationName(rel))));
15176 
15177  /* Check index is valid to cluster on */
15178  check_index_is_clusterable(rel, indexOid, lockmode);
15179 
15180  /* And do the work */
15181  mark_index_clustered(rel, indexOid, false);
15182 
15183  ObjectAddressSet(address,
15184  RelationRelationId, indexOid);
15185 
15186  return address;
15187 }
15188 
15189 /*
15190  * ALTER TABLE SET WITHOUT CLUSTER
15191  *
15192  * We have to find any indexes on the table that have indisclustered bit
15193  * set and turn it off.
15194  */
15195 static void
15197 {
15198  mark_index_clustered(rel, InvalidOid, false);
15199 }
15200 
15201 /*
15202  * Preparation phase for SET ACCESS METHOD
15203  *
15204  * Check that access method exists. If it is the same as the table's current
15205  * access method, it is a no-op. Otherwise, a table rewrite is necessary.
15206  * If amname is NULL, select default_table_access_method as access method.
15207  */
15208 static void
15209 ATPrepSetAccessMethod(AlteredTableInfo *tab, Relation rel, const char *amname)
15210 {
15211  Oid amoid;
15212 
15213  /* Check that the table access method exists */
15214  amoid = get_table_am_oid(amname ? amname : default_table_access_method,
15215  false);
15216 
15217  if (rel->rd_rel->relam == amoid)
15218  return;
15219 
15220  /* Save info for Phase 3 to do the real work */
15222  tab->newAccessMethod = amoid;
15223 }
15224 
15225 /*
15226  * ALTER TABLE SET TABLESPACE
15227  */
15228 static void
15229 ATPrepSetTableSpace(AlteredTableInfo *tab, Relation rel, const char *tablespacename, LOCKMODE lockmode)
15230 {
15231  Oid tablespaceId;
15232 
15233  /* Check that the tablespace exists */
15234  tablespaceId = get_tablespace_oid(tablespacename, false);
15235 
15236  /* Check permissions except when moving to database's default */
15237  if (OidIsValid(tablespaceId) && tablespaceId != MyDatabaseTableSpace)
15238  {
15239  AclResult aclresult;
15240 
15241  aclresult = object_aclcheck(TableSpaceRelationId, tablespaceId, GetUserId(), ACL_CREATE);
15242  if (aclresult != ACLCHECK_OK)
15243  aclcheck_error(aclresult, OBJECT_TABLESPACE, tablespacename);
15244  }
15245 
15246  /* Save info for Phase 3 to do the real work */
15247  if (OidIsValid(tab->newTableSpace))
15248  ereport(ERROR,
15249  (errcode(ERRCODE_SYNTAX_ERROR),
15250  errmsg("cannot have multiple SET TABLESPACE subcommands")));
15251 
15252  tab->newTableSpace = tablespaceId;
15253 }
15254 
15255 /*
15256  * Set, reset, or replace reloptions.
15257  */
15258 static void
15260  LOCKMODE lockmode)
15261 {
15262  Oid relid;
15263  Relation pgclass;
15264  HeapTuple tuple;
15265  HeapTuple newtuple;
15266  Datum datum;
15267  bool isnull;
15268  Datum newOptions;
15269  Datum repl_val[Natts_pg_class];
15270  bool repl_null[Natts_pg_class];
15271  bool repl_repl[Natts_pg_class];
15272  static char *validnsps[] = HEAP_RELOPT_NAMESPACES;
15273 
15274  if (defList == NIL && operation != AT_ReplaceRelOptions)
15275  return; /* nothing to do */
15276 
15277  pgclass = table_open(RelationRelationId, RowExclusiveLock);
15278 
15279  /* Fetch heap tuple */
15280  relid = RelationGetRelid(rel);
15281  tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
15282  if (!HeapTupleIsValid(tuple))
15283  elog(ERROR, "cache lookup failed for relation %u", relid);
15284 
15285  if (operation == AT_ReplaceRelOptions)
15286  {
15287  /*
15288  * If we're supposed to replace the reloptions list, we just pretend
15289  * there were none before.
15290  */
15291  datum = (Datum) 0;
15292  isnull = true;
15293  }
15294  else
15295  {
15296  /* Get the old reloptions */
15297  datum = SysCacheGetAttr(RELOID, tuple, Anum_pg_class_reloptions,
15298  &isnull);
15299  }
15300 
15301  /* Generate new proposed reloptions (text array) */
15302  newOptions = transformRelOptions(isnull ? (Datum) 0 : datum,
15303  defList, NULL, validnsps, false,
15304  operation == AT_ResetRelOptions);
15305 
15306  /* Validate */
15307  switch (rel->rd_rel->relkind)
15308  {
15309  case RELKIND_RELATION:
15310  case RELKIND_TOASTVALUE:
15311  case RELKIND_MATVIEW:
15312  (void) heap_reloptions(rel->rd_rel->relkind, newOptions, true);
15313  break;
15314  case RELKIND_PARTITIONED_TABLE:
15315  (void) partitioned_table_reloptions(newOptions, true);
15316  break;
15317  case RELKIND_VIEW:
15318  (void) view_reloptions(newOptions, true);
15319  break;
15320  case RELKIND_INDEX:
15321  case RELKIND_PARTITIONED_INDEX:
15322  (void) index_reloptions(rel->rd_indam->amoptions, newOptions, true);
15323  break;
15324  default:
15325  ereport(ERROR,
15326  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
15327  errmsg("cannot set options for relation \"%s\"",
15329  errdetail_relkind_not_supported(rel->rd_rel->relkind)));
15330  break;
15331  }
15332 
15333  /* Special-case validation of view options */
15334  if (rel->rd_rel->relkind == RELKIND_VIEW)
15335  {
15336  Query *view_query = get_view_query(rel);
15337  List *view_options = untransformRelOptions(newOptions);
15338  ListCell *cell;
15339  bool check_option = false;
15340 
15341  foreach(cell, view_options)
15342  {
15343  DefElem *defel = (DefElem *) lfirst(cell);
15344 
15345  if (strcmp(defel->defname, "check_option") == 0)
15346  check_option = true;
15347  }
15348 
15349  /*
15350  * If the check option is specified, look to see if the view is
15351  * actually auto-updatable or not.
15352  */
15353  if (check_option)
15354  {
15355  const char *view_updatable_error =
15356  view_query_is_auto_updatable(view_query, true);
15357 
15358  if (view_updatable_error)
15359  ereport(ERROR,
15360  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
15361  errmsg("WITH CHECK OPTION is supported only on automatically updatable views"),
15362  errhint("%s", _(view_updatable_error))));
15363  }
15364  }
15365 
15366  /*
15367  * All we need do here is update the pg_class row; the new options will be
15368  * propagated into relcaches during post-commit cache inval.
15369  */
15370  memset(repl_val, 0, sizeof(repl_val));
15371  memset(repl_null, false, sizeof(repl_null));
15372  memset(repl_repl, false, sizeof(repl_repl));
15373 
15374  if (newOptions != (Datum) 0)
15375  repl_val[Anum_pg_class_reloptions - 1] = newOptions;
15376  else
15377  repl_null[Anum_pg_class_reloptions - 1] = true;
15378 
15379  repl_repl[Anum_pg_class_reloptions - 1] = true;
15380 
15381  newtuple = heap_modify_tuple(tuple, RelationGetDescr(pgclass),
15382  repl_val, repl_null, repl_repl);
15383 
15384  CatalogTupleUpdate(pgclass, &newtuple->t_self, newtuple);
15385 
15386  InvokeObjectPostAlterHook(RelationRelationId, RelationGetRelid(rel), 0);
15387 
15388  heap_freetuple(newtuple);
15389 
15390  ReleaseSysCache(tuple);
15391 
15392  /* repeat the whole exercise for the toast table, if there's one */
15393  if (OidIsValid(rel->rd_rel->reltoastrelid))
15394  {
15395  Relation toastrel;
15396  Oid toastid = rel->rd_rel->reltoastrelid;
15397 
15398  toastrel = table_open(toastid, lockmode);
15399 
15400  /* Fetch heap tuple */
15401  tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(toastid));
15402  if (!HeapTupleIsValid(tuple))
15403  elog(ERROR, "cache lookup failed for relation %u", toastid);
15404 
15405  if (operation == AT_ReplaceRelOptions)
15406  {
15407  /*
15408  * If we're supposed to replace the reloptions list, we just
15409  * pretend there were none before.
15410  */
15411  datum = (Datum) 0;
15412  isnull = true;
15413  }
15414  else
15415  {
15416  /* Get the old reloptions */
15417  datum = SysCacheGetAttr(RELOID, tuple, Anum_pg_class_reloptions,
15418  &isnull);
15419  }
15420 
15421  newOptions = transformRelOptions(isnull ? (Datum) 0 : datum,
15422  defList, "toast", validnsps, false,
15423  operation == AT_ResetRelOptions);
15424 
15425  (void) heap_reloptions(RELKIND_TOASTVALUE, newOptions, true);
15426 
15427  memset(repl_val, 0, sizeof(repl_val));
15428  memset(repl_null, false, sizeof(repl_null));
15429  memset(repl_repl, false, sizeof(repl_repl));
15430 
15431  if (newOptions != (Datum) 0)
15432  repl_val[Anum_pg_class_reloptions - 1] = newOptions;
15433  else
15434  repl_null[Anum_pg_class_reloptions - 1] = true;
15435 
15436  repl_repl[Anum_pg_class_reloptions - 1] = true;
15437 
15438  newtuple = heap_modify_tuple(tuple, RelationGetDescr(pgclass),
15439  repl_val, repl_null, repl_repl);
15440 
15441  CatalogTupleUpdate(pgclass, &newtuple->t_self, newtuple);
15442 
15443  InvokeObjectPostAlterHookArg(RelationRelationId,
15444  RelationGetRelid(toastrel), 0,
15445  InvalidOid, true);
15446 
15447  heap_freetuple(newtuple);
15448 
15449  ReleaseSysCache(tuple);
15450 
15451  table_close(toastrel, NoLock);
15452  }
15453 
15454  table_close(pgclass, RowExclusiveLock);
15455 }
15456 
15457 /*
15458  * Execute ALTER TABLE SET TABLESPACE for cases where there is no tuple
15459  * rewriting to be done, so we just want to copy the data as fast as possible.
15460  */
15461 static void
15462 ATExecSetTableSpace(Oid tableOid, Oid newTableSpace, LOCKMODE lockmode)
15463 {
15464  Relation rel;
15465  Oid reltoastrelid;
15466  RelFileNumber newrelfilenumber;
15467  RelFileLocator newrlocator;
15468  List *reltoastidxids = NIL;
15469  ListCell *lc;
15470 
15471  /*
15472  * Need lock here in case we are recursing to toast table or index
15473  */
15474  rel = relation_open(tableOid, lockmode);
15475 
15476  /* Check first if relation can be moved to new tablespace */
15477  if (!CheckRelationTableSpaceMove(rel, newTableSpace))
15478  {
15479  InvokeObjectPostAlterHook(RelationRelationId,
15480  RelationGetRelid(rel), 0);
15481  relation_close(rel, NoLock);
15482  return;
15483  }
15484 
15485  reltoastrelid = rel->rd_rel->reltoastrelid;
15486  /* Fetch the list of indexes on toast relation if necessary */
15487  if (OidIsValid(reltoastrelid))
15488  {
15489  Relation toastRel = relation_open(reltoastrelid, lockmode);
15490 
15491  reltoastidxids = RelationGetIndexList(toastRel);
15492  relation_close(toastRel, lockmode);
15493  }
15494 
15495  /*
15496  * Relfilenumbers are not unique in databases across tablespaces, so we
15497  * need to allocate a new one in the new tablespace.
15498  */
15499  newrelfilenumber = GetNewRelFileNumber(newTableSpace, NULL,
15500  rel->rd_rel->relpersistence);
15501 
15502  /* Open old and new relation */
15503  newrlocator = rel->rd_locator;
15504  newrlocator.relNumber = newrelfilenumber;
15505  newrlocator.spcOid = newTableSpace;
15506 
15507  /* hand off to AM to actually create new rel storage and copy the data */
15508  if (rel->rd_rel->relkind == RELKIND_INDEX)
15509  {
15510  index_copy_data(rel, newrlocator);
15511  }
15512  else
15513  {
15514  Assert(RELKIND_HAS_TABLE_AM(rel->rd_rel->relkind));
15515  table_relation_copy_data(rel, &newrlocator);
15516  }
15517 
15518  /*
15519  * Update the pg_class row.
15520  *
15521  * NB: This wouldn't work if ATExecSetTableSpace() were allowed to be
15522  * executed on pg_class or its indexes (the above copy wouldn't contain
15523  * the updated pg_class entry), but that's forbidden with
15524  * CheckRelationTableSpaceMove().
15525  */
15526  SetRelationTableSpace(rel, newTableSpace, newrelfilenumber);
15527 
15528  InvokeObjectPostAlterHook(RelationRelationId, RelationGetRelid(rel), 0);
15529 
15531 
15532  relation_close(rel, NoLock);
15533 
15534  /* Make sure the reltablespace change is visible */
15536 
15537  /* Move associated toast relation and/or indexes, too */
15538  if (OidIsValid(reltoastrelid))
15539  ATExecSetTableSpace(reltoastrelid, newTableSpace, lockmode);
15540  foreach(lc, reltoastidxids)
15541  ATExecSetTableSpace(lfirst_oid(lc), newTableSpace, lockmode);
15542 
15543  /* Clean up */
15544  list_free(reltoastidxids);
15545 }
15546 
15547 /*
15548  * Special handling of ALTER TABLE SET TABLESPACE for relations with no
15549  * storage that have an interest in preserving tablespace.
15550  *
15551  * Since these have no storage the tablespace can be updated with a simple
15552  * metadata only operation to update the tablespace.
15553  */
15554 static void
15556 {
15557  /*
15558  * Shouldn't be called on relations having storage; these are processed in
15559  * phase 3.
15560  */
15561  Assert(!RELKIND_HAS_STORAGE(rel->rd_rel->relkind));
15562 
15563  /* check if relation can be moved to its new tablespace */
15564  if (!CheckRelationTableSpaceMove(rel, newTableSpace))
15565  {
15566  InvokeObjectPostAlterHook(RelationRelationId,
15567  RelationGetRelid(rel),
15568  0);
15569  return;
15570  }
15571 
15572  /* Update can be done, so change reltablespace */
15573  SetRelationTableSpace(rel, newTableSpace, InvalidOid);
15574 
15575  InvokeObjectPostAlterHook(RelationRelationId, RelationGetRelid(rel), 0);
15576 
15577  /* Make sure the reltablespace change is visible */
15579 }
15580 
15581 /*
15582  * Alter Table ALL ... SET TABLESPACE
15583  *
15584  * Allows a user to move all objects of some type in a given tablespace in the
15585  * current database to another tablespace. Objects can be chosen based on the
15586  * owner of the object also, to allow users to move only their objects.
15587  * The user must have CREATE rights on the new tablespace, as usual. The main
15588  * permissions handling is done by the lower-level table move function.
15589  *
15590  * All to-be-moved objects are locked first. If NOWAIT is specified and the
15591  * lock can't be acquired then we ereport(ERROR).
15592  */
15593 Oid
15595 {
15596  List *relations = NIL;
15597  ListCell *l;
15598  ScanKeyData key[1];
15599  Relation rel;
15600  TableScanDesc scan;
15601  HeapTuple tuple;
15602  Oid orig_tablespaceoid;
15603  Oid new_tablespaceoid;
15604  List *role_oids = roleSpecsToIds(stmt->roles);
15605 
15606  /* Ensure we were not asked to move something we can't */
15607  if (stmt->objtype != OBJECT_TABLE && stmt->objtype != OBJECT_INDEX &&
15608  stmt->objtype != OBJECT_MATVIEW)
15609  ereport(ERROR,
15610  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
15611  errmsg("only tables, indexes, and materialized views exist in tablespaces")));
15612 
15613  /* Get the orig and new tablespace OIDs */
15614  orig_tablespaceoid = get_tablespace_oid(stmt->orig_tablespacename, false);
15615  new_tablespaceoid = get_tablespace_oid(stmt->new_tablespacename, false);
15616 
15617  /* Can't move shared relations in to or out of pg_global */
15618  /* This is also checked by ATExecSetTableSpace, but nice to stop earlier */
15619  if (orig_tablespaceoid == GLOBALTABLESPACE_OID ||
15620  new_tablespaceoid == GLOBALTABLESPACE_OID)
15621  ereport(ERROR,
15622  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
15623  errmsg("cannot move relations in to or out of pg_global tablespace")));
15624 
15625  /*
15626  * Must have CREATE rights on the new tablespace, unless it is the
15627  * database default tablespace (which all users implicitly have CREATE
15628  * rights on).
15629  */
15630  if (OidIsValid(new_tablespaceoid) && new_tablespaceoid != MyDatabaseTableSpace)
15631  {
15632  AclResult aclresult;
15633 
15634  aclresult = object_aclcheck(TableSpaceRelationId, new_tablespaceoid, GetUserId(),
15635  ACL_CREATE);
15636  if (aclresult != ACLCHECK_OK)
15637  aclcheck_error(aclresult, OBJECT_TABLESPACE,
15638  get_tablespace_name(new_tablespaceoid));
15639  }
15640 
15641  /*
15642  * Now that the checks are done, check if we should set either to
15643  * InvalidOid because it is our database's default tablespace.
15644  */
15645  if (orig_tablespaceoid == MyDatabaseTableSpace)
15646  orig_tablespaceoid = InvalidOid;
15647 
15648  if (new_tablespaceoid == MyDatabaseTableSpace)
15649  new_tablespaceoid = InvalidOid;
15650 
15651  /* no-op */
15652  if (orig_tablespaceoid == new_tablespaceoid)
15653  return new_tablespaceoid;
15654 
15655  /*
15656  * Walk the list of objects in the tablespace and move them. This will
15657  * only find objects in our database, of course.
15658  */
15659  ScanKeyInit(&key[0],
15660  Anum_pg_class_reltablespace,
15661  BTEqualStrategyNumber, F_OIDEQ,
15662  ObjectIdGetDatum(orig_tablespaceoid));
15663 
15664  rel = table_open(RelationRelationId, AccessShareLock);
15665  scan = table_beginscan_catalog(rel, 1, key);
15666  while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
15667  {
15668  Form_pg_class relForm = (Form_pg_class) GETSTRUCT(tuple);
15669  Oid relOid = relForm->oid;
15670 
15671  /*
15672  * Do not move objects in pg_catalog as part of this, if an admin
15673  * really wishes to do so, they can issue the individual ALTER
15674  * commands directly.
15675  *
15676  * Also, explicitly avoid any shared tables, temp tables, or TOAST
15677  * (TOAST will be moved with the main table).
15678  */
15679  if (IsCatalogNamespace(relForm->relnamespace) ||
15680  relForm->relisshared ||
15681  isAnyTempNamespace(relForm->relnamespace) ||
15682  IsToastNamespace(relForm->relnamespace))
15683  continue;
15684 
15685  /* Only move the object type requested */
15686  if ((stmt->objtype == OBJECT_TABLE &&
15687  relForm->relkind != RELKIND_RELATION &&
15688  relForm->relkind != RELKIND_PARTITIONED_TABLE) ||
15689  (stmt->objtype == OBJECT_INDEX &&
15690  relForm->relkind != RELKIND_INDEX &&
15691  relForm->relkind != RELKIND_PARTITIONED_INDEX) ||
15692  (stmt->objtype == OBJECT_MATVIEW &&
15693  relForm->relkind != RELKIND_MATVIEW))
15694  continue;
15695 
15696  /* Check if we are only moving objects owned by certain roles */
15697  if (role_oids != NIL && !list_member_oid(role_oids, relForm->relowner))
15698  continue;
15699 
15700  /*
15701  * Handle permissions-checking here since we are locking the tables
15702  * and also to avoid doing a bunch of work only to fail part-way. Note
15703  * that permissions will also be checked by AlterTableInternal().
15704  *
15705  * Caller must be considered an owner on the table to move it.
15706  */
15707  if (!object_ownercheck(RelationRelationId, relOid, GetUserId()))
15709  NameStr(relForm->relname));
15710 
15711  if (stmt->nowait &&
15713  ereport(ERROR,
15714  (errcode(ERRCODE_OBJECT_IN_USE),
15715  errmsg("aborting because lock on relation \"%s.%s\" is not available",
15716  get_namespace_name(relForm->relnamespace),
15717  NameStr(relForm->relname))));
15718  else
15720 
15721  /* Add to our list of objects to move */
15722  relations = lappend_oid(relations, relOid);
15723  }
15724 
15725  table_endscan(scan);
15727 
15728  if (relations == NIL)
15729  ereport(NOTICE,
15730  (errcode(ERRCODE_NO_DATA_FOUND),
15731  errmsg("no matching relations in tablespace \"%s\" found",
15732  orig_tablespaceoid == InvalidOid ? "(database default)" :
15733  get_tablespace_name(orig_tablespaceoid))));
15734 
15735  /* Everything is locked, loop through and move all of the relations. */
15736  foreach(l, relations)
15737  {
15738  List *cmds = NIL;
15740 
15741  cmd->subtype = AT_SetTableSpace;
15742  cmd->name = stmt->new_tablespacename;
15743 
15744  cmds = lappend(cmds, cmd);
15745 
15747  /* OID is set by AlterTableInternal */
15748  AlterTableInternal(lfirst_oid(l), cmds, false);
15750  }
15751 
15752  return new_tablespaceoid;
15753 }
15754 
15755 static void
15757 {
15758  SMgrRelation dstrel;
15759 
15760  /*
15761  * Since we copy the file directly without looking at the shared buffers,
15762  * we'd better first flush out any pages of the source relation that are
15763  * in shared buffers. We assume no new changes will be made while we are
15764  * holding exclusive lock on the rel.
15765  */
15766  FlushRelationBuffers(rel);
15767 
15768  /*
15769  * Create and copy all forks of the relation, and schedule unlinking of
15770  * old physical files.
15771  *
15772  * NOTE: any conflict in relfilenumber value will be caught in
15773  * RelationCreateStorage().
15774  */
15775  dstrel = RelationCreateStorage(newrlocator, rel->rd_rel->relpersistence, true);
15776 
15777  /* copy main fork */
15779  rel->rd_rel->relpersistence);
15780 
15781  /* copy those extra forks that exist */
15782  for (ForkNumber forkNum = MAIN_FORKNUM + 1;
15783  forkNum <= MAX_FORKNUM; forkNum++)
15784  {
15785  if (smgrexists(RelationGetSmgr(rel), forkNum))
15786  {
15787  smgrcreate(dstrel, forkNum, false);
15788 
15789  /*
15790  * WAL log creation if the relation is persistent, or this is the
15791  * init fork of an unlogged relation.
15792  */
15793  if (RelationIsPermanent(rel) ||
15794  (rel->rd_rel->relpersistence == RELPERSISTENCE_UNLOGGED &&
15795  forkNum == INIT_FORKNUM))
15796  log_smgrcreate(&newrlocator, forkNum);
15797  RelationCopyStorage(RelationGetSmgr(rel), dstrel, forkNum,
15798  rel->rd_rel->relpersistence);
15799  }
15800  }
15801 
15802  /* drop old relation, and close new one */
15803  RelationDropStorage(rel);
15804  smgrclose(dstrel);
15805 }
15806 
15807 /*
15808  * ALTER TABLE ENABLE/DISABLE TRIGGER
15809  *
15810  * We just pass this off to trigger.c.
15811  */
15812 static void
15813 ATExecEnableDisableTrigger(Relation rel, const char *trigname,
15814  char fires_when, bool skip_system, bool recurse,
15815  LOCKMODE lockmode)
15816 {
15817  EnableDisableTrigger(rel, trigname, InvalidOid,
15818  fires_when, skip_system, recurse,
15819  lockmode);
15820 
15821  InvokeObjectPostAlterHook(RelationRelationId,
15822  RelationGetRelid(rel), 0);
15823 }
15824 
15825 /*
15826  * ALTER TABLE ENABLE/DISABLE RULE
15827  *
15828  * We just pass this off to rewriteDefine.c.
15829  */
15830 static void
15831 ATExecEnableDisableRule(Relation rel, const char *rulename,
15832  char fires_when, LOCKMODE lockmode)
15833 {
15834  EnableDisableRule(rel, rulename, fires_when);
15835 
15836  InvokeObjectPostAlterHook(RelationRelationId,
15837  RelationGetRelid(rel), 0);
15838 }
15839 
15840 /*
15841  * ALTER TABLE INHERIT
15842  *
15843  * Add a parent to the child's parents. This verifies that all the columns and
15844  * check constraints of the parent appear in the child and that they have the
15845  * same data types and expressions.
15846  */
15847 static void
15849 {
15850  if (child_rel->rd_rel->reloftype)
15851  ereport(ERROR,
15852  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
15853  errmsg("cannot change inheritance of typed table")));
15854 
15855  if (child_rel->rd_rel->relispartition)
15856  ereport(ERROR,
15857  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
15858  errmsg("cannot change inheritance of a partition")));
15859 
15860  if (child_rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
15861  ereport(ERROR,
15862  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
15863  errmsg("cannot change inheritance of partitioned table")));
15864 }
15865 
15866 /*
15867  * Return the address of the new parent relation.
15868  */
15869 static ObjectAddress
15870 ATExecAddInherit(Relation child_rel, RangeVar *parent, LOCKMODE lockmode)
15871 {
15872  Relation parent_rel;
15873  List *children;
15874  ObjectAddress address;
15875  const char *trigger_name;
15876 
15877  /*
15878  * A self-exclusive lock is needed here. See the similar case in
15879  * MergeAttributes() for a full explanation.
15880  */
15881  parent_rel = table_openrv(parent, ShareUpdateExclusiveLock);
15882 
15883  /*
15884  * Must be owner of both parent and child -- child was checked by
15885  * ATSimplePermissions call in ATPrepCmd
15886  */
15888 
15889  /* Permanent rels cannot inherit from temporary ones */
15890  if (parent_rel->rd_rel->relpersistence == RELPERSISTENCE_TEMP &&
15891  child_rel->rd_rel->relpersistence != RELPERSISTENCE_TEMP)
15892  ereport(ERROR,
15893  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
15894  errmsg("cannot inherit from temporary relation \"%s\"",
15895  RelationGetRelationName(parent_rel))));
15896 
15897  /* If parent rel is temp, it must belong to this session */
15898  if (parent_rel->rd_rel->relpersistence == RELPERSISTENCE_TEMP &&
15899  !parent_rel->rd_islocaltemp)
15900  ereport(ERROR,
15901  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
15902  errmsg("cannot inherit from temporary relation of another session")));
15903 
15904  /* Ditto for the child */
15905  if (child_rel->rd_rel->relpersistence == RELPERSISTENCE_TEMP &&
15906  !child_rel->rd_islocaltemp)
15907  ereport(ERROR,
15908  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
15909  errmsg("cannot inherit to temporary relation of another session")));
15910 
15911  /* Prevent partitioned tables from becoming inheritance parents */
15912  if (parent_rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
15913  ereport(ERROR,
15914  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
15915  errmsg("cannot inherit from partitioned table \"%s\"",
15916  parent->relname)));
15917 
15918  /* Likewise for partitions */
15919  if (parent_rel->rd_rel->relispartition)
15920  ereport(ERROR,
15921  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
15922  errmsg("cannot inherit from a partition")));
15923 
15924  /*
15925  * Prevent circularity by seeing if proposed parent inherits from child.
15926  * (In particular, this disallows making a rel inherit from itself.)
15927  *
15928  * This is not completely bulletproof because of race conditions: in
15929  * multi-level inheritance trees, someone else could concurrently be
15930  * making another inheritance link that closes the loop but does not join
15931  * either of the rels we have locked. Preventing that seems to require
15932  * exclusive locks on the entire inheritance tree, which is a cure worse
15933  * than the disease. find_all_inheritors() will cope with circularity
15934  * anyway, so don't sweat it too much.
15935  *
15936  * We use weakest lock we can on child's children, namely AccessShareLock.
15937  */
15938  children = find_all_inheritors(RelationGetRelid(child_rel),
15939  AccessShareLock, NULL);
15940 
15941  if (list_member_oid(children, RelationGetRelid(parent_rel)))
15942  ereport(ERROR,
15943  (errcode(ERRCODE_DUPLICATE_TABLE),
15944  errmsg("circular inheritance not allowed"),
15945  errdetail("\"%s\" is already a child of \"%s\".",
15946  parent->relname,
15947  RelationGetRelationName(child_rel))));
15948 
15949  /*
15950  * If child_rel has row-level triggers with transition tables, we
15951  * currently don't allow it to become an inheritance child. See also
15952  * prohibitions in ATExecAttachPartition() and CreateTrigger().
15953  */
15954  trigger_name = FindTriggerIncompatibleWithInheritance(child_rel->trigdesc);
15955  if (trigger_name != NULL)
15956  ereport(ERROR,
15957  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
15958  errmsg("trigger \"%s\" prevents table \"%s\" from becoming an inheritance child",
15959  trigger_name, RelationGetRelationName(child_rel)),
15960  errdetail("ROW triggers with transition tables are not supported in inheritance hierarchies.")));
15961 
15962  /* OK to create inheritance */
15963  CreateInheritance(child_rel, parent_rel, false);
15964 
15965  /*
15966  * If parent_rel has a primary key, then child_rel has not-null
15967  * constraints that make these columns as non nullable. Make those
15968  * constraints as inherited.
15969  */
15970  ATInheritAdjustNotNulls(parent_rel, child_rel, 1);
15971 
15972  ObjectAddressSet(address, RelationRelationId,
15973  RelationGetRelid(parent_rel));
15974 
15975  /* keep our lock on the parent relation until commit */
15976  table_close(parent_rel, NoLock);
15977 
15978  return address;
15979 }
15980 
15981 /*
15982  * CreateInheritance
15983  * Catalog manipulation portion of creating inheritance between a child
15984  * table and a parent table.
15985  *
15986  * Common to ATExecAddInherit() and ATExecAttachPartition().
15987  */
15988 static void
15989 CreateInheritance(Relation child_rel, Relation parent_rel, bool ispartition)
15990 {
15991  Relation catalogRelation;
15992  SysScanDesc scan;
15993  ScanKeyData key;
15994  HeapTuple inheritsTuple;
15995  int32 inhseqno;
15996 
15997  /* Note: get RowExclusiveLock because we will write pg_inherits below. */
15998  catalogRelation = table_open(InheritsRelationId, RowExclusiveLock);
15999 
16000  /*
16001  * Check for duplicates in the list of parents, and determine the highest
16002  * inhseqno already present; we'll use the next one for the new parent.
16003  * Also, if proposed child is a partition, it cannot already be
16004  * inheriting.
16005  *
16006  * Note: we do not reject the case where the child already inherits from
16007  * the parent indirectly; CREATE TABLE doesn't reject comparable cases.
16008  */
16009  ScanKeyInit(&key,
16010  Anum_pg_inherits_inhrelid,
16011  BTEqualStrategyNumber, F_OIDEQ,
16012  ObjectIdGetDatum(RelationGetRelid(child_rel)));
16013  scan = systable_beginscan(catalogRelation, InheritsRelidSeqnoIndexId,
16014  true, NULL, 1, &key);
16015 
16016  /* inhseqno sequences start at 1 */
16017  inhseqno = 0;
16018  while (HeapTupleIsValid(inheritsTuple = systable_getnext(scan)))
16019  {
16020  Form_pg_inherits inh = (Form_pg_inherits) GETSTRUCT(inheritsTuple);
16021 
16022  if (inh->inhparent == RelationGetRelid(parent_rel))
16023  ereport(ERROR,
16024  (errcode(ERRCODE_DUPLICATE_TABLE),
16025  errmsg("relation \"%s\" would be inherited from more than once",
16026  RelationGetRelationName(parent_rel))));
16027 
16028  if (inh->inhseqno > inhseqno)
16029  inhseqno = inh->inhseqno;
16030  }
16031  systable_endscan(scan);
16032 
16033  /* Match up the columns and bump attinhcount as needed */
16034  MergeAttributesIntoExisting(child_rel, parent_rel, ispartition);
16035 
16036  /* Match up the constraints and bump coninhcount as needed */
16037  MergeConstraintsIntoExisting(child_rel, parent_rel);
16038 
16039  /*
16040  * OK, it looks valid. Make the catalog entries that show inheritance.
16041  */
16043  RelationGetRelid(parent_rel),
16044  inhseqno + 1,
16045  catalogRelation,
16046  parent_rel->rd_rel->relkind ==
16047  RELKIND_PARTITIONED_TABLE);
16048 
16049  /* Now we're done with pg_inherits */
16050  table_close(catalogRelation, RowExclusiveLock);
16051 }
16052 
16053 /*
16054  * Obtain the source-text form of the constraint expression for a check
16055  * constraint, given its pg_constraint tuple
16056  */
16057 static char *
16059 {
16060  Form_pg_constraint con;
16061  bool isnull;
16062  Datum attr;
16063  Datum expr;
16064 
16065  con = (Form_pg_constraint) GETSTRUCT(contup);
16066  attr = heap_getattr(contup, Anum_pg_constraint_conbin, tupdesc, &isnull);
16067  if (isnull)
16068  elog(ERROR, "null conbin for constraint %u", con->oid);
16069 
16070  expr = DirectFunctionCall2(pg_get_expr, attr,
16071  ObjectIdGetDatum(con->conrelid));
16072  return TextDatumGetCString(expr);
16073 }
16074 
16075 /*
16076  * Determine whether two check constraints are functionally equivalent
16077  *
16078  * The test we apply is to see whether they reverse-compile to the same
16079  * source string. This insulates us from issues like whether attributes
16080  * have the same physical column numbers in parent and child relations.
16081  */
16082 static bool
16084 {
16087 
16088  if (acon->condeferrable != bcon->condeferrable ||
16089  acon->condeferred != bcon->condeferred ||
16090  strcmp(decompile_conbin(a, tupleDesc),
16091  decompile_conbin(b, tupleDesc)) != 0)
16092  return false;
16093  else
16094  return true;
16095 }
16096 
16097 /*
16098  * Check columns in child table match up with columns in parent, and increment
16099  * their attinhcount.
16100  *
16101  * Called by CreateInheritance
16102  *
16103  * Currently all parent columns must be found in child. Missing columns are an
16104  * error. One day we might consider creating new columns like CREATE TABLE
16105  * does. However, that is widely unpopular --- in the common use case of
16106  * partitioned tables it's a foot-gun.
16107  *
16108  * The data type must match exactly. If the parent column is NOT NULL then
16109  * the child must be as well. Defaults are not compared, however.
16110  */
16111 static void
16112 MergeAttributesIntoExisting(Relation child_rel, Relation parent_rel, bool ispartition)
16113 {
16114  Relation attrrel;
16115  TupleDesc parent_desc;
16116 
16117  attrrel = table_open(AttributeRelationId, RowExclusiveLock);
16118  parent_desc = RelationGetDescr(parent_rel);
16119 
16120  for (AttrNumber parent_attno = 1; parent_attno <= parent_desc->natts; parent_attno++)
16121  {
16122  Form_pg_attribute parent_att = TupleDescAttr(parent_desc, parent_attno - 1);
16123  char *parent_attname = NameStr(parent_att->attname);
16124  HeapTuple tuple;
16125 
16126  /* Ignore dropped columns in the parent. */
16127  if (parent_att->attisdropped)
16128  continue;
16129 
16130  /* Find same column in child (matching on column name). */
16131  tuple = SearchSysCacheCopyAttName(RelationGetRelid(child_rel), parent_attname);
16132  if (HeapTupleIsValid(tuple))
16133  {
16134  Form_pg_attribute child_att = (Form_pg_attribute) GETSTRUCT(tuple);
16135 
16136  if (parent_att->atttypid != child_att->atttypid ||
16137  parent_att->atttypmod != child_att->atttypmod)
16138  ereport(ERROR,
16139  (errcode(ERRCODE_DATATYPE_MISMATCH),
16140  errmsg("child table \"%s\" has different type for column \"%s\"",
16141  RelationGetRelationName(child_rel), parent_attname)));
16142 
16143  if (parent_att->attcollation != child_att->attcollation)
16144  ereport(ERROR,
16145  (errcode(ERRCODE_COLLATION_MISMATCH),
16146  errmsg("child table \"%s\" has different collation for column \"%s\"",
16147  RelationGetRelationName(child_rel), parent_attname)));
16148 
16149  /*
16150  * If the parent has a not-null constraint that's not NO INHERIT,
16151  * make sure the child has one too.
16152  *
16153  * Other constraints are checked elsewhere.
16154  */
16155  if (parent_att->attnotnull && !child_att->attnotnull)
16156  {
16157  HeapTuple contup;
16158 
16159  contup = findNotNullConstraintAttnum(RelationGetRelid(parent_rel),
16160  parent_att->attnum);
16161  if (HeapTupleIsValid(contup) &&
16162  !((Form_pg_constraint) GETSTRUCT(contup))->connoinherit)
16163  ereport(ERROR,
16164  errcode(ERRCODE_DATATYPE_MISMATCH),
16165  errmsg("column \"%s\" in child table must be marked NOT NULL",
16166  parent_attname));
16167  }
16168 
16169  /*
16170  * Child column must be generated if and only if parent column is.
16171  */
16172  if (parent_att->attgenerated && !child_att->attgenerated)
16173  ereport(ERROR,
16174  (errcode(ERRCODE_DATATYPE_MISMATCH),
16175  errmsg("column \"%s\" in child table must be a generated column", parent_attname)));
16176  if (child_att->attgenerated && !parent_att->attgenerated)
16177  ereport(ERROR,
16178  (errcode(ERRCODE_DATATYPE_MISMATCH),
16179  errmsg("column \"%s\" in child table must not be a generated column", parent_attname)));
16180 
16181  /*
16182  * Regular inheritance children are independent enough not to
16183  * inherit identity columns. But partitions are integral part of
16184  * a partitioned table and inherit identity column.
16185  */
16186  if (ispartition)
16187  child_att->attidentity = parent_att->attidentity;
16188 
16189  /*
16190  * OK, bump the child column's inheritance count. (If we fail
16191  * later on, this change will just roll back.)
16192  */
16193  child_att->attinhcount++;
16194  if (child_att->attinhcount < 0)
16195  ereport(ERROR,
16196  errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
16197  errmsg("too many inheritance parents"));
16198 
16199  /*
16200  * In case of partitions, we must enforce that value of attislocal
16201  * is same in all partitions. (Note: there are only inherited
16202  * attributes in partitions)
16203  */
16204  if (parent_rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
16205  {
16206  Assert(child_att->attinhcount == 1);
16207  child_att->attislocal = false;
16208  }
16209 
16210  CatalogTupleUpdate(attrrel, &tuple->t_self, tuple);
16211  heap_freetuple(tuple);
16212  }
16213  else
16214  {
16215  ereport(ERROR,
16216  (errcode(ERRCODE_DATATYPE_MISMATCH),
16217  errmsg("child table is missing column \"%s\"", parent_attname)));
16218  }
16219  }
16220 
16221  table_close(attrrel, RowExclusiveLock);
16222 }
16223 
16224 /*
16225  * Check constraints in child table match up with constraints in parent,
16226  * and increment their coninhcount.
16227  *
16228  * Constraints that are marked ONLY in the parent are ignored.
16229  *
16230  * Called by CreateInheritance
16231  *
16232  * Currently all constraints in parent must be present in the child. One day we
16233  * may consider adding new constraints like CREATE TABLE does.
16234  *
16235  * XXX This is O(N^2) which may be an issue with tables with hundreds of
16236  * constraints. As long as tables have more like 10 constraints it shouldn't be
16237  * a problem though. Even 100 constraints ought not be the end of the world.
16238  *
16239  * XXX See MergeWithExistingConstraint too if you change this code.
16240  */
16241 static void
16243 {
16244  Relation constraintrel;
16245  SysScanDesc parent_scan;
16246  ScanKeyData parent_key;
16247  HeapTuple parent_tuple;
16248  Oid parent_relid = RelationGetRelid(parent_rel);
16249 
16250  constraintrel = table_open(ConstraintRelationId, RowExclusiveLock);
16251 
16252  /* Outer loop scans through the parent's constraint definitions */
16253  ScanKeyInit(&parent_key,
16254  Anum_pg_constraint_conrelid,
16255  BTEqualStrategyNumber, F_OIDEQ,
16256  ObjectIdGetDatum(parent_relid));
16257  parent_scan = systable_beginscan(constraintrel, ConstraintRelidTypidNameIndexId,
16258  true, NULL, 1, &parent_key);
16259 
16260  while (HeapTupleIsValid(parent_tuple = systable_getnext(parent_scan)))
16261  {
16262  Form_pg_constraint parent_con = (Form_pg_constraint) GETSTRUCT(parent_tuple);
16263  SysScanDesc child_scan;
16264  ScanKeyData child_key;
16265  HeapTuple child_tuple;
16266  bool found = false;
16267 
16268  if (parent_con->contype != CONSTRAINT_CHECK &&
16269  parent_con->contype != CONSTRAINT_NOTNULL)
16270  continue;
16271 
16272  /* if the parent's constraint is marked NO INHERIT, it's not inherited */
16273  if (parent_con->connoinherit)
16274  continue;
16275 
16276  /* Search for a child constraint matching this one */
16277  ScanKeyInit(&child_key,
16278  Anum_pg_constraint_conrelid,
16279  BTEqualStrategyNumber, F_OIDEQ,
16280  ObjectIdGetDatum(RelationGetRelid(child_rel)));
16281  child_scan = systable_beginscan(constraintrel, ConstraintRelidTypidNameIndexId,
16282  true, NULL, 1, &child_key);
16283 
16284  while (HeapTupleIsValid(child_tuple = systable_getnext(child_scan)))
16285  {
16286  Form_pg_constraint child_con = (Form_pg_constraint) GETSTRUCT(child_tuple);
16287  HeapTuple child_copy;
16288 
16289  if (child_con->contype != parent_con->contype)
16290  continue;
16291 
16292  /*
16293  * CHECK constraint are matched by name, NOT NULL ones by
16294  * attribute number
16295  */
16296  if (child_con->contype == CONSTRAINT_CHECK)
16297  {
16298  if (strcmp(NameStr(parent_con->conname),
16299  NameStr(child_con->conname)) != 0)
16300  continue;
16301  }
16302  else if (child_con->contype == CONSTRAINT_NOTNULL)
16303  {
16304  AttrNumber parent_attno = extractNotNullColumn(parent_tuple);
16305  AttrNumber child_attno = extractNotNullColumn(child_tuple);
16306 
16307  if (strcmp(get_attname(parent_relid, parent_attno, false),
16308  get_attname(RelationGetRelid(child_rel), child_attno,
16309  false)) != 0)
16310  continue;
16311  }
16312 
16313  if (child_con->contype == CONSTRAINT_CHECK &&
16314  !constraints_equivalent(parent_tuple, child_tuple, RelationGetDescr(constraintrel)))
16315  ereport(ERROR,
16316  (errcode(ERRCODE_DATATYPE_MISMATCH),
16317  errmsg("child table \"%s\" has different definition for check constraint \"%s\"",
16318  RelationGetRelationName(child_rel), NameStr(parent_con->conname))));
16319 
16320  /*
16321  * If the CHECK child constraint is "no inherit" then cannot
16322  * merge.
16323  *
16324  * This is not desirable for not-null constraints, mostly because
16325  * it breaks our pg_upgrade strategy, but it also makes sense on
16326  * its own: if a child has its own not-null constraint and then
16327  * acquires a parent with the same constraint, then we start to
16328  * enforce that constraint for all the descendants of that child
16329  * too, if any.
16330  */
16331  if (child_con->contype == CONSTRAINT_CHECK &&
16332  child_con->connoinherit)
16333  ereport(ERROR,
16334  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
16335  errmsg("constraint \"%s\" conflicts with non-inherited constraint on child table \"%s\"",
16336  NameStr(child_con->conname), RelationGetRelationName(child_rel))));
16337 
16338  /*
16339  * If the child constraint is "not valid" then cannot merge with a
16340  * valid parent constraint
16341  */
16342  if (parent_con->convalidated && !child_con->convalidated)
16343  ereport(ERROR,
16344  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
16345  errmsg("constraint \"%s\" conflicts with NOT VALID constraint on child table \"%s\"",
16346  NameStr(child_con->conname), RelationGetRelationName(child_rel))));
16347 
16348  /*
16349  * OK, bump the child constraint's inheritance count. (If we fail
16350  * later on, this change will just roll back.)
16351  */
16352  child_copy = heap_copytuple(child_tuple);
16353  child_con = (Form_pg_constraint) GETSTRUCT(child_copy);
16354  child_con->coninhcount++;
16355  if (child_con->coninhcount < 0)
16356  ereport(ERROR,
16357  errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
16358  errmsg("too many inheritance parents"));
16359  if (child_con->contype == CONSTRAINT_NOTNULL &&
16360  child_con->connoinherit)
16361  child_con->connoinherit = false;
16362 
16363  /*
16364  * In case of partitions, an inherited constraint must be
16365  * inherited only once since it cannot have multiple parents and
16366  * it is never considered local.
16367  */
16368  if (parent_rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
16369  {
16370  Assert(child_con->coninhcount == 1);
16371  child_con->conislocal = false;
16372  }
16373 
16374  CatalogTupleUpdate(constraintrel, &child_copy->t_self, child_copy);
16375  heap_freetuple(child_copy);
16376 
16377  found = true;
16378  break;
16379  }
16380 
16381  systable_endscan(child_scan);
16382 
16383  if (!found)
16384  {
16385  if (parent_con->contype == CONSTRAINT_NOTNULL)
16386  ereport(ERROR,
16387  errcode(ERRCODE_DATATYPE_MISMATCH),
16388  errmsg("column \"%s\" in child table must be marked NOT NULL",
16389  get_attname(parent_relid,
16390  extractNotNullColumn(parent_tuple),
16391  false)));
16392 
16393  ereport(ERROR,
16394  (errcode(ERRCODE_DATATYPE_MISMATCH),
16395  errmsg("child table is missing constraint \"%s\"",
16396  NameStr(parent_con->conname))));
16397  }
16398  }
16399 
16400  systable_endscan(parent_scan);
16401  table_close(constraintrel, RowExclusiveLock);
16402 }
16403 
16404 /*
16405  * ALTER TABLE NO INHERIT
16406  *
16407  * Return value is the address of the relation that is no longer parent.
16408  */
16409 static ObjectAddress
16411 {
16412  ObjectAddress address;
16413  Relation parent_rel;
16414 
16415  if (rel->rd_rel->relispartition)
16416  ereport(ERROR,
16417  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
16418  errmsg("cannot change inheritance of a partition")));
16419 
16420  /*
16421  * AccessShareLock on the parent is probably enough, seeing that DROP
16422  * TABLE doesn't lock parent tables at all. We need some lock since we'll
16423  * be inspecting the parent's schema.
16424  */
16425  parent_rel = table_openrv(parent, AccessShareLock);
16426 
16427  /*
16428  * We don't bother to check ownership of the parent table --- ownership of
16429  * the child is presumed enough rights.
16430  */
16431 
16432  /* Off to RemoveInheritance() where most of the work happens */
16433  RemoveInheritance(rel, parent_rel, false);
16434 
16435  /*
16436  * If parent_rel has a primary key, then child_rel has not-null
16437  * constraints that make these columns as non nullable. Mark those
16438  * constraints as no longer inherited by this parent.
16439  */
16440  ATInheritAdjustNotNulls(parent_rel, rel, -1);
16441 
16442  /*
16443  * If the parent has a primary key, then we decrement counts for all NOT
16444  * NULL constraints
16445  */
16446 
16447  ObjectAddressSet(address, RelationRelationId,
16448  RelationGetRelid(parent_rel));
16449 
16450  /* keep our lock on the parent relation until commit */
16451  table_close(parent_rel, NoLock);
16452 
16453  return address;
16454 }
16455 
16456 /*
16457  * MarkInheritDetached
16458  *
16459  * Set inhdetachpending for a partition, for ATExecDetachPartition
16460  * in concurrent mode. While at it, verify that no other partition is
16461  * already pending detach.
16462  */
16463 static void
16464 MarkInheritDetached(Relation child_rel, Relation parent_rel)
16465 {
16466  Relation catalogRelation;
16467  SysScanDesc scan;
16468  ScanKeyData key;
16469  HeapTuple inheritsTuple;
16470  bool found = false;
16471 
16472  Assert(parent_rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
16473 
16474  /*
16475  * Find pg_inherits entries by inhparent. (We need to scan them all in
16476  * order to verify that no other partition is pending detach.)
16477  */
16478  catalogRelation = table_open(InheritsRelationId, RowExclusiveLock);
16479  ScanKeyInit(&key,
16480  Anum_pg_inherits_inhparent,
16481  BTEqualStrategyNumber, F_OIDEQ,
16482  ObjectIdGetDatum(RelationGetRelid(parent_rel)));
16483  scan = systable_beginscan(catalogRelation, InheritsParentIndexId,
16484  true, NULL, 1, &key);
16485 
16486  while (HeapTupleIsValid(inheritsTuple = systable_getnext(scan)))
16487  {
16488  Form_pg_inherits inhForm;
16489 
16490  inhForm = (Form_pg_inherits) GETSTRUCT(inheritsTuple);
16491  if (inhForm->inhdetachpending)
16492  ereport(ERROR,
16493  errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
16494  errmsg("partition \"%s\" already pending detach in partitioned table \"%s.%s\"",
16495  get_rel_name(inhForm->inhrelid),
16496  get_namespace_name(parent_rel->rd_rel->relnamespace),
16497  RelationGetRelationName(parent_rel)),
16498  errhint("Use ALTER TABLE ... DETACH PARTITION ... FINALIZE to complete the pending detach operation."));
16499 
16500  if (inhForm->inhrelid == RelationGetRelid(child_rel))
16501  {
16502  HeapTuple newtup;
16503 
16504  newtup = heap_copytuple(inheritsTuple);
16505  ((Form_pg_inherits) GETSTRUCT(newtup))->inhdetachpending = true;
16506 
16507  CatalogTupleUpdate(catalogRelation,
16508  &inheritsTuple->t_self,
16509  newtup);
16510  found = true;
16511  heap_freetuple(newtup);
16512  /* keep looking, to ensure we catch others pending detach */
16513  }
16514  }
16515 
16516  /* Done */
16517  systable_endscan(scan);
16518  table_close(catalogRelation, RowExclusiveLock);
16519 
16520  if (!found)
16521  ereport(ERROR,
16523  errmsg("relation \"%s\" is not a partition of relation \"%s\"",
16524  RelationGetRelationName(child_rel),
16525  RelationGetRelationName(parent_rel))));
16526 }
16527 
16528 /*
16529  * RemoveInheritance
16530  *
16531  * Drop a parent from the child's parents. This just adjusts the attinhcount
16532  * and attislocal of the columns and removes the pg_inherit and pg_depend
16533  * entries. expect_detached is passed down to DeleteInheritsTuple, q.v..
16534  *
16535  * If attinhcount goes to 0 then attislocal gets set to true. If it goes back
16536  * up attislocal stays true, which means if a child is ever removed from a
16537  * parent then its columns will never be automatically dropped which may
16538  * surprise. But at least we'll never surprise by dropping columns someone
16539  * isn't expecting to be dropped which would actually mean data loss.
16540  *
16541  * coninhcount and conislocal for inherited constraints are adjusted in
16542  * exactly the same way.
16543  *
16544  * Common to ATExecDropInherit() and ATExecDetachPartition().
16545  */
16546 static void
16547 RemoveInheritance(Relation child_rel, Relation parent_rel, bool expect_detached)
16548 {
16549  Relation catalogRelation;
16550  SysScanDesc scan;
16551  ScanKeyData key[3];
16552  HeapTuple attributeTuple,
16553  constraintTuple;
16554  List *connames;
16555  List *nncolumns;
16556  bool found;
16557  bool is_partitioning;
16558 
16559  is_partitioning = (parent_rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
16560 
16561  found = DeleteInheritsTuple(RelationGetRelid(child_rel),
16562  RelationGetRelid(parent_rel),
16563  expect_detached,
16564  RelationGetRelationName(child_rel));
16565  if (!found)
16566  {
16567  if (is_partitioning)
16568  ereport(ERROR,
16570  errmsg("relation \"%s\" is not a partition of relation \"%s\"",
16571  RelationGetRelationName(child_rel),
16572  RelationGetRelationName(parent_rel))));
16573  else
16574  ereport(ERROR,
16576  errmsg("relation \"%s\" is not a parent of relation \"%s\"",
16577  RelationGetRelationName(parent_rel),
16578  RelationGetRelationName(child_rel))));
16579  }
16580 
16581  /*
16582  * Search through child columns looking for ones matching parent rel
16583  */
16584  catalogRelation = table_open(AttributeRelationId, RowExclusiveLock);
16585  ScanKeyInit(&key[0],
16586  Anum_pg_attribute_attrelid,
16587  BTEqualStrategyNumber, F_OIDEQ,
16588  ObjectIdGetDatum(RelationGetRelid(child_rel)));
16589  scan = systable_beginscan(catalogRelation, AttributeRelidNumIndexId,
16590  true, NULL, 1, key);
16591  while (HeapTupleIsValid(attributeTuple = systable_getnext(scan)))
16592  {
16593  Form_pg_attribute att = (Form_pg_attribute) GETSTRUCT(attributeTuple);
16594 
16595  /* Ignore if dropped or not inherited */
16596  if (att->attisdropped)
16597  continue;
16598  if (att->attinhcount <= 0)
16599  continue;
16600 
16602  NameStr(att->attname)))
16603  {
16604  /* Decrement inhcount and possibly set islocal to true */
16605  HeapTuple copyTuple = heap_copytuple(attributeTuple);
16606  Form_pg_attribute copy_att = (Form_pg_attribute) GETSTRUCT(copyTuple);
16607 
16608  copy_att->attinhcount--;
16609  if (copy_att->attinhcount == 0)
16610  copy_att->attislocal = true;
16611 
16612  CatalogTupleUpdate(catalogRelation, &copyTuple->t_self, copyTuple);
16613  heap_freetuple(copyTuple);
16614  }
16615  }
16616  systable_endscan(scan);
16617  table_close(catalogRelation, RowExclusiveLock);
16618 
16619  /*
16620  * Likewise, find inherited check constraints and disinherit them. To do
16621  * this, we first need a list of the names of the parent's check
16622  * constraints. (We cheat a bit by only checking for name matches,
16623  * assuming that the expressions will match.)
16624  *
16625  * For NOT NULL columns, we store column numbers to match.
16626  */
16627  catalogRelation = table_open(ConstraintRelationId, RowExclusiveLock);
16628  ScanKeyInit(&key[0],
16629  Anum_pg_constraint_conrelid,
16630  BTEqualStrategyNumber, F_OIDEQ,
16631  ObjectIdGetDatum(RelationGetRelid(parent_rel)));
16632  scan = systable_beginscan(catalogRelation, ConstraintRelidTypidNameIndexId,
16633  true, NULL, 1, key);
16634 
16635  connames = NIL;
16636  nncolumns = NIL;
16637 
16638  while (HeapTupleIsValid(constraintTuple = systable_getnext(scan)))
16639  {
16640  Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(constraintTuple);
16641 
16642  if (con->contype == CONSTRAINT_CHECK)
16643  connames = lappend(connames, pstrdup(NameStr(con->conname)));
16644  if (con->contype == CONSTRAINT_NOTNULL)
16645  nncolumns = lappend_int(nncolumns, extractNotNullColumn(constraintTuple));
16646  }
16647 
16648  systable_endscan(scan);
16649 
16650  /* Now scan the child's constraints */
16651  ScanKeyInit(&key[0],
16652  Anum_pg_constraint_conrelid,
16653  BTEqualStrategyNumber, F_OIDEQ,
16654  ObjectIdGetDatum(RelationGetRelid(child_rel)));
16655  scan = systable_beginscan(catalogRelation, ConstraintRelidTypidNameIndexId,
16656  true, NULL, 1, key);
16657 
16658  while (HeapTupleIsValid(constraintTuple = systable_getnext(scan)))
16659  {
16660  Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(constraintTuple);
16661  bool match = false;
16662  ListCell *lc;
16663 
16664  /*
16665  * Match CHECK constraints by name, not-null constraints by column
16666  * number, and ignore all others.
16667  */
16668  if (con->contype == CONSTRAINT_CHECK)
16669  {
16670  foreach(lc, connames)
16671  {
16672  if (con->contype == CONSTRAINT_CHECK &&
16673  strcmp(NameStr(con->conname), (char *) lfirst(lc)) == 0)
16674  {
16675  match = true;
16676  break;
16677  }
16678  }
16679  }
16680  else if (con->contype == CONSTRAINT_NOTNULL)
16681  {
16682  AttrNumber child_attno = extractNotNullColumn(constraintTuple);
16683 
16684  foreach(lc, nncolumns)
16685  {
16686  if (lfirst_int(lc) == child_attno)
16687  {
16688  match = true;
16689  break;
16690  }
16691  }
16692  }
16693  else
16694  continue;
16695 
16696  if (match)
16697  {
16698  /* Decrement inhcount and possibly set islocal to true */
16699  HeapTuple copyTuple = heap_copytuple(constraintTuple);
16700  Form_pg_constraint copy_con = (Form_pg_constraint) GETSTRUCT(copyTuple);
16701 
16702  if (copy_con->coninhcount <= 0) /* shouldn't happen */
16703  elog(ERROR, "relation %u has non-inherited constraint \"%s\"",
16704  RelationGetRelid(child_rel), NameStr(copy_con->conname));
16705 
16706  copy_con->coninhcount--;
16707  if (copy_con->coninhcount == 0)
16708  copy_con->conislocal = true;
16709 
16710  CatalogTupleUpdate(catalogRelation, &copyTuple->t_self, copyTuple);
16711  heap_freetuple(copyTuple);
16712  }
16713  }
16714 
16715  systable_endscan(scan);
16716  table_close(catalogRelation, RowExclusiveLock);
16717 
16719  RelationRelationId,
16720  RelationGetRelid(parent_rel),
16721  child_dependency_type(is_partitioning));
16722 
16723  /*
16724  * Post alter hook of this inherits. Since object_access_hook doesn't take
16725  * multiple object identifiers, we relay oid of parent relation using
16726  * auxiliary_id argument.
16727  */
16728  InvokeObjectPostAlterHookArg(InheritsRelationId,
16729  RelationGetRelid(child_rel), 0,
16730  RelationGetRelid(parent_rel), false);
16731 }
16732 
16733 /*
16734  * Adjust coninhcount of not-null constraints upwards or downwards when a
16735  * table is marked as inheriting or no longer doing so a table with a primary
16736  * key.
16737  *
16738  * Note: these constraints are not dropped, even if their inhcount goes to zero
16739  * and conislocal is false. Instead we mark the constraints as locally defined.
16740  * This is seen as more useful behavior, with no downsides. The user can always
16741  * drop them afterwards.
16742  */
16743 static void
16744 ATInheritAdjustNotNulls(Relation parent_rel, Relation child_rel, int inhcount)
16745 {
16746  Bitmapset *pkattnos;
16747 
16748  /* Quick exit when parent has no PK */
16749  if (!parent_rel->rd_rel->relhasindex)
16750  return;
16751 
16752  pkattnos = RelationGetIndexAttrBitmap(parent_rel,
16754  if (pkattnos != NULL)
16755  {
16756  Bitmapset *childattnums = NULL;
16757  AttrMap *attmap;
16758  int i;
16759 
16760  attmap = build_attrmap_by_name(RelationGetDescr(parent_rel),
16761  RelationGetDescr(child_rel), true);
16762 
16763  i = -1;
16764  while ((i = bms_next_member(pkattnos, i)) >= 0)
16765  {
16766  childattnums = bms_add_member(childattnums,
16768  }
16769 
16770  /*
16771  * CCI is needed in case there's a NOT NULL PRIMARY KEY column in the
16772  * parent: the relevant not-null constraint in the child already had
16773  * its inhcount modified earlier.
16774  */
16776  AdjustNotNullInheritance(RelationGetRelid(child_rel), childattnums,
16777  inhcount);
16778  }
16779 }
16780 
16781 /*
16782  * Drop the dependency created by StoreCatalogInheritance1 (CREATE TABLE
16783  * INHERITS/ALTER TABLE INHERIT -- refclassid will be RelationRelationId) or
16784  * heap_create_with_catalog (CREATE TABLE OF/ALTER TABLE OF -- refclassid will
16785  * be TypeRelationId). There's no convenient way to do this, so go trawling
16786  * through pg_depend.
16787  */
16788 static void
16789 drop_parent_dependency(Oid relid, Oid refclassid, Oid refobjid,
16790  DependencyType deptype)
16791 {
16792  Relation catalogRelation;
16793  SysScanDesc scan;
16794  ScanKeyData key[3];
16795  HeapTuple depTuple;
16796 
16797  catalogRelation = table_open(DependRelationId, RowExclusiveLock);
16798 
16799  ScanKeyInit(&key[0],
16800  Anum_pg_depend_classid,
16801  BTEqualStrategyNumber, F_OIDEQ,
16802  ObjectIdGetDatum(RelationRelationId));
16803  ScanKeyInit(&key[1],
16804  Anum_pg_depend_objid,
16805  BTEqualStrategyNumber, F_OIDEQ,
16806  ObjectIdGetDatum(relid));
16807  ScanKeyInit(&key[2],
16808  Anum_pg_depend_objsubid,
16809  BTEqualStrategyNumber, F_INT4EQ,
16810  Int32GetDatum(0));
16811 
16812  scan = systable_beginscan(catalogRelation, DependDependerIndexId, true,
16813  NULL, 3, key);
16814 
16815  while (HeapTupleIsValid(depTuple = systable_getnext(scan)))
16816  {
16817  Form_pg_depend dep = (Form_pg_depend) GETSTRUCT(depTuple);
16818 
16819  if (dep->refclassid == refclassid &&
16820  dep->refobjid == refobjid &&
16821  dep->refobjsubid == 0 &&
16822  dep->deptype == deptype)
16823  CatalogTupleDelete(catalogRelation, &depTuple->t_self);
16824  }
16825 
16826  systable_endscan(scan);
16827  table_close(catalogRelation, RowExclusiveLock);
16828 }
16829 
16830 /*
16831  * ALTER TABLE OF
16832  *
16833  * Attach a table to a composite type, as though it had been created with CREATE
16834  * TABLE OF. All attname, atttypid, atttypmod and attcollation must match. The
16835  * subject table must not have inheritance parents. These restrictions ensure
16836  * that you cannot create a configuration impossible with CREATE TABLE OF alone.
16837  *
16838  * The address of the type is returned.
16839  */
16840 static ObjectAddress
16841 ATExecAddOf(Relation rel, const TypeName *ofTypename, LOCKMODE lockmode)
16842 {
16843  Oid relid = RelationGetRelid(rel);
16844  Type typetuple;
16845  Form_pg_type typeform;
16846  Oid typeid;
16847  Relation inheritsRelation,
16848  relationRelation;
16849  SysScanDesc scan;
16850  ScanKeyData key;
16851  AttrNumber table_attno,
16852  type_attno;
16853  TupleDesc typeTupleDesc,
16854  tableTupleDesc;
16855  ObjectAddress tableobj,
16856  typeobj;
16857  HeapTuple classtuple;
16858 
16859  /* Validate the type. */
16860  typetuple = typenameType(NULL, ofTypename, NULL);
16861  check_of_type(typetuple);
16862  typeform = (Form_pg_type) GETSTRUCT(typetuple);
16863  typeid = typeform->oid;
16864 
16865  /* Fail if the table has any inheritance parents. */
16866  inheritsRelation = table_open(InheritsRelationId, AccessShareLock);
16867  ScanKeyInit(&key,
16868  Anum_pg_inherits_inhrelid,
16869  BTEqualStrategyNumber, F_OIDEQ,
16870  ObjectIdGetDatum(relid));
16871  scan = systable_beginscan(inheritsRelation, InheritsRelidSeqnoIndexId,
16872  true, NULL, 1, &key);
16874  ereport(ERROR,
16875  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
16876  errmsg("typed tables cannot inherit")));
16877  systable_endscan(scan);
16878  table_close(inheritsRelation, AccessShareLock);
16879 
16880  /*
16881  * Check the tuple descriptors for compatibility. Unlike inheritance, we
16882  * require that the order also match. However, attnotnull need not match.
16883  */
16884  typeTupleDesc = lookup_rowtype_tupdesc(typeid, -1);
16885  tableTupleDesc = RelationGetDescr(rel);
16886  table_attno = 1;
16887  for (type_attno = 1; type_attno <= typeTupleDesc->natts; type_attno++)
16888  {
16889  Form_pg_attribute type_attr,
16890  table_attr;
16891  const char *type_attname,
16892  *table_attname;
16893 
16894  /* Get the next non-dropped type attribute. */
16895  type_attr = TupleDescAttr(typeTupleDesc, type_attno - 1);
16896  if (type_attr->attisdropped)
16897  continue;
16898  type_attname = NameStr(type_attr->attname);
16899 
16900  /* Get the next non-dropped table attribute. */
16901  do
16902  {
16903  if (table_attno > tableTupleDesc->natts)
16904  ereport(ERROR,
16905  (errcode(ERRCODE_DATATYPE_MISMATCH),
16906  errmsg("table is missing column \"%s\"",
16907  type_attname)));
16908  table_attr = TupleDescAttr(tableTupleDesc, table_attno - 1);
16909  table_attno++;
16910  } while (table_attr->attisdropped);
16911  table_attname = NameStr(table_attr->attname);
16912 
16913  /* Compare name. */
16914  if (strncmp(table_attname, type_attname, NAMEDATALEN) != 0)
16915  ereport(ERROR,
16916  (errcode(ERRCODE_DATATYPE_MISMATCH),
16917  errmsg("table has column \"%s\" where type requires \"%s\"",
16918  table_attname, type_attname)));
16919 
16920  /* Compare type. */
16921  if (table_attr->atttypid != type_attr->atttypid ||
16922  table_attr->atttypmod != type_attr->atttypmod ||
16923  table_attr->attcollation != type_attr->attcollation)
16924  ereport(ERROR,
16925  (errcode(ERRCODE_DATATYPE_MISMATCH),
16926  errmsg("table \"%s\" has different type for column \"%s\"",
16927  RelationGetRelationName(rel), type_attname)));
16928  }
16929  ReleaseTupleDesc(typeTupleDesc);
16930 
16931  /* Any remaining columns at the end of the table had better be dropped. */
16932  for (; table_attno <= tableTupleDesc->natts; table_attno++)
16933  {
16934  Form_pg_attribute table_attr = TupleDescAttr(tableTupleDesc,
16935  table_attno - 1);
16936 
16937  if (!table_attr->attisdropped)
16938  ereport(ERROR,
16939  (errcode(ERRCODE_DATATYPE_MISMATCH),
16940  errmsg("table has extra column \"%s\"",
16941  NameStr(table_attr->attname))));
16942  }
16943 
16944  /* If the table was already typed, drop the existing dependency. */
16945  if (rel->rd_rel->reloftype)
16946  drop_parent_dependency(relid, TypeRelationId, rel->rd_rel->reloftype,
16948 
16949  /* Record a dependency on the new type. */
16950  tableobj.classId = RelationRelationId;
16951  tableobj.objectId = relid;
16952  tableobj.objectSubId = 0;
16953  typeobj.classId = TypeRelationId;
16954  typeobj.objectId = typeid;
16955  typeobj.objectSubId = 0;
16956  recordDependencyOn(&tableobj, &typeobj, DEPENDENCY_NORMAL);
16957 
16958  /* Update pg_class.reloftype */
16959  relationRelation = table_open(RelationRelationId, RowExclusiveLock);
16960  classtuple = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
16961  if (!HeapTupleIsValid(classtuple))
16962  elog(ERROR, "cache lookup failed for relation %u", relid);
16963  ((Form_pg_class) GETSTRUCT(classtuple))->reloftype = typeid;
16964  CatalogTupleUpdate(relationRelation, &classtuple->t_self, classtuple);
16965 
16966  InvokeObjectPostAlterHook(RelationRelationId, relid, 0);
16967 
16968  heap_freetuple(classtuple);
16969  table_close(relationRelation, RowExclusiveLock);
16970 
16971  ReleaseSysCache(typetuple);
16972 
16973  return typeobj;
16974 }
16975 
16976 /*
16977  * ALTER TABLE NOT OF
16978  *
16979  * Detach a typed table from its originating type. Just clear reloftype and
16980  * remove the dependency.
16981  */
16982 static void
16984 {
16985  Oid relid = RelationGetRelid(rel);
16986  Relation relationRelation;
16987  HeapTuple tuple;
16988 
16989  if (!OidIsValid(rel->rd_rel->reloftype))
16990  ereport(ERROR,
16991  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
16992  errmsg("\"%s\" is not a typed table",
16993  RelationGetRelationName(rel))));
16994 
16995  /*
16996  * We don't bother to check ownership of the type --- ownership of the
16997  * table is presumed enough rights. No lock required on the type, either.
16998  */
16999 
17000  drop_parent_dependency(relid, TypeRelationId, rel->rd_rel->reloftype,
17002 
17003  /* Clear pg_class.reloftype */
17004  relationRelation = table_open(RelationRelationId, RowExclusiveLock);
17005  tuple = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
17006  if (!HeapTupleIsValid(tuple))
17007  elog(ERROR, "cache lookup failed for relation %u", relid);
17008  ((Form_pg_class) GETSTRUCT(tuple))->reloftype = InvalidOid;
17009  CatalogTupleUpdate(relationRelation, &tuple->t_self, tuple);
17010 
17011  InvokeObjectPostAlterHook(RelationRelationId, relid, 0);
17012 
17013  heap_freetuple(tuple);
17014  table_close(relationRelation, RowExclusiveLock);
17015 }
17016 
17017 /*
17018  * relation_mark_replica_identity: Update a table's replica identity
17019  *
17020  * Iff ri_type = REPLICA_IDENTITY_INDEX, indexOid must be the Oid of a suitable
17021  * index. Otherwise, it must be InvalidOid.
17022  *
17023  * Caller had better hold an exclusive lock on the relation, as the results
17024  * of running two of these concurrently wouldn't be pretty.
17025  */
17026 static void
17027 relation_mark_replica_identity(Relation rel, char ri_type, Oid indexOid,
17028  bool is_internal)
17029 {
17030  Relation pg_index;
17031  Relation pg_class;
17032  HeapTuple pg_class_tuple;
17033  HeapTuple pg_index_tuple;
17034  Form_pg_class pg_class_form;
17035  Form_pg_index pg_index_form;
17036  ListCell *index;
17037 
17038  /*
17039  * Check whether relreplident has changed, and update it if so.
17040  */
17041  pg_class = table_open(RelationRelationId, RowExclusiveLock);
17042  pg_class_tuple = SearchSysCacheCopy1(RELOID,
17044  if (!HeapTupleIsValid(pg_class_tuple))
17045  elog(ERROR, "cache lookup failed for relation \"%s\"",
17047  pg_class_form = (Form_pg_class) GETSTRUCT(pg_class_tuple);
17048  if (pg_class_form->relreplident != ri_type)
17049  {
17050  pg_class_form->relreplident = ri_type;
17051  CatalogTupleUpdate(pg_class, &pg_class_tuple->t_self, pg_class_tuple);
17052  }
17053  table_close(pg_class, RowExclusiveLock);
17054  heap_freetuple(pg_class_tuple);
17055 
17056  /*
17057  * Update the per-index indisreplident flags correctly.
17058  */
17059  pg_index = table_open(IndexRelationId, RowExclusiveLock);
17060  foreach(index, RelationGetIndexList(rel))
17061  {
17062  Oid thisIndexOid = lfirst_oid(index);
17063  bool dirty = false;
17064 
17065  pg_index_tuple = SearchSysCacheCopy1(INDEXRELID,
17066  ObjectIdGetDatum(thisIndexOid));
17067  if (!HeapTupleIsValid(pg_index_tuple))
17068  elog(ERROR, "cache lookup failed for index %u", thisIndexOid);
17069  pg_index_form = (Form_pg_index) GETSTRUCT(pg_index_tuple);
17070 
17071  if (thisIndexOid == indexOid)
17072  {
17073  /* Set the bit if not already set. */
17074  if (!pg_index_form->indisreplident)
17075  {
17076  dirty = true;
17077  pg_index_form->indisreplident = true;
17078  }
17079  }
17080  else
17081  {
17082  /* Unset the bit if set. */
17083  if (pg_index_form->indisreplident)
17084  {
17085  dirty = true;
17086  pg_index_form->indisreplident = false;
17087  }
17088  }
17089 
17090  if (dirty)
17091  {
17092  CatalogTupleUpdate(pg_index, &pg_index_tuple->t_self, pg_index_tuple);
17093  InvokeObjectPostAlterHookArg(IndexRelationId, thisIndexOid, 0,
17094  InvalidOid, is_internal);
17095 
17096  /*
17097  * Invalidate the relcache for the table, so that after we commit
17098  * all sessions will refresh the table's replica identity index
17099  * before attempting any UPDATE or DELETE on the table. (If we
17100  * changed the table's pg_class row above, then a relcache inval
17101  * is already queued due to that; but we might not have.)
17102  */
17104  }
17105  heap_freetuple(pg_index_tuple);
17106  }
17107 
17108  table_close(pg_index, RowExclusiveLock);
17109 }
17110 
17111 /*
17112  * ALTER TABLE <name> REPLICA IDENTITY ...
17113  */
17114 static void
17116 {
17117  Oid indexOid;
17118  Relation indexRel;
17119  int key;
17120 
17121  if (stmt->identity_type == REPLICA_IDENTITY_DEFAULT)
17122  {
17123  relation_mark_replica_identity(rel, stmt->identity_type, InvalidOid, true);
17124  return;
17125  }
17126  else if (stmt->identity_type == REPLICA_IDENTITY_FULL)
17127  {
17128  relation_mark_replica_identity(rel, stmt->identity_type, InvalidOid, true);
17129  return;
17130  }
17131  else if (stmt->identity_type == REPLICA_IDENTITY_NOTHING)
17132  {
17133  relation_mark_replica_identity(rel, stmt->identity_type, InvalidOid, true);
17134  return;
17135  }
17136  else if (stmt->identity_type == REPLICA_IDENTITY_INDEX)
17137  {
17138  /* fallthrough */ ;
17139  }
17140  else
17141  elog(ERROR, "unexpected identity type %u", stmt->identity_type);
17142 
17143  /* Check that the index exists */
17144  indexOid = get_relname_relid(stmt->name, rel->rd_rel->relnamespace);
17145  if (!OidIsValid(indexOid))
17146  ereport(ERROR,
17147  (errcode(ERRCODE_UNDEFINED_OBJECT),
17148  errmsg("index \"%s\" for table \"%s\" does not exist",
17149  stmt->name, RelationGetRelationName(rel))));
17150 
17151  indexRel = index_open(indexOid, ShareLock);
17152 
17153  /* Check that the index is on the relation we're altering. */
17154  if (indexRel->rd_index == NULL ||
17155  indexRel->rd_index->indrelid != RelationGetRelid(rel))
17156  ereport(ERROR,
17157  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
17158  errmsg("\"%s\" is not an index for table \"%s\"",
17159  RelationGetRelationName(indexRel),
17160  RelationGetRelationName(rel))));
17161  /* The AM must support uniqueness, and the index must in fact be unique. */
17162  if (!indexRel->rd_indam->amcanunique ||
17163  !indexRel->rd_index->indisunique)
17164  ereport(ERROR,
17165  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
17166  errmsg("cannot use non-unique index \"%s\" as replica identity",
17167  RelationGetRelationName(indexRel))));
17168  /* Deferred indexes are not guaranteed to be always unique. */
17169  if (!indexRel->rd_index->indimmediate)
17170  ereport(ERROR,
17171  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
17172  errmsg("cannot use non-immediate index \"%s\" as replica identity",
17173  RelationGetRelationName(indexRel))));
17174  /* Expression indexes aren't supported. */
17175  if (RelationGetIndexExpressions(indexRel) != NIL)
17176  ereport(ERROR,
17177  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
17178  errmsg("cannot use expression index \"%s\" as replica identity",
17179  RelationGetRelationName(indexRel))));
17180  /* Predicate indexes aren't supported. */
17181  if (RelationGetIndexPredicate(indexRel) != NIL)
17182  ereport(ERROR,
17183  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
17184  errmsg("cannot use partial index \"%s\" as replica identity",
17185  RelationGetRelationName(indexRel))));
17186 
17187  /* Check index for nullable columns. */
17188  for (key = 0; key < IndexRelationGetNumberOfKeyAttributes(indexRel); key++)
17189  {
17190  int16 attno = indexRel->rd_index->indkey.values[key];
17191  Form_pg_attribute attr;
17192 
17193  /*
17194  * Reject any other system columns. (Going forward, we'll disallow
17195  * indexes containing such columns in the first place, but they might
17196  * exist in older branches.)
17197  */
17198  if (attno <= 0)
17199  ereport(ERROR,
17200  (errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
17201  errmsg("index \"%s\" cannot be used as replica identity because column %d is a system column",
17202  RelationGetRelationName(indexRel), attno)));
17203 
17204  attr = TupleDescAttr(rel->rd_att, attno - 1);
17205  if (!attr->attnotnull)
17206  ereport(ERROR,
17207  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
17208  errmsg("index \"%s\" cannot be used as replica identity because column \"%s\" is nullable",
17209  RelationGetRelationName(indexRel),
17210  NameStr(attr->attname))));
17211  }
17212 
17213  /* This index is suitable for use as a replica identity. Mark it. */
17214  relation_mark_replica_identity(rel, stmt->identity_type, indexOid, true);
17215 
17216  index_close(indexRel, NoLock);
17217 }
17218 
17219 /*
17220  * ALTER TABLE ENABLE/DISABLE ROW LEVEL SECURITY
17221  */
17222 static void
17224 {
17225  Relation pg_class;
17226  Oid relid;
17227  HeapTuple tuple;
17228 
17229  relid = RelationGetRelid(rel);
17230 
17231  /* Pull the record for this relation and update it */
17232  pg_class = table_open(RelationRelationId, RowExclusiveLock);
17233 
17234  tuple = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
17235 
17236  if (!HeapTupleIsValid(tuple))
17237  elog(ERROR, "cache lookup failed for relation %u", relid);
17238 
17239  ((Form_pg_class) GETSTRUCT(tuple))->relrowsecurity = rls;
17240  CatalogTupleUpdate(pg_class, &tuple->t_self, tuple);
17241 
17242  InvokeObjectPostAlterHook(RelationRelationId,
17243  RelationGetRelid(rel), 0);
17244 
17245  table_close(pg_class, RowExclusiveLock);
17246  heap_freetuple(tuple);
17247 }
17248 
17249 /*
17250  * ALTER TABLE FORCE/NO FORCE ROW LEVEL SECURITY
17251  */
17252 static void
17254 {
17255  Relation pg_class;
17256  Oid relid;
17257  HeapTuple tuple;
17258 
17259  relid = RelationGetRelid(rel);
17260 
17261  pg_class = table_open(RelationRelationId, RowExclusiveLock);
17262 
17263  tuple = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
17264 
17265  if (!HeapTupleIsValid(tuple))
17266  elog(ERROR, "cache lookup failed for relation %u", relid);
17267 
17268  ((Form_pg_class) GETSTRUCT(tuple))->relforcerowsecurity = force_rls;
17269  CatalogTupleUpdate(pg_class, &tuple->t_self, tuple);
17270 
17271  InvokeObjectPostAlterHook(RelationRelationId,
17272  RelationGetRelid(rel), 0);
17273 
17274  table_close(pg_class, RowExclusiveLock);
17275  heap_freetuple(tuple);
17276 }
17277 
17278 /*
17279  * ALTER FOREIGN TABLE <name> OPTIONS (...)
17280  */
17281 static void
17283 {
17284  Relation ftrel;
17285  ForeignServer *server;
17286  ForeignDataWrapper *fdw;
17287  HeapTuple tuple;
17288  bool isnull;
17289  Datum repl_val[Natts_pg_foreign_table];
17290  bool repl_null[Natts_pg_foreign_table];
17291  bool repl_repl[Natts_pg_foreign_table];
17292  Datum datum;
17293  Form_pg_foreign_table tableform;
17294 
17295  if (options == NIL)
17296  return;
17297 
17298  ftrel = table_open(ForeignTableRelationId, RowExclusiveLock);
17299 
17300  tuple = SearchSysCacheCopy1(FOREIGNTABLEREL,
17301  ObjectIdGetDatum(rel->rd_id));
17302  if (!HeapTupleIsValid(tuple))
17303  ereport(ERROR,
17304  (errcode(ERRCODE_UNDEFINED_OBJECT),
17305  errmsg("foreign table \"%s\" does not exist",
17306  RelationGetRelationName(rel))));
17307  tableform = (Form_pg_foreign_table) GETSTRUCT(tuple);
17308  server = GetForeignServer(tableform->ftserver);
17309  fdw = GetForeignDataWrapper(server->fdwid);
17310 
17311  memset(repl_val, 0, sizeof(repl_val));
17312  memset(repl_null, false, sizeof(repl_null));
17313  memset(repl_repl, false, sizeof(repl_repl));
17314 
17315  /* Extract the current options */
17316  datum = SysCacheGetAttr(FOREIGNTABLEREL,
17317  tuple,
17318  Anum_pg_foreign_table_ftoptions,
17319  &isnull);
17320  if (isnull)
17321  datum = PointerGetDatum(NULL);
17322 
17323  /* Transform the options */
17324  datum = transformGenericOptions(ForeignTableRelationId,
17325  datum,
17326  options,
17327  fdw->fdwvalidator);
17328 
17329  if (PointerIsValid(DatumGetPointer(datum)))
17330  repl_val[Anum_pg_foreign_table_ftoptions - 1] = datum;
17331  else
17332  repl_null[Anum_pg_foreign_table_ftoptions - 1] = true;
17333 
17334  repl_repl[Anum_pg_foreign_table_ftoptions - 1] = true;
17335 
17336  /* Everything looks good - update the tuple */
17337 
17338  tuple = heap_modify_tuple(tuple, RelationGetDescr(ftrel),
17339  repl_val, repl_null, repl_repl);
17340 
17341  CatalogTupleUpdate(ftrel, &tuple->t_self, tuple);
17342 
17343  /*
17344  * Invalidate relcache so that all sessions will refresh any cached plans
17345  * that might depend on the old options.
17346  */
17348 
17349  InvokeObjectPostAlterHook(ForeignTableRelationId,
17350  RelationGetRelid(rel), 0);
17351 
17352  table_close(ftrel, RowExclusiveLock);
17353 
17354  heap_freetuple(tuple);
17355 }
17356 
17357 /*
17358  * ALTER TABLE ALTER COLUMN SET COMPRESSION
17359  *
17360  * Return value is the address of the modified column
17361  */
17362 static ObjectAddress
17364  const char *column,
17365  Node *newValue,
17366  LOCKMODE lockmode)
17367 {
17368  Relation attrel;
17369  HeapTuple tuple;
17370  Form_pg_attribute atttableform;
17372  char *compression;
17373  char cmethod;
17374  ObjectAddress address;
17375 
17376  compression = strVal(newValue);
17377 
17378  attrel = table_open(AttributeRelationId, RowExclusiveLock);
17379 
17380  /* copy the cache entry so we can scribble on it below */
17381  tuple = SearchSysCacheCopyAttName(RelationGetRelid(rel), column);
17382  if (!HeapTupleIsValid(tuple))
17383  ereport(ERROR,
17384  (errcode(ERRCODE_UNDEFINED_COLUMN),
17385  errmsg("column \"%s\" of relation \"%s\" does not exist",
17386  column, RelationGetRelationName(rel))));
17387 
17388  /* prevent them from altering a system attribute */
17389  atttableform = (Form_pg_attribute) GETSTRUCT(tuple);
17390  attnum = atttableform->attnum;
17391  if (attnum <= 0)
17392  ereport(ERROR,
17393  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
17394  errmsg("cannot alter system column \"%s\"", column)));
17395 
17396  /*
17397  * Check that column type is compressible, then get the attribute
17398  * compression method code
17399  */
17400  cmethod = GetAttributeCompression(atttableform->atttypid, compression);
17401 
17402  /* update pg_attribute entry */
17403  atttableform->attcompression = cmethod;
17404  CatalogTupleUpdate(attrel, &tuple->t_self, tuple);
17405 
17406  InvokeObjectPostAlterHook(RelationRelationId,
17407  RelationGetRelid(rel),
17408  attnum);
17409 
17410  /*
17411  * Apply the change to indexes as well (only for simple index columns,
17412  * matching behavior of index.c ConstructTupleDescriptor()).
17413  */
17414  SetIndexStorageProperties(rel, attrel, attnum,
17415  false, 0,
17416  true, cmethod,
17417  lockmode);
17418 
17419  heap_freetuple(tuple);
17420 
17421  table_close(attrel, RowExclusiveLock);
17422 
17423  /* make changes visible */
17425 
17426  ObjectAddressSubSet(address, RelationRelationId,
17427  RelationGetRelid(rel), attnum);
17428  return address;
17429 }
17430 
17431 
17432 /*
17433  * Preparation phase for SET LOGGED/UNLOGGED
17434  *
17435  * This verifies that we're not trying to change a temp table. Also,
17436  * existing foreign key constraints are checked to avoid ending up with
17437  * permanent tables referencing unlogged tables.
17438  *
17439  * Return value is false if the operation is a no-op (in which case the
17440  * checks are skipped), otherwise true.
17441  */
17442 static bool
17444 {
17445  Relation pg_constraint;
17446  HeapTuple tuple;
17447  SysScanDesc scan;
17448  ScanKeyData skey[1];
17449 
17450  /*
17451  * Disallow changing status for a temp table. Also verify whether we can
17452  * get away with doing nothing; in such cases we don't need to run the
17453  * checks below, either.
17454  */
17455  switch (rel->rd_rel->relpersistence)
17456  {
17457  case RELPERSISTENCE_TEMP:
17458  ereport(ERROR,
17459  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
17460  errmsg("cannot change logged status of table \"%s\" because it is temporary",
17462  errtable(rel)));
17463  break;
17464  case RELPERSISTENCE_PERMANENT:
17465  if (toLogged)
17466  /* nothing to do */
17467  return false;
17468  break;
17469  case RELPERSISTENCE_UNLOGGED:
17470  if (!toLogged)
17471  /* nothing to do */
17472  return false;
17473  break;
17474  }
17475 
17476  /*
17477  * Check that the table is not part of any publication when changing to
17478  * UNLOGGED, as UNLOGGED tables can't be published.
17479  */
17480  if (!toLogged &&
17482  ereport(ERROR,
17483  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
17484  errmsg("cannot change table \"%s\" to unlogged because it is part of a publication",
17486  errdetail("Unlogged relations cannot be replicated.")));
17487 
17488  /*
17489  * Check existing foreign key constraints to preserve the invariant that
17490  * permanent tables cannot reference unlogged ones. Self-referencing
17491  * foreign keys can safely be ignored.
17492  */
17493  pg_constraint = table_open(ConstraintRelationId, AccessShareLock);
17494 
17495  /*
17496  * Scan conrelid if changing to permanent, else confrelid. This also
17497  * determines whether a useful index exists.
17498  */
17499  ScanKeyInit(&skey[0],
17500  toLogged ? Anum_pg_constraint_conrelid :
17501  Anum_pg_constraint_confrelid,
17502  BTEqualStrategyNumber, F_OIDEQ,
17504  scan = systable_beginscan(pg_constraint,
17505  toLogged ? ConstraintRelidTypidNameIndexId : InvalidOid,
17506  true, NULL, 1, skey);
17507 
17508  while (HeapTupleIsValid(tuple = systable_getnext(scan)))
17509  {
17511 
17512  if (con->contype == CONSTRAINT_FOREIGN)
17513  {
17514  Oid foreignrelid;
17515  Relation foreignrel;
17516 
17517  /* the opposite end of what we used as scankey */
17518  foreignrelid = toLogged ? con->confrelid : con->conrelid;
17519 
17520  /* ignore if self-referencing */
17521  if (RelationGetRelid(rel) == foreignrelid)
17522  continue;
17523 
17524  foreignrel = relation_open(foreignrelid, AccessShareLock);
17525 
17526  if (toLogged)
17527  {
17528  if (!RelationIsPermanent(foreignrel))
17529  ereport(ERROR,
17530  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
17531  errmsg("could not change table \"%s\" to logged because it references unlogged table \"%s\"",
17533  RelationGetRelationName(foreignrel)),
17534  errtableconstraint(rel, NameStr(con->conname))));
17535  }
17536  else
17537  {
17538  if (RelationIsPermanent(foreignrel))
17539  ereport(ERROR,
17540  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
17541  errmsg("could not change table \"%s\" to unlogged because it references logged table \"%s\"",
17543  RelationGetRelationName(foreignrel)),
17544  errtableconstraint(rel, NameStr(con->conname))));
17545  }
17546 
17547  relation_close(foreignrel, AccessShareLock);
17548  }
17549  }
17550 
17551  systable_endscan(scan);
17552 
17553  table_close(pg_constraint, AccessShareLock);
17554 
17555  return true;
17556 }
17557 
17558 /*
17559  * Execute ALTER TABLE SET SCHEMA
17560  */
17563 {
17564  Relation rel;
17565  Oid relid;
17566  Oid oldNspOid;
17567  Oid nspOid;
17568  RangeVar *newrv;
17569  ObjectAddresses *objsMoved;
17570  ObjectAddress myself;
17571 
17573  stmt->missing_ok ? RVR_MISSING_OK : 0,
17575  (void *) stmt);
17576 
17577  if (!OidIsValid(relid))
17578  {
17579  ereport(NOTICE,
17580  (errmsg("relation \"%s\" does not exist, skipping",
17581  stmt->relation->relname)));
17582  return InvalidObjectAddress;
17583  }
17584 
17585  rel = relation_open(relid, NoLock);
17586 
17587  oldNspOid = RelationGetNamespace(rel);
17588 
17589  /* If it's an owned sequence, disallow moving it by itself. */
17590  if (rel->rd_rel->relkind == RELKIND_SEQUENCE)
17591  {
17592  Oid tableId;
17593  int32 colId;
17594 
17595  if (sequenceIsOwned(relid, DEPENDENCY_AUTO, &tableId, &colId) ||
17596  sequenceIsOwned(relid, DEPENDENCY_INTERNAL, &tableId, &colId))
17597  ereport(ERROR,
17598  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
17599  errmsg("cannot move an owned sequence into another schema"),
17600  errdetail("Sequence \"%s\" is linked to table \"%s\".",
17602  get_rel_name(tableId))));
17603  }
17604 
17605  /* Get and lock schema OID and check its permissions. */
17606  newrv = makeRangeVar(stmt->newschema, RelationGetRelationName(rel), -1);
17607  nspOid = RangeVarGetAndCheckCreationNamespace(newrv, NoLock, NULL);
17608 
17609  /* common checks on switching namespaces */
17610  CheckSetNamespace(oldNspOid, nspOid);
17611 
17612  objsMoved = new_object_addresses();
17613  AlterTableNamespaceInternal(rel, oldNspOid, nspOid, objsMoved);
17614  free_object_addresses(objsMoved);
17615 
17616  ObjectAddressSet(myself, RelationRelationId, relid);
17617 
17618  if (oldschema)
17619  *oldschema = oldNspOid;
17620 
17621  /* close rel, but keep lock until commit */
17622  relation_close(rel, NoLock);
17623 
17624  return myself;
17625 }
17626 
17627 /*
17628  * The guts of relocating a table or materialized view to another namespace:
17629  * besides moving the relation itself, its dependent objects are relocated to
17630  * the new schema.
17631  */
17632 void
17634  ObjectAddresses *objsMoved)
17635 {
17636  Relation classRel;
17637 
17638  Assert(objsMoved != NULL);
17639 
17640  /* OK, modify the pg_class row and pg_depend entry */
17641  classRel = table_open(RelationRelationId, RowExclusiveLock);
17642 
17643  AlterRelationNamespaceInternal(classRel, RelationGetRelid(rel), oldNspOid,
17644  nspOid, true, objsMoved);
17645 
17646  /* Fix the table's row type too, if it has one */
17647  if (OidIsValid(rel->rd_rel->reltype))
17648  AlterTypeNamespaceInternal(rel->rd_rel->reltype,
17649  nspOid, false, false, objsMoved);
17650 
17651  /* Fix other dependent stuff */
17652  if (rel->rd_rel->relkind == RELKIND_RELATION ||
17653  rel->rd_rel->relkind == RELKIND_MATVIEW ||
17654  rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
17655  {
17656  AlterIndexNamespaces(classRel, rel, oldNspOid, nspOid, objsMoved);
17657  AlterSeqNamespaces(classRel, rel, oldNspOid, nspOid,
17658  objsMoved, AccessExclusiveLock);
17659  AlterConstraintNamespaces(RelationGetRelid(rel), oldNspOid, nspOid,
17660  false, objsMoved);
17661  }
17662 
17663  table_close(classRel, RowExclusiveLock);
17664 }
17665 
17666 /*
17667  * The guts of relocating a relation to another namespace: fix the pg_class
17668  * entry, and the pg_depend entry if any. Caller must already have
17669  * opened and write-locked pg_class.
17670  */
17671 void
17673  Oid oldNspOid, Oid newNspOid,
17674  bool hasDependEntry,
17675  ObjectAddresses *objsMoved)
17676 {
17677  HeapTuple classTup;
17678  Form_pg_class classForm;
17679  ObjectAddress thisobj;
17680  bool already_done = false;
17681 
17682  classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relOid));
17683  if (!HeapTupleIsValid(classTup))
17684  elog(ERROR, "cache lookup failed for relation %u", relOid);
17685  classForm = (Form_pg_class) GETSTRUCT(classTup);
17686 
17687  Assert(classForm->relnamespace == oldNspOid);
17688 
17689  thisobj.classId = RelationRelationId;
17690  thisobj.objectId = relOid;
17691  thisobj.objectSubId = 0;
17692 
17693  /*
17694  * If the object has already been moved, don't move it again. If it's
17695  * already in the right place, don't move it, but still fire the object
17696  * access hook.
17697  */
17698  already_done = object_address_present(&thisobj, objsMoved);
17699  if (!already_done && oldNspOid != newNspOid)
17700  {
17701  /* check for duplicate name (more friendly than unique-index failure) */
17702  if (get_relname_relid(NameStr(classForm->relname),
17703  newNspOid) != InvalidOid)
17704  ereport(ERROR,
17705  (errcode(ERRCODE_DUPLICATE_TABLE),
17706  errmsg("relation \"%s\" already exists in schema \"%s\"",
17707  NameStr(classForm->relname),
17708  get_namespace_name(newNspOid))));
17709 
17710  /* classTup is a copy, so OK to scribble on */
17711  classForm->relnamespace = newNspOid;
17712 
17713  CatalogTupleUpdate(classRel, &classTup->t_self, classTup);
17714 
17715  /* Update dependency on schema if caller said so */
17716  if (hasDependEntry &&
17717  changeDependencyFor(RelationRelationId,
17718  relOid,
17719  NamespaceRelationId,
17720  oldNspOid,
17721  newNspOid) != 1)
17722  elog(ERROR, "could not change schema dependency for relation \"%s\"",
17723  NameStr(classForm->relname));
17724  }
17725  if (!already_done)
17726  {
17727  add_exact_object_address(&thisobj, objsMoved);
17728 
17729  InvokeObjectPostAlterHook(RelationRelationId, relOid, 0);
17730  }
17731 
17732  heap_freetuple(classTup);
17733 }
17734 
17735 /*
17736  * Move all indexes for the specified relation to another namespace.
17737  *
17738  * Note: we assume adequate permission checking was done by the caller,
17739  * and that the caller has a suitable lock on the owning relation.
17740  */
17741 static void
17743  Oid oldNspOid, Oid newNspOid, ObjectAddresses *objsMoved)
17744 {
17745  List *indexList;
17746  ListCell *l;
17747 
17748  indexList = RelationGetIndexList(rel);
17749 
17750  foreach(l, indexList)
17751  {
17752  Oid indexOid = lfirst_oid(l);
17753  ObjectAddress thisobj;
17754 
17755  thisobj.classId = RelationRelationId;
17756  thisobj.objectId = indexOid;
17757  thisobj.objectSubId = 0;
17758 
17759  /*
17760  * Note: currently, the index will not have its own dependency on the
17761  * namespace, so we don't need to do changeDependencyFor(). There's no
17762  * row type in pg_type, either.
17763  *
17764  * XXX this objsMoved test may be pointless -- surely we have a single
17765  * dependency link from a relation to each index?
17766  */
17767  if (!object_address_present(&thisobj, objsMoved))
17768  {
17769  AlterRelationNamespaceInternal(classRel, indexOid,
17770  oldNspOid, newNspOid,
17771  false, objsMoved);
17772  add_exact_object_address(&thisobj, objsMoved);
17773  }
17774  }
17775 
17776  list_free(indexList);
17777 }
17778 
17779 /*
17780  * Move all identity and SERIAL-column sequences of the specified relation to another
17781  * namespace.
17782  *
17783  * Note: we assume adequate permission checking was done by the caller,
17784  * and that the caller has a suitable lock on the owning relation.
17785  */
17786 static void
17788  Oid oldNspOid, Oid newNspOid, ObjectAddresses *objsMoved,
17789  LOCKMODE lockmode)
17790 {
17791  Relation depRel;
17792  SysScanDesc scan;
17793  ScanKeyData key[2];
17794  HeapTuple tup;
17795 
17796  /*
17797  * SERIAL sequences are those having an auto dependency on one of the
17798  * table's columns (we don't care *which* column, exactly).
17799  */
17800  depRel = table_open(DependRelationId, AccessShareLock);
17801 
17802  ScanKeyInit(&key[0],
17803  Anum_pg_depend_refclassid,
17804  BTEqualStrategyNumber, F_OIDEQ,
17805  ObjectIdGetDatum(RelationRelationId));
17806  ScanKeyInit(&key[1],
17807  Anum_pg_depend_refobjid,
17808  BTEqualStrategyNumber, F_OIDEQ,
17810  /* we leave refobjsubid unspecified */
17811 
17812  scan = systable_beginscan(depRel, DependReferenceIndexId, true,
17813  NULL, 2, key);
17814 
17815  while (HeapTupleIsValid(tup = systable_getnext(scan)))
17816  {
17817  Form_pg_depend depForm = (Form_pg_depend) GETSTRUCT(tup);
17818  Relation seqRel;
17819 
17820  /* skip dependencies other than auto dependencies on columns */
17821  if (depForm->refobjsubid == 0 ||
17822  depForm->classid != RelationRelationId ||
17823  depForm->objsubid != 0 ||
17824  !(depForm->deptype == DEPENDENCY_AUTO || depForm->deptype == DEPENDENCY_INTERNAL))
17825  continue;
17826 
17827  /* Use relation_open just in case it's an index */
17828  seqRel = relation_open(depForm->objid, lockmode);
17829 
17830  /* skip non-sequence relations */
17831  if (RelationGetForm(seqRel)->relkind != RELKIND_SEQUENCE)
17832  {
17833  /* No need to keep the lock */
17834  relation_close(seqRel, lockmode);
17835  continue;
17836  }
17837 
17838  /* Fix the pg_class and pg_depend entries */
17839  AlterRelationNamespaceInternal(classRel, depForm->objid,
17840  oldNspOid, newNspOid,
17841  true, objsMoved);
17842 
17843  /*
17844  * Sequences used to have entries in pg_type, but no longer do. If we
17845  * ever re-instate that, we'll need to move the pg_type entry to the
17846  * new namespace, too (using AlterTypeNamespaceInternal).
17847  */
17848  Assert(RelationGetForm(seqRel)->reltype == InvalidOid);
17849 
17850  /* Now we can close it. Keep the lock till end of transaction. */
17851  relation_close(seqRel, NoLock);
17852  }
17853 
17854  systable_endscan(scan);
17855 
17857 }
17858 
17859 
17860 /*
17861  * This code supports
17862  * CREATE TEMP TABLE ... ON COMMIT { DROP | PRESERVE ROWS | DELETE ROWS }
17863  *
17864  * Because we only support this for TEMP tables, it's sufficient to remember
17865  * the state in a backend-local data structure.
17866  */
17867 
17868 /*
17869  * Register a newly-created relation's ON COMMIT action.
17870  */
17871 void
17873 {
17874  OnCommitItem *oc;
17875  MemoryContext oldcxt;
17876 
17877  /*
17878  * We needn't bother registering the relation unless there is an ON COMMIT
17879  * action we need to take.
17880  */
17882  return;
17883 
17885 
17886  oc = (OnCommitItem *) palloc(sizeof(OnCommitItem));
17887  oc->relid = relid;
17888  oc->oncommit = action;
17891 
17892  /*
17893  * We use lcons() here so that ON COMMIT actions are processed in reverse
17894  * order of registration. That might not be essential but it seems
17895  * reasonable.
17896  */
17897  on_commits = lcons(oc, on_commits);
17898 
17899  MemoryContextSwitchTo(oldcxt);
17900 }
17901 
17902 /*
17903  * Unregister any ON COMMIT action when a relation is deleted.
17904  *
17905  * Actually, we only mark the OnCommitItem entry as to be deleted after commit.
17906  */
17907 void
17909 {
17910  ListCell *l;
17911 
17912  foreach(l, on_commits)
17913  {
17914  OnCommitItem *oc = (OnCommitItem *) lfirst(l);
17915 
17916  if (oc->relid == relid)
17917  {
17919  break;
17920  }
17921  }
17922 }
17923 
17924 /*
17925  * Perform ON COMMIT actions.
17926  *
17927  * This is invoked just before actually committing, since it's possible
17928  * to encounter errors.
17929  */
17930 void
17932 {
17933  ListCell *l;
17934  List *oids_to_truncate = NIL;
17935  List *oids_to_drop = NIL;
17936 
17937  foreach(l, on_commits)
17938  {
17939  OnCommitItem *oc = (OnCommitItem *) lfirst(l);
17940 
17941  /* Ignore entry if already dropped in this xact */
17943  continue;
17944 
17945  switch (oc->oncommit)
17946  {
17947  case ONCOMMIT_NOOP:
17949  /* Do nothing (there shouldn't be such entries, actually) */
17950  break;
17951  case ONCOMMIT_DELETE_ROWS:
17952 
17953  /*
17954  * If this transaction hasn't accessed any temporary
17955  * relations, we can skip truncating ON COMMIT DELETE ROWS
17956  * tables, as they must still be empty.
17957  */
17959  oids_to_truncate = lappend_oid(oids_to_truncate, oc->relid);
17960  break;
17961  case ONCOMMIT_DROP:
17962  oids_to_drop = lappend_oid(oids_to_drop, oc->relid);
17963  break;
17964  }
17965  }
17966 
17967  /*
17968  * Truncate relations before dropping so that all dependencies between
17969  * relations are removed after they are worked on. Doing it like this
17970  * might be a waste as it is possible that a relation being truncated will
17971  * be dropped anyway due to its parent being dropped, but this makes the
17972  * code more robust because of not having to re-check that the relation
17973  * exists at truncation time.
17974  */
17975  if (oids_to_truncate != NIL)
17976  heap_truncate(oids_to_truncate);
17977 
17978  if (oids_to_drop != NIL)
17979  {
17980  ObjectAddresses *targetObjects = new_object_addresses();
17981 
17982  foreach(l, oids_to_drop)
17983  {
17984  ObjectAddress object;
17985 
17986  object.classId = RelationRelationId;
17987  object.objectId = lfirst_oid(l);
17988  object.objectSubId = 0;
17989 
17990  Assert(!object_address_present(&object, targetObjects));
17991 
17992  add_exact_object_address(&object, targetObjects);
17993  }
17994 
17995  /*
17996  * Object deletion might involve toast table access (to clean up
17997  * toasted catalog entries), so ensure we have a valid snapshot.
17998  */
18000 
18001  /*
18002  * Since this is an automatic drop, rather than one directly initiated
18003  * by the user, we pass the PERFORM_DELETION_INTERNAL flag.
18004  */
18005  performMultipleDeletions(targetObjects, DROP_CASCADE,
18007 
18009 
18010 #ifdef USE_ASSERT_CHECKING
18011 
18012  /*
18013  * Note that table deletion will call remove_on_commit_action, so the
18014  * entry should get marked as deleted.
18015  */
18016  foreach(l, on_commits)
18017  {
18018  OnCommitItem *oc = (OnCommitItem *) lfirst(l);
18019 
18020  if (oc->oncommit != ONCOMMIT_DROP)
18021  continue;
18022 
18024  }
18025 #endif
18026  }
18027 }
18028 
18029 /*
18030  * Post-commit or post-abort cleanup for ON COMMIT management.
18031  *
18032  * All we do here is remove no-longer-needed OnCommitItem entries.
18033  *
18034  * During commit, remove entries that were deleted during this transaction;
18035  * during abort, remove those created during this transaction.
18036  */
18037 void
18039 {
18040  ListCell *cur_item;
18041 
18042  foreach(cur_item, on_commits)
18043  {
18044  OnCommitItem *oc = (OnCommitItem *) lfirst(cur_item);
18045 
18046  if (isCommit ? oc->deleting_subid != InvalidSubTransactionId :
18048  {
18049  /* cur_item must be removed */
18051  pfree(oc);
18052  }
18053  else
18054  {
18055  /* cur_item must be preserved */
18058  }
18059  }
18060 }
18061 
18062 /*
18063  * Post-subcommit or post-subabort cleanup for ON COMMIT management.
18064  *
18065  * During subabort, we can immediately remove entries created during this
18066  * subtransaction. During subcommit, just relabel entries marked during
18067  * this subtransaction as being the parent's responsibility.
18068  */
18069 void
18071  SubTransactionId parentSubid)
18072 {
18073  ListCell *cur_item;
18074 
18075  foreach(cur_item, on_commits)
18076  {
18077  OnCommitItem *oc = (OnCommitItem *) lfirst(cur_item);
18078 
18079  if (!isCommit && oc->creating_subid == mySubid)
18080  {
18081  /* cur_item must be removed */
18083  pfree(oc);
18084  }
18085  else
18086  {
18087  /* cur_item must be preserved */
18088  if (oc->creating_subid == mySubid)
18089  oc->creating_subid = parentSubid;
18090  if (oc->deleting_subid == mySubid)
18091  oc->deleting_subid = isCommit ? parentSubid : InvalidSubTransactionId;
18092  }
18093  }
18094 }
18095 
18096 /*
18097  * This is intended as a callback for RangeVarGetRelidExtended(). It allows
18098  * the relation to be locked only if (1) it's a plain or partitioned table,
18099  * materialized view, or TOAST table and (2) the current user is the owner (or
18100  * the superuser) or has been granted MAINTAIN. This meets the
18101  * permission-checking needs of CLUSTER, REINDEX TABLE, and REFRESH
18102  * MATERIALIZED VIEW; we expose it here so that it can be used by all.
18103  */
18104 void
18106  Oid relId, Oid oldRelId, void *arg)
18107 {
18108  char relkind;
18109  AclResult aclresult;
18110 
18111  /* Nothing to do if the relation was not found. */
18112  if (!OidIsValid(relId))
18113  return;
18114 
18115  /*
18116  * If the relation does exist, check whether it's an index. But note that
18117  * the relation might have been dropped between the time we did the name
18118  * lookup and now. In that case, there's nothing to do.
18119  */
18120  relkind = get_rel_relkind(relId);
18121  if (!relkind)
18122  return;
18123  if (relkind != RELKIND_RELATION && relkind != RELKIND_TOASTVALUE &&
18124  relkind != RELKIND_MATVIEW && relkind != RELKIND_PARTITIONED_TABLE)
18125  ereport(ERROR,
18126  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
18127  errmsg("\"%s\" is not a table or materialized view", relation->relname)));
18128 
18129  /* Check permissions */
18130  aclresult = pg_class_aclcheck(relId, GetUserId(), ACL_MAINTAIN);
18131  if (aclresult != ACLCHECK_OK)
18132  aclcheck_error(aclresult,
18134  relation->relname);
18135 }
18136 
18137 /*
18138  * Callback to RangeVarGetRelidExtended() for TRUNCATE processing.
18139  */
18140 static void
18142  Oid relId, Oid oldRelId, void *arg)
18143 {
18144  HeapTuple tuple;
18145 
18146  /* Nothing to do if the relation was not found. */
18147  if (!OidIsValid(relId))
18148  return;
18149 
18150  tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relId));
18151  if (!HeapTupleIsValid(tuple)) /* should not happen */
18152  elog(ERROR, "cache lookup failed for relation %u", relId);
18153 
18154  truncate_check_rel(relId, (Form_pg_class) GETSTRUCT(tuple));
18155  truncate_check_perms(relId, (Form_pg_class) GETSTRUCT(tuple));
18156 
18157  ReleaseSysCache(tuple);
18158 }
18159 
18160 /*
18161  * Callback for RangeVarGetRelidExtended(). Checks that the current user is
18162  * the owner of the relation, or superuser.
18163  */
18164 void
18166  Oid relId, Oid oldRelId, void *arg)
18167 {
18168  HeapTuple tuple;
18169 
18170  /* Nothing to do if the relation was not found. */
18171  if (!OidIsValid(relId))
18172  return;
18173 
18174  tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relId));
18175  if (!HeapTupleIsValid(tuple)) /* should not happen */
18176  elog(ERROR, "cache lookup failed for relation %u", relId);
18177 
18178  if (!object_ownercheck(RelationRelationId, relId, GetUserId()))
18180  relation->relname);
18181 
18182  if (!allowSystemTableMods &&
18183  IsSystemClass(relId, (Form_pg_class) GETSTRUCT(tuple)))
18184  ereport(ERROR,
18185  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
18186  errmsg("permission denied: \"%s\" is a system catalog",
18187  relation->relname)));
18188 
18189  ReleaseSysCache(tuple);
18190 }
18191 
18192 /*
18193  * Common RangeVarGetRelid callback for rename, set schema, and alter table
18194  * processing.
18195  */
18196 static void
18198  void *arg)
18199 {
18200  Node *stmt = (Node *) arg;
18201  ObjectType reltype;
18202  HeapTuple tuple;
18203  Form_pg_class classform;
18204  AclResult aclresult;
18205  char relkind;
18206 
18207  tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
18208  if (!HeapTupleIsValid(tuple))
18209  return; /* concurrently dropped */
18210  classform = (Form_pg_class) GETSTRUCT(tuple);
18211  relkind = classform->relkind;
18212 
18213  /* Must own relation. */
18214  if (!object_ownercheck(RelationRelationId, relid, GetUserId()))
18216 
18217  /* No system table modifications unless explicitly allowed. */
18218  if (!allowSystemTableMods && IsSystemClass(relid, classform))
18219  ereport(ERROR,
18220  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
18221  errmsg("permission denied: \"%s\" is a system catalog",
18222  rv->relname)));
18223 
18224  /*
18225  * Extract the specified relation type from the statement parse tree.
18226  *
18227  * Also, for ALTER .. RENAME, check permissions: the user must (still)
18228  * have CREATE rights on the containing namespace.
18229  */
18230  if (IsA(stmt, RenameStmt))
18231  {
18232  aclresult = object_aclcheck(NamespaceRelationId, classform->relnamespace,
18233  GetUserId(), ACL_CREATE);
18234  if (aclresult != ACLCHECK_OK)
18235  aclcheck_error(aclresult, OBJECT_SCHEMA,
18236  get_namespace_name(classform->relnamespace));
18237  reltype = ((RenameStmt *) stmt)->renameType;
18238  }
18239  else if (IsA(stmt, AlterObjectSchemaStmt))
18240  reltype = ((AlterObjectSchemaStmt *) stmt)->objectType;
18241 
18242  else if (IsA(stmt, AlterTableStmt))
18243  reltype = ((AlterTableStmt *) stmt)->objtype;
18244  else
18245  {
18246  elog(ERROR, "unrecognized node type: %d", (int) nodeTag(stmt));
18247  reltype = OBJECT_TABLE; /* placate compiler */
18248  }
18249 
18250  /*
18251  * For compatibility with prior releases, we allow ALTER TABLE to be used
18252  * with most other types of relations (but not composite types). We allow
18253  * similar flexibility for ALTER INDEX in the case of RENAME, but not
18254  * otherwise. Otherwise, the user must select the correct form of the
18255  * command for the relation at issue.
18256  */
18257  if (reltype == OBJECT_SEQUENCE && relkind != RELKIND_SEQUENCE)
18258  ereport(ERROR,
18259  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
18260  errmsg("\"%s\" is not a sequence", rv->relname)));
18261 
18262  if (reltype == OBJECT_VIEW && relkind != RELKIND_VIEW)
18263  ereport(ERROR,
18264  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
18265  errmsg("\"%s\" is not a view", rv->relname)));
18266 
18267  if (reltype == OBJECT_MATVIEW && relkind != RELKIND_MATVIEW)
18268  ereport(ERROR,
18269  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
18270  errmsg("\"%s\" is not a materialized view", rv->relname)));
18271 
18272  if (reltype == OBJECT_FOREIGN_TABLE && relkind != RELKIND_FOREIGN_TABLE)
18273  ereport(ERROR,
18274  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
18275  errmsg("\"%s\" is not a foreign table", rv->relname)));
18276 
18277  if (reltype == OBJECT_TYPE && relkind != RELKIND_COMPOSITE_TYPE)
18278  ereport(ERROR,
18279  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
18280  errmsg("\"%s\" is not a composite type", rv->relname)));
18281 
18282  if (reltype == OBJECT_INDEX && relkind != RELKIND_INDEX &&
18283  relkind != RELKIND_PARTITIONED_INDEX
18284  && !IsA(stmt, RenameStmt))
18285  ereport(ERROR,
18286  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
18287  errmsg("\"%s\" is not an index", rv->relname)));
18288 
18289  /*
18290  * Don't allow ALTER TABLE on composite types. We want people to use ALTER
18291  * TYPE for that.
18292  */
18293  if (reltype != OBJECT_TYPE && relkind == RELKIND_COMPOSITE_TYPE)
18294  ereport(ERROR,
18295  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
18296  errmsg("\"%s\" is a composite type", rv->relname),
18297  /* translator: %s is an SQL ALTER command */
18298  errhint("Use %s instead.",
18299  "ALTER TYPE")));
18300 
18301  /*
18302  * Don't allow ALTER TABLE .. SET SCHEMA on relations that can't be moved
18303  * to a different schema, such as indexes and TOAST tables.
18304  */
18306  {
18307  if (relkind == RELKIND_INDEX || relkind == RELKIND_PARTITIONED_INDEX)
18308  ereport(ERROR,
18309  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
18310  errmsg("cannot change schema of index \"%s\"",
18311  rv->relname),
18312  errhint("Change the schema of the table instead.")));
18313  else if (relkind == RELKIND_COMPOSITE_TYPE)
18314  ereport(ERROR,
18315  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
18316  errmsg("cannot change schema of composite type \"%s\"",
18317  rv->relname),
18318  /* translator: %s is an SQL ALTER command */
18319  errhint("Use %s instead.",
18320  "ALTER TYPE")));
18321  else if (relkind == RELKIND_TOASTVALUE)
18322  ereport(ERROR,
18323  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
18324  errmsg("cannot change schema of TOAST table \"%s\"",
18325  rv->relname),
18326  errhint("Change the schema of the table instead.")));
18327  }
18328 
18329  ReleaseSysCache(tuple);
18330 }
18331 
18332 /*
18333  * Transform any expressions present in the partition key
18334  *
18335  * Returns a transformed PartitionSpec.
18336  */
18337 static PartitionSpec *
18339 {
18340  PartitionSpec *newspec;
18341  ParseState *pstate;
18342  ParseNamespaceItem *nsitem;
18343  ListCell *l;
18344 
18345  newspec = makeNode(PartitionSpec);
18346 
18347  newspec->strategy = partspec->strategy;
18348  newspec->partParams = NIL;
18349  newspec->location = partspec->location;
18350 
18351  /* Check valid number of columns for strategy */
18352  if (partspec->strategy == PARTITION_STRATEGY_LIST &&
18353  list_length(partspec->partParams) != 1)
18354  ereport(ERROR,
18355  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
18356  errmsg("cannot use \"list\" partition strategy with more than one column")));
18357 
18358  /*
18359  * Create a dummy ParseState and insert the target relation as its sole
18360  * rangetable entry. We need a ParseState for transformExpr.
18361  */
18362  pstate = make_parsestate(NULL);
18363  nsitem = addRangeTableEntryForRelation(pstate, rel, AccessShareLock,
18364  NULL, false, true);
18365  addNSItemToQuery(pstate, nsitem, true, true, true);
18366 
18367  /* take care of any partition expressions */
18368  foreach(l, partspec->partParams)
18369  {
18371 
18372  if (pelem->expr)
18373  {
18374  /* Copy, to avoid scribbling on the input */
18375  pelem = copyObject(pelem);
18376 
18377  /* Now do parse transformation of the expression */
18378  pelem->expr = transformExpr(pstate, pelem->expr,
18380 
18381  /* we have to fix its collations too */
18382  assign_expr_collations(pstate, pelem->expr);
18383  }
18384 
18385  newspec->partParams = lappend(newspec->partParams, pelem);
18386  }
18387 
18388  return newspec;
18389 }
18390 
18391 /*
18392  * Compute per-partition-column information from a list of PartitionElems.
18393  * Expressions in the PartitionElems must be parse-analyzed already.
18394  */
18395 static void
18396 ComputePartitionAttrs(ParseState *pstate, Relation rel, List *partParams, AttrNumber *partattrs,
18397  List **partexprs, Oid *partopclass, Oid *partcollation,
18398  PartitionStrategy strategy)
18399 {
18400  int attn;
18401  ListCell *lc;
18402  Oid am_oid;
18403 
18404  attn = 0;
18405  foreach(lc, partParams)
18406  {
18407  PartitionElem *pelem = lfirst_node(PartitionElem, lc);
18408  Oid atttype;
18409  Oid attcollation;
18410 
18411  if (pelem->name != NULL)
18412  {
18413  /* Simple attribute reference */
18414  HeapTuple atttuple;
18415  Form_pg_attribute attform;
18416 
18417  atttuple = SearchSysCacheAttName(RelationGetRelid(rel),
18418  pelem->name);
18419  if (!HeapTupleIsValid(atttuple))
18420  ereport(ERROR,
18421  (errcode(ERRCODE_UNDEFINED_COLUMN),
18422  errmsg("column \"%s\" named in partition key does not exist",
18423  pelem->name),
18424  parser_errposition(pstate, pelem->location)));
18425  attform = (Form_pg_attribute) GETSTRUCT(atttuple);
18426 
18427  if (attform->attnum <= 0)
18428  ereport(ERROR,
18429  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
18430  errmsg("cannot use system column \"%s\" in partition key",
18431  pelem->name),
18432  parser_errposition(pstate, pelem->location)));
18433 
18434  /*
18435  * Generated columns cannot work: They are computed after BEFORE
18436  * triggers, but partition routing is done before all triggers.
18437  */
18438  if (attform->attgenerated)
18439  ereport(ERROR,
18440  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
18441  errmsg("cannot use generated column in partition key"),
18442  errdetail("Column \"%s\" is a generated column.",
18443  pelem->name),
18444  parser_errposition(pstate, pelem->location)));
18445 
18446  partattrs[attn] = attform->attnum;
18447  atttype = attform->atttypid;
18448  attcollation = attform->attcollation;
18449  ReleaseSysCache(atttuple);
18450  }
18451  else
18452  {
18453  /* Expression */
18454  Node *expr = pelem->expr;
18455  char partattname[16];
18456 
18457  Assert(expr != NULL);
18458  atttype = exprType(expr);
18459  attcollation = exprCollation(expr);
18460 
18461  /*
18462  * The expression must be of a storable type (e.g., not RECORD).
18463  * The test is the same as for whether a table column is of a safe
18464  * type (which is why we needn't check for the non-expression
18465  * case).
18466  */
18467  snprintf(partattname, sizeof(partattname), "%d", attn + 1);
18468  CheckAttributeType(partattname,
18469  atttype, attcollation,
18471 
18472  /*
18473  * Strip any top-level COLLATE clause. This ensures that we treat
18474  * "x COLLATE y" and "(x COLLATE y)" alike.
18475  */
18476  while (IsA(expr, CollateExpr))
18477  expr = (Node *) ((CollateExpr *) expr)->arg;
18478 
18479  if (IsA(expr, Var) &&
18480  ((Var *) expr)->varattno > 0)
18481  {
18482  /*
18483  * User wrote "(column)" or "(column COLLATE something)".
18484  * Treat it like simple attribute anyway.
18485  */
18486  partattrs[attn] = ((Var *) expr)->varattno;
18487  }
18488  else
18489  {
18490  Bitmapset *expr_attrs = NULL;
18491  int i;
18492 
18493  partattrs[attn] = 0; /* marks the column as expression */
18494  *partexprs = lappend(*partexprs, expr);
18495 
18496  /*
18497  * transformPartitionSpec() should have already rejected
18498  * subqueries, aggregates, window functions, and SRFs, based
18499  * on the EXPR_KIND_ for partition expressions.
18500  */
18501 
18502  /*
18503  * Cannot allow system column references, since that would
18504  * make partition routing impossible: their values won't be
18505  * known yet when we need to do that.
18506  */
18507  pull_varattnos(expr, 1, &expr_attrs);
18508  for (i = FirstLowInvalidHeapAttributeNumber; i < 0; i++)
18509  {
18511  expr_attrs))
18512  ereport(ERROR,
18513  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
18514  errmsg("partition key expressions cannot contain system column references")));
18515  }
18516 
18517  /*
18518  * Generated columns cannot work: They are computed after
18519  * BEFORE triggers, but partition routing is done before all
18520  * triggers.
18521  */
18522  i = -1;
18523  while ((i = bms_next_member(expr_attrs, i)) >= 0)
18524  {
18526 
18527  if (attno > 0 &&
18528  TupleDescAttr(RelationGetDescr(rel), attno - 1)->attgenerated)
18529  ereport(ERROR,
18530  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
18531  errmsg("cannot use generated column in partition key"),
18532  errdetail("Column \"%s\" is a generated column.",
18533  get_attname(RelationGetRelid(rel), attno, false)),
18534  parser_errposition(pstate, pelem->location)));
18535  }
18536 
18537  /*
18538  * Preprocess the expression before checking for mutability.
18539  * This is essential for the reasons described in
18540  * contain_mutable_functions_after_planning. However, we call
18541  * expression_planner for ourselves rather than using that
18542  * function, because if constant-folding reduces the
18543  * expression to a constant, we'd like to know that so we can
18544  * complain below.
18545  *
18546  * Like contain_mutable_functions_after_planning, assume that
18547  * expression_planner won't scribble on its input, so this
18548  * won't affect the partexprs entry we saved above.
18549  */
18550  expr = (Node *) expression_planner((Expr *) expr);
18551 
18552  /*
18553  * Partition expressions cannot contain mutable functions,
18554  * because a given row must always map to the same partition
18555  * as long as there is no change in the partition boundary
18556  * structure.
18557  */
18558  if (contain_mutable_functions(expr))
18559  ereport(ERROR,
18560  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
18561  errmsg("functions in partition key expression must be marked IMMUTABLE")));
18562 
18563  /*
18564  * While it is not exactly *wrong* for a partition expression
18565  * to be a constant, it seems better to reject such keys.
18566  */
18567  if (IsA(expr, Const))
18568  ereport(ERROR,
18569  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
18570  errmsg("cannot use constant expression as partition key")));
18571  }
18572  }
18573 
18574  /*
18575  * Apply collation override if any
18576  */
18577  if (pelem->collation)
18578  attcollation = get_collation_oid(pelem->collation, false);
18579 
18580  /*
18581  * Check we have a collation iff it's a collatable type. The only
18582  * expected failures here are (1) COLLATE applied to a noncollatable
18583  * type, or (2) partition expression had an unresolved collation. But
18584  * we might as well code this to be a complete consistency check.
18585  */
18586  if (type_is_collatable(atttype))
18587  {
18588  if (!OidIsValid(attcollation))
18589  ereport(ERROR,
18590  (errcode(ERRCODE_INDETERMINATE_COLLATION),
18591  errmsg("could not determine which collation to use for partition expression"),
18592  errhint("Use the COLLATE clause to set the collation explicitly.")));
18593  }
18594  else
18595  {
18596  if (OidIsValid(attcollation))
18597  ereport(ERROR,
18598  (errcode(ERRCODE_DATATYPE_MISMATCH),
18599  errmsg("collations are not supported by type %s",
18600  format_type_be(atttype))));
18601  }
18602 
18603  partcollation[attn] = attcollation;
18604 
18605  /*
18606  * Identify the appropriate operator class. For list and range
18607  * partitioning, we use a btree operator class; hash partitioning uses
18608  * a hash operator class.
18609  */
18610  if (strategy == PARTITION_STRATEGY_HASH)
18611  am_oid = HASH_AM_OID;
18612  else
18613  am_oid = BTREE_AM_OID;
18614 
18615  if (!pelem->opclass)
18616  {
18617  partopclass[attn] = GetDefaultOpClass(atttype, am_oid);
18618 
18619  if (!OidIsValid(partopclass[attn]))
18620  {
18621  if (strategy == PARTITION_STRATEGY_HASH)
18622  ereport(ERROR,
18623  (errcode(ERRCODE_UNDEFINED_OBJECT),
18624  errmsg("data type %s has no default operator class for access method \"%s\"",
18625  format_type_be(atttype), "hash"),
18626  errhint("You must specify a hash operator class or define a default hash operator class for the data type.")));
18627  else
18628  ereport(ERROR,
18629  (errcode(ERRCODE_UNDEFINED_OBJECT),
18630  errmsg("data type %s has no default operator class for access method \"%s\"",
18631  format_type_be(atttype), "btree"),
18632  errhint("You must specify a btree operator class or define a default btree operator class for the data type.")));
18633  }
18634  }
18635  else
18636  partopclass[attn] = ResolveOpClass(pelem->opclass,
18637  atttype,
18638  am_oid == HASH_AM_OID ? "hash" : "btree",
18639  am_oid);
18640 
18641  attn++;
18642  }
18643 }
18644 
18645 /*
18646  * PartConstraintImpliedByRelConstraint
18647  * Do scanrel's existing constraints imply the partition constraint?
18648  *
18649  * "Existing constraints" include its check constraints and column-level
18650  * not-null constraints. partConstraint describes the partition constraint,
18651  * in implicit-AND form.
18652  */
18653 bool
18655  List *partConstraint)
18656 {
18657  List *existConstraint = NIL;
18658  TupleConstr *constr = RelationGetDescr(scanrel)->constr;
18659  int i;
18660 
18661  if (constr && constr->has_not_null)
18662  {
18663  int natts = scanrel->rd_att->natts;
18664 
18665  for (i = 1; i <= natts; i++)
18666  {
18667  Form_pg_attribute att = TupleDescAttr(scanrel->rd_att, i - 1);
18668 
18669  if (att->attnotnull && !att->attisdropped)
18670  {
18671  NullTest *ntest = makeNode(NullTest);
18672 
18673  ntest->arg = (Expr *) makeVar(1,
18674  i,
18675  att->atttypid,
18676  att->atttypmod,
18677  att->attcollation,
18678  0);
18679  ntest->nulltesttype = IS_NOT_NULL;
18680 
18681  /*
18682  * argisrow=false is correct even for a composite column,
18683  * because attnotnull does not represent a SQL-spec IS NOT
18684  * NULL test in such a case, just IS DISTINCT FROM NULL.
18685  */
18686  ntest->argisrow = false;
18687  ntest->location = -1;
18688  existConstraint = lappend(existConstraint, ntest);
18689  }
18690  }
18691  }
18692 
18693  return ConstraintImpliedByRelConstraint(scanrel, partConstraint, existConstraint);
18694 }
18695 
18696 /*
18697  * ConstraintImpliedByRelConstraint
18698  * Do scanrel's existing constraints imply the given constraint?
18699  *
18700  * testConstraint is the constraint to validate. provenConstraint is a
18701  * caller-provided list of conditions which this function may assume
18702  * to be true. Both provenConstraint and testConstraint must be in
18703  * implicit-AND form, must only contain immutable clauses, and must
18704  * contain only Vars with varno = 1.
18705  */
18706 bool
18707 ConstraintImpliedByRelConstraint(Relation scanrel, List *testConstraint, List *provenConstraint)
18708 {
18709  List *existConstraint = list_copy(provenConstraint);
18710  TupleConstr *constr = RelationGetDescr(scanrel)->constr;
18711  int num_check,
18712  i;
18713 
18714  num_check = (constr != NULL) ? constr->num_check : 0;
18715  for (i = 0; i < num_check; i++)
18716  {
18717  Node *cexpr;
18718 
18719  /*
18720  * If this constraint hasn't been fully validated yet, we must ignore
18721  * it here.
18722  */
18723  if (!constr->check[i].ccvalid)
18724  continue;
18725 
18726  cexpr = stringToNode(constr->check[i].ccbin);
18727 
18728  /*
18729  * Run each expression through const-simplification and
18730  * canonicalization. It is necessary, because we will be comparing it
18731  * to similarly-processed partition constraint expressions, and may
18732  * fail to detect valid matches without this.
18733  */
18734  cexpr = eval_const_expressions(NULL, cexpr);
18735  cexpr = (Node *) canonicalize_qual((Expr *) cexpr, true);
18736 
18737  existConstraint = list_concat(existConstraint,
18738  make_ands_implicit((Expr *) cexpr));
18739  }
18740 
18741  /*
18742  * Try to make the proof. Since we are comparing CHECK constraints, we
18743  * need to use weak implication, i.e., we assume existConstraint is
18744  * not-false and try to prove the same for testConstraint.
18745  *
18746  * Note that predicate_implied_by assumes its first argument is known
18747  * immutable. That should always be true for both NOT NULL and partition
18748  * constraints, so we don't test it here.
18749  */
18750  return predicate_implied_by(testConstraint, existConstraint, true);
18751 }
18752 
18753 /*
18754  * QueuePartitionConstraintValidation
18755  *
18756  * Add an entry to wqueue to have the given partition constraint validated by
18757  * Phase 3, for the given relation, and all its children.
18758  *
18759  * We first verify whether the given constraint is implied by pre-existing
18760  * relation constraints; if it is, there's no need to scan the table to
18761  * validate, so don't queue in that case.
18762  */
18763 static void
18765  List *partConstraint,
18766  bool validate_default)
18767 {
18768  /*
18769  * Based on the table's existing constraints, determine whether or not we
18770  * may skip scanning the table.
18771  */
18772  if (PartConstraintImpliedByRelConstraint(scanrel, partConstraint))
18773  {
18774  if (!validate_default)
18775  ereport(DEBUG1,
18776  (errmsg_internal("partition constraint for table \"%s\" is implied by existing constraints",
18777  RelationGetRelationName(scanrel))));
18778  else
18779  ereport(DEBUG1,
18780  (errmsg_internal("updated partition constraint for default partition \"%s\" is implied by existing constraints",
18781  RelationGetRelationName(scanrel))));
18782  return;
18783  }
18784 
18785  /*
18786  * Constraints proved insufficient. For plain relations, queue a
18787  * validation item now; for partitioned tables, recurse to process each
18788  * partition.
18789  */
18790  if (scanrel->rd_rel->relkind == RELKIND_RELATION)
18791  {
18792  AlteredTableInfo *tab;
18793 
18794  /* Grab a work queue entry. */
18795  tab = ATGetQueueEntry(wqueue, scanrel);
18796  Assert(tab->partition_constraint == NULL);
18797  tab->partition_constraint = (Expr *) linitial(partConstraint);
18798  tab->validate_default = validate_default;
18799  }
18800  else if (scanrel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
18801  {
18802  PartitionDesc partdesc = RelationGetPartitionDesc(scanrel, true);
18803  int i;
18804 
18805  for (i = 0; i < partdesc->nparts; i++)
18806  {
18807  Relation part_rel;
18808  List *thisPartConstraint;
18809 
18810  /*
18811  * This is the minimum lock we need to prevent deadlocks.
18812  */
18813  part_rel = table_open(partdesc->oids[i], AccessExclusiveLock);
18814 
18815  /*
18816  * Adjust the constraint for scanrel so that it matches this
18817  * partition's attribute numbers.
18818  */
18819  thisPartConstraint =
18820  map_partition_varattnos(partConstraint, 1,
18821  part_rel, scanrel);
18822 
18823  QueuePartitionConstraintValidation(wqueue, part_rel,
18824  thisPartConstraint,
18825  validate_default);
18826  table_close(part_rel, NoLock); /* keep lock till commit */
18827  }
18828  }
18829 }
18830 
18831 /*
18832  * ALTER TABLE <name> ATTACH PARTITION <partition-name> FOR VALUES
18833  *
18834  * Return the address of the newly attached partition.
18835  */
18836 static ObjectAddress
18838  AlterTableUtilityContext *context)
18839 {
18840  Relation attachrel,
18841  catalog;
18842  List *attachrel_children;
18843  List *partConstraint;
18844  SysScanDesc scan;
18845  ScanKeyData skey;
18846  AttrNumber attno;
18847  int natts;
18848  TupleDesc tupleDesc;
18849  ObjectAddress address;
18850  const char *trigger_name;
18851  Oid defaultPartOid;
18852  List *partBoundConstraint;
18853  ParseState *pstate = make_parsestate(NULL);
18854 
18855  pstate->p_sourcetext = context->queryString;
18856 
18857  /*
18858  * We must lock the default partition if one exists, because attaching a
18859  * new partition will change its partition constraint.
18860  */
18861  defaultPartOid =
18863  if (OidIsValid(defaultPartOid))
18864  LockRelationOid(defaultPartOid, AccessExclusiveLock);
18865 
18866  attachrel = table_openrv(cmd->name, AccessExclusiveLock);
18867 
18868  /*
18869  * XXX I think it'd be a good idea to grab locks on all tables referenced
18870  * by FKs at this point also.
18871  */
18872 
18873  /*
18874  * Must be owner of both parent and source table -- parent was checked by
18875  * ATSimplePermissions call in ATPrepCmd
18876  */
18878 
18879  /* A partition can only have one parent */
18880  if (attachrel->rd_rel->relispartition)
18881  ereport(ERROR,
18882  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
18883  errmsg("\"%s\" is already a partition",
18884  RelationGetRelationName(attachrel))));
18885 
18886  if (OidIsValid(attachrel->rd_rel->reloftype))
18887  ereport(ERROR,
18888  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
18889  errmsg("cannot attach a typed table as partition")));
18890 
18891  /*
18892  * Table being attached should not already be part of inheritance; either
18893  * as a child table...
18894  */
18895  catalog = table_open(InheritsRelationId, AccessShareLock);
18896  ScanKeyInit(&skey,
18897  Anum_pg_inherits_inhrelid,
18898  BTEqualStrategyNumber, F_OIDEQ,
18899  ObjectIdGetDatum(RelationGetRelid(attachrel)));
18900  scan = systable_beginscan(catalog, InheritsRelidSeqnoIndexId, true,
18901  NULL, 1, &skey);
18903  ereport(ERROR,
18904  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
18905  errmsg("cannot attach inheritance child as partition")));
18906  systable_endscan(scan);
18907 
18908  /* ...or as a parent table (except the case when it is partitioned) */
18909  ScanKeyInit(&skey,
18910  Anum_pg_inherits_inhparent,
18911  BTEqualStrategyNumber, F_OIDEQ,
18912  ObjectIdGetDatum(RelationGetRelid(attachrel)));
18913  scan = systable_beginscan(catalog, InheritsParentIndexId, true, NULL,
18914  1, &skey);
18915  if (HeapTupleIsValid(systable_getnext(scan)) &&
18916  attachrel->rd_rel->relkind == RELKIND_RELATION)
18917  ereport(ERROR,
18918  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
18919  errmsg("cannot attach inheritance parent as partition")));
18920  systable_endscan(scan);
18921  table_close(catalog, AccessShareLock);
18922 
18923  /*
18924  * Prevent circularity by seeing if rel is a partition of attachrel. (In
18925  * particular, this disallows making a rel a partition of itself.)
18926  *
18927  * We do that by checking if rel is a member of the list of attachrel's
18928  * partitions provided the latter is partitioned at all. We want to avoid
18929  * having to construct this list again, so we request the strongest lock
18930  * on all partitions. We need the strongest lock, because we may decide
18931  * to scan them if we find out that the table being attached (or its leaf
18932  * partitions) may contain rows that violate the partition constraint. If
18933  * the table has a constraint that would prevent such rows, which by
18934  * definition is present in all the partitions, we need not scan the
18935  * table, nor its partitions. But we cannot risk a deadlock by taking a
18936  * weaker lock now and the stronger one only when needed.
18937  */
18938  attachrel_children = find_all_inheritors(RelationGetRelid(attachrel),
18939  AccessExclusiveLock, NULL);
18940  if (list_member_oid(attachrel_children, RelationGetRelid(rel)))
18941  ereport(ERROR,
18942  (errcode(ERRCODE_DUPLICATE_TABLE),
18943  errmsg("circular inheritance not allowed"),
18944  errdetail("\"%s\" is already a child of \"%s\".",
18946  RelationGetRelationName(attachrel))));
18947 
18948  /* If the parent is permanent, so must be all of its partitions. */
18949  if (rel->rd_rel->relpersistence != RELPERSISTENCE_TEMP &&
18950  attachrel->rd_rel->relpersistence == RELPERSISTENCE_TEMP)
18951  ereport(ERROR,
18952  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
18953  errmsg("cannot attach a temporary relation as partition of permanent relation \"%s\"",
18954  RelationGetRelationName(rel))));
18955 
18956  /* Temp parent cannot have a partition that is itself not a temp */
18957  if (rel->rd_rel->relpersistence == RELPERSISTENCE_TEMP &&
18958  attachrel->rd_rel->relpersistence != RELPERSISTENCE_TEMP)
18959  ereport(ERROR,
18960  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
18961  errmsg("cannot attach a permanent relation as partition of temporary relation \"%s\"",
18962  RelationGetRelationName(rel))));
18963 
18964  /* If the parent is temp, it must belong to this session */
18965  if (rel->rd_rel->relpersistence == RELPERSISTENCE_TEMP &&
18966  !rel->rd_islocaltemp)
18967  ereport(ERROR,
18968  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
18969  errmsg("cannot attach as partition of temporary relation of another session")));
18970 
18971  /* Ditto for the partition */
18972  if (attachrel->rd_rel->relpersistence == RELPERSISTENCE_TEMP &&
18973  !attachrel->rd_islocaltemp)
18974  ereport(ERROR,
18975  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
18976  errmsg("cannot attach temporary relation of another session as partition")));
18977 
18978  /*
18979  * Check if attachrel has any identity columns or any columns that aren't
18980  * in the parent.
18981  */
18982  tupleDesc = RelationGetDescr(attachrel);
18983  natts = tupleDesc->natts;
18984  for (attno = 1; attno <= natts; attno++)
18985  {
18986  Form_pg_attribute attribute = TupleDescAttr(tupleDesc, attno - 1);
18987  char *attributeName = NameStr(attribute->attname);
18988 
18989  /* Ignore dropped */
18990  if (attribute->attisdropped)
18991  continue;
18992 
18993  if (attribute->attidentity)
18994  ereport(ERROR,
18995  errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
18996  errmsg("table \"%s\" being attached contains an identity column \"%s\"",
18997  RelationGetRelationName(attachrel), attributeName),
18998  errdetail("The new partition may not contain an identity column."));
18999 
19000  /* Try to find the column in parent (matching on column name) */
19001  if (!SearchSysCacheExists2(ATTNAME,
19003  CStringGetDatum(attributeName)))
19004  ereport(ERROR,
19005  (errcode(ERRCODE_DATATYPE_MISMATCH),
19006  errmsg("table \"%s\" contains column \"%s\" not found in parent \"%s\"",
19007  RelationGetRelationName(attachrel), attributeName,
19009  errdetail("The new partition may contain only the columns present in parent.")));
19010  }
19011 
19012  /*
19013  * If child_rel has row-level triggers with transition tables, we
19014  * currently don't allow it to become a partition. See also prohibitions
19015  * in ATExecAddInherit() and CreateTrigger().
19016  */
19017  trigger_name = FindTriggerIncompatibleWithInheritance(attachrel->trigdesc);
19018  if (trigger_name != NULL)
19019  ereport(ERROR,
19020  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
19021  errmsg("trigger \"%s\" prevents table \"%s\" from becoming a partition",
19022  trigger_name, RelationGetRelationName(attachrel)),
19023  errdetail("ROW triggers with transition tables are not supported on partitions.")));
19024 
19025  /*
19026  * Check that the new partition's bound is valid and does not overlap any
19027  * of existing partitions of the parent - note that it does not return on
19028  * error.
19029  */
19031  cmd->bound, pstate);
19032 
19033  /* OK to create inheritance. Rest of the checks performed there */
19034  CreateInheritance(attachrel, rel, true);
19035 
19036  /* Update the pg_class entry. */
19037  StorePartitionBound(attachrel, rel, cmd->bound);
19038 
19039  /* Ensure there exists a correct set of indexes in the partition. */
19040  AttachPartitionEnsureIndexes(wqueue, rel, attachrel);
19041 
19042  /* and triggers */
19043  CloneRowTriggersToPartition(rel, attachrel);
19044 
19045  /*
19046  * Clone foreign key constraints. Callee is responsible for setting up
19047  * for phase 3 constraint verification.
19048  */
19049  CloneForeignKeyConstraints(wqueue, rel, attachrel);
19050 
19051  /*
19052  * Generate partition constraint from the partition bound specification.
19053  * If the parent itself is a partition, make sure to include its
19054  * constraint as well.
19055  */
19056  partBoundConstraint = get_qual_from_partbound(rel, cmd->bound);
19057  partConstraint = list_concat(partBoundConstraint,
19059 
19060  /* Skip validation if there are no constraints to validate. */
19061  if (partConstraint)
19062  {
19063  /*
19064  * Run the partition quals through const-simplification similar to
19065  * check constraints. We skip canonicalize_qual, though, because
19066  * partition quals should be in canonical form already.
19067  */
19068  partConstraint =
19069  (List *) eval_const_expressions(NULL,
19070  (Node *) partConstraint);
19071 
19072  /* XXX this sure looks wrong */
19073  partConstraint = list_make1(make_ands_explicit(partConstraint));
19074 
19075  /*
19076  * Adjust the generated constraint to match this partition's attribute
19077  * numbers.
19078  */
19079  partConstraint = map_partition_varattnos(partConstraint, 1, attachrel,
19080  rel);
19081 
19082  /* Validate partition constraints against the table being attached. */
19083  QueuePartitionConstraintValidation(wqueue, attachrel, partConstraint,
19084  false);
19085  }
19086 
19087  /*
19088  * If we're attaching a partition other than the default partition and a
19089  * default one exists, then that partition's partition constraint changes,
19090  * so add an entry to the work queue to validate it, too. (We must not do
19091  * this when the partition being attached is the default one; we already
19092  * did it above!)
19093  */
19094  if (OidIsValid(defaultPartOid))
19095  {
19096  Relation defaultrel;
19097  List *defPartConstraint;
19098 
19099  Assert(!cmd->bound->is_default);
19100 
19101  /* we already hold a lock on the default partition */
19102  defaultrel = table_open(defaultPartOid, NoLock);
19103  defPartConstraint =
19104  get_proposed_default_constraint(partBoundConstraint);
19105 
19106  /*
19107  * Map the Vars in the constraint expression from rel's attnos to
19108  * defaultrel's.
19109  */
19110  defPartConstraint =
19111  map_partition_varattnos(defPartConstraint,
19112  1, defaultrel, rel);
19113  QueuePartitionConstraintValidation(wqueue, defaultrel,
19114  defPartConstraint, true);
19115 
19116  /* keep our lock until commit. */
19117  table_close(defaultrel, NoLock);
19118  }
19119 
19120  ObjectAddressSet(address, RelationRelationId, RelationGetRelid(attachrel));
19121 
19122  /*
19123  * If the partition we just attached is partitioned itself, invalidate
19124  * relcache for all descendent partitions too to ensure that their
19125  * rd_partcheck expression trees are rebuilt; partitions already locked at
19126  * the beginning of this function.
19127  */
19128  if (attachrel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
19129  {
19130  ListCell *l;
19131 
19132  foreach(l, attachrel_children)
19133  {
19135  }
19136  }
19137 
19138  /* keep our lock until commit */
19139  table_close(attachrel, NoLock);
19140 
19141  return address;
19142 }
19143 
19144 /*
19145  * AttachPartitionEnsureIndexes
19146  * subroutine for ATExecAttachPartition to create/match indexes
19147  *
19148  * Enforce the indexing rule for partitioned tables during ALTER TABLE / ATTACH
19149  * PARTITION: every partition must have an index attached to each index on the
19150  * partitioned table.
19151  */
19152 static void
19154 {
19155  List *idxes;
19156  List *attachRelIdxs;
19157  Relation *attachrelIdxRels;
19158  IndexInfo **attachInfos;
19159  ListCell *cell;
19160  MemoryContext cxt;
19161  MemoryContext oldcxt;
19162 
19164  "AttachPartitionEnsureIndexes",
19166  oldcxt = MemoryContextSwitchTo(cxt);
19167 
19168  idxes = RelationGetIndexList(rel);
19169  attachRelIdxs = RelationGetIndexList(attachrel);
19170  attachrelIdxRels = palloc(sizeof(Relation) * list_length(attachRelIdxs));
19171  attachInfos = palloc(sizeof(IndexInfo *) * list_length(attachRelIdxs));
19172 
19173  /* Build arrays of all existing indexes and their IndexInfos */
19174  foreach(cell, attachRelIdxs)
19175  {
19176  Oid cldIdxId = lfirst_oid(cell);
19177  int i = foreach_current_index(cell);
19178 
19179  attachrelIdxRels[i] = index_open(cldIdxId, AccessShareLock);
19180  attachInfos[i] = BuildIndexInfo(attachrelIdxRels[i]);
19181  }
19182 
19183  /*
19184  * If we're attaching a foreign table, we must fail if any of the indexes
19185  * is a constraint index; otherwise, there's nothing to do here. Do this
19186  * before starting work, to avoid wasting the effort of building a few
19187  * non-unique indexes before coming across a unique one.
19188  */
19189  if (attachrel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
19190  {
19191  foreach(cell, idxes)
19192  {
19193  Oid idx = lfirst_oid(cell);
19195 
19196  if (idxRel->rd_index->indisunique ||
19197  idxRel->rd_index->indisprimary)
19198  ereport(ERROR,
19199  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
19200  errmsg("cannot attach foreign table \"%s\" as partition of partitioned table \"%s\"",
19201  RelationGetRelationName(attachrel),
19203  errdetail("Partitioned table \"%s\" contains unique indexes.",
19204  RelationGetRelationName(rel))));
19205  index_close(idxRel, AccessShareLock);
19206  }
19207 
19208  goto out;
19209  }
19210 
19211  /*
19212  * For each index on the partitioned table, find a matching one in the
19213  * partition-to-be; if one is not found, create one.
19214  */
19215  foreach(cell, idxes)
19216  {
19217  Oid idx = lfirst_oid(cell);
19219  IndexInfo *info;
19220  AttrMap *attmap;
19221  bool found = false;
19222  Oid constraintOid;
19223 
19224  /*
19225  * Ignore indexes in the partitioned table other than partitioned
19226  * indexes.
19227  */
19228  if (idxRel->rd_rel->relkind != RELKIND_PARTITIONED_INDEX)
19229  {
19230  index_close(idxRel, AccessShareLock);
19231  continue;
19232  }
19233 
19234  /* construct an indexinfo to compare existing indexes against */
19235  info = BuildIndexInfo(idxRel);
19236  attmap = build_attrmap_by_name(RelationGetDescr(attachrel),
19237  RelationGetDescr(rel),
19238  false);
19239  constraintOid = get_relation_idx_constraint_oid(RelationGetRelid(rel), idx);
19240 
19241  /*
19242  * Scan the list of existing indexes in the partition-to-be, and mark
19243  * the first matching, valid, unattached one we find, if any, as
19244  * partition of the parent index. If we find one, we're done.
19245  */
19246  for (int i = 0; i < list_length(attachRelIdxs); i++)
19247  {
19248  Oid cldIdxId = RelationGetRelid(attachrelIdxRels[i]);
19249  Oid cldConstrOid = InvalidOid;
19250 
19251  /* does this index have a parent? if so, can't use it */
19252  if (attachrelIdxRels[i]->rd_rel->relispartition)
19253  continue;
19254 
19255  /* If this index is invalid, can't use it */
19256  if (!attachrelIdxRels[i]->rd_index->indisvalid)
19257  continue;
19258 
19259  if (CompareIndexInfo(attachInfos[i], info,
19260  attachrelIdxRels[i]->rd_indcollation,
19261  idxRel->rd_indcollation,
19262  attachrelIdxRels[i]->rd_opfamily,
19263  idxRel->rd_opfamily,
19264  attmap))
19265  {
19266  /*
19267  * If this index is being created in the parent because of a
19268  * constraint, then the child needs to have a constraint also,
19269  * so look for one. If there is no such constraint, this
19270  * index is no good, so keep looking.
19271  */
19272  if (OidIsValid(constraintOid))
19273  {
19274  cldConstrOid =
19276  cldIdxId);
19277  /* no dice */
19278  if (!OidIsValid(cldConstrOid))
19279  continue;
19280  }
19281 
19282  /* bingo. */
19283  IndexSetParentIndex(attachrelIdxRels[i], idx);
19284  if (OidIsValid(constraintOid))
19285  ConstraintSetParentConstraint(cldConstrOid, constraintOid,
19286  RelationGetRelid(attachrel));
19287  found = true;
19288 
19290  break;
19291  }
19292  }
19293 
19294  /*
19295  * If no suitable index was found in the partition-to-be, create one
19296  * now.
19297  */
19298  if (!found)
19299  {
19300  IndexStmt *stmt;
19301  Oid conOid;
19302 
19304  idxRel, attmap,
19305  &conOid);
19306 
19307  /*
19308  * If the index is a primary key, mark all columns as NOT NULL if
19309  * they aren't already.
19310  */
19311  if (stmt->primary)
19312  {
19313  MemoryContextSwitchTo(oldcxt);
19314  for (int j = 0; j < info->ii_NumIndexKeyAttrs; j++)
19315  {
19316  AttrNumber childattno;
19317 
19318  childattno = get_attnum(RelationGetRelid(attachrel),
19320  info->ii_IndexAttrNumbers[j],
19321  false));
19322  set_attnotnull(wqueue, attachrel, childattno,
19323  true, AccessExclusiveLock);
19324  }
19325  MemoryContextSwitchTo(cxt);
19326  }
19327 
19329  RelationGetRelid(idxRel),
19330  conOid,
19331  -1,
19332  true, false, false, false, false);
19333  }
19334 
19335  index_close(idxRel, AccessShareLock);
19336  }
19337 
19338 out:
19339  /* Clean up. */
19340  for (int i = 0; i < list_length(attachRelIdxs); i++)
19341  index_close(attachrelIdxRels[i], AccessShareLock);
19342  MemoryContextSwitchTo(oldcxt);
19343  MemoryContextDelete(cxt);
19344 }
19345 
19346 /*
19347  * CloneRowTriggersToPartition
19348  * subroutine for ATExecAttachPartition/DefineRelation to create row
19349  * triggers on partitions
19350  */
19351 static void
19353 {
19354  Relation pg_trigger;
19355  ScanKeyData key;
19356  SysScanDesc scan;
19357  HeapTuple tuple;
19358  MemoryContext perTupCxt;
19359 
19360  ScanKeyInit(&key, Anum_pg_trigger_tgrelid, BTEqualStrategyNumber,
19361  F_OIDEQ, ObjectIdGetDatum(RelationGetRelid(parent)));
19362  pg_trigger = table_open(TriggerRelationId, RowExclusiveLock);
19363  scan = systable_beginscan(pg_trigger, TriggerRelidNameIndexId,
19364  true, NULL, 1, &key);
19365 
19367  "clone trig", ALLOCSET_SMALL_SIZES);
19368 
19369  while (HeapTupleIsValid(tuple = systable_getnext(scan)))
19370  {
19371  Form_pg_trigger trigForm = (Form_pg_trigger) GETSTRUCT(tuple);
19372  CreateTrigStmt *trigStmt;
19373  Node *qual = NULL;
19374  Datum value;
19375  bool isnull;
19376  List *cols = NIL;
19377  List *trigargs = NIL;
19378  MemoryContext oldcxt;
19379 
19380  /*
19381  * Ignore statement-level triggers; those are not cloned.
19382  */
19383  if (!TRIGGER_FOR_ROW(trigForm->tgtype))
19384  continue;
19385 
19386  /*
19387  * Don't clone internal triggers, because the constraint cloning code
19388  * will.
19389  */
19390  if (trigForm->tgisinternal)
19391  continue;
19392 
19393  /*
19394  * Complain if we find an unexpected trigger type.
19395  */
19396  if (!TRIGGER_FOR_BEFORE(trigForm->tgtype) &&
19397  !TRIGGER_FOR_AFTER(trigForm->tgtype))
19398  elog(ERROR, "unexpected trigger \"%s\" found",
19399  NameStr(trigForm->tgname));
19400 
19401  /* Use short-lived context for CREATE TRIGGER */
19402  oldcxt = MemoryContextSwitchTo(perTupCxt);
19403 
19404  /*
19405  * If there is a WHEN clause, generate a 'cooked' version of it that's
19406  * appropriate for the partition.
19407  */
19408  value = heap_getattr(tuple, Anum_pg_trigger_tgqual,
19409  RelationGetDescr(pg_trigger), &isnull);
19410  if (!isnull)
19411  {
19413  qual = (Node *) map_partition_varattnos((List *) qual, PRS2_OLD_VARNO,
19414  partition, parent);
19415  qual = (Node *) map_partition_varattnos((List *) qual, PRS2_NEW_VARNO,
19416  partition, parent);
19417  }
19418 
19419  /*
19420  * If there is a column list, transform it to a list of column names.
19421  * Note we don't need to map this list in any way ...
19422  */
19423  if (trigForm->tgattr.dim1 > 0)
19424  {
19425  int i;
19426 
19427  for (i = 0; i < trigForm->tgattr.dim1; i++)
19428  {
19429  Form_pg_attribute col;
19430 
19431  col = TupleDescAttr(parent->rd_att,
19432  trigForm->tgattr.values[i] - 1);
19433  cols = lappend(cols,
19434  makeString(pstrdup(NameStr(col->attname))));
19435  }
19436  }
19437 
19438  /* Reconstruct trigger arguments list. */
19439  if (trigForm->tgnargs > 0)
19440  {
19441  char *p;
19442 
19443  value = heap_getattr(tuple, Anum_pg_trigger_tgargs,
19444  RelationGetDescr(pg_trigger), &isnull);
19445  if (isnull)
19446  elog(ERROR, "tgargs is null for trigger \"%s\" in partition \"%s\"",
19447  NameStr(trigForm->tgname), RelationGetRelationName(partition));
19448 
19449  p = (char *) VARDATA_ANY(DatumGetByteaPP(value));
19450 
19451  for (int i = 0; i < trigForm->tgnargs; i++)
19452  {
19453  trigargs = lappend(trigargs, makeString(pstrdup(p)));
19454  p += strlen(p) + 1;
19455  }
19456  }
19457 
19458  trigStmt = makeNode(CreateTrigStmt);
19459  trigStmt->replace = false;
19460  trigStmt->isconstraint = OidIsValid(trigForm->tgconstraint);
19461  trigStmt->trigname = NameStr(trigForm->tgname);
19462  trigStmt->relation = NULL;
19463  trigStmt->funcname = NULL; /* passed separately */
19464  trigStmt->args = trigargs;
19465  trigStmt->row = true;
19466  trigStmt->timing = trigForm->tgtype & TRIGGER_TYPE_TIMING_MASK;
19467  trigStmt->events = trigForm->tgtype & TRIGGER_TYPE_EVENT_MASK;
19468  trigStmt->columns = cols;
19469  trigStmt->whenClause = NULL; /* passed separately */
19470  trigStmt->transitionRels = NIL; /* not supported at present */
19471  trigStmt->deferrable = trigForm->tgdeferrable;
19472  trigStmt->initdeferred = trigForm->tginitdeferred;
19473  trigStmt->constrrel = NULL; /* passed separately */
19474 
19475  CreateTriggerFiringOn(trigStmt, NULL, RelationGetRelid(partition),
19476  trigForm->tgconstrrelid, InvalidOid, InvalidOid,
19477  trigForm->tgfoid, trigForm->oid, qual,
19478  false, true, trigForm->tgenabled);
19479 
19480  MemoryContextSwitchTo(oldcxt);
19481  MemoryContextReset(perTupCxt);
19482  }
19483 
19484  MemoryContextDelete(perTupCxt);
19485 
19486  systable_endscan(scan);
19487  table_close(pg_trigger, RowExclusiveLock);
19488 }
19489 
19490 /*
19491  * ALTER TABLE DETACH PARTITION
19492  *
19493  * Return the address of the relation that is no longer a partition of rel.
19494  *
19495  * If concurrent mode is requested, we run in two transactions. A side-
19496  * effect is that this command cannot run in a multi-part ALTER TABLE.
19497  * Currently, that's enforced by the grammar.
19498  *
19499  * The strategy for concurrency is to first modify the partition's
19500  * pg_inherit catalog row to make it visible to everyone that the
19501  * partition is detached, lock the partition against writes, and commit
19502  * the transaction; anyone who requests the partition descriptor from
19503  * that point onwards has to ignore such a partition. In a second
19504  * transaction, we wait until all transactions that could have seen the
19505  * partition as attached are gone, then we remove the rest of partition
19506  * metadata (pg_inherits and pg_class.relpartbounds).
19507  */
19508 static ObjectAddress
19510  RangeVar *name, bool concurrent)
19511 {
19512  Relation partRel;
19513  ObjectAddress address;
19514  Oid defaultPartOid;
19515 
19516  /*
19517  * We must lock the default partition, because detaching this partition
19518  * will change its partition constraint.
19519  */
19520  defaultPartOid =
19522  if (OidIsValid(defaultPartOid))
19523  {
19524  /*
19525  * Concurrent detaching when a default partition exists is not
19526  * supported. The main problem is that the default partition
19527  * constraint would change. And there's a definitional problem: what
19528  * should happen to the tuples that are being inserted that belong to
19529  * the partition being detached? Putting them on the partition being
19530  * detached would be wrong, since they'd become "lost" after the
19531  * detaching completes but we cannot put them in the default partition
19532  * either until we alter its partition constraint.
19533  *
19534  * I think we could solve this problem if we effected the constraint
19535  * change before committing the first transaction. But the lock would
19536  * have to remain AEL and it would cause concurrent query planning to
19537  * be blocked, so changing it that way would be even worse.
19538  */
19539  if (concurrent)
19540  ereport(ERROR,
19541  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
19542  errmsg("cannot detach partitions concurrently when a default partition exists")));
19543  LockRelationOid(defaultPartOid, AccessExclusiveLock);
19544  }
19545 
19546  /*
19547  * In concurrent mode, the partition is locked with share-update-exclusive
19548  * in the first transaction. This allows concurrent transactions to be
19549  * doing DML to the partition.
19550  */
19551  partRel = table_openrv(name, concurrent ? ShareUpdateExclusiveLock :
19553 
19554  /*
19555  * Check inheritance conditions and either delete the pg_inherits row (in
19556  * non-concurrent mode) or just set the inhdetachpending flag.
19557  */
19558  if (!concurrent)
19559  RemoveInheritance(partRel, rel, false);
19560  else
19561  MarkInheritDetached(partRel, rel);
19562 
19563  /*
19564  * Ensure that foreign keys still hold after this detach. This keeps
19565  * locks on the referencing tables, which prevents concurrent transactions
19566  * from adding rows that we wouldn't see. For this to work in concurrent
19567  * mode, it is critical that the partition appears as no longer attached
19568  * for the RI queries as soon as the first transaction commits.
19569  */
19571 
19572  /*
19573  * Concurrent mode has to work harder; first we add a new constraint to
19574  * the partition that matches the partition constraint. Then we close our
19575  * existing transaction, and in a new one wait for all processes to catch
19576  * up on the catalog updates we've done so far; at that point we can
19577  * complete the operation.
19578  */
19579  if (concurrent)
19580  {
19581  Oid partrelid,
19582  parentrelid;
19583  LOCKTAG tag;
19584  char *parentrelname;
19585  char *partrelname;
19586 
19587  /*
19588  * Add a new constraint to the partition being detached, which
19589  * supplants the partition constraint (unless there is one already).
19590  */
19591  DetachAddConstraintIfNeeded(wqueue, partRel);
19592 
19593  /*
19594  * We're almost done now; the only traces that remain are the
19595  * pg_inherits tuple and the partition's relpartbounds. Before we can
19596  * remove those, we need to wait until all transactions that know that
19597  * this is a partition are gone.
19598  */
19599 
19600  /*
19601  * Remember relation OIDs to re-acquire them later; and relation names
19602  * too, for error messages if something is dropped in between.
19603  */
19604  partrelid = RelationGetRelid(partRel);
19605  parentrelid = RelationGetRelid(rel);
19606  parentrelname = MemoryContextStrdup(PortalContext,
19608  partrelname = MemoryContextStrdup(PortalContext,
19609  RelationGetRelationName(partRel));
19610 
19611  /* Invalidate relcache entries for the parent -- must be before close */
19613 
19614  table_close(partRel, NoLock);
19615  table_close(rel, NoLock);
19616  tab->rel = NULL;
19617 
19618  /* Make updated catalog entry visible */
19621 
19623 
19624  /*
19625  * Now wait. This ensures that all queries that were planned
19626  * including the partition are finished before we remove the rest of
19627  * catalog entries. We don't need or indeed want to acquire this
19628  * lock, though -- that would block later queries.
19629  *
19630  * We don't need to concern ourselves with waiting for a lock on the
19631  * partition itself, since we will acquire AccessExclusiveLock below.
19632  */
19633  SET_LOCKTAG_RELATION(tag, MyDatabaseId, parentrelid);
19635 
19636  /*
19637  * Now acquire locks in both relations again. Note they may have been
19638  * removed in the meantime, so care is required.
19639  */
19640  rel = try_relation_open(parentrelid, ShareUpdateExclusiveLock);
19641  partRel = try_relation_open(partrelid, AccessExclusiveLock);
19642 
19643  /* If the relations aren't there, something bad happened; bail out */
19644  if (rel == NULL)
19645  {
19646  if (partRel != NULL) /* shouldn't happen */
19647  elog(WARNING, "dangling partition \"%s\" remains, can't fix",
19648  partrelname);
19649  ereport(ERROR,
19650  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
19651  errmsg("partitioned table \"%s\" was removed concurrently",
19652  parentrelname)));
19653  }
19654  if (partRel == NULL)
19655  ereport(ERROR,
19656  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
19657  errmsg("partition \"%s\" was removed concurrently", partrelname)));
19658 
19659  tab->rel = rel;
19660  }
19661 
19662  /* Do the final part of detaching */
19663  DetachPartitionFinalize(rel, partRel, concurrent, defaultPartOid);
19664 
19665  ObjectAddressSet(address, RelationRelationId, RelationGetRelid(partRel));
19666 
19667  /* keep our lock until commit */
19668  table_close(partRel, NoLock);
19669 
19670  return address;
19671 }
19672 
19673 /*
19674  * Second part of ALTER TABLE .. DETACH.
19675  *
19676  * This is separate so that it can be run independently when the second
19677  * transaction of the concurrent algorithm fails (crash or abort).
19678  */
19679 static void
19680 DetachPartitionFinalize(Relation rel, Relation partRel, bool concurrent,
19681  Oid defaultPartOid)
19682 {
19683  Relation classRel;
19684  List *fks;
19685  ListCell *cell;
19686  List *indexes;
19687  Datum new_val[Natts_pg_class];
19688  bool new_null[Natts_pg_class],
19689  new_repl[Natts_pg_class];
19690  HeapTuple tuple,
19691  newtuple;
19692  Relation trigrel = NULL;
19693 
19694  if (concurrent)
19695  {
19696  /*
19697  * We can remove the pg_inherits row now. (In the non-concurrent case,
19698  * this was already done).
19699  */
19700  RemoveInheritance(partRel, rel, true);
19701  }
19702 
19703  /* Drop any triggers that were cloned on creation/attach. */
19705 
19706  /*
19707  * Detach any foreign keys that are inherited. This includes creating
19708  * additional action triggers.
19709  */
19710  fks = copyObject(RelationGetFKeyList(partRel));
19711  if (fks != NIL)
19712  trigrel = table_open(TriggerRelationId, RowExclusiveLock);
19713  foreach(cell, fks)
19714  {
19715  ForeignKeyCacheInfo *fk = lfirst(cell);
19716  HeapTuple contup;
19717  Form_pg_constraint conform;
19718  Constraint *fkconstraint;
19719  Oid insertTriggerOid,
19720  updateTriggerOid;
19721 
19722  contup = SearchSysCache1(CONSTROID, ObjectIdGetDatum(fk->conoid));
19723  if (!HeapTupleIsValid(contup))
19724  elog(ERROR, "cache lookup failed for constraint %u", fk->conoid);
19725  conform = (Form_pg_constraint) GETSTRUCT(contup);
19726 
19727  /* consider only the inherited foreign keys */
19728  if (conform->contype != CONSTRAINT_FOREIGN ||
19729  !OidIsValid(conform->conparentid))
19730  {
19731  ReleaseSysCache(contup);
19732  continue;
19733  }
19734 
19735  /* unset conparentid and adjust conislocal, coninhcount, etc. */
19737 
19738  /*
19739  * Also, look up the partition's "check" triggers corresponding to the
19740  * constraint being detached and detach them from the parent triggers.
19741  */
19743  fk->conoid, fk->confrelid, fk->conrelid,
19744  &insertTriggerOid, &updateTriggerOid);
19745  Assert(OidIsValid(insertTriggerOid));
19746  TriggerSetParentTrigger(trigrel, insertTriggerOid, InvalidOid,
19747  RelationGetRelid(partRel));
19748  Assert(OidIsValid(updateTriggerOid));
19749  TriggerSetParentTrigger(trigrel, updateTriggerOid, InvalidOid,
19750  RelationGetRelid(partRel));
19751 
19752  /*
19753  * Make the action triggers on the referenced relation. When this was
19754  * a partition the action triggers pointed to the parent rel (they
19755  * still do), but now we need separate ones of our own.
19756  */
19757  fkconstraint = makeNode(Constraint);
19758  fkconstraint->contype = CONSTRAINT_FOREIGN;
19759  fkconstraint->conname = pstrdup(NameStr(conform->conname));
19760  fkconstraint->deferrable = conform->condeferrable;
19761  fkconstraint->initdeferred = conform->condeferred;
19762  fkconstraint->location = -1;
19763  fkconstraint->pktable = NULL;
19764  fkconstraint->fk_attrs = NIL;
19765  fkconstraint->pk_attrs = NIL;
19766  fkconstraint->fk_matchtype = conform->confmatchtype;
19767  fkconstraint->fk_upd_action = conform->confupdtype;
19768  fkconstraint->fk_del_action = conform->confdeltype;
19769  fkconstraint->fk_del_set_cols = NIL;
19770  fkconstraint->old_conpfeqop = NIL;
19771  fkconstraint->old_pktable_oid = InvalidOid;
19772  fkconstraint->skip_validation = false;
19773  fkconstraint->initially_valid = true;
19774 
19775  createForeignKeyActionTriggers(partRel, conform->confrelid,
19776  fkconstraint, fk->conoid,
19777  conform->conindid,
19779  NULL, NULL);
19780 
19781  ReleaseSysCache(contup);
19782  }
19783  list_free_deep(fks);
19784  if (trigrel)
19785  table_close(trigrel, RowExclusiveLock);
19786 
19787  /*
19788  * Any sub-constraints that are in the referenced-side of a larger
19789  * constraint have to be removed. This partition is no longer part of the
19790  * key space of the constraint.
19791  */
19792  foreach(cell, GetParentedForeignKeyRefs(partRel))
19793  {
19794  Oid constrOid = lfirst_oid(cell);
19795  ObjectAddress constraint;
19796 
19798  deleteDependencyRecordsForClass(ConstraintRelationId,
19799  constrOid,
19800  ConstraintRelationId,
19803 
19804  ObjectAddressSet(constraint, ConstraintRelationId, constrOid);
19805  performDeletion(&constraint, DROP_RESTRICT, 0);
19806  }
19807 
19808  /* Now we can detach indexes */
19809  indexes = RelationGetIndexList(partRel);
19810  foreach(cell, indexes)
19811  {
19812  Oid idxid = lfirst_oid(cell);
19813  Relation idx;
19814  Oid constrOid;
19815 
19816  if (!has_superclass(idxid))
19817  continue;
19818 
19819  Assert((IndexGetRelation(get_partition_parent(idxid, false), false) ==
19820  RelationGetRelid(rel)));
19821 
19824 
19825  /* If there's a constraint associated with the index, detach it too */
19827  idxid);
19828  if (OidIsValid(constrOid))
19830 
19832  }
19833 
19834  /* Update pg_class tuple */
19835  classRel = table_open(RelationRelationId, RowExclusiveLock);
19836  tuple = SearchSysCacheCopy1(RELOID,
19838  if (!HeapTupleIsValid(tuple))
19839  elog(ERROR, "cache lookup failed for relation %u",
19840  RelationGetRelid(partRel));
19841  Assert(((Form_pg_class) GETSTRUCT(tuple))->relispartition);
19842 
19843  /* Clear relpartbound and reset relispartition */
19844  memset(new_val, 0, sizeof(new_val));
19845  memset(new_null, false, sizeof(new_null));
19846  memset(new_repl, false, sizeof(new_repl));
19847  new_val[Anum_pg_class_relpartbound - 1] = (Datum) 0;
19848  new_null[Anum_pg_class_relpartbound - 1] = true;
19849  new_repl[Anum_pg_class_relpartbound - 1] = true;
19850  newtuple = heap_modify_tuple(tuple, RelationGetDescr(classRel),
19851  new_val, new_null, new_repl);
19852 
19853  ((Form_pg_class) GETSTRUCT(newtuple))->relispartition = false;
19854  CatalogTupleUpdate(classRel, &newtuple->t_self, newtuple);
19855  heap_freetuple(newtuple);
19856  table_close(classRel, RowExclusiveLock);
19857 
19858  /*
19859  * Drop identity property from all identity columns of partition.
19860  */
19861  for (int attno = 0; attno < RelationGetNumberOfAttributes(partRel); attno++)
19862  {
19863  Form_pg_attribute attr = TupleDescAttr(partRel->rd_att, attno);
19864 
19865  if (!attr->attisdropped && attr->attidentity)
19866  ATExecDropIdentity(partRel, NameStr(attr->attname), false,
19867  AccessExclusiveLock, true, true);
19868  }
19869 
19870  if (OidIsValid(defaultPartOid))
19871  {
19872  /*
19873  * If the relation being detached is the default partition itself,
19874  * remove it from the parent's pg_partitioned_table entry.
19875  *
19876  * If not, we must invalidate default partition's relcache entry, as
19877  * in StorePartitionBound: its partition constraint depends on every
19878  * other partition's partition constraint.
19879  */
19880  if (RelationGetRelid(partRel) == defaultPartOid)
19882  else
19883  CacheInvalidateRelcacheByRelid(defaultPartOid);
19884  }
19885 
19886  /*
19887  * Invalidate the parent's relcache so that the partition is no longer
19888  * included in its partition descriptor.
19889  */
19891 
19892  /*
19893  * If the partition we just detached is partitioned itself, invalidate
19894  * relcache for all descendent partitions too to ensure that their
19895  * rd_partcheck expression trees are rebuilt; must lock partitions before
19896  * doing so, using the same lockmode as what partRel has been locked with
19897  * by the caller.
19898  */
19899  if (partRel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
19900  {
19901  List *children;
19902 
19903  children = find_all_inheritors(RelationGetRelid(partRel),
19904  AccessExclusiveLock, NULL);
19905  foreach(cell, children)
19906  {
19908  }
19909  }
19910 }
19911 
19912 /*
19913  * ALTER TABLE ... DETACH PARTITION ... FINALIZE
19914  *
19915  * To use when a DETACH PARTITION command previously did not run to
19916  * completion; this completes the detaching process.
19917  */
19918 static ObjectAddress
19920 {
19921  Relation partRel;
19922  ObjectAddress address;
19923  Snapshot snap = GetActiveSnapshot();
19924 
19926 
19927  /*
19928  * Wait until existing snapshots are gone. This is important if the
19929  * second transaction of DETACH PARTITION CONCURRENTLY is canceled: the
19930  * user could immediately run DETACH FINALIZE without actually waiting for
19931  * existing transactions. We must not complete the detach action until
19932  * all such queries are complete (otherwise we would present them with an
19933  * inconsistent view of catalogs).
19934  */
19935  WaitForOlderSnapshots(snap->xmin, false);
19936 
19937  DetachPartitionFinalize(rel, partRel, true, InvalidOid);
19938 
19939  ObjectAddressSet(address, RelationRelationId, RelationGetRelid(partRel));
19940 
19941  table_close(partRel, NoLock);
19942 
19943  return address;
19944 }
19945 
19946 /*
19947  * DetachAddConstraintIfNeeded
19948  * Subroutine for ATExecDetachPartition. Create a constraint that
19949  * takes the place of the partition constraint, but avoid creating
19950  * a dupe if an constraint already exists which implies the needed
19951  * constraint.
19952  */
19953 static void
19955 {
19956  List *constraintExpr;
19957 
19958  constraintExpr = RelationGetPartitionQual(partRel);
19959  constraintExpr = (List *) eval_const_expressions(NULL, (Node *) constraintExpr);
19960 
19961  /*
19962  * Avoid adding a new constraint if the needed constraint is implied by an
19963  * existing constraint
19964  */
19965  if (!PartConstraintImpliedByRelConstraint(partRel, constraintExpr))
19966  {
19967  AlteredTableInfo *tab;
19968  Constraint *n;
19969 
19970  tab = ATGetQueueEntry(wqueue, partRel);
19971 
19972  /* Add constraint on partition, equivalent to the partition constraint */
19973  n = makeNode(Constraint);
19974  n->contype = CONSTR_CHECK;
19975  n->conname = NULL;
19976  n->location = -1;
19977  n->is_no_inherit = false;
19978  n->raw_expr = NULL;
19979  n->cooked_expr = nodeToString(make_ands_explicit(constraintExpr));
19980  n->initially_valid = true;
19981  n->skip_validation = true;
19982  /* It's a re-add, since it nominally already exists */
19983  ATAddCheckNNConstraint(wqueue, tab, partRel, n,
19984  true, false, true, ShareUpdateExclusiveLock);
19985  }
19986 }
19987 
19988 /*
19989  * DropClonedTriggersFromPartition
19990  * subroutine for ATExecDetachPartition to remove any triggers that were
19991  * cloned to the partition when it was created-as-partition or attached.
19992  * This undoes what CloneRowTriggersToPartition did.
19993  */
19994 static void
19996 {
19997  ScanKeyData skey;
19998  SysScanDesc scan;
19999  HeapTuple trigtup;
20000  Relation tgrel;
20001  ObjectAddresses *objects;
20002 
20003  objects = new_object_addresses();
20004 
20005  /*
20006  * Scan pg_trigger to search for all triggers on this rel.
20007  */
20008  ScanKeyInit(&skey, Anum_pg_trigger_tgrelid, BTEqualStrategyNumber,
20009  F_OIDEQ, ObjectIdGetDatum(partitionId));
20010  tgrel = table_open(TriggerRelationId, RowExclusiveLock);
20011  scan = systable_beginscan(tgrel, TriggerRelidNameIndexId,
20012  true, NULL, 1, &skey);
20013  while (HeapTupleIsValid(trigtup = systable_getnext(scan)))
20014  {
20015  Form_pg_trigger pg_trigger = (Form_pg_trigger) GETSTRUCT(trigtup);
20016  ObjectAddress trig;
20017 
20018  /* Ignore triggers that weren't cloned */
20019  if (!OidIsValid(pg_trigger->tgparentid))
20020  continue;
20021 
20022  /*
20023  * Ignore internal triggers that are implementation objects of foreign
20024  * keys, because these will be detached when the foreign keys
20025  * themselves are.
20026  */
20027  if (OidIsValid(pg_trigger->tgconstrrelid))
20028  continue;
20029 
20030  /*
20031  * This is ugly, but necessary: remove the dependency markings on the
20032  * trigger so that it can be removed.
20033  */
20034  deleteDependencyRecordsForClass(TriggerRelationId, pg_trigger->oid,
20035  TriggerRelationId,
20037  deleteDependencyRecordsForClass(TriggerRelationId, pg_trigger->oid,
20038  RelationRelationId,
20040 
20041  /* remember this trigger to remove it below */
20042  ObjectAddressSet(trig, TriggerRelationId, pg_trigger->oid);
20043  add_exact_object_address(&trig, objects);
20044  }
20045 
20046  /* make the dependency removal visible to the deletion below */
20049 
20050  /* done */
20051  free_object_addresses(objects);
20052  systable_endscan(scan);
20053  table_close(tgrel, RowExclusiveLock);
20054 }
20055 
20056 /*
20057  * Before acquiring lock on an index, acquire the same lock on the owning
20058  * table.
20059  */
20061 {
20065 };
20066 
20067 static void
20068 RangeVarCallbackForAttachIndex(const RangeVar *rv, Oid relOid, Oid oldRelOid,
20069  void *arg)
20070 {
20072  Form_pg_class classform;
20073  HeapTuple tuple;
20074 
20075  state = (struct AttachIndexCallbackState *) arg;
20076 
20077  if (!state->lockedParentTbl)
20078  {
20079  LockRelationOid(state->parentTblOid, AccessShareLock);
20080  state->lockedParentTbl = true;
20081  }
20082 
20083  /*
20084  * If we previously locked some other heap, and the name we're looking up
20085  * no longer refers to an index on that relation, release the now-useless
20086  * lock. XXX maybe we should do *after* we verify whether the index does
20087  * not actually belong to the same relation ...
20088  */
20089  if (relOid != oldRelOid && OidIsValid(state->partitionOid))
20090  {
20091  UnlockRelationOid(state->partitionOid, AccessShareLock);
20092  state->partitionOid = InvalidOid;
20093  }
20094 
20095  /* Didn't find a relation, so no need for locking or permission checks. */
20096  if (!OidIsValid(relOid))
20097  return;
20098 
20099  tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relOid));
20100  if (!HeapTupleIsValid(tuple))
20101  return; /* concurrently dropped, so nothing to do */
20102  classform = (Form_pg_class) GETSTRUCT(tuple);
20103  if (classform->relkind != RELKIND_PARTITIONED_INDEX &&
20104  classform->relkind != RELKIND_INDEX)
20105  ereport(ERROR,
20106  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
20107  errmsg("\"%s\" is not an index", rv->relname)));
20108  ReleaseSysCache(tuple);
20109 
20110  /*
20111  * Since we need only examine the heap's tupledesc, an access share lock
20112  * on it (preventing any DDL) is sufficient.
20113  */
20114  state->partitionOid = IndexGetRelation(relOid, false);
20115  LockRelationOid(state->partitionOid, AccessShareLock);
20116 }
20117 
20118 /*
20119  * ALTER INDEX i1 ATTACH PARTITION i2
20120  */
20121 static ObjectAddress
20123 {
20124  Relation partIdx;
20125  Relation partTbl;
20126  Relation parentTbl;
20127  ObjectAddress address;
20128  Oid partIdxId;
20129  Oid currParent;
20131 
20132  /*
20133  * We need to obtain lock on the index 'name' to modify it, but we also
20134  * need to read its owning table's tuple descriptor -- so we need to lock
20135  * both. To avoid deadlocks, obtain lock on the table before doing so on
20136  * the index. Furthermore, we need to examine the parent table of the
20137  * partition, so lock that one too.
20138  */
20139  state.partitionOid = InvalidOid;
20140  state.parentTblOid = parentIdx->rd_index->indrelid;
20141  state.lockedParentTbl = false;
20142  partIdxId =
20145  (void *) &state);
20146  /* Not there? */
20147  if (!OidIsValid(partIdxId))
20148  ereport(ERROR,
20149  (errcode(ERRCODE_UNDEFINED_OBJECT),
20150  errmsg("index \"%s\" does not exist", name->relname)));
20151 
20152  /* no deadlock risk: RangeVarGetRelidExtended already acquired the lock */
20153  partIdx = relation_open(partIdxId, AccessExclusiveLock);
20154 
20155  /* we already hold locks on both tables, so this is safe: */
20156  parentTbl = relation_open(parentIdx->rd_index->indrelid, AccessShareLock);
20157  partTbl = relation_open(partIdx->rd_index->indrelid, NoLock);
20158 
20159  ObjectAddressSet(address, RelationRelationId, RelationGetRelid(partIdx));
20160 
20161  /* Silently do nothing if already in the right state */
20162  currParent = partIdx->rd_rel->relispartition ?
20163  get_partition_parent(partIdxId, false) : InvalidOid;
20164  if (currParent != RelationGetRelid(parentIdx))
20165  {
20166  IndexInfo *childInfo;
20167  IndexInfo *parentInfo;
20168  AttrMap *attmap;
20169  bool found;
20170  int i;
20171  PartitionDesc partDesc;
20172  Oid constraintOid,
20173  cldConstrId = InvalidOid;
20174 
20175  /*
20176  * If this partition already has an index attached, refuse the
20177  * operation.
20178  */
20179  refuseDupeIndexAttach(parentIdx, partIdx, partTbl);
20180 
20181  if (OidIsValid(currParent))
20182  ereport(ERROR,
20183  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
20184  errmsg("cannot attach index \"%s\" as a partition of index \"%s\"",
20185  RelationGetRelationName(partIdx),
20186  RelationGetRelationName(parentIdx)),
20187  errdetail("Index \"%s\" is already attached to another index.",
20188  RelationGetRelationName(partIdx))));
20189 
20190  /* Make sure it indexes a partition of the other index's table */
20191  partDesc = RelationGetPartitionDesc(parentTbl, true);
20192  found = false;
20193  for (i = 0; i < partDesc->nparts; i++)
20194  {
20195  if (partDesc->oids[i] == state.partitionOid)
20196  {
20197  found = true;
20198  break;
20199  }
20200  }
20201  if (!found)
20202  ereport(ERROR,
20203  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
20204  errmsg("cannot attach index \"%s\" as a partition of index \"%s\"",
20205  RelationGetRelationName(partIdx),
20206  RelationGetRelationName(parentIdx)),
20207  errdetail("Index \"%s\" is not an index on any partition of table \"%s\".",
20208  RelationGetRelationName(partIdx),
20209  RelationGetRelationName(parentTbl))));
20210 
20211  /* Ensure the indexes are compatible */
20212  childInfo = BuildIndexInfo(partIdx);
20213  parentInfo = BuildIndexInfo(parentIdx);
20214  attmap = build_attrmap_by_name(RelationGetDescr(partTbl),
20215  RelationGetDescr(parentTbl),
20216  false);
20217  if (!CompareIndexInfo(childInfo, parentInfo,
20218  partIdx->rd_indcollation,
20219  parentIdx->rd_indcollation,
20220  partIdx->rd_opfamily,
20221  parentIdx->rd_opfamily,
20222  attmap))
20223  ereport(ERROR,
20224  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
20225  errmsg("cannot attach index \"%s\" as a partition of index \"%s\"",
20226  RelationGetRelationName(partIdx),
20227  RelationGetRelationName(parentIdx)),
20228  errdetail("The index definitions do not match.")));
20229 
20230  /*
20231  * If there is a constraint in the parent, make sure there is one in
20232  * the child too.
20233  */
20234  constraintOid = get_relation_idx_constraint_oid(RelationGetRelid(parentTbl),
20235  RelationGetRelid(parentIdx));
20236 
20237  if (OidIsValid(constraintOid))
20238  {
20239  cldConstrId = get_relation_idx_constraint_oid(RelationGetRelid(partTbl),
20240  partIdxId);
20241  if (!OidIsValid(cldConstrId))
20242  ereport(ERROR,
20243  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
20244  errmsg("cannot attach index \"%s\" as a partition of index \"%s\"",
20245  RelationGetRelationName(partIdx),
20246  RelationGetRelationName(parentIdx)),
20247  errdetail("The index \"%s\" belongs to a constraint in table \"%s\" but no constraint exists for index \"%s\".",
20248  RelationGetRelationName(parentIdx),
20249  RelationGetRelationName(parentTbl),
20250  RelationGetRelationName(partIdx))));
20251  }
20252 
20253  /*
20254  * If it's a primary key, make sure the columns in the partition are
20255  * NOT NULL.
20256  */
20257  if (parentIdx->rd_index->indisprimary)
20258  verifyPartitionIndexNotNull(childInfo, partTbl);
20259 
20260  /* All good -- do it */
20261  IndexSetParentIndex(partIdx, RelationGetRelid(parentIdx));
20262  if (OidIsValid(constraintOid))
20263  ConstraintSetParentConstraint(cldConstrId, constraintOid,
20264  RelationGetRelid(partTbl));
20265 
20266  free_attrmap(attmap);
20267 
20268  validatePartitionedIndex(parentIdx, parentTbl);
20269  }
20270 
20271  relation_close(parentTbl, AccessShareLock);
20272  /* keep these locks till commit */
20273  relation_close(partTbl, NoLock);
20274  relation_close(partIdx, NoLock);
20275 
20276  return address;
20277 }
20278 
20279 /*
20280  * Verify whether the given partition already contains an index attached
20281  * to the given partitioned index. If so, raise an error.
20282  */
20283 static void
20284 refuseDupeIndexAttach(Relation parentIdx, Relation partIdx, Relation partitionTbl)
20285 {
20286  Oid existingIdx;
20287 
20288  existingIdx = index_get_partition(partitionTbl,
20289  RelationGetRelid(parentIdx));
20290  if (OidIsValid(existingIdx))
20291  ereport(ERROR,
20292  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
20293  errmsg("cannot attach index \"%s\" as a partition of index \"%s\"",
20294  RelationGetRelationName(partIdx),
20295  RelationGetRelationName(parentIdx)),
20296  errdetail("Another index is already attached for partition \"%s\".",
20297  RelationGetRelationName(partitionTbl))));
20298 }
20299 
20300 /*
20301  * Verify whether the set of attached partition indexes to a parent index on
20302  * a partitioned table is complete. If it is, mark the parent index valid.
20303  *
20304  * This should be called each time a partition index is attached.
20305  */
20306 static void
20308 {
20309  Relation inheritsRel;
20310  SysScanDesc scan;
20311  ScanKeyData key;
20312  int tuples = 0;
20313  HeapTuple inhTup;
20314  bool updated = false;
20315 
20316  Assert(partedIdx->rd_rel->relkind == RELKIND_PARTITIONED_INDEX);
20317 
20318  /*
20319  * Scan pg_inherits for this parent index. Count each valid index we find
20320  * (verifying the pg_index entry for each), and if we reach the total
20321  * amount we expect, we can mark this parent index as valid.
20322  */
20323  inheritsRel = table_open(InheritsRelationId, AccessShareLock);
20324  ScanKeyInit(&key, Anum_pg_inherits_inhparent,
20325  BTEqualStrategyNumber, F_OIDEQ,
20326  ObjectIdGetDatum(RelationGetRelid(partedIdx)));
20327  scan = systable_beginscan(inheritsRel, InheritsParentIndexId, true,
20328  NULL, 1, &key);
20329  while ((inhTup = systable_getnext(scan)) != NULL)
20330  {
20331  Form_pg_inherits inhForm = (Form_pg_inherits) GETSTRUCT(inhTup);
20332  HeapTuple indTup;
20333  Form_pg_index indexForm;
20334 
20335  indTup = SearchSysCache1(INDEXRELID,
20336  ObjectIdGetDatum(inhForm->inhrelid));
20337  if (!HeapTupleIsValid(indTup))
20338  elog(ERROR, "cache lookup failed for index %u", inhForm->inhrelid);
20339  indexForm = (Form_pg_index) GETSTRUCT(indTup);
20340  if (indexForm->indisvalid)
20341  tuples += 1;
20342  ReleaseSysCache(indTup);
20343  }
20344 
20345  /* Done with pg_inherits */
20346  systable_endscan(scan);
20347  table_close(inheritsRel, AccessShareLock);
20348 
20349  /*
20350  * If we found as many inherited indexes as the partitioned table has
20351  * partitions, we're good; update pg_index to set indisvalid.
20352  */
20353  if (tuples == RelationGetPartitionDesc(partedTbl, true)->nparts)
20354  {
20355  Relation idxRel;
20356  HeapTuple indTup;
20357  Form_pg_index indexForm;
20358 
20359  idxRel = table_open(IndexRelationId, RowExclusiveLock);
20360  indTup = SearchSysCacheCopy1(INDEXRELID,
20361  ObjectIdGetDatum(RelationGetRelid(partedIdx)));
20362  if (!HeapTupleIsValid(indTup))
20363  elog(ERROR, "cache lookup failed for index %u",
20364  RelationGetRelid(partedIdx));
20365  indexForm = (Form_pg_index) GETSTRUCT(indTup);
20366 
20367  indexForm->indisvalid = true;
20368  updated = true;
20369 
20370  CatalogTupleUpdate(idxRel, &indTup->t_self, indTup);
20371 
20372  table_close(idxRel, RowExclusiveLock);
20373  heap_freetuple(indTup);
20374  }
20375 
20376  /*
20377  * If this index is in turn a partition of a larger index, validating it
20378  * might cause the parent to become valid also. Try that.
20379  */
20380  if (updated && partedIdx->rd_rel->relispartition)
20381  {
20382  Oid parentIdxId,
20383  parentTblId;
20384  Relation parentIdx,
20385  parentTbl;
20386 
20387  /* make sure we see the validation we just did */
20389 
20390  parentIdxId = get_partition_parent(RelationGetRelid(partedIdx), false);
20391  parentTblId = get_partition_parent(RelationGetRelid(partedTbl), false);
20392  parentIdx = relation_open(parentIdxId, AccessExclusiveLock);
20393  parentTbl = relation_open(parentTblId, AccessExclusiveLock);
20394  Assert(!parentIdx->rd_index->indisvalid);
20395 
20396  validatePartitionedIndex(parentIdx, parentTbl);
20397 
20398  relation_close(parentIdx, AccessExclusiveLock);
20399  relation_close(parentTbl, AccessExclusiveLock);
20400  }
20401 }
20402 
20403 /*
20404  * When attaching an index as a partition of a partitioned index which is a
20405  * primary key, verify that all the columns in the partition are marked NOT
20406  * NULL.
20407  */
20408 static void
20410 {
20411  for (int i = 0; i < iinfo->ii_NumIndexKeyAttrs; i++)
20412  {
20414  iinfo->ii_IndexAttrNumbers[i] - 1);
20415 
20416  if (!att->attnotnull)
20417  ereport(ERROR,
20418  errcode(ERRCODE_INVALID_TABLE_DEFINITION),
20419  errmsg("invalid primary key definition"),
20420  errdetail("Column \"%s\" of relation \"%s\" is not marked NOT NULL.",
20421  NameStr(att->attname),
20422  RelationGetRelationName(partition)));
20423  }
20424 }
20425 
20426 /*
20427  * Return an OID list of constraints that reference the given relation
20428  * that are marked as having a parent constraints.
20429  */
20430 static List *
20432 {
20433  Relation pg_constraint;
20434  HeapTuple tuple;
20435  SysScanDesc scan;
20436  ScanKeyData key[2];
20437  List *constraints = NIL;
20438 
20439  /*
20440  * If no indexes, or no columns are referenceable by FKs, we can avoid the
20441  * scan.
20442  */
20443  if (RelationGetIndexList(partition) == NIL ||
20446  return NIL;
20447 
20448  /* Search for constraints referencing this table */
20449  pg_constraint = table_open(ConstraintRelationId, AccessShareLock);
20450  ScanKeyInit(&key[0],
20451  Anum_pg_constraint_confrelid, BTEqualStrategyNumber,
20452  F_OIDEQ, ObjectIdGetDatum(RelationGetRelid(partition)));
20453  ScanKeyInit(&key[1],
20454  Anum_pg_constraint_contype, BTEqualStrategyNumber,
20455  F_CHAREQ, CharGetDatum(CONSTRAINT_FOREIGN));
20456 
20457  /* XXX This is a seqscan, as we don't have a usable index */
20458  scan = systable_beginscan(pg_constraint, InvalidOid, true, NULL, 2, key);
20459  while ((tuple = systable_getnext(scan)) != NULL)
20460  {
20461  Form_pg_constraint constrForm = (Form_pg_constraint) GETSTRUCT(tuple);
20462 
20463  /*
20464  * We only need to process constraints that are part of larger ones.
20465  */
20466  if (!OidIsValid(constrForm->conparentid))
20467  continue;
20468 
20469  constraints = lappend_oid(constraints, constrForm->oid);
20470  }
20471 
20472  systable_endscan(scan);
20473  table_close(pg_constraint, AccessShareLock);
20474 
20475  return constraints;
20476 }
20477 
20478 /*
20479  * During DETACH PARTITION, verify that any foreign keys pointing to the
20480  * partitioned table would not become invalid. An error is raised if any
20481  * referenced values exist.
20482  */
20483 static void
20485 {
20486  List *constraints;
20487  ListCell *cell;
20488 
20489  constraints = GetParentedForeignKeyRefs(partition);
20490 
20491  foreach(cell, constraints)
20492  {
20493  Oid constrOid = lfirst_oid(cell);
20494  HeapTuple tuple;
20495  Form_pg_constraint constrForm;
20496  Relation rel;
20497  Trigger trig = {0};
20498 
20499  tuple = SearchSysCache1(CONSTROID, ObjectIdGetDatum(constrOid));
20500  if (!HeapTupleIsValid(tuple))
20501  elog(ERROR, "cache lookup failed for constraint %u", constrOid);
20502  constrForm = (Form_pg_constraint) GETSTRUCT(tuple);
20503 
20504  Assert(OidIsValid(constrForm->conparentid));
20505  Assert(constrForm->confrelid == RelationGetRelid(partition));
20506 
20507  /* prevent data changes into the referencing table until commit */
20508  rel = table_open(constrForm->conrelid, ShareLock);
20509 
20510  trig.tgoid = InvalidOid;
20511  trig.tgname = NameStr(constrForm->conname);
20513  trig.tgisinternal = true;
20514  trig.tgconstrrelid = RelationGetRelid(partition);
20515  trig.tgconstrindid = constrForm->conindid;
20516  trig.tgconstraint = constrForm->oid;
20517  trig.tgdeferrable = false;
20518  trig.tginitdeferred = false;
20519  /* we needn't fill in remaining fields */
20520 
20521  RI_PartitionRemove_Check(&trig, rel, partition);
20522 
20523  ReleaseSysCache(tuple);
20524 
20525  table_close(rel, NoLock);
20526  }
20527 }
20528 
20529 /*
20530  * resolve column compression specification to compression method.
20531  */
20532 static char
20533 GetAttributeCompression(Oid atttypid, const char *compression)
20534 {
20535  char cmethod;
20536 
20537  if (compression == NULL || strcmp(compression, "default") == 0)
20538  return InvalidCompressionMethod;
20539 
20540  /*
20541  * To specify a nondefault method, the column data type must be toastable.
20542  * Note this says nothing about whether the column's attstorage setting
20543  * permits compression; we intentionally allow attstorage and
20544  * attcompression to be independent. But with a non-toastable type,
20545  * attstorage could not be set to a value that would permit compression.
20546  *
20547  * We don't actually need to enforce this, since nothing bad would happen
20548  * if attcompression were non-default; it would never be consulted. But
20549  * it seems more user-friendly to complain about a certainly-useless
20550  * attempt to set the property.
20551  */
20552  if (!TypeIsToastable(atttypid))
20553  ereport(ERROR,
20554  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
20555  errmsg("column data type %s does not support compression",
20556  format_type_be(atttypid))));
20557 
20558  cmethod = CompressionNameToMethod(compression);
20559  if (!CompressionMethodIsValid(cmethod))
20560  ereport(ERROR,
20561  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
20562  errmsg("invalid compression method \"%s\"", compression)));
20563 
20564  return cmethod;
20565 }
20566 
20567 /*
20568  * resolve column storage specification
20569  */
20570 static char
20571 GetAttributeStorage(Oid atttypid, const char *storagemode)
20572 {
20573  char cstorage = 0;
20574 
20575  if (pg_strcasecmp(storagemode, "plain") == 0)
20576  cstorage = TYPSTORAGE_PLAIN;
20577  else if (pg_strcasecmp(storagemode, "external") == 0)
20578  cstorage = TYPSTORAGE_EXTERNAL;
20579  else if (pg_strcasecmp(storagemode, "extended") == 0)
20580  cstorage = TYPSTORAGE_EXTENDED;
20581  else if (pg_strcasecmp(storagemode, "main") == 0)
20582  cstorage = TYPSTORAGE_MAIN;
20583  else if (pg_strcasecmp(storagemode, "default") == 0)
20584  cstorage = get_typstorage(atttypid);
20585  else
20586  ereport(ERROR,
20587  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
20588  errmsg("invalid storage type \"%s\"",
20589  storagemode)));
20590 
20591  /*
20592  * safety check: do not allow toasted storage modes unless column datatype
20593  * is TOAST-aware.
20594  */
20595  if (!(cstorage == TYPSTORAGE_PLAIN || TypeIsToastable(atttypid)))
20596  ereport(ERROR,
20597  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
20598  errmsg("column data type %s can only have storage PLAIN",
20599  format_type_be(atttypid))));
20600 
20601  return cstorage;
20602 }
Datum idx(PG_FUNCTION_ARGS)
Definition: _int_op.c:259
Acl * aclnewowner(const Acl *old_acl, Oid oldOwnerId, Oid newOwnerId)
Definition: acl.c:1088
void check_can_set_role(Oid member, Oid role)
Definition: acl.c:5123
Oid get_rolespec_oid(const RoleSpec *role, bool missing_ok)
Definition: acl.c:5386
AclResult
Definition: acl.h:182
@ ACLCHECK_OK
Definition: acl.h:183
@ ACLCHECK_NOT_OWNER
Definition: acl.h:185
#define DatumGetAclP(X)
Definition: acl.h:120
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:2688
AclResult pg_attribute_aclcheck(Oid table_oid, AttrNumber attnum, Oid roleid, AclMode mode)
Definition: aclchk.c:3908
AclResult object_aclcheck(Oid classid, Oid objectid, Oid roleid, AclMode mode)
Definition: aclchk.c:3876
bool object_ownercheck(Oid classid, Oid objectid, Oid roleid)
Definition: aclchk.c:4130
void aclcheck_error_type(AclResult aclerr, Oid typeOid)
Definition: aclchk.c:3007
AclResult pg_class_aclcheck(Oid table_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4079
Oid get_table_am_oid(const char *amname, bool missing_ok)
Definition: amcmds.c:173
#define ARR_NDIM(a)
Definition: array.h:290
#define ARR_DATA_PTR(a)
Definition: array.h:322
#define DatumGetArrayTypeP(X)
Definition: array.h:261
#define ARR_ELEMTYPE(a)
Definition: array.h:292
#define ARR_DIMS(a)
Definition: array.h:294
#define ARR_HASNULL(a)
Definition: array.h:291
ArrayType * construct_array(Datum *elems, int nelems, Oid elmtype, int elmlen, bool elmbyval, char elmalign)
Definition: arrayfuncs.c:3354
Datum array_get_element(Datum arraydatum, int nSubscripts, int *indx, int arraytyplen, int elmlen, bool elmbyval, char elmalign, bool *isNull)
Definition: arrayfuncs.c:1820
void free_attrmap(AttrMap *map)
Definition: attmap.c:56
AttrMap * make_attrmap(int maplen)
Definition: attmap.c:40
AttrMap * build_attrmap_by_name_if_req(TupleDesc indesc, TupleDesc outdesc, bool missing_ok)
Definition: attmap.c:263
AttrMap * build_attrmap_by_name(TupleDesc indesc, TupleDesc outdesc, bool missing_ok)
Definition: attmap.c:177
int16 AttrNumber
Definition: attnum.h:21
#define InvalidAttrNumber
Definition: attnum.h:23
char * get_tablespace_name(Oid spc_oid)
Definition: tablespace.c:1472
Oid get_tablespace_oid(const char *tablespacename, bool missing_ok)
Definition: tablespace.c:1426
Oid GetDefaultTablespace(char relpersistence, bool partitioned)
Definition: tablespace.c:1143
List * roleSpecsToIds(List *memberNames)
Definition: user.c:1652
List * raw_parser(const char *str, RawParseMode mode)
Definition: parser.c:42
bool TimestampTimestampTzRequiresRewrite(void)
Definition: timestamp.c:6261
int bms_next_member(const Bitmapset *a, int prevbit)
Definition: bitmapset.c:1306
bool bms_is_member(int x, const Bitmapset *a)
Definition: bitmapset.c:510
Bitmapset * bms_make_singleton(int x)
Definition: bitmapset.c:216
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:815
#define bms_is_empty(a)
Definition: bitmapset.h:118
void FlushRelationBuffers(Relation rel)
Definition: bufmgr.c:4145
#define TextDatumGetCString(d)
Definition: builtins.h:98
#define NameStr(name)
Definition: c.h:733
uint16 bits16
Definition: c.h:501
signed short int16
Definition: c.h:480
uint32 SubTransactionId
Definition: c.h:643
signed int int32
Definition: c.h:481
#define gettext_noop(x)
Definition: c.h:1183
#define InvalidSubTransactionId
Definition: c.h:645
#define PointerIsValid(pointer)
Definition: c.h:750
#define MemSet(start, val, len)
Definition: c.h:1007
uint32 CommandId
Definition: c.h:653
#define PG_INT16_MAX
Definition: c.h:573
#define OidIsValid(objectId)
Definition: c.h:762
bool IsToastNamespace(Oid namespaceId)
Definition: catalog.c:200
bool IsSystemRelation(Relation relation)
Definition: catalog.c:73
RelFileNumber GetNewRelFileNumber(Oid reltablespace, Relation pg_class, char relpersistence)
Definition: catalog.c:500
bool IsCatalogNamespace(Oid namespaceId)
Definition: catalog.c:182
bool IsSystemClass(Oid relid, Form_pg_class reltuple)
Definition: catalog.c:85
bool contain_mutable_functions(Node *clause)
Definition: clauses.c:369
Node * eval_const_expressions(PlannerInfo *root, Node *node)
Definition: clauses.c:2234
void check_index_is_clusterable(Relation OldHeap, Oid indexOid, LOCKMODE lockmode)
Definition: cluster.c:500
void finish_heap_swap(Oid OIDOldHeap, Oid OIDNewHeap, bool is_system_catalog, bool swap_toast_by_content, bool check_constraints, bool is_internal, TransactionId frozenXid, MultiXactId cutoffMulti, char newrelpersistence)
Definition: cluster.c:1432
Oid make_new_heap(Oid OIDOldHeap, Oid NewTableSpace, Oid NewAccessMethod, char relpersistence, LOCKMODE lockmode)
Definition: cluster.c:688
void mark_index_clustered(Relation rel, Oid indexOid, bool is_internal)
Definition: cluster.c:560
Oid collid
void ResetSequence(Oid seq_relid)
Definition: sequence.c:262
void SequenceChangePersistence(Oid relid, char newrelpersistence)
Definition: sequence.c:541
char * GetComment(Oid oid, Oid classoid, int32 subid)
Definition: comment.c:410
ObjectAddress CommentObject(CommentStmt *stmt)
Definition: comment.c:40
int32 defGetInt32(DefElem *def)
Definition: define.c:162
void performMultipleDeletions(const ObjectAddresses *objects, DropBehavior behavior, int flags)
Definition: dependency.c:332
ObjectClass getObjectClass(const ObjectAddress *object)
Definition: dependency.c:2784
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:2589
ObjectAddresses * new_object_addresses(void)
Definition: dependency.c:2483
void add_exact_object_address(const ObjectAddress *object, ObjectAddresses *addrs)
Definition: dependency.c:2529
void free_object_addresses(ObjectAddresses *addrs)
Definition: dependency.c:2769
#define PERFORM_DELETION_CONCURRENTLY
Definition: dependency.h:135
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:136
#define PERFORM_DELETION_INTERNAL
Definition: dependency.h:134
@ OCLASS_OPERATOR
Definition: dependency.h:100
@ OCLASS_PARAMETER_ACL
Definition: dependency.h:124
@ OCLASS_LARGEOBJECT
Definition: dependency.h:99
@ OCLASS_FDW
Definition: dependency.h:118
@ OCLASS_OPFAMILY
Definition: dependency.h:102
@ OCLASS_DEFACL
Definition: dependency.h:121
@ OCLASS_TSPARSER
Definition: dependency.h:110
@ OCLASS_TRIGGER
Definition: dependency.h:107
@ OCLASS_DEFAULT
Definition: dependency.h:97
@ OCLASS_TSTEMPLATE
Definition: dependency.h:112
@ OCLASS_AMPROC
Definition: dependency.h:105
@ OCLASS_TBLSPACE
Definition: dependency.h:117
@ OCLASS_TSCONFIG
Definition: dependency.h:113
@ OCLASS_TYPE
Definition: dependency.h:92
@ OCLASS_LANGUAGE
Definition: dependency.h:98
@ OCLASS_CAST
Definition: dependency.h:93
@ OCLASS_SUBSCRIPTION
Definition: dependency.h:129
@ OCLASS_PUBLICATION_NAMESPACE
Definition: dependency.h:127
@ OCLASS_EXTENSION
Definition: dependency.h:122
@ OCLASS_COLLATION
Definition: dependency.h:94
@ OCLASS_FOREIGN_SERVER
Definition: dependency.h:119
@ OCLASS_REWRITE
Definition: dependency.h:106
@ OCLASS_STATISTIC_EXT
Definition: dependency.h:109
@ OCLASS_PROC
Definition: dependency.h:91
@ OCLASS_OPCLASS
Definition: dependency.h:101
@ OCLASS_CONVERSION
Definition: dependency.h:96
@ OCLASS_DATABASE
Definition: dependency.h:116
@ OCLASS_ROLE_MEMBERSHIP
Definition: dependency.h:115
@ OCLASS_SCHEMA
Definition: dependency.h:108
@ OCLASS_EVENT_TRIGGER
Definition: dependency.h:123
@ OCLASS_CLASS
Definition: dependency.h:90
@ OCLASS_TRANSFORM
Definition: dependency.h:130
@ OCLASS_ROLE
Definition: dependency.h:114
@ OCLASS_CONSTRAINT
Definition: dependency.h:95
@ OCLASS_POLICY
Definition: dependency.h:125
@ OCLASS_USER_MAPPING
Definition: dependency.h:120
@ OCLASS_PUBLICATION_REL
Definition: dependency.h:128
@ OCLASS_AM
Definition: dependency.h:103
@ OCLASS_TSDICT
Definition: dependency.h:111
@ OCLASS_PUBLICATION
Definition: dependency.h:126
@ OCLASS_AMOP
Definition: dependency.h:104
void hash_destroy(HTAB *hashp)
Definition: dynahash.c:865
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:955
HTAB * hash_create(const char *tabname, long nelem, const HASHCTL *info, int flags)
Definition: dynahash.c:352
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1395
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1385
int errmsg_internal(const char *fmt,...)
Definition: elog.c:1159
int errdetail(const char *fmt,...)
Definition: elog.c:1205
int errhint(const char *fmt,...)
Definition: elog.c:1319
int errcode(int sqlerrcode)
Definition: elog.c:859
int errmsg(const char *fmt,...)
Definition: elog.c:1072
#define _(x)
Definition: elog.c:90
#define PG_TRY(...)
Definition: elog.h:370
#define WARNING
Definition: elog.h:36
#define PG_END_TRY(...)
Definition: elog.h:395
#define DEBUG1
Definition: elog.h:30
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:224
#define NOTICE
Definition: elog.h:35
#define PG_FINALLY(...)
Definition: elog.h:387
#define ereport(elevel,...)
Definition: elog.h:149
bool equal(const void *a, const void *b)
Definition: equalfuncs.c:223
void EventTriggerAlterTableStart(Node *parsetree)
void EventTriggerTableRewrite(Node *parsetree, Oid tableOid, int reason)
void EventTriggerAlterTableRelid(Oid objectId)
void EventTriggerAlterTableEnd(void)
void EventTriggerCollectAlterTableSubcmd(Node *subcmd, ObjectAddress address)
#define AT_REWRITE_ALTER_PERSISTENCE
Definition: event_trigger.h:34
#define AT_REWRITE_DEFAULT_VAL
Definition: event_trigger.h:35
#define AT_REWRITE_ACCESS_METHOD
Definition: event_trigger.h:37
#define AT_REWRITE_COLUMN_REWRITE
Definition: event_trigger.h:36
ExprState * ExecPrepareExpr(Expr *node, EState *estate)
Definition: execExpr.c:732
bool ExecCheck(ExprState *state, ExprContext *econtext)
Definition: execExpr.c:839
ExprState * ExecInitExpr(Expr *node, PlanState *parent)
Definition: execExpr.c:127
void InitResultRelInfo(ResultRelInfo *resultRelInfo, Relation resultRelationDesc, Index resultRelationIndex, ResultRelInfo *partition_root_rri, int instrument_options)
Definition: execMain.c:1199
TupleTableSlot * ExecStoreVirtualTuple(TupleTableSlot *slot)
Definition: execTuples.c:1551
void ExecDropSingleTupleTableSlot(TupleTableSlot *slot)
Definition: execTuples.c:1253
TupleTableSlot * ExecStoreAllNullTuple(TupleTableSlot *slot)
Definition: execTuples.c:1575
HeapTuple ExecFetchSlotHeapTuple(TupleTableSlot *slot, bool materialize, bool *shouldFree)
Definition: execTuples.c:1643
TupleTableSlot * MakeSingleTupleTableSlot(TupleDesc tupdesc, const TupleTableSlotOps *tts_ops)
Definition: execTuples.c:1237
EState * CreateExecutorState(void)
Definition: execUtils.c:88
void FreeExecutorState(EState *estate)
Definition: execUtils.c:189
struct ResultRelInfo ResultRelInfo
#define GetPerTupleExprContext(estate)
Definition: executor.h:550
#define ResetExprContext(econtext)
Definition: executor.h:544
#define GetPerTupleMemoryContext(estate)
Definition: executor.h:555
static Datum ExecEvalExpr(ExprState *state, ExprContext *econtext, bool *isNull)
Definition: executor.h:333
#define palloc0_object(type)
Definition: fe_memutils.h:63
#define DirectFunctionCall2(func, arg1, arg2)
Definition: fmgr.h:644
#define DatumGetByteaPP(X)
Definition: fmgr.h:291
#define SizeForFunctionCallInfo(nargs)
Definition: fmgr.h:102
#define LOCAL_FCINFO(name, nargs)
Definition: fmgr.h:110
ForeignDataWrapper * GetForeignDataWrapper(Oid fdwid)
Definition: foreign.c:36
ForeignServer * GetForeignServer(Oid serverid)
Definition: foreign.c:110
Oid GetForeignServerIdByRelId(Oid relid)
Definition: foreign.c:345
FdwRoutine * GetFdwRoutineByServerId(Oid serverid)
Definition: foreign.c:367
Datum transformGenericOptions(Oid catalogId, Datum oldOptions, List *options, Oid fdwvalidator)
Definition: foreigncmds.c:110
char * format_type_with_typemod(Oid type_oid, int32 typemod)
Definition: format_type.c:362
char * format_type_be(Oid type_oid)
Definition: format_type.c:343
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:596
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:503
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:384
bool IsBinaryUpgrade
Definition: globals.c:118
bool allowSystemTableMods
Definition: globals.c:127
Oid MyDatabaseTableSpace
Definition: globals.c:93
Oid MyDatabaseId
Definition: globals.c:91
#define newval
void RelationClearMissing(Relation rel)
Definition: heap.c:1937
void StorePartitionKey(Relation rel, char strategy, int16 partnatts, AttrNumber *partattrs, List *partexprs, Oid *partopclass, Oid *partcollation)
Definition: heap.c:3656
List * heap_truncate_find_FKs(List *relationIds)
Definition: heap.c:3529
void RemoveStatistics(Oid relid, AttrNumber attnum)
Definition: heap.c:3254
List * AddRelationNotNullConstraints(Relation rel, List *constraints, List *old_notnulls)
Definition: heap.c:2799
Oid heap_create_with_catalog(const char *relname, Oid relnamespace, Oid reltablespace, Oid relid, Oid reltypeid, Oid reloftypeid, Oid ownerid, Oid accessmtd, TupleDesc tupdesc, List *cooked_constraints, char relkind, char relpersistence, bool shared_relation, bool mapped_relation, OnCommitAction oncommit, Datum reloptions, bool use_user_acl, bool allow_system_table_mods, bool is_internal, Oid relrewrite, ObjectAddress *typaddress)
Definition: heap.c:1104
void heap_truncate(List *relids)
Definition: heap.c:3349
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:3434
void StorePartitionBound(Relation rel, Relation parent, PartitionBoundSpec *bound)
Definition: heap.c:3812
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:3390
List * AddRelationNewConstraints(Relation rel, List *newColDefaults, List *newConstraints, bool allow_merge, bool is_local, bool is_internal, const char *queryString)
Definition: heap.c:2307
#define CHKATYPE_IS_PARTKEY
Definition: heap.h:25
HeapTuple heap_getnext(TableScanDesc sscan, ScanDirection direction)
Definition: heapam.c:1082
BulkInsertState GetBulkInsertState(void)
Definition: heapam.c:1757
void FreeBulkInsertState(BulkInsertState bistate)
Definition: heapam.c:1774
#define XLOG_HEAP_TRUNCATE
Definition: heapam_xlog.h:35
#define XLH_TRUNCATE_RESTART_SEQS
Definition: heapam_xlog.h:121
#define SizeOfHeapTruncate
Definition: heapam_xlog.h:136
#define XLH_TRUNCATE_CASCADE
Definition: heapam_xlog.h:120
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:3520
bool CompareIndexInfo(const IndexInfo *info1, const IndexInfo *info2, const Oid *collations1, const Oid *collations2, const Oid *opfamilies1, const Oid *opfamilies2, const AttrMap *attmap)
Definition: index.c:2514
bool reindex_relation(const ReindexStmt *stmt, Oid relid, int flags, const ReindexParams *params)
Definition: index.c:3885
void index_check_primary_key(Relation heapRel, const IndexInfo *indexInfo, bool is_alter_table, const IndexStmt *stmt)
Definition: index.c:201
ObjectAddress index_constraint_create(Relation heapRelation, Oid indexRelationId, Oid parentConstraintId, const IndexInfo *indexInfo, const char *constraintName, char constraintType, bits16 constr_flags, bool allow_system_table_mods, bool is_internal)
Definition: index.c:1881
IndexInfo * BuildIndexInfo(Relation index)
Definition: index.c:2407
#define REINDEX_REL_PROCESS_TOAST
Definition: index.h:159
#define INDEX_CONSTR_CREATE_UPDATE_INDEX
Definition: index.h:94
#define INDEX_CONSTR_CREATE_REMOVE_OLD_DEPS
Definition: index.h:95
#define INDEX_CONSTR_CREATE_DEFERRABLE
Definition: index.h:92
#define INDEX_CONSTR_CREATE_MARK_AS_PRIMARY
Definition: index.h:91
#define INDEX_CONSTR_CREATE_INIT_DEFERRED
Definition: index.h:93
void index_close(Relation relation, LOCKMODE lockmode)
Definition: indexam.c:177
Relation index_open(Oid relationId, LOCKMODE lockmode)
Definition: indexam.c:133
ObjectAddress DefineIndex(Oid tableId, IndexStmt *stmt, Oid indexRelationId, Oid parentIndexId, Oid parentConstraintId, int total_parts, bool is_alter_table, bool check_rights, bool check_not_in_use, bool skip_build, bool quiet)
Definition: indexcmds.c:535
void IndexSetParentIndex(Relation partitionIdx, Oid parentOid)
Definition: indexcmds.c:4391
Oid GetDefaultOpClass(Oid type_id, Oid am_id)
Definition: indexcmds.c:2338
bool CheckIndexCompatible(Oid oldId, const char *accessMethodName, const List *attributeList, const List *exclusionOpNames, bool isWithoutOverlaps)
Definition: indexcmds.c:177
void WaitForOlderSnapshots(TransactionId limitXmin, bool progress)
Definition: indexcmds.c:428
Oid ResolveOpClass(const List *opclass, Oid attrType, const char *accessMethodName, Oid accessMethodId)
Definition: indexcmds.c:2253
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:313
void CatalogTupleDelete(Relation heapRel, ItemPointer tid)
Definition: indexing.c:365
long val
Definition: informix.c:664
static struct @150 value
void AcceptInvalidationMessages(void)
Definition: inval.c:806
void CacheInvalidateRelcache(Relation relation)
Definition: inval.c:1360
void CacheInvalidateRelcacheByRelid(Oid relid)
Definition: inval.c:1419
void CacheInvalidateRelcacheByTuple(HeapTuple classTuple)
Definition: inval.c:1396
int b
Definition: isn.c:70
int a
Definition: isn.c:69
int j
Definition: isn.c:74
int i
Definition: isn.c:73
if(TABLE==NULL||TABLE_index==NULL)
Definition: isn.c:77
Assert(fmt[strlen(fmt) - 1] !='\n')
List * list_difference_ptr(const List *list1, const List *list2)
Definition: list.c:1263
List * lappend(List *list, void *datum)
Definition: list.c:339
List * lappend_int(List *list, int datum)
Definition: list.c:357
List * lappend_oid(List *list, Oid datum)
Definition: list.c:375
List * list_copy(const List *oldlist)
Definition: list.c:1573
List * list_delete_nth_cell(List *list, int n)
Definition: list.c:767
void list_free(List *list)
Definition: list.c:1546
bool list_member_oid(const List *list, Oid datum)
Definition: list.c:722
List * list_concat(List *list1, const List *list2)
Definition: list.c:561
List * lcons(void *datum, List *list)
Definition: list.c:495
List * list_append_unique_oid(List *list, Oid datum)
Definition: list.c:1380
void list_free_deep(List *list)
Definition: list.c:1560
bool ConditionalLockRelationOid(Oid relid, LOCKMODE lockmode)
Definition: lmgr.c:151
void UnlockRelationOid(Oid relid, LOCKMODE lockmode)
Definition: lmgr.c:227
void WaitForLockersMultiple(List *locktags, LOCKMODE lockmode, bool progress)
Definition: lmgr.c:907
void LockRelationOid(Oid relid, LOCKMODE lockmode)
Definition: lmgr.c:108
#define SET_LOCKTAG_RELATION(locktag, dboid, reloid)
Definition: lock.h:181
int LOCKMODE
Definition: lockdefs.h:26
#define NoLock
Definition: lockdefs.h:34
#define AccessExclusiveLock
Definition: lockdefs.h:43
#define ShareRowExclusiveLock
Definition: lockdefs.h:41
#define AccessShareLock
Definition: lockdefs.h:36
#define ShareUpdateExclusiveLock
Definition: lockdefs.h:39
#define RowShareLock
Definition: lockdefs.h:37
#define ShareLock
Definition: lockdefs.h:40
#define RowExclusiveLock
Definition: lockdefs.h:38
AttrNumber get_attnum(Oid relid, const char *attname)
Definition: lsyscache.c:858
Oid get_constraint_index(Oid conoid)
Definition: lsyscache.c:1113
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3322
char get_typstorage(Oid typid)
Definition: lsyscache.c:2375
bool get_index_isreplident(Oid index_oid)
Definition: lsyscache.c:3511
char get_rel_relkind(Oid relid)
Definition: lsyscache.c:1981
Oid get_typcollation(Oid typid)
Definition: lsyscache.c:3012
char * get_rel_name(Oid relid)
Definition: lsyscache.c:1906
bool get_index_isclustered(Oid index_oid)
Definition: lsyscache.c:3557
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
bool type_is_collatable(Oid typid)
Definition: lsyscache.c:3037
Oid get_rel_tablespace(Oid relid)
Definition: lsyscache.c:2032
Oid get_typ_typrelid(Oid typid)
Definition: lsyscache.c:2687
Oid getBaseTypeAndTypmod(Oid typid, int32 *typmod)
Definition: lsyscache.c:2494
Oid getBaseType(Oid typid)
Definition: lsyscache.c:2477
Oid get_relname_relid(const char *relname, Oid relnamespace)
Definition: lsyscache.c:1863
char * get_attname(Oid relid, AttrNumber attnum, bool missing_ok)
Definition: lsyscache.c:827
#define TypeIsToastable(typid)
Definition: lsyscache.h:210
List * make_ands_implicit(Expr *clause)
Definition: makefuncs.c:721
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:710
void MemoryContextReset(MemoryContext context)
Definition: mcxt.c:371
char * pstrdup(const char *in)
Definition: mcxt.c:1683
void pfree(void *pointer)
Definition: mcxt.c:1508
void * palloc0(Size size)
Definition: mcxt.c:1334
MemoryContext CurrentMemoryContext
Definition: mcxt.c:131
char * MemoryContextStrdup(MemoryContext context, const char *string)
Definition: mcxt.c:1670
MemoryContext CacheMemoryContext
Definition: mcxt.c:140
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:442
void * palloc(Size size)
Definition: mcxt.c:1304
MemoryContext PortalContext
Definition: mcxt.c:146
#define AllocSetContextCreate
Definition: memutils.h:129
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:153
#define ALLOCSET_SMALL_SIZES
Definition: memutils.h:163
#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:722
void namestrcpy(Name name, const char *str)
Definition: name.c:233
Oid RangeVarGetAndCheckCreationNamespace(RangeVar *relation, LOCKMODE lockmode, Oid *existing_relation_id)
Definition: namespace.c:724
bool isAnyTempNamespace(Oid namespaceId)
Definition: namespace.c:3672
Oid get_collation_oid(List *collname, bool missing_ok)
Definition: namespace.c:3956
void CheckSetNamespace(Oid oldNspOid, Oid nspOid)
Definition: namespace.c:3444
RangeVar * makeRangeVarFromNameList(const List *names)
Definition: namespace.c:3539
Oid LookupNamespaceNoError(const char *nspname)
Definition: namespace.c:3340
Oid RangeVarGetRelidExtended(const RangeVar *relation, LOCKMODE lockmode, uint32 flags, RangeVarGetRelidCallback callback, void *callback_arg)
Definition: namespace.c:426
@ RVR_MISSING_OK
Definition: namespace.h:72
#define RangeVarGetRelid(relation, lockmode, missing_ok)
Definition: namespace.h:80
Oid exprType(const Node *expr)
Definition: nodeFuncs.c:42
Oid exprCollation(const Node *expr)
Definition: nodeFuncs.c:788
Node * strip_implicit_coercions(Node *node)
Definition: nodeFuncs.c:672
#define IsA(nodeptr, _type_)
Definition: nodes.h:158
#define copyObject(obj)
Definition: nodes.h:223
#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:763
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:124
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:111
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:2570
#define ACL_MAINTAIN
Definition: parsenodes.h:90
#define ACL_USAGE
Definition: parsenodes.h:84
#define FKCONSTR_ACTION_SETDEFAULT
Definition: parsenodes.h:2573
PartitionStrategy
Definition: parsenodes.h:867
@ PARTITION_STRATEGY_HASH
Definition: parsenodes.h:870
@ PARTITION_STRATEGY_LIST
Definition: parsenodes.h:868
ConstrType
Definition: parsenodes.h:2550
@ CONSTR_FOREIGN
Definition: parsenodes.h:2561
@ CONSTR_UNIQUE
Definition: parsenodes.h:2559
@ CONSTR_DEFAULT
Definition: parsenodes.h:2554
@ CONSTR_NOTNULL
Definition: parsenodes.h:2553
@ CONSTR_CHECK
Definition: parsenodes.h:2557
@ CONSTR_EXCLUSION
Definition: parsenodes.h:2560
@ CONSTR_PRIMARY
Definition: parsenodes.h:2558
DropBehavior
Definition: parsenodes.h:2181
@ DROP_CASCADE
Definition: parsenodes.h:2183
@ DROP_RESTRICT
Definition: parsenodes.h:2182
ObjectType
Definition: parsenodes.h:2108
@ OBJECT_MATVIEW
Definition: parsenodes.h:2132
@ OBJECT_SCHEMA
Definition: parsenodes.h:2145
@ OBJECT_FOREIGN_TABLE
Definition: parsenodes.h:2127
@ OBJECT_TABLESPACE
Definition: parsenodes.h:2151
@ OBJECT_INDEX
Definition: parsenodes.h:2129
@ OBJECT_SEQUENCE
Definition: parsenodes.h:2146
@ OBJECT_TABLE
Definition: parsenodes.h:2150
@ OBJECT_VIEW
Definition: parsenodes.h:2160
@ OBJECT_TYPE
Definition: parsenodes.h:2158
@ OBJECT_TABCONSTRAINT
Definition: parsenodes.h:2149
@ OBJECT_DOMCONSTRAINT
Definition: parsenodes.h:2122
AlterTableType
Definition: parsenodes.h:2200
@ AT_AddIndexConstraint
Definition: parsenodes.h:2223
@ AT_DropOf
Definition: parsenodes.h:2254
@ AT_SetOptions
Definition: parsenodes.h:2211
@ AT_DropIdentity
Definition: parsenodes.h:2266
@ AT_SetAttNotNull
Definition: parsenodes.h:2207
@ AT_DisableTrigUser
Definition: parsenodes.h:2246
@ AT_DropNotNull
Definition: parsenodes.h:2205
@ AT_AddOf
Definition: parsenodes.h:2253
@ AT_ResetOptions
Definition: parsenodes.h:2212
@ AT_ReplicaIdentity
Definition: parsenodes.h:2255
@ AT_ReplaceRelOptions
Definition: parsenodes.h:2238
@ AT_EnableRowSecurity
Definition: parsenodes.h:2256
@ AT_AddColumnToView
Definition: parsenodes.h:2202
@ AT_ResetRelOptions
Definition: parsenodes.h:2237
@ AT_EnableReplicaTrig
Definition: parsenodes.h:2241
@ AT_DropOids
Definition: parsenodes.h:2233
@ AT_SetIdentity
Definition: parsenodes.h:2265
@ AT_ReAddStatistics
Definition: parsenodes.h:2267
@ AT_SetUnLogged
Definition: parsenodes.h:2232
@ AT_DisableTrig
Definition: parsenodes.h:2242
@ AT_SetCompression
Definition: parsenodes.h:2214
@ AT_DropExpression
Definition: parsenodes.h:2209
@ AT_AddIndex
Definition: parsenodes.h:2216
@ AT_EnableReplicaRule
Definition: parsenodes.h:2249
@ AT_ReAddIndex
Definition: parsenodes.h:2217
@ AT_DropConstraint
Definition: parsenodes.h:2224
@ AT_SetNotNull
Definition: parsenodes.h:2206
@ AT_ClusterOn
Definition: parsenodes.h:2229
@ AT_AddIdentity
Definition: parsenodes.h:2264
@ AT_ForceRowSecurity
Definition: parsenodes.h:2258
@ AT_EnableAlwaysRule
Definition: parsenodes.h:2248
@ AT_SetAccessMethod
Definition: parsenodes.h:2234
@ AT_AlterColumnType
Definition: parsenodes.h:2226
@ AT_DetachPartitionFinalize
Definition: parsenodes.h:2263
@ AT_AddInherit
Definition: parsenodes.h:2251
@ AT_ReAddDomainConstraint
Definition: parsenodes.h:2220
@ AT_EnableTrig
Definition: parsenodes.h:2239
@ AT_DropColumn
Definition: parsenodes.h:2215
@ AT_ReAddComment
Definition: parsenodes.h:2225
@ AT_AlterColumnGenericOptions
Definition: parsenodes.h:2227
@ AT_DisableTrigAll
Definition: parsenodes.h:2244
@ AT_EnableRule
Definition: parsenodes.h:2247
@ AT_NoForceRowSecurity
Definition: parsenodes.h:2259
@ AT_DetachPartition
Definition: parsenodes.h:2262
@ AT_SetStatistics
Definition: parsenodes.h:2210
@ AT_AttachPartition
Definition: parsenodes.h:2261
@ AT_AddConstraint
Definition: parsenodes.h:2218
@ AT_DropInherit
Definition: parsenodes.h:2252
@ AT_EnableAlwaysTrig
Definition: parsenodes.h:2240
@ AT_SetLogged
Definition: parsenodes.h:2231
@ AT_SetStorage
Definition: parsenodes.h:2213
@ AT_DisableRule
Definition: parsenodes.h:2250
@ AT_DisableRowSecurity
Definition: parsenodes.h:2257
@ AT_SetRelOptions
Definition: parsenodes.h:2236
@ AT_ChangeOwner
Definition: parsenodes.h:2228
@ AT_EnableTrigUser
Definition: parsenodes.h:2245
@ AT_SetExpression
Definition: parsenodes.h:2208
@ AT_ReAddConstraint
Definition: parsenodes.h:2219
@ AT_SetTableSpace
Definition: parsenodes.h:2235
@ AT_GenericOptions
Definition: parsenodes.h:2260
@ AT_ColumnDefault
Definition: parsenodes.h:2203
@ AT_CookedColumnDefault
Definition: parsenodes.h:2204
@ AT_AlterConstraint
Definition: parsenodes.h:2221
@ AT_EnableTrigAll
Definition: parsenodes.h:2243
@ AT_DropCluster
Definition: parsenodes.h:2230
@ AT_ValidateConstraint
Definition: parsenodes.h:2222
@ AT_AddColumn
Definition: parsenodes.h:2201
#define ACL_REFERENCES
Definition: parsenodes.h:81
#define FKCONSTR_ACTION_CASCADE
Definition: parsenodes.h:2571
#define ACL_TRUNCATE
Definition: parsenodes.h:80
#define ACL_CREATE
Definition: parsenodes.h:85
#define FKCONSTR_ACTION_SETNULL
Definition: parsenodes.h:2572
#define FKCONSTR_ACTION_NOACTION
Definition: parsenodes.h:2569
@ 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:70
Oid get_default_oid_from_partdesc(PartitionDesc partdesc)
Definition: partdesc.c:459
bool has_partition_attrs(Relation rel, Bitmapset *attnums, bool *used_in_expr)
Definition: partition.c:255
List * map_partition_varattnos(List *expr, int fromrel_varno, Relation to_rel, Relation from_rel)
Definition: partition.c:222
List * get_proposed_default_constraint(List *new_part_constraints)
Definition: partition.c:370
void update_default_partition_oid(Oid parentId, Oid defaultPartId)
Definition: partition.c:340
Oid index_get_partition(Relation partition, Oid indexId)
Definition: partition.c:176
Oid get_partition_parent(Oid relid, bool even_if_detached)
Definition: partition.c:53
Oid GetAttrDefaultOid(Oid relid, AttrNumber attnum)
Definition: pg_attrdef.c:339
Oid StoreAttrDefault(Relation rel, AttrNumber attnum, Node *expr, bool is_internal, bool add_column_mode)
Definition: pg_attrdef.c:46
ObjectAddress GetAttrDefaultColumnAddress(Oid attrdefoid)
Definition: pg_attrdef.c:381
void RemoveAttrDefault(Oid relid, AttrNumber attnum, DropBehavior behavior, bool complain, bool internal)
Definition: pg_attrdef.c:213
NameData attname
Definition: pg_attribute.h:41
int16 attnum
Definition: pg_attribute.h:74
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:209
bool attnotnull
Definition: pg_attribute.h:130
void * arg
int errdetail_relkind_not_supported(char relkind)
Definition: pg_class.c:24
NameData relname
Definition: pg_class.h:38
FormData_pg_class * Form_pg_class
Definition: pg_class.h:153
#define PARTITION_MAX_KEYS
#define INDEX_MAX_KEYS
#define NAMEDATALEN
char * ChooseConstraintName(const char *name1, const char *name2, const char *label, Oid namespaceid, List *others)
HeapTuple findNotNullConstraint(Oid relid, const char *colname)
bool ConstraintNameIsUsed(ConstraintCategory conCat, Oid objId, const char *conname)
Oid CreateConstraintEntry(const char *constraintName, Oid constraintNamespace, char constraintType, bool isDeferrable, bool isDeferred, bool isValidated, Oid parentConstrId, Oid relId, const int16 *constraintKey, int constraintNKeys, int constraintNTotalKeys, Oid domainId, Oid indexRelId, Oid foreignRelId, const int16 *foreignKey, const Oid *pfEqOp, const Oid *ppEqOp, const Oid *ffEqOp, int foreignNKeys, char foreignUpdateType, char foreignDeleteType, const int16 *fkDeleteSetCols, int numFkDeleteSetCols, char foreignMatchType, const Oid *exclOp, Node *conExpr, const char *conBin, bool conIsLocal, int conInhCount, bool conNoInherit, bool conPeriod, bool is_internal)
Definition: pg_constraint.c:49
void RenameConstraintById(Oid conId, const char *newname)
Oid get_relation_idx_constraint_oid(Oid relationId, Oid indexId)
void ConstraintSetParentConstraint(Oid childConstrId, Oid parentConstrId, Oid childTableId)
List * RelationGetNotNullConstraints(Oid relid, bool cooked)
void DeconstructFkConstraintRow(HeapTuple tuple, int *numfks, AttrNumber *conkey, AttrNumber *confkey, Oid *pf_eq_oprs, Oid *pp_eq_oprs, Oid *ff_eq_oprs, int *num_fk_del_set_cols, AttrNumber *fk_del_set_cols)
void AdjustNotNullInheritance(Oid relid, Bitmapset *columns, int count)
HeapTuple findNotNullConstraintAttnum(Oid relid, AttrNumber attnum)
void AlterConstraintNamespaces(Oid ownerId, Oid oldNspId, Oid newNspId, bool isType, ObjectAddresses *objsMoved)
Oid get_relation_constraint_oid(Oid relid, const char *conname, bool missing_ok)
AttrNumber extractNotNullColumn(HeapTuple constrTup)
Oid get_domain_constraint_oid(Oid typid, const char *conname, bool missing_ok)
FormData_pg_constraint * Form_pg_constraint
@ CONSTRAINT_RELATION
void recordDependencyOn(const ObjectAddress *depender, const ObjectAddress *referenced, DependencyType behavior)
Definition: pg_depend.c:44
long changeDependencyFor(Oid classId, Oid objectId, Oid refClassId, Oid oldRefObjectId, Oid newRefObjectId)
Definition: pg_depend.c:456
long deleteDependencyRecordsForClass(Oid classId, Oid objectId, Oid refclassId, char deptype)
Definition: pg_depend.c:350
long deleteDependencyRecordsFor(Oid classId, Oid objectId, bool skipExtensionDeps)
Definition: pg_depend.c:300
Oid get_index_constraint(Oid indexId)
Definition: pg_depend.c:968
Oid getIdentitySequence(Oid relid, AttrNumber attnum, bool missing_ok)
Definition: pg_depend.c:944
List * getOwnedSequences(Oid relid)
Definition: pg_depend.c:935
bool sequenceIsOwned(Oid seqId, char deptype, Oid *tableId, int32 *colId)
Definition: pg_depend.c:827
FormData_pg_depend * Form_pg_depend
Definition: pg_depend.h:72
FormData_pg_foreign_table * Form_pg_foreign_table
FormData_pg_index * Form_pg_index
Definition: pg_index.h:70
bool DeleteInheritsTuple(Oid inhrelid, Oid inhparent, bool expect_detach_pending, const char *childname)
Definition: pg_inherits.c:552
List * find_all_inheritors(Oid parentrelId, LOCKMODE lockmode, List **numparents)
Definition: pg_inherits.c:255
void StoreSingleInheritance(Oid relationId, Oid parentOid, int32 seqNumber)
Definition: pg_inherits.c:508
List * find_inheritance_children(Oid parentrelId, LOCKMODE lockmode)
Definition: pg_inherits.c:58
bool has_superclass(Oid relationId)
Definition: pg_inherits.c:377
bool PartitionHasPendingDetach(Oid partoid)
Definition: pg_inherits.c:620
FormData_pg_inherits * Form_pg_inherits
Definition: pg_inherits.h:45
#define lfirst(lc)
Definition: pg_list.h:172
#define lfirst_node(type, lc)
Definition: pg_list.h:176
static int list_length(const List *l)
Definition: pg_list.h:152
#define NIL
Definition: pg_list.h:68
#define forboth(cell1, list1, cell2, list2)
Definition: pg_list.h:518
#define foreach_current_index(var_or_cell)
Definition: pg_list.h:403
#define lfirst_int(lc)
Definition: pg_list.h:173
#define foreach_delete_current(lst, var_or_cell)
Definition: pg_list.h:391
#define list_make1_oid(x1)
Definition: pg_list.h:242
#define list_make1(x1)
Definition: pg_list.h:212
#define linitial_int(l)
Definition: pg_list.h:179
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 list_nth_node(type, list, n)
Definition: pg_list.h:327
static ListCell * lnext(const List *l, const ListCell *c)
Definition: pg_list.h:343
#define list_make1_int(x1)
Definition: pg_list.h:227
#define linitial_oid(l)
Definition: pg_list.h:180
#define lfirst_oid(lc)
Definition: pg_list.h:174
#define list_make2(x1, x2)
Definition: pg_list.h:214
FormData_pg_opclass * Form_pg_opclass
Definition: pg_opclass.h:83
List * GetRelationPublications(Oid relid)
void changeDependencyOnOwner(Oid classId, Oid objectId, Oid newOwnerId)
Definition: pg_shdepend.c:308
void changeDependencyOnTablespace(Oid classId, Oid objectId, Oid newTablespaceId)
Definition: pg_shdepend.c:377
static char * buf
Definition: pg_test_fsync.c:73
FormData_pg_trigger * Form_pg_trigger
Definition: pg_trigger.h:80
void RenameTypeInternal(Oid typeOid, const char *newTypeName, Oid typeNamespace)
Definition: pg_type.c:765
FormData_pg_type * Form_pg_type
Definition: pg_type.h:261
#define ERRCODE_UNDEFINED_TABLE
Definition: pgbench.c:78
void pgstat_count_truncate(Relation rel)
Expr * expression_planner(Expr *expr)
Definition: planner.c:6400
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:3531
static Datum PointerGetDatum(const void *X)
Definition: postgres.h:322
uintptr_t Datum
Definition: postgres.h:64
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:252
static Pointer DatumGetPointer(Datum X)
Definition: postgres.h:312
static Datum CStringGetDatum(const char *X)
Definition: postgres.h:350
static Datum Int32GetDatum(int32 X)
Definition: postgres.h:212
static Datum CharGetDatum(char X)
Definition: postgres.h:122
#define InvalidOid
Definition: postgres_ext.h:36
unsigned int Oid
Definition: postgres_ext.h:31
void CheckTableForSerializableConflictIn(Relation relation)
Definition: predicate.c:4399
void TransferPredicateLocksToHeapRelation(Relation relation)
Definition: predicate.c:3103
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:230
#define PRS2_NEW_VARNO
Definition: primnodes.h:231
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:692
@ IS_NOT_NULL
Definition: primnodes.h:1715
@ COERCION_ASSIGNMENT
Definition: primnodes.h:671
@ COERCION_IMPLICIT
Definition: primnodes.h:670
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:4749
int errtableconstraint(Relation rel, const char *conname)
Definition: relcache.c:5988
int errtablecol(Relation rel, int attnum)
Definition: relcache.c:5951
List * RelationGetIndexPredicate(Relation relation)
Definition: relcache.c:5127
Bitmapset * RelationGetIndexAttrBitmap(Relation relation, IndexAttrBitmapKind attrKind)
Definition: relcache.c:5220
List * RelationGetFKeyList(Relation relation)
Definition: relcache.c:4640
void RelationSetNewRelfilenumber(Relation relation, char persistence)
Definition: relcache.c:3719
void RelationAssumeNewRelfilelocator(Relation relation)
Definition: relcache.c:3918
int errtable(Relation rel)
Definition: relcache.c:5934
List * RelationGetIndexExpressions(Relation relation)
Definition: relcache.c:5014
struct RelationData * Relation
Definition: relcache.h:27
@ INDEX_ATTR_BITMAP_KEY
Definition: relcache.h:61
@ INDEX_ATTR_BITMAP_PRIMARY_KEY
Definition: relcache.h:62
@ INDEX_ATTR_BITMAP_IDENTITY_KEY
Definition: relcache.h:63
bytea * index_reloptions(amoptions_function amoptions, Datum reloptions, bool validate)
Definition: reloptions.c:2054
List * untransformRelOptions(Datum options)
Definition: reloptions.c:1331
Datum transformRelOptions(Datum oldOptions, List *defList, const char *namspace, char *validnsps[], bool acceptOidsOff, bool isReset)
Definition: reloptions.c:1156
bytea * heap_reloptions(char relkind, Datum reloptions, bool validate)
Definition: reloptions.c:2019
bytea * view_reloptions(Datum reloptions, bool validate)
Definition: reloptions.c:1998
bytea * partitioned_table_reloptions(Datum reloptions, bool validate)
Definition: reloptions.c:1984
LOCKMODE AlterTableGetRelOptionsLockLevel(List *defList)
Definition: reloptions.c:2108
bytea * attribute_reloptions(Datum reloptions, bool validate)
Definition: reloptions.c:2069
#define HEAP_RELOPT_NAMESPACES
Definition: reloptions.h:61
Oid RelFileNumber
Definition: relpath.h:25
ForkNumber
Definition: relpath.h:48
@ MAIN_FORKNUM
Definition: relpath.h:50
@ INIT_FORKNUM
Definition: relpath.h:53
#define MAX_FORKNUM
Definition: relpath.h:62
#define RelFileNumberIsValid(relnumber)
Definition: relpath.h:27
void EnableDisableRule(Relation rel, const char *rulename, char fires_when)
#define RULE_FIRES_ON_ORIGIN
Definition: rewriteDefine.h:21
#define RULE_FIRES_ON_REPLICA
Definition: rewriteDefine.h:23
#define RULE_FIRES_ALWAYS
Definition: rewriteDefine.h:22
#define RULE_DISABLED
Definition: rewriteDefine.h:24
const char * view_query_is_auto_updatable(Query *viewquery, bool check_cols)
Query * get_view_query(Relation view)
Node * build_column_default(Relation rel, int attrno)
Node * map_variable_attnos(Node *node, int target_varno, int sublevels_up, const AttrMap *attno_map, Oid to_rowtype, bool *found_whole_row)
Datum RI_FKey_check_ins(PG_FUNCTION_ARGS)
Definition: ri_triggers.c:424
bool RI_Initial_Check(Trigger *trigger, Relation fk_rel, Relation pk_rel)
Definition: ri_triggers.c:1365
void RI_PartitionRemove_Check(Trigger *trigger, Relation fk_rel, Relation pk_rel)
Definition: ri_triggers.c:1660
int RI_FKey_trigger_type(Oid tgfoid)
Definition: ri_triggers.c:3007
char * pg_get_constraintdef_command(Oid constraintId)
Definition: ruleutils.c:2153
const char * quote_identifier(const char *ident)
Definition: ruleutils.c:11987
char * pg_get_statisticsobjdef_string(Oid statextid)
Definition: ruleutils.c:1596
Datum pg_get_expr(PG_FUNCTION_ARGS)
Definition: ruleutils.c:2629
char * pg_get_indexdef_string(Oid indexrelid)
Definition: ruleutils.c:1194
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
@ ForwardScanDirection
Definition: sdir.h:28
void smgrcreate(SMgrRelation reln, ForkNumber forknum, bool isRedo)
Definition: smgr.c:411
void smgrclose(SMgrRelation reln)
Definition: smgr.c:320
bool smgrexists(SMgrRelation reln, ForkNumber forknum)
Definition: smgr.c:398
TransactionId RecentXmin
Definition: snapmgr.c:99
Snapshot GetTransactionSnapshot(void)
Definition: snapmgr.c:216
Snapshot GetLatestSnapshot(void)
Definition: snapmgr.c:291
void UnregisterSnapshot(Snapshot snapshot)
Definition: snapmgr.c:836
void PushActiveSnapshot(Snapshot snapshot)
Definition: snapmgr.c:648
Snapshot RegisterSnapshot(Snapshot snapshot)
Definition: snapmgr.c:794
void PopActiveSnapshot(void)
Definition: snapmgr.c:743
Snapshot GetActiveSnapshot(void)
Definition: snapmgr.c:770
void relation_close(Relation relation, LOCKMODE lockmode)
Definition: relation.c:205
Relation try_relation_open(Oid relationId, LOCKMODE lockmode)
Definition: relation.c:88
Relation relation_open(Oid relationId, LOCKMODE lockmode)
Definition: relation.c:47
ObjectAddress CreateStatistics(CreateStatsStmt *stmt)
Definition: statscmds.c:62
Oid StatisticsGetRelation(Oid statId, bool missing_ok)
Definition: statscmds.c:898
void RelationPreserveStorage(RelFileLocator rlocator, bool atCommit)
Definition: storage.c:251
void RelationCopyStorage(SMgrRelation src, SMgrRelation dst, ForkNumber forkNum, char relpersistence)
Definition: storage.c:452
SMgrRelation RelationCreateStorage(RelFileLocator rlocator, char relpersistence, bool register_delete)
Definition: storage.c:121
void log_smgrcreate(const RelFileLocator *rlocator, ForkNumber forkNum)
Definition: storage.c:186
void RelationDropStorage(Relation rel)
Definition: storage.c:206
#define BTEqualStrategyNumber
Definition: stratnum.h:31
#define ERRCODE_DUPLICATE_OBJECT
Definition: streamutil.c:32
RoleSpec * newowner
Definition: parsenodes.h:2285
DropBehavior behavior
Definition: parsenodes.h:2288
AlterTableType subtype
Definition: parsenodes.h:2280
RangeVar * relation
Definition: parsenodes.h:2193
ObjectType objtype
Definition: parsenodes.h:2195
const char * queryString
Definition: utility.h:33
List * constraints
Definition: tablecmds.c:181
bool verify_new_notnull
Definition: tablecmds.c:184
List * changedConstraintDefs
Definition: tablecmds.c:195
Expr * partition_constraint
Definition: tablecmds.c:190
char newrelpersistence
Definition: tablecmds.c:189
List * changedStatisticsDefs
Definition: tablecmds.c:201
List * afterStmts
Definition: tablecmds.c:183
char * clusterOnIndex
Definition: tablecmds.c:199
char * replicaIdentityIndex
Definition: tablecmds.c:198
List * changedStatisticsOids
Definition: tablecmds.c:200
List * changedIndexDefs
Definition: tablecmds.c:197
List * changedIndexOids
Definition: tablecmds.c:196
List * changedConstraintOids
Definition: tablecmds.c:194
bool validate_default
Definition: tablecmds.c:192
List * subcmds[AT_NUM_PASSES]
Definition: tablecmds.c:179
TupleDesc oldDesc
Definition: tablecmds.c:167
Relation rel
Definition: tablecmds.c:176
Definition: attmap.h:35
AttrNumber * attnums
Definition: attmap.h:36
bool is_not_null
Definition: parsenodes.h:727
char identity
Definition: parsenodes.h:733
RangeVar * identitySequence
Definition: parsenodes.h:734
List * constraints
Definition: parsenodes.h:739
Node * cooked_default
Definition: parsenodes.h:732
char * storage_name
Definition: parsenodes.h:730
int inhcount
Definition: parsenodes.h:725
char * colname
Definition: parsenodes.h:722
TypeName * typeName
Definition: parsenodes.h:723
char generated
Definition: parsenodes.h:736
bool is_from_type
Definition: parsenodes.h:728
Node * raw_default
Definition: parsenodes.h:731
char storage
Definition: parsenodes.h:729
bool is_local
Definition: parsenodes.h:726
char * compression
Definition: parsenodes.h:724
char * comment
Definition: parsenodes.h:3110
ObjectType objtype
Definition: parsenodes.h:3108
Node * object
Definition: parsenodes.h:3109
char * ccname
Definition: tupdesc.h:30
bool ccvalid
Definition: tupdesc.h:32
char * ccbin
Definition: tupdesc.h:31
bool initdeferred
Definition: parsenodes.h:2586
bool reset_default_tblspc
Definition: parsenodes.h:2608
List * keys
Definition: parsenodes.h:2598
List * pk_attrs
Definition: parsenodes.h:2616
List * fk_del_set_cols
Definition: parsenodes.h:2620
ConstrType contype
Definition: parsenodes.h:2583
Oid old_pktable_oid
Definition: parsenodes.h:2622
bool is_no_inherit
Definition: parsenodes.h:2589
char fk_upd_action
Definition: parsenodes.h:2618
List * old_conpfeqop
Definition: parsenodes.h:2621
char fk_matchtype
Definition: parsenodes.h:2617
char * cooked_expr
Definition: parsenodes.h:2592
bool initially_valid
Definition: parsenodes.h:2588
bool skip_validation
Definition: parsenodes.h:2587
bool deferrable
Definition: parsenodes.h:2585
Node * raw_expr
Definition: parsenodes.h:2590
char * conname
Definition: parsenodes.h:2584
RangeVar * pktable
Definition: parsenodes.h:2614
char fk_del_action
Definition: parsenodes.h:2619
List * fk_attrs
Definition: parsenodes.h:2615
Oid conoid
Definition: heap.h:39
char * name
Definition: heap.h:40
AttrNumber attnum
Definition: heap.h:41
bool skip_validation
Definition: heap.h:43
bool is_no_inherit
Definition: heap.h:46
int inhcount
Definition: heap.h:45
bool is_local
Definition: heap.h:44
ConstrType contype
Definition: heap.h:37
Node * expr
Definition: heap.h:42
Node * whenClause
Definition: parsenodes.h:2869
List * transitionRels
Definition: parsenodes.h:2871
RangeVar * constrrel
Definition: parsenodes.h:2875
RangeVar * relation
Definition: parsenodes.h:2860
char * defname
Definition: parsenodes.h:811
bool missing_ok
Definition: parsenodes.h:3085
List * objects
Definition: parsenodes.h:3082
ObjectType removeType
Definition: parsenodes.h:3083
bool concurrent
Definition: parsenodes.h:3086
DropBehavior behavior
Definition: parsenodes.h:3084
List * es_opened_result_relations
Definition: execnodes.h:643
TupleTableSlot * ecxt_scantuple
Definition: execnodes.h:255
ExecForeignTruncate_function ExecForeignTruncate
Definition: fdwapi.h:263
Oid funcid
Definition: primnodes.h:706
List * args
Definition: primnodes.h:724
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:274
bool amcanunique
Definition: amapi.h:229
Node * expr
Definition: parsenodes.h:780
char * name
Definition: parsenodes.h:779
bool ii_Unique
Definition: execnodes.h:197
int ii_NumIndexKeyAttrs
Definition: execnodes.h:185
AttrNumber ii_IndexAttrNumbers[INDEX_MAX_KEYS]
Definition: execnodes.h:186
bool reset_default_tblspc
Definition: parsenodes.h:3230
List * indexParams
Definition: parsenodes.h:3208
char * idxname
Definition: parsenodes.h:3204
char * idxcomment
Definition: parsenodes.h:3214
bool primary
Definition: parsenodes.h:3222
Definition: lock.h:165
Definition: pg_list.h:54
AttrNumber attnum
Definition: tablecmds.c:227
bool is_generated
Definition: tablecmds.c:230
ExprState * exprstate
Definition: tablecmds.c:229
char * name
Definition: tablecmds.c:208
ConstrType contype
Definition: tablecmds.c:209
Node * qual
Definition: tablecmds.c:213
ExprState * qualstate
Definition: tablecmds.c:214
Definition: nodes.h:129
NullTestType nulltesttype
Definition: primnodes.h:1722
int location
Definition: primnodes.h:1725
Expr * arg
Definition: primnodes.h:1721
SubTransactionId creating_subid
Definition: tablecmds.c:121
SubTransactionId deleting_subid
Definition: tablecmds.c:122
OnCommitAction oncommit
Definition: tablecmds.c:112
const char * p_sourcetext
Definition: parse_node.h:193
PartitionBoundSpec * bound
Definition: parsenodes.h:943
RangeVar * name
Definition: parsenodes.h:942
List * collation
Definition: parsenodes.h:861
List * opclass
Definition: parsenodes.h:862
List * partParams
Definition: parsenodes.h:882
PartitionStrategy strategy
Definition: parsenodes.h:881
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:1873
RelFileNumber relNumber
struct IndexAmRoutine * rd_indam
Definition: rel.h:206
SubTransactionId rd_firstRelfilelocatorSubid
Definition: rel.h:106
int rd_refcnt
Definition: rel.h:59
TriggerDesc * trigdesc
Definition: rel.h:117
bool rd_islocaltemp
Definition: rel.h:61
TupleDesc rd_att
Definition: rel.h:112
Form_pg_index rd_index
Definition: rel.h:192
bool rd_isnailed
Definition: rel.h:62
Oid rd_id
Definition: rel.h:113
SubTransactionId rd_newRelfilelocatorSubid
Definition: rel.h:104
SubTransactionId rd_createSubid
Definition: rel.h:103
RelFileLocator rd_locator
Definition: rel.h:57
Oid * rd_opfamily
Definition: rel.h:207
Oid * rd_indcollation
Definition: rel.h:217
Form_pg_class rd_rel
Definition: rel.h:111
Relation ri_RelationDesc
Definition: execnodes.h:456
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
AttrDefault * defval
Definition: tupdesc.h:39
bool has_generated_stored
Definition: tupdesc.h:45
struct AttrMissing * missing
Definition: tupdesc.h:41
ConstrCheck * check
Definition: tupdesc.h:40
uint16 num_defval
Definition: tupdesc.h:42
uint16 num_check
Definition: tupdesc.h:43
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:269
List * arrayBounds
Definition: parsenodes.h:273
Definition: primnodes.h:234
const char * skipping_msg
Definition: tablecmds.c:241
int nonexistent_code
Definition: tablecmds.c:239
const char * nonexistent_msg
Definition: tablecmds.c:240
const char * drophint_msg
Definition: tablecmds.c:243
const char * nota_msg
Definition: tablecmds.c:242
Definition: type.h:95
Definition: c.h:713
Oid values[FLEXIBLE_ARRAY_MEMBER]
Definition: c.h:720
Definition: regguts.h:323
bool superuser(void)
Definition: superuser.c:46
#define FirstLowInvalidHeapAttributeNumber
Definition: sysattr.h:27
HeapTuple SearchSysCacheCopyAttName(Oid relid, const char *attname)
Definition: syscache.c:382
HeapTuple SearchSysCacheCopyAttNum(Oid relid, int16 attnum)
Definition: syscache.c:445
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:266
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:218
HeapTuple SearchSysCacheAttNum(Oid relid, int16 attnum)
Definition: syscache.c:422
Datum SysCacheGetAttr(int cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition: syscache.c:479
bool SearchSysCacheExistsAttName(Oid relid, const char *attname)
Definition: syscache.c:401
HeapTuple SearchSysCache2(int cacheId, Datum key1, Datum key2)
Definition: syscache.c:229
HeapTuple SearchSysCacheAttName(Oid relid, const char *attname)
Definition: syscache.c:359
Datum SysCacheGetAttrNotNull(int cacheId, HeapTuple tup, AttrNumber attributeNumber)
Definition: syscache.c:510
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:86
#define SearchSysCacheExists2(cacheId, key1, key2)
Definition: syscache.h:97
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:126
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:40
Relation table_openrv(const RangeVar *relation, LOCKMODE lockmode)
Definition: table.c:83
const TupleTableSlotOps * table_slot_callbacks(Relation relation)
Definition: tableam.c:58
TableScanDesc table_beginscan_catalog(Relation relation, int nkeys, struct ScanKeyData *key)
Definition: tableam.c:112
char * default_table_access_method
Definition: tableam.c:48
TupleTableSlot * table_slot_create(Relation relation, List **reglist)
Definition: tableam.c:91
static TableScanDesc table_beginscan(Relation rel, Snapshot snapshot, int nkeys, struct ScanKeyData *key)
Definition: tableam.h:901
static void table_endscan(TableScanDesc scan)
Definition: tableam.h:1009
#define TABLE_INSERT_SKIP_FSM
Definition: tableam.h:252
static void table_finish_bulk_insert(Relation rel, int options)
Definition: tableam.h:1585
static void table_tuple_insert(Relation rel, TupleTableSlot *slot, CommandId cid, int options, struct BulkInsertStateData *bistate)
Definition: tableam.h:1392
static void table_relation_copy_data(Relation rel, const RelFileLocator *newrlocator)
Definition: tableam.h:1641
static bool table_scan_getnextslot(TableScanDesc sscan, ScanDirection direction, TupleTableSlot *slot)
Definition: tableam.h:1045
static AttrNumber renameatt_internal(Oid myrelid, const char *oldattname, const char *newattname, bool recurse, bool recursing, int expected_parents, DropBehavior behavior)
Definition: tablecmds.c:3763
void ResetRelRewrite(Oid myrelid)
Definition: tablecmds.c:4279
static void MergeAttributesIntoExisting(Relation child_rel, Relation parent_rel, bool ispartition)
Definition: tablecmds.c:16112
static void MarkInheritDetached(Relation child_rel, Relation parent_rel)
Definition: tablecmds.c:16464
static ObjectAddress ATExecAlterColumnGenericOptions(Relation rel, const char *colName, List *options, LOCKMODE lockmode)
Definition: tablecmds.c:14672
static void ATRewriteCatalogs(List **wqueue, LOCKMODE lockmode, AlterTableUtilityContext *context)
Definition: tablecmds.c:5178
static ObjectAddress ATExecAddInherit(Relation child_rel, RangeVar *parent, LOCKMODE lockmode)
Definition: tablecmds.c:15870
ObjectAddress RenameRelation(RenameStmt *stmt)
Definition: tablecmds.c:4125
static AlteredTableInfo * ATGetQueueEntry(List **wqueue, Relation rel)
Definition: tablecmds.c:6379
static void ATExecDropOf(Relation rel, LOCKMODE lockmode)
Definition: tablecmds.c:16983
static ColumnDef * MergeInheritedAttribute(List *inh_columns, int exist_attno, const ColumnDef *newdef)
Definition: tablecmds.c:3354
#define ATT_TABLE
Definition: tablecmds.c:319
static bool ConstraintImpliedByRelConstraint(Relation scanrel, List *testConstraint, List *provenConstraint)
Definition: tablecmds.c:18707
static const char * storage_name(char c)
Definition: tablecmds.c:2393
static ObjectAddress ATExecDropExpression(Relation rel, const char *colName, bool missing_ok, LOCKMODE lockmode)
Definition: tablecmds.c:8621
void AtEOSubXact_on_commit_actions(bool isCommit, SubTransactionId mySubid, SubTransactionId parentSubid)
Definition: tablecmds.c:18070
static void add_column_datatype_dependency(Oid relid, int32 attnum, Oid typid)
Definition: tablecmds.c:7472
static ObjectAddress ATExecColumnDefault(Relation rel, const char *colName, Node *newDefault, LOCKMODE lockmode)
Definition: tablecmds.c:8010
static void ATPostAlterTypeParse(Oid oldId, Oid oldRelId, Oid refRelId, char *cmd, List **wqueue, LOCKMODE lockmode, bool rewrite)
Definition: tablecmds.c:14343
static void ATExecSetTableSpace(Oid tableOid, Oid newTableSpace, LOCKMODE lockmode)
Definition: tablecmds.c:15462
static void drop_parent_dependency(Oid relid, Oid refclassid, Oid refobjid, DependencyType deptype)
Definition: tablecmds.c:16789
static void RemoveInheritance(Relation child_rel, Relation parent_rel, bool expect_detached)
Definition: tablecmds.c:16547
#define AT_NUM_PASSES
Definition: tablecmds.c:160
void PreCommit_on_commit_actions(void)
Definition: tablecmds.c:17931
static int transformFkeyGetPrimaryKey(Relation pkrel, Oid *indexOid, List **attnamelist, int16 *attnums, Oid *atttypids, Oid *opclasses)
Definition: tablecmds.c:12039
static ObjectAddress ATExecDropIdentity(Relation rel, const char *colName, bool missing_ok, LOCKMODE lockmode, bool recurse, bool recursing)
Definition: tablecmds.c:8348
static char GetAttributeCompression(Oid atttypid, const char *compression)
Definition: tablecmds.c:20533
static int findAttrByName(const char *attributeName, const List *columns)
Definition: tablecmds.c:3544
static void RememberIndexForRebuilding(Oid indoid, AlteredTableInfo *tab)
Definition: tablecmds.c:14094
static bool ATColumnChangeRequiresRewrite(Node *expr, AttrNumber varattno)
Definition: tablecmds.c:13435
static char * ChooseForeignKeyConstraintNameAddition(List *colnames)
Definition: tablecmds.c:9602
static ObjectAddress ATExecValidateConstraint(List **wqueue, Relation rel, char *constrName, bool recurse, bool recursing, LOCKMODE lockmode)
Definition: tablecmds.c:11798
void AlterTable(AlterTableStmt *stmt, LOCKMODE lockmode, AlterTableUtilityContext *context)
Definition: tablecmds.c:4419
static void RememberStatisticsForRebuilding(Oid stxoid, AlteredTableInfo *tab)
Definition: tablecmds.c:14145
static CoercionPathType findFkeyCast(Oid targetTypeId, Oid sourceTypeId, Oid *funcid)
Definition: tablecmds.c:12277
static void add_column_collation_dependency(Oid relid, int32 attnum, Oid collid)
Definition: tablecmds.c:7490
static ObjectAddress ATExecDropNotNull(Relation rel, const char *colName, bool recurse, LOCKMODE lockmode)
Definition: tablecmds.c:7515
#define ATT_SEQUENCE
Definition: tablecmds.c:326
void RemoveRelations(DropStmt *drop)
Definition: tablecmds.c:1470
static void ATPrepSetTableSpace(AlteredTableInfo *tab, Relation rel, const char *tablespacename, LOCKMODE lockmode)
Definition: tablecmds.c:15229
static void ATTypedTableRecursion(List **wqueue, Relation rel, AlterTableCmd *cmd, LOCKMODE lockmode, AlterTableUtilityContext *context)
Definition: tablecmds.c:6707
static void RememberReplicaIdentityForRebuilding(Oid indoid, AlteredTableInfo *tab)
Definition: tablecmds.c:14023
static ObjectAddress ATExecSetNotNull(List **wqueue, Relation rel, char *constrname, char *colName, bool recurse, bool recursing, List **readyRels, LOCKMODE lockmode)
Definition: tablecmds.c:7740
static List * GetParentedForeignKeyRefs(Relation partition)
Definition: tablecmds.c:20431
void AlterRelationNamespaceInternal(Relation classRel, Oid relOid, Oid oldNspOid, Oid newNspOid, bool hasDependEntry, ObjectAddresses *objsMoved)
Definition: tablecmds.c:17672
static ObjectAddress ATExecAddConstraint(List **wqueue, AlteredTableInfo *tab, Relation rel, Constraint *newConstraint, bool recurse, bool is_readd, LOCKMODE lockmode)
Definition: tablecmds.c:9528
ObjectAddress renameatt(RenameStmt *stmt)
Definition: tablecmds.c:3928
void ATExecChangeOwner(Oid relationOid, Oid newOwnerId, bool recursing, LOCKMODE lockmode)
Definition: tablecmds.c:14789
static void RangeVarCallbackForAlterRelation(const RangeVar *rv, Oid relid, Oid oldrelid, void *arg)
Definition: tablecmds.c:18197
static ObjectAddress ATExecSetAttNotNull(List **wqueue, Relation rel, const char *colName, LOCKMODE lockmode)
Definition: tablecmds.c:7944
static void DropErrorMsgWrongType(const char *relname, char wrongkind, char rightkind)
Definition: tablecmds.c:1443
LOCKMODE AlterTableGetLockLevel(List *cmds)
Definition: tablecmds.c:4493
static int transformColumnNameList(Oid relId, List *colList, int16 *attnums, Oid *atttypids)
Definition: tablecmds.c:11987
static void verifyPartitionIndexNotNull(IndexInfo *iinfo, Relation partIdx)
Definition: tablecmds.c:20409
static void validateForeignKeyConstraint(char *conname, Relation rel, Relation pkrel, Oid pkindOid, Oid constraintOid)
Definition: tablecmds.c:12335
struct ForeignTruncateInfo ForeignTruncateInfo
static ObjectAddress ATExecDetachPartition(List **wqueue, AlteredTableInfo *tab, Relation rel, RangeVar *name, bool concurrent)
Definition: tablecmds.c:19509
static bool ATExecAlterConstrRecurse(Constraint *cmdcon, Relation conrel, Relation tgrel, Relation rel, HeapTuple contuple, List **otherrelids, LOCKMODE lockmode)
Definition: tablecmds.c:11647
static void AlterSeqNamespaces(Relation classRel, Relation rel, Oid oldNspOid, Oid newNspOid, ObjectAddresses *objsMoved, LOCKMODE lockmode)
Definition: tablecmds.c:17787
static void RangeVarCallbackForRenameAttribute(const RangeVar *rv, Oid relid, Oid oldrelid, void *arg)
Definition: tablecmds.c:3908
TupleDesc BuildDescForRelation(const List *columns)
Definition: tablecmds.c:1293
static void ATExecForceNoForceRowSecurity(Relation rel, bool force_rls)
Definition: tablecmds.c:17253
void AtEOXact_on_commit_actions(bool isCommit)
Definition: tablecmds.c:18038
static void checkFkeyPermissions(Relation rel, int16 *attnums, int natts)
Definition: tablecmds.c:12306
struct OnCommitItem OnCommitItem
void CheckTableNotInUse(Relation rel, const char *stmt)
Definition: tablecmds.c:4332
static void ATExecEnableDisableTrigger(Relation rel, const char *trigname, char fires_when, bool skip_system, bool recurse, LOCKMODE lockmode)
Definition: tablecmds.c:15813
static void createForeignKeyActionTriggers(Relation rel, Oid refRelOid, Constraint *fkconstraint, Oid constraintOid, Oid indexOid, Oid parentDelTrigger, Oid parentUpdTrigger, Oid *deleteTrigOid, Oid *updateTrigOid)
Definition: tablecmds.c:12495
static void renameatt_check(Oid myrelid, Form_pg_class classform, bool recursing)
Definition: tablecmds.c:3714
static void RangeVarCallbackForAttachIndex(const RangeVar *rv, Oid relOid, Oid oldRelOid, void *arg)
Definition: tablecmds.c:20068
static void ATCheckPartitionsNotInUse(Relation rel, LOCKMODE lockmode)
Definition: tablecmds.c:6677
static void truncate_check_activity(Relation rel)
Definition: tablecmds.c:2370
static void validatePartitionedIndex(Relation partedIdx, Relation partedTbl)
Definition: tablecmds.c:20307
static ObjectAddress ATAddForeignKeyConstraint(List **wqueue, AlteredTableInfo *tab, Relation rel, Constraint *fkconstraint, bool recurse, bool recursing, LOCKMODE lockmode)
Definition: tablecmds.c:9802
static void TryReuseIndex(Oid oldId, IndexStmt *stmt)
Definition: tablecmds.c:14603
static void GetForeignKeyCheckTriggers(Relation trigrel, Oid conoid, Oid confrelid, Oid conrelid, Oid *insertTriggerOid, Oid *updateTriggerOid)
Definition: tablecmds.c:11444
static void RememberClusterOnForRebuilding(Oid indoid, AlteredTableInfo *tab)
Definition: tablecmds.c:14038
static ObjectAddress ATExecSetOptions(Relation rel, const char *colName, Node *options, bool isReset, LOCKMODE lockmode)
Definition: tablecmds.c:8847
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:9080
static void CloneFkReferencing(List **wqueue, Relation parentRel, Relation partRel)
Definition: tablecmds.c:10971
static void SetIndexStorageProperties(Relation rel, Relation attrelation, AttrNumber attnum, bool setstorage, char newstorage, bool setcompression, char newcompression, LOCKMODE lockmode)
Definition: tablecmds.c:8926
static void ATController(AlterTableStmt *parsetree, Relation rel, List *cmds, bool recurse, LOCKMODE lockmode, AlterTableUtilityContext *context)
Definition: tablecmds.c:4756
bool CheckRelationTableSpaceMove(Relation rel, Oid newTableSpaceId)
Definition: tablecmds.c:3615
static void ATExecSetRowSecurity(Relation rel, bool rls)
Definition: tablecmds.c:17223
static Oid transformFkeyCheckAttrs(Relation pkrel, int numattrs, int16 *attnums, Oid *opclasses)
Definition: tablecmds.c:12138
void find_composite_type_dependencies(Oid typeOid, Relation origRelation, const char *origTypeName)
Definition: tablecmds.c:6752
static void truncate_check_perms(Oid relid, Form_pg_class reltuple)
Definition: tablecmds.c:2352
static void truncate_check_rel(Oid relid, Form_pg_class reltuple)
Definition: tablecmds.c:2304
#define ATT_INDEX
Definition: tablecmds.c:322
static void change_owner_recurse_to_sequences(Oid relationOid, Oid newOwnerId, LOCKMODE lockmode)
Definition: tablecmds.c:15095
static void StoreCatalogInheritance1(Oid relationId, Oid parentOid, int32 seqNumber, Relation inhRelation, bool child_is_partition)
Definition: tablecmds.c:3499
static void RememberAllDependentForRebuilding(AlteredTableInfo *tab, AlterTableType subtype, Relation rel, AttrNumber attnum, const char *colName)
Definition: tablecmds.c:13799
static void ATPrepDropExpression(Relation rel, AlterTableCmd *cmd, bool recurse, bool recursing, LOCKMODE lockmode)
Definition: tablecmds.c:8575
static ObjectAddress ATExecCookedColumnDefault(Relation rel, AttrNumber attnum, Node *newDefault)
Definition: tablecmds.c:8096
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:3966
static void DropErrorMsgNonExistent(RangeVar *rel, char rightkind, bool missing_ok)
Definition: tablecmds.c:1395
static void ATPostAlterTypeCleanup(List **wqueue, AlteredTableInfo *tab, LOCKMODE lockmode)
Definition: tablecmds.c:14174
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:11240
static AlterTableCmd * ATParseTransformCmd(List **wqueue, AlteredTableInfo *tab, Relation rel, AlterTableCmd *cmd, bool recurse, LOCKMODE lockmode, AlterTablePass cur_pass, AlterTableUtilityContext *context)
Definition: tablecmds.c:5581
void AlterTableNamespaceInternal(Relation rel, Oid oldNspOid, Oid nspOid, ObjectAddresses *objsMoved)
Definition: tablecmds.c:17633
static ObjectAddress ATAddCheckNNConstraint(List **wqueue, AlteredTableInfo *tab, Relation rel, Constraint *constr, bool recurse, bool recursing, bool is_readd, LOCKMODE lockmode)
Definition: tablecmds.c:9644
static void CloneFkReferenced(Relation parentRel, Relation partitionRel)
Definition: tablecmds.c:10766
static void MergeConstraintsIntoExisting(Relation child_rel, Relation parent_rel)
Definition: tablecmds.c:16242
static void ATPrepDropColumn(List **wqueue, Relation rel, bool recurse, bool recursing, AlterTableCmd *cmd, LOCKMODE lockmode, AlterTableUtilityContext *context)
Definition: tablecmds.c:9052
void SetRelationHasSubclass(Oid relationId, bool relhassubclass)
Definition: tablecmds.c:3574
static void MergeChildAttribute(List *inh_columns, int exist_attno, int newcol_attno, const ColumnDef *newdef)
Definition: tablecmds.c:3193
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:3127
static void ATExecSetRelOptions(Relation rel, List *defList, AlterTableType operation, LOCKMODE lockmode)
Definition: tablecmds.c:15259
static ObjectAddress ATExecSetIdentity(Relation rel, const char *colName, Node *def, LOCKMODE lockmode, bool recurse, bool recursing)
Definition: tablecmds.c:8231
ObjectAddress AlterTableNamespace(AlterObjectSchemaStmt *stmt, Oid *oldschema)
Definition: tablecmds.c:17562
static void RememberConstraintForRebuilding(Oid conoid, AlteredTableInfo *tab)
Definition: tablecmds.c:14054
void ExecuteTruncate(TruncateStmt *stmt)
Definition: tablecmds.c:1793
static ObjectAddress dropconstraint_internal(Relation rel, HeapTuple constraintTup, DropBehavior behavior, bool recurse, bool recursing, bool missing_ok, List **readyRels, LOCKMODE lockmode)
Definition: tablecmds.c:12717
static bool ATPrepChangePersistence(Relation rel, bool toLogged)
Definition: tablecmds.c:17443
static void relation_mark_replica_identity(Relation rel, char ri_type, Oid indexOid, bool is_internal)
Definition: tablecmds.c:17027
#define ATT_FOREIGN_TABLE
Definition: tablecmds.c:324
static ObjectAddress ATExecAlterConstraint(Relation rel, AlterTableCmd *cmd, bool recurse, bool recursing, LOCKMODE lockmode)
Definition: tablecmds.c:11510
static void ATPrepAddColumn(List **wqueue, Relation rel, bool recurse, bool recursing, bool is_view, AlterTableCmd *cmd, LOCKMODE lockmode, AlterTableUtilityContext *context)
Definition: tablecmds.c:7002
static void ComputePartitionAttrs(ParseState *pstate, Relation rel, List *partParams, AttrNumber *partattrs, List **partexprs, Oid *partopclass, Oid *partcollation, PartitionStrategy strategy)
Definition: tablecmds.c:18396
static void CloneRowTriggersToPartition(Relation parent, Relation partition)
Definition: tablecmds.c:19352
static void ATInheritAdjustNotNulls(Relation parent_rel, Relation child_rel, int inhcount)
Definition: tablecmds.c:16744
static void AttachPartitionEnsureIndexes(List **wqueue, Relation rel, Relation attachrel)
Definition: tablecmds.c:19153
static void StoreCatalogInheritance(Oid relationId, List *supers, bool child_is_partition)
Definition: tablecmds.c:3455
static void ATExecGenericOptions(Relation rel, List *options)
Definition: tablecmds.c:17282
static void TryReuseForeignKey(Oid oldId, Constraint *con)
Definition: tablecmds.c:14632
struct AlteredTableInfo AlteredTableInfo
static void validateFkOnDeleteSetColumns(int numfks, const int16 *fkattnums, int numfksetcols, const int16 *fksetcolsattnums, List *fksetcols)
Definition: tablecmds.c:10227
Oid AlterTableLookupRelation(AlterTableStmt *stmt, LOCKMODE lockmode)
Definition: tablecmds.c:4360
static void ATPrepAddPrimaryKey(List **wqueue, Relation rel, AlterTableCmd *cmd, LOCKMODE lockmode, AlterTableUtilityContext *context)
Definition: tablecmds.c:9276
struct NewConstraint NewConstraint
static ObjectAddress ATExecSetStatistics(Relation rel, const char *colName, int16 colNum, Node *newValue, LOCKMODE lockmode)
Definition: tablecmds.c:8712
static void ATSimpleRecursion(List **wqueue, Relation rel, AlterTableCmd *cmd, bool recurse, LOCKMODE lockmode, AlterTableUtilityContext *context)
Definition: tablecmds.c:6632
static void DetachPartitionFinalize(Relation rel, Relation partRel, bool concurrent, Oid defaultPartOid)
Definition: tablecmds.c:19680
static void RebuildConstraintComment(AlteredTableInfo *tab, AlterTablePass pass, Oid objid, Relation rel, List *domname, const char *conname)
Definition: tablecmds.c:14559
static void CloneForeignKeyConstraints(List **wqueue, Relation parentRel, Relation partitionRel)
Definition: tablecmds.c:10735
static bool check_for_column_name_collision(Relation rel, const char *colname, bool if_not_exists)
Definition: tablecmds.c:7419
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:7026
AlterTablePass
Definition: tablecmds.c:143
@ AT_PASS_ADD_CONSTR
Definition: tablecmds.c:152
@ AT_PASS_ADD_OTHERCONSTR
Definition: tablecmds.c:156
@ AT_PASS_OLD_CONSTR
Definition: tablecmds.c:150
@ AT_PASS_ADD_COL
Definition: tablecmds.c:147
@ AT_PASS_OLD_INDEX
Definition: tablecmds.c:149
@ AT_PASS_ALTER_TYPE
Definition: tablecmds.c:146
@ AT_PASS_ADD_INDEXCONSTR
Definition: tablecmds.c:154
@ AT_PASS_DROP
Definition: tablecmds.c:145
@ AT_PASS_MISC
Definition: tablecmds.c:157
@ AT_PASS_COL_ATTRS
Definition: tablecmds.c:153
@ AT_PASS_SET_EXPRESSION
Definition: tablecmds.c:148
@ AT_PASS_ADD_INDEX
Definition: tablecmds.c:155
@ AT_PASS_UNSET
Definition: tablecmds.c:144
static ObjectAddress ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel, AlterTableCmd *cmd, LOCKMODE lockmode)
Definition: tablecmds.c:13482
void SetRelationTableSpace(Relation rel, Oid newTableSpaceId, RelFileNumber newRelFilenumber)
Definition: tablecmds.c:3672
void remove_on_commit_action(Oid relid)
Definition: tablecmds.c:17908
static void DetachAddConstraintIfNeeded(List **wqueue, Relation partRel)
Definition: tablecmds.c:19954
static void ATExecDropCluster(Relation rel, LOCKMODE lockmode)
Definition: tablecmds.c:15196
static bool set_attnotnull(List **wqueue, Relation rel, AttrNumber attnum, bool recurse, LOCKMODE lockmode)
Definition: tablecmds.c:7660
#define ATT_PARTITIONED_INDEX
Definition: tablecmds.c:325
static void CreateInheritance(Relation child_rel, Relation parent_rel, bool ispartition)
Definition: tablecmds.c:15989
static void addFkRecurseReferencing(List **wqueue, Constraint *fkconstraint, Relation rel, Relation pkrel, Oid indexOid, Oid parentConstr, int numfks, int16 *pkattnum, int16 *fkattnum, Oid *pfeqoperators, Oid *ppeqoperators, Oid *ffeqoperators, int numfkdelsetcols, int16 *fkdelsetcols, bool old_check_ok, LOCKMODE lockmode, Oid parentInsTrigger, Oid parentUpdTrigger)
Definition: tablecmds.c:10510
static const struct dropmsgstrings dropmsgstringarray[]
Definition: tablecmds.c:246
static ObjectAddress ATExecSetExpression(AlteredTableInfo *tab, Relation rel, const char *colName, Node *newExpr, LOCKMODE lockmode)
Definition: tablecmds.c:8462
ObjectAddress DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId, ObjectAddress *typaddress, const char *queryString)
Definition: tablecmds.c:683
static Oid CreateFKCheckTrigger(Oid myRelOid, Oid refRelOid, Constraint *fkconstraint, Oid constraintOid, Oid indexOid, Oid parentTrigOid, bool on_insert)
Definition: tablecmds.c:12432
static void DropClonedTriggersFromPartition(Oid partitionId)
Definition: tablecmds.c:19995
static void QueuePartitionConstraintValidation(List **wqueue, Relation scanrel, List *partConstraint, bool validate_default)
Definition: tablecmds.c:18764
static ObjectAddress ATExecAddOf(Relation rel, const TypeName *ofTypename, LOCKMODE lockmode)
Definition: tablecmds.c:16841
static void RangeVarCallbackForDropRelation(const RangeVar *rel, Oid relOid, Oid oldRelOid, void *arg)
Definition: tablecmds.c:1634
void AlterTableInternal(Oid relid, List *cmds, bool recurse)
Definition: tablecmds.c:4448
static void GetForeignKeyActionTriggers(Relation trigrel, Oid conoid, Oid confrelid, Oid conrelid, Oid *deleteTriggerOid, Oid *updateTriggerOid)
Definition: tablecmds.c:11383
void check_of_type(HeapTuple typetuple)
Definition: tablecmds.c:6959
static ObjectAddress ATExecDropInherit(Relation rel, RangeVar *parent, LOCKMODE lockmode)
Definition: tablecmds.c:16410
static void ATDetachCheckNoForeignKeyRefs(Relation partition)
Definition: tablecmds.c:20484
static ObjectAddress ATExecAddIndexConstraint(AlteredTableInfo *tab, Relation rel, IndexStmt *stmt, LOCKMODE lockmode)
Definition: tablecmds.c:9436
#define ATT_VIEW
Definition: tablecmds.c:320
static void AlterIndexNamespaces(Relation classRel, Relation rel, Oid oldNspOid, Oid newNspOid, ObjectAddresses *objsMoved)
Definition: tablecmds.c:17742
static char * decompile_conbin(HeapTuple contup, TupleDesc tupdesc)
Definition: tablecmds.c:16058
static void ATExecCmd(List **wqueue, AlteredTableInfo *tab, AlterTableCmd *cmd, LOCKMODE lockmode, AlterTablePass cur_pass, AlterTableUtilityContext *context)
Definition: tablecmds.c:5252
static void ATExecReplicaIdentity(Relation rel, ReplicaIdentityStmt *stmt, LOCKMODE lockmode)
Definition: tablecmds.c:17115
static void createForeignKeyCheckTriggers(Oid myRelOid, Oid refRelOid, Constraint *fkconstraint, Oid constraintOid, Oid indexOid, Oid parentInsTrigger, Oid parentUpdTrigger, Oid *insertTrigOid, Oid *updateTrigOid)
Definition: tablecmds.c:12630
static void ATPrepAddInherit(Relation child_rel)
Definition: tablecmds.c:15848
static ObjectAddress ATExecDetachPartitionFinalize(Relation rel, RangeVar *name)
Definition: tablecmds.c:19919
static ObjectAddress ATExecSetStorage(Relation rel, const char *colName, Node *newValue, LOCKMODE lockmode)
Definition: tablecmds.c:8989
static ObjectAddress ATExecAttachPartition(List **wqueue, Relation rel, PartitionCmd *cmd, AlterTableUtilityContext *context)
Definition: tablecmds.c:18837
static List * find_typed_table_dependencies(Oid typeOid, const char *typeName, DropBehavior behavior)
Definition: tablecmds.c:6910
Oid AlterTableMoveAll(AlterTableMoveAllStmt *stmt)
Definition: tablecmds.c:15594
static ObjectAddress ATExecAddIdentity(Relation rel, const char *colName, Node *def, LOCKMODE lockmode, bool recurse, bool recursing)
Definition: tablecmds.c:8125
static void ATExecDropConstraint(Relation rel, const char *constrName, DropBehavior behavior, bool recurse, bool missing_ok, LOCKMODE lockmode)
Definition: tablecmds.c:12650
static ObjectAddress ATExecAddIndex(AlteredTableInfo *tab, Relation rel, IndexStmt *stmt, bool is_rebuild, LOCKMODE lockmode)
Definition: tablecmds.c:9352
static ObjectAddress ATExecSetCompression(Relation rel, const char *column, Node *newValue, LOCKMODE lockmode)
Definition: tablecmds.c:17363
static PartitionSpec * transformPartitionSpec(Relation rel, PartitionSpec *partspec)
Definition: tablecmds.c:18338
static void ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd, bool recurse, bool recursing, LOCKMODE lockmode, AlterTableUtilityContext *context)
Definition: tablecmds.c:4791
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:15756
void RenameRelationInternal(Oid myrelid, const char *newrelname, bool is_internal, bool is_index)
Definition: tablecmds.c:4189
static void ATExecSetTableSpaceNoStorage(Relation rel, Oid newTableSpace)
Definition: tablecmds.c:15555
static void ATPrepAlterColumnType(List **wqueue, AlteredTableInfo *tab, Relation rel, bool recurse, bool recursing, AlterTableCmd *cmd, LOCKMODE lockmode, AlterTableUtilityContext *context)
Definition: tablecmds.c:13154
static void change_owner_fix_column_acls(Oid relationOid, Oid oldOwnerId, Oid newOwnerId)
Definition: tablecmds.c:15030
#define ATT_COMPOSITE_TYPE
Definition: tablecmds.c:323
static ObjectAddress ATExecAttachPartitionIdx(List **wqueue, Relation parentIdx, RangeVar *name)
Definition: tablecmds.c:20122
bool PartConstraintImpliedByRelConstraint(Relation scanrel, List *partConstraint)
Definition: tablecmds.c:18654
void RangeVarCallbackMaintainsTable(const RangeVar *relation, Oid relId, Oid oldRelId, void *arg)
Definition: tablecmds.c:18105
static const char * alter_table_type_to_string(AlterTableType cmdtype)
Definition: tablecmds.c:6412
static ObjectAddress addFkRecurseReferenced(List **wqueue, Constraint *fkconstraint, Relation rel, Relation pkrel, Oid indexOid, Oid parentConstr, int numfks, int16 *pkattnum, int16 *fkattnum, Oid *pfeqoperators, Oid *ppeqoperators, Oid *ffeqoperators, int numfkdelsetcols, int16 *fkdelsetcols, bool old_check_ok, Oid parentDelTrigger, Oid parentUpdTrigger)
Definition: tablecmds.c:10289
static List * on_commits
Definition: tablecmds.c:125
static bool constraints_equivalent(HeapTuple a, HeapTuple b, TupleDesc tupleDesc)
Definition: tablecmds.c:16083
static ObjectAddress ATExecAddStatistics(AlteredTableInfo *tab, Relation rel, CreateStatsStmt *stmt, bool is_rebuild, LOCKMODE lockmode)
Definition: tablecmds.c:9415
ObjectAddress RenameConstraint(RenameStmt *stmt)
Definition: tablecmds.c:4075
static void ATRewriteTables(AlterTableStmt *parsetree, List **wqueue, LOCKMODE lockmode, AlterTableUtilityContext *context)
Definition: tablecmds.c:5718
void register_on_commit_action(Oid relid, OnCommitAction action)
Definition: tablecmds.c:17872
static void RangeVarCallbackForTruncate(const RangeVar *relation, Oid relId, Oid oldRelId, void *arg)
Definition: tablecmds.c:18141
static ObjectAddress ATExecClusterOn(Relation rel, const char *indexName, LOCKMODE lockmode)
Definition: tablecmds.c:15164
static char GetAttributeStorage(Oid atttypid, const char *storagemode)
Definition: tablecmds.c:20571
void RangeVarCallbackOwnsRelation(const RangeVar *relation, Oid relId, Oid oldRelId, void *arg)
Definition: tablecmds.c:18165
#define ATT_MATVIEW
Definition: tablecmds.c:321
#define child_dependency_type(child_is_partition)
Definition: tablecmds.c:347
static void refuseDupeIndexAttach(Relation parentIdx, Relation partIdx, Relation partitionTbl)
Definition: tablecmds.c:20284
void ExecuteTruncateGuts(List *explicit_rels, List *relids, List *relids_logged, DropBehavior behavior, bool restart_seqs, bool run_as_table_owner)
Definition: tablecmds.c:1917
static List * MergeAttributes(List *columns, const List *supers, char relpersistence, bool is_partition, List **supconstr, List **supnotnulls)
Definition: tablecmds.c:2477
static void ATExecEnableDisableRule(Relation rel, const char *rulename, char fires_when, LOCKMODE lockmode)
Definition: tablecmds.c:15831
struct NewColumnValue NewColumnValue
static void ATPrepSetAccessMethod(AlteredTableInfo *tab, Relation rel, const char *amname)
Definition: tablecmds.c:15209
static bool NotNullImpliedByRelConstraints(Relation rel, Form_pg_attribute attr)
Definition: tablecmds.c:7973
const char * GetCompressionMethodName(char method)
char CompressionNameToMethod(const char *compression)
#define CompressionMethodIsValid(cm)
#define InvalidCompressionMethod
void AlterTableCreateToastTable(Oid relOid, Datum reloptions, LOCKMODE lockmode)
Definition: toasting.c:57
void ExecBSTruncateTriggers(EState *estate, ResultRelInfo *relinfo)
Definition: trigger.c:3222
void EnableDisableTrigger(Relation rel, const char *tgname, Oid tgparent, char fires_when, bool skip_system, bool recurse, LOCKMODE lockmode)
Definition: trigger.c:1721
void ExecASTruncateTriggers(EState *estate, ResultRelInfo *relinfo)
Definition: trigger.c:3269
const char * FindTriggerIncompatibleWithInheritance(TriggerDesc *trigdesc)
Definition: trigger.c:2272
ObjectAddress CreateTrigger(CreateTrigStmt *stmt, const char *queryString, Oid relOid, Oid refRelOid, Oid constraintOid, Oid indexOid, Oid funcoid, Oid parentTriggerOid, Node *whenClause, bool isInternal, bool in_partition)
Definition: trigger.c:158
void TriggerSetParentTrigger(Relation trigRel, Oid childTrigId, Oid parentTrigId, Oid childTableId)
Definition: trigger.c:1216
ObjectAddress CreateTriggerFiringOn(CreateTrigStmt *stmt, const char *queryString, Oid relOid, Oid refRelOid, Oid constraintOid, Oid indexOid, Oid funcoid, Oid parentTriggerOid, Node *whenClause, bool isInternal, bool in_partition, char trigger_fires_when)
Definition: trigger.c:175
bool AfterTriggerPendingOnRel(Oid relid)
Definition: trigger.c:5974
void AfterTriggerEndQuery(EState *estate)
Definition: trigger.c:5038
void AfterTriggerBeginQuery(void)
Definition: trigger.c:5018
#define RI_TRIGGER_FK
Definition: trigger.h:283
#define TRIGGER_FIRES_ON_ORIGIN
Definition: trigger.h:149
#define TRIGGER_DISABLED
Definition: trigger.h:152
#define TRIGGER_FIRES_ON_REPLICA
Definition: trigger.h:151
#define TRIGGER_EVENT_ROW
Definition: trigger.h:98
#define TRIGGER_FIRES_ALWAYS
Definition: trigger.h:150
#define TRIGGER_EVENT_INSERT
Definition: trigger.h:92
#define RI_TRIGGER_PK
Definition: trigger.h:282
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:433
static void slot_getallattrs(TupleTableSlot *slot)
Definition: tuptable.h:362
static bool slot_attisnull(TupleTableSlot *slot, int attnum)
Definition: tuptable.h:375
TupleDesc lookup_rowtype_tupdesc(Oid type_id, int32 typmod)
Definition: typcache.c:1833
bool DomainHasConstraints(Oid type_id)
Definition: typcache.c:1400
void AlterTypeOwnerInternal(Oid typeOid, Oid newOwnerId)
Definition: typecmds.c:3838
ObjectAddress AlterDomainAddConstraint(List *names, Node *newConstraint, ObjectAddress *constrAddr)
Definition: typecmds.c:2914
Oid AlterTypeNamespaceInternal(Oid typeOid, Oid nspOid, bool isImplicitArray, bool errorOnTableType, ObjectAddresses *objsMoved)
Definition: typecmds.c:3981
void checkDomainOwner(HeapTuple tup)
Definition: typecmds.c:3415
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:309
String * makeString(char *str)
Definition: value.c:63
#define intVal(v)
Definition: value.h:79
#define strVal(v)
Definition: value.h:82
void pull_varattnos(Node *node, Index varno, Bitmapset **varattnos)
Definition: var.c:291
#define VARDATA_ANY(PTR)
Definition: varatt.h:324
const char * name
SubTransactionId GetCurrentSubTransactionId(void)
Definition: xact.c:781
void CommandCounterIncrement(void)
Definition: xact.c:1079
void StartTransactionCommand(void)
Definition: xact.c:2955
void CommitTransactionCommand(void)
Definition: xact.c:3053
int MyXactFlags
Definition: xact.c:134
CommandId GetCurrentCommandId(bool used)
Definition: xact.c:819
#define XACT_FLAGS_ACCESSEDTEMPNAMESPACE
Definition: xact.h:102
#define XLogLogicalInfoActive()
Definition: xlog.h:124
#define XLOG_INCLUDE_ORIGIN
Definition: xlog.h:152
void XLogRegisterData(char *data, uint32 len)
Definition: xloginsert.c:364
XLogRecPtr XLogInsert(RmgrId rmid, uint8 info)
Definition: xloginsert.c:474
void XLogSetRecordFlags(uint8 flags)
Definition: xloginsert.c:456
void XLogBeginInsert(void)
Definition: xloginsert.c:149