1 /*-------------------------------------------------------------------------
2  *
3  * tablecmds.c
4  *	  Commands for creating and altering table structures and settings
5  *
6  * Portions Copyright (c) 1996-2021, 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"
26 #include "access/toast_compression.h"
27 #include "access/xact.h"
28 #include "access/xlog.h"
29 #include "catalog/catalog.h"
30 #include "catalog/heap.h"
31 #include "catalog/index.h"
32 #include "catalog/namespace.h"
33 #include "catalog/objectaccess.h"
34 #include "catalog/partition.h"
35 #include "catalog/pg_am.h"
36 #include "catalog/pg_collation.h"
37 #include "catalog/pg_constraint.h"
38 #include "catalog/pg_depend.h"
39 #include "catalog/pg_foreign_table.h"
40 #include "catalog/pg_inherits.h"
41 #include "catalog/pg_namespace.h"
42 #include "catalog/pg_opclass.h"
43 #include "catalog/pg_tablespace.h"
44 #include "catalog/pg_statistic_ext.h"
45 #include "catalog/pg_trigger.h"
46 #include "catalog/pg_type.h"
47 #include "catalog/storage.h"
48 #include "catalog/storage_xlog.h"
49 #include "catalog/toasting.h"
50 #include "commands/cluster.h"
51 #include "commands/comment.h"
52 #include "commands/defrem.h"
53 #include "commands/event_trigger.h"
54 #include "commands/policy.h"
55 #include "commands/sequence.h"
56 #include "commands/tablecmds.h"
57 #include "commands/tablespace.h"
58 #include "commands/trigger.h"
59 #include "commands/typecmds.h"
60 #include "commands/user.h"
61 #include "executor/executor.h"
62 #include "foreign/fdwapi.h"
63 #include "foreign/foreign.h"
64 #include "miscadmin.h"
65 #include "nodes/makefuncs.h"
66 #include "nodes/nodeFuncs.h"
67 #include "nodes/parsenodes.h"
68 #include "optimizer/optimizer.h"
69 #include "parser/parse_clause.h"
70 #include "parser/parse_coerce.h"
71 #include "parser/parse_collate.h"
72 #include "parser/parse_expr.h"
73 #include "parser/parse_oper.h"
74 #include "parser/parse_relation.h"
75 #include "parser/parse_type.h"
76 #include "parser/parse_utilcmd.h"
77 #include "parser/parser.h"
78 #include "partitioning/partbounds.h"
79 #include "partitioning/partdesc.h"
80 #include "pgstat.h"
81 #include "rewrite/rewriteDefine.h"
82 #include "rewrite/rewriteHandler.h"
83 #include "rewrite/rewriteManip.h"
84 #include "storage/bufmgr.h"
85 #include "storage/lmgr.h"
86 #include "storage/lock.h"
87 #include "storage/predicate.h"
88 #include "storage/smgr.h"
89 #include "tcop/utility.h"
90 #include "utils/acl.h"
91 #include "utils/builtins.h"
92 #include "utils/fmgroids.h"
93 #include "utils/inval.h"
94 #include "utils/lsyscache.h"
95 #include "utils/memutils.h"
96 #include "utils/partcache.h"
97 #include "utils/relcache.h"
98 #include "utils/ruleutils.h"
99 #include "utils/snapmgr.h"
100 #include "utils/syscache.h"
101 #include "utils/timestamp.h"
102 #include "utils/typcache.h"
103 
104 /*
105  * ON COMMIT action list
106  */
107 typedef struct OnCommitItem
108 {
109 	Oid			relid;			/* relid of relation */
110 	OnCommitAction oncommit;	/* what to do at end of xact */
111 
112 	/*
113 	 * If this entry was created during the current transaction,
114 	 * creating_subid is the ID of the creating subxact; if created in a prior
115 	 * transaction, creating_subid is zero.  If deleted during the current
116 	 * transaction, deleting_subid is the ID of the deleting subxact; if no
117 	 * deletion request is pending, deleting_subid is zero.
118 	 */
119 	SubTransactionId creating_subid;
120 	SubTransactionId deleting_subid;
121 } OnCommitItem;
122 
123 static List *on_commits = NIL;
124 
125 
126 /*
127  * State information for ALTER TABLE
128  *
129  * The pending-work queue for an ALTER TABLE is a List of AlteredTableInfo
130  * structs, one for each table modified by the operation (the named table
131  * plus any child tables that are affected).  We save lists of subcommands
132  * to apply to this table (possibly modified by parse transformation steps);
133  * these lists will be executed in Phase 2.  If a Phase 3 step is needed,
134  * necessary information is stored in the constraints and newvals lists.
135  *
136  * Phase 2 is divided into multiple passes; subcommands are executed in
137  * a pass determined by subcommand type.
138  */
139 
140 #define AT_PASS_UNSET			-1	/* UNSET will cause ERROR */
141 #define AT_PASS_DROP			0	/* DROP (all flavors) */
142 #define AT_PASS_ALTER_TYPE		1	/* ALTER COLUMN TYPE */
143 #define AT_PASS_OLD_INDEX		2	/* re-add existing indexes */
144 #define AT_PASS_OLD_CONSTR		3	/* re-add existing constraints */
145 /* We could support a RENAME COLUMN pass here, but not currently used */
146 #define AT_PASS_ADD_COL			4	/* ADD COLUMN */
147 #define AT_PASS_ADD_CONSTR		5	/* ADD constraints (initial examination) */
148 #define AT_PASS_COL_ATTRS		6	/* set column attributes, eg NOT NULL */
149 #define AT_PASS_ADD_INDEXCONSTR	7	/* ADD index-based constraints */
150 #define AT_PASS_ADD_INDEX		8	/* ADD indexes */
151 #define AT_PASS_ADD_OTHERCONSTR	9	/* ADD other constraints, defaults */
152 #define AT_PASS_MISC			10	/* other stuff */
153 #define AT_NUM_PASSES			11
154 
155 typedef struct AlteredTableInfo
156 {
157 	/* Information saved before any work commences: */
158 	Oid			relid;			/* Relation to work on */
159 	char		relkind;		/* Its relkind */
160 	TupleDesc	oldDesc;		/* Pre-modification tuple descriptor */
161 
162 	/*
163 	 * Transiently set during Phase 2, normally set to NULL.
164 	 *
165 	 * ATRewriteCatalogs sets this when it starts, and closes when ATExecCmd
166 	 * returns control.  This can be exploited by ATExecCmd subroutines to
167 	 * close/reopen across transaction boundaries.
168 	 */
169 	Relation	rel;
170 
171 	/* Information saved by Phase 1 for Phase 2: */
172 	List	   *subcmds[AT_NUM_PASSES]; /* Lists of AlterTableCmd */
173 	/* Information saved by Phases 1/2 for Phase 3: */
174 	List	   *constraints;	/* List of NewConstraint */
175 	List	   *newvals;		/* List of NewColumnValue */
176 	List	   *afterStmts;		/* List of utility command parsetrees */
177 	bool		verify_new_notnull; /* T if we should recheck NOT NULL */
178 	int			rewrite;		/* Reason for forced rewrite, if any */
179 	Oid			newTableSpace;	/* new tablespace; 0 means no change */
180 	bool		chgPersistence; /* T if SET LOGGED/UNLOGGED is used */
181 	char		newrelpersistence;	/* if above is true */
182 	Expr	   *partition_constraint;	/* for attach partition validation */
183 	/* true, if validating default due to some other attach/detach */
184 	bool		validate_default;
185 	/* Objects to rebuild after completing ALTER TYPE operations */
186 	List	   *changedConstraintOids;	/* OIDs of constraints to rebuild */
187 	List	   *changedConstraintDefs;	/* string definitions of same */
188 	List	   *changedIndexOids;	/* OIDs of indexes to rebuild */
189 	List	   *changedIndexDefs;	/* string definitions of same */
190 	char	   *replicaIdentityIndex;	/* index to reset as REPLICA IDENTITY */
191 	char	   *clusterOnIndex; /* index to use for CLUSTER */
192 	List	   *changedStatisticsOids;	/* OIDs of statistics to rebuild */
193 	List	   *changedStatisticsDefs;	/* string definitions of same */
194 } AlteredTableInfo;
195 
196 /* Struct describing one new constraint to check in Phase 3 scan */
197 /* Note: new NOT NULL constraints are handled elsewhere */
198 typedef struct NewConstraint
199 {
200 	char	   *name;			/* Constraint name, or NULL if none */
201 	ConstrType	contype;		/* CHECK or FOREIGN */
202 	Oid			refrelid;		/* PK rel, if FOREIGN */
203 	Oid			refindid;		/* OID of PK's index, if FOREIGN */
204 	Oid			conid;			/* OID of pg_constraint entry, if FOREIGN */
205 	Node	   *qual;			/* Check expr or CONSTR_FOREIGN Constraint */
206 	ExprState  *qualstate;		/* Execution state for CHECK expr */
207 } NewConstraint;
208 
209 /*
210  * Struct describing one new column value that needs to be computed during
211  * Phase 3 copy (this could be either a new column with a non-null default, or
212  * a column that we're changing the type of).  Columns without such an entry
213  * are just copied from the old table during ATRewriteTable.  Note that the
214  * expr is an expression over *old* table values, except when is_generated
215  * is true; then it is an expression over columns of the *new* tuple.
216  */
217 typedef struct NewColumnValue
218 {
219 	AttrNumber	attnum;			/* which column */
220 	Expr	   *expr;			/* expression to compute */
221 	ExprState  *exprstate;		/* execution state */
222 	bool		is_generated;	/* is it a GENERATED expression? */
223 } NewColumnValue;
224 
225 /*
226  * Error-reporting support for RemoveRelations
227  */
228 struct dropmsgstrings
229 {
230 	char		kind;
231 	int			nonexistent_code;
232 	const char *nonexistent_msg;
233 	const char *skipping_msg;
234 	const char *nota_msg;
235 	const char *drophint_msg;
236 };
237 
238 static const struct dropmsgstrings dropmsgstringarray[] = {
239 	{RELKIND_RELATION,
240 		ERRCODE_UNDEFINED_TABLE,
241 		gettext_noop("table \"%s\" does not exist"),
242 		gettext_noop("table \"%s\" does not exist, skipping"),
243 		gettext_noop("\"%s\" is not a table"),
244 	gettext_noop("Use DROP TABLE to remove a table.")},
245 	{RELKIND_SEQUENCE,
246 		ERRCODE_UNDEFINED_TABLE,
247 		gettext_noop("sequence \"%s\" does not exist"),
248 		gettext_noop("sequence \"%s\" does not exist, skipping"),
249 		gettext_noop("\"%s\" is not a sequence"),
250 	gettext_noop("Use DROP SEQUENCE to remove a sequence.")},
251 	{RELKIND_VIEW,
252 		ERRCODE_UNDEFINED_TABLE,
253 		gettext_noop("view \"%s\" does not exist"),
254 		gettext_noop("view \"%s\" does not exist, skipping"),
255 		gettext_noop("\"%s\" is not a view"),
256 	gettext_noop("Use DROP VIEW to remove a view.")},
257 	{RELKIND_MATVIEW,
258 		ERRCODE_UNDEFINED_TABLE,
259 		gettext_noop("materialized view \"%s\" does not exist"),
260 		gettext_noop("materialized view \"%s\" does not exist, skipping"),
261 		gettext_noop("\"%s\" is not a materialized view"),
262 	gettext_noop("Use DROP MATERIALIZED VIEW to remove a materialized view.")},
263 	{RELKIND_INDEX,
264 		ERRCODE_UNDEFINED_OBJECT,
265 		gettext_noop("index \"%s\" does not exist"),
266 		gettext_noop("index \"%s\" does not exist, skipping"),
267 		gettext_noop("\"%s\" is not an index"),
268 	gettext_noop("Use DROP INDEX to remove an index.")},
269 	{RELKIND_COMPOSITE_TYPE,
270 		ERRCODE_UNDEFINED_OBJECT,
271 		gettext_noop("type \"%s\" does not exist"),
272 		gettext_noop("type \"%s\" does not exist, skipping"),
273 		gettext_noop("\"%s\" is not a type"),
274 	gettext_noop("Use DROP TYPE to remove a type.")},
275 	{RELKIND_FOREIGN_TABLE,
276 		ERRCODE_UNDEFINED_OBJECT,
277 		gettext_noop("foreign table \"%s\" does not exist"),
278 		gettext_noop("foreign table \"%s\" does not exist, skipping"),
279 		gettext_noop("\"%s\" is not a foreign table"),
280 	gettext_noop("Use DROP FOREIGN TABLE to remove a foreign table.")},
281 	{RELKIND_PARTITIONED_TABLE,
282 		ERRCODE_UNDEFINED_TABLE,
283 		gettext_noop("table \"%s\" does not exist"),
284 		gettext_noop("table \"%s\" does not exist, skipping"),
285 		gettext_noop("\"%s\" is not a table"),
286 	gettext_noop("Use DROP TABLE to remove a table.")},
287 	{RELKIND_PARTITIONED_INDEX,
288 		ERRCODE_UNDEFINED_OBJECT,
289 		gettext_noop("index \"%s\" does not exist"),
290 		gettext_noop("index \"%s\" does not exist, skipping"),
291 		gettext_noop("\"%s\" is not an index"),
292 	gettext_noop("Use DROP INDEX to remove an index.")},
293 	{'\0', 0, NULL, NULL, NULL, NULL}
294 };
295 
296 struct DropRelationCallbackState
297 {
298 	char		relkind;
299 	Oid			heapOid;
300 	Oid			partParentOid;
301 	bool		concurrent;
302 };
303 
304 /* Alter table target-type flags for ATSimplePermissions */
305 #define		ATT_TABLE				0x0001
306 #define		ATT_VIEW				0x0002
307 #define		ATT_MATVIEW				0x0004
308 #define		ATT_INDEX				0x0008
309 #define		ATT_COMPOSITE_TYPE		0x0010
310 #define		ATT_FOREIGN_TABLE		0x0020
311 #define		ATT_PARTITIONED_INDEX	0x0040
312 
313 /*
314  * ForeignTruncateInfo
315  *
316  * Information related to truncation of foreign tables.  This is used for
317  * the elements in a hash table. It uses the server OID as lookup key,
318  * and includes a per-server list of all foreign tables involved in the
319  * truncation.
320  */
321 typedef struct ForeignTruncateInfo
322 {
323 	Oid			serverid;
324 	List	   *rels;
325 } ForeignTruncateInfo;
326 
327 /*
328  * Partition tables are expected to be dropped when the parent partitioned
329  * table gets dropped. Hence for partitioning we use AUTO dependency.
330  * Otherwise, for regular inheritance use NORMAL dependency.
331  */
332 #define child_dependency_type(child_is_partition)	\
333 	((child_is_partition) ? DEPENDENCY_AUTO : DEPENDENCY_NORMAL)
334 
335 static void truncate_check_rel(Oid relid, Form_pg_class reltuple);
336 static void truncate_check_perms(Oid relid, Form_pg_class reltuple);
337 static void truncate_check_activity(Relation rel);
338 static void RangeVarCallbackForTruncate(const RangeVar *relation,
339 										Oid relId, Oid oldRelId, void *arg);
340 static List *MergeAttributes(List *schema, List *supers, char relpersistence,
341 							 bool is_partition, List **supconstr);
342 static bool MergeCheckConstraint(List *constraints, char *name, Node *expr);
343 static void MergeAttributesIntoExisting(Relation child_rel, Relation parent_rel);
344 static void MergeConstraintsIntoExisting(Relation child_rel, Relation parent_rel);
345 static void StoreCatalogInheritance(Oid relationId, List *supers,
346 									bool child_is_partition);
347 static void StoreCatalogInheritance1(Oid relationId, Oid parentOid,
348 									 int32 seqNumber, Relation inhRelation,
349 									 bool child_is_partition);
350 static int	findAttrByName(const char *attributeName, List *schema);
351 static void AlterIndexNamespaces(Relation classRel, Relation rel,
352 								 Oid oldNspOid, Oid newNspOid, ObjectAddresses *objsMoved);
353 static void AlterSeqNamespaces(Relation classRel, Relation rel,
354 							   Oid oldNspOid, Oid newNspOid, ObjectAddresses *objsMoved,
355 							   LOCKMODE lockmode);
356 static ObjectAddress ATExecAlterConstraint(Relation rel, AlterTableCmd *cmd,
357 										   bool recurse, bool recursing, LOCKMODE lockmode);
358 static bool ATExecAlterConstrRecurse(Constraint *cmdcon, Relation conrel, Relation tgrel,
359 									 Relation rel, HeapTuple contuple, List **otherrelids,
360 									 LOCKMODE lockmode);
361 static ObjectAddress ATExecValidateConstraint(List **wqueue,
362 											  Relation rel, char *constrName,
363 											  bool recurse, bool recursing, LOCKMODE lockmode);
364 static int	transformColumnNameList(Oid relId, List *colList,
365 									int16 *attnums, Oid *atttypids);
366 static int	transformFkeyGetPrimaryKey(Relation pkrel, Oid *indexOid,
367 									   List **attnamelist,
368 									   int16 *attnums, Oid *atttypids,
369 									   Oid *opclasses);
370 static Oid	transformFkeyCheckAttrs(Relation pkrel,
371 									int numattrs, int16 *attnums,
372 									Oid *opclasses);
373 static void checkFkeyPermissions(Relation rel, int16 *attnums, int natts);
374 static CoercionPathType findFkeyCast(Oid targetTypeId, Oid sourceTypeId,
375 									 Oid *funcid);
376 static void validateForeignKeyConstraint(char *conname,
377 										 Relation rel, Relation pkrel,
378 										 Oid pkindOid, Oid constraintOid);
379 static void ATController(AlterTableStmt *parsetree,
380 						 Relation rel, List *cmds, bool recurse, LOCKMODE lockmode,
381 						 AlterTableUtilityContext *context);
382 static void ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd,
383 					  bool recurse, bool recursing, LOCKMODE lockmode,
384 					  AlterTableUtilityContext *context);
385 static void ATRewriteCatalogs(List **wqueue, LOCKMODE lockmode,
386 							  AlterTableUtilityContext *context);
387 static void ATExecCmd(List **wqueue, AlteredTableInfo *tab,
388 					  AlterTableCmd *cmd, LOCKMODE lockmode, int cur_pass,
389 					  AlterTableUtilityContext *context);
390 static AlterTableCmd *ATParseTransformCmd(List **wqueue, AlteredTableInfo *tab,
391 										  Relation rel, AlterTableCmd *cmd,
392 										  bool recurse, LOCKMODE lockmode,
393 										  int cur_pass,
394 										  AlterTableUtilityContext *context);
395 static void ATRewriteTables(AlterTableStmt *parsetree,
396 							List **wqueue, LOCKMODE lockmode,
397 							AlterTableUtilityContext *context);
398 static void ATRewriteTable(AlteredTableInfo *tab, Oid OIDNewHeap, LOCKMODE lockmode);
399 static AlteredTableInfo *ATGetQueueEntry(List **wqueue, Relation rel);
400 static void ATSimplePermissions(Relation rel, int allowed_targets);
401 static void ATWrongRelkindError(Relation rel, int allowed_targets);
402 static void ATSimpleRecursion(List **wqueue, Relation rel,
403 							  AlterTableCmd *cmd, bool recurse, LOCKMODE lockmode,
404 							  AlterTableUtilityContext *context);
405 static void ATCheckPartitionsNotInUse(Relation rel, LOCKMODE lockmode);
406 static void ATTypedTableRecursion(List **wqueue, Relation rel, AlterTableCmd *cmd,
407 								  LOCKMODE lockmode,
408 								  AlterTableUtilityContext *context);
409 static List *find_typed_table_dependencies(Oid typeOid, const char *typeName,
410 										   DropBehavior behavior);
411 static void ATPrepAddColumn(List **wqueue, Relation rel, bool recurse, bool recursing,
412 							bool is_view, AlterTableCmd *cmd, LOCKMODE lockmode,
413 							AlterTableUtilityContext *context);
414 static ObjectAddress ATExecAddColumn(List **wqueue, AlteredTableInfo *tab,
415 									 Relation rel, AlterTableCmd **cmd,
416 									 bool recurse, bool recursing,
417 									 LOCKMODE lockmode, int cur_pass,
418 									 AlterTableUtilityContext *context);
419 static bool check_for_column_name_collision(Relation rel, const char *colname,
420 											bool if_not_exists);
421 static void add_column_datatype_dependency(Oid relid, int32 attnum, Oid typid);
422 static void add_column_collation_dependency(Oid relid, int32 attnum, Oid collid);
423 static void ATPrepDropNotNull(Relation rel, bool recurse, bool recursing);
424 static ObjectAddress ATExecDropNotNull(Relation rel, const char *colName, LOCKMODE lockmode);
425 static void ATPrepSetNotNull(List **wqueue, Relation rel,
426 							 AlterTableCmd *cmd, bool recurse, bool recursing,
427 							 LOCKMODE lockmode,
428 							 AlterTableUtilityContext *context);
429 static ObjectAddress ATExecSetNotNull(AlteredTableInfo *tab, Relation rel,
430 									  const char *colName, LOCKMODE lockmode);
431 static void ATExecCheckNotNull(AlteredTableInfo *tab, Relation rel,
432 							   const char *colName, LOCKMODE lockmode);
433 static bool NotNullImpliedByRelConstraints(Relation rel, Form_pg_attribute attr);
434 static bool ConstraintImpliedByRelConstraint(Relation scanrel,
435 											 List *testConstraint, List *provenConstraint);
436 static ObjectAddress ATExecColumnDefault(Relation rel, const char *colName,
437 										 Node *newDefault, LOCKMODE lockmode);
438 static ObjectAddress ATExecCookedColumnDefault(Relation rel, AttrNumber attnum,
439 											   Node *newDefault);
440 static ObjectAddress ATExecAddIdentity(Relation rel, const char *colName,
441 									   Node *def, LOCKMODE lockmode);
442 static ObjectAddress ATExecSetIdentity(Relation rel, const char *colName,
443 									   Node *def, LOCKMODE lockmode);
444 static ObjectAddress ATExecDropIdentity(Relation rel, const char *colName, bool missing_ok, LOCKMODE lockmode);
445 static void ATPrepDropExpression(Relation rel, AlterTableCmd *cmd, bool recurse, bool recursing, LOCKMODE lockmode);
446 static ObjectAddress ATExecDropExpression(Relation rel, const char *colName, bool missing_ok, LOCKMODE lockmode);
447 static ObjectAddress ATExecSetStatistics(Relation rel, const char *colName, int16 colNum,
448 										 Node *newValue, LOCKMODE lockmode);
449 static ObjectAddress ATExecSetOptions(Relation rel, const char *colName,
450 									  Node *options, bool isReset, LOCKMODE lockmode);
451 static ObjectAddress ATExecSetStorage(Relation rel, const char *colName,
452 									  Node *newValue, LOCKMODE lockmode);
453 static void ATPrepDropColumn(List **wqueue, Relation rel, bool recurse, bool recursing,
454 							 AlterTableCmd *cmd, LOCKMODE lockmode,
455 							 AlterTableUtilityContext *context);
456 static ObjectAddress ATExecDropColumn(List **wqueue, Relation rel, const char *colName,
457 									  DropBehavior behavior,
458 									  bool recurse, bool recursing,
459 									  bool missing_ok, LOCKMODE lockmode,
460 									  ObjectAddresses *addrs);
461 static ObjectAddress ATExecAddIndex(AlteredTableInfo *tab, Relation rel,
462 									IndexStmt *stmt, bool is_rebuild, LOCKMODE lockmode);
463 static ObjectAddress ATExecAddStatistics(AlteredTableInfo *tab, Relation rel,
464 										 CreateStatsStmt *stmt, bool is_rebuild, LOCKMODE lockmode);
465 static ObjectAddress ATExecAddConstraint(List **wqueue,
466 										 AlteredTableInfo *tab, Relation rel,
467 										 Constraint *newConstraint, bool recurse, bool is_readd,
468 										 LOCKMODE lockmode);
469 static char *ChooseForeignKeyConstraintNameAddition(List *colnames);
470 static ObjectAddress ATExecAddIndexConstraint(AlteredTableInfo *tab, Relation rel,
471 											  IndexStmt *stmt, LOCKMODE lockmode);
472 static ObjectAddress ATAddCheckConstraint(List **wqueue,
473 										  AlteredTableInfo *tab, Relation rel,
474 										  Constraint *constr,
475 										  bool recurse, bool recursing, bool is_readd,
476 										  LOCKMODE lockmode);
477 static ObjectAddress ATAddForeignKeyConstraint(List **wqueue, AlteredTableInfo *tab,
478 											   Relation rel, Constraint *fkconstraint,
479 											   bool recurse, bool recursing,
480 											   LOCKMODE lockmode);
481 static ObjectAddress addFkRecurseReferenced(List **wqueue, Constraint *fkconstraint,
482 											Relation rel, Relation pkrel, Oid indexOid, Oid parentConstr,
483 											int numfks, int16 *pkattnum, int16 *fkattnum,
484 											Oid *pfeqoperators, Oid *ppeqoperators, Oid *ffeqoperators,
485 											bool old_check_ok);
486 static void addFkRecurseReferencing(List **wqueue, Constraint *fkconstraint,
487 									Relation rel, Relation pkrel, Oid indexOid, Oid parentConstr,
488 									int numfks, int16 *pkattnum, int16 *fkattnum,
489 									Oid *pfeqoperators, Oid *ppeqoperators, Oid *ffeqoperators,
490 									bool old_check_ok, LOCKMODE lockmode);
491 static void CloneForeignKeyConstraints(List **wqueue, Relation parentRel,
492 									   Relation partitionRel);
493 static void CloneFkReferenced(Relation parentRel, Relation partitionRel);
494 static void CloneFkReferencing(List **wqueue, Relation parentRel,
495 							   Relation partRel);
496 static void createForeignKeyCheckTriggers(Oid myRelOid, Oid refRelOid,
497 										  Constraint *fkconstraint, Oid constraintOid,
498 										  Oid indexOid);
499 static void createForeignKeyActionTriggers(Relation rel, Oid refRelOid,
500 										   Constraint *fkconstraint, Oid constraintOid,
501 										   Oid indexOid);
502 static bool tryAttachPartitionForeignKey(ForeignKeyCacheInfo *fk,
503 										 Oid partRelid,
504 										 Oid parentConstrOid, int numfks,
505 										 AttrNumber *mapped_conkey, AttrNumber *confkey,
506 										 Oid *conpfeqop);
507 static void ATExecDropConstraint(Relation rel, const char *constrName,
508 								 DropBehavior behavior,
509 								 bool recurse, bool recursing,
510 								 bool missing_ok, LOCKMODE lockmode);
511 static void ATPrepAlterColumnType(List **wqueue,
512 								  AlteredTableInfo *tab, Relation rel,
513 								  bool recurse, bool recursing,
514 								  AlterTableCmd *cmd, LOCKMODE lockmode,
515 								  AlterTableUtilityContext *context);
516 static bool ATColumnChangeRequiresRewrite(Node *expr, AttrNumber varattno);
517 static ObjectAddress ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel,
518 										   AlterTableCmd *cmd, LOCKMODE lockmode);
519 static void RememberConstraintForRebuilding(Oid conoid, AlteredTableInfo *tab);
520 static void RememberIndexForRebuilding(Oid indoid, AlteredTableInfo *tab);
521 static void RememberStatisticsForRebuilding(Oid indoid, AlteredTableInfo *tab);
522 static void ATPostAlterTypeCleanup(List **wqueue, AlteredTableInfo *tab,
523 								   LOCKMODE lockmode);
524 static void ATPostAlterTypeParse(Oid oldId, Oid oldRelId, Oid refRelId,
525 								 char *cmd, List **wqueue, LOCKMODE lockmode,
526 								 bool rewrite);
527 static void RebuildConstraintComment(AlteredTableInfo *tab, int pass,
528 									 Oid objid, Relation rel, List *domname,
529 									 const char *conname);
530 static void TryReuseIndex(Oid oldId, IndexStmt *stmt);
531 static void TryReuseForeignKey(Oid oldId, Constraint *con);
532 static ObjectAddress ATExecAlterColumnGenericOptions(Relation rel, const char *colName,
533 													 List *options, LOCKMODE lockmode);
534 static void change_owner_fix_column_acls(Oid relationOid,
535 										 Oid oldOwnerId, Oid newOwnerId);
536 static void change_owner_recurse_to_sequences(Oid relationOid,
537 											  Oid newOwnerId, LOCKMODE lockmode);
538 static ObjectAddress ATExecClusterOn(Relation rel, const char *indexName,
539 									 LOCKMODE lockmode);
540 static void ATExecDropCluster(Relation rel, LOCKMODE lockmode);
541 static bool ATPrepChangePersistence(Relation rel, bool toLogged);
542 static void ATPrepSetTableSpace(AlteredTableInfo *tab, Relation rel,
543 								const char *tablespacename, LOCKMODE lockmode);
544 static void ATExecSetTableSpace(Oid tableOid, Oid newTableSpace, LOCKMODE lockmode);
545 static void ATExecSetTableSpaceNoStorage(Relation rel, Oid newTableSpace);
546 static void ATExecSetRelOptions(Relation rel, List *defList,
547 								AlterTableType operation,
548 								LOCKMODE lockmode);
549 static void ATExecEnableDisableTrigger(Relation rel, const char *trigname,
550 									   char fires_when, bool skip_system, LOCKMODE lockmode);
551 static void ATExecEnableDisableRule(Relation rel, const char *rulename,
552 									char fires_when, LOCKMODE lockmode);
553 static void ATPrepAddInherit(Relation child_rel);
554 static ObjectAddress ATExecAddInherit(Relation child_rel, RangeVar *parent, LOCKMODE lockmode);
555 static ObjectAddress ATExecDropInherit(Relation rel, RangeVar *parent, LOCKMODE lockmode);
556 static void drop_parent_dependency(Oid relid, Oid refclassid, Oid refobjid,
557 								   DependencyType deptype);
558 static ObjectAddress ATExecAddOf(Relation rel, const TypeName *ofTypename, LOCKMODE lockmode);
559 static void ATExecDropOf(Relation rel, LOCKMODE lockmode);
560 static void ATExecReplicaIdentity(Relation rel, ReplicaIdentityStmt *stmt, LOCKMODE lockmode);
561 static void ATExecGenericOptions(Relation rel, List *options);
562 static void ATExecSetRowSecurity(Relation rel, bool rls);
563 static void ATExecForceNoForceRowSecurity(Relation rel, bool force_rls);
564 static ObjectAddress ATExecSetCompression(AlteredTableInfo *tab, Relation rel,
565 										  const char *column, Node *newValue, LOCKMODE lockmode);
566 
567 static void index_copy_data(Relation rel, RelFileNode newrnode);
568 static const char *storage_name(char c);
569 
570 static void RangeVarCallbackForDropRelation(const RangeVar *rel, Oid relOid,
571 											Oid oldRelOid, void *arg);
572 static void RangeVarCallbackForAlterRelation(const RangeVar *rv, Oid relid,
573 											 Oid oldrelid, void *arg);
574 static PartitionSpec *transformPartitionSpec(Relation rel, PartitionSpec *partspec, char *strategy);
575 static void ComputePartitionAttrs(ParseState *pstate, Relation rel, List *partParams, AttrNumber *partattrs,
576 								  List **partexprs, Oid *partopclass, Oid *partcollation, char strategy);
577 static void CreateInheritance(Relation child_rel, Relation parent_rel);
578 static void RemoveInheritance(Relation child_rel, Relation parent_rel,
579 							  bool allow_detached);
580 static ObjectAddress ATExecAttachPartition(List **wqueue, Relation rel,
581 										   PartitionCmd *cmd,
582 										   AlterTableUtilityContext *context);
583 static void AttachPartitionEnsureIndexes(Relation rel, Relation attachrel);
584 static void QueuePartitionConstraintValidation(List **wqueue, Relation scanrel,
585 											   List *partConstraint,
586 											   bool validate_default);
587 static void CloneRowTriggersToPartition(Relation parent, Relation partition);
588 static void DetachAddConstraintIfNeeded(List **wqueue, Relation partRel);
589 static void DropClonedTriggersFromPartition(Oid partitionId);
590 static ObjectAddress ATExecDetachPartition(List **wqueue, AlteredTableInfo *tab,
591 										   Relation rel, RangeVar *name,
592 										   bool concurrent);
593 static void DetachPartitionFinalize(Relation rel, Relation partRel,
594 									bool concurrent, Oid defaultPartOid);
595 static ObjectAddress ATExecDetachPartitionFinalize(Relation rel, RangeVar *name);
596 static ObjectAddress ATExecAttachPartitionIdx(List **wqueue, Relation rel,
597 											  RangeVar *name);
598 static void validatePartitionedIndex(Relation partedIdx, Relation partedTbl);
599 static void refuseDupeIndexAttach(Relation parentIdx, Relation partIdx,
600 								  Relation partitionTbl);
601 static List *GetParentedForeignKeyRefs(Relation partition);
602 static void ATDetachCheckNoForeignKeyRefs(Relation partition);
603 static char GetAttributeCompression(Oid atttypid, char *compression);
604 
605 
606 /* ----------------------------------------------------------------
607  *		DefineRelation
608  *				Creates a new relation.
609  *
610  * stmt carries parsetree information from an ordinary CREATE TABLE statement.
611  * The other arguments are used to extend the behavior for other cases:
612  * relkind: relkind to assign to the new relation
613  * ownerId: if not InvalidOid, use this as the new relation's owner.
614  * typaddress: if not null, it's set to the pg_type entry's address.
615  * queryString: for error reporting
616  *
617  * Note that permissions checks are done against current user regardless of
618  * ownerId.  A nonzero ownerId is used when someone is creating a relation
619  * "on behalf of" someone else, so we still want to see that the current user
620  * has permissions to do it.
621  *
622  * If successful, returns the address of the new relation.
623  * ----------------------------------------------------------------
624  */
625 ObjectAddress
DefineRelation(CreateStmt * stmt,char relkind,Oid ownerId,ObjectAddress * typaddress,const char * queryString)626 DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId,
627 			   ObjectAddress *typaddress, const char *queryString)
628 {
629 	char		relname[NAMEDATALEN];
630 	Oid			namespaceId;
631 	Oid			relationId;
632 	Oid			tablespaceId;
633 	Relation	rel;
634 	TupleDesc	descriptor;
635 	List	   *inheritOids;
636 	List	   *old_constraints;
637 	List	   *rawDefaults;
638 	List	   *cookedDefaults;
639 	Datum		reloptions;
640 	ListCell   *listptr;
641 	AttrNumber	attnum;
642 	bool		partitioned;
643 	static char *validnsps[] = HEAP_RELOPT_NAMESPACES;
644 	Oid			ofTypeId;
645 	ObjectAddress address;
646 	LOCKMODE	parentLockmode;
647 	const char *accessMethod = NULL;
648 	Oid			accessMethodId = InvalidOid;
649 
650 	/*
651 	 * Truncate relname to appropriate length (probably a waste of time, as
652 	 * parser should have done this already).
653 	 */
654 	strlcpy(relname, stmt->relation->relname, NAMEDATALEN);
655 
656 	/*
657 	 * Check consistency of arguments
658 	 */
659 	if (stmt->oncommit != ONCOMMIT_NOOP
660 		&& stmt->relation->relpersistence != RELPERSISTENCE_TEMP)
661 		ereport(ERROR,
662 				(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
663 				 errmsg("ON COMMIT can only be used on temporary tables")));
664 
665 	if (stmt->partspec != NULL)
666 	{
667 		if (relkind != RELKIND_RELATION)
668 			elog(ERROR, "unexpected relkind: %d", (int) relkind);
669 
670 		relkind = RELKIND_PARTITIONED_TABLE;
671 		partitioned = true;
672 	}
673 	else
674 		partitioned = false;
675 
676 	/*
677 	 * Look up the namespace in which we are supposed to create the relation,
678 	 * check we have permission to create there, lock it against concurrent
679 	 * drop, and mark stmt->relation as RELPERSISTENCE_TEMP if a temporary
680 	 * namespace is selected.
681 	 */
682 	namespaceId =
683 		RangeVarGetAndCheckCreationNamespace(stmt->relation, NoLock, NULL);
684 
685 	/*
686 	 * Security check: disallow creating temp tables from security-restricted
687 	 * code.  This is needed because calling code might not expect untrusted
688 	 * tables to appear in pg_temp at the front of its search path.
689 	 */
690 	if (stmt->relation->relpersistence == RELPERSISTENCE_TEMP
691 		&& InSecurityRestrictedOperation())
692 		ereport(ERROR,
693 				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
694 				 errmsg("cannot create temporary table within security-restricted operation")));
695 
696 	/*
697 	 * Determine the lockmode to use when scanning parents.  A self-exclusive
698 	 * lock is needed here.
699 	 *
700 	 * For regular inheritance, if two backends attempt to add children to the
701 	 * same parent simultaneously, and that parent has no pre-existing
702 	 * children, then both will attempt to update the parent's relhassubclass
703 	 * field, leading to a "tuple concurrently updated" error.  Also, this
704 	 * interlocks against a concurrent ANALYZE on the parent table, which
705 	 * might otherwise be attempting to clear the parent's relhassubclass
706 	 * field, if its previous children were recently dropped.
707 	 *
708 	 * If the child table is a partition, then we instead grab an exclusive
709 	 * lock on the parent because its partition descriptor will be changed by
710 	 * addition of the new partition.
711 	 */
712 	parentLockmode = (stmt->partbound != NULL ? AccessExclusiveLock :
713 					  ShareUpdateExclusiveLock);
714 
715 	/* Determine the list of OIDs of the parents. */
716 	inheritOids = NIL;
717 	foreach(listptr, stmt->inhRelations)
718 	{
719 		RangeVar   *rv = (RangeVar *) lfirst(listptr);
720 		Oid			parentOid;
721 
722 		parentOid = RangeVarGetRelid(rv, parentLockmode, false);
723 
724 		/*
725 		 * Reject duplications in the list of parents.
726 		 */
727 		if (list_member_oid(inheritOids, parentOid))
728 			ereport(ERROR,
729 					(errcode(ERRCODE_DUPLICATE_TABLE),
730 					 errmsg("relation \"%s\" would be inherited from more than once",
731 							get_rel_name(parentOid))));
732 
733 		inheritOids = lappend_oid(inheritOids, parentOid);
734 	}
735 
736 	/*
737 	 * Select tablespace to use: an explicitly indicated one, or (in the case
738 	 * of a partitioned table) the parent's, if it has one.
739 	 */
740 	if (stmt->tablespacename)
741 	{
742 		tablespaceId = get_tablespace_oid(stmt->tablespacename, false);
743 
744 		if (partitioned && tablespaceId == MyDatabaseTableSpace)
745 			ereport(ERROR,
746 					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
747 					 errmsg("cannot specify default tablespace for partitioned relations")));
748 	}
749 	else if (stmt->partbound)
750 	{
751 		/*
752 		 * For partitions, when no other tablespace is specified, we default
753 		 * the tablespace to the parent partitioned table's.
754 		 */
755 		Assert(list_length(inheritOids) == 1);
756 		tablespaceId = get_rel_tablespace(linitial_oid(inheritOids));
757 	}
758 	else
759 		tablespaceId = InvalidOid;
760 
761 	/* still nothing? use the default */
762 	if (!OidIsValid(tablespaceId))
763 		tablespaceId = GetDefaultTablespace(stmt->relation->relpersistence,
764 											partitioned);
765 
766 	/* Check permissions except when using database's default */
767 	if (OidIsValid(tablespaceId) && tablespaceId != MyDatabaseTableSpace)
768 	{
769 		AclResult	aclresult;
770 
771 		aclresult = pg_tablespace_aclcheck(tablespaceId, GetUserId(),
772 										   ACL_CREATE);
773 		if (aclresult != ACLCHECK_OK)
774 			aclcheck_error(aclresult, OBJECT_TABLESPACE,
775 						   get_tablespace_name(tablespaceId));
776 	}
777 
778 	/* In all cases disallow placing user relations in pg_global */
779 	if (tablespaceId == GLOBALTABLESPACE_OID)
780 		ereport(ERROR,
781 				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
782 				 errmsg("only shared relations can be placed in pg_global tablespace")));
783 
784 	/* Identify user ID that will own the table */
785 	if (!OidIsValid(ownerId))
786 		ownerId = GetUserId();
787 
788 	/*
789 	 * Parse and validate reloptions, if any.
790 	 */
791 	reloptions = transformRelOptions((Datum) 0, stmt->options, NULL, validnsps,
792 									 true, false);
793 
794 	switch (relkind)
795 	{
796 		case RELKIND_VIEW:
797 			(void) view_reloptions(reloptions, true);
798 			break;
799 		case RELKIND_PARTITIONED_TABLE:
800 			(void) partitioned_table_reloptions(reloptions, true);
801 			break;
802 		default:
803 			(void) heap_reloptions(relkind, reloptions, true);
804 	}
805 
806 	if (stmt->ofTypename)
807 	{
808 		AclResult	aclresult;
809 
810 		ofTypeId = typenameTypeId(NULL, stmt->ofTypename);
811 
812 		aclresult = pg_type_aclcheck(ofTypeId, GetUserId(), ACL_USAGE);
813 		if (aclresult != ACLCHECK_OK)
814 			aclcheck_error_type(aclresult, ofTypeId);
815 	}
816 	else
817 		ofTypeId = InvalidOid;
818 
819 	/*
820 	 * Look up inheritance ancestors and generate relation schema, including
821 	 * inherited attributes.  (Note that stmt->tableElts is destructively
822 	 * modified by MergeAttributes.)
823 	 */
824 	stmt->tableElts =
825 		MergeAttributes(stmt->tableElts, inheritOids,
826 						stmt->relation->relpersistence,
827 						stmt->partbound != NULL,
828 						&old_constraints);
829 
830 	/*
831 	 * Create a tuple descriptor from the relation schema.  Note that this
832 	 * deals with column names, types, and NOT NULL constraints, but not
833 	 * default values or CHECK constraints; we handle those below.
834 	 */
835 	descriptor = BuildDescForRelation(stmt->tableElts);
836 
837 	/*
838 	 * Find columns with default values and prepare for insertion of the
839 	 * defaults.  Pre-cooked (that is, inherited) defaults go into a list of
840 	 * CookedConstraint structs that we'll pass to heap_create_with_catalog,
841 	 * while raw defaults go into a list of RawColumnDefault structs that will
842 	 * be processed by AddRelationNewConstraints.  (We can't deal with raw
843 	 * expressions until we can do transformExpr.)
844 	 *
845 	 * We can set the atthasdef flags now in the tuple descriptor; this just
846 	 * saves StoreAttrDefault from having to do an immediate update of the
847 	 * pg_attribute rows.
848 	 */
849 	rawDefaults = NIL;
850 	cookedDefaults = NIL;
851 	attnum = 0;
852 
853 	foreach(listptr, stmt->tableElts)
854 	{
855 		ColumnDef  *colDef = lfirst(listptr);
856 		Form_pg_attribute attr;
857 
858 		attnum++;
859 		attr = TupleDescAttr(descriptor, attnum - 1);
860 
861 		if (colDef->raw_default != NULL)
862 		{
863 			RawColumnDefault *rawEnt;
864 
865 			Assert(colDef->cooked_default == NULL);
866 
867 			rawEnt = (RawColumnDefault *) palloc(sizeof(RawColumnDefault));
868 			rawEnt->attnum = attnum;
869 			rawEnt->raw_default = colDef->raw_default;
870 			rawEnt->missingMode = false;
871 			rawEnt->generated = colDef->generated;
872 			rawDefaults = lappend(rawDefaults, rawEnt);
873 			attr->atthasdef = true;
874 		}
875 		else if (colDef->cooked_default != NULL)
876 		{
877 			CookedConstraint *cooked;
878 
879 			cooked = (CookedConstraint *) palloc(sizeof(CookedConstraint));
880 			cooked->contype = CONSTR_DEFAULT;
881 			cooked->conoid = InvalidOid;	/* until created */
882 			cooked->name = NULL;
883 			cooked->attnum = attnum;
884 			cooked->expr = colDef->cooked_default;
885 			cooked->skip_validation = false;
886 			cooked->is_local = true;	/* not used for defaults */
887 			cooked->inhcount = 0;	/* ditto */
888 			cooked->is_no_inherit = false;
889 			cookedDefaults = lappend(cookedDefaults, cooked);
890 			attr->atthasdef = true;
891 		}
892 
893 		if (colDef->identity)
894 			attr->attidentity = colDef->identity;
895 
896 		if (colDef->generated)
897 			attr->attgenerated = colDef->generated;
898 
899 		if (colDef->compression)
900 			attr->attcompression = GetAttributeCompression(attr->atttypid,
901 														   colDef->compression);
902 	}
903 
904 	/*
905 	 * If the statement hasn't specified an access method, but we're defining
906 	 * a type of relation that needs one, use the default.
907 	 */
908 	if (stmt->accessMethod != NULL)
909 	{
910 		accessMethod = stmt->accessMethod;
911 
912 		if (partitioned)
913 			ereport(ERROR,
914 					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
915 					 errmsg("specifying a table access method is not supported on a partitioned table")));
916 
917 	}
918 	else if (relkind == RELKIND_RELATION ||
919 			 relkind == RELKIND_TOASTVALUE ||
920 			 relkind == RELKIND_MATVIEW)
921 		accessMethod = default_table_access_method;
922 
923 	/* look up the access method, verify it is for a table */
924 	if (accessMethod != NULL)
925 		accessMethodId = get_table_am_oid(accessMethod, false);
926 
927 	/*
928 	 * Create the relation.  Inherited defaults and constraints are passed in
929 	 * for immediate handling --- since they don't need parsing, they can be
930 	 * stored immediately.
931 	 */
932 	relationId = heap_create_with_catalog(relname,
933 										  namespaceId,
934 										  tablespaceId,
935 										  InvalidOid,
936 										  InvalidOid,
937 										  ofTypeId,
938 										  ownerId,
939 										  accessMethodId,
940 										  descriptor,
941 										  list_concat(cookedDefaults,
942 													  old_constraints),
943 										  relkind,
944 										  stmt->relation->relpersistence,
945 										  false,
946 										  false,
947 										  stmt->oncommit,
948 										  reloptions,
949 										  true,
950 										  allowSystemTableMods,
951 										  false,
952 										  InvalidOid,
953 										  typaddress);
954 
955 	/*
956 	 * We must bump the command counter to make the newly-created relation
957 	 * tuple visible for opening.
958 	 */
959 	CommandCounterIncrement();
960 
961 	/*
962 	 * Open the new relation and acquire exclusive lock on it.  This isn't
963 	 * really necessary for locking out other backends (since they can't see
964 	 * the new rel anyway until we commit), but it keeps the lock manager from
965 	 * complaining about deadlock risks.
966 	 */
967 	rel = relation_open(relationId, AccessExclusiveLock);
968 
969 	/*
970 	 * Now add any newly specified column default and generation expressions
971 	 * to the new relation.  These are passed to us in the form of raw
972 	 * parsetrees; we need to transform them to executable expression trees
973 	 * before they can be added. The most convenient way to do that is to
974 	 * apply the parser's transformExpr routine, but transformExpr doesn't
975 	 * work unless we have a pre-existing relation. So, the transformation has
976 	 * to be postponed to this final step of CREATE TABLE.
977 	 *
978 	 * This needs to be before processing the partitioning clauses because
979 	 * those could refer to generated columns.
980 	 */
981 	if (rawDefaults)
982 		AddRelationNewConstraints(rel, rawDefaults, NIL,
983 								  true, true, false, queryString);
984 
985 	/*
986 	 * Make column generation expressions visible for use by partitioning.
987 	 */
988 	CommandCounterIncrement();
989 
990 	/* Process and store partition bound, if any. */
991 	if (stmt->partbound)
992 	{
993 		PartitionBoundSpec *bound;
994 		ParseState *pstate;
995 		Oid			parentId = linitial_oid(inheritOids),
996 					defaultPartOid;
997 		Relation	parent,
998 					defaultRel = NULL;
999 		ParseNamespaceItem *nsitem;
1000 
1001 		/* Already have strong enough lock on the parent */
1002 		parent = table_open(parentId, NoLock);
1003 
1004 		/*
1005 		 * We are going to try to validate the partition bound specification
1006 		 * against the partition key of parentRel, so it better have one.
1007 		 */
1008 		if (parent->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
1009 			ereport(ERROR,
1010 					(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1011 					 errmsg("\"%s\" is not partitioned",
1012 							RelationGetRelationName(parent))));
1013 
1014 		/*
1015 		 * The partition constraint of the default partition depends on the
1016 		 * partition bounds of every other partition. It is possible that
1017 		 * another backend might be about to execute a query on the default
1018 		 * partition table, and that the query relies on previously cached
1019 		 * default partition constraints. We must therefore take a table lock
1020 		 * strong enough to prevent all queries on the default partition from
1021 		 * proceeding until we commit and send out a shared-cache-inval notice
1022 		 * that will make them update their index lists.
1023 		 *
1024 		 * Order of locking: The relation being added won't be visible to
1025 		 * other backends until it is committed, hence here in
1026 		 * DefineRelation() the order of locking the default partition and the
1027 		 * relation being added does not matter. But at all other places we
1028 		 * need to lock the default relation before we lock the relation being
1029 		 * added or removed i.e. we should take the lock in same order at all
1030 		 * the places such that lock parent, lock default partition and then
1031 		 * lock the partition so as to avoid a deadlock.
1032 		 */
1033 		defaultPartOid =
1034 			get_default_oid_from_partdesc(RelationGetPartitionDesc(parent,
1035 																   true));
1036 		if (OidIsValid(defaultPartOid))
1037 			defaultRel = table_open(defaultPartOid, AccessExclusiveLock);
1038 
1039 		/* Transform the bound values */
1040 		pstate = make_parsestate(NULL);
1041 		pstate->p_sourcetext = queryString;
1042 
1043 		/*
1044 		 * Add an nsitem containing this relation, so that transformExpr
1045 		 * called on partition bound expressions is able to report errors
1046 		 * using a proper context.
1047 		 */
1048 		nsitem = addRangeTableEntryForRelation(pstate, rel, AccessShareLock,
1049 											   NULL, false, false);
1050 		addNSItemToQuery(pstate, nsitem, false, true, true);
1051 
1052 		bound = transformPartitionBound(pstate, parent, stmt->partbound);
1053 
1054 		/*
1055 		 * Check first that the new partition's bound is valid and does not
1056 		 * overlap with any of existing partitions of the parent.
1057 		 */
1058 		check_new_partition_bound(relname, parent, bound, pstate);
1059 
1060 		/*
1061 		 * If the default partition exists, its partition constraints will
1062 		 * change after the addition of this new partition such that it won't
1063 		 * allow any row that qualifies for this new partition. So, check that
1064 		 * the existing data in the default partition satisfies the constraint
1065 		 * as it will exist after adding this partition.
1066 		 */
1067 		if (OidIsValid(defaultPartOid))
1068 		{
1069 			check_default_partition_contents(parent, defaultRel, bound);
1070 			/* Keep the lock until commit. */
1071 			table_close(defaultRel, NoLock);
1072 		}
1073 
1074 		/* Update the pg_class entry. */
1075 		StorePartitionBound(rel, parent, bound);
1076 
1077 		table_close(parent, NoLock);
1078 	}
1079 
1080 	/* Store inheritance information for new rel. */
1081 	StoreCatalogInheritance(relationId, inheritOids, stmt->partbound != NULL);
1082 
1083 	/*
1084 	 * Process the partitioning specification (if any) and store the partition
1085 	 * key information into the catalog.
1086 	 */
1087 	if (partitioned)
1088 	{
1089 		ParseState *pstate;
1090 		char		strategy;
1091 		int			partnatts;
1092 		AttrNumber	partattrs[PARTITION_MAX_KEYS];
1093 		Oid			partopclass[PARTITION_MAX_KEYS];
1094 		Oid			partcollation[PARTITION_MAX_KEYS];
1095 		List	   *partexprs = NIL;
1096 
1097 		pstate = make_parsestate(NULL);
1098 		pstate->p_sourcetext = queryString;
1099 
1100 		partnatts = list_length(stmt->partspec->partParams);
1101 
1102 		/* Protect fixed-size arrays here and in executor */
1103 		if (partnatts > PARTITION_MAX_KEYS)
1104 			ereport(ERROR,
1105 					(errcode(ERRCODE_TOO_MANY_COLUMNS),
1106 					 errmsg("cannot partition using more than %d columns",
1107 							PARTITION_MAX_KEYS)));
1108 
1109 		/*
1110 		 * We need to transform the raw parsetrees corresponding to partition
1111 		 * expressions into executable expression trees.  Like column defaults
1112 		 * and CHECK constraints, we could not have done the transformation
1113 		 * earlier.
1114 		 */
1115 		stmt->partspec = transformPartitionSpec(rel, stmt->partspec,
1116 												&strategy);
1117 
1118 		ComputePartitionAttrs(pstate, rel, stmt->partspec->partParams,
1119 							  partattrs, &partexprs, partopclass,
1120 							  partcollation, strategy);
1121 
1122 		StorePartitionKey(rel, strategy, partnatts, partattrs, partexprs,
1123 						  partopclass, partcollation);
1124 
1125 		/* make it all visible */
1126 		CommandCounterIncrement();
1127 	}
1128 
1129 	/*
1130 	 * If we're creating a partition, create now all the indexes, triggers,
1131 	 * FKs defined in the parent.
1132 	 *
1133 	 * We can't do it earlier, because DefineIndex wants to know the partition
1134 	 * key which we just stored.
1135 	 */
1136 	if (stmt->partbound)
1137 	{
1138 		Oid			parentId = linitial_oid(inheritOids);
1139 		Relation	parent;
1140 		List	   *idxlist;
1141 		ListCell   *cell;
1142 
1143 		/* Already have strong enough lock on the parent */
1144 		parent = table_open(parentId, NoLock);
1145 		idxlist = RelationGetIndexList(parent);
1146 
1147 		/*
1148 		 * For each index in the parent table, create one in the partition
1149 		 */
1150 		foreach(cell, idxlist)
1151 		{
1152 			Relation	idxRel = index_open(lfirst_oid(cell), AccessShareLock);
1153 			AttrMap    *attmap;
1154 			IndexStmt  *idxstmt;
1155 			Oid			constraintOid;
1156 
1157 			if (rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
1158 			{
1159 				if (idxRel->rd_index->indisunique)
1160 					ereport(ERROR,
1161 							(errcode(ERRCODE_WRONG_OBJECT_TYPE),
1162 							 errmsg("cannot create foreign partition of partitioned table \"%s\"",
1163 									RelationGetRelationName(parent)),
1164 							 errdetail("Table \"%s\" contains indexes that are unique.",
1165 									   RelationGetRelationName(parent))));
1166 				else
1167 				{
1168 					index_close(idxRel, AccessShareLock);
1169 					continue;
1170 				}
1171 			}
1172 
1173 			attmap = build_attrmap_by_name(RelationGetDescr(rel),
1174 										   RelationGetDescr(parent));
1175 			idxstmt =
1176 				generateClonedIndexStmt(NULL, idxRel,
1177 										attmap, &constraintOid);
1178 			DefineIndex(RelationGetRelid(rel),
1179 						idxstmt,
1180 						InvalidOid,
1181 						RelationGetRelid(idxRel),
1182 						constraintOid,
1183 						false, false, false, false, false);
1184 
1185 			index_close(idxRel, AccessShareLock);
1186 		}
1187 
1188 		list_free(idxlist);
1189 
1190 		/*
1191 		 * If there are any row-level triggers, clone them to the new
1192 		 * partition.
1193 		 */
1194 		if (parent->trigdesc != NULL)
1195 			CloneRowTriggersToPartition(parent, rel);
1196 
1197 		/*
1198 		 * And foreign keys too.  Note that because we're freshly creating the
1199 		 * table, there is no need to verify these new constraints.
1200 		 */
1201 		CloneForeignKeyConstraints(NULL, parent, rel);
1202 
1203 		table_close(parent, NoLock);
1204 	}
1205 
1206 	/*
1207 	 * Now add any newly specified CHECK constraints to the new relation. Same
1208 	 * as for defaults above, but these need to come after partitioning is set
1209 	 * up.
1210 	 */
1211 	if (stmt->constraints)
1212 		AddRelationNewConstraints(rel, NIL, stmt->constraints,
1213 								  true, true, false, queryString);
1214 
1215 	ObjectAddressSet(address, RelationRelationId, relationId);
1216 
1217 	/*
1218 	 * Clean up.  We keep lock on new relation (although it shouldn't be
1219 	 * visible to anyone else anyway, until commit).
1220 	 */
1221 	relation_close(rel, NoLock);
1222 
1223 	return address;
1224 }
1225 
1226 /*
1227  * Emit the right error or warning message for a "DROP" command issued on a
1228  * non-existent relation
1229  */
1230 static void
DropErrorMsgNonExistent(RangeVar * rel,char rightkind,bool missing_ok)1231 DropErrorMsgNonExistent(RangeVar *rel, char rightkind, bool missing_ok)
1232 {
1233 	const struct dropmsgstrings *rentry;
1234 
1235 	if (rel->schemaname != NULL &&
1236 		!OidIsValid(LookupNamespaceNoError(rel->schemaname)))
1237 	{
1238 		if (!missing_ok)
1239 		{
1240 			ereport(ERROR,
1241 					(errcode(ERRCODE_UNDEFINED_SCHEMA),
1242 					 errmsg("schema \"%s\" does not exist", rel->schemaname)));
1243 		}
1244 		else
1245 		{
1246 			ereport(NOTICE,
1247 					(errmsg("schema \"%s\" does not exist, skipping",
1248 							rel->schemaname)));
1249 		}
1250 		return;
1251 	}
1252 
1253 	for (rentry = dropmsgstringarray; rentry->kind != '\0'; rentry++)
1254 	{
1255 		if (rentry->kind == rightkind)
1256 		{
1257 			if (!missing_ok)
1258 			{
1259 				ereport(ERROR,
1260 						(errcode(rentry->nonexistent_code),
1261 						 errmsg(rentry->nonexistent_msg, rel->relname)));
1262 			}
1263 			else
1264 			{
1265 				ereport(NOTICE, (errmsg(rentry->skipping_msg, rel->relname)));
1266 				break;
1267 			}
1268 		}
1269 	}
1270 
1271 	Assert(rentry->kind != '\0');	/* Should be impossible */
1272 }
1273 
1274 /*
1275  * Emit the right error message for a "DROP" command issued on a
1276  * relation of the wrong type
1277  */
1278 static void
DropErrorMsgWrongType(const char * relname,char wrongkind,char rightkind)1279 DropErrorMsgWrongType(const char *relname, char wrongkind, char rightkind)
1280 {
1281 	const struct dropmsgstrings *rentry;
1282 	const struct dropmsgstrings *wentry;
1283 
1284 	for (rentry = dropmsgstringarray; rentry->kind != '\0'; rentry++)
1285 		if (rentry->kind == rightkind)
1286 			break;
1287 	Assert(rentry->kind != '\0');
1288 
1289 	for (wentry = dropmsgstringarray; wentry->kind != '\0'; wentry++)
1290 		if (wentry->kind == wrongkind)
1291 			break;
1292 	/* wrongkind could be something we don't have in our table... */
1293 
1294 	ereport(ERROR,
1295 			(errcode(ERRCODE_WRONG_OBJECT_TYPE),
1296 			 errmsg(rentry->nota_msg, relname),
1297 			 (wentry->kind != '\0') ? errhint("%s", _(wentry->drophint_msg)) : 0));
1298 }
1299 
1300 /*
1301  * RemoveRelations
1302  *		Implements DROP TABLE, DROP INDEX, DROP SEQUENCE, DROP VIEW,
1303  *		DROP MATERIALIZED VIEW, DROP FOREIGN TABLE
1304  */
1305 void
RemoveRelations(DropStmt * drop)1306 RemoveRelations(DropStmt *drop)
1307 {
1308 	ObjectAddresses *objects;
1309 	char		relkind;
1310 	ListCell   *cell;
1311 	int			flags = 0;
1312 	LOCKMODE	lockmode = AccessExclusiveLock;
1313 
1314 	/* DROP CONCURRENTLY uses a weaker lock, and has some restrictions */
1315 	if (drop->concurrent)
1316 	{
1317 		/*
1318 		 * Note that for temporary relations this lock may get upgraded later
1319 		 * on, but as no other session can access a temporary relation, this
1320 		 * is actually fine.
1321 		 */
1322 		lockmode = ShareUpdateExclusiveLock;
1323 		Assert(drop->removeType == OBJECT_INDEX);
1324 		if (list_length(drop->objects) != 1)
1325 			ereport(ERROR,
1326 					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1327 					 errmsg("DROP INDEX CONCURRENTLY does not support dropping multiple objects")));
1328 		if (drop->behavior == DROP_CASCADE)
1329 			ereport(ERROR,
1330 					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1331 					 errmsg("DROP INDEX CONCURRENTLY does not support CASCADE")));
1332 	}
1333 
1334 	/*
1335 	 * First we identify all the relations, then we delete them in a single
1336 	 * performMultipleDeletions() call.  This is to avoid unwanted DROP
1337 	 * RESTRICT errors if one of the relations depends on another.
1338 	 */
1339 
1340 	/* Determine required relkind */
1341 	switch (drop->removeType)
1342 	{
1343 		case OBJECT_TABLE:
1344 			relkind = RELKIND_RELATION;
1345 			break;
1346 
1347 		case OBJECT_INDEX:
1348 			relkind = RELKIND_INDEX;
1349 			break;
1350 
1351 		case OBJECT_SEQUENCE:
1352 			relkind = RELKIND_SEQUENCE;
1353 			break;
1354 
1355 		case OBJECT_VIEW:
1356 			relkind = RELKIND_VIEW;
1357 			break;
1358 
1359 		case OBJECT_MATVIEW:
1360 			relkind = RELKIND_MATVIEW;
1361 			break;
1362 
1363 		case OBJECT_FOREIGN_TABLE:
1364 			relkind = RELKIND_FOREIGN_TABLE;
1365 			break;
1366 
1367 		default:
1368 			elog(ERROR, "unrecognized drop object type: %d",
1369 				 (int) drop->removeType);
1370 			relkind = 0;		/* keep compiler quiet */
1371 			break;
1372 	}
1373 
1374 	/* Lock and validate each relation; build a list of object addresses */
1375 	objects = new_object_addresses();
1376 
1377 	foreach(cell, drop->objects)
1378 	{
1379 		RangeVar   *rel = makeRangeVarFromNameList((List *) lfirst(cell));
1380 		Oid			relOid;
1381 		ObjectAddress obj;
1382 		struct DropRelationCallbackState state;
1383 
1384 		/*
1385 		 * These next few steps are a great deal like relation_openrv, but we
1386 		 * don't bother building a relcache entry since we don't need it.
1387 		 *
1388 		 * Check for shared-cache-inval messages before trying to access the
1389 		 * relation.  This is needed to cover the case where the name
1390 		 * identifies a rel that has been dropped and recreated since the
1391 		 * start of our transaction: if we don't flush the old syscache entry,
1392 		 * then we'll latch onto that entry and suffer an error later.
1393 		 */
1394 		AcceptInvalidationMessages();
1395 
1396 		/* Look up the appropriate relation using namespace search. */
1397 		state.relkind = relkind;
1398 		state.heapOid = InvalidOid;
1399 		state.partParentOid = InvalidOid;
1400 		state.concurrent = drop->concurrent;
1401 		relOid = RangeVarGetRelidExtended(rel, lockmode, RVR_MISSING_OK,
1402 										  RangeVarCallbackForDropRelation,
1403 										  (void *) &state);
1404 
1405 		/* Not there? */
1406 		if (!OidIsValid(relOid))
1407 		{
1408 			DropErrorMsgNonExistent(rel, relkind, drop->missing_ok);
1409 			continue;
1410 		}
1411 
1412 		/*
1413 		 * Decide if concurrent mode needs to be used here or not.  The
1414 		 * relation persistence cannot be known without its OID.
1415 		 */
1416 		if (drop->concurrent &&
1417 			get_rel_persistence(relOid) != RELPERSISTENCE_TEMP)
1418 		{
1419 			Assert(list_length(drop->objects) == 1 &&
1420 				   drop->removeType == OBJECT_INDEX);
1421 			flags |= PERFORM_DELETION_CONCURRENTLY;
1422 		}
1423 
1424 		/*
1425 		 * Concurrent index drop cannot be used with partitioned indexes,
1426 		 * either.
1427 		 */
1428 		if ((flags & PERFORM_DELETION_CONCURRENTLY) != 0 &&
1429 			get_rel_relkind(relOid) == RELKIND_PARTITIONED_INDEX)
1430 			ereport(ERROR,
1431 					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1432 					 errmsg("cannot drop partitioned index \"%s\" concurrently",
1433 							rel->relname)));
1434 
1435 		/* OK, we're ready to delete this one */
1436 		obj.classId = RelationRelationId;
1437 		obj.objectId = relOid;
1438 		obj.objectSubId = 0;
1439 
1440 		add_exact_object_address(&obj, objects);
1441 	}
1442 
1443 	performMultipleDeletions(objects, drop->behavior, flags);
1444 
1445 	free_object_addresses(objects);
1446 }
1447 
1448 /*
1449  * Before acquiring a table lock, check whether we have sufficient rights.
1450  * In the case of DROP INDEX, also try to lock the table before the index.
1451  * Also, if the table to be dropped is a partition, we try to lock the parent
1452  * first.
1453  */
1454 static void
RangeVarCallbackForDropRelation(const RangeVar * rel,Oid relOid,Oid oldRelOid,void * arg)1455 RangeVarCallbackForDropRelation(const RangeVar *rel, Oid relOid, Oid oldRelOid,
1456 								void *arg)
1457 {
1458 	HeapTuple	tuple;
1459 	struct DropRelationCallbackState *state;
1460 	char		relkind;
1461 	char		expected_relkind;
1462 	bool		is_partition;
1463 	Form_pg_class classform;
1464 	LOCKMODE	heap_lockmode;
1465 	bool		invalid_system_index = false;
1466 
1467 	state = (struct DropRelationCallbackState *) arg;
1468 	relkind = state->relkind;
1469 	heap_lockmode = state->concurrent ?
1470 		ShareUpdateExclusiveLock : AccessExclusiveLock;
1471 
1472 	/*
1473 	 * If we previously locked some other index's heap, and the name we're
1474 	 * looking up no longer refers to that relation, release the now-useless
1475 	 * lock.
1476 	 */
1477 	if (relOid != oldRelOid && OidIsValid(state->heapOid))
1478 	{
1479 		UnlockRelationOid(state->heapOid, heap_lockmode);
1480 		state->heapOid = InvalidOid;
1481 	}
1482 
1483 	/*
1484 	 * Similarly, if we previously locked some other partition's heap, and the
1485 	 * name we're looking up no longer refers to that relation, release the
1486 	 * now-useless lock.
1487 	 */
1488 	if (relOid != oldRelOid && OidIsValid(state->partParentOid))
1489 	{
1490 		UnlockRelationOid(state->partParentOid, AccessExclusiveLock);
1491 		state->partParentOid = InvalidOid;
1492 	}
1493 
1494 	/* Didn't find a relation, so no need for locking or permission checks. */
1495 	if (!OidIsValid(relOid))
1496 		return;
1497 
1498 	tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relOid));
1499 	if (!HeapTupleIsValid(tuple))
1500 		return;					/* concurrently dropped, so nothing to do */
1501 	classform = (Form_pg_class) GETSTRUCT(tuple);
1502 	is_partition = classform->relispartition;
1503 
1504 	/*
1505 	 * Both RELKIND_RELATION and RELKIND_PARTITIONED_TABLE are OBJECT_TABLE,
1506 	 * but RemoveRelations() can only pass one relkind for a given relation.
1507 	 * It chooses RELKIND_RELATION for both regular and partitioned tables.
1508 	 * That means we must be careful before giving the wrong type error when
1509 	 * the relation is RELKIND_PARTITIONED_TABLE.  An equivalent problem
1510 	 * exists with indexes.
1511 	 */
1512 	if (classform->relkind == RELKIND_PARTITIONED_TABLE)
1513 		expected_relkind = RELKIND_RELATION;
1514 	else if (classform->relkind == RELKIND_PARTITIONED_INDEX)
1515 		expected_relkind = RELKIND_INDEX;
1516 	else
1517 		expected_relkind = classform->relkind;
1518 
1519 	if (relkind != expected_relkind)
1520 		DropErrorMsgWrongType(rel->relname, classform->relkind, relkind);
1521 
1522 	/* Allow DROP to either table owner or schema owner */
1523 	if (!pg_class_ownercheck(relOid, GetUserId()) &&
1524 		!pg_namespace_ownercheck(classform->relnamespace, GetUserId()))
1525 		aclcheck_error(ACLCHECK_NOT_OWNER, get_relkind_objtype(get_rel_relkind(relOid)),
1526 					   rel->relname);
1527 
1528 	/*
1529 	 * Check the case of a system index that might have been invalidated by a
1530 	 * failed concurrent process and allow its drop. For the time being, this
1531 	 * only concerns indexes of toast relations that became invalid during a
1532 	 * REINDEX CONCURRENTLY process.
1533 	 */
1534 	if (IsSystemClass(relOid, classform) && relkind == RELKIND_INDEX)
1535 	{
1536 		HeapTuple	locTuple;
1537 		Form_pg_index indexform;
1538 		bool		indisvalid;
1539 
1540 		locTuple = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(relOid));
1541 		if (!HeapTupleIsValid(locTuple))
1542 		{
1543 			ReleaseSysCache(tuple);
1544 			return;
1545 		}
1546 
1547 		indexform = (Form_pg_index) GETSTRUCT(locTuple);
1548 		indisvalid = indexform->indisvalid;
1549 		ReleaseSysCache(locTuple);
1550 
1551 		/* Mark object as being an invalid index of system catalogs */
1552 		if (!indisvalid)
1553 			invalid_system_index = true;
1554 	}
1555 
1556 	/* In the case of an invalid index, it is fine to bypass this check */
1557 	if (!invalid_system_index && !allowSystemTableMods && IsSystemClass(relOid, classform))
1558 		ereport(ERROR,
1559 				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1560 				 errmsg("permission denied: \"%s\" is a system catalog",
1561 						rel->relname)));
1562 
1563 	ReleaseSysCache(tuple);
1564 
1565 	/*
1566 	 * In DROP INDEX, attempt to acquire lock on the parent table before
1567 	 * locking the index.  index_drop() will need this anyway, and since
1568 	 * regular queries lock tables before their indexes, we risk deadlock if
1569 	 * we do it the other way around.  No error if we don't find a pg_index
1570 	 * entry, though --- the relation may have been dropped.
1571 	 */
1572 	if ((relkind == RELKIND_INDEX || relkind == RELKIND_PARTITIONED_INDEX) &&
1573 		relOid != oldRelOid)
1574 	{
1575 		state->heapOid = IndexGetRelation(relOid, true);
1576 		if (OidIsValid(state->heapOid))
1577 			LockRelationOid(state->heapOid, heap_lockmode);
1578 	}
1579 
1580 	/*
1581 	 * Similarly, if the relation is a partition, we must acquire lock on its
1582 	 * parent before locking the partition.  That's because queries lock the
1583 	 * parent before its partitions, so we risk deadlock it we do it the other
1584 	 * way around.
1585 	 */
1586 	if (is_partition && relOid != oldRelOid)
1587 	{
1588 		state->partParentOid = get_partition_parent(relOid, true);
1589 		if (OidIsValid(state->partParentOid))
1590 			LockRelationOid(state->partParentOid, AccessExclusiveLock);
1591 	}
1592 }
1593 
1594 /*
1595  * ExecuteTruncate
1596  *		Executes a TRUNCATE command.
1597  *
1598  * This is a multi-relation truncate.  We first open and grab exclusive
1599  * lock on all relations involved, checking permissions and otherwise
1600  * verifying that the relation is OK for truncation.  Note that if relations
1601  * are foreign tables, at this stage, we have not yet checked that their
1602  * foreign data in external data sources are OK for truncation.  These are
1603  * checked when foreign data are actually truncated later.  In CASCADE mode,
1604  * relations having FK references to the targeted relations are automatically
1605  * added to the group; in RESTRICT mode, we check that all FK references are
1606  * internal to the group that's being truncated.  Finally all the relations
1607  * are truncated and reindexed.
1608  */
1609 void
ExecuteTruncate(TruncateStmt * stmt)1610 ExecuteTruncate(TruncateStmt *stmt)
1611 {
1612 	List	   *rels = NIL;
1613 	List	   *relids = NIL;
1614 	List	   *relids_logged = NIL;
1615 	ListCell   *cell;
1616 
1617 	/*
1618 	 * Open, exclusive-lock, and check all the explicitly-specified relations
1619 	 */
1620 	foreach(cell, stmt->relations)
1621 	{
1622 		RangeVar   *rv = lfirst(cell);
1623 		Relation	rel;
1624 		bool		recurse = rv->inh;
1625 		Oid			myrelid;
1626 		LOCKMODE	lockmode = AccessExclusiveLock;
1627 
1628 		myrelid = RangeVarGetRelidExtended(rv, lockmode,
1629 										   0, RangeVarCallbackForTruncate,
1630 										   NULL);
1631 
1632 		/* don't throw error for "TRUNCATE foo, foo" */
1633 		if (list_member_oid(relids, myrelid))
1634 			continue;
1635 
1636 		/* open the relation, we already hold a lock on it */
1637 		rel = table_open(myrelid, NoLock);
1638 
1639 		/*
1640 		 * RangeVarGetRelidExtended() has done most checks with its callback,
1641 		 * but other checks with the now-opened Relation remain.
1642 		 */
1643 		truncate_check_activity(rel);
1644 
1645 		rels = lappend(rels, rel);
1646 		relids = lappend_oid(relids, myrelid);
1647 
1648 		/* Log this relation only if needed for logical decoding */
1649 		if (RelationIsLogicallyLogged(rel))
1650 			relids_logged = lappend_oid(relids_logged, myrelid);
1651 
1652 		if (recurse)
1653 		{
1654 			ListCell   *child;
1655 			List	   *children;
1656 
1657 			children = find_all_inheritors(myrelid, lockmode, NULL);
1658 
1659 			foreach(child, children)
1660 			{
1661 				Oid			childrelid = lfirst_oid(child);
1662 
1663 				if (list_member_oid(relids, childrelid))
1664 					continue;
1665 
1666 				/* find_all_inheritors already got lock */
1667 				rel = table_open(childrelid, NoLock);
1668 
1669 				/*
1670 				 * It is possible that the parent table has children that are
1671 				 * temp tables of other backends.  We cannot safely access
1672 				 * such tables (because of buffering issues), and the best
1673 				 * thing to do is to silently ignore them.  Note that this
1674 				 * check is the same as one of the checks done in
1675 				 * truncate_check_activity() called below, still it is kept
1676 				 * here for simplicity.
1677 				 */
1678 				if (RELATION_IS_OTHER_TEMP(rel))
1679 				{
1680 					table_close(rel, lockmode);
1681 					continue;
1682 				}
1683 
1684 				/*
1685 				 * Inherited TRUNCATE commands perform access permission
1686 				 * checks on the parent table only. So we skip checking the
1687 				 * children's permissions and don't call
1688 				 * truncate_check_perms() here.
1689 				 */
1690 				truncate_check_rel(RelationGetRelid(rel), rel->rd_rel);
1691 				truncate_check_activity(rel);
1692 
1693 				rels = lappend(rels, rel);
1694 				relids = lappend_oid(relids, childrelid);
1695 
1696 				/* Log this relation only if needed for logical decoding */
1697 				if (RelationIsLogicallyLogged(rel))
1698 					relids_logged = lappend_oid(relids_logged, childrelid);
1699 			}
1700 		}
1701 		else if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
1702 			ereport(ERROR,
1703 					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
1704 					 errmsg("cannot truncate only a partitioned table"),
1705 					 errhint("Do not specify the ONLY keyword, or use TRUNCATE ONLY on the partitions directly.")));
1706 	}
1707 
1708 	ExecuteTruncateGuts(rels, relids, relids_logged,
1709 						stmt->behavior, stmt->restart_seqs);
1710 
1711 	/* And close the rels */
1712 	foreach(cell, rels)
1713 	{
1714 		Relation	rel = (Relation) lfirst(cell);
1715 
1716 		table_close(rel, NoLock);
1717 	}
1718 }
1719 
1720 /*
1721  * ExecuteTruncateGuts
1722  *
1723  * Internal implementation of TRUNCATE.  This is called by the actual TRUNCATE
1724  * command (see above) as well as replication subscribers that execute a
1725  * replicated TRUNCATE action.
1726  *
1727  * explicit_rels is the list of Relations to truncate that the command
1728  * specified.  relids is the list of Oids corresponding to explicit_rels.
1729  * relids_logged is the list of Oids (a subset of relids) that require
1730  * WAL-logging.  This is all a bit redundant, but the existing callers have
1731  * this information handy in this form.
1732  */
1733 void
ExecuteTruncateGuts(List * explicit_rels,List * relids,List * relids_logged,DropBehavior behavior,bool restart_seqs)1734 ExecuteTruncateGuts(List *explicit_rels,
1735 					List *relids,
1736 					List *relids_logged,
1737 					DropBehavior behavior, bool restart_seqs)
1738 {
1739 	List	   *rels;
1740 	List	   *seq_relids = NIL;
1741 	HTAB	   *ft_htab = NULL;
1742 	EState	   *estate;
1743 	ResultRelInfo *resultRelInfos;
1744 	ResultRelInfo *resultRelInfo;
1745 	SubTransactionId mySubid;
1746 	ListCell   *cell;
1747 	Oid		   *logrelids;
1748 
1749 	/*
1750 	 * Check the explicitly-specified relations.
1751 	 *
1752 	 * In CASCADE mode, suck in all referencing relations as well.  This
1753 	 * requires multiple iterations to find indirectly-dependent relations. At
1754 	 * each phase, we need to exclusive-lock new rels before looking for their
1755 	 * dependencies, else we might miss something.  Also, we check each rel as
1756 	 * soon as we open it, to avoid a faux pas such as holding lock for a long
1757 	 * time on a rel we have no permissions for.
1758 	 */
1759 	rels = list_copy(explicit_rels);
1760 	if (behavior == DROP_CASCADE)
1761 	{
1762 		for (;;)
1763 		{
1764 			List	   *newrelids;
1765 
1766 			newrelids = heap_truncate_find_FKs(relids);
1767 			if (newrelids == NIL)
1768 				break;			/* nothing else to add */
1769 
1770 			foreach(cell, newrelids)
1771 			{
1772 				Oid			relid = lfirst_oid(cell);
1773 				Relation	rel;
1774 
1775 				rel = table_open(relid, AccessExclusiveLock);
1776 				ereport(NOTICE,
1777 						(errmsg("truncate cascades to table \"%s\"",
1778 								RelationGetRelationName(rel))));
1779 				truncate_check_rel(relid, rel->rd_rel);
1780 				truncate_check_perms(relid, rel->rd_rel);
1781 				truncate_check_activity(rel);
1782 				rels = lappend(rels, rel);
1783 				relids = lappend_oid(relids, relid);
1784 
1785 				/* Log this relation only if needed for logical decoding */
1786 				if (RelationIsLogicallyLogged(rel))
1787 					relids_logged = lappend_oid(relids_logged, relid);
1788 			}
1789 		}
1790 	}
1791 
1792 	/*
1793 	 * Check foreign key references.  In CASCADE mode, this should be
1794 	 * unnecessary since we just pulled in all the references; but as a
1795 	 * cross-check, do it anyway if in an Assert-enabled build.
1796 	 */
1797 #ifdef USE_ASSERT_CHECKING
1798 	heap_truncate_check_FKs(rels, false);
1799 #else
1800 	if (behavior == DROP_RESTRICT)
1801 		heap_truncate_check_FKs(rels, false);
1802 #endif
1803 
1804 	/*
1805 	 * If we are asked to restart sequences, find all the sequences, lock them
1806 	 * (we need AccessExclusiveLock for ResetSequence), and check permissions.
1807 	 * We want to do this early since it's pointless to do all the truncation
1808 	 * work only to fail on sequence permissions.
1809 	 */
1810 	if (restart_seqs)
1811 	{
1812 		foreach(cell, rels)
1813 		{
1814 			Relation	rel = (Relation) lfirst(cell);
1815 			List	   *seqlist = getOwnedSequences(RelationGetRelid(rel));
1816 			ListCell   *seqcell;
1817 
1818 			foreach(seqcell, seqlist)
1819 			{
1820 				Oid			seq_relid = lfirst_oid(seqcell);
1821 				Relation	seq_rel;
1822 
1823 				seq_rel = relation_open(seq_relid, AccessExclusiveLock);
1824 
1825 				/* This check must match AlterSequence! */
1826 				if (!pg_class_ownercheck(seq_relid, GetUserId()))
1827 					aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_SEQUENCE,
1828 								   RelationGetRelationName(seq_rel));
1829 
1830 				seq_relids = lappend_oid(seq_relids, seq_relid);
1831 
1832 				relation_close(seq_rel, NoLock);
1833 			}
1834 		}
1835 	}
1836 
1837 	/* Prepare to catch AFTER triggers. */
1838 	AfterTriggerBeginQuery();
1839 
1840 	/*
1841 	 * To fire triggers, we'll need an EState as well as a ResultRelInfo for
1842 	 * each relation.  We don't need to call ExecOpenIndices, though.
1843 	 *
1844 	 * We put the ResultRelInfos in the es_opened_result_relations list, even
1845 	 * though we don't have a range table and don't populate the
1846 	 * es_result_relations array.  That's a bit bogus, but it's enough to make
1847 	 * ExecGetTriggerResultRel() find them.
1848 	 */
1849 	estate = CreateExecutorState();
1850 	resultRelInfos = (ResultRelInfo *)
1851 		palloc(list_length(rels) * sizeof(ResultRelInfo));
1852 	resultRelInfo = resultRelInfos;
1853 	foreach(cell, rels)
1854 	{
1855 		Relation	rel = (Relation) lfirst(cell);
1856 
1857 		InitResultRelInfo(resultRelInfo,
1858 						  rel,
1859 						  0,	/* dummy rangetable index */
1860 						  NULL,
1861 						  0);
1862 		estate->es_opened_result_relations =
1863 			lappend(estate->es_opened_result_relations, resultRelInfo);
1864 		resultRelInfo++;
1865 	}
1866 
1867 	/*
1868 	 * Process all BEFORE STATEMENT TRUNCATE triggers before we begin
1869 	 * truncating (this is because one of them might throw an error). Also, if
1870 	 * we were to allow them to prevent statement execution, that would need
1871 	 * to be handled here.
1872 	 */
1873 	resultRelInfo = resultRelInfos;
1874 	foreach(cell, rels)
1875 	{
1876 		ExecBSTruncateTriggers(estate, resultRelInfo);
1877 		resultRelInfo++;
1878 	}
1879 
1880 	/*
1881 	 * OK, truncate each table.
1882 	 */
1883 	mySubid = GetCurrentSubTransactionId();
1884 
1885 	foreach(cell, rels)
1886 	{
1887 		Relation	rel = (Relation) lfirst(cell);
1888 
1889 		/* Skip partitioned tables as there is nothing to do */
1890 		if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
1891 			continue;
1892 
1893 		/*
1894 		 * Build the lists of foreign tables belonging to each foreign server
1895 		 * and pass each list to the foreign data wrapper's callback function,
1896 		 * so that each server can truncate its all foreign tables in bulk.
1897 		 * Each list is saved as a single entry in a hash table that uses the
1898 		 * server OID as lookup key.
1899 		 */
1900 		if (rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
1901 		{
1902 			Oid			serverid = GetForeignServerIdByRelId(RelationGetRelid(rel));
1903 			bool		found;
1904 			ForeignTruncateInfo *ft_info;
1905 
1906 			/* First time through, initialize hashtable for foreign tables */
1907 			if (!ft_htab)
1908 			{
1909 				HASHCTL		hctl;
1910 
1911 				memset(&hctl, 0, sizeof(HASHCTL));
1912 				hctl.keysize = sizeof(Oid);
1913 				hctl.entrysize = sizeof(ForeignTruncateInfo);
1914 				hctl.hcxt = CurrentMemoryContext;
1915 
1916 				ft_htab = hash_create("TRUNCATE for Foreign Tables",
1917 									  32,	/* start small and extend */
1918 									  &hctl,
1919 									  HASH_ELEM | HASH_BLOBS | HASH_CONTEXT);
1920 			}
1921 
1922 			/* Find or create cached entry for the foreign table */
1923 			ft_info = hash_search(ft_htab, &serverid, HASH_ENTER, &found);
1924 			if (!found)
1925 			{
1926 				ft_info->serverid = serverid;
1927 				ft_info->rels = NIL;
1928 			}
1929 
1930 			/*
1931 			 * Save the foreign table in the entry of the server that the
1932 			 * foreign table belongs to.
1933 			 */
1934 			ft_info->rels = lappend(ft_info->rels, rel);
1935 			continue;
1936 		}
1937 
1938 		/*
1939 		 * Normally, we need a transaction-safe truncation here.  However, if
1940 		 * the table was either created in the current (sub)transaction or has
1941 		 * a new relfilenode in the current (sub)transaction, then we can just
1942 		 * truncate it in-place, because a rollback would cause the whole
1943 		 * table or the current physical file to be thrown away anyway.
1944 		 */
1945 		if (rel->rd_createSubid == mySubid ||
1946 			rel->rd_newRelfilenodeSubid == mySubid)
1947 		{
1948 			/* Immediate, non-rollbackable truncation is OK */
1949 			heap_truncate_one_rel(rel);
1950 		}
1951 		else
1952 		{
1953 			Oid			heap_relid;
1954 			Oid			toast_relid;
1955 			ReindexParams reindex_params = {0};
1956 
1957 			/*
1958 			 * This effectively deletes all rows in the table, and may be done
1959 			 * in a serializable transaction.  In that case we must record a
1960 			 * rw-conflict in to this transaction from each transaction
1961 			 * holding a predicate lock on the table.
1962 			 */
1963 			CheckTableForSerializableConflictIn(rel);
1964 
1965 			/*
1966 			 * Need the full transaction-safe pushups.
1967 			 *
1968 			 * Create a new empty storage file for the relation, and assign it
1969 			 * as the relfilenode value. The old storage file is scheduled for
1970 			 * deletion at commit.
1971 			 */
1972 			RelationSetNewRelfilenode(rel, rel->rd_rel->relpersistence);
1973 
1974 			heap_relid = RelationGetRelid(rel);
1975 
1976 			/*
1977 			 * The same for the toast table, if any.
1978 			 */
1979 			toast_relid = rel->rd_rel->reltoastrelid;
1980 			if (OidIsValid(toast_relid))
1981 			{
1982 				Relation	toastrel = relation_open(toast_relid,
1983 													 AccessExclusiveLock);
1984 
1985 				RelationSetNewRelfilenode(toastrel,
1986 										  toastrel->rd_rel->relpersistence);
1987 				table_close(toastrel, NoLock);
1988 			}
1989 
1990 			/*
1991 			 * Reconstruct the indexes to match, and we're done.
1992 			 */
1993 			reindex_relation(heap_relid, REINDEX_REL_PROCESS_TOAST,
1994 							 &reindex_params);
1995 		}
1996 
1997 		pgstat_count_truncate(rel);
1998 	}
1999 
2000 	/* Now go through the hash table, and truncate foreign tables */
2001 	if (ft_htab)
2002 	{
2003 		ForeignTruncateInfo *ft_info;
2004 		HASH_SEQ_STATUS seq;
2005 
2006 		hash_seq_init(&seq, ft_htab);
2007 
2008 		PG_TRY();
2009 		{
2010 			while ((ft_info = hash_seq_search(&seq)) != NULL)
2011 			{
2012 				FdwRoutine *routine = GetFdwRoutineByServerId(ft_info->serverid);
2013 
2014 				/* truncate_check_rel() has checked that already */
2015 				Assert(routine->ExecForeignTruncate != NULL);
2016 
2017 				routine->ExecForeignTruncate(ft_info->rels,
2018 											 behavior,
2019 											 restart_seqs);
2020 			}
2021 		}
2022 		PG_FINALLY();
2023 		{
2024 			hash_destroy(ft_htab);
2025 		}
2026 		PG_END_TRY();
2027 	}
2028 
2029 	/*
2030 	 * Restart owned sequences if we were asked to.
2031 	 */
2032 	foreach(cell, seq_relids)
2033 	{
2034 		Oid			seq_relid = lfirst_oid(cell);
2035 
2036 		ResetSequence(seq_relid);
2037 	}
2038 
2039 	/*
2040 	 * Write a WAL record to allow this set of actions to be logically
2041 	 * decoded.
2042 	 *
2043 	 * Assemble an array of relids so we can write a single WAL record for the
2044 	 * whole action.
2045 	 */
2046 	if (list_length(relids_logged) > 0)
2047 	{
2048 		xl_heap_truncate xlrec;
2049 		int			i = 0;
2050 
2051 		/* should only get here if wal_level >= logical */
2052 		Assert(XLogLogicalInfoActive());
2053 
2054 		logrelids = palloc(list_length(relids_logged) * sizeof(Oid));
2055 		foreach(cell, relids_logged)
2056 			logrelids[i++] = lfirst_oid(cell);
2057 
2058 		xlrec.dbId = MyDatabaseId;
2059 		xlrec.nrelids = list_length(relids_logged);
2060 		xlrec.flags = 0;
2061 		if (behavior == DROP_CASCADE)
2062 			xlrec.flags |= XLH_TRUNCATE_CASCADE;
2063 		if (restart_seqs)
2064 			xlrec.flags |= XLH_TRUNCATE_RESTART_SEQS;
2065 
2066 		XLogBeginInsert();
2067 		XLogRegisterData((char *) &xlrec, SizeOfHeapTruncate);
2068 		XLogRegisterData((char *) logrelids, list_length(relids_logged) * sizeof(Oid));
2069 
2070 		XLogSetRecordFlags(XLOG_INCLUDE_ORIGIN);
2071 
2072 		(void) XLogInsert(RM_HEAP_ID, XLOG_HEAP_TRUNCATE);
2073 	}
2074 
2075 	/*
2076 	 * Process all AFTER STATEMENT TRUNCATE triggers.
2077 	 */
2078 	resultRelInfo = resultRelInfos;
2079 	foreach(cell, rels)
2080 	{
2081 		ExecASTruncateTriggers(estate, resultRelInfo);
2082 		resultRelInfo++;
2083 	}
2084 
2085 	/* Handle queued AFTER triggers */
2086 	AfterTriggerEndQuery(estate);
2087 
2088 	/* We can clean up the EState now */
2089 	FreeExecutorState(estate);
2090 
2091 	/*
2092 	 * Close any rels opened by CASCADE (can't do this while EState still
2093 	 * holds refs)
2094 	 */
2095 	rels = list_difference_ptr(rels, explicit_rels);
2096 	foreach(cell, rels)
2097 	{
2098 		Relation	rel = (Relation) lfirst(cell);
2099 
2100 		table_close(rel, NoLock);
2101 	}
2102 }
2103 
2104 /*
2105  * Check that a given relation is safe to truncate.  Subroutine for
2106  * ExecuteTruncate() and RangeVarCallbackForTruncate().
2107  */
2108 static void
truncate_check_rel(Oid relid,Form_pg_class reltuple)2109 truncate_check_rel(Oid relid, Form_pg_class reltuple)
2110 {
2111 	char	   *relname = NameStr(reltuple->relname);
2112 
2113 	/*
2114 	 * Only allow truncate on regular tables, foreign tables using foreign
2115 	 * data wrappers supporting TRUNCATE and partitioned tables (although, the
2116 	 * latter are only being included here for the following checks; no
2117 	 * physical truncation will occur in their case.).
2118 	 */
2119 	if (reltuple->relkind == RELKIND_FOREIGN_TABLE)
2120 	{
2121 		Oid			serverid = GetForeignServerIdByRelId(relid);
2122 		FdwRoutine *fdwroutine = GetFdwRoutineByServerId(serverid);
2123 
2124 		if (!fdwroutine->ExecForeignTruncate)
2125 			ereport(ERROR,
2126 					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2127 					 errmsg("cannot truncate foreign table \"%s\"",
2128 							relname)));
2129 	}
2130 	else if (reltuple->relkind != RELKIND_RELATION &&
2131 			 reltuple->relkind != RELKIND_PARTITIONED_TABLE)
2132 		ereport(ERROR,
2133 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
2134 				 errmsg("\"%s\" is not a table", relname)));
2135 
2136 	if (!allowSystemTableMods && IsSystemClass(relid, reltuple))
2137 		ereport(ERROR,
2138 				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
2139 				 errmsg("permission denied: \"%s\" is a system catalog",
2140 						relname)));
2141 
2142 	InvokeObjectTruncateHook(relid);
2143 }
2144 
2145 /*
2146  * Check that current user has the permission to truncate given relation.
2147  */
2148 static void
truncate_check_perms(Oid relid,Form_pg_class reltuple)2149 truncate_check_perms(Oid relid, Form_pg_class reltuple)
2150 {
2151 	char	   *relname = NameStr(reltuple->relname);
2152 	AclResult	aclresult;
2153 
2154 	/* Permissions checks */
2155 	aclresult = pg_class_aclcheck(relid, GetUserId(), ACL_TRUNCATE);
2156 	if (aclresult != ACLCHECK_OK)
2157 		aclcheck_error(aclresult, get_relkind_objtype(reltuple->relkind),
2158 					   relname);
2159 }
2160 
2161 /*
2162  * Set of extra sanity checks to check if a given relation is safe to
2163  * truncate.  This is split with truncate_check_rel() as
2164  * RangeVarCallbackForTruncate() cannot open a Relation yet.
2165  */
2166 static void
truncate_check_activity(Relation rel)2167 truncate_check_activity(Relation rel)
2168 {
2169 	/*
2170 	 * Don't allow truncate on temp tables of other backends ... their local
2171 	 * buffer manager is not going to cope.
2172 	 */
2173 	if (RELATION_IS_OTHER_TEMP(rel))
2174 		ereport(ERROR,
2175 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2176 				 errmsg("cannot truncate temporary tables of other sessions")));
2177 
2178 	/*
2179 	 * Also check for active uses of the relation in the current transaction,
2180 	 * including open scans and pending AFTER trigger events.
2181 	 */
2182 	CheckTableNotInUse(rel, "TRUNCATE");
2183 }
2184 
2185 /*
2186  * storage_name
2187  *	  returns the name corresponding to a typstorage/attstorage enum value
2188  */
2189 static const char *
storage_name(char c)2190 storage_name(char c)
2191 {
2192 	switch (c)
2193 	{
2194 		case TYPSTORAGE_PLAIN:
2195 			return "PLAIN";
2196 		case TYPSTORAGE_EXTERNAL:
2197 			return "EXTERNAL";
2198 		case TYPSTORAGE_EXTENDED:
2199 			return "EXTENDED";
2200 		case TYPSTORAGE_MAIN:
2201 			return "MAIN";
2202 		default:
2203 			return "???";
2204 	}
2205 }
2206 
2207 /*----------
2208  * MergeAttributes
2209  *		Returns new schema given initial schema and superclasses.
2210  *
2211  * Input arguments:
2212  * 'schema' is the column/attribute definition for the table. (It's a list
2213  *		of ColumnDef's.) It is destructively changed.
2214  * 'supers' is a list of OIDs of parent relations, already locked by caller.
2215  * 'relpersistence' is the persistence type of the table.
2216  * 'is_partition' tells if the table is a partition.
2217  *
2218  * Output arguments:
2219  * 'supconstr' receives a list of constraints belonging to the parents,
2220  *		updated as necessary to be valid for the child.
2221  *
2222  * Return value:
2223  * Completed schema list.
2224  *
2225  * Notes:
2226  *	  The order in which the attributes are inherited is very important.
2227  *	  Intuitively, the inherited attributes should come first. If a table
2228  *	  inherits from multiple parents, the order of those attributes are
2229  *	  according to the order of the parents specified in CREATE TABLE.
2230  *
2231  *	  Here's an example:
2232  *
2233  *		create table person (name text, age int4, location point);
2234  *		create table emp (salary int4, manager text) inherits(person);
2235  *		create table student (gpa float8) inherits (person);
2236  *		create table stud_emp (percent int4) inherits (emp, student);
2237  *
2238  *	  The order of the attributes of stud_emp is:
2239  *
2240  *							person {1:name, 2:age, 3:location}
2241  *							/	 \
2242  *			   {6:gpa}	student   emp {4:salary, 5:manager}
2243  *							\	 /
2244  *						   stud_emp {7:percent}
2245  *
2246  *	   If the same attribute name appears multiple times, then it appears
2247  *	   in the result table in the proper location for its first appearance.
2248  *
2249  *	   Constraints (including NOT NULL constraints) for the child table
2250  *	   are the union of all relevant constraints, from both the child schema
2251  *	   and parent tables.
2252  *
2253  *	   The default value for a child column is defined as:
2254  *		(1) If the child schema specifies a default, that value is used.
2255  *		(2) If neither the child nor any parent specifies a default, then
2256  *			the column will not have a default.
2257  *		(3) If conflicting defaults are inherited from different parents
2258  *			(and not overridden by the child), an error is raised.
2259  *		(4) Otherwise the inherited default is used.
2260  *		Rule (3) is new in Postgres 7.1; in earlier releases you got a
2261  *		rather arbitrary choice of which parent default to use.
2262  *----------
2263  */
2264 static List *
MergeAttributes(List * schema,List * supers,char relpersistence,bool is_partition,List ** supconstr)2265 MergeAttributes(List *schema, List *supers, char relpersistence,
2266 				bool is_partition, List **supconstr)
2267 {
2268 	List	   *inhSchema = NIL;
2269 	List	   *constraints = NIL;
2270 	bool		have_bogus_defaults = false;
2271 	int			child_attno;
2272 	static Node bogus_marker = {0}; /* marks conflicting defaults */
2273 	List	   *saved_schema = NIL;
2274 	ListCell   *entry;
2275 
2276 	/*
2277 	 * Check for and reject tables with too many columns. We perform this
2278 	 * check relatively early for two reasons: (a) we don't run the risk of
2279 	 * overflowing an AttrNumber in subsequent code (b) an O(n^2) algorithm is
2280 	 * okay if we're processing <= 1600 columns, but could take minutes to
2281 	 * execute if the user attempts to create a table with hundreds of
2282 	 * thousands of columns.
2283 	 *
2284 	 * Note that we also need to check that we do not exceed this figure after
2285 	 * including columns from inherited relations.
2286 	 */
2287 	if (list_length(schema) > MaxHeapAttributeNumber)
2288 		ereport(ERROR,
2289 				(errcode(ERRCODE_TOO_MANY_COLUMNS),
2290 				 errmsg("tables can have at most %d columns",
2291 						MaxHeapAttributeNumber)));
2292 
2293 	/*
2294 	 * Check for duplicate names in the explicit list of attributes.
2295 	 *
2296 	 * Although we might consider merging such entries in the same way that we
2297 	 * handle name conflicts for inherited attributes, it seems to make more
2298 	 * sense to assume such conflicts are errors.
2299 	 *
2300 	 * We don't use foreach() here because we have two nested loops over the
2301 	 * schema list, with possible element deletions in the inner one.  If we
2302 	 * used foreach_delete_current() it could only fix up the state of one of
2303 	 * the loops, so it seems cleaner to use looping over list indexes for
2304 	 * both loops.  Note that any deletion will happen beyond where the outer
2305 	 * loop is, so its index never needs adjustment.
2306 	 */
2307 	for (int coldefpos = 0; coldefpos < list_length(schema); coldefpos++)
2308 	{
2309 		ColumnDef  *coldef = list_nth_node(ColumnDef, schema, coldefpos);
2310 
2311 		if (!is_partition && coldef->typeName == NULL)
2312 		{
2313 			/*
2314 			 * Typed table column option that does not belong to a column from
2315 			 * the type.  This works because the columns from the type come
2316 			 * first in the list.  (We omit this check for partition column
2317 			 * lists; those are processed separately below.)
2318 			 */
2319 			ereport(ERROR,
2320 					(errcode(ERRCODE_UNDEFINED_COLUMN),
2321 					 errmsg("column \"%s\" does not exist",
2322 							coldef->colname)));
2323 		}
2324 
2325 		/* restpos scans all entries beyond coldef; incr is in loop body */
2326 		for (int restpos = coldefpos + 1; restpos < list_length(schema);)
2327 		{
2328 			ColumnDef  *restdef = list_nth_node(ColumnDef, schema, restpos);
2329 
2330 			if (strcmp(coldef->colname, restdef->colname) == 0)
2331 			{
2332 				if (coldef->is_from_type)
2333 				{
2334 					/*
2335 					 * merge the column options into the column from the type
2336 					 */
2337 					coldef->is_not_null = restdef->is_not_null;
2338 					coldef->raw_default = restdef->raw_default;
2339 					coldef->cooked_default = restdef->cooked_default;
2340 					coldef->constraints = restdef->constraints;
2341 					coldef->is_from_type = false;
2342 					schema = list_delete_nth_cell(schema, restpos);
2343 				}
2344 				else
2345 					ereport(ERROR,
2346 							(errcode(ERRCODE_DUPLICATE_COLUMN),
2347 							 errmsg("column \"%s\" specified more than once",
2348 									coldef->colname)));
2349 			}
2350 			else
2351 				restpos++;
2352 		}
2353 	}
2354 
2355 	/*
2356 	 * In case of a partition, there are no new column definitions, only dummy
2357 	 * ColumnDefs created for column constraints.  Set them aside for now and
2358 	 * process them at the end.
2359 	 */
2360 	if (is_partition)
2361 	{
2362 		saved_schema = schema;
2363 		schema = NIL;
2364 	}
2365 
2366 	/*
2367 	 * Scan the parents left-to-right, and merge their attributes to form a
2368 	 * list of inherited attributes (inhSchema).  Also check to see if we need
2369 	 * to inherit an OID column.
2370 	 */
2371 	child_attno = 0;
2372 	foreach(entry, supers)
2373 	{
2374 		Oid			parent = lfirst_oid(entry);
2375 		Relation	relation;
2376 		TupleDesc	tupleDesc;
2377 		TupleConstr *constr;
2378 		AttrMap    *newattmap;
2379 		List	   *inherited_defaults;
2380 		List	   *cols_with_defaults;
2381 		AttrNumber	parent_attno;
2382 		ListCell   *lc1;
2383 		ListCell   *lc2;
2384 
2385 		/* caller already got lock */
2386 		relation = table_open(parent, NoLock);
2387 
2388 		/*
2389 		 * Check for active uses of the parent partitioned table in the
2390 		 * current transaction, such as being used in some manner by an
2391 		 * enclosing command.
2392 		 */
2393 		if (is_partition)
2394 			CheckTableNotInUse(relation, "CREATE TABLE .. PARTITION OF");
2395 
2396 		/*
2397 		 * We do not allow partitioned tables and partitions to participate in
2398 		 * regular inheritance.
2399 		 */
2400 		if (relation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE &&
2401 			!is_partition)
2402 			ereport(ERROR,
2403 					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
2404 					 errmsg("cannot inherit from partitioned table \"%s\"",
2405 							RelationGetRelationName(relation))));
2406 		if (relation->rd_rel->relispartition && !is_partition)
2407 			ereport(ERROR,
2408 					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
2409 					 errmsg("cannot inherit from partition \"%s\"",
2410 							RelationGetRelationName(relation))));
2411 
2412 		if (relation->rd_rel->relkind != RELKIND_RELATION &&
2413 			relation->rd_rel->relkind != RELKIND_FOREIGN_TABLE &&
2414 			relation->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
2415 			ereport(ERROR,
2416 					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
2417 					 errmsg("inherited relation \"%s\" is not a table or foreign table",
2418 							RelationGetRelationName(relation))));
2419 
2420 		/*
2421 		 * If the parent is permanent, so must be all of its partitions.  Note
2422 		 * that inheritance allows that case.
2423 		 */
2424 		if (is_partition &&
2425 			relation->rd_rel->relpersistence != RELPERSISTENCE_TEMP &&
2426 			relpersistence == RELPERSISTENCE_TEMP)
2427 			ereport(ERROR,
2428 					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
2429 					 errmsg("cannot create a temporary relation as partition of permanent relation \"%s\"",
2430 							RelationGetRelationName(relation))));
2431 
2432 		/* Permanent rels cannot inherit from temporary ones */
2433 		if (relpersistence != RELPERSISTENCE_TEMP &&
2434 			relation->rd_rel->relpersistence == RELPERSISTENCE_TEMP)
2435 			ereport(ERROR,
2436 					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
2437 					 errmsg(!is_partition
2438 							? "cannot inherit from temporary relation \"%s\""
2439 							: "cannot create a permanent relation as partition of temporary relation \"%s\"",
2440 							RelationGetRelationName(relation))));
2441 
2442 		/* If existing rel is temp, it must belong to this session */
2443 		if (relation->rd_rel->relpersistence == RELPERSISTENCE_TEMP &&
2444 			!relation->rd_islocaltemp)
2445 			ereport(ERROR,
2446 					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
2447 					 errmsg(!is_partition
2448 							? "cannot inherit from temporary relation of another session"
2449 							: "cannot create as partition of temporary relation of another session")));
2450 
2451 		/*
2452 		 * We should have an UNDER permission flag for this, but for now,
2453 		 * demand that creator of a child table own the parent.
2454 		 */
2455 		if (!pg_class_ownercheck(RelationGetRelid(relation), GetUserId()))
2456 			aclcheck_error(ACLCHECK_NOT_OWNER, get_relkind_objtype(relation->rd_rel->relkind),
2457 						   RelationGetRelationName(relation));
2458 
2459 		tupleDesc = RelationGetDescr(relation);
2460 		constr = tupleDesc->constr;
2461 
2462 		/*
2463 		 * newattmap->attnums[] will contain the child-table attribute numbers
2464 		 * for the attributes of this parent table.  (They are not the same
2465 		 * for parents after the first one, nor if we have dropped columns.)
2466 		 */
2467 		newattmap = make_attrmap(tupleDesc->natts);
2468 
2469 		/* We can't process inherited defaults until newattmap is complete. */
2470 		inherited_defaults = cols_with_defaults = NIL;
2471 
2472 		for (parent_attno = 1; parent_attno <= tupleDesc->natts;
2473 			 parent_attno++)
2474 		{
2475 			Form_pg_attribute attribute = TupleDescAttr(tupleDesc,
2476 														parent_attno - 1);
2477 			char	   *attributeName = NameStr(attribute->attname);
2478 			int			exist_attno;
2479 			ColumnDef  *def;
2480 
2481 			/*
2482 			 * Ignore dropped columns in the parent.
2483 			 */
2484 			if (attribute->attisdropped)
2485 				continue;		/* leave newattmap->attnums entry as zero */
2486 
2487 			/*
2488 			 * Does it conflict with some previously inherited column?
2489 			 */
2490 			exist_attno = findAttrByName(attributeName, inhSchema);
2491 			if (exist_attno > 0)
2492 			{
2493 				Oid			defTypeId;
2494 				int32		deftypmod;
2495 				Oid			defCollId;
2496 
2497 				/*
2498 				 * Yes, try to merge the two column definitions. They must
2499 				 * have the same type, typmod, and collation.
2500 				 */
2501 				ereport(NOTICE,
2502 						(errmsg("merging multiple inherited definitions of column \"%s\"",
2503 								attributeName)));
2504 				def = (ColumnDef *) list_nth(inhSchema, exist_attno - 1);
2505 				typenameTypeIdAndMod(NULL, def->typeName, &defTypeId, &deftypmod);
2506 				if (defTypeId != attribute->atttypid ||
2507 					deftypmod != attribute->atttypmod)
2508 					ereport(ERROR,
2509 							(errcode(ERRCODE_DATATYPE_MISMATCH),
2510 							 errmsg("inherited column \"%s\" has a type conflict",
2511 									attributeName),
2512 							 errdetail("%s versus %s",
2513 									   format_type_with_typemod(defTypeId,
2514 																deftypmod),
2515 									   format_type_with_typemod(attribute->atttypid,
2516 																attribute->atttypmod))));
2517 				defCollId = GetColumnDefCollation(NULL, def, defTypeId);
2518 				if (defCollId != attribute->attcollation)
2519 					ereport(ERROR,
2520 							(errcode(ERRCODE_COLLATION_MISMATCH),
2521 							 errmsg("inherited column \"%s\" has a collation conflict",
2522 									attributeName),
2523 							 errdetail("\"%s\" versus \"%s\"",
2524 									   get_collation_name(defCollId),
2525 									   get_collation_name(attribute->attcollation))));
2526 
2527 				/* Copy/check storage parameter */
2528 				if (def->storage == 0)
2529 					def->storage = attribute->attstorage;
2530 				else if (def->storage != attribute->attstorage)
2531 					ereport(ERROR,
2532 							(errcode(ERRCODE_DATATYPE_MISMATCH),
2533 							 errmsg("inherited column \"%s\" has a storage parameter conflict",
2534 									attributeName),
2535 							 errdetail("%s versus %s",
2536 									   storage_name(def->storage),
2537 									   storage_name(attribute->attstorage))));
2538 
2539 				/* Copy/check compression parameter */
2540 				if (CompressionMethodIsValid(attribute->attcompression))
2541 				{
2542 					const char *compression =
2543 					GetCompressionMethodName(attribute->attcompression);
2544 
2545 					if (def->compression == NULL)
2546 						def->compression = pstrdup(compression);
2547 					else if (strcmp(def->compression, compression) != 0)
2548 						ereport(ERROR,
2549 								(errcode(ERRCODE_DATATYPE_MISMATCH),
2550 								 errmsg("column \"%s\" has a compression method conflict",
2551 										attributeName),
2552 								 errdetail("%s versus %s", def->compression, compression)));
2553 				}
2554 
2555 				def->inhcount++;
2556 				/* Merge of NOT NULL constraints = OR 'em together */
2557 				def->is_not_null |= attribute->attnotnull;
2558 				/* Default and other constraints are handled below */
2559 				newattmap->attnums[parent_attno - 1] = exist_attno;
2560 
2561 				/* Check for GENERATED conflicts */
2562 				if (def->generated != attribute->attgenerated)
2563 					ereport(ERROR,
2564 							(errcode(ERRCODE_DATATYPE_MISMATCH),
2565 							 errmsg("inherited column \"%s\" has a generation conflict",
2566 									attributeName)));
2567 			}
2568 			else
2569 			{
2570 				/*
2571 				 * No, create a new inherited column
2572 				 */
2573 				def = makeNode(ColumnDef);
2574 				def->colname = pstrdup(attributeName);
2575 				def->typeName = makeTypeNameFromOid(attribute->atttypid,
2576 													attribute->atttypmod);
2577 				def->inhcount = 1;
2578 				def->is_local = false;
2579 				def->is_not_null = attribute->attnotnull;
2580 				def->is_from_type = false;
2581 				def->storage = attribute->attstorage;
2582 				def->raw_default = NULL;
2583 				def->cooked_default = NULL;
2584 				def->generated = attribute->attgenerated;
2585 				def->collClause = NULL;
2586 				def->collOid = attribute->attcollation;
2587 				def->constraints = NIL;
2588 				def->location = -1;
2589 				if (CompressionMethodIsValid(attribute->attcompression))
2590 					def->compression =
2591 						pstrdup(GetCompressionMethodName(attribute->attcompression));
2592 				else
2593 					def->compression = NULL;
2594 				inhSchema = lappend(inhSchema, def);
2595 				newattmap->attnums[parent_attno - 1] = ++child_attno;
2596 			}
2597 
2598 			/*
2599 			 * Locate default if any
2600 			 */
2601 			if (attribute->atthasdef)
2602 			{
2603 				Node	   *this_default = NULL;
2604 
2605 				/* Find default in constraint structure */
2606 				if (constr != NULL)
2607 				{
2608 					AttrDefault *attrdef = constr->defval;
2609 
2610 					for (int i = 0; i < constr->num_defval; i++)
2611 					{
2612 						if (attrdef[i].adnum == parent_attno)
2613 						{
2614 							this_default = stringToNode(attrdef[i].adbin);
2615 							break;
2616 						}
2617 					}
2618 				}
2619 				if (this_default == NULL)
2620 					elog(ERROR, "default expression not found for attribute %d of relation \"%s\"",
2621 						 parent_attno, RelationGetRelationName(relation));
2622 
2623 				/*
2624 				 * If it's a GENERATED default, it might contain Vars that
2625 				 * need to be mapped to the inherited column(s)' new numbers.
2626 				 * We can't do that till newattmap is ready, so just remember
2627 				 * all the inherited default expressions for the moment.
2628 				 */
2629 				inherited_defaults = lappend(inherited_defaults, this_default);
2630 				cols_with_defaults = lappend(cols_with_defaults, def);
2631 			}
2632 		}
2633 
2634 		/*
2635 		 * Now process any inherited default expressions, adjusting attnos
2636 		 * using the completed newattmap map.
2637 		 */
2638 		forboth(lc1, inherited_defaults, lc2, cols_with_defaults)
2639 		{
2640 			Node	   *this_default = (Node *) lfirst(lc1);
2641 			ColumnDef  *def = (ColumnDef *) lfirst(lc2);
2642 			bool		found_whole_row;
2643 
2644 			/* Adjust Vars to match new table's column numbering */
2645 			this_default = map_variable_attnos(this_default,
2646 											   1, 0,
2647 											   newattmap,
2648 											   InvalidOid, &found_whole_row);
2649 
2650 			/*
2651 			 * For the moment we have to reject whole-row variables.  We could
2652 			 * convert them, if we knew the new table's rowtype OID, but that
2653 			 * hasn't been assigned yet.  (A variable could only appear in a
2654 			 * generation expression, so the error message is correct.)
2655 			 */
2656 			if (found_whole_row)
2657 				ereport(ERROR,
2658 						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2659 						 errmsg("cannot convert whole-row table reference"),
2660 						 errdetail("Generation expression for column \"%s\" contains a whole-row reference to table \"%s\".",
2661 								   def->colname,
2662 								   RelationGetRelationName(relation))));
2663 
2664 			/*
2665 			 * If we already had a default from some prior parent, check to
2666 			 * see if they are the same.  If so, no problem; if not, mark the
2667 			 * column as having a bogus default.  Below, we will complain if
2668 			 * the bogus default isn't overridden by the child schema.
2669 			 */
2670 			Assert(def->raw_default == NULL);
2671 			if (def->cooked_default == NULL)
2672 				def->cooked_default = this_default;
2673 			else if (!equal(def->cooked_default, this_default))
2674 			{
2675 				def->cooked_default = &bogus_marker;
2676 				have_bogus_defaults = true;
2677 			}
2678 		}
2679 
2680 		/*
2681 		 * Now copy the CHECK constraints of this parent, adjusting attnos
2682 		 * using the completed newattmap map.  Identically named constraints
2683 		 * are merged if possible, else we throw error.
2684 		 */
2685 		if (constr && constr->num_check > 0)
2686 		{
2687 			ConstrCheck *check = constr->check;
2688 			int			i;
2689 
2690 			for (i = 0; i < constr->num_check; i++)
2691 			{
2692 				char	   *name = check[i].ccname;
2693 				Node	   *expr;
2694 				bool		found_whole_row;
2695 
2696 				/* ignore if the constraint is non-inheritable */
2697 				if (check[i].ccnoinherit)
2698 					continue;
2699 
2700 				/* Adjust Vars to match new table's column numbering */
2701 				expr = map_variable_attnos(stringToNode(check[i].ccbin),
2702 										   1, 0,
2703 										   newattmap,
2704 										   InvalidOid, &found_whole_row);
2705 
2706 				/*
2707 				 * For the moment we have to reject whole-row variables. We
2708 				 * could convert them, if we knew the new table's rowtype OID,
2709 				 * but that hasn't been assigned yet.
2710 				 */
2711 				if (found_whole_row)
2712 					ereport(ERROR,
2713 							(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2714 							 errmsg("cannot convert whole-row table reference"),
2715 							 errdetail("Constraint \"%s\" contains a whole-row reference to table \"%s\".",
2716 									   name,
2717 									   RelationGetRelationName(relation))));
2718 
2719 				/* check for duplicate */
2720 				if (!MergeCheckConstraint(constraints, name, expr))
2721 				{
2722 					/* nope, this is a new one */
2723 					CookedConstraint *cooked;
2724 
2725 					cooked = (CookedConstraint *) palloc(sizeof(CookedConstraint));
2726 					cooked->contype = CONSTR_CHECK;
2727 					cooked->conoid = InvalidOid;	/* until created */
2728 					cooked->name = pstrdup(name);
2729 					cooked->attnum = 0; /* not used for constraints */
2730 					cooked->expr = expr;
2731 					cooked->skip_validation = false;
2732 					cooked->is_local = false;
2733 					cooked->inhcount = 1;
2734 					cooked->is_no_inherit = false;
2735 					constraints = lappend(constraints, cooked);
2736 				}
2737 			}
2738 		}
2739 
2740 		free_attrmap(newattmap);
2741 
2742 		/*
2743 		 * Close the parent rel, but keep our lock on it until xact commit.
2744 		 * That will prevent someone else from deleting or ALTERing the parent
2745 		 * before the child is committed.
2746 		 */
2747 		table_close(relation, NoLock);
2748 	}
2749 
2750 	/*
2751 	 * If we had no inherited attributes, the result schema is just the
2752 	 * explicitly declared columns.  Otherwise, we need to merge the declared
2753 	 * columns into the inherited schema list.  Although, we never have any
2754 	 * explicitly declared columns if the table is a partition.
2755 	 */
2756 	if (inhSchema != NIL)
2757 	{
2758 		int			schema_attno = 0;
2759 
2760 		foreach(entry, schema)
2761 		{
2762 			ColumnDef  *newdef = lfirst(entry);
2763 			char	   *attributeName = newdef->colname;
2764 			int			exist_attno;
2765 
2766 			schema_attno++;
2767 
2768 			/*
2769 			 * Does it conflict with some previously inherited column?
2770 			 */
2771 			exist_attno = findAttrByName(attributeName, inhSchema);
2772 			if (exist_attno > 0)
2773 			{
2774 				ColumnDef  *def;
2775 				Oid			defTypeId,
2776 							newTypeId;
2777 				int32		deftypmod,
2778 							newtypmod;
2779 				Oid			defcollid,
2780 							newcollid;
2781 
2782 				/*
2783 				 * Partitions have only one parent and have no column
2784 				 * definitions of their own, so conflict should never occur.
2785 				 */
2786 				Assert(!is_partition);
2787 
2788 				/*
2789 				 * Yes, try to merge the two column definitions. They must
2790 				 * have the same type, typmod, and collation.
2791 				 */
2792 				if (exist_attno == schema_attno)
2793 					ereport(NOTICE,
2794 							(errmsg("merging column \"%s\" with inherited definition",
2795 									attributeName)));
2796 				else
2797 					ereport(NOTICE,
2798 							(errmsg("moving and merging column \"%s\" with inherited definition", attributeName),
2799 							 errdetail("User-specified column moved to the position of the inherited column.")));
2800 				def = (ColumnDef *) list_nth(inhSchema, exist_attno - 1);
2801 				typenameTypeIdAndMod(NULL, def->typeName, &defTypeId, &deftypmod);
2802 				typenameTypeIdAndMod(NULL, newdef->typeName, &newTypeId, &newtypmod);
2803 				if (defTypeId != newTypeId || deftypmod != newtypmod)
2804 					ereport(ERROR,
2805 							(errcode(ERRCODE_DATATYPE_MISMATCH),
2806 							 errmsg("column \"%s\" has a type conflict",
2807 									attributeName),
2808 							 errdetail("%s versus %s",
2809 									   format_type_with_typemod(defTypeId,
2810 																deftypmod),
2811 									   format_type_with_typemod(newTypeId,
2812 																newtypmod))));
2813 				defcollid = GetColumnDefCollation(NULL, def, defTypeId);
2814 				newcollid = GetColumnDefCollation(NULL, newdef, newTypeId);
2815 				if (defcollid != newcollid)
2816 					ereport(ERROR,
2817 							(errcode(ERRCODE_COLLATION_MISMATCH),
2818 							 errmsg("column \"%s\" has a collation conflict",
2819 									attributeName),
2820 							 errdetail("\"%s\" versus \"%s\"",
2821 									   get_collation_name(defcollid),
2822 									   get_collation_name(newcollid))));
2823 
2824 				/*
2825 				 * Identity is never inherited.  The new column can have an
2826 				 * identity definition, so we always just take that one.
2827 				 */
2828 				def->identity = newdef->identity;
2829 
2830 				/* Copy storage parameter */
2831 				if (def->storage == 0)
2832 					def->storage = newdef->storage;
2833 				else if (newdef->storage != 0 && def->storage != newdef->storage)
2834 					ereport(ERROR,
2835 							(errcode(ERRCODE_DATATYPE_MISMATCH),
2836 							 errmsg("column \"%s\" has a storage parameter conflict",
2837 									attributeName),
2838 							 errdetail("%s versus %s",
2839 									   storage_name(def->storage),
2840 									   storage_name(newdef->storage))));
2841 
2842 				/* Copy compression parameter */
2843 				if (def->compression == NULL)
2844 					def->compression = newdef->compression;
2845 				else if (newdef->compression != NULL)
2846 				{
2847 					if (strcmp(def->compression, newdef->compression) != 0)
2848 						ereport(ERROR,
2849 								(errcode(ERRCODE_DATATYPE_MISMATCH),
2850 								 errmsg("column \"%s\" has a compression method conflict",
2851 										attributeName),
2852 								 errdetail("%s versus %s", def->compression, newdef->compression)));
2853 				}
2854 
2855 				/* Mark the column as locally defined */
2856 				def->is_local = true;
2857 				/* Merge of NOT NULL constraints = OR 'em together */
2858 				def->is_not_null |= newdef->is_not_null;
2859 
2860 				/*
2861 				 * Check for conflicts related to generated columns.
2862 				 *
2863 				 * If the parent column is generated, the child column must be
2864 				 * unadorned and will be made a generated column.  (We could
2865 				 * in theory allow the child column definition specifying the
2866 				 * exact same generation expression, but that's a bit
2867 				 * complicated to implement and doesn't seem very useful.)  We
2868 				 * also check that the child column doesn't specify a default
2869 				 * value or identity, which matches the rules for a single
2870 				 * column in parse_util.c.
2871 				 */
2872 				if (def->generated)
2873 				{
2874 					if (newdef->generated)
2875 						ereport(ERROR,
2876 								(errcode(ERRCODE_INVALID_COLUMN_DEFINITION),
2877 								 errmsg("child column \"%s\" specifies generation expression",
2878 										def->colname),
2879 								 errhint("Omit the generation expression in the definition of the child table column to inherit the generation expression from the parent table.")));
2880 					if (newdef->raw_default && !newdef->generated)
2881 						ereport(ERROR,
2882 								(errcode(ERRCODE_INVALID_COLUMN_DEFINITION),
2883 								 errmsg("column \"%s\" inherits from generated column but specifies default",
2884 										def->colname)));
2885 					if (newdef->identity)
2886 						ereport(ERROR,
2887 								(errcode(ERRCODE_INVALID_COLUMN_DEFINITION),
2888 								 errmsg("column \"%s\" inherits from generated column but specifies identity",
2889 										def->colname)));
2890 				}
2891 
2892 				/*
2893 				 * If the parent column is not generated, then take whatever
2894 				 * the child column definition says.
2895 				 */
2896 				else
2897 				{
2898 					if (newdef->generated)
2899 						def->generated = newdef->generated;
2900 				}
2901 
2902 				/* If new def has a default, override previous default */
2903 				if (newdef->raw_default != NULL)
2904 				{
2905 					def->raw_default = newdef->raw_default;
2906 					def->cooked_default = newdef->cooked_default;
2907 				}
2908 			}
2909 			else
2910 			{
2911 				/*
2912 				 * No, attach new column to result schema
2913 				 */
2914 				inhSchema = lappend(inhSchema, newdef);
2915 			}
2916 		}
2917 
2918 		schema = inhSchema;
2919 
2920 		/*
2921 		 * Check that we haven't exceeded the legal # of columns after merging
2922 		 * in inherited columns.
2923 		 */
2924 		if (list_length(schema) > MaxHeapAttributeNumber)
2925 			ereport(ERROR,
2926 					(errcode(ERRCODE_TOO_MANY_COLUMNS),
2927 					 errmsg("tables can have at most %d columns",
2928 							MaxHeapAttributeNumber)));
2929 	}
2930 
2931 	/*
2932 	 * Now that we have the column definition list for a partition, we can
2933 	 * check whether the columns referenced in the column constraint specs
2934 	 * actually exist.  Also, we merge NOT NULL and defaults into each
2935 	 * corresponding column definition.
2936 	 */
2937 	if (is_partition)
2938 	{
2939 		foreach(entry, saved_schema)
2940 		{
2941 			ColumnDef  *restdef = lfirst(entry);
2942 			bool		found = false;
2943 			ListCell   *l;
2944 
2945 			foreach(l, schema)
2946 			{
2947 				ColumnDef  *coldef = lfirst(l);
2948 
2949 				if (strcmp(coldef->colname, restdef->colname) == 0)
2950 				{
2951 					found = true;
2952 					coldef->is_not_null |= restdef->is_not_null;
2953 
2954 					/*
2955 					 * Override the parent's default value for this column
2956 					 * (coldef->cooked_default) with the partition's local
2957 					 * definition (restdef->raw_default), if there's one. It
2958 					 * should be physically impossible to get a cooked default
2959 					 * in the local definition or a raw default in the
2960 					 * inherited definition, but make sure they're nulls, for
2961 					 * future-proofing.
2962 					 */
2963 					Assert(restdef->cooked_default == NULL);
2964 					Assert(coldef->raw_default == NULL);
2965 					if (restdef->raw_default)
2966 					{
2967 						coldef->raw_default = restdef->raw_default;
2968 						coldef->cooked_default = NULL;
2969 					}
2970 				}
2971 			}
2972 
2973 			/* complain for constraints on columns not in parent */
2974 			if (!found)
2975 				ereport(ERROR,
2976 						(errcode(ERRCODE_UNDEFINED_COLUMN),
2977 						 errmsg("column \"%s\" does not exist",
2978 								restdef->colname)));
2979 		}
2980 	}
2981 
2982 	/*
2983 	 * If we found any conflicting parent default values, check to make sure
2984 	 * they were overridden by the child.
2985 	 */
2986 	if (have_bogus_defaults)
2987 	{
2988 		foreach(entry, schema)
2989 		{
2990 			ColumnDef  *def = lfirst(entry);
2991 
2992 			if (def->cooked_default == &bogus_marker)
2993 			{
2994 				if (def->generated)
2995 					ereport(ERROR,
2996 							(errcode(ERRCODE_INVALID_COLUMN_DEFINITION),
2997 							 errmsg("column \"%s\" inherits conflicting generation expressions",
2998 									def->colname)));
2999 				else
3000 					ereport(ERROR,
3001 							(errcode(ERRCODE_INVALID_COLUMN_DEFINITION),
3002 							 errmsg("column \"%s\" inherits conflicting default values",
3003 									def->colname),
3004 							 errhint("To resolve the conflict, specify a default explicitly.")));
3005 			}
3006 		}
3007 	}
3008 
3009 	*supconstr = constraints;
3010 	return schema;
3011 }
3012 
3013 
3014 /*
3015  * MergeCheckConstraint
3016  *		Try to merge an inherited CHECK constraint with previous ones
3017  *
3018  * If we inherit identically-named constraints from multiple parents, we must
3019  * merge them, or throw an error if they don't have identical definitions.
3020  *
3021  * constraints is a list of CookedConstraint structs for previous constraints.
3022  *
3023  * Returns true if merged (constraint is a duplicate), or false if it's
3024  * got a so-far-unique name, or throws error if conflict.
3025  */
3026 static bool
MergeCheckConstraint(List * constraints,char * name,Node * expr)3027 MergeCheckConstraint(List *constraints, char *name, Node *expr)
3028 {
3029 	ListCell   *lc;
3030 
3031 	foreach(lc, constraints)
3032 	{
3033 		CookedConstraint *ccon = (CookedConstraint *) lfirst(lc);
3034 
3035 		Assert(ccon->contype == CONSTR_CHECK);
3036 
3037 		/* Non-matching names never conflict */
3038 		if (strcmp(ccon->name, name) != 0)
3039 			continue;
3040 
3041 		if (equal(expr, ccon->expr))
3042 		{
3043 			/* OK to merge */
3044 			ccon->inhcount++;
3045 			return true;
3046 		}
3047 
3048 		ereport(ERROR,
3049 				(errcode(ERRCODE_DUPLICATE_OBJECT),
3050 				 errmsg("check constraint name \"%s\" appears multiple times but with different expressions",
3051 						name)));
3052 	}
3053 
3054 	return false;
3055 }
3056 
3057 
3058 /*
3059  * StoreCatalogInheritance
3060  *		Updates the system catalogs with proper inheritance information.
3061  *
3062  * supers is a list of the OIDs of the new relation's direct ancestors.
3063  */
3064 static void
StoreCatalogInheritance(Oid relationId,List * supers,bool child_is_partition)3065 StoreCatalogInheritance(Oid relationId, List *supers,
3066 						bool child_is_partition)
3067 {
3068 	Relation	relation;
3069 	int32		seqNumber;
3070 	ListCell   *entry;
3071 
3072 	/*
3073 	 * sanity checks
3074 	 */
3075 	AssertArg(OidIsValid(relationId));
3076 
3077 	if (supers == NIL)
3078 		return;
3079 
3080 	/*
3081 	 * Store INHERITS information in pg_inherits using direct ancestors only.
3082 	 * Also enter dependencies on the direct ancestors, and make sure they are
3083 	 * marked with relhassubclass = true.
3084 	 *
3085 	 * (Once upon a time, both direct and indirect ancestors were found here
3086 	 * and then entered into pg_ipl.  Since that catalog doesn't exist
3087 	 * anymore, there's no need to look for indirect ancestors.)
3088 	 */
3089 	relation = table_open(InheritsRelationId, RowExclusiveLock);
3090 
3091 	seqNumber = 1;
3092 	foreach(entry, supers)
3093 	{
3094 		Oid			parentOid = lfirst_oid(entry);
3095 
3096 		StoreCatalogInheritance1(relationId, parentOid, seqNumber, relation,
3097 								 child_is_partition);
3098 		seqNumber++;
3099 	}
3100 
3101 	table_close(relation, RowExclusiveLock);
3102 }
3103 
3104 /*
3105  * Make catalog entries showing relationId as being an inheritance child
3106  * of parentOid.  inhRelation is the already-opened pg_inherits catalog.
3107  */
3108 static void
StoreCatalogInheritance1(Oid relationId,Oid parentOid,int32 seqNumber,Relation inhRelation,bool child_is_partition)3109 StoreCatalogInheritance1(Oid relationId, Oid parentOid,
3110 						 int32 seqNumber, Relation inhRelation,
3111 						 bool child_is_partition)
3112 {
3113 	ObjectAddress childobject,
3114 				parentobject;
3115 
3116 	/* store the pg_inherits row */
3117 	StoreSingleInheritance(relationId, parentOid, seqNumber);
3118 
3119 	/*
3120 	 * Store a dependency too
3121 	 */
3122 	parentobject.classId = RelationRelationId;
3123 	parentobject.objectId = parentOid;
3124 	parentobject.objectSubId = 0;
3125 	childobject.classId = RelationRelationId;
3126 	childobject.objectId = relationId;
3127 	childobject.objectSubId = 0;
3128 
3129 	recordDependencyOn(&childobject, &parentobject,
3130 					   child_dependency_type(child_is_partition));
3131 
3132 	/*
3133 	 * Post creation hook of this inheritance. Since object_access_hook
3134 	 * doesn't take multiple object identifiers, we relay oid of parent
3135 	 * relation using auxiliary_id argument.
3136 	 */
3137 	InvokeObjectPostAlterHookArg(InheritsRelationId,
3138 								 relationId, 0,
3139 								 parentOid, false);
3140 
3141 	/*
3142 	 * Mark the parent as having subclasses.
3143 	 */
3144 	SetRelationHasSubclass(parentOid, true);
3145 }
3146 
3147 /*
3148  * Look for an existing schema entry with the given name.
3149  *
3150  * Returns the index (starting with 1) if attribute already exists in schema,
3151  * 0 if it doesn't.
3152  */
3153 static int
findAttrByName(const char * attributeName,List * schema)3154 findAttrByName(const char *attributeName, List *schema)
3155 {
3156 	ListCell   *s;
3157 	int			i = 1;
3158 
3159 	foreach(s, schema)
3160 	{
3161 		ColumnDef  *def = lfirst(s);
3162 
3163 		if (strcmp(attributeName, def->colname) == 0)
3164 			return i;
3165 
3166 		i++;
3167 	}
3168 	return 0;
3169 }
3170 
3171 
3172 /*
3173  * SetRelationHasSubclass
3174  *		Set the value of the relation's relhassubclass field in pg_class.
3175  *
3176  * NOTE: caller must be holding an appropriate lock on the relation.
3177  * ShareUpdateExclusiveLock is sufficient.
3178  *
3179  * NOTE: an important side-effect of this operation is that an SI invalidation
3180  * message is sent out to all backends --- including me --- causing plans
3181  * referencing the relation to be rebuilt with the new list of children.
3182  * This must happen even if we find that no change is needed in the pg_class
3183  * row.
3184  */
3185 void
SetRelationHasSubclass(Oid relationId,bool relhassubclass)3186 SetRelationHasSubclass(Oid relationId, bool relhassubclass)
3187 {
3188 	Relation	relationRelation;
3189 	HeapTuple	tuple;
3190 	Form_pg_class classtuple;
3191 
3192 	/*
3193 	 * Fetch a modifiable copy of the tuple, modify it, update pg_class.
3194 	 */
3195 	relationRelation = table_open(RelationRelationId, RowExclusiveLock);
3196 	tuple = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relationId));
3197 	if (!HeapTupleIsValid(tuple))
3198 		elog(ERROR, "cache lookup failed for relation %u", relationId);
3199 	classtuple = (Form_pg_class) GETSTRUCT(tuple);
3200 
3201 	if (classtuple->relhassubclass != relhassubclass)
3202 	{
3203 		classtuple->relhassubclass = relhassubclass;
3204 		CatalogTupleUpdate(relationRelation, &tuple->t_self, tuple);
3205 	}
3206 	else
3207 	{
3208 		/* no need to change tuple, but force relcache rebuild anyway */
3209 		CacheInvalidateRelcacheByTuple(tuple);
3210 	}
3211 
3212 	heap_freetuple(tuple);
3213 	table_close(relationRelation, RowExclusiveLock);
3214 }
3215 
3216 /*
3217  * CheckRelationTableSpaceMove
3218  *		Check if relation can be moved to new tablespace.
3219  *
3220  * NOTE: The caller must hold AccessExclusiveLock on the relation.
3221  *
3222  * Returns true if the relation can be moved to the new tablespace; raises
3223  * an error if it is not possible to do the move; returns false if the move
3224  * would have no effect.
3225  */
3226 bool
CheckRelationTableSpaceMove(Relation rel,Oid newTableSpaceId)3227 CheckRelationTableSpaceMove(Relation rel, Oid newTableSpaceId)
3228 {
3229 	Oid			oldTableSpaceId;
3230 
3231 	/*
3232 	 * No work if no change in tablespace.  Note that MyDatabaseTableSpace is
3233 	 * stored as 0.
3234 	 */
3235 	oldTableSpaceId = rel->rd_rel->reltablespace;
3236 	if (newTableSpaceId == oldTableSpaceId ||
3237 		(newTableSpaceId == MyDatabaseTableSpace && oldTableSpaceId == 0))
3238 		return false;
3239 
3240 	/*
3241 	 * We cannot support moving mapped relations into different tablespaces.
3242 	 * (In particular this eliminates all shared catalogs.)
3243 	 */
3244 	if (RelationIsMapped(rel))
3245 		ereport(ERROR,
3246 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3247 				 errmsg("cannot move system relation \"%s\"",
3248 						RelationGetRelationName(rel))));
3249 
3250 	/* Cannot move a non-shared relation into pg_global */
3251 	if (newTableSpaceId == GLOBALTABLESPACE_OID)
3252 		ereport(ERROR,
3253 				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
3254 				 errmsg("only shared relations can be placed in pg_global tablespace")));
3255 
3256 	/*
3257 	 * Do not allow moving temp tables of other backends ... their local
3258 	 * buffer manager is not going to cope.
3259 	 */
3260 	if (RELATION_IS_OTHER_TEMP(rel))
3261 		ereport(ERROR,
3262 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3263 				 errmsg("cannot move temporary tables of other sessions")));
3264 
3265 	return true;
3266 }
3267 
3268 /*
3269  * SetRelationTableSpace
3270  *		Set new reltablespace and relfilenode in pg_class entry.
3271  *
3272  * newTableSpaceId is the new tablespace for the relation, and
3273  * newRelFileNode its new filenode.  If newRelFileNode is InvalidOid,
3274  * this field is not updated.
3275  *
3276  * NOTE: The caller must hold AccessExclusiveLock on the relation.
3277  *
3278  * The caller of this routine had better check if a relation can be
3279  * moved to this new tablespace by calling CheckRelationTableSpaceMove()
3280  * first, and is responsible for making the change visible with
3281  * CommandCounterIncrement().
3282  */
3283 void
SetRelationTableSpace(Relation rel,Oid newTableSpaceId,Oid newRelFileNode)3284 SetRelationTableSpace(Relation rel,
3285 					  Oid newTableSpaceId,
3286 					  Oid newRelFileNode)
3287 {
3288 	Relation	pg_class;
3289 	HeapTuple	tuple;
3290 	Form_pg_class rd_rel;
3291 	Oid			reloid = RelationGetRelid(rel);
3292 
3293 	Assert(CheckRelationTableSpaceMove(rel, newTableSpaceId));
3294 
3295 	/* Get a modifiable copy of the relation's pg_class row. */
3296 	pg_class = table_open(RelationRelationId, RowExclusiveLock);
3297 
3298 	tuple = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(reloid));
3299 	if (!HeapTupleIsValid(tuple))
3300 		elog(ERROR, "cache lookup failed for relation %u", reloid);
3301 	rd_rel = (Form_pg_class) GETSTRUCT(tuple);
3302 
3303 	/* Update the pg_class row. */
3304 	rd_rel->reltablespace = (newTableSpaceId == MyDatabaseTableSpace) ?
3305 		InvalidOid : newTableSpaceId;
3306 	if (OidIsValid(newRelFileNode))
3307 		rd_rel->relfilenode = newRelFileNode;
3308 	CatalogTupleUpdate(pg_class, &tuple->t_self, tuple);
3309 
3310 	/*
3311 	 * Record dependency on tablespace.  This is only required for relations
3312 	 * that have no physical storage.
3313 	 */
3314 	if (!RELKIND_HAS_STORAGE(rel->rd_rel->relkind))
3315 		changeDependencyOnTablespace(RelationRelationId, reloid,
3316 									 rd_rel->reltablespace);
3317 
3318 	heap_freetuple(tuple);
3319 	table_close(pg_class, RowExclusiveLock);
3320 }
3321 
3322 /*
3323  *		renameatt_check			- basic sanity checks before attribute rename
3324  */
3325 static void
renameatt_check(Oid myrelid,Form_pg_class classform,bool recursing)3326 renameatt_check(Oid myrelid, Form_pg_class classform, bool recursing)
3327 {
3328 	char		relkind = classform->relkind;
3329 
3330 	if (classform->reloftype && !recursing)
3331 		ereport(ERROR,
3332 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
3333 				 errmsg("cannot rename column of typed table")));
3334 
3335 	/*
3336 	 * Renaming the columns of sequences or toast tables doesn't actually
3337 	 * break anything from the system's point of view, since internal
3338 	 * references are by attnum.  But it doesn't seem right to allow users to
3339 	 * change names that are hardcoded into the system, hence the following
3340 	 * restriction.
3341 	 */
3342 	if (relkind != RELKIND_RELATION &&
3343 		relkind != RELKIND_VIEW &&
3344 		relkind != RELKIND_MATVIEW &&
3345 		relkind != RELKIND_COMPOSITE_TYPE &&
3346 		relkind != RELKIND_INDEX &&
3347 		relkind != RELKIND_PARTITIONED_INDEX &&
3348 		relkind != RELKIND_FOREIGN_TABLE &&
3349 		relkind != RELKIND_PARTITIONED_TABLE)
3350 		ereport(ERROR,
3351 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
3352 				 errmsg("\"%s\" is not a table, view, materialized view, composite type, index, or foreign table",
3353 						NameStr(classform->relname))));
3354 
3355 	/*
3356 	 * permissions checking.  only the owner of a class can change its schema.
3357 	 */
3358 	if (!pg_class_ownercheck(myrelid, GetUserId()))
3359 		aclcheck_error(ACLCHECK_NOT_OWNER, get_relkind_objtype(get_rel_relkind(myrelid)),
3360 					   NameStr(classform->relname));
3361 	if (!allowSystemTableMods && IsSystemClass(myrelid, classform))
3362 		ereport(ERROR,
3363 				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
3364 				 errmsg("permission denied: \"%s\" is a system catalog",
3365 						NameStr(classform->relname))));
3366 }
3367 
3368 /*
3369  *		renameatt_internal		- workhorse for renameatt
3370  *
3371  * Return value is the attribute number in the 'myrelid' relation.
3372  */
3373 static AttrNumber
renameatt_internal(Oid myrelid,const char * oldattname,const char * newattname,bool recurse,bool recursing,int expected_parents,DropBehavior behavior)3374 renameatt_internal(Oid myrelid,
3375 				   const char *oldattname,
3376 				   const char *newattname,
3377 				   bool recurse,
3378 				   bool recursing,
3379 				   int expected_parents,
3380 				   DropBehavior behavior)
3381 {
3382 	Relation	targetrelation;
3383 	Relation	attrelation;
3384 	HeapTuple	atttup;
3385 	Form_pg_attribute attform;
3386 	AttrNumber	attnum;
3387 
3388 	/*
3389 	 * Grab an exclusive lock on the target table, which we will NOT release
3390 	 * until end of transaction.
3391 	 */
3392 	targetrelation = relation_open(myrelid, AccessExclusiveLock);
3393 	renameatt_check(myrelid, RelationGetForm(targetrelation), recursing);
3394 
3395 	/*
3396 	 * if the 'recurse' flag is set then we are supposed to rename this
3397 	 * attribute in all classes that inherit from 'relname' (as well as in
3398 	 * 'relname').
3399 	 *
3400 	 * any permissions or problems with duplicate attributes will cause the
3401 	 * whole transaction to abort, which is what we want -- all or nothing.
3402 	 */
3403 	if (recurse)
3404 	{
3405 		List	   *child_oids,
3406 				   *child_numparents;
3407 		ListCell   *lo,
3408 				   *li;
3409 
3410 		/*
3411 		 * we need the number of parents for each child so that the recursive
3412 		 * calls to renameatt() can determine whether there are any parents
3413 		 * outside the inheritance hierarchy being processed.
3414 		 */
3415 		child_oids = find_all_inheritors(myrelid, AccessExclusiveLock,
3416 										 &child_numparents);
3417 
3418 		/*
3419 		 * find_all_inheritors does the recursive search of the inheritance
3420 		 * hierarchy, so all we have to do is process all of the relids in the
3421 		 * list that it returns.
3422 		 */
3423 		forboth(lo, child_oids, li, child_numparents)
3424 		{
3425 			Oid			childrelid = lfirst_oid(lo);
3426 			int			numparents = lfirst_int(li);
3427 
3428 			if (childrelid == myrelid)
3429 				continue;
3430 			/* note we need not recurse again */
3431 			renameatt_internal(childrelid, oldattname, newattname, false, true, numparents, behavior);
3432 		}
3433 	}
3434 	else
3435 	{
3436 		/*
3437 		 * If we are told not to recurse, there had better not be any child
3438 		 * tables; else the rename would put them out of step.
3439 		 *
3440 		 * expected_parents will only be 0 if we are not already recursing.
3441 		 */
3442 		if (expected_parents == 0 &&
3443 			find_inheritance_children(myrelid, NoLock) != NIL)
3444 			ereport(ERROR,
3445 					(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
3446 					 errmsg("inherited column \"%s\" must be renamed in child tables too",
3447 							oldattname)));
3448 	}
3449 
3450 	/* rename attributes in typed tables of composite type */
3451 	if (targetrelation->rd_rel->relkind == RELKIND_COMPOSITE_TYPE)
3452 	{
3453 		List	   *child_oids;
3454 		ListCell   *lo;
3455 
3456 		child_oids = find_typed_table_dependencies(targetrelation->rd_rel->reltype,
3457 												   RelationGetRelationName(targetrelation),
3458 												   behavior);
3459 
3460 		foreach(lo, child_oids)
3461 			renameatt_internal(lfirst_oid(lo), oldattname, newattname, true, true, 0, behavior);
3462 	}
3463 
3464 	attrelation = table_open(AttributeRelationId, RowExclusiveLock);
3465 
3466 	atttup = SearchSysCacheCopyAttName(myrelid, oldattname);
3467 	if (!HeapTupleIsValid(atttup))
3468 		ereport(ERROR,
3469 				(errcode(ERRCODE_UNDEFINED_COLUMN),
3470 				 errmsg("column \"%s\" does not exist",
3471 						oldattname)));
3472 	attform = (Form_pg_attribute) GETSTRUCT(atttup);
3473 
3474 	attnum = attform->attnum;
3475 	if (attnum <= 0)
3476 		ereport(ERROR,
3477 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3478 				 errmsg("cannot rename system column \"%s\"",
3479 						oldattname)));
3480 
3481 	/*
3482 	 * if the attribute is inherited, forbid the renaming.  if this is a
3483 	 * top-level call to renameatt(), then expected_parents will be 0, so the
3484 	 * effect of this code will be to prohibit the renaming if the attribute
3485 	 * is inherited at all.  if this is a recursive call to renameatt(),
3486 	 * expected_parents will be the number of parents the current relation has
3487 	 * within the inheritance hierarchy being processed, so we'll prohibit the
3488 	 * renaming only if there are additional parents from elsewhere.
3489 	 */
3490 	if (attform->attinhcount > expected_parents)
3491 		ereport(ERROR,
3492 				(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
3493 				 errmsg("cannot rename inherited column \"%s\"",
3494 						oldattname)));
3495 
3496 	/* new name should not already exist */
3497 	(void) check_for_column_name_collision(targetrelation, newattname, false);
3498 
3499 	/* apply the update */
3500 	namestrcpy(&(attform->attname), newattname);
3501 
3502 	CatalogTupleUpdate(attrelation, &atttup->t_self, atttup);
3503 
3504 	InvokeObjectPostAlterHook(RelationRelationId, myrelid, attnum);
3505 
3506 	heap_freetuple(atttup);
3507 
3508 	table_close(attrelation, RowExclusiveLock);
3509 
3510 	relation_close(targetrelation, NoLock); /* close rel but keep lock */
3511 
3512 	return attnum;
3513 }
3514 
3515 /*
3516  * Perform permissions and integrity checks before acquiring a relation lock.
3517  */
3518 static void
RangeVarCallbackForRenameAttribute(const RangeVar * rv,Oid relid,Oid oldrelid,void * arg)3519 RangeVarCallbackForRenameAttribute(const RangeVar *rv, Oid relid, Oid oldrelid,
3520 								   void *arg)
3521 {
3522 	HeapTuple	tuple;
3523 	Form_pg_class form;
3524 
3525 	tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
3526 	if (!HeapTupleIsValid(tuple))
3527 		return;					/* concurrently dropped */
3528 	form = (Form_pg_class) GETSTRUCT(tuple);
3529 	renameatt_check(relid, form, false);
3530 	ReleaseSysCache(tuple);
3531 }
3532 
3533 /*
3534  *		renameatt		- changes the name of an attribute in a relation
3535  *
3536  * The returned ObjectAddress is that of the renamed column.
3537  */
3538 ObjectAddress
renameatt(RenameStmt * stmt)3539 renameatt(RenameStmt *stmt)
3540 {
3541 	Oid			relid;
3542 	AttrNumber	attnum;
3543 	ObjectAddress address;
3544 
3545 	/* lock level taken here should match renameatt_internal */
3546 	relid = RangeVarGetRelidExtended(stmt->relation, AccessExclusiveLock,
3547 									 stmt->missing_ok ? RVR_MISSING_OK : 0,
3548 									 RangeVarCallbackForRenameAttribute,
3549 									 NULL);
3550 
3551 	if (!OidIsValid(relid))
3552 	{
3553 		ereport(NOTICE,
3554 				(errmsg("relation \"%s\" does not exist, skipping",
3555 						stmt->relation->relname)));
3556 		return InvalidObjectAddress;
3557 	}
3558 
3559 	attnum =
3560 		renameatt_internal(relid,
3561 						   stmt->subname,	/* old att name */
3562 						   stmt->newname,	/* new att name */
3563 						   stmt->relation->inh, /* recursive? */
3564 						   false,	/* recursing? */
3565 						   0,	/* expected inhcount */
3566 						   stmt->behavior);
3567 
3568 	ObjectAddressSubSet(address, RelationRelationId, relid, attnum);
3569 
3570 	return address;
3571 }
3572 
3573 /*
3574  * same logic as renameatt_internal
3575  */
3576 static ObjectAddress
rename_constraint_internal(Oid myrelid,Oid mytypid,const char * oldconname,const char * newconname,bool recurse,bool recursing,int expected_parents)3577 rename_constraint_internal(Oid myrelid,
3578 						   Oid mytypid,
3579 						   const char *oldconname,
3580 						   const char *newconname,
3581 						   bool recurse,
3582 						   bool recursing,
3583 						   int expected_parents)
3584 {
3585 	Relation	targetrelation = NULL;
3586 	Oid			constraintOid;
3587 	HeapTuple	tuple;
3588 	Form_pg_constraint con;
3589 	ObjectAddress address;
3590 
3591 	AssertArg(!myrelid || !mytypid);
3592 
3593 	if (mytypid)
3594 	{
3595 		constraintOid = get_domain_constraint_oid(mytypid, oldconname, false);
3596 	}
3597 	else
3598 	{
3599 		targetrelation = relation_open(myrelid, AccessExclusiveLock);
3600 
3601 		/*
3602 		 * don't tell it whether we're recursing; we allow changing typed
3603 		 * tables here
3604 		 */
3605 		renameatt_check(myrelid, RelationGetForm(targetrelation), false);
3606 
3607 		constraintOid = get_relation_constraint_oid(myrelid, oldconname, false);
3608 	}
3609 
3610 	tuple = SearchSysCache1(CONSTROID, ObjectIdGetDatum(constraintOid));
3611 	if (!HeapTupleIsValid(tuple))
3612 		elog(ERROR, "cache lookup failed for constraint %u",
3613 			 constraintOid);
3614 	con = (Form_pg_constraint) GETSTRUCT(tuple);
3615 
3616 	if (myrelid && con->contype == CONSTRAINT_CHECK && !con->connoinherit)
3617 	{
3618 		if (recurse)
3619 		{
3620 			List	   *child_oids,
3621 					   *child_numparents;
3622 			ListCell   *lo,
3623 					   *li;
3624 
3625 			child_oids = find_all_inheritors(myrelid, AccessExclusiveLock,
3626 											 &child_numparents);
3627 
3628 			forboth(lo, child_oids, li, child_numparents)
3629 			{
3630 				Oid			childrelid = lfirst_oid(lo);
3631 				int			numparents = lfirst_int(li);
3632 
3633 				if (childrelid == myrelid)
3634 					continue;
3635 
3636 				rename_constraint_internal(childrelid, InvalidOid, oldconname, newconname, false, true, numparents);
3637 			}
3638 		}
3639 		else
3640 		{
3641 			if (expected_parents == 0 &&
3642 				find_inheritance_children(myrelid, NoLock) != NIL)
3643 				ereport(ERROR,
3644 						(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
3645 						 errmsg("inherited constraint \"%s\" must be renamed in child tables too",
3646 								oldconname)));
3647 		}
3648 
3649 		if (con->coninhcount > expected_parents)
3650 			ereport(ERROR,
3651 					(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
3652 					 errmsg("cannot rename inherited constraint \"%s\"",
3653 							oldconname)));
3654 	}
3655 
3656 	if (con->conindid
3657 		&& (con->contype == CONSTRAINT_PRIMARY
3658 			|| con->contype == CONSTRAINT_UNIQUE
3659 			|| con->contype == CONSTRAINT_EXCLUSION))
3660 		/* rename the index; this renames the constraint as well */
3661 		RenameRelationInternal(con->conindid, newconname, false, true);
3662 	else
3663 		RenameConstraintById(constraintOid, newconname);
3664 
3665 	ObjectAddressSet(address, ConstraintRelationId, constraintOid);
3666 
3667 	ReleaseSysCache(tuple);
3668 
3669 	if (targetrelation)
3670 	{
3671 		/*
3672 		 * Invalidate relcache so as others can see the new constraint name.
3673 		 */
3674 		CacheInvalidateRelcache(targetrelation);
3675 
3676 		relation_close(targetrelation, NoLock); /* close rel but keep lock */
3677 	}
3678 
3679 	return address;
3680 }
3681 
3682 ObjectAddress
RenameConstraint(RenameStmt * stmt)3683 RenameConstraint(RenameStmt *stmt)
3684 {
3685 	Oid			relid = InvalidOid;
3686 	Oid			typid = InvalidOid;
3687 
3688 	if (stmt->renameType == OBJECT_DOMCONSTRAINT)
3689 	{
3690 		Relation	rel;
3691 		HeapTuple	tup;
3692 
3693 		typid = typenameTypeId(NULL, makeTypeNameFromNameList(castNode(List, stmt->object)));
3694 		rel = table_open(TypeRelationId, RowExclusiveLock);
3695 		tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
3696 		if (!HeapTupleIsValid(tup))
3697 			elog(ERROR, "cache lookup failed for type %u", typid);
3698 		checkDomainOwner(tup);
3699 		ReleaseSysCache(tup);
3700 		table_close(rel, NoLock);
3701 	}
3702 	else
3703 	{
3704 		/* lock level taken here should match rename_constraint_internal */
3705 		relid = RangeVarGetRelidExtended(stmt->relation, AccessExclusiveLock,
3706 										 stmt->missing_ok ? RVR_MISSING_OK : 0,
3707 										 RangeVarCallbackForRenameAttribute,
3708 										 NULL);
3709 		if (!OidIsValid(relid))
3710 		{
3711 			ereport(NOTICE,
3712 					(errmsg("relation \"%s\" does not exist, skipping",
3713 							stmt->relation->relname)));
3714 			return InvalidObjectAddress;
3715 		}
3716 	}
3717 
3718 	return
3719 		rename_constraint_internal(relid, typid,
3720 								   stmt->subname,
3721 								   stmt->newname,
3722 								   (stmt->relation &&
3723 									stmt->relation->inh),	/* recursive? */
3724 								   false,	/* recursing? */
3725 								   0 /* expected inhcount */ );
3726 
3727 }
3728 
3729 /*
3730  * Execute ALTER TABLE/INDEX/SEQUENCE/VIEW/MATERIALIZED VIEW/FOREIGN TABLE
3731  * RENAME
3732  */
3733 ObjectAddress
RenameRelation(RenameStmt * stmt)3734 RenameRelation(RenameStmt *stmt)
3735 {
3736 	bool		is_index_stmt = stmt->renameType == OBJECT_INDEX;
3737 	Oid			relid;
3738 	ObjectAddress address;
3739 
3740 	/*
3741 	 * Grab an exclusive lock on the target table, index, sequence, view,
3742 	 * materialized view, or foreign table, which we will NOT release until
3743 	 * end of transaction.
3744 	 *
3745 	 * Lock level used here should match RenameRelationInternal, to avoid lock
3746 	 * escalation.  However, because ALTER INDEX can be used with any relation
3747 	 * type, we mustn't believe without verification.
3748 	 */
3749 	for (;;)
3750 	{
3751 		LOCKMODE	lockmode;
3752 		char		relkind;
3753 		bool		obj_is_index;
3754 
3755 		lockmode = is_index_stmt ? ShareUpdateExclusiveLock : AccessExclusiveLock;
3756 
3757 		relid = RangeVarGetRelidExtended(stmt->relation, lockmode,
3758 										 stmt->missing_ok ? RVR_MISSING_OK : 0,
3759 										 RangeVarCallbackForAlterRelation,
3760 										 (void *) stmt);
3761 
3762 		if (!OidIsValid(relid))
3763 		{
3764 			ereport(NOTICE,
3765 					(errmsg("relation \"%s\" does not exist, skipping",
3766 							stmt->relation->relname)));
3767 			return InvalidObjectAddress;
3768 		}
3769 
3770 		/*
3771 		 * We allow mismatched statement and object types (e.g., ALTER INDEX
3772 		 * to rename a table), but we might've used the wrong lock level.  If
3773 		 * that happens, retry with the correct lock level.  We don't bother
3774 		 * if we already acquired AccessExclusiveLock with an index, however.
3775 		 */
3776 		relkind = get_rel_relkind(relid);
3777 		obj_is_index = (relkind == RELKIND_INDEX ||
3778 						relkind == RELKIND_PARTITIONED_INDEX);
3779 		if (obj_is_index || is_index_stmt == obj_is_index)
3780 			break;
3781 
3782 		UnlockRelationOid(relid, lockmode);
3783 		is_index_stmt = obj_is_index;
3784 	}
3785 
3786 	/* Do the work */
3787 	RenameRelationInternal(relid, stmt->newname, false, is_index_stmt);
3788 
3789 	ObjectAddressSet(address, RelationRelationId, relid);
3790 
3791 	return address;
3792 }
3793 
3794 /*
3795  *		RenameRelationInternal - change the name of a relation
3796  */
3797 void
RenameRelationInternal(Oid myrelid,const char * newrelname,bool is_internal,bool is_index)3798 RenameRelationInternal(Oid myrelid, const char *newrelname, bool is_internal, bool is_index)
3799 {
3800 	Relation	targetrelation;
3801 	Relation	relrelation;	/* for RELATION relation */
3802 	HeapTuple	reltup;
3803 	Form_pg_class relform;
3804 	Oid			namespaceId;
3805 
3806 	/*
3807 	 * Grab a lock on the target relation, which we will NOT release until end
3808 	 * of transaction.  We need at least a self-exclusive lock so that
3809 	 * concurrent DDL doesn't overwrite the rename if they start updating
3810 	 * while still seeing the old version.  The lock also guards against
3811 	 * triggering relcache reloads in concurrent sessions, which might not
3812 	 * handle this information changing under them.  For indexes, we can use a
3813 	 * reduced lock level because RelationReloadIndexInfo() handles indexes
3814 	 * specially.
3815 	 */
3816 	targetrelation = relation_open(myrelid, is_index ? ShareUpdateExclusiveLock : AccessExclusiveLock);
3817 	namespaceId = RelationGetNamespace(targetrelation);
3818 
3819 	/*
3820 	 * Find relation's pg_class tuple, and make sure newrelname isn't in use.
3821 	 */
3822 	relrelation = table_open(RelationRelationId, RowExclusiveLock);
3823 
3824 	reltup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(myrelid));
3825 	if (!HeapTupleIsValid(reltup))	/* shouldn't happen */
3826 		elog(ERROR, "cache lookup failed for relation %u", myrelid);
3827 	relform = (Form_pg_class) GETSTRUCT(reltup);
3828 
3829 	if (get_relname_relid(newrelname, namespaceId) != InvalidOid)
3830 		ereport(ERROR,
3831 				(errcode(ERRCODE_DUPLICATE_TABLE),
3832 				 errmsg("relation \"%s\" already exists",
3833 						newrelname)));
3834 
3835 	/*
3836 	 * RenameRelation is careful not to believe the caller's idea of the
3837 	 * relation kind being handled.  We don't have to worry about this, but
3838 	 * let's not be totally oblivious to it.  We can process an index as
3839 	 * not-an-index, but not the other way around.
3840 	 */
3841 	Assert(!is_index ||
3842 		   is_index == (targetrelation->rd_rel->relkind == RELKIND_INDEX ||
3843 						targetrelation->rd_rel->relkind == RELKIND_PARTITIONED_INDEX));
3844 
3845 	/*
3846 	 * Update pg_class tuple with new relname.  (Scribbling on reltup is OK
3847 	 * because it's a copy...)
3848 	 */
3849 	namestrcpy(&(relform->relname), newrelname);
3850 
3851 	CatalogTupleUpdate(relrelation, &reltup->t_self, reltup);
3852 
3853 	InvokeObjectPostAlterHookArg(RelationRelationId, myrelid, 0,
3854 								 InvalidOid, is_internal);
3855 
3856 	heap_freetuple(reltup);
3857 	table_close(relrelation, RowExclusiveLock);
3858 
3859 	/*
3860 	 * Also rename the associated type, if any.
3861 	 */
3862 	if (OidIsValid(targetrelation->rd_rel->reltype))
3863 		RenameTypeInternal(targetrelation->rd_rel->reltype,
3864 						   newrelname, namespaceId);
3865 
3866 	/*
3867 	 * Also rename the associated constraint, if any.
3868 	 */
3869 	if (targetrelation->rd_rel->relkind == RELKIND_INDEX ||
3870 		targetrelation->rd_rel->relkind == RELKIND_PARTITIONED_INDEX)
3871 	{
3872 		Oid			constraintId = get_index_constraint(myrelid);
3873 
3874 		if (OidIsValid(constraintId))
3875 			RenameConstraintById(constraintId, newrelname);
3876 	}
3877 
3878 	/*
3879 	 * Close rel, but keep lock!
3880 	 */
3881 	relation_close(targetrelation, NoLock);
3882 }
3883 
3884 /*
3885  *		ResetRelRewrite - reset relrewrite
3886  */
3887 void
ResetRelRewrite(Oid myrelid)3888 ResetRelRewrite(Oid myrelid)
3889 {
3890 	Relation	relrelation;	/* for RELATION relation */
3891 	HeapTuple	reltup;
3892 	Form_pg_class relform;
3893 
3894 	/*
3895 	 * Find relation's pg_class tuple.
3896 	 */
3897 	relrelation = table_open(RelationRelationId, RowExclusiveLock);
3898 
3899 	reltup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(myrelid));
3900 	if (!HeapTupleIsValid(reltup))	/* shouldn't happen */
3901 		elog(ERROR, "cache lookup failed for relation %u", myrelid);
3902 	relform = (Form_pg_class) GETSTRUCT(reltup);
3903 
3904 	/*
3905 	 * Update pg_class tuple.
3906 	 */
3907 	relform->relrewrite = InvalidOid;
3908 
3909 	CatalogTupleUpdate(relrelation, &reltup->t_self, reltup);
3910 
3911 	heap_freetuple(reltup);
3912 	table_close(relrelation, RowExclusiveLock);
3913 }
3914 
3915 /*
3916  * Disallow ALTER TABLE (and similar commands) when the current backend has
3917  * any open reference to the target table besides the one just acquired by
3918  * the calling command; this implies there's an open cursor or active plan.
3919  * We need this check because our lock doesn't protect us against stomping
3920  * on our own foot, only other people's feet!
3921  *
3922  * For ALTER TABLE, the only case known to cause serious trouble is ALTER
3923  * COLUMN TYPE, and some changes are obviously pretty benign, so this could
3924  * possibly be relaxed to only error out for certain types of alterations.
3925  * But the use-case for allowing any of these things is not obvious, so we
3926  * won't work hard at it for now.
3927  *
3928  * We also reject these commands if there are any pending AFTER trigger events
3929  * for the rel.  This is certainly necessary for the rewriting variants of
3930  * ALTER TABLE, because they don't preserve tuple TIDs and so the pending
3931  * events would try to fetch the wrong tuples.  It might be overly cautious
3932  * in other cases, but again it seems better to err on the side of paranoia.
3933  *
3934  * REINDEX calls this with "rel" referencing the index to be rebuilt; here
3935  * we are worried about active indexscans on the index.  The trigger-event
3936  * check can be skipped, since we are doing no damage to the parent table.
3937  *
3938  * The statement name (eg, "ALTER TABLE") is passed for use in error messages.
3939  */
3940 void
CheckTableNotInUse(Relation rel,const char * stmt)3941 CheckTableNotInUse(Relation rel, const char *stmt)
3942 {
3943 	int			expected_refcnt;
3944 
3945 	expected_refcnt = rel->rd_isnailed ? 2 : 1;
3946 	if (rel->rd_refcnt != expected_refcnt)
3947 		ereport(ERROR,
3948 				(errcode(ERRCODE_OBJECT_IN_USE),
3949 		/* translator: first %s is a SQL command, eg ALTER TABLE */
3950 				 errmsg("cannot %s \"%s\" because it is being used by active queries in this session",
3951 						stmt, RelationGetRelationName(rel))));
3952 
3953 	if (rel->rd_rel->relkind != RELKIND_INDEX &&
3954 		rel->rd_rel->relkind != RELKIND_PARTITIONED_INDEX &&
3955 		AfterTriggerPendingOnRel(RelationGetRelid(rel)))
3956 		ereport(ERROR,
3957 				(errcode(ERRCODE_OBJECT_IN_USE),
3958 		/* translator: first %s is a SQL command, eg ALTER TABLE */
3959 				 errmsg("cannot %s \"%s\" because it has pending trigger events",
3960 						stmt, RelationGetRelationName(rel))));
3961 }
3962 
3963 /*
3964  * AlterTableLookupRelation
3965  *		Look up, and lock, the OID for the relation named by an alter table
3966  *		statement.
3967  */
3968 Oid
AlterTableLookupRelation(AlterTableStmt * stmt,LOCKMODE lockmode)3969 AlterTableLookupRelation(AlterTableStmt *stmt, LOCKMODE lockmode)
3970 {
3971 	return RangeVarGetRelidExtended(stmt->relation, lockmode,
3972 									stmt->missing_ok ? RVR_MISSING_OK : 0,
3973 									RangeVarCallbackForAlterRelation,
3974 									(void *) stmt);
3975 }
3976 
3977 /*
3978  * AlterTable
3979  *		Execute ALTER TABLE, which can be a list of subcommands
3980  *
3981  * ALTER TABLE is performed in three phases:
3982  *		1. Examine subcommands and perform pre-transformation checking.
3983  *		2. Validate and transform subcommands, and update system catalogs.
3984  *		3. Scan table(s) to check new constraints, and optionally recopy
3985  *		   the data into new table(s).
3986  * Phase 3 is not performed unless one or more of the subcommands requires
3987  * it.  The intention of this design is to allow multiple independent
3988  * updates of the table schema to be performed with only one pass over the
3989  * data.
3990  *
3991  * ATPrepCmd performs phase 1.  A "work queue" entry is created for
3992  * each table to be affected (there may be multiple affected tables if the
3993  * commands traverse a table inheritance hierarchy).  Also we do preliminary
3994  * validation of the subcommands.  Because earlier subcommands may change
3995  * the catalog state seen by later commands, there are limits to what can
3996  * be done in this phase.  Generally, this phase acquires table locks,
3997  * checks permissions and relkind, and recurses to find child tables.
3998  *
3999  * ATRewriteCatalogs performs phase 2 for each affected table.  (Note that
4000  * phases 2 and 3 normally do no explicit recursion, since phase 1 already
4001  * did it --- although some subcommands have to recurse in phase 2 instead.)
4002  * Certain subcommands need to be performed before others to avoid
4003  * unnecessary conflicts; for example, DROP COLUMN should come before
4004  * ADD COLUMN.  Therefore phase 1 divides the subcommands into multiple
4005  * lists, one for each logical "pass" of phase 2.
4006  *
4007  * ATRewriteTables performs phase 3 for those tables that need it.
4008  *
4009  * Thanks to the magic of MVCC, an error anywhere along the way rolls back
4010  * the whole operation; we don't have to do anything special to clean up.
4011  *
4012  * The caller must lock the relation, with an appropriate lock level
4013  * for the subcommands requested, using AlterTableGetLockLevel(stmt->cmds)
4014  * or higher. We pass the lock level down
4015  * so that we can apply it recursively to inherited tables. Note that the
4016  * lock level we want as we recurse might well be higher than required for
4017  * that specific subcommand. So we pass down the overall lock requirement,
4018  * rather than reassess it at lower levels.
4019  *
4020  * The caller also provides a "context" which is to be passed back to
4021  * utility.c when we need to execute a subcommand such as CREATE INDEX.
4022  * Some of the fields therein, such as the relid, are used here as well.
4023  */
4024 void
AlterTable(AlterTableStmt * stmt,LOCKMODE lockmode,AlterTableUtilityContext * context)4025 AlterTable(AlterTableStmt *stmt, LOCKMODE lockmode,
4026 		   AlterTableUtilityContext *context)
4027 {
4028 	Relation	rel;
4029 
4030 	/* Caller is required to provide an adequate lock. */
4031 	rel = relation_open(context->relid, NoLock);
4032 
4033 	CheckTableNotInUse(rel, "ALTER TABLE");
4034 
4035 	ATController(stmt, rel, stmt->cmds, stmt->relation->inh, lockmode, context);
4036 }
4037 
4038 /*
4039  * AlterTableInternal
4040  *
4041  * ALTER TABLE with target specified by OID
4042  *
4043  * We do not reject if the relation is already open, because it's quite
4044  * likely that one or more layers of caller have it open.  That means it
4045  * is unsafe to use this entry point for alterations that could break
4046  * existing query plans.  On the assumption it's not used for such, we
4047  * don't have to reject pending AFTER triggers, either.
4048  *
4049  * Also, since we don't have an AlterTableUtilityContext, this cannot be
4050  * used for any subcommand types that require parse transformation or
4051  * could generate subcommands that have to be passed to ProcessUtility.
4052  */
4053 void
AlterTableInternal(Oid relid,List * cmds,bool recurse)4054 AlterTableInternal(Oid relid, List *cmds, bool recurse)
4055 {
4056 	Relation	rel;
4057 	LOCKMODE	lockmode = AlterTableGetLockLevel(cmds);
4058 
4059 	rel = relation_open(relid, lockmode);
4060 
4061 	EventTriggerAlterTableRelid(relid);
4062 
4063 	ATController(NULL, rel, cmds, recurse, lockmode, NULL);
4064 }
4065 
4066 /*
4067  * AlterTableGetLockLevel
4068  *
4069  * Sets the overall lock level required for the supplied list of subcommands.
4070  * Policy for doing this set according to needs of AlterTable(), see
4071  * comments there for overall explanation.
4072  *
4073  * Function is called before and after parsing, so it must give same
4074  * answer each time it is called. Some subcommands are transformed
4075  * into other subcommand types, so the transform must never be made to a
4076  * lower lock level than previously assigned. All transforms are noted below.
4077  *
4078  * Since this is called before we lock the table we cannot use table metadata
4079  * to influence the type of lock we acquire.
4080  *
4081  * There should be no lockmodes hardcoded into the subcommand functions. All
4082  * lockmode decisions for ALTER TABLE are made here only. The one exception is
4083  * ALTER TABLE RENAME which is treated as a different statement type T_RenameStmt
4084  * and does not travel through this section of code and cannot be combined with
4085  * any of the subcommands given here.
4086  *
4087  * Note that Hot Standby only knows about AccessExclusiveLocks on the primary
4088  * so any changes that might affect SELECTs running on standbys need to use
4089  * AccessExclusiveLocks even if you think a lesser lock would do, unless you
4090  * have a solution for that also.
4091  *
4092  * Also note that pg_dump uses only an AccessShareLock, meaning that anything
4093  * that takes a lock less than AccessExclusiveLock can change object definitions
4094  * while pg_dump is running. Be careful to check that the appropriate data is
4095  * derived by pg_dump using an MVCC snapshot, rather than syscache lookups,
4096  * otherwise we might end up with an inconsistent dump that can't restore.
4097  */
4098 LOCKMODE
AlterTableGetLockLevel(List * cmds)4099 AlterTableGetLockLevel(List *cmds)
4100 {
4101 	/*
4102 	 * This only works if we read catalog tables using MVCC snapshots.
4103 	 */
4104 	ListCell   *lcmd;
4105 	LOCKMODE	lockmode = ShareUpdateExclusiveLock;
4106 
4107 	foreach(lcmd, cmds)
4108 	{
4109 		AlterTableCmd *cmd = (AlterTableCmd *) lfirst(lcmd);
4110 		LOCKMODE	cmd_lockmode = AccessExclusiveLock; /* default for compiler */
4111 
4112 		switch (cmd->subtype)
4113 		{
4114 				/*
4115 				 * These subcommands rewrite the heap, so require full locks.
4116 				 */
4117 			case AT_AddColumn:	/* may rewrite heap, in some cases and visible
4118 								 * to SELECT */
4119 			case AT_SetTableSpace:	/* must rewrite heap */
4120 			case AT_AlterColumnType:	/* must rewrite heap */
4121 				cmd_lockmode = AccessExclusiveLock;
4122 				break;
4123 
4124 				/*
4125 				 * These subcommands may require addition of toast tables. If
4126 				 * we add a toast table to a table currently being scanned, we
4127 				 * might miss data added to the new toast table by concurrent
4128 				 * insert transactions.
4129 				 */
4130 			case AT_SetStorage: /* may add toast tables, see
4131 								 * ATRewriteCatalogs() */
4132 				cmd_lockmode = AccessExclusiveLock;
4133 				break;
4134 
4135 				/*
4136 				 * Removing constraints can affect SELECTs that have been
4137 				 * optimized assuming the constraint holds true. See also
4138 				 * CloneFkReferenced.
4139 				 */
4140 			case AT_DropConstraint: /* as DROP INDEX */
4141 			case AT_DropNotNull:	/* may change some SQL plans */
4142 				cmd_lockmode = AccessExclusiveLock;
4143 				break;
4144 
4145 				/*
4146 				 * Subcommands that may be visible to concurrent SELECTs
4147 				 */
4148 			case AT_DropColumn: /* change visible to SELECT */
4149 			case AT_AddColumnToView:	/* CREATE VIEW */
4150 			case AT_DropOids:	/* used to equiv to DropColumn */
4151 			case AT_EnableAlwaysRule:	/* may change SELECT rules */
4152 			case AT_EnableReplicaRule:	/* may change SELECT rules */
4153 			case AT_EnableRule: /* may change SELECT rules */
4154 			case AT_DisableRule:	/* may change SELECT rules */
4155 				cmd_lockmode = AccessExclusiveLock;
4156 				break;
4157 
4158 				/*
4159 				 * Changing owner may remove implicit SELECT privileges
4160 				 */
4161 			case AT_ChangeOwner:	/* change visible to SELECT */
4162 				cmd_lockmode = AccessExclusiveLock;
4163 				break;
4164 
4165 				/*
4166 				 * Changing foreign table options may affect optimization.
4167 				 */
4168 			case AT_GenericOptions:
4169 			case AT_AlterColumnGenericOptions:
4170 				cmd_lockmode = AccessExclusiveLock;
4171 				break;
4172 
4173 				/*
4174 				 * These subcommands affect write operations only.
4175 				 */
4176 			case AT_EnableTrig:
4177 			case AT_EnableAlwaysTrig:
4178 			case AT_EnableReplicaTrig:
4179 			case AT_EnableTrigAll:
4180 			case AT_EnableTrigUser:
4181 			case AT_DisableTrig:
4182 			case AT_DisableTrigAll:
4183 			case AT_DisableTrigUser:
4184 				cmd_lockmode = ShareRowExclusiveLock;
4185 				break;
4186 
4187 				/*
4188 				 * These subcommands affect write operations only. XXX
4189 				 * Theoretically, these could be ShareRowExclusiveLock.
4190 				 */
4191 			case AT_ColumnDefault:
4192 			case AT_CookedColumnDefault:
4193 			case AT_AlterConstraint:
4194 			case AT_AddIndex:	/* from ADD CONSTRAINT */
4195 			case AT_AddIndexConstraint:
4196 			case AT_ReplicaIdentity:
4197 			case AT_SetNotNull:
4198 			case AT_EnableRowSecurity:
4199 			case AT_DisableRowSecurity:
4200 			case AT_ForceRowSecurity:
4201 			case AT_NoForceRowSecurity:
4202 			case AT_AddIdentity:
4203 			case AT_DropIdentity:
4204 			case AT_SetIdentity:
4205 			case AT_DropExpression:
4206 			case AT_SetCompression:
4207 				cmd_lockmode = AccessExclusiveLock;
4208 				break;
4209 
4210 			case AT_AddConstraint:
4211 			case AT_AddConstraintRecurse:	/* becomes AT_AddConstraint */
4212 			case AT_ReAddConstraint:	/* becomes AT_AddConstraint */
4213 			case AT_ReAddDomainConstraint:	/* becomes AT_AddConstraint */
4214 				if (IsA(cmd->def, Constraint))
4215 				{
4216 					Constraint *con = (Constraint *) cmd->def;
4217 
4218 					switch (con->contype)
4219 					{
4220 						case CONSTR_EXCLUSION:
4221 						case CONSTR_PRIMARY:
4222 						case CONSTR_UNIQUE:
4223 
4224 							/*
4225 							 * Cases essentially the same as CREATE INDEX. We
4226 							 * could reduce the lock strength to ShareLock if
4227 							 * we can work out how to allow concurrent catalog
4228 							 * updates. XXX Might be set down to
4229 							 * ShareRowExclusiveLock but requires further
4230 							 * analysis.
4231 							 */
4232 							cmd_lockmode = AccessExclusiveLock;
4233 							break;
4234 						case CONSTR_FOREIGN:
4235 
4236 							/*
4237 							 * We add triggers to both tables when we add a
4238 							 * Foreign Key, so the lock level must be at least
4239 							 * as strong as CREATE TRIGGER.
4240 							 */
4241 							cmd_lockmode = ShareRowExclusiveLock;
4242 							break;
4243 
4244 						default:
4245 							cmd_lockmode = AccessExclusiveLock;
4246 					}
4247 				}
4248 				break;
4249 
4250 				/*
4251 				 * These subcommands affect inheritance behaviour. Queries
4252 				 * started before us will continue to see the old inheritance
4253 				 * behaviour, while queries started after we commit will see
4254 				 * new behaviour. No need to prevent reads or writes to the
4255 				 * subtable while we hook it up though. Changing the TupDesc
4256 				 * may be a problem, so keep highest lock.
4257 				 */
4258 			case AT_AddInherit:
4259 			case AT_DropInherit:
4260 				cmd_lockmode = AccessExclusiveLock;
4261 				break;
4262 
4263 				/*
4264 				 * These subcommands affect implicit row type conversion. They
4265 				 * have affects similar to CREATE/DROP CAST on queries. don't
4266 				 * provide for invalidating parse trees as a result of such
4267 				 * changes, so we keep these at AccessExclusiveLock.
4268 				 */
4269 			case AT_AddOf:
4270 			case AT_DropOf:
4271 				cmd_lockmode = AccessExclusiveLock;
4272 				break;
4273 
4274 				/*
4275 				 * Only used by CREATE OR REPLACE VIEW which must conflict
4276 				 * with an SELECTs currently using the view.
4277 				 */
4278 			case AT_ReplaceRelOptions:
4279 				cmd_lockmode = AccessExclusiveLock;
4280 				break;
4281 
4282 				/*
4283 				 * These subcommands affect general strategies for performance
4284 				 * and maintenance, though don't change the semantic results
4285 				 * from normal data reads and writes. Delaying an ALTER TABLE
4286 				 * behind currently active writes only delays the point where
4287 				 * the new strategy begins to take effect, so there is no
4288 				 * benefit in waiting. In this case the minimum restriction
4289 				 * applies: we don't currently allow concurrent catalog
4290 				 * updates.
4291 				 */
4292 			case AT_SetStatistics:	/* Uses MVCC in getTableAttrs() */
4293 			case AT_ClusterOn:	/* Uses MVCC in getIndexes() */
4294 			case AT_DropCluster:	/* Uses MVCC in getIndexes() */
4295 			case AT_SetOptions: /* Uses MVCC in getTableAttrs() */
4296 			case AT_ResetOptions:	/* Uses MVCC in getTableAttrs() */
4297 				cmd_lockmode = ShareUpdateExclusiveLock;
4298 				break;
4299 
4300 			case AT_SetLogged:
4301 			case AT_SetUnLogged:
4302 				cmd_lockmode = AccessExclusiveLock;
4303 				break;
4304 
4305 			case AT_ValidateConstraint: /* Uses MVCC in getConstraints() */
4306 				cmd_lockmode = ShareUpdateExclusiveLock;
4307 				break;
4308 
4309 				/*
4310 				 * Rel options are more complex than first appears. Options
4311 				 * are set here for tables, views and indexes; for historical
4312 				 * reasons these can all be used with ALTER TABLE, so we can't
4313 				 * decide between them using the basic grammar.
4314 				 */
4315 			case AT_SetRelOptions:	/* Uses MVCC in getIndexes() and
4316 									 * getTables() */
4317 			case AT_ResetRelOptions:	/* Uses MVCC in getIndexes() and
4318 										 * getTables() */
4319 				cmd_lockmode = AlterTableGetRelOptionsLockLevel((List *) cmd->def);
4320 				break;
4321 
4322 			case AT_AttachPartition:
4323 				cmd_lockmode = ShareUpdateExclusiveLock;
4324 				break;
4325 
4326 			case AT_DetachPartition:
4327 				if (((PartitionCmd *) cmd->def)->concurrent)
4328 					cmd_lockmode = ShareUpdateExclusiveLock;
4329 				else
4330 					cmd_lockmode = AccessExclusiveLock;
4331 				break;
4332 
4333 			case AT_DetachPartitionFinalize:
4334 				cmd_lockmode = ShareUpdateExclusiveLock;
4335 				break;
4336 
4337 			case AT_CheckNotNull:
4338 
4339 				/*
4340 				 * This only examines the table's schema; but lock must be
4341 				 * strong enough to prevent concurrent DROP NOT NULL.
4342 				 */
4343 				cmd_lockmode = AccessShareLock;
4344 				break;
4345 
4346 			default:			/* oops */
4347 				elog(ERROR, "unrecognized alter table type: %d",
4348 					 (int) cmd->subtype);
4349 				break;
4350 		}
4351 
4352 		/*
4353 		 * Take the greatest lockmode from any subcommand
4354 		 */
4355 		if (cmd_lockmode > lockmode)
4356 			lockmode = cmd_lockmode;
4357 	}
4358 
4359 	return lockmode;
4360 }
4361 
4362 /*
4363  * ATController provides top level control over the phases.
4364  *
4365  * parsetree is passed in to allow it to be passed to event triggers
4366  * when requested.
4367  */
4368 static void
ATController(AlterTableStmt * parsetree,Relation rel,List * cmds,bool recurse,LOCKMODE lockmode,AlterTableUtilityContext * context)4369 ATController(AlterTableStmt *parsetree,
4370 			 Relation rel, List *cmds, bool recurse, LOCKMODE lockmode,
4371 			 AlterTableUtilityContext *context)
4372 {
4373 	List	   *wqueue = NIL;
4374 	ListCell   *lcmd;
4375 
4376 	/* Phase 1: preliminary examination of commands, create work queue */
4377 	foreach(lcmd, cmds)
4378 	{
4379 		AlterTableCmd *cmd = (AlterTableCmd *) lfirst(lcmd);
4380 
4381 		ATPrepCmd(&wqueue, rel, cmd, recurse, false, lockmode, context);
4382 	}
4383 
4384 	/* Close the relation, but keep lock until commit */
4385 	relation_close(rel, NoLock);
4386 
4387 	/* Phase 2: update system catalogs */
4388 	ATRewriteCatalogs(&wqueue, lockmode, context);
4389 
4390 	/* Phase 3: scan/rewrite tables as needed, and run afterStmts */
4391 	ATRewriteTables(parsetree, &wqueue, lockmode, context);
4392 }
4393 
4394 /*
4395  * ATPrepCmd
4396  *
4397  * Traffic cop for ALTER TABLE Phase 1 operations, including simple
4398  * recursion and permission checks.
4399  *
4400  * Caller must have acquired appropriate lock type on relation already.
4401  * This lock should be held until commit.
4402  */
4403 static void
ATPrepCmd(List ** wqueue,Relation rel,AlterTableCmd * cmd,bool recurse,bool recursing,LOCKMODE lockmode,AlterTableUtilityContext * context)4404 ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd,
4405 		  bool recurse, bool recursing, LOCKMODE lockmode,
4406 		  AlterTableUtilityContext *context)
4407 {
4408 	AlteredTableInfo *tab;
4409 	int			pass = AT_PASS_UNSET;
4410 
4411 	/* Find or create work queue entry for this table */
4412 	tab = ATGetQueueEntry(wqueue, rel);
4413 
4414 	/*
4415 	 * Disallow any ALTER TABLE other than ALTER TABLE DETACH FINALIZE on
4416 	 * partitions that are pending detach.
4417 	 */
4418 	if (rel->rd_rel->relispartition &&
4419 		cmd->subtype != AT_DetachPartitionFinalize &&
4420 		PartitionHasPendingDetach(RelationGetRelid(rel)))
4421 		ereport(ERROR,
4422 				errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
4423 				errmsg("cannot alter partition \"%s\" with an incomplete detach",
4424 					   RelationGetRelationName(rel)),
4425 				errhint("Use ALTER TABLE ... DETACH PARTITION ... FINALIZE to complete the pending detach operation."));
4426 
4427 	/*
4428 	 * Copy the original subcommand for each table.  This avoids conflicts
4429 	 * when different child tables need to make different parse
4430 	 * transformations (for example, the same column may have different column
4431 	 * numbers in different children).
4432 	 */
4433 	cmd = copyObject(cmd);
4434 
4435 	/*
4436 	 * Do permissions and relkind checking, recursion to child tables if
4437 	 * needed, and any additional phase-1 processing needed.  (But beware of
4438 	 * adding any processing that looks at table details that another
4439 	 * subcommand could change.  In some cases we reject multiple subcommands
4440 	 * that could try to change the same state in contrary ways.)
4441 	 */
4442 	switch (cmd->subtype)
4443 	{
4444 		case AT_AddColumn:		/* ADD COLUMN */
4445 			ATSimplePermissions(rel,
4446 								ATT_TABLE | ATT_COMPOSITE_TYPE | ATT_FOREIGN_TABLE);
4447 			ATPrepAddColumn(wqueue, rel, recurse, recursing, false, cmd,
4448 							lockmode, context);
4449 			/* Recursion occurs during execution phase */
4450 			pass = AT_PASS_ADD_COL;
4451 			break;
4452 		case AT_AddColumnToView:	/* add column via CREATE OR REPLACE VIEW */
4453 			ATSimplePermissions(rel, ATT_VIEW);
4454 			ATPrepAddColumn(wqueue, rel, recurse, recursing, true, cmd,
4455 							lockmode, context);
4456 			/* Recursion occurs during execution phase */
4457 			pass = AT_PASS_ADD_COL;
4458 			break;
4459 		case AT_ColumnDefault:	/* ALTER COLUMN DEFAULT */
4460 
4461 			/*
4462 			 * We allow defaults on views so that INSERT into a view can have
4463 			 * default-ish behavior.  This works because the rewriter
4464 			 * substitutes default values into INSERTs before it expands
4465 			 * rules.
4466 			 */
4467 			ATSimplePermissions(rel, ATT_TABLE | ATT_VIEW | ATT_FOREIGN_TABLE);
4468 			ATSimpleRecursion(wqueue, rel, cmd, recurse, lockmode, context);
4469 			/* No command-specific prep needed */
4470 			pass = cmd->def ? AT_PASS_ADD_OTHERCONSTR : AT_PASS_DROP;
4471 			break;
4472 		case AT_CookedColumnDefault:	/* add a pre-cooked default */
4473 			/* This is currently used only in CREATE TABLE */
4474 			/* (so the permission check really isn't necessary) */
4475 			ATSimplePermissions(rel, ATT_TABLE | ATT_FOREIGN_TABLE);
4476 			/* This command never recurses */
4477 			pass = AT_PASS_ADD_OTHERCONSTR;
4478 			break;
4479 		case AT_AddIdentity:
4480 			ATSimplePermissions(rel, ATT_TABLE | ATT_VIEW | ATT_FOREIGN_TABLE);
4481 			/* This command never recurses */
4482 			pass = AT_PASS_ADD_OTHERCONSTR;
4483 			break;
4484 		case AT_SetIdentity:
4485 			ATSimplePermissions(rel, ATT_TABLE | ATT_VIEW | ATT_FOREIGN_TABLE);
4486 			/* This command never recurses */
4487 			/* This should run after AddIdentity, so do it in MISC pass */
4488 			pass = AT_PASS_MISC;
4489 			break;
4490 		case AT_DropIdentity:
4491 			ATSimplePermissions(rel, ATT_TABLE | ATT_VIEW | ATT_FOREIGN_TABLE);
4492 			/* This command never recurses */
4493 			pass = AT_PASS_DROP;
4494 			break;
4495 		case AT_DropNotNull:	/* ALTER COLUMN DROP NOT NULL */
4496 			ATSimplePermissions(rel, ATT_TABLE | ATT_FOREIGN_TABLE);
4497 			ATPrepDropNotNull(rel, recurse, recursing);
4498 			ATSimpleRecursion(wqueue, rel, cmd, recurse, lockmode, context);
4499 			pass = AT_PASS_DROP;
4500 			break;
4501 		case AT_SetNotNull:		/* ALTER COLUMN SET NOT NULL */
4502 			ATSimplePermissions(rel, ATT_TABLE | ATT_FOREIGN_TABLE);
4503 			/* Need command-specific recursion decision */
4504 			ATPrepSetNotNull(wqueue, rel, cmd, recurse, recursing,
4505 							 lockmode, context);
4506 			pass = AT_PASS_COL_ATTRS;
4507 			break;
4508 		case AT_CheckNotNull:	/* check column is already marked NOT NULL */
4509 			ATSimplePermissions(rel, ATT_TABLE | ATT_FOREIGN_TABLE);
4510 			ATSimpleRecursion(wqueue, rel, cmd, recurse, lockmode, context);
4511 			/* No command-specific prep needed */
4512 			pass = AT_PASS_COL_ATTRS;
4513 			break;
4514 		case AT_DropExpression: /* ALTER COLUMN DROP EXPRESSION */
4515 			ATSimplePermissions(rel, ATT_TABLE | ATT_FOREIGN_TABLE);
4516 			ATSimpleRecursion(wqueue, rel, cmd, recurse, lockmode, context);
4517 			ATPrepDropExpression(rel, cmd, recurse, recursing, lockmode);
4518 			pass = AT_PASS_DROP;
4519 			break;
4520 		case AT_SetStatistics:	/* ALTER COLUMN SET STATISTICS */
4521 			ATSimplePermissions(rel, ATT_TABLE | ATT_MATVIEW | ATT_INDEX | ATT_PARTITIONED_INDEX | ATT_FOREIGN_TABLE);
4522 			ATSimpleRecursion(wqueue, rel, cmd, recurse, lockmode, context);
4523 			/* No command-specific prep needed */
4524 			pass = AT_PASS_MISC;
4525 			break;
4526 		case AT_SetOptions:		/* ALTER COLUMN SET ( options ) */
4527 		case AT_ResetOptions:	/* ALTER COLUMN RESET ( options ) */
4528 			ATSimplePermissions(rel, ATT_TABLE | ATT_MATVIEW | ATT_FOREIGN_TABLE);
4529 			/* This command never recurses */
4530 			pass = AT_PASS_MISC;
4531 			break;
4532 		case AT_SetStorage:		/* ALTER COLUMN SET STORAGE */
4533 			ATSimplePermissions(rel, ATT_TABLE | ATT_MATVIEW | ATT_FOREIGN_TABLE);
4534 			ATSimpleRecursion(wqueue, rel, cmd, recurse, lockmode, context);
4535 			/* No command-specific prep needed */
4536 			pass = AT_PASS_MISC;
4537 			break;
4538 		case AT_SetCompression: /* ALTER COLUMN SET COMPRESSION */
4539 			ATSimplePermissions(rel, ATT_TABLE | ATT_MATVIEW);
4540 			/* This command never recurses */
4541 			/* No command-specific prep needed */
4542 			pass = AT_PASS_MISC;
4543 			break;
4544 		case AT_DropColumn:		/* DROP COLUMN */
4545 			ATSimplePermissions(rel,
4546 								ATT_TABLE | ATT_COMPOSITE_TYPE | ATT_FOREIGN_TABLE);
4547 			ATPrepDropColumn(wqueue, rel, recurse, recursing, cmd,
4548 							 lockmode, context);
4549 			/* Recursion occurs during execution phase */
4550 			pass = AT_PASS_DROP;
4551 			break;
4552 		case AT_AddIndex:		/* ADD INDEX */
4553 			ATSimplePermissions(rel, ATT_TABLE);
4554 			/* This command never recurses */
4555 			/* No command-specific prep needed */
4556 			pass = AT_PASS_ADD_INDEX;
4557 			break;
4558 		case AT_AddConstraint:	/* ADD CONSTRAINT */
4559 			ATSimplePermissions(rel, ATT_TABLE | ATT_FOREIGN_TABLE);
4560 			/* Recursion occurs during execution phase */
4561 			/* No command-specific prep needed except saving recurse flag */
4562 			if (recurse)
4563 				cmd->subtype = AT_AddConstraintRecurse;
4564 			pass = AT_PASS_ADD_CONSTR;
4565 			break;
4566 		case AT_AddIndexConstraint: /* ADD CONSTRAINT USING INDEX */
4567 			ATSimplePermissions(rel, ATT_TABLE);
4568 			/* This command never recurses */
4569 			/* No command-specific prep needed */
4570 			pass = AT_PASS_ADD_INDEXCONSTR;
4571 			break;
4572 		case AT_DropConstraint: /* DROP CONSTRAINT */
4573 			ATSimplePermissions(rel, ATT_TABLE | ATT_FOREIGN_TABLE);
4574 			ATCheckPartitionsNotInUse(rel, lockmode);
4575 			/* Other recursion occurs during execution phase */
4576 			/* No command-specific prep needed except saving recurse flag */
4577 			if (recurse)
4578 				cmd->subtype = AT_DropConstraintRecurse;
4579 			pass = AT_PASS_DROP;
4580 			break;
4581 		case AT_AlterColumnType:	/* ALTER COLUMN TYPE */
4582 			ATSimplePermissions(rel,
4583 								ATT_TABLE | ATT_COMPOSITE_TYPE | ATT_FOREIGN_TABLE);
4584 			/* See comments for ATPrepAlterColumnType */
4585 			cmd = ATParseTransformCmd(wqueue, tab, rel, cmd, recurse, lockmode,
4586 									  AT_PASS_UNSET, context);
4587 			Assert(cmd != NULL);
4588 			/* Performs own recursion */
4589 			ATPrepAlterColumnType(wqueue, tab, rel, recurse, recursing, cmd,
4590 								  lockmode, context);
4591 			pass = AT_PASS_ALTER_TYPE;
4592 			break;
4593 		case AT_AlterColumnGenericOptions:
4594 			ATSimplePermissions(rel, ATT_FOREIGN_TABLE);
4595 			/* This command never recurses */
4596 			/* No command-specific prep needed */
4597 			pass = AT_PASS_MISC;
4598 			break;
4599 		case AT_ChangeOwner:	/* ALTER OWNER */
4600 			/* This command never recurses */
4601 			/* No command-specific prep needed */
4602 			pass = AT_PASS_MISC;
4603 			break;
4604 		case AT_ClusterOn:		/* CLUSTER ON */
4605 		case AT_DropCluster:	/* SET WITHOUT CLUSTER */
4606 			ATSimplePermissions(rel, ATT_TABLE | ATT_MATVIEW);
4607 			/* These commands never recurse */
4608 			/* No command-specific prep needed */
4609 			pass = AT_PASS_MISC;
4610 			break;
4611 		case AT_SetLogged:		/* SET LOGGED */
4612 			ATSimplePermissions(rel, ATT_TABLE);
4613 			if (tab->chgPersistence)
4614 				ereport(ERROR,
4615 						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
4616 						 errmsg("cannot change persistence setting twice")));
4617 			tab->chgPersistence = ATPrepChangePersistence(rel, true);
4618 			/* force rewrite if necessary; see comment in ATRewriteTables */
4619 			if (tab->chgPersistence)
4620 			{
4621 				tab->rewrite |= AT_REWRITE_ALTER_PERSISTENCE;
4622 				tab->newrelpersistence = RELPERSISTENCE_PERMANENT;
4623 			}
4624 			pass = AT_PASS_MISC;
4625 			break;
4626 		case AT_SetUnLogged:	/* SET UNLOGGED */
4627 			ATSimplePermissions(rel, ATT_TABLE);
4628 			if (tab->chgPersistence)
4629 				ereport(ERROR,
4630 						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
4631 						 errmsg("cannot change persistence setting twice")));
4632 			tab->chgPersistence = ATPrepChangePersistence(rel, false);
4633 			/* force rewrite if necessary; see comment in ATRewriteTables */
4634 			if (tab->chgPersistence)
4635 			{
4636 				tab->rewrite |= AT_REWRITE_ALTER_PERSISTENCE;
4637 				tab->newrelpersistence = RELPERSISTENCE_UNLOGGED;
4638 			}
4639 			pass = AT_PASS_MISC;
4640 			break;
4641 		case AT_DropOids:		/* SET WITHOUT OIDS */
4642 			ATSimplePermissions(rel, ATT_TABLE | ATT_FOREIGN_TABLE);
4643 			pass = AT_PASS_DROP;
4644 			break;
4645 		case AT_SetTableSpace:	/* SET TABLESPACE */
4646 			ATSimplePermissions(rel, ATT_TABLE | ATT_MATVIEW | ATT_INDEX |
4647 								ATT_PARTITIONED_INDEX);
4648 			/* This command never recurses */
4649 			ATPrepSetTableSpace(tab, rel, cmd->name, lockmode);
4650 			pass = AT_PASS_MISC;	/* doesn't actually matter */
4651 			break;
4652 		case AT_SetRelOptions:	/* SET (...) */
4653 		case AT_ResetRelOptions:	/* RESET (...) */
4654 		case AT_ReplaceRelOptions:	/* reset them all, then set just these */
4655 			ATSimplePermissions(rel, ATT_TABLE | ATT_VIEW | ATT_MATVIEW | ATT_INDEX);
4656 			/* This command never recurses */
4657 			/* No command-specific prep needed */
4658 			pass = AT_PASS_MISC;
4659 			break;
4660 		case AT_AddInherit:		/* INHERIT */
4661 			ATSimplePermissions(rel, ATT_TABLE | ATT_FOREIGN_TABLE);
4662 			/* This command never recurses */
4663 			ATPrepAddInherit(rel);
4664 			pass = AT_PASS_MISC;
4665 			break;
4666 		case AT_DropInherit:	/* NO INHERIT */
4667 			ATSimplePermissions(rel, ATT_TABLE | ATT_FOREIGN_TABLE);
4668 			/* This command never recurses */
4669 			/* No command-specific prep needed */
4670 			pass = AT_PASS_MISC;
4671 			break;
4672 		case AT_AlterConstraint:	/* ALTER CONSTRAINT */
4673 			ATSimplePermissions(rel, ATT_TABLE);
4674 			/* Recursion occurs during execution phase */
4675 			pass = AT_PASS_MISC;
4676 			break;
4677 		case AT_ValidateConstraint: /* VALIDATE CONSTRAINT */
4678 			ATSimplePermissions(rel, ATT_TABLE | ATT_FOREIGN_TABLE);
4679 			/* Recursion occurs during execution phase */
4680 			/* No command-specific prep needed except saving recurse flag */
4681 			if (recurse)
4682 				cmd->subtype = AT_ValidateConstraintRecurse;
4683 			pass = AT_PASS_MISC;
4684 			break;
4685 		case AT_ReplicaIdentity:	/* REPLICA IDENTITY ... */
4686 			ATSimplePermissions(rel, ATT_TABLE | ATT_MATVIEW);
4687 			pass = AT_PASS_MISC;
4688 			/* This command never recurses */
4689 			/* No command-specific prep needed */
4690 			break;
4691 		case AT_EnableTrig:		/* ENABLE TRIGGER variants */
4692 		case AT_EnableAlwaysTrig:
4693 		case AT_EnableReplicaTrig:
4694 		case AT_EnableTrigAll:
4695 		case AT_EnableTrigUser:
4696 		case AT_DisableTrig:	/* DISABLE TRIGGER variants */
4697 		case AT_DisableTrigAll:
4698 		case AT_DisableTrigUser:
4699 			ATSimplePermissions(rel, ATT_TABLE | ATT_FOREIGN_TABLE);
4700 			if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
4701 				ATSimpleRecursion(wqueue, rel, cmd, recurse, lockmode, context);
4702 			pass = AT_PASS_MISC;
4703 			break;
4704 		case AT_EnableRule:		/* ENABLE/DISABLE RULE variants */
4705 		case AT_EnableAlwaysRule:
4706 		case AT_EnableReplicaRule:
4707 		case AT_DisableRule:
4708 		case AT_AddOf:			/* OF */
4709 		case AT_DropOf:			/* NOT OF */
4710 		case AT_EnableRowSecurity:
4711 		case AT_DisableRowSecurity:
4712 		case AT_ForceRowSecurity:
4713 		case AT_NoForceRowSecurity:
4714 			ATSimplePermissions(rel, ATT_TABLE);
4715 			/* These commands never recurse */
4716 			/* No command-specific prep needed */
4717 			pass = AT_PASS_MISC;
4718 			break;
4719 		case AT_GenericOptions:
4720 			ATSimplePermissions(rel, ATT_FOREIGN_TABLE);
4721 			/* No command-specific prep needed */
4722 			pass = AT_PASS_MISC;
4723 			break;
4724 		case AT_AttachPartition:
4725 			ATSimplePermissions(rel, ATT_TABLE | ATT_PARTITIONED_INDEX);
4726 			/* No command-specific prep needed */
4727 			pass = AT_PASS_MISC;
4728 			break;
4729 		case AT_DetachPartition:
4730 			ATSimplePermissions(rel, ATT_TABLE);
4731 			/* No command-specific prep needed */
4732 			pass = AT_PASS_MISC;
4733 			break;
4734 		case AT_DetachPartitionFinalize:
4735 			ATSimplePermissions(rel, ATT_TABLE);
4736 			/* No command-specific prep needed */
4737 			pass = AT_PASS_MISC;
4738 			break;
4739 		default:				/* oops */
4740 			elog(ERROR, "unrecognized alter table type: %d",
4741 				 (int) cmd->subtype);
4742 			pass = AT_PASS_UNSET;	/* keep compiler quiet */
4743 			break;
4744 	}
4745 	Assert(pass > AT_PASS_UNSET);
4746 
4747 	/* Add the subcommand to the appropriate list for phase 2 */
4748 	tab->subcmds[pass] = lappend(tab->subcmds[pass], cmd);
4749 }
4750 
4751 /*
4752  * ATRewriteCatalogs
4753  *
4754  * Traffic cop for ALTER TABLE Phase 2 operations.  Subcommands are
4755  * dispatched in a "safe" execution order (designed to avoid unnecessary
4756  * conflicts).
4757  */
4758 static void
ATRewriteCatalogs(List ** wqueue,LOCKMODE lockmode,AlterTableUtilityContext * context)4759 ATRewriteCatalogs(List **wqueue, LOCKMODE lockmode,
4760 				  AlterTableUtilityContext *context)
4761 {
4762 	int			pass;
4763 	ListCell   *ltab;
4764 
4765 	/*
4766 	 * We process all the tables "in parallel", one pass at a time.  This is
4767 	 * needed because we may have to propagate work from one table to another
4768 	 * (specifically, ALTER TYPE on a foreign key's PK has to dispatch the
4769 	 * re-adding of the foreign key constraint to the other table).  Work can
4770 	 * only be propagated into later passes, however.
4771 	 */
4772 	for (pass = 0; pass < AT_NUM_PASSES; pass++)
4773 	{
4774 		/* Go through each table that needs to be processed */
4775 		foreach(ltab, *wqueue)
4776 		{
4777 			AlteredTableInfo *tab = (AlteredTableInfo *) lfirst(ltab);
4778 			List	   *subcmds = tab->subcmds[pass];
4779 			ListCell   *lcmd;
4780 
4781 			if (subcmds == NIL)
4782 				continue;
4783 
4784 			/*
4785 			 * Open the relation and store it in tab.  This allows subroutines
4786 			 * close and reopen, if necessary.  Appropriate lock was obtained
4787 			 * by phase 1, needn't get it again.
4788 			 */
4789 			tab->rel = relation_open(tab->relid, NoLock);
4790 
4791 			foreach(lcmd, subcmds)
4792 				ATExecCmd(wqueue, tab,
4793 						  castNode(AlterTableCmd, lfirst(lcmd)),
4794 						  lockmode, pass, context);
4795 
4796 			/*
4797 			 * After the ALTER TYPE pass, do cleanup work (this is not done in
4798 			 * ATExecAlterColumnType since it should be done only once if
4799 			 * multiple columns of a table are altered).
4800 			 */
4801 			if (pass == AT_PASS_ALTER_TYPE)
4802 				ATPostAlterTypeCleanup(wqueue, tab, lockmode);
4803 
4804 			if (tab->rel)
4805 			{
4806 				relation_close(tab->rel, NoLock);
4807 				tab->rel = NULL;
4808 			}
4809 		}
4810 	}
4811 
4812 	/* Check to see if a toast table must be added. */
4813 	foreach(ltab, *wqueue)
4814 	{
4815 		AlteredTableInfo *tab = (AlteredTableInfo *) lfirst(ltab);
4816 
4817 		/*
4818 		 * If the table is source table of ATTACH PARTITION command, we did
4819 		 * not modify anything about it that will change its toasting
4820 		 * requirement, so no need to check.
4821 		 */
4822 		if (((tab->relkind == RELKIND_RELATION ||
4823 			  tab->relkind == RELKIND_PARTITIONED_TABLE) &&
4824 			 tab->partition_constraint == NULL) ||
4825 			tab->relkind == RELKIND_MATVIEW)
4826 			AlterTableCreateToastTable(tab->relid, (Datum) 0, lockmode);
4827 	}
4828 }
4829 
4830 /*
4831  * ATExecCmd: dispatch a subcommand to appropriate execution routine
4832  */
4833 static void
ATExecCmd(List ** wqueue,AlteredTableInfo * tab,AlterTableCmd * cmd,LOCKMODE lockmode,int cur_pass,AlterTableUtilityContext * context)4834 ATExecCmd(List **wqueue, AlteredTableInfo *tab,
4835 		  AlterTableCmd *cmd, LOCKMODE lockmode, int cur_pass,
4836 		  AlterTableUtilityContext *context)
4837 {
4838 	ObjectAddress address = InvalidObjectAddress;
4839 	Relation	rel = tab->rel;
4840 
4841 	switch (cmd->subtype)
4842 	{
4843 		case AT_AddColumn:		/* ADD COLUMN */
4844 		case AT_AddColumnToView:	/* add column via CREATE OR REPLACE VIEW */
4845 			address = ATExecAddColumn(wqueue, tab, rel, &cmd,
4846 									  false, false,
4847 									  lockmode, cur_pass, context);
4848 			break;
4849 		case AT_AddColumnRecurse:
4850 			address = ATExecAddColumn(wqueue, tab, rel, &cmd,
4851 									  true, false,
4852 									  lockmode, cur_pass, context);
4853 			break;
4854 		case AT_ColumnDefault:	/* ALTER COLUMN DEFAULT */
4855 			address = ATExecColumnDefault(rel, cmd->name, cmd->def, lockmode);
4856 			break;
4857 		case AT_CookedColumnDefault:	/* add a pre-cooked default */
4858 			address = ATExecCookedColumnDefault(rel, cmd->num, cmd->def);
4859 			break;
4860 		case AT_AddIdentity:
4861 			cmd = ATParseTransformCmd(wqueue, tab, rel, cmd, false, lockmode,
4862 									  cur_pass, context);
4863 			Assert(cmd != NULL);
4864 			address = ATExecAddIdentity(rel, cmd->name, cmd->def, lockmode);
4865 			break;
4866 		case AT_SetIdentity:
4867 			cmd = ATParseTransformCmd(wqueue, tab, rel, cmd, false, lockmode,
4868 									  cur_pass, context);
4869 			Assert(cmd != NULL);
4870 			address = ATExecSetIdentity(rel, cmd->name, cmd->def, lockmode);
4871 			break;
4872 		case AT_DropIdentity:
4873 			address = ATExecDropIdentity(rel, cmd->name, cmd->missing_ok, lockmode);
4874 			break;
4875 		case AT_DropNotNull:	/* ALTER COLUMN DROP NOT NULL */
4876 			address = ATExecDropNotNull(rel, cmd->name, lockmode);
4877 			break;
4878 		case AT_SetNotNull:		/* ALTER COLUMN SET NOT NULL */
4879 			address = ATExecSetNotNull(tab, rel, cmd->name, lockmode);
4880 			break;
4881 		case AT_CheckNotNull:	/* check column is already marked NOT NULL */
4882 			ATExecCheckNotNull(tab, rel, cmd->name, lockmode);
4883 			break;
4884 		case AT_DropExpression:
4885 			address = ATExecDropExpression(rel, cmd->name, cmd->missing_ok, lockmode);
4886 			break;
4887 		case AT_SetStatistics:	/* ALTER COLUMN SET STATISTICS */
4888 			address = ATExecSetStatistics(rel, cmd->name, cmd->num, cmd->def, lockmode);
4889 			break;
4890 		case AT_SetOptions:		/* ALTER COLUMN SET ( options ) */
4891 			address = ATExecSetOptions(rel, cmd->name, cmd->def, false, lockmode);
4892 			break;
4893 		case AT_ResetOptions:	/* ALTER COLUMN RESET ( options ) */
4894 			address = ATExecSetOptions(rel, cmd->name, cmd->def, true, lockmode);
4895 			break;
4896 		case AT_SetStorage:		/* ALTER COLUMN SET STORAGE */
4897 			address = ATExecSetStorage(rel, cmd->name, cmd->def, lockmode);
4898 			break;
4899 		case AT_SetCompression:
4900 			address = ATExecSetCompression(tab, rel, cmd->name, cmd->def,
4901 										   lockmode);
4902 			break;
4903 		case AT_DropColumn:		/* DROP COLUMN */
4904 			address = ATExecDropColumn(wqueue, rel, cmd->name,
4905 									   cmd->behavior, false, false,
4906 									   cmd->missing_ok, lockmode,
4907 									   NULL);
4908 			break;
4909 		case AT_DropColumnRecurse:	/* DROP COLUMN with recursion */
4910 			address = ATExecDropColumn(wqueue, rel, cmd->name,
4911 									   cmd->behavior, true, false,
4912 									   cmd->missing_ok, lockmode,
4913 									   NULL);
4914 			break;
4915 		case AT_AddIndex:		/* ADD INDEX */
4916 			address = ATExecAddIndex(tab, rel, (IndexStmt *) cmd->def, false,
4917 									 lockmode);
4918 			break;
4919 		case AT_ReAddIndex:		/* ADD INDEX */
4920 			address = ATExecAddIndex(tab, rel, (IndexStmt *) cmd->def, true,
4921 									 lockmode);
4922 			break;
4923 		case AT_ReAddStatistics:	/* ADD STATISTICS */
4924 			address = ATExecAddStatistics(tab, rel, (CreateStatsStmt *) cmd->def,
4925 										  true, lockmode);
4926 			break;
4927 		case AT_AddConstraint:	/* ADD CONSTRAINT */
4928 			/* Transform the command only during initial examination */
4929 			if (cur_pass == AT_PASS_ADD_CONSTR)
4930 				cmd = ATParseTransformCmd(wqueue, tab, rel, cmd,
4931 										  false, lockmode,
4932 										  cur_pass, context);
4933 			/* Depending on constraint type, might be no more work to do now */
4934 			if (cmd != NULL)
4935 				address =
4936 					ATExecAddConstraint(wqueue, tab, rel,
4937 										(Constraint *) cmd->def,
4938 										false, false, lockmode);
4939 			break;
4940 		case AT_AddConstraintRecurse:	/* ADD CONSTRAINT with recursion */
4941 			/* Transform the command only during initial examination */
4942 			if (cur_pass == AT_PASS_ADD_CONSTR)
4943 				cmd = ATParseTransformCmd(wqueue, tab, rel, cmd,
4944 										  true, lockmode,
4945 										  cur_pass, context);
4946 			/* Depending on constraint type, might be no more work to do now */
4947 			if (cmd != NULL)
4948 				address =
4949 					ATExecAddConstraint(wqueue, tab, rel,
4950 										(Constraint *) cmd->def,
4951 										true, false, lockmode);
4952 			break;
4953 		case AT_ReAddConstraint:	/* Re-add pre-existing check constraint */
4954 			address =
4955 				ATExecAddConstraint(wqueue, tab, rel, (Constraint *) cmd->def,
4956 									true, true, lockmode);
4957 			break;
4958 		case AT_ReAddDomainConstraint:	/* Re-add pre-existing domain check
4959 										 * constraint */
4960 			address =
4961 				AlterDomainAddConstraint(((AlterDomainStmt *) cmd->def)->typeName,
4962 										 ((AlterDomainStmt *) cmd->def)->def,
4963 										 NULL);
4964 			break;
4965 		case AT_ReAddComment:	/* Re-add existing comment */
4966 			address = CommentObject((CommentStmt *) cmd->def);
4967 			break;
4968 		case AT_AddIndexConstraint: /* ADD CONSTRAINT USING INDEX */
4969 			address = ATExecAddIndexConstraint(tab, rel, (IndexStmt *) cmd->def,
4970 											   lockmode);
4971 			break;
4972 		case AT_AlterConstraint:	/* ALTER CONSTRAINT */
4973 			address = ATExecAlterConstraint(rel, cmd, false, false, lockmode);
4974 			break;
4975 		case AT_ValidateConstraint: /* VALIDATE CONSTRAINT */
4976 			address = ATExecValidateConstraint(wqueue, rel, cmd->name, false,
4977 											   false, lockmode);
4978 			break;
4979 		case AT_ValidateConstraintRecurse:	/* VALIDATE CONSTRAINT with
4980 											 * recursion */
4981 			address = ATExecValidateConstraint(wqueue, rel, cmd->name, true,
4982 											   false, lockmode);
4983 			break;
4984 		case AT_DropConstraint: /* DROP CONSTRAINT */
4985 			ATExecDropConstraint(rel, cmd->name, cmd->behavior,
4986 								 false, false,
4987 								 cmd->missing_ok, lockmode);
4988 			break;
4989 		case AT_DropConstraintRecurse:	/* DROP CONSTRAINT with recursion */
4990 			ATExecDropConstraint(rel, cmd->name, cmd->behavior,
4991 								 true, false,
4992 								 cmd->missing_ok, lockmode);
4993 			break;
4994 		case AT_AlterColumnType:	/* ALTER COLUMN TYPE */
4995 			/* parse transformation was done earlier */
4996 			address = ATExecAlterColumnType(tab, rel, cmd, lockmode);
4997 			break;
4998 		case AT_AlterColumnGenericOptions:	/* ALTER COLUMN OPTIONS */
4999 			address =
5000 				ATExecAlterColumnGenericOptions(rel, cmd->name,
5001 												(List *) cmd->def, lockmode);
5002 			break;
5003 		case AT_ChangeOwner:	/* ALTER OWNER */
5004 			ATExecChangeOwner(RelationGetRelid(rel),
5005 							  get_rolespec_oid(cmd->newowner, false),
5006 							  false, lockmode);
5007 			break;
5008 		case AT_ClusterOn:		/* CLUSTER ON */
5009 			address = ATExecClusterOn(rel, cmd->name, lockmode);
5010 			break;
5011 		case AT_DropCluster:	/* SET WITHOUT CLUSTER */
5012 			ATExecDropCluster(rel, lockmode);
5013 			break;
5014 		case AT_SetLogged:		/* SET LOGGED */
5015 		case AT_SetUnLogged:	/* SET UNLOGGED */
5016 			break;
5017 		case AT_DropOids:		/* SET WITHOUT OIDS */
5018 			/* nothing to do here, oid columns don't exist anymore */
5019 			break;
5020 		case AT_SetTableSpace:	/* SET TABLESPACE */
5021 
5022 			/*
5023 			 * Only do this for partitioned tables and indexes, for which this
5024 			 * is just a catalog change.  Other relation types which have
5025 			 * storage are handled by Phase 3.
5026 			 */
5027 			if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE ||
5028 				rel->rd_rel->relkind == RELKIND_PARTITIONED_INDEX)
5029 				ATExecSetTableSpaceNoStorage(rel, tab->newTableSpace);
5030 
5031 			break;
5032 		case AT_SetRelOptions:	/* SET (...) */
5033 		case AT_ResetRelOptions:	/* RESET (...) */
5034 		case AT_ReplaceRelOptions:	/* replace entire option list */
5035 			ATExecSetRelOptions(rel, (List *) cmd->def, cmd->subtype, lockmode);
5036 			break;
5037 		case AT_EnableTrig:		/* ENABLE TRIGGER name */
5038 			ATExecEnableDisableTrigger(rel, cmd->name,
5039 									   TRIGGER_FIRES_ON_ORIGIN, false, lockmode);
5040 			break;
5041 		case AT_EnableAlwaysTrig:	/* ENABLE ALWAYS TRIGGER name */
5042 			ATExecEnableDisableTrigger(rel, cmd->name,
5043 									   TRIGGER_FIRES_ALWAYS, false, lockmode);
5044 			break;
5045 		case AT_EnableReplicaTrig:	/* ENABLE REPLICA TRIGGER name */
5046 			ATExecEnableDisableTrigger(rel, cmd->name,
5047 									   TRIGGER_FIRES_ON_REPLICA, false, lockmode);
5048 			break;
5049 		case AT_DisableTrig:	/* DISABLE TRIGGER name */
5050 			ATExecEnableDisableTrigger(rel, cmd->name,
5051 									   TRIGGER_DISABLED, false, lockmode);
5052 			break;
5053 		case AT_EnableTrigAll:	/* ENABLE TRIGGER ALL */
5054 			ATExecEnableDisableTrigger(rel, NULL,
5055 									   TRIGGER_FIRES_ON_ORIGIN, false, lockmode);
5056 			break;
5057 		case AT_DisableTrigAll: /* DISABLE TRIGGER ALL */
5058 			ATExecEnableDisableTrigger(rel, NULL,
5059 									   TRIGGER_DISABLED, false, lockmode);
5060 			break;
5061 		case AT_EnableTrigUser: /* ENABLE TRIGGER USER */
5062 			ATExecEnableDisableTrigger(rel, NULL,
5063 									   TRIGGER_FIRES_ON_ORIGIN, true, lockmode);
5064 			break;
5065 		case AT_DisableTrigUser:	/* DISABLE TRIGGER USER */
5066 			ATExecEnableDisableTrigger(rel, NULL,
5067 									   TRIGGER_DISABLED, true, lockmode);
5068 			break;
5069 
5070 		case AT_EnableRule:		/* ENABLE RULE name */
5071 			ATExecEnableDisableRule(rel, cmd->name,
5072 									RULE_FIRES_ON_ORIGIN, lockmode);
5073 			break;
5074 		case AT_EnableAlwaysRule:	/* ENABLE ALWAYS RULE name */
5075 			ATExecEnableDisableRule(rel, cmd->name,
5076 									RULE_FIRES_ALWAYS, lockmode);
5077 			break;
5078 		case AT_EnableReplicaRule:	/* ENABLE REPLICA RULE name */
5079 			ATExecEnableDisableRule(rel, cmd->name,
5080 									RULE_FIRES_ON_REPLICA, lockmode);
5081 			break;
5082 		case AT_DisableRule:	/* DISABLE RULE name */
5083 			ATExecEnableDisableRule(rel, cmd->name,
5084 									RULE_DISABLED, lockmode);
5085 			break;
5086 
5087 		case AT_AddInherit:
5088 			address = ATExecAddInherit(rel, (RangeVar *) cmd->def, lockmode);
5089 			break;
5090 		case AT_DropInherit:
5091 			address = ATExecDropInherit(rel, (RangeVar *) cmd->def, lockmode);
5092 			break;
5093 		case AT_AddOf:
5094 			address = ATExecAddOf(rel, (TypeName *) cmd->def, lockmode);
5095 			break;
5096 		case AT_DropOf:
5097 			ATExecDropOf(rel, lockmode);
5098 			break;
5099 		case AT_ReplicaIdentity:
5100 			ATExecReplicaIdentity(rel, (ReplicaIdentityStmt *) cmd->def, lockmode);
5101 			break;
5102 		case AT_EnableRowSecurity:
5103 			ATExecSetRowSecurity(rel, true);
5104 			break;
5105 		case AT_DisableRowSecurity:
5106 			ATExecSetRowSecurity(rel, false);
5107 			break;
5108 		case AT_ForceRowSecurity:
5109 			ATExecForceNoForceRowSecurity(rel, true);
5110 			break;
5111 		case AT_NoForceRowSecurity:
5112 			ATExecForceNoForceRowSecurity(rel, false);
5113 			break;
5114 		case AT_GenericOptions:
5115 			ATExecGenericOptions(rel, (List *) cmd->def);
5116 			break;
5117 		case AT_AttachPartition:
5118 			cmd = ATParseTransformCmd(wqueue, tab, rel, cmd, false, lockmode,
5119 									  cur_pass, context);
5120 			Assert(cmd != NULL);
5121 			if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
5122 				ATExecAttachPartition(wqueue, rel, (PartitionCmd *) cmd->def,
5123 									  context);
5124 			else
5125 				ATExecAttachPartitionIdx(wqueue, rel,
5126 										 ((PartitionCmd *) cmd->def)->name);
5127 			break;
5128 		case AT_DetachPartition:
5129 			cmd = ATParseTransformCmd(wqueue, tab, rel, cmd, false, lockmode,
5130 									  cur_pass, context);
5131 			Assert(cmd != NULL);
5132 			/* ATPrepCmd ensures it must be a table */
5133 			Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
5134 			ATExecDetachPartition(wqueue, tab, rel,
5135 								  ((PartitionCmd *) cmd->def)->name,
5136 								  ((PartitionCmd *) cmd->def)->concurrent);
5137 			break;
5138 		case AT_DetachPartitionFinalize:
5139 			ATExecDetachPartitionFinalize(rel, ((PartitionCmd *) cmd->def)->name);
5140 			break;
5141 		default:				/* oops */
5142 			elog(ERROR, "unrecognized alter table type: %d",
5143 				 (int) cmd->subtype);
5144 			break;
5145 	}
5146 
5147 	/*
5148 	 * Report the subcommand to interested event triggers.
5149 	 */
5150 	if (cmd)
5151 		EventTriggerCollectAlterTableSubcmd((Node *) cmd, address);
5152 
5153 	/*
5154 	 * Bump the command counter to ensure the next subcommand in the sequence
5155 	 * can see the changes so far
5156 	 */
5157 	CommandCounterIncrement();
5158 }
5159 
5160 /*
5161  * ATParseTransformCmd: perform parse transformation for one subcommand
5162  *
5163  * Returns the transformed subcommand tree, if there is one, else NULL.
5164  *
5165  * The parser may hand back additional AlterTableCmd(s) and/or other
5166  * utility statements, either before or after the original subcommand.
5167  * Other AlterTableCmds are scheduled into the appropriate slot of the
5168  * AlteredTableInfo (they had better be for later passes than the current one).
5169  * Utility statements that are supposed to happen before the AlterTableCmd
5170  * are executed immediately.  Those that are supposed to happen afterwards
5171  * are added to the tab->afterStmts list to be done at the very end.
5172  */
5173 static AlterTableCmd *
ATParseTransformCmd(List ** wqueue,AlteredTableInfo * tab,Relation rel,AlterTableCmd * cmd,bool recurse,LOCKMODE lockmode,int cur_pass,AlterTableUtilityContext * context)5174 ATParseTransformCmd(List **wqueue, AlteredTableInfo *tab, Relation rel,
5175 					AlterTableCmd *cmd, bool recurse, LOCKMODE lockmode,
5176 					int cur_pass, AlterTableUtilityContext *context)
5177 {
5178 	AlterTableCmd *newcmd = NULL;
5179 	AlterTableStmt *atstmt = makeNode(AlterTableStmt);
5180 	List	   *beforeStmts;
5181 	List	   *afterStmts;
5182 	ListCell   *lc;
5183 
5184 	/* Gin up an AlterTableStmt with just this subcommand and this table */
5185 	atstmt->relation =
5186 		makeRangeVar(get_namespace_name(RelationGetNamespace(rel)),
5187 					 pstrdup(RelationGetRelationName(rel)),
5188 					 -1);
5189 	atstmt->relation->inh = recurse;
5190 	atstmt->cmds = list_make1(cmd);
5191 	atstmt->objtype = OBJECT_TABLE; /* needn't be picky here */
5192 	atstmt->missing_ok = false;
5193 
5194 	/* Transform the AlterTableStmt */
5195 	atstmt = transformAlterTableStmt(RelationGetRelid(rel),
5196 									 atstmt,
5197 									 context->queryString,
5198 									 &beforeStmts,
5199 									 &afterStmts);
5200 
5201 	/* Execute any statements that should happen before these subcommand(s) */
5202 	foreach(lc, beforeStmts)
5203 	{
5204 		Node	   *stmt = (Node *) lfirst(lc);
5205 
5206 		ProcessUtilityForAlterTable(stmt, context);
5207 		CommandCounterIncrement();
5208 	}
5209 
5210 	/* Examine the transformed subcommands and schedule them appropriately */
5211 	foreach(lc, atstmt->cmds)
5212 	{
5213 		AlterTableCmd *cmd2 = lfirst_node(AlterTableCmd, lc);
5214 		int			pass;
5215 
5216 		/*
5217 		 * This switch need only cover the subcommand types that can be added
5218 		 * by parse_utilcmd.c; otherwise, we'll use the default strategy of
5219 		 * executing the subcommand immediately, as a substitute for the
5220 		 * original subcommand.  (Note, however, that this does cause
5221 		 * AT_AddConstraint subcommands to be rescheduled into later passes,
5222 		 * which is important for index and foreign key constraints.)
5223 		 *
5224 		 * We assume we needn't do any phase-1 checks for added subcommands.
5225 		 */
5226 		switch (cmd2->subtype)
5227 		{
5228 			case AT_SetNotNull:
5229 				/* Need command-specific recursion decision */
5230 				ATPrepSetNotNull(wqueue, rel, cmd2,
5231 								 recurse, false,
5232 								 lockmode, context);
5233 				pass = AT_PASS_COL_ATTRS;
5234 				break;
5235 			case AT_AddIndex:
5236 				/* This command never recurses */
5237 				/* No command-specific prep needed */
5238 				pass = AT_PASS_ADD_INDEX;
5239 				break;
5240 			case AT_AddIndexConstraint:
5241 				/* This command never recurses */
5242 				/* No command-specific prep needed */
5243 				pass = AT_PASS_ADD_INDEXCONSTR;
5244 				break;
5245 			case AT_AddConstraint:
5246 				/* Recursion occurs during execution phase */
5247 				if (recurse)
5248 					cmd2->subtype = AT_AddConstraintRecurse;
5249 				switch (castNode(Constraint, cmd2->def)->contype)
5250 				{
5251 					case CONSTR_PRIMARY:
5252 					case CONSTR_UNIQUE:
5253 					case CONSTR_EXCLUSION:
5254 						pass = AT_PASS_ADD_INDEXCONSTR;
5255 						break;
5256 					default:
5257 						pass = AT_PASS_ADD_OTHERCONSTR;
5258 						break;
5259 				}
5260 				break;
5261 			case AT_AlterColumnGenericOptions:
5262 				/* This command never recurses */
5263 				/* No command-specific prep needed */
5264 				pass = AT_PASS_MISC;
5265 				break;
5266 			default:
5267 				pass = cur_pass;
5268 				break;
5269 		}
5270 
5271 		if (pass < cur_pass)
5272 		{
5273 			/* Cannot schedule into a pass we already finished */
5274 			elog(ERROR, "ALTER TABLE scheduling failure: too late for pass %d",
5275 				 pass);
5276 		}
5277 		else if (pass > cur_pass)
5278 		{
5279 			/* OK, queue it up for later */
5280 			tab->subcmds[pass] = lappend(tab->subcmds[pass], cmd2);
5281 		}
5282 		else
5283 		{
5284 			/*
5285 			 * We should see at most one subcommand for the current pass,
5286 			 * which is the transformed version of the original subcommand.
5287 			 */
5288 			if (newcmd == NULL && cmd->subtype == cmd2->subtype)
5289 			{
5290 				/* Found the transformed version of our subcommand */
5291 				newcmd = cmd2;
5292 			}
5293 			else
5294 				elog(ERROR, "ALTER TABLE scheduling failure: bogus item for pass %d",
5295 					 pass);
5296 		}
5297 	}
5298 
5299 	/* Queue up any after-statements to happen at the end */
5300 	tab->afterStmts = list_concat(tab->afterStmts, afterStmts);
5301 
5302 	return newcmd;
5303 }
5304 
5305 /*
5306  * ATRewriteTables: ALTER TABLE phase 3
5307  */
5308 static void
ATRewriteTables(AlterTableStmt * parsetree,List ** wqueue,LOCKMODE lockmode,AlterTableUtilityContext * context)5309 ATRewriteTables(AlterTableStmt *parsetree, List **wqueue, LOCKMODE lockmode,
5310 				AlterTableUtilityContext *context)
5311 {
5312 	ListCell   *ltab;
5313 
5314 	/* Go through each table that needs to be checked or rewritten */
5315 	foreach(ltab, *wqueue)
5316 	{
5317 		AlteredTableInfo *tab = (AlteredTableInfo *) lfirst(ltab);
5318 
5319 		/* Relations without storage may be ignored here */
5320 		if (!RELKIND_HAS_STORAGE(tab->relkind))
5321 			continue;
5322 
5323 		/*
5324 		 * If we change column data types, the operation has to be propagated
5325 		 * to tables that use this table's rowtype as a column type.
5326 		 * tab->newvals will also be non-NULL in the case where we're adding a
5327 		 * column with a default.  We choose to forbid that case as well,
5328 		 * since composite types might eventually support defaults.
5329 		 *
5330 		 * (Eventually we'll probably need to check for composite type
5331 		 * dependencies even when we're just scanning the table without a
5332 		 * rewrite, but at the moment a composite type does not enforce any
5333 		 * constraints, so it's not necessary/appropriate to enforce them just
5334 		 * during ALTER.)
5335 		 */
5336 		if (tab->newvals != NIL || tab->rewrite > 0)
5337 		{
5338 			Relation	rel;
5339 
5340 			rel = table_open(tab->relid, NoLock);
5341 			find_composite_type_dependencies(rel->rd_rel->reltype, rel, NULL);
5342 			table_close(rel, NoLock);
5343 		}
5344 
5345 		/*
5346 		 * We only need to rewrite the table if at least one column needs to
5347 		 * be recomputed, or we are changing its persistence.
5348 		 *
5349 		 * There are two reasons for requiring a rewrite when changing
5350 		 * persistence: on one hand, we need to ensure that the buffers
5351 		 * belonging to each of the two relations are marked with or without
5352 		 * BM_PERMANENT properly.  On the other hand, since rewriting creates
5353 		 * and assigns a new relfilenode, we automatically create or drop an
5354 		 * init fork for the relation as appropriate.
5355 		 */
5356 		if (tab->rewrite > 0)
5357 		{
5358 			/* Build a temporary relation and copy data */
5359 			Relation	OldHeap;
5360 			Oid			OIDNewHeap;
5361 			Oid			NewTableSpace;
5362 			char		persistence;
5363 
5364 			OldHeap = table_open(tab->relid, NoLock);
5365 
5366 			/*
5367 			 * We don't support rewriting of system catalogs; there are too
5368 			 * many corner cases and too little benefit.  In particular this
5369 			 * is certainly not going to work for mapped catalogs.
5370 			 */
5371 			if (IsSystemRelation(OldHeap))
5372 				ereport(ERROR,
5373 						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
5374 						 errmsg("cannot rewrite system relation \"%s\"",
5375 								RelationGetRelationName(OldHeap))));
5376 
5377 			if (RelationIsUsedAsCatalogTable(OldHeap))
5378 				ereport(ERROR,
5379 						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
5380 						 errmsg("cannot rewrite table \"%s\" used as a catalog table",
5381 								RelationGetRelationName(OldHeap))));
5382 
5383 			/*
5384 			 * Don't allow rewrite on temp tables of other backends ... their
5385 			 * local buffer manager is not going to cope.
5386 			 */
5387 			if (RELATION_IS_OTHER_TEMP(OldHeap))
5388 				ereport(ERROR,
5389 						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
5390 						 errmsg("cannot rewrite temporary tables of other sessions")));
5391 
5392 			/*
5393 			 * Select destination tablespace (same as original unless user
5394 			 * requested a change)
5395 			 */
5396 			if (tab->newTableSpace)
5397 				NewTableSpace = tab->newTableSpace;
5398 			else
5399 				NewTableSpace = OldHeap->rd_rel->reltablespace;
5400 
5401 			/*
5402 			 * Select persistence of transient table (same as original unless
5403 			 * user requested a change)
5404 			 */
5405 			persistence = tab->chgPersistence ?
5406 				tab->newrelpersistence : OldHeap->rd_rel->relpersistence;
5407 
5408 			table_close(OldHeap, NoLock);
5409 
5410 			/*
5411 			 * Fire off an Event Trigger now, before actually rewriting the
5412 			 * table.
5413 			 *
5414 			 * We don't support Event Trigger for nested commands anywhere,
5415 			 * here included, and parsetree is given NULL when coming from
5416 			 * AlterTableInternal.
5417 			 *
5418 			 * And fire it only once.
5419 			 */
5420 			if (parsetree)
5421 				EventTriggerTableRewrite((Node *) parsetree,
5422 										 tab->relid,
5423 										 tab->rewrite);
5424 
5425 			/*
5426 			 * Create transient table that will receive the modified data.
5427 			 *
5428 			 * Ensure it is marked correctly as logged or unlogged.  We have
5429 			 * to do this here so that buffers for the new relfilenode will
5430 			 * have the right persistence set, and at the same time ensure
5431 			 * that the original filenode's buffers will get read in with the
5432 			 * correct setting (i.e. the original one).  Otherwise a rollback
5433 			 * after the rewrite would possibly result with buffers for the
5434 			 * original filenode having the wrong persistence setting.
5435 			 *
5436 			 * NB: This relies on swap_relation_files() also swapping the
5437 			 * persistence. That wouldn't work for pg_class, but that can't be
5438 			 * unlogged anyway.
5439 			 */
5440 			OIDNewHeap = make_new_heap(tab->relid, NewTableSpace, persistence,
5441 									   lockmode);
5442 
5443 			/*
5444 			 * Copy the heap data into the new table with the desired
5445 			 * modifications, and test the current data within the table
5446 			 * against new constraints generated by ALTER TABLE commands.
5447 			 */
5448 			ATRewriteTable(tab, OIDNewHeap, lockmode);
5449 
5450 			/*
5451 			 * Swap the physical files of the old and new heaps, then rebuild
5452 			 * indexes and discard the old heap.  We can use RecentXmin for
5453 			 * the table's new relfrozenxid because we rewrote all the tuples
5454 			 * in ATRewriteTable, so no older Xid remains in the table.  Also,
5455 			 * we never try to swap toast tables by content, since we have no
5456 			 * interest in letting this code work on system catalogs.
5457 			 */
5458 			finish_heap_swap(tab->relid, OIDNewHeap,
5459 							 false, false, true,
5460 							 !OidIsValid(tab->newTableSpace),
5461 							 RecentXmin,
5462 							 ReadNextMultiXactId(),
5463 							 persistence);
5464 		}
5465 		else
5466 		{
5467 			/*
5468 			 * If required, test the current data within the table against new
5469 			 * constraints generated by ALTER TABLE commands, but don't
5470 			 * rebuild data.
5471 			 */
5472 			if (tab->constraints != NIL || tab->verify_new_notnull ||
5473 				tab->partition_constraint != NULL)
5474 				ATRewriteTable(tab, InvalidOid, lockmode);
5475 
5476 			/*
5477 			 * If we had SET TABLESPACE but no reason to reconstruct tuples,
5478 			 * just do a block-by-block copy.
5479 			 */
5480 			if (tab->newTableSpace)
5481 				ATExecSetTableSpace(tab->relid, tab->newTableSpace, lockmode);
5482 		}
5483 	}
5484 
5485 	/*
5486 	 * Foreign key constraints are checked in a final pass, since (a) it's
5487 	 * generally best to examine each one separately, and (b) it's at least
5488 	 * theoretically possible that we have changed both relations of the
5489 	 * foreign key, and we'd better have finished both rewrites before we try
5490 	 * to read the tables.
5491 	 */
5492 	foreach(ltab, *wqueue)
5493 	{
5494 		AlteredTableInfo *tab = (AlteredTableInfo *) lfirst(ltab);
5495 		Relation	rel = NULL;
5496 		ListCell   *lcon;
5497 
5498 		/* Relations without storage may be ignored here too */
5499 		if (!RELKIND_HAS_STORAGE(tab->relkind))
5500 			continue;
5501 
5502 		foreach(lcon, tab->constraints)
5503 		{
5504 			NewConstraint *con = lfirst(lcon);
5505 
5506 			if (con->contype == CONSTR_FOREIGN)
5507 			{
5508 				Constraint *fkconstraint = (Constraint *) con->qual;
5509 				Relation	refrel;
5510 
5511 				if (rel == NULL)
5512 				{
5513 					/* Long since locked, no need for another */
5514 					rel = table_open(tab->relid, NoLock);
5515 				}
5516 
5517 				refrel = table_open(con->refrelid, RowShareLock);
5518 
5519 				validateForeignKeyConstraint(fkconstraint->conname, rel, refrel,
5520 											 con->refindid,
5521 											 con->conid);
5522 
5523 				/*
5524 				 * No need to mark the constraint row as validated, we did
5525 				 * that when we inserted the row earlier.
5526 				 */
5527 
5528 				table_close(refrel, NoLock);
5529 			}
5530 		}
5531 
5532 		if (rel)
5533 			table_close(rel, NoLock);
5534 	}
5535 
5536 	/* Finally, run any afterStmts that were queued up */
5537 	foreach(ltab, *wqueue)
5538 	{
5539 		AlteredTableInfo *tab = (AlteredTableInfo *) lfirst(ltab);
5540 		ListCell   *lc;
5541 
5542 		foreach(lc, tab->afterStmts)
5543 		{
5544 			Node	   *stmt = (Node *) lfirst(lc);
5545 
5546 			ProcessUtilityForAlterTable(stmt, context);
5547 			CommandCounterIncrement();
5548 		}
5549 	}
5550 }
5551 
5552 /*
5553  * ATRewriteTable: scan or rewrite one table
5554  *
5555  * OIDNewHeap is InvalidOid if we don't need to rewrite
5556  */
5557 static void
ATRewriteTable(AlteredTableInfo * tab,Oid OIDNewHeap,LOCKMODE lockmode)5558 ATRewriteTable(AlteredTableInfo *tab, Oid OIDNewHeap, LOCKMODE lockmode)
5559 {
5560 	Relation	oldrel;
5561 	Relation	newrel;
5562 	TupleDesc	oldTupDesc;
5563 	TupleDesc	newTupDesc;
5564 	bool		needscan = false;
5565 	List	   *notnull_attrs;
5566 	int			i;
5567 	ListCell   *l;
5568 	EState	   *estate;
5569 	CommandId	mycid;
5570 	BulkInsertState bistate;
5571 	int			ti_options;
5572 	ExprState  *partqualstate = NULL;
5573 
5574 	/*
5575 	 * Open the relation(s).  We have surely already locked the existing
5576 	 * table.
5577 	 */
5578 	oldrel = table_open(tab->relid, NoLock);
5579 	oldTupDesc = tab->oldDesc;
5580 	newTupDesc = RelationGetDescr(oldrel);	/* includes all mods */
5581 
5582 	if (OidIsValid(OIDNewHeap))
5583 		newrel = table_open(OIDNewHeap, lockmode);
5584 	else
5585 		newrel = NULL;
5586 
5587 	/*
5588 	 * Prepare a BulkInsertState and options for table_tuple_insert.  The FSM
5589 	 * is empty, so don't bother using it.
5590 	 */
5591 	if (newrel)
5592 	{
5593 		mycid = GetCurrentCommandId(true);
5594 		bistate = GetBulkInsertState();
5595 		ti_options = TABLE_INSERT_SKIP_FSM;
5596 	}
5597 	else
5598 	{
5599 		/* keep compiler quiet about using these uninitialized */
5600 		mycid = 0;
5601 		bistate = NULL;
5602 		ti_options = 0;
5603 	}
5604 
5605 	/*
5606 	 * Generate the constraint and default execution states
5607 	 */
5608 
5609 	estate = CreateExecutorState();
5610 
5611 	/* Build the needed expression execution states */
5612 	foreach(l, tab->constraints)
5613 	{
5614 		NewConstraint *con = lfirst(l);
5615 
5616 		switch (con->contype)
5617 		{
5618 			case CONSTR_CHECK:
5619 				needscan = true;
5620 				con->qualstate = ExecPrepareExpr((Expr *) con->qual, estate);
5621 				break;
5622 			case CONSTR_FOREIGN:
5623 				/* Nothing to do here */
5624 				break;
5625 			default:
5626 				elog(ERROR, "unrecognized constraint type: %d",
5627 					 (int) con->contype);
5628 		}
5629 	}
5630 
5631 	/* Build expression execution states for partition check quals */
5632 	if (tab->partition_constraint)
5633 	{
5634 		needscan = true;
5635 		partqualstate = ExecPrepareExpr(tab->partition_constraint, estate);
5636 	}
5637 
5638 	foreach(l, tab->newvals)
5639 	{
5640 		NewColumnValue *ex = lfirst(l);
5641 
5642 		/* expr already planned */
5643 		ex->exprstate = ExecInitExpr((Expr *) ex->expr, NULL);
5644 	}
5645 
5646 	notnull_attrs = NIL;
5647 	if (newrel || tab->verify_new_notnull)
5648 	{
5649 		/*
5650 		 * If we are rebuilding the tuples OR if we added any new but not
5651 		 * verified NOT NULL constraints, check all not-null constraints. This
5652 		 * is a bit of overkill but it minimizes risk of bugs, and
5653 		 * heap_attisnull is a pretty cheap test anyway.
5654 		 */
5655 		for (i = 0; i < newTupDesc->natts; i++)
5656 		{
5657 			Form_pg_attribute attr = TupleDescAttr(newTupDesc, i);
5658 
5659 			if (attr->attnotnull && !attr->attisdropped)
5660 				notnull_attrs = lappend_int(notnull_attrs, i);
5661 		}
5662 		if (notnull_attrs)
5663 			needscan = true;
5664 	}
5665 
5666 	if (newrel || needscan)
5667 	{
5668 		ExprContext *econtext;
5669 		TupleTableSlot *oldslot;
5670 		TupleTableSlot *newslot;
5671 		TableScanDesc scan;
5672 		MemoryContext oldCxt;
5673 		List	   *dropped_attrs = NIL;
5674 		ListCell   *lc;
5675 		Snapshot	snapshot;
5676 
5677 		if (newrel)
5678 			ereport(DEBUG1,
5679 					(errmsg_internal("rewriting table \"%s\"",
5680 									 RelationGetRelationName(oldrel))));
5681 		else
5682 			ereport(DEBUG1,
5683 					(errmsg_internal("verifying table \"%s\"",
5684 									 RelationGetRelationName(oldrel))));
5685 
5686 		if (newrel)
5687 		{
5688 			/*
5689 			 * All predicate locks on the tuples or pages are about to be made
5690 			 * invalid, because we move tuples around.  Promote them to
5691 			 * relation locks.
5692 			 */
5693 			TransferPredicateLocksToHeapRelation(oldrel);
5694 		}
5695 
5696 		econtext = GetPerTupleExprContext(estate);
5697 
5698 		/*
5699 		 * Create necessary tuple slots. When rewriting, two slots are needed,
5700 		 * otherwise one suffices. In the case where one slot suffices, we
5701 		 * need to use the new tuple descriptor, otherwise some constraints
5702 		 * can't be evaluated.  Note that even when the tuple layout is the
5703 		 * same and no rewrite is required, the tupDescs might not be
5704 		 * (consider ADD COLUMN without a default).
5705 		 */
5706 		if (tab->rewrite)
5707 		{
5708 			Assert(newrel != NULL);
5709 			oldslot = MakeSingleTupleTableSlot(oldTupDesc,
5710 											   table_slot_callbacks(oldrel));
5711 			newslot = MakeSingleTupleTableSlot(newTupDesc,
5712 											   table_slot_callbacks(newrel));
5713 
5714 			/*
5715 			 * Set all columns in the new slot to NULL initially, to ensure
5716 			 * columns added as part of the rewrite are initialized to NULL.
5717 			 * That is necessary as tab->newvals will not contain an
5718 			 * expression for columns with a NULL default, e.g. when adding a
5719 			 * column without a default together with a column with a default
5720 			 * requiring an actual rewrite.
5721 			 */
5722 			ExecStoreAllNullTuple(newslot);
5723 		}
5724 		else
5725 		{
5726 			oldslot = MakeSingleTupleTableSlot(newTupDesc,
5727 											   table_slot_callbacks(oldrel));
5728 			newslot = NULL;
5729 		}
5730 
5731 		/*
5732 		 * Any attributes that are dropped according to the new tuple
5733 		 * descriptor can be set to NULL. We precompute the list of dropped
5734 		 * attributes to avoid needing to do so in the per-tuple loop.
5735 		 */
5736 		for (i = 0; i < newTupDesc->natts; i++)
5737 		{
5738 			if (TupleDescAttr(newTupDesc, i)->attisdropped)
5739 				dropped_attrs = lappend_int(dropped_attrs, i);
5740 		}
5741 
5742 		/*
5743 		 * Scan through the rows, generating a new row if needed and then
5744 		 * checking all the constraints.
5745 		 */
5746 		snapshot = RegisterSnapshot(GetLatestSnapshot());
5747 		scan = table_beginscan(oldrel, snapshot, 0, NULL);
5748 
5749 		/*
5750 		 * Switch to per-tuple memory context and reset it for each tuple
5751 		 * produced, so we don't leak memory.
5752 		 */
5753 		oldCxt = MemoryContextSwitchTo(GetPerTupleMemoryContext(estate));
5754 
5755 		while (table_scan_getnextslot(scan, ForwardScanDirection, oldslot))
5756 		{
5757 			TupleTableSlot *insertslot;
5758 
5759 			if (tab->rewrite > 0)
5760 			{
5761 				/* Extract data from old tuple */
5762 				slot_getallattrs(oldslot);
5763 				ExecClearTuple(newslot);
5764 
5765 				/* copy attributes */
5766 				memcpy(newslot->tts_values, oldslot->tts_values,
5767 					   sizeof(Datum) * oldslot->tts_nvalid);
5768 				memcpy(newslot->tts_isnull, oldslot->tts_isnull,
5769 					   sizeof(bool) * oldslot->tts_nvalid);
5770 
5771 				/* Set dropped attributes to null in new tuple */
5772 				foreach(lc, dropped_attrs)
5773 					newslot->tts_isnull[lfirst_int(lc)] = true;
5774 
5775 				/*
5776 				 * Constraints and GENERATED expressions might reference the
5777 				 * tableoid column, so fill tts_tableOid with the desired
5778 				 * value.  (We must do this each time, because it gets
5779 				 * overwritten with newrel's OID during storing.)
5780 				 */
5781 				newslot->tts_tableOid = RelationGetRelid(oldrel);
5782 
5783 				/*
5784 				 * Process supplied expressions to replace selected columns.
5785 				 *
5786 				 * First, evaluate expressions whose inputs come from the old
5787 				 * tuple.
5788 				 */
5789 				econtext->ecxt_scantuple = oldslot;
5790 
5791 				foreach(l, tab->newvals)
5792 				{
5793 					NewColumnValue *ex = lfirst(l);
5794 
5795 					if (ex->is_generated)
5796 						continue;
5797 
5798 					newslot->tts_values[ex->attnum - 1]
5799 						= ExecEvalExpr(ex->exprstate,
5800 									   econtext,
5801 									   &newslot->tts_isnull[ex->attnum - 1]);
5802 				}
5803 
5804 				ExecStoreVirtualTuple(newslot);
5805 
5806 				/*
5807 				 * Now, evaluate any expressions whose inputs come from the
5808 				 * new tuple.  We assume these columns won't reference each
5809 				 * other, so that there's no ordering dependency.
5810 				 */
5811 				econtext->ecxt_scantuple = newslot;
5812 
5813 				foreach(l, tab->newvals)
5814 				{
5815 					NewColumnValue *ex = lfirst(l);
5816 
5817 					if (!ex->is_generated)
5818 						continue;
5819 
5820 					newslot->tts_values[ex->attnum - 1]
5821 						= ExecEvalExpr(ex->exprstate,
5822 									   econtext,
5823 									   &newslot->tts_isnull[ex->attnum - 1]);
5824 				}
5825 
5826 				insertslot = newslot;
5827 			}
5828 			else
5829 			{
5830 				/*
5831 				 * If there's no rewrite, old and new table are guaranteed to
5832 				 * have the same AM, so we can just use the old slot to verify
5833 				 * new constraints etc.
5834 				 */
5835 				insertslot = oldslot;
5836 			}
5837 
5838 			/* Now check any constraints on the possibly-changed tuple */
5839 			econtext->ecxt_scantuple = insertslot;
5840 
5841 			foreach(l, notnull_attrs)
5842 			{
5843 				int			attn = lfirst_int(l);
5844 
5845 				if (slot_attisnull(insertslot, attn + 1))
5846 				{
5847 					Form_pg_attribute attr = TupleDescAttr(newTupDesc, attn);
5848 
5849 					ereport(ERROR,
5850 							(errcode(ERRCODE_NOT_NULL_VIOLATION),
5851 							 errmsg("column \"%s\" of relation \"%s\" contains null values",
5852 									NameStr(attr->attname),
5853 									RelationGetRelationName(oldrel)),
5854 							 errtablecol(oldrel, attn + 1)));
5855 				}
5856 			}
5857 
5858 			foreach(l, tab->constraints)
5859 			{
5860 				NewConstraint *con = lfirst(l);
5861 
5862 				switch (con->contype)
5863 				{
5864 					case CONSTR_CHECK:
5865 						if (!ExecCheck(con->qualstate, econtext))
5866 							ereport(ERROR,
5867 									(errcode(ERRCODE_CHECK_VIOLATION),
5868 									 errmsg("check constraint \"%s\" of relation \"%s\" is violated by some row",
5869 											con->name,
5870 											RelationGetRelationName(oldrel)),
5871 									 errtableconstraint(oldrel, con->name)));
5872 						break;
5873 					case CONSTR_FOREIGN:
5874 						/* Nothing to do here */
5875 						break;
5876 					default:
5877 						elog(ERROR, "unrecognized constraint type: %d",
5878 							 (int) con->contype);
5879 				}
5880 			}
5881 
5882 			if (partqualstate && !ExecCheck(partqualstate, econtext))
5883 			{
5884 				if (tab->validate_default)
5885 					ereport(ERROR,
5886 							(errcode(ERRCODE_CHECK_VIOLATION),
5887 							 errmsg("updated partition constraint for default partition \"%s\" would be violated by some row",
5888 									RelationGetRelationName(oldrel)),
5889 							 errtable(oldrel)));
5890 				else
5891 					ereport(ERROR,
5892 							(errcode(ERRCODE_CHECK_VIOLATION),
5893 							 errmsg("partition constraint of relation \"%s\" is violated by some row",
5894 									RelationGetRelationName(oldrel)),
5895 							 errtable(oldrel)));
5896 			}
5897 
5898 			/* Write the tuple out to the new relation */
5899 			if (newrel)
5900 				table_tuple_insert(newrel, insertslot, mycid,
5901 								   ti_options, bistate);
5902 
5903 			ResetExprContext(econtext);
5904 
5905 			CHECK_FOR_INTERRUPTS();
5906 		}
5907 
5908 		MemoryContextSwitchTo(oldCxt);
5909 		table_endscan(scan);
5910 		UnregisterSnapshot(snapshot);
5911 
5912 		ExecDropSingleTupleTableSlot(oldslot);
5913 		if (newslot)
5914 			ExecDropSingleTupleTableSlot(newslot);
5915 	}
5916 
5917 	FreeExecutorState(estate);
5918 
5919 	table_close(oldrel, NoLock);
5920 	if (newrel)
5921 	{
5922 		FreeBulkInsertState(bistate);
5923 
5924 		table_finish_bulk_insert(newrel, ti_options);
5925 
5926 		table_close(newrel, NoLock);
5927 	}
5928 }
5929 
5930 /*
5931  * ATGetQueueEntry: find or create an entry in the ALTER TABLE work queue
5932  */
5933 static AlteredTableInfo *
ATGetQueueEntry(List ** wqueue,Relation rel)5934 ATGetQueueEntry(List **wqueue, Relation rel)
5935 {
5936 	Oid			relid = RelationGetRelid(rel);
5937 	AlteredTableInfo *tab;
5938 	ListCell   *ltab;
5939 
5940 	foreach(ltab, *wqueue)
5941 	{
5942 		tab = (AlteredTableInfo *) lfirst(ltab);
5943 		if (tab->relid == relid)
5944 			return tab;
5945 	}
5946 
5947 	/*
5948 	 * Not there, so add it.  Note that we make a copy of the relation's
5949 	 * existing descriptor before anything interesting can happen to it.
5950 	 */
5951 	tab = (AlteredTableInfo *) palloc0(sizeof(AlteredTableInfo));
5952 	tab->relid = relid;
5953 	tab->rel = NULL;			/* set later */
5954 	tab->relkind = rel->rd_rel->relkind;
5955 	tab->oldDesc = CreateTupleDescCopyConstr(RelationGetDescr(rel));
5956 	tab->newrelpersistence = RELPERSISTENCE_PERMANENT;
5957 	tab->chgPersistence = false;
5958 
5959 	*wqueue = lappend(*wqueue, tab);
5960 
5961 	return tab;
5962 }
5963 
5964 /*
5965  * ATSimplePermissions
5966  *
5967  * - Ensure that it is a relation (or possibly a view)
5968  * - Ensure this user is the owner
5969  * - Ensure that it is not a system table
5970  */
5971 static void
ATSimplePermissions(Relation rel,int allowed_targets)5972 ATSimplePermissions(Relation rel, int allowed_targets)
5973 {
5974 	int			actual_target;
5975 
5976 	switch (rel->rd_rel->relkind)
5977 	{
5978 		case RELKIND_RELATION:
5979 		case RELKIND_PARTITIONED_TABLE:
5980 			actual_target = ATT_TABLE;
5981 			break;
5982 		case RELKIND_VIEW:
5983 			actual_target = ATT_VIEW;
5984 			break;
5985 		case RELKIND_MATVIEW:
5986 			actual_target = ATT_MATVIEW;
5987 			break;
5988 		case RELKIND_INDEX:
5989 			actual_target = ATT_INDEX;
5990 			break;
5991 		case RELKIND_PARTITIONED_INDEX:
5992 			actual_target = ATT_PARTITIONED_INDEX;
5993 			break;
5994 		case RELKIND_COMPOSITE_TYPE:
5995 			actual_target = ATT_COMPOSITE_TYPE;
5996 			break;
5997 		case RELKIND_FOREIGN_TABLE:
5998 			actual_target = ATT_FOREIGN_TABLE;
5999 			break;
6000 		default:
6001 			actual_target = 0;
6002 			break;
6003 	}
6004 
6005 	/* Wrong target type? */
6006 	if ((actual_target & allowed_targets) == 0)
6007 		ATWrongRelkindError(rel, allowed_targets);
6008 
6009 	/* Permissions checks */
6010 	if (!pg_class_ownercheck(RelationGetRelid(rel), GetUserId()))
6011 		aclcheck_error(ACLCHECK_NOT_OWNER, get_relkind_objtype(rel->rd_rel->relkind),
6012 					   RelationGetRelationName(rel));
6013 
6014 	if (!allowSystemTableMods && IsSystemRelation(rel))
6015 		ereport(ERROR,
6016 				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
6017 				 errmsg("permission denied: \"%s\" is a system catalog",
6018 						RelationGetRelationName(rel))));
6019 }
6020 
6021 /*
6022  * ATWrongRelkindError
6023  *
6024  * Throw an error when a relation has been determined to be of the wrong
6025  * type.
6026  */
6027 static void
ATWrongRelkindError(Relation rel,int allowed_targets)6028 ATWrongRelkindError(Relation rel, int allowed_targets)
6029 {
6030 	char	   *msg;
6031 
6032 	switch (allowed_targets)
6033 	{
6034 		case ATT_TABLE:
6035 			msg = _("\"%s\" is not a table");
6036 			break;
6037 		case ATT_TABLE | ATT_VIEW:
6038 			msg = _("\"%s\" is not a table or view");
6039 			break;
6040 		case ATT_TABLE | ATT_VIEW | ATT_FOREIGN_TABLE:
6041 			msg = _("\"%s\" is not a table, view, or foreign table");
6042 			break;
6043 		case ATT_TABLE | ATT_VIEW | ATT_MATVIEW | ATT_INDEX:
6044 			msg = _("\"%s\" is not a table, view, materialized view, or index");
6045 			break;
6046 		case ATT_TABLE | ATT_MATVIEW:
6047 			msg = _("\"%s\" is not a table or materialized view");
6048 			break;
6049 		case ATT_TABLE | ATT_MATVIEW | ATT_INDEX:
6050 			msg = _("\"%s\" is not a table, materialized view, or index");
6051 			break;
6052 		case ATT_TABLE | ATT_MATVIEW | ATT_INDEX | ATT_PARTITIONED_INDEX:
6053 			msg = _("\"%s\" is not a table, materialized view, index, or partitioned index");
6054 			break;
6055 		case ATT_TABLE | ATT_MATVIEW | ATT_INDEX | ATT_PARTITIONED_INDEX | ATT_FOREIGN_TABLE:
6056 			msg = _("\"%s\" is not a table, materialized view, index, partitioned index, or foreign table");
6057 			break;
6058 		case ATT_TABLE | ATT_MATVIEW | ATT_FOREIGN_TABLE:
6059 			msg = _("\"%s\" is not a table, materialized view, or foreign table");
6060 			break;
6061 		case ATT_TABLE | ATT_FOREIGN_TABLE:
6062 			msg = _("\"%s\" is not a table or foreign table");
6063 			break;
6064 		case ATT_TABLE | ATT_COMPOSITE_TYPE | ATT_FOREIGN_TABLE:
6065 			msg = _("\"%s\" is not a table, composite type, or foreign table");
6066 			break;
6067 		case ATT_TABLE | ATT_MATVIEW | ATT_INDEX | ATT_FOREIGN_TABLE:
6068 			msg = _("\"%s\" is not a table, materialized view, index, or foreign table");
6069 			break;
6070 		case ATT_TABLE | ATT_PARTITIONED_INDEX:
6071 			msg = _("\"%s\" is not a table or partitioned index");
6072 			break;
6073 		case ATT_VIEW:
6074 			msg = _("\"%s\" is not a view");
6075 			break;
6076 		case ATT_FOREIGN_TABLE:
6077 			msg = _("\"%s\" is not a foreign table");
6078 			break;
6079 		default:
6080 			/* shouldn't get here, add all necessary cases above */
6081 			msg = _("\"%s\" is of the wrong type");
6082 			break;
6083 	}
6084 
6085 	ereport(ERROR,
6086 			(errcode(ERRCODE_WRONG_OBJECT_TYPE),
6087 			 errmsg(msg, RelationGetRelationName(rel))));
6088 }
6089 
6090 /*
6091  * ATSimpleRecursion
6092  *
6093  * Simple table recursion sufficient for most ALTER TABLE operations.
6094  * All direct and indirect children are processed in an unspecified order.
6095  * Note that if a child inherits from the original table via multiple
6096  * inheritance paths, it will be visited just once.
6097  */
6098 static void
ATSimpleRecursion(List ** wqueue,Relation rel,AlterTableCmd * cmd,bool recurse,LOCKMODE lockmode,AlterTableUtilityContext * context)6099 ATSimpleRecursion(List **wqueue, Relation rel,
6100 				  AlterTableCmd *cmd, bool recurse, LOCKMODE lockmode,
6101 				  AlterTableUtilityContext *context)
6102 {
6103 	/*
6104 	 * Propagate to children, if desired and if there are (or might be) any
6105 	 * children.
6106 	 */
6107 	if (recurse && rel->rd_rel->relhassubclass)
6108 	{
6109 		Oid			relid = RelationGetRelid(rel);
6110 		ListCell   *child;
6111 		List	   *children;
6112 
6113 		children = find_all_inheritors(relid, lockmode, NULL);
6114 
6115 		/*
6116 		 * find_all_inheritors does the recursive search of the inheritance
6117 		 * hierarchy, so all we have to do is process all of the relids in the
6118 		 * list that it returns.
6119 		 */
6120 		foreach(child, children)
6121 		{
6122 			Oid			childrelid = lfirst_oid(child);
6123 			Relation	childrel;
6124 
6125 			if (childrelid == relid)
6126 				continue;
6127 			/* find_all_inheritors already got lock */
6128 			childrel = relation_open(childrelid, NoLock);
6129 			CheckTableNotInUse(childrel, "ALTER TABLE");
6130 			ATPrepCmd(wqueue, childrel, cmd, false, true, lockmode, context);
6131 			relation_close(childrel, NoLock);
6132 		}
6133 	}
6134 }
6135 
6136 /*
6137  * Obtain list of partitions of the given table, locking them all at the given
6138  * lockmode and ensuring that they all pass CheckTableNotInUse.
6139  *
6140  * This function is a no-op if the given relation is not a partitioned table;
6141  * in particular, nothing is done if it's a legacy inheritance parent.
6142  */
6143 static void
ATCheckPartitionsNotInUse(Relation rel,LOCKMODE lockmode)6144 ATCheckPartitionsNotInUse(Relation rel, LOCKMODE lockmode)
6145 {
6146 	if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
6147 	{
6148 		List	   *inh;
6149 		ListCell   *cell;
6150 
6151 		inh = find_all_inheritors(RelationGetRelid(rel), lockmode, NULL);
6152 		/* first element is the parent rel; must ignore it */
6153 		for_each_from(cell, inh, 1)
6154 		{
6155 			Relation	childrel;
6156 
6157 			/* find_all_inheritors already got lock */
6158 			childrel = table_open(lfirst_oid(cell), NoLock);
6159 			CheckTableNotInUse(childrel, "ALTER TABLE");
6160 			table_close(childrel, NoLock);
6161 		}
6162 		list_free(inh);
6163 	}
6164 }
6165 
6166 /*
6167  * ATTypedTableRecursion
6168  *
6169  * Propagate ALTER TYPE operations to the typed tables of that type.
6170  * Also check the RESTRICT/CASCADE behavior.  Given CASCADE, also permit
6171  * recursion to inheritance children of the typed tables.
6172  */
6173 static void
ATTypedTableRecursion(List ** wqueue,Relation rel,AlterTableCmd * cmd,LOCKMODE lockmode,AlterTableUtilityContext * context)6174 ATTypedTableRecursion(List **wqueue, Relation rel, AlterTableCmd *cmd,
6175 					  LOCKMODE lockmode, AlterTableUtilityContext *context)
6176 {
6177 	ListCell   *child;
6178 	List	   *children;
6179 
6180 	Assert(rel->rd_rel->relkind == RELKIND_COMPOSITE_TYPE);
6181 
6182 	children = find_typed_table_dependencies(rel->rd_rel->reltype,
6183 											 RelationGetRelationName(rel),
6184 											 cmd->behavior);
6185 
6186 	foreach(child, children)
6187 	{
6188 		Oid			childrelid = lfirst_oid(child);
6189 		Relation	childrel;
6190 
6191 		childrel = relation_open(childrelid, lockmode);
6192 		CheckTableNotInUse(childrel, "ALTER TABLE");
6193 		ATPrepCmd(wqueue, childrel, cmd, true, true, lockmode, context);
6194 		relation_close(childrel, NoLock);
6195 	}
6196 }
6197 
6198 
6199 /*
6200  * find_composite_type_dependencies
6201  *
6202  * Check to see if the type "typeOid" is being used as a column in some table
6203  * (possibly nested several levels deep in composite types, arrays, etc!).
6204  * Eventually, we'd like to propagate the check or rewrite operation
6205  * into such tables, but for now, just error out if we find any.
6206  *
6207  * Caller should provide either the associated relation of a rowtype,
6208  * or a type name (not both) for use in the error message, if any.
6209  *
6210  * Note that "typeOid" is not necessarily a composite type; it could also be
6211  * another container type such as an array or range, or a domain over one of
6212  * these things.  The name of this function is therefore somewhat historical,
6213  * but it's not worth changing.
6214  *
6215  * We assume that functions and views depending on the type are not reasons
6216  * to reject the ALTER.  (How safe is this really?)
6217  */
6218 void
find_composite_type_dependencies(Oid typeOid,Relation origRelation,const char * origTypeName)6219 find_composite_type_dependencies(Oid typeOid, Relation origRelation,
6220 								 const char *origTypeName)
6221 {
6222 	Relation	depRel;
6223 	ScanKeyData key[2];
6224 	SysScanDesc depScan;
6225 	HeapTuple	depTup;
6226 
6227 	/* since this function recurses, it could be driven to stack overflow */
6228 	check_stack_depth();
6229 
6230 	/*
6231 	 * We scan pg_depend to find those things that depend on the given type.
6232 	 * (We assume we can ignore refobjsubid for a type.)
6233 	 */
6234 	depRel = table_open(DependRelationId, AccessShareLock);
6235 
6236 	ScanKeyInit(&key[0],
6237 				Anum_pg_depend_refclassid,
6238 				BTEqualStrategyNumber, F_OIDEQ,
6239 				ObjectIdGetDatum(TypeRelationId));
6240 	ScanKeyInit(&key[1],
6241 				Anum_pg_depend_refobjid,
6242 				BTEqualStrategyNumber, F_OIDEQ,
6243 				ObjectIdGetDatum(typeOid));
6244 
6245 	depScan = systable_beginscan(depRel, DependReferenceIndexId, true,
6246 								 NULL, 2, key);
6247 
6248 	while (HeapTupleIsValid(depTup = systable_getnext(depScan)))
6249 	{
6250 		Form_pg_depend pg_depend = (Form_pg_depend) GETSTRUCT(depTup);
6251 		Relation	rel;
6252 		Form_pg_attribute att;
6253 
6254 		/* Check for directly dependent types */
6255 		if (pg_depend->classid == TypeRelationId)
6256 		{
6257 			/*
6258 			 * This must be an array, domain, or range containing the given
6259 			 * type, so recursively check for uses of this type.  Note that
6260 			 * any error message will mention the original type not the
6261 			 * container; this is intentional.
6262 			 */
6263 			find_composite_type_dependencies(pg_depend->objid,
6264 											 origRelation, origTypeName);
6265 			continue;
6266 		}
6267 
6268 		/* Else, ignore dependees that aren't user columns of relations */
6269 		/* (we assume system columns are never of interesting types) */
6270 		if (pg_depend->classid != RelationRelationId ||
6271 			pg_depend->objsubid <= 0)
6272 			continue;
6273 
6274 		rel = relation_open(pg_depend->objid, AccessShareLock);
6275 		att = TupleDescAttr(rel->rd_att, pg_depend->objsubid - 1);
6276 
6277 		if (rel->rd_rel->relkind == RELKIND_RELATION ||
6278 			rel->rd_rel->relkind == RELKIND_MATVIEW ||
6279 			rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
6280 		{
6281 			if (origTypeName)
6282 				ereport(ERROR,
6283 						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
6284 						 errmsg("cannot alter type \"%s\" because column \"%s.%s\" uses it",
6285 								origTypeName,
6286 								RelationGetRelationName(rel),
6287 								NameStr(att->attname))));
6288 			else if (origRelation->rd_rel->relkind == RELKIND_COMPOSITE_TYPE)
6289 				ereport(ERROR,
6290 						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
6291 						 errmsg("cannot alter type \"%s\" because column \"%s.%s\" uses it",
6292 								RelationGetRelationName(origRelation),
6293 								RelationGetRelationName(rel),
6294 								NameStr(att->attname))));
6295 			else if (origRelation->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
6296 				ereport(ERROR,
6297 						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
6298 						 errmsg("cannot alter foreign table \"%s\" because column \"%s.%s\" uses its row type",
6299 								RelationGetRelationName(origRelation),
6300 								RelationGetRelationName(rel),
6301 								NameStr(att->attname))));
6302 			else
6303 				ereport(ERROR,
6304 						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
6305 						 errmsg("cannot alter table \"%s\" because column \"%s.%s\" uses its row type",
6306 								RelationGetRelationName(origRelation),
6307 								RelationGetRelationName(rel),
6308 								NameStr(att->attname))));
6309 		}
6310 		else if (OidIsValid(rel->rd_rel->reltype))
6311 		{
6312 			/*
6313 			 * A view or composite type itself isn't a problem, but we must
6314 			 * recursively check for indirect dependencies via its rowtype.
6315 			 */
6316 			find_composite_type_dependencies(rel->rd_rel->reltype,
6317 											 origRelation, origTypeName);
6318 		}
6319 
6320 		relation_close(rel, AccessShareLock);
6321 	}
6322 
6323 	systable_endscan(depScan);
6324 
6325 	relation_close(depRel, AccessShareLock);
6326 }
6327 
6328 
6329 /*
6330  * find_typed_table_dependencies
6331  *
6332  * Check to see if a composite type is being used as the type of a
6333  * typed table.  Abort if any are found and behavior is RESTRICT.
6334  * Else return the list of tables.
6335  */
6336 static List *
find_typed_table_dependencies(Oid typeOid,const char * typeName,DropBehavior behavior)6337 find_typed_table_dependencies(Oid typeOid, const char *typeName, DropBehavior behavior)
6338 {
6339 	Relation	classRel;
6340 	ScanKeyData key[1];
6341 	TableScanDesc scan;
6342 	HeapTuple	tuple;
6343 	List	   *result = NIL;
6344 
6345 	classRel = table_open(RelationRelationId, AccessShareLock);
6346 
6347 	ScanKeyInit(&key[0],
6348 				Anum_pg_class_reloftype,
6349 				BTEqualStrategyNumber, F_OIDEQ,
6350 				ObjectIdGetDatum(typeOid));
6351 
6352 	scan = table_beginscan_catalog(classRel, 1, key);
6353 
6354 	while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
6355 	{
6356 		Form_pg_class classform = (Form_pg_class) GETSTRUCT(tuple);
6357 
6358 		if (behavior == DROP_RESTRICT)
6359 			ereport(ERROR,
6360 					(errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
6361 					 errmsg("cannot alter type \"%s\" because it is the type of a typed table",
6362 							typeName),
6363 					 errhint("Use ALTER ... CASCADE to alter the typed tables too.")));
6364 		else
6365 			result = lappend_oid(result, classform->oid);
6366 	}
6367 
6368 	table_endscan(scan);
6369 	table_close(classRel, AccessShareLock);
6370 
6371 	return result;
6372 }
6373 
6374 
6375 /*
6376  * check_of_type
6377  *
6378  * Check whether a type is suitable for CREATE TABLE OF/ALTER TABLE OF.  If it
6379  * isn't suitable, throw an error.  Currently, we require that the type
6380  * originated with CREATE TYPE AS.  We could support any row type, but doing so
6381  * would require handling a number of extra corner cases in the DDL commands.
6382  * (Also, allowing domain-over-composite would open up a can of worms about
6383  * whether and how the domain's constraints should apply to derived tables.)
6384  */
6385 void
check_of_type(HeapTuple typetuple)6386 check_of_type(HeapTuple typetuple)
6387 {
6388 	Form_pg_type typ = (Form_pg_type) GETSTRUCT(typetuple);
6389 	bool		typeOk = false;
6390 
6391 	if (typ->typtype == TYPTYPE_COMPOSITE)
6392 	{
6393 		Relation	typeRelation;
6394 
6395 		Assert(OidIsValid(typ->typrelid));
6396 		typeRelation = relation_open(typ->typrelid, AccessShareLock);
6397 		typeOk = (typeRelation->rd_rel->relkind == RELKIND_COMPOSITE_TYPE);
6398 
6399 		/*
6400 		 * Close the parent rel, but keep our AccessShareLock on it until xact
6401 		 * commit.  That will prevent someone else from deleting or ALTERing
6402 		 * the type before the typed table creation/conversion commits.
6403 		 */
6404 		relation_close(typeRelation, NoLock);
6405 	}
6406 	if (!typeOk)
6407 		ereport(ERROR,
6408 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
6409 				 errmsg("type %s is not a composite type",
6410 						format_type_be(typ->oid))));
6411 }
6412 
6413 
6414 /*
6415  * ALTER TABLE ADD COLUMN
6416  *
6417  * Adds an additional attribute to a relation making the assumption that
6418  * CHECK, NOT NULL, and FOREIGN KEY constraints will be removed from the
6419  * AT_AddColumn AlterTableCmd by parse_utilcmd.c and added as independent
6420  * AlterTableCmd's.
6421  *
6422  * ADD COLUMN cannot use the normal ALTER TABLE recursion mechanism, because we
6423  * have to decide at runtime whether to recurse or not depending on whether we
6424  * actually add a column or merely merge with an existing column.  (We can't
6425  * check this in a static pre-pass because it won't handle multiple inheritance
6426  * situations correctly.)
6427  */
6428 static void
ATPrepAddColumn(List ** wqueue,Relation rel,bool recurse,bool recursing,bool is_view,AlterTableCmd * cmd,LOCKMODE lockmode,AlterTableUtilityContext * context)6429 ATPrepAddColumn(List **wqueue, Relation rel, bool recurse, bool recursing,
6430 				bool is_view, AlterTableCmd *cmd, LOCKMODE lockmode,
6431 				AlterTableUtilityContext *context)
6432 {
6433 	if (rel->rd_rel->reloftype && !recursing)
6434 		ereport(ERROR,
6435 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
6436 				 errmsg("cannot add column to typed table")));
6437 
6438 	if (rel->rd_rel->relkind == RELKIND_COMPOSITE_TYPE)
6439 		ATTypedTableRecursion(wqueue, rel, cmd, lockmode, context);
6440 
6441 	if (recurse && !is_view)
6442 		cmd->subtype = AT_AddColumnRecurse;
6443 }
6444 
6445 /*
6446  * Add a column to a table.  The return value is the address of the
6447  * new column in the parent relation.
6448  *
6449  * cmd is pass-by-ref so that we can replace it with the parse-transformed
6450  * copy (but that happens only after we check for IF NOT EXISTS).
6451  */
6452 static ObjectAddress
ATExecAddColumn(List ** wqueue,AlteredTableInfo * tab,Relation rel,AlterTableCmd ** cmd,bool recurse,bool recursing,LOCKMODE lockmode,int cur_pass,AlterTableUtilityContext * context)6453 ATExecAddColumn(List **wqueue, AlteredTableInfo *tab, Relation rel,
6454 				AlterTableCmd **cmd,
6455 				bool recurse, bool recursing,
6456 				LOCKMODE lockmode, int cur_pass,
6457 				AlterTableUtilityContext *context)
6458 {
6459 	Oid			myrelid = RelationGetRelid(rel);
6460 	ColumnDef  *colDef = castNode(ColumnDef, (*cmd)->def);
6461 	bool		if_not_exists = (*cmd)->missing_ok;
6462 	Relation	pgclass,
6463 				attrdesc;
6464 	HeapTuple	reltup;
6465 	FormData_pg_attribute attribute;
6466 	int			newattnum;
6467 	char		relkind;
6468 	HeapTuple	typeTuple;
6469 	Oid			typeOid;
6470 	int32		typmod;
6471 	Oid			collOid;
6472 	Form_pg_type tform;
6473 	Expr	   *defval;
6474 	List	   *children;
6475 	ListCell   *child;
6476 	AlterTableCmd *childcmd;
6477 	AclResult	aclresult;
6478 	ObjectAddress address;
6479 	TupleDesc	tupdesc;
6480 	FormData_pg_attribute *aattr[] = {&attribute};
6481 
6482 	/* At top level, permission check was done in ATPrepCmd, else do it */
6483 	if (recursing)
6484 		ATSimplePermissions(rel, ATT_TABLE | ATT_FOREIGN_TABLE);
6485 
6486 	if (rel->rd_rel->relispartition && !recursing)
6487 		ereport(ERROR,
6488 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
6489 				 errmsg("cannot add column to a partition")));
6490 
6491 	attrdesc = table_open(AttributeRelationId, RowExclusiveLock);
6492 
6493 	/*
6494 	 * Are we adding the column to a recursion child?  If so, check whether to
6495 	 * merge with an existing definition for the column.  If we do merge, we
6496 	 * must not recurse.  Children will already have the column, and recursing
6497 	 * into them would mess up attinhcount.
6498 	 */
6499 	if (colDef->inhcount > 0)
6500 	{
6501 		HeapTuple	tuple;
6502 
6503 		/* Does child already have a column by this name? */
6504 		tuple = SearchSysCacheCopyAttName(myrelid, colDef->colname);
6505 		if (HeapTupleIsValid(tuple))
6506 		{
6507 			Form_pg_attribute childatt = (Form_pg_attribute) GETSTRUCT(tuple);
6508 			Oid			ctypeId;
6509 			int32		ctypmod;
6510 			Oid			ccollid;
6511 
6512 			/* Child column must match on type, typmod, and collation */
6513 			typenameTypeIdAndMod(NULL, colDef->typeName, &ctypeId, &ctypmod);
6514 			if (ctypeId != childatt->atttypid ||
6515 				ctypmod != childatt->atttypmod)
6516 				ereport(ERROR,
6517 						(errcode(ERRCODE_DATATYPE_MISMATCH),
6518 						 errmsg("child table \"%s\" has different type for column \"%s\"",
6519 								RelationGetRelationName(rel), colDef->colname)));
6520 			ccollid = GetColumnDefCollation(NULL, colDef, ctypeId);
6521 			if (ccollid != childatt->attcollation)
6522 				ereport(ERROR,
6523 						(errcode(ERRCODE_COLLATION_MISMATCH),
6524 						 errmsg("child table \"%s\" has different collation for column \"%s\"",
6525 								RelationGetRelationName(rel), colDef->colname),
6526 						 errdetail("\"%s\" versus \"%s\"",
6527 								   get_collation_name(ccollid),
6528 								   get_collation_name(childatt->attcollation))));
6529 
6530 			/* Bump the existing child att's inhcount */
6531 			childatt->attinhcount++;
6532 			CatalogTupleUpdate(attrdesc, &tuple->t_self, tuple);
6533 
6534 			heap_freetuple(tuple);
6535 
6536 			/* Inform the user about the merge */
6537 			ereport(NOTICE,
6538 					(errmsg("merging definition of column \"%s\" for child \"%s\"",
6539 							colDef->colname, RelationGetRelationName(rel))));
6540 
6541 			table_close(attrdesc, RowExclusiveLock);
6542 			return InvalidObjectAddress;
6543 		}
6544 	}
6545 
6546 	/* skip if the name already exists and if_not_exists is true */
6547 	if (!check_for_column_name_collision(rel, colDef->colname, if_not_exists))
6548 	{
6549 		table_close(attrdesc, RowExclusiveLock);
6550 		return InvalidObjectAddress;
6551 	}
6552 
6553 	/*
6554 	 * Okay, we need to add the column, so go ahead and do parse
6555 	 * transformation.  This can result in queueing up, or even immediately
6556 	 * executing, subsidiary operations (such as creation of unique indexes);
6557 	 * so we mustn't do it until we have made the if_not_exists check.
6558 	 *
6559 	 * When recursing, the command was already transformed and we needn't do
6560 	 * so again.  Also, if context isn't given we can't transform.  (That
6561 	 * currently happens only for AT_AddColumnToView; we expect that view.c
6562 	 * passed us a ColumnDef that doesn't need work.)
6563 	 */
6564 	if (context != NULL && !recursing)
6565 	{
6566 		*cmd = ATParseTransformCmd(wqueue, tab, rel, *cmd, recurse, lockmode,
6567 								   cur_pass, context);
6568 		Assert(*cmd != NULL);
6569 		colDef = castNode(ColumnDef, (*cmd)->def);
6570 	}
6571 
6572 	/*
6573 	 * Cannot add identity column if table has children, because identity does
6574 	 * not inherit.  (Adding column and identity separately will work.)
6575 	 */
6576 	if (colDef->identity &&
6577 		recurse &&
6578 		find_inheritance_children(myrelid, NoLock) != NIL)
6579 		ereport(ERROR,
6580 				(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
6581 				 errmsg("cannot recursively add identity column to table that has child tables")));
6582 
6583 	pgclass = table_open(RelationRelationId, RowExclusiveLock);
6584 
6585 	reltup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(myrelid));
6586 	if (!HeapTupleIsValid(reltup))
6587 		elog(ERROR, "cache lookup failed for relation %u", myrelid);
6588 	relkind = ((Form_pg_class) GETSTRUCT(reltup))->relkind;
6589 
6590 	/* Determine the new attribute's number */
6591 	newattnum = ((Form_pg_class) GETSTRUCT(reltup))->relnatts + 1;
6592 	if (newattnum > MaxHeapAttributeNumber)
6593 		ereport(ERROR,
6594 				(errcode(ERRCODE_TOO_MANY_COLUMNS),
6595 				 errmsg("tables can have at most %d columns",
6596 						MaxHeapAttributeNumber)));
6597 
6598 	typeTuple = typenameType(NULL, colDef->typeName, &typmod);
6599 	tform = (Form_pg_type) GETSTRUCT(typeTuple);
6600 	typeOid = tform->oid;
6601 
6602 	aclresult = pg_type_aclcheck(typeOid, GetUserId(), ACL_USAGE);
6603 	if (aclresult != ACLCHECK_OK)
6604 		aclcheck_error_type(aclresult, typeOid);
6605 
6606 	collOid = GetColumnDefCollation(NULL, colDef, typeOid);
6607 
6608 	/* make sure datatype is legal for a column */
6609 	CheckAttributeType(colDef->colname, typeOid, collOid,
6610 					   list_make1_oid(rel->rd_rel->reltype),
6611 					   0);
6612 
6613 	/* construct new attribute's pg_attribute entry */
6614 	attribute.attrelid = myrelid;
6615 	namestrcpy(&(attribute.attname), colDef->colname);
6616 	attribute.atttypid = typeOid;
6617 	attribute.attstattarget = (newattnum > 0) ? -1 : 0;
6618 	attribute.attlen = tform->typlen;
6619 	attribute.attnum = newattnum;
6620 	attribute.attndims = list_length(colDef->typeName->arrayBounds);
6621 	attribute.atttypmod = typmod;
6622 	attribute.attbyval = tform->typbyval;
6623 	attribute.attalign = tform->typalign;
6624 	attribute.attstorage = tform->typstorage;
6625 	attribute.attcompression = GetAttributeCompression(typeOid,
6626 													   colDef->compression);
6627 	attribute.attnotnull = colDef->is_not_null;
6628 	attribute.atthasdef = false;
6629 	attribute.atthasmissing = false;
6630 	attribute.attidentity = colDef->identity;
6631 	attribute.attgenerated = colDef->generated;
6632 	attribute.attisdropped = false;
6633 	attribute.attislocal = colDef->is_local;
6634 	attribute.attinhcount = colDef->inhcount;
6635 	attribute.attcollation = collOid;
6636 
6637 	/* attribute.attacl is handled by InsertPgAttributeTuples() */
6638 
6639 	ReleaseSysCache(typeTuple);
6640 
6641 	tupdesc = CreateTupleDesc(lengthof(aattr), (FormData_pg_attribute **) &aattr);
6642 
6643 	InsertPgAttributeTuples(attrdesc, tupdesc, myrelid, NULL, NULL);
6644 
6645 	table_close(attrdesc, RowExclusiveLock);
6646 
6647 	/*
6648 	 * Update pg_class tuple as appropriate
6649 	 */
6650 	((Form_pg_class) GETSTRUCT(reltup))->relnatts = newattnum;
6651 
6652 	CatalogTupleUpdate(pgclass, &reltup->t_self, reltup);
6653 
6654 	heap_freetuple(reltup);
6655 
6656 	/* Post creation hook for new attribute */
6657 	InvokeObjectPostCreateHook(RelationRelationId, myrelid, newattnum);
6658 
6659 	table_close(pgclass, RowExclusiveLock);
6660 
6661 	/* Make the attribute's catalog entry visible */
6662 	CommandCounterIncrement();
6663 
6664 	/*
6665 	 * Store the DEFAULT, if any, in the catalogs
6666 	 */
6667 	if (colDef->raw_default)
6668 	{
6669 		RawColumnDefault *rawEnt;
6670 
6671 		rawEnt = (RawColumnDefault *) palloc(sizeof(RawColumnDefault));
6672 		rawEnt->attnum = attribute.attnum;
6673 		rawEnt->raw_default = copyObject(colDef->raw_default);
6674 
6675 		/*
6676 		 * Attempt to skip a complete table rewrite by storing the specified
6677 		 * DEFAULT value outside of the heap.  This may be disabled inside
6678 		 * AddRelationNewConstraints if the optimization cannot be applied.
6679 		 */
6680 		rawEnt->missingMode = (!colDef->generated);
6681 
6682 		rawEnt->generated = colDef->generated;
6683 
6684 		/*
6685 		 * This function is intended for CREATE TABLE, so it processes a
6686 		 * _list_ of defaults, but we just do one.
6687 		 */
6688 		AddRelationNewConstraints(rel, list_make1(rawEnt), NIL,
6689 								  false, true, false, NULL);
6690 
6691 		/* Make the additional catalog changes visible */
6692 		CommandCounterIncrement();
6693 
6694 		/*
6695 		 * Did the request for a missing value work? If not we'll have to do a
6696 		 * rewrite
6697 		 */
6698 		if (!rawEnt->missingMode)
6699 			tab->rewrite |= AT_REWRITE_DEFAULT_VAL;
6700 	}
6701 
6702 	/*
6703 	 * Tell Phase 3 to fill in the default expression, if there is one.
6704 	 *
6705 	 * If there is no default, Phase 3 doesn't have to do anything, because
6706 	 * that effectively means that the default is NULL.  The heap tuple access
6707 	 * routines always check for attnum > # of attributes in tuple, and return
6708 	 * NULL if so, so without any modification of the tuple data we will get
6709 	 * the effect of NULL values in the new column.
6710 	 *
6711 	 * An exception occurs when the new column is of a domain type: the domain
6712 	 * might have a NOT NULL constraint, or a check constraint that indirectly
6713 	 * rejects nulls.  If there are any domain constraints then we construct
6714 	 * an explicit NULL default value that will be passed through
6715 	 * CoerceToDomain processing.  (This is a tad inefficient, since it causes
6716 	 * rewriting the table which we really don't have to do, but the present
6717 	 * design of domain processing doesn't offer any simple way of checking
6718 	 * the constraints more directly.)
6719 	 *
6720 	 * Note: we use build_column_default, and not just the cooked default
6721 	 * returned by AddRelationNewConstraints, so that the right thing happens
6722 	 * when a datatype's default applies.
6723 	 *
6724 	 * Note: it might seem that this should happen at the end of Phase 2, so
6725 	 * that the effects of subsequent subcommands can be taken into account.
6726 	 * It's intentional that we do it now, though.  The new column should be
6727 	 * filled according to what is said in the ADD COLUMN subcommand, so that
6728 	 * the effects are the same as if this subcommand had been run by itself
6729 	 * and the later subcommands had been issued in new ALTER TABLE commands.
6730 	 *
6731 	 * We can skip this entirely for relations without storage, since Phase 3
6732 	 * is certainly not going to touch them.  System attributes don't have
6733 	 * interesting defaults, either.
6734 	 */
6735 	if (RELKIND_HAS_STORAGE(relkind) && attribute.attnum > 0)
6736 	{
6737 		/*
6738 		 * For an identity column, we can't use build_column_default(),
6739 		 * because the sequence ownership isn't set yet.  So do it manually.
6740 		 */
6741 		if (colDef->identity)
6742 		{
6743 			NextValueExpr *nve = makeNode(NextValueExpr);
6744 
6745 			nve->seqid = RangeVarGetRelid(colDef->identitySequence, NoLock, false);
6746 			nve->typeId = typeOid;
6747 
6748 			defval = (Expr *) nve;
6749 
6750 			/* must do a rewrite for identity columns */
6751 			tab->rewrite |= AT_REWRITE_DEFAULT_VAL;
6752 		}
6753 		else
6754 			defval = (Expr *) build_column_default(rel, attribute.attnum);
6755 
6756 		if (!defval && DomainHasConstraints(typeOid))
6757 		{
6758 			Oid			baseTypeId;
6759 			int32		baseTypeMod;
6760 			Oid			baseTypeColl;
6761 
6762 			baseTypeMod = typmod;
6763 			baseTypeId = getBaseTypeAndTypmod(typeOid, &baseTypeMod);
6764 			baseTypeColl = get_typcollation(baseTypeId);
6765 			defval = (Expr *) makeNullConst(baseTypeId, baseTypeMod, baseTypeColl);
6766 			defval = (Expr *) coerce_to_target_type(NULL,
6767 													(Node *) defval,
6768 													baseTypeId,
6769 													typeOid,
6770 													typmod,
6771 													COERCION_ASSIGNMENT,
6772 													COERCE_IMPLICIT_CAST,
6773 													-1);
6774 			if (defval == NULL) /* should not happen */
6775 				elog(ERROR, "failed to coerce base type to domain");
6776 		}
6777 
6778 		if (defval)
6779 		{
6780 			NewColumnValue *newval;
6781 
6782 			newval = (NewColumnValue *) palloc0(sizeof(NewColumnValue));
6783 			newval->attnum = attribute.attnum;
6784 			newval->expr = expression_planner(defval);
6785 			newval->is_generated = (colDef->generated != '\0');
6786 
6787 			tab->newvals = lappend(tab->newvals, newval);
6788 		}
6789 
6790 		if (DomainHasConstraints(typeOid))
6791 			tab->rewrite |= AT_REWRITE_DEFAULT_VAL;
6792 
6793 		if (!TupleDescAttr(rel->rd_att, attribute.attnum - 1)->atthasmissing)
6794 		{
6795 			/*
6796 			 * If the new column is NOT NULL, and there is no missing value,
6797 			 * tell Phase 3 it needs to check for NULLs.
6798 			 */
6799 			tab->verify_new_notnull |= colDef->is_not_null;
6800 		}
6801 	}
6802 
6803 	/*
6804 	 * Add needed dependency entries for the new column.
6805 	 */
6806 	add_column_datatype_dependency(myrelid, newattnum, attribute.atttypid);
6807 	add_column_collation_dependency(myrelid, newattnum, attribute.attcollation);
6808 
6809 	/*
6810 	 * Propagate to children as appropriate.  Unlike most other ALTER
6811 	 * routines, we have to do this one level of recursion at a time; we can't
6812 	 * use find_all_inheritors to do it in one pass.
6813 	 */
6814 	children =
6815 		find_inheritance_children(RelationGetRelid(rel), lockmode);
6816 
6817 	/*
6818 	 * If we are told not to recurse, there had better not be any child
6819 	 * tables; else the addition would put them out of step.
6820 	 */
6821 	if (children && !recurse)
6822 		ereport(ERROR,
6823 				(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
6824 				 errmsg("column must be added to child tables too")));
6825 
6826 	/* Children should see column as singly inherited */
6827 	if (!recursing)
6828 	{
6829 		childcmd = copyObject(*cmd);
6830 		colDef = castNode(ColumnDef, childcmd->def);
6831 		colDef->inhcount = 1;
6832 		colDef->is_local = false;
6833 	}
6834 	else
6835 		childcmd = *cmd;		/* no need to copy again */
6836 
6837 	foreach(child, children)
6838 	{
6839 		Oid			childrelid = lfirst_oid(child);
6840 		Relation	childrel;
6841 		AlteredTableInfo *childtab;
6842 
6843 		/* find_inheritance_children already got lock */
6844 		childrel = table_open(childrelid, NoLock);
6845 		CheckTableNotInUse(childrel, "ALTER TABLE");
6846 
6847 		/* Find or create work queue entry for this table */
6848 		childtab = ATGetQueueEntry(wqueue, childrel);
6849 
6850 		/* Recurse to child; return value is ignored */
6851 		ATExecAddColumn(wqueue, childtab, childrel,
6852 						&childcmd, recurse, true,
6853 						lockmode, cur_pass, context);
6854 
6855 		table_close(childrel, NoLock);
6856 	}
6857 
6858 	ObjectAddressSubSet(address, RelationRelationId, myrelid, newattnum);
6859 	return address;
6860 }
6861 
6862 /*
6863  * If a new or renamed column will collide with the name of an existing
6864  * column and if_not_exists is false then error out, else do nothing.
6865  */
6866 static bool
check_for_column_name_collision(Relation rel,const char * colname,bool if_not_exists)6867 check_for_column_name_collision(Relation rel, const char *colname,
6868 								bool if_not_exists)
6869 {
6870 	HeapTuple	attTuple;
6871 	int			attnum;
6872 
6873 	/*
6874 	 * this test is deliberately not attisdropped-aware, since if one tries to
6875 	 * add a column matching a dropped column name, it's gonna fail anyway.
6876 	 */
6877 	attTuple = SearchSysCache2(ATTNAME,
6878 							   ObjectIdGetDatum(RelationGetRelid(rel)),
6879 							   PointerGetDatum(colname));
6880 	if (!HeapTupleIsValid(attTuple))
6881 		return true;
6882 
6883 	attnum = ((Form_pg_attribute) GETSTRUCT(attTuple))->attnum;
6884 	ReleaseSysCache(attTuple);
6885 
6886 	/*
6887 	 * We throw a different error message for conflicts with system column
6888 	 * names, since they are normally not shown and the user might otherwise
6889 	 * be confused about the reason for the conflict.
6890 	 */
6891 	if (attnum <= 0)
6892 		ereport(ERROR,
6893 				(errcode(ERRCODE_DUPLICATE_COLUMN),
6894 				 errmsg("column name \"%s\" conflicts with a system column name",
6895 						colname)));
6896 	else
6897 	{
6898 		if (if_not_exists)
6899 		{
6900 			ereport(NOTICE,
6901 					(errcode(ERRCODE_DUPLICATE_COLUMN),
6902 					 errmsg("column \"%s\" of relation \"%s\" already exists, skipping",
6903 							colname, RelationGetRelationName(rel))));
6904 			return false;
6905 		}
6906 
6907 		ereport(ERROR,
6908 				(errcode(ERRCODE_DUPLICATE_COLUMN),
6909 				 errmsg("column \"%s\" of relation \"%s\" already exists",
6910 						colname, RelationGetRelationName(rel))));
6911 	}
6912 
6913 	return true;
6914 }
6915 
6916 /*
6917  * Install a column's dependency on its datatype.
6918  */
6919 static void
add_column_datatype_dependency(Oid relid,int32 attnum,Oid typid)6920 add_column_datatype_dependency(Oid relid, int32 attnum, Oid typid)
6921 {
6922 	ObjectAddress myself,
6923 				referenced;
6924 
6925 	myself.classId = RelationRelationId;
6926 	myself.objectId = relid;
6927 	myself.objectSubId = attnum;
6928 	referenced.classId = TypeRelationId;
6929 	referenced.objectId = typid;
6930 	referenced.objectSubId = 0;
6931 	recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
6932 }
6933 
6934 /*
6935  * Install a column's dependency on its collation.
6936  */
6937 static void
add_column_collation_dependency(Oid relid,int32 attnum,Oid collid)6938 add_column_collation_dependency(Oid relid, int32 attnum, Oid collid)
6939 {
6940 	ObjectAddress myself,
6941 				referenced;
6942 
6943 	/* We know the default collation is pinned, so don't bother recording it */
6944 	if (OidIsValid(collid) && collid != DEFAULT_COLLATION_OID)
6945 	{
6946 		myself.classId = RelationRelationId;
6947 		myself.objectId = relid;
6948 		myself.objectSubId = attnum;
6949 		referenced.classId = CollationRelationId;
6950 		referenced.objectId = collid;
6951 		referenced.objectSubId = 0;
6952 		recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
6953 	}
6954 }
6955 
6956 /*
6957  * ALTER TABLE ALTER COLUMN DROP NOT NULL
6958  */
6959 
6960 static void
ATPrepDropNotNull(Relation rel,bool recurse,bool recursing)6961 ATPrepDropNotNull(Relation rel, bool recurse, bool recursing)
6962 {
6963 	/*
6964 	 * If the parent is a partitioned table, like check constraints, we do not
6965 	 * support removing the NOT NULL while partitions exist.
6966 	 */
6967 	if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
6968 	{
6969 		PartitionDesc partdesc = RelationGetPartitionDesc(rel, true);
6970 
6971 		Assert(partdesc != NULL);
6972 		if (partdesc->nparts > 0 && !recurse && !recursing)
6973 			ereport(ERROR,
6974 					(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
6975 					 errmsg("cannot remove constraint from only the partitioned table when partitions exist"),
6976 					 errhint("Do not specify the ONLY keyword.")));
6977 	}
6978 }
6979 
6980 /*
6981  * Return the address of the modified column.  If the column was already
6982  * nullable, InvalidObjectAddress is returned.
6983  */
6984 static ObjectAddress
ATExecDropNotNull(Relation rel,const char * colName,LOCKMODE lockmode)6985 ATExecDropNotNull(Relation rel, const char *colName, LOCKMODE lockmode)
6986 {
6987 	HeapTuple	tuple;
6988 	Form_pg_attribute attTup;
6989 	AttrNumber	attnum;
6990 	Relation	attr_rel;
6991 	List	   *indexoidlist;
6992 	ListCell   *indexoidscan;
6993 	ObjectAddress address;
6994 
6995 	/*
6996 	 * lookup the attribute
6997 	 */
6998 	attr_rel = table_open(AttributeRelationId, RowExclusiveLock);
6999 
7000 	tuple = SearchSysCacheCopyAttName(RelationGetRelid(rel), colName);
7001 	if (!HeapTupleIsValid(tuple))
7002 		ereport(ERROR,
7003 				(errcode(ERRCODE_UNDEFINED_COLUMN),
7004 				 errmsg("column \"%s\" of relation \"%s\" does not exist",
7005 						colName, RelationGetRelationName(rel))));
7006 	attTup = (Form_pg_attribute) GETSTRUCT(tuple);
7007 	attnum = attTup->attnum;
7008 
7009 	/* Prevent them from altering a system attribute */
7010 	if (attnum <= 0)
7011 		ereport(ERROR,
7012 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
7013 				 errmsg("cannot alter system column \"%s\"",
7014 						colName)));
7015 
7016 	if (attTup->attidentity)
7017 		ereport(ERROR,
7018 				(errcode(ERRCODE_SYNTAX_ERROR),
7019 				 errmsg("column \"%s\" of relation \"%s\" is an identity column",
7020 						colName, RelationGetRelationName(rel))));
7021 
7022 	/*
7023 	 * Check that the attribute is not in a primary key
7024 	 *
7025 	 * Note: we'll throw error even if the pkey index is not valid.
7026 	 */
7027 
7028 	/* Loop over all indexes on the relation */
7029 	indexoidlist = RelationGetIndexList(rel);
7030 
7031 	foreach(indexoidscan, indexoidlist)
7032 	{
7033 		Oid			indexoid = lfirst_oid(indexoidscan);
7034 		HeapTuple	indexTuple;
7035 		Form_pg_index indexStruct;
7036 		int			i;
7037 
7038 		indexTuple = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(indexoid));
7039 		if (!HeapTupleIsValid(indexTuple))
7040 			elog(ERROR, "cache lookup failed for index %u", indexoid);
7041 		indexStruct = (Form_pg_index) GETSTRUCT(indexTuple);
7042 
7043 		/* If the index is not a primary key, skip the check */
7044 		if (indexStruct->indisprimary)
7045 		{
7046 			/*
7047 			 * Loop over each attribute in the primary key and see if it
7048 			 * matches the to-be-altered attribute
7049 			 */
7050 			for (i = 0; i < indexStruct->indnkeyatts; i++)
7051 			{
7052 				if (indexStruct->indkey.values[i] == attnum)
7053 					ereport(ERROR,
7054 							(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
7055 							 errmsg("column \"%s\" is in a primary key",
7056 									colName)));
7057 			}
7058 		}
7059 
7060 		ReleaseSysCache(indexTuple);
7061 	}
7062 
7063 	list_free(indexoidlist);
7064 
7065 	/* If rel is partition, shouldn't drop NOT NULL if parent has the same */
7066 	if (rel->rd_rel->relispartition)
7067 	{
7068 		Oid			parentId = get_partition_parent(RelationGetRelid(rel), false);
7069 		Relation	parent = table_open(parentId, AccessShareLock);
7070 		TupleDesc	tupDesc = RelationGetDescr(parent);
7071 		AttrNumber	parent_attnum;
7072 
7073 		parent_attnum = get_attnum(parentId, colName);
7074 		if (TupleDescAttr(tupDesc, parent_attnum - 1)->attnotnull)
7075 			ereport(ERROR,
7076 					(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
7077 					 errmsg("column \"%s\" is marked NOT NULL in parent table",
7078 							colName)));
7079 		table_close(parent, AccessShareLock);
7080 	}
7081 
7082 	/*
7083 	 * Okay, actually perform the catalog change ... if needed
7084 	 */
7085 	if (attTup->attnotnull)
7086 	{
7087 		attTup->attnotnull = false;
7088 
7089 		CatalogTupleUpdate(attr_rel, &tuple->t_self, tuple);
7090 
7091 		ObjectAddressSubSet(address, RelationRelationId,
7092 							RelationGetRelid(rel), attnum);
7093 	}
7094 	else
7095 		address = InvalidObjectAddress;
7096 
7097 	InvokeObjectPostAlterHook(RelationRelationId,
7098 							  RelationGetRelid(rel), attnum);
7099 
7100 	table_close(attr_rel, RowExclusiveLock);
7101 
7102 	return address;
7103 }
7104 
7105 /*
7106  * ALTER TABLE ALTER COLUMN SET NOT NULL
7107  */
7108 
7109 static void
ATPrepSetNotNull(List ** wqueue,Relation rel,AlterTableCmd * cmd,bool recurse,bool recursing,LOCKMODE lockmode,AlterTableUtilityContext * context)7110 ATPrepSetNotNull(List **wqueue, Relation rel,
7111 				 AlterTableCmd *cmd, bool recurse, bool recursing,
7112 				 LOCKMODE lockmode, AlterTableUtilityContext *context)
7113 {
7114 	/*
7115 	 * If we're already recursing, there's nothing to do; the topmost
7116 	 * invocation of ATSimpleRecursion already visited all children.
7117 	 */
7118 	if (recursing)
7119 		return;
7120 
7121 	/*
7122 	 * If the target column is already marked NOT NULL, we can skip recursing
7123 	 * to children, because their columns should already be marked NOT NULL as
7124 	 * well.  But there's no point in checking here unless the relation has
7125 	 * some children; else we can just wait till execution to check.  (If it
7126 	 * does have children, however, this can save taking per-child locks
7127 	 * unnecessarily.  This greatly improves concurrency in some parallel
7128 	 * restore scenarios.)
7129 	 *
7130 	 * Unfortunately, we can only apply this optimization to partitioned
7131 	 * tables, because traditional inheritance doesn't enforce that child
7132 	 * columns be NOT NULL when their parent is.  (That's a bug that should
7133 	 * get fixed someday.)
7134 	 */
7135 	if (rel->rd_rel->relhassubclass &&
7136 		rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
7137 	{
7138 		HeapTuple	tuple;
7139 		bool		attnotnull;
7140 
7141 		tuple = SearchSysCacheAttName(RelationGetRelid(rel), cmd->name);
7142 
7143 		/* Might as well throw the error now, if name is bad */
7144 		if (!HeapTupleIsValid(tuple))
7145 			ereport(ERROR,
7146 					(errcode(ERRCODE_UNDEFINED_COLUMN),
7147 					 errmsg("column \"%s\" of relation \"%s\" does not exist",
7148 							cmd->name, RelationGetRelationName(rel))));
7149 
7150 		attnotnull = ((Form_pg_attribute) GETSTRUCT(tuple))->attnotnull;
7151 		ReleaseSysCache(tuple);
7152 		if (attnotnull)
7153 			return;
7154 	}
7155 
7156 	/*
7157 	 * If we have ALTER TABLE ONLY ... SET NOT NULL on a partitioned table,
7158 	 * apply ALTER TABLE ... CHECK NOT NULL to every child.  Otherwise, use
7159 	 * normal recursion logic.
7160 	 */
7161 	if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE &&
7162 		!recurse)
7163 	{
7164 		AlterTableCmd *newcmd = makeNode(AlterTableCmd);
7165 
7166 		newcmd->subtype = AT_CheckNotNull;
7167 		newcmd->name = pstrdup(cmd->name);
7168 		ATSimpleRecursion(wqueue, rel, newcmd, true, lockmode, context);
7169 	}
7170 	else
7171 		ATSimpleRecursion(wqueue, rel, cmd, recurse, lockmode, context);
7172 }
7173 
7174 /*
7175  * Return the address of the modified column.  If the column was already NOT
7176  * NULL, InvalidObjectAddress is returned.
7177  */
7178 static ObjectAddress
ATExecSetNotNull(AlteredTableInfo * tab,Relation rel,const char * colName,LOCKMODE lockmode)7179 ATExecSetNotNull(AlteredTableInfo *tab, Relation rel,
7180 				 const char *colName, LOCKMODE lockmode)
7181 {
7182 	HeapTuple	tuple;
7183 	AttrNumber	attnum;
7184 	Relation	attr_rel;
7185 	ObjectAddress address;
7186 
7187 	/*
7188 	 * lookup the attribute
7189 	 */
7190 	attr_rel = table_open(AttributeRelationId, RowExclusiveLock);
7191 
7192 	tuple = SearchSysCacheCopyAttName(RelationGetRelid(rel), colName);
7193 
7194 	if (!HeapTupleIsValid(tuple))
7195 		ereport(ERROR,
7196 				(errcode(ERRCODE_UNDEFINED_COLUMN),
7197 				 errmsg("column \"%s\" of relation \"%s\" does not exist",
7198 						colName, RelationGetRelationName(rel))));
7199 
7200 	attnum = ((Form_pg_attribute) GETSTRUCT(tuple))->attnum;
7201 
7202 	/* Prevent them from altering a system attribute */
7203 	if (attnum <= 0)
7204 		ereport(ERROR,
7205 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
7206 				 errmsg("cannot alter system column \"%s\"",
7207 						colName)));
7208 
7209 	/*
7210 	 * Okay, actually perform the catalog change ... if needed
7211 	 */
7212 	if (!((Form_pg_attribute) GETSTRUCT(tuple))->attnotnull)
7213 	{
7214 		((Form_pg_attribute) GETSTRUCT(tuple))->attnotnull = true;
7215 
7216 		CatalogTupleUpdate(attr_rel, &tuple->t_self, tuple);
7217 
7218 		/*
7219 		 * Ordinarily phase 3 must ensure that no NULLs exist in columns that
7220 		 * are set NOT NULL; however, if we can find a constraint which proves
7221 		 * this then we can skip that.  We needn't bother looking if we've
7222 		 * already found that we must verify some other NOT NULL constraint.
7223 		 */
7224 		if (!tab->verify_new_notnull &&
7225 			!NotNullImpliedByRelConstraints(rel, (Form_pg_attribute) GETSTRUCT(tuple)))
7226 		{
7227 			/* Tell Phase 3 it needs to test the constraint */
7228 			tab->verify_new_notnull = true;
7229 		}
7230 
7231 		ObjectAddressSubSet(address, RelationRelationId,
7232 							RelationGetRelid(rel), attnum);
7233 	}
7234 	else
7235 		address = InvalidObjectAddress;
7236 
7237 	InvokeObjectPostAlterHook(RelationRelationId,
7238 							  RelationGetRelid(rel), attnum);
7239 
7240 	table_close(attr_rel, RowExclusiveLock);
7241 
7242 	return address;
7243 }
7244 
7245 /*
7246  * ALTER TABLE ALTER COLUMN CHECK NOT NULL
7247  *
7248  * This doesn't exist in the grammar, but we generate AT_CheckNotNull
7249  * commands against the partitions of a partitioned table if the user
7250  * writes ALTER TABLE ONLY ... SET NOT NULL on the partitioned table,
7251  * or tries to create a primary key on it (which internally creates
7252  * AT_SetNotNull on the partitioned table).   Such a command doesn't
7253  * allow us to actually modify any partition, but we want to let it
7254  * go through if the partitions are already properly marked.
7255  *
7256  * In future, this might need to adjust the child table's state, likely
7257  * by incrementing an inheritance count for the attnotnull constraint.
7258  * For now we need only check for the presence of the flag.
7259  */
7260 static void
ATExecCheckNotNull(AlteredTableInfo * tab,Relation rel,const char * colName,LOCKMODE lockmode)7261 ATExecCheckNotNull(AlteredTableInfo *tab, Relation rel,
7262 				   const char *colName, LOCKMODE lockmode)
7263 {
7264 	HeapTuple	tuple;
7265 
7266 	tuple = SearchSysCacheAttName(RelationGetRelid(rel), colName);
7267 
7268 	if (!HeapTupleIsValid(tuple))
7269 		ereport(ERROR,
7270 				(errcode(ERRCODE_UNDEFINED_COLUMN),
7271 				 errmsg("column \"%s\" of relation \"%s\" does not exist",
7272 						colName, RelationGetRelationName(rel))));
7273 
7274 	if (!((Form_pg_attribute) GETSTRUCT(tuple))->attnotnull)
7275 		ereport(ERROR,
7276 				(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
7277 				 errmsg("constraint must be added to child tables too"),
7278 				 errdetail("Column \"%s\" of relation \"%s\" is not already NOT NULL.",
7279 						   colName, RelationGetRelationName(rel)),
7280 				 errhint("Do not specify the ONLY keyword.")));
7281 
7282 	ReleaseSysCache(tuple);
7283 }
7284 
7285 /*
7286  * NotNullImpliedByRelConstraints
7287  *		Does rel's existing constraints imply NOT NULL for the given attribute?
7288  */
7289 static bool
NotNullImpliedByRelConstraints(Relation rel,Form_pg_attribute attr)7290 NotNullImpliedByRelConstraints(Relation rel, Form_pg_attribute attr)
7291 {
7292 	NullTest   *nnulltest = makeNode(NullTest);
7293 
7294 	nnulltest->arg = (Expr *) makeVar(1,
7295 									  attr->attnum,
7296 									  attr->atttypid,
7297 									  attr->atttypmod,
7298 									  attr->attcollation,
7299 									  0);
7300 	nnulltest->nulltesttype = IS_NOT_NULL;
7301 
7302 	/*
7303 	 * argisrow = false is correct even for a composite column, because
7304 	 * attnotnull does not represent a SQL-spec IS NOT NULL test in such a
7305 	 * case, just IS DISTINCT FROM NULL.
7306 	 */
7307 	nnulltest->argisrow = false;
7308 	nnulltest->location = -1;
7309 
7310 	if (ConstraintImpliedByRelConstraint(rel, list_make1(nnulltest), NIL))
7311 	{
7312 		ereport(DEBUG1,
7313 				(errmsg_internal("existing constraints on column \"%s.%s\" are sufficient to prove that it does not contain nulls",
7314 								 RelationGetRelationName(rel), NameStr(attr->attname))));
7315 		return true;
7316 	}
7317 
7318 	return false;
7319 }
7320 
7321 /*
7322  * ALTER TABLE ALTER COLUMN SET/DROP DEFAULT
7323  *
7324  * Return the address of the affected column.
7325  */
7326 static ObjectAddress
ATExecColumnDefault(Relation rel,const char * colName,Node * newDefault,LOCKMODE lockmode)7327 ATExecColumnDefault(Relation rel, const char *colName,
7328 					Node *newDefault, LOCKMODE lockmode)
7329 {
7330 	TupleDesc	tupdesc = RelationGetDescr(rel);
7331 	AttrNumber	attnum;
7332 	ObjectAddress address;
7333 
7334 	/*
7335 	 * get the number of the attribute
7336 	 */
7337 	attnum = get_attnum(RelationGetRelid(rel), colName);
7338 	if (attnum == InvalidAttrNumber)
7339 		ereport(ERROR,
7340 				(errcode(ERRCODE_UNDEFINED_COLUMN),
7341 				 errmsg("column \"%s\" of relation \"%s\" does not exist",
7342 						colName, RelationGetRelationName(rel))));
7343 
7344 	/* Prevent them from altering a system attribute */
7345 	if (attnum <= 0)
7346 		ereport(ERROR,
7347 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
7348 				 errmsg("cannot alter system column \"%s\"",
7349 						colName)));
7350 
7351 	if (TupleDescAttr(tupdesc, attnum - 1)->attidentity)
7352 		ereport(ERROR,
7353 				(errcode(ERRCODE_SYNTAX_ERROR),
7354 				 errmsg("column \"%s\" of relation \"%s\" is an identity column",
7355 						colName, RelationGetRelationName(rel)),
7356 				 newDefault ? 0 : errhint("Use ALTER TABLE ... ALTER COLUMN ... DROP IDENTITY instead.")));
7357 
7358 	if (TupleDescAttr(tupdesc, attnum - 1)->attgenerated)
7359 		ereport(ERROR,
7360 				(errcode(ERRCODE_SYNTAX_ERROR),
7361 				 errmsg("column \"%s\" of relation \"%s\" is a generated column",
7362 						colName, RelationGetRelationName(rel)),
7363 				 newDefault || TupleDescAttr(tupdesc, attnum - 1)->attgenerated != ATTRIBUTE_GENERATED_STORED ? 0 :
7364 				 errhint("Use ALTER TABLE ... ALTER COLUMN ... DROP EXPRESSION instead.")));
7365 
7366 	/*
7367 	 * Remove any old default for the column.  We use RESTRICT here for
7368 	 * safety, but at present we do not expect anything to depend on the
7369 	 * default.
7370 	 *
7371 	 * We treat removing the existing default as an internal operation when it
7372 	 * is preparatory to adding a new default, but as a user-initiated
7373 	 * operation when the user asked for a drop.
7374 	 */
7375 	RemoveAttrDefault(RelationGetRelid(rel), attnum, DROP_RESTRICT, false,
7376 					  newDefault == NULL ? false : true);
7377 
7378 	if (newDefault)
7379 	{
7380 		/* SET DEFAULT */
7381 		RawColumnDefault *rawEnt;
7382 
7383 		rawEnt = (RawColumnDefault *) palloc(sizeof(RawColumnDefault));
7384 		rawEnt->attnum = attnum;
7385 		rawEnt->raw_default = newDefault;
7386 		rawEnt->missingMode = false;
7387 		rawEnt->generated = '\0';
7388 
7389 		/*
7390 		 * This function is intended for CREATE TABLE, so it processes a
7391 		 * _list_ of defaults, but we just do one.
7392 		 */
7393 		AddRelationNewConstraints(rel, list_make1(rawEnt), NIL,
7394 								  false, true, false, NULL);
7395 	}
7396 
7397 	ObjectAddressSubSet(address, RelationRelationId,
7398 						RelationGetRelid(rel), attnum);
7399 	return address;
7400 }
7401 
7402 /*
7403  * Add a pre-cooked default expression.
7404  *
7405  * Return the address of the affected column.
7406  */
7407 static ObjectAddress
ATExecCookedColumnDefault(Relation rel,AttrNumber attnum,Node * newDefault)7408 ATExecCookedColumnDefault(Relation rel, AttrNumber attnum,
7409 						  Node *newDefault)
7410 {
7411 	ObjectAddress address;
7412 
7413 	/* We assume no checking is required */
7414 
7415 	/*
7416 	 * Remove any old default for the column.  We use RESTRICT here for
7417 	 * safety, but at present we do not expect anything to depend on the
7418 	 * default.  (In ordinary cases, there could not be a default in place
7419 	 * anyway, but it's possible when combining LIKE with inheritance.)
7420 	 */
7421 	RemoveAttrDefault(RelationGetRelid(rel), attnum, DROP_RESTRICT, false,
7422 					  true);
7423 
7424 	(void) StoreAttrDefault(rel, attnum, newDefault, true, false);
7425 
7426 	ObjectAddressSubSet(address, RelationRelationId,
7427 						RelationGetRelid(rel), attnum);
7428 	return address;
7429 }
7430 
7431 /*
7432  * ALTER TABLE ALTER COLUMN ADD IDENTITY
7433  *
7434  * Return the address of the affected column.
7435  */
7436 static ObjectAddress
ATExecAddIdentity(Relation rel,const char * colName,Node * def,LOCKMODE lockmode)7437 ATExecAddIdentity(Relation rel, const char *colName,
7438 				  Node *def, LOCKMODE lockmode)
7439 {
7440 	Relation	attrelation;
7441 	HeapTuple	tuple;
7442 	Form_pg_attribute attTup;
7443 	AttrNumber	attnum;
7444 	ObjectAddress address;
7445 	ColumnDef  *cdef = castNode(ColumnDef, def);
7446 
7447 	attrelation = table_open(AttributeRelationId, RowExclusiveLock);
7448 
7449 	tuple = SearchSysCacheCopyAttName(RelationGetRelid(rel), colName);
7450 	if (!HeapTupleIsValid(tuple))
7451 		ereport(ERROR,
7452 				(errcode(ERRCODE_UNDEFINED_COLUMN),
7453 				 errmsg("column \"%s\" of relation \"%s\" does not exist",
7454 						colName, RelationGetRelationName(rel))));
7455 	attTup = (Form_pg_attribute) GETSTRUCT(tuple);
7456 	attnum = attTup->attnum;
7457 
7458 	/* Can't alter a system attribute */
7459 	if (attnum <= 0)
7460 		ereport(ERROR,
7461 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
7462 				 errmsg("cannot alter system column \"%s\"",
7463 						colName)));
7464 
7465 	/*
7466 	 * Creating a column as identity implies NOT NULL, so adding the identity
7467 	 * to an existing column that is not NOT NULL would create a state that
7468 	 * cannot be reproduced without contortions.
7469 	 */
7470 	if (!attTup->attnotnull)
7471 		ereport(ERROR,
7472 				(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
7473 				 errmsg("column \"%s\" of relation \"%s\" must be declared NOT NULL before identity can be added",
7474 						colName, RelationGetRelationName(rel))));
7475 
7476 	if (attTup->attidentity)
7477 		ereport(ERROR,
7478 				(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
7479 				 errmsg("column \"%s\" of relation \"%s\" is already an identity column",
7480 						colName, RelationGetRelationName(rel))));
7481 
7482 	if (attTup->atthasdef)
7483 		ereport(ERROR,
7484 				(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
7485 				 errmsg("column \"%s\" of relation \"%s\" already has a default value",
7486 						colName, RelationGetRelationName(rel))));
7487 
7488 	attTup->attidentity = cdef->identity;
7489 	CatalogTupleUpdate(attrelation, &tuple->t_self, tuple);
7490 
7491 	InvokeObjectPostAlterHook(RelationRelationId,
7492 							  RelationGetRelid(rel),
7493 							  attTup->attnum);
7494 	ObjectAddressSubSet(address, RelationRelationId,
7495 						RelationGetRelid(rel), attnum);
7496 	heap_freetuple(tuple);
7497 
7498 	table_close(attrelation, RowExclusiveLock);
7499 
7500 	return address;
7501 }
7502 
7503 /*
7504  * ALTER TABLE ALTER COLUMN SET { GENERATED or sequence options }
7505  *
7506  * Return the address of the affected column.
7507  */
7508 static ObjectAddress
ATExecSetIdentity(Relation rel,const char * colName,Node * def,LOCKMODE lockmode)7509 ATExecSetIdentity(Relation rel, const char *colName, Node *def, LOCKMODE lockmode)
7510 {
7511 	ListCell   *option;
7512 	DefElem    *generatedEl = NULL;
7513 	HeapTuple	tuple;
7514 	Form_pg_attribute attTup;
7515 	AttrNumber	attnum;
7516 	Relation	attrelation;
7517 	ObjectAddress address;
7518 
7519 	foreach(option, castNode(List, def))
7520 	{
7521 		DefElem    *defel = lfirst_node(DefElem, option);
7522 
7523 		if (strcmp(defel->defname, "generated") == 0)
7524 		{
7525 			if (generatedEl)
7526 				ereport(ERROR,
7527 						(errcode(ERRCODE_SYNTAX_ERROR),
7528 						 errmsg("conflicting or redundant options")));
7529 			generatedEl = defel;
7530 		}
7531 		else
7532 			elog(ERROR, "option \"%s\" not recognized",
7533 				 defel->defname);
7534 	}
7535 
7536 	/*
7537 	 * Even if there is nothing to change here, we run all the checks.  There
7538 	 * will be a subsequent ALTER SEQUENCE that relies on everything being
7539 	 * there.
7540 	 */
7541 
7542 	attrelation = table_open(AttributeRelationId, RowExclusiveLock);
7543 	tuple = SearchSysCacheCopyAttName(RelationGetRelid(rel), colName);
7544 	if (!HeapTupleIsValid(tuple))
7545 		ereport(ERROR,
7546 				(errcode(ERRCODE_UNDEFINED_COLUMN),
7547 				 errmsg("column \"%s\" of relation \"%s\" does not exist",
7548 						colName, RelationGetRelationName(rel))));
7549 
7550 	attTup = (Form_pg_attribute) GETSTRUCT(tuple);
7551 	attnum = attTup->attnum;
7552 
7553 	if (attnum <= 0)
7554 		ereport(ERROR,
7555 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
7556 				 errmsg("cannot alter system column \"%s\"",
7557 						colName)));
7558 
7559 	if (!attTup->attidentity)
7560 		ereport(ERROR,
7561 				(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
7562 				 errmsg("column \"%s\" of relation \"%s\" is not an identity column",
7563 						colName, RelationGetRelationName(rel))));
7564 
7565 	if (generatedEl)
7566 	{
7567 		attTup->attidentity = defGetInt32(generatedEl);
7568 		CatalogTupleUpdate(attrelation, &tuple->t_self, tuple);
7569 
7570 		InvokeObjectPostAlterHook(RelationRelationId,
7571 								  RelationGetRelid(rel),
7572 								  attTup->attnum);
7573 		ObjectAddressSubSet(address, RelationRelationId,
7574 							RelationGetRelid(rel), attnum);
7575 	}
7576 	else
7577 		address = InvalidObjectAddress;
7578 
7579 	heap_freetuple(tuple);
7580 	table_close(attrelation, RowExclusiveLock);
7581 
7582 	return address;
7583 }
7584 
7585 /*
7586  * ALTER TABLE ALTER COLUMN DROP IDENTITY
7587  *
7588  * Return the address of the affected column.
7589  */
7590 static ObjectAddress
ATExecDropIdentity(Relation rel,const char * colName,bool missing_ok,LOCKMODE lockmode)7591 ATExecDropIdentity(Relation rel, const char *colName, bool missing_ok, LOCKMODE lockmode)
7592 {
7593 	HeapTuple	tuple;
7594 	Form_pg_attribute attTup;
7595 	AttrNumber	attnum;
7596 	Relation	attrelation;
7597 	ObjectAddress address;
7598 	Oid			seqid;
7599 	ObjectAddress seqaddress;
7600 
7601 	attrelation = table_open(AttributeRelationId, RowExclusiveLock);
7602 	tuple = SearchSysCacheCopyAttName(RelationGetRelid(rel), colName);
7603 	if (!HeapTupleIsValid(tuple))
7604 		ereport(ERROR,
7605 				(errcode(ERRCODE_UNDEFINED_COLUMN),
7606 				 errmsg("column \"%s\" of relation \"%s\" does not exist",
7607 						colName, RelationGetRelationName(rel))));
7608 
7609 	attTup = (Form_pg_attribute) GETSTRUCT(tuple);
7610 	attnum = attTup->attnum;
7611 
7612 	if (attnum <= 0)
7613 		ereport(ERROR,
7614 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
7615 				 errmsg("cannot alter system column \"%s\"",
7616 						colName)));
7617 
7618 	if (!attTup->attidentity)
7619 	{
7620 		if (!missing_ok)
7621 			ereport(ERROR,
7622 					(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
7623 					 errmsg("column \"%s\" of relation \"%s\" is not an identity column",
7624 							colName, RelationGetRelationName(rel))));
7625 		else
7626 		{
7627 			ereport(NOTICE,
7628 					(errmsg("column \"%s\" of relation \"%s\" is not an identity column, skipping",
7629 							colName, RelationGetRelationName(rel))));
7630 			heap_freetuple(tuple);
7631 			table_close(attrelation, RowExclusiveLock);
7632 			return InvalidObjectAddress;
7633 		}
7634 	}
7635 
7636 	attTup->attidentity = '\0';
7637 	CatalogTupleUpdate(attrelation, &tuple->t_self, tuple);
7638 
7639 	InvokeObjectPostAlterHook(RelationRelationId,
7640 							  RelationGetRelid(rel),
7641 							  attTup->attnum);
7642 	ObjectAddressSubSet(address, RelationRelationId,
7643 						RelationGetRelid(rel), attnum);
7644 	heap_freetuple(tuple);
7645 
7646 	table_close(attrelation, RowExclusiveLock);
7647 
7648 	/* drop the internal sequence */
7649 	seqid = getIdentitySequence(RelationGetRelid(rel), attnum, false);
7650 	deleteDependencyRecordsForClass(RelationRelationId, seqid,
7651 									RelationRelationId, DEPENDENCY_INTERNAL);
7652 	CommandCounterIncrement();
7653 	seqaddress.classId = RelationRelationId;
7654 	seqaddress.objectId = seqid;
7655 	seqaddress.objectSubId = 0;
7656 	performDeletion(&seqaddress, DROP_RESTRICT, PERFORM_DELETION_INTERNAL);
7657 
7658 	return address;
7659 }
7660 
7661 /*
7662  * ALTER TABLE ALTER COLUMN DROP EXPRESSION
7663  */
7664 static void
ATPrepDropExpression(Relation rel,AlterTableCmd * cmd,bool recurse,bool recursing,LOCKMODE lockmode)7665 ATPrepDropExpression(Relation rel, AlterTableCmd *cmd, bool recurse, bool recursing, LOCKMODE lockmode)
7666 {
7667 	/*
7668 	 * Reject ONLY if there are child tables.  We could implement this, but it
7669 	 * is a bit complicated.  GENERATED clauses must be attached to the column
7670 	 * definition and cannot be added later like DEFAULT, so if a child table
7671 	 * has a generation expression that the parent does not have, the child
7672 	 * column will necessarily be an attlocal column.  So to implement ONLY
7673 	 * here, we'd need extra code to update attislocal of the direct child
7674 	 * tables, somewhat similar to how DROP COLUMN does it, so that the
7675 	 * resulting state can be properly dumped and restored.
7676 	 */
7677 	if (!recurse &&
7678 		find_inheritance_children(RelationGetRelid(rel), lockmode))
7679 		ereport(ERROR,
7680 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
7681 				 errmsg("ALTER TABLE / DROP EXPRESSION must be applied to child tables too")));
7682 
7683 	/*
7684 	 * Cannot drop generation expression from inherited columns.
7685 	 */
7686 	if (!recursing)
7687 	{
7688 		HeapTuple	tuple;
7689 		Form_pg_attribute attTup;
7690 
7691 		tuple = SearchSysCacheCopyAttName(RelationGetRelid(rel), cmd->name);
7692 		if (!HeapTupleIsValid(tuple))
7693 			ereport(ERROR,
7694 					(errcode(ERRCODE_UNDEFINED_COLUMN),
7695 					 errmsg("column \"%s\" of relation \"%s\" does not exist",
7696 							cmd->name, RelationGetRelationName(rel))));
7697 
7698 		attTup = (Form_pg_attribute) GETSTRUCT(tuple);
7699 
7700 		if (attTup->attinhcount > 0)
7701 			ereport(ERROR,
7702 					(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
7703 					 errmsg("cannot drop generation expression from inherited column")));
7704 	}
7705 }
7706 
7707 /*
7708  * Return the address of the affected column.
7709  */
7710 static ObjectAddress
ATExecDropExpression(Relation rel,const char * colName,bool missing_ok,LOCKMODE lockmode)7711 ATExecDropExpression(Relation rel, const char *colName, bool missing_ok, LOCKMODE lockmode)
7712 {
7713 	HeapTuple	tuple;
7714 	Form_pg_attribute attTup;
7715 	AttrNumber	attnum;
7716 	Relation	attrelation;
7717 	ObjectAddress address;
7718 
7719 	attrelation = table_open(AttributeRelationId, RowExclusiveLock);
7720 	tuple = SearchSysCacheCopyAttName(RelationGetRelid(rel), colName);
7721 	if (!HeapTupleIsValid(tuple))
7722 		ereport(ERROR,
7723 				(errcode(ERRCODE_UNDEFINED_COLUMN),
7724 				 errmsg("column \"%s\" of relation \"%s\" does not exist",
7725 						colName, RelationGetRelationName(rel))));
7726 
7727 	attTup = (Form_pg_attribute) GETSTRUCT(tuple);
7728 	attnum = attTup->attnum;
7729 
7730 	if (attnum <= 0)
7731 		ereport(ERROR,
7732 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
7733 				 errmsg("cannot alter system column \"%s\"",
7734 						colName)));
7735 
7736 	if (attTup->attgenerated != ATTRIBUTE_GENERATED_STORED)
7737 	{
7738 		if (!missing_ok)
7739 			ereport(ERROR,
7740 					(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
7741 					 errmsg("column \"%s\" of relation \"%s\" is not a stored generated column",
7742 							colName, RelationGetRelationName(rel))));
7743 		else
7744 		{
7745 			ereport(NOTICE,
7746 					(errmsg("column \"%s\" of relation \"%s\" is not a stored generated column, skipping",
7747 							colName, RelationGetRelationName(rel))));
7748 			heap_freetuple(tuple);
7749 			table_close(attrelation, RowExclusiveLock);
7750 			return InvalidObjectAddress;
7751 		}
7752 	}
7753 
7754 	attTup->attgenerated = '\0';
7755 	CatalogTupleUpdate(attrelation, &tuple->t_self, tuple);
7756 
7757 	InvokeObjectPostAlterHook(RelationRelationId,
7758 							  RelationGetRelid(rel),
7759 							  attTup->attnum);
7760 	ObjectAddressSubSet(address, RelationRelationId,
7761 						RelationGetRelid(rel), attnum);
7762 	heap_freetuple(tuple);
7763 
7764 	table_close(attrelation, RowExclusiveLock);
7765 
7766 	CommandCounterIncrement();
7767 
7768 	RemoveAttrDefault(RelationGetRelid(rel), attnum, DROP_RESTRICT, false, false);
7769 
7770 	/*
7771 	 * Remove all dependencies of this (formerly generated) column on other
7772 	 * columns in the same table.  (See StoreAttrDefault() for which
7773 	 * dependencies are created.)  We don't expect there to be dependencies
7774 	 * between columns of the same table for other reasons, so it's okay to
7775 	 * remove all of them.
7776 	 */
7777 	{
7778 		Relation	depRel;
7779 		ScanKeyData key[3];
7780 		SysScanDesc scan;
7781 		HeapTuple	tup;
7782 
7783 		depRel = table_open(DependRelationId, RowExclusiveLock);
7784 
7785 		ScanKeyInit(&key[0],
7786 					Anum_pg_depend_classid,
7787 					BTEqualStrategyNumber, F_OIDEQ,
7788 					ObjectIdGetDatum(RelationRelationId));
7789 		ScanKeyInit(&key[1],
7790 					Anum_pg_depend_objid,
7791 					BTEqualStrategyNumber, F_OIDEQ,
7792 					ObjectIdGetDatum(RelationGetRelid(rel)));
7793 		ScanKeyInit(&key[2],
7794 					Anum_pg_depend_objsubid,
7795 					BTEqualStrategyNumber, F_INT4EQ,
7796 					Int32GetDatum(attnum));
7797 
7798 		scan = systable_beginscan(depRel, DependDependerIndexId, true,
7799 								  NULL, 3, key);
7800 
7801 		while (HeapTupleIsValid(tup = systable_getnext(scan)))
7802 		{
7803 			Form_pg_depend depform = (Form_pg_depend) GETSTRUCT(tup);
7804 
7805 			if (depform->refclassid == RelationRelationId &&
7806 				depform->refobjid == RelationGetRelid(rel) &&
7807 				depform->refobjsubid != 0 &&
7808 				depform->deptype == DEPENDENCY_AUTO)
7809 			{
7810 				CatalogTupleDelete(depRel, &tup->t_self);
7811 			}
7812 		}
7813 
7814 		systable_endscan(scan);
7815 
7816 		table_close(depRel, RowExclusiveLock);
7817 	}
7818 
7819 	return address;
7820 }
7821 
7822 /*
7823  * ALTER TABLE ALTER COLUMN SET STATISTICS
7824  *
7825  * Return value is the address of the modified column
7826  */
7827 static ObjectAddress
ATExecSetStatistics(Relation rel,const char * colName,int16 colNum,Node * newValue,LOCKMODE lockmode)7828 ATExecSetStatistics(Relation rel, const char *colName, int16 colNum, Node *newValue, LOCKMODE lockmode)
7829 {
7830 	int			newtarget;
7831 	Relation	attrelation;
7832 	HeapTuple	tuple;
7833 	Form_pg_attribute attrtuple;
7834 	AttrNumber	attnum;
7835 	ObjectAddress address;
7836 
7837 	/*
7838 	 * We allow referencing columns by numbers only for indexes, since table
7839 	 * column numbers could contain gaps if columns are later dropped.
7840 	 */
7841 	if (rel->rd_rel->relkind != RELKIND_INDEX &&
7842 		rel->rd_rel->relkind != RELKIND_PARTITIONED_INDEX &&
7843 		!colName)
7844 		ereport(ERROR,
7845 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
7846 				 errmsg("cannot refer to non-index column by number")));
7847 
7848 	Assert(IsA(newValue, Integer));
7849 	newtarget = intVal(newValue);
7850 
7851 	/*
7852 	 * Limit target to a sane range
7853 	 */
7854 	if (newtarget < -1)
7855 	{
7856 		ereport(ERROR,
7857 				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
7858 				 errmsg("statistics target %d is too low",
7859 						newtarget)));
7860 	}
7861 	else if (newtarget > 10000)
7862 	{
7863 		newtarget = 10000;
7864 		ereport(WARNING,
7865 				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
7866 				 errmsg("lowering statistics target to %d",
7867 						newtarget)));
7868 	}
7869 
7870 	attrelation = table_open(AttributeRelationId, RowExclusiveLock);
7871 
7872 	if (colName)
7873 	{
7874 		tuple = SearchSysCacheCopyAttName(RelationGetRelid(rel), colName);
7875 
7876 		if (!HeapTupleIsValid(tuple))
7877 			ereport(ERROR,
7878 					(errcode(ERRCODE_UNDEFINED_COLUMN),
7879 					 errmsg("column \"%s\" of relation \"%s\" does not exist",
7880 							colName, RelationGetRelationName(rel))));
7881 	}
7882 	else
7883 	{
7884 		tuple = SearchSysCacheCopyAttNum(RelationGetRelid(rel), colNum);
7885 
7886 		if (!HeapTupleIsValid(tuple))
7887 			ereport(ERROR,
7888 					(errcode(ERRCODE_UNDEFINED_COLUMN),
7889 					 errmsg("column number %d of relation \"%s\" does not exist",
7890 							colNum, RelationGetRelationName(rel))));
7891 	}
7892 
7893 	attrtuple = (Form_pg_attribute) GETSTRUCT(tuple);
7894 
7895 	attnum = attrtuple->attnum;
7896 	if (attnum <= 0)
7897 		ereport(ERROR,
7898 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
7899 				 errmsg("cannot alter system column \"%s\"",
7900 						colName)));
7901 
7902 	if (rel->rd_rel->relkind == RELKIND_INDEX ||
7903 		rel->rd_rel->relkind == RELKIND_PARTITIONED_INDEX)
7904 	{
7905 		if (attnum > rel->rd_index->indnkeyatts)
7906 			ereport(ERROR,
7907 					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
7908 					 errmsg("cannot alter statistics on included column \"%s\" of index \"%s\"",
7909 							NameStr(attrtuple->attname), RelationGetRelationName(rel))));
7910 		else if (rel->rd_index->indkey.values[attnum - 1] != 0)
7911 			ereport(ERROR,
7912 					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
7913 					 errmsg("cannot alter statistics on non-expression column \"%s\" of index \"%s\"",
7914 							NameStr(attrtuple->attname), RelationGetRelationName(rel)),
7915 					 errhint("Alter statistics on table column instead.")));
7916 	}
7917 
7918 	attrtuple->attstattarget = newtarget;
7919 
7920 	CatalogTupleUpdate(attrelation, &tuple->t_self, tuple);
7921 
7922 	InvokeObjectPostAlterHook(RelationRelationId,
7923 							  RelationGetRelid(rel),
7924 							  attrtuple->attnum);
7925 	ObjectAddressSubSet(address, RelationRelationId,
7926 						RelationGetRelid(rel), attnum);
7927 	heap_freetuple(tuple);
7928 
7929 	table_close(attrelation, RowExclusiveLock);
7930 
7931 	return address;
7932 }
7933 
7934 /*
7935  * Return value is the address of the modified column
7936  */
7937 static ObjectAddress
ATExecSetOptions(Relation rel,const char * colName,Node * options,bool isReset,LOCKMODE lockmode)7938 ATExecSetOptions(Relation rel, const char *colName, Node *options,
7939 				 bool isReset, LOCKMODE lockmode)
7940 {
7941 	Relation	attrelation;
7942 	HeapTuple	tuple,
7943 				newtuple;
7944 	Form_pg_attribute attrtuple;
7945 	AttrNumber	attnum;
7946 	Datum		datum,
7947 				newOptions;
7948 	bool		isnull;
7949 	ObjectAddress address;
7950 	Datum		repl_val[Natts_pg_attribute];
7951 	bool		repl_null[Natts_pg_attribute];
7952 	bool		repl_repl[Natts_pg_attribute];
7953 
7954 	attrelation = table_open(AttributeRelationId, RowExclusiveLock);
7955 
7956 	tuple = SearchSysCacheAttName(RelationGetRelid(rel), colName);
7957 
7958 	if (!HeapTupleIsValid(tuple))
7959 		ereport(ERROR,
7960 				(errcode(ERRCODE_UNDEFINED_COLUMN),
7961 				 errmsg("column \"%s\" of relation \"%s\" does not exist",
7962 						colName, RelationGetRelationName(rel))));
7963 	attrtuple = (Form_pg_attribute) GETSTRUCT(tuple);
7964 
7965 	attnum = attrtuple->attnum;
7966 	if (attnum <= 0)
7967 		ereport(ERROR,
7968 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
7969 				 errmsg("cannot alter system column \"%s\"",
7970 						colName)));
7971 
7972 	/* Generate new proposed attoptions (text array) */
7973 	datum = SysCacheGetAttr(ATTNAME, tuple, Anum_pg_attribute_attoptions,
7974 							&isnull);
7975 	newOptions = transformRelOptions(isnull ? (Datum) 0 : datum,
7976 									 castNode(List, options), NULL, NULL,
7977 									 false, isReset);
7978 	/* Validate new options */
7979 	(void) attribute_reloptions(newOptions, true);
7980 
7981 	/* Build new tuple. */
7982 	memset(repl_null, false, sizeof(repl_null));
7983 	memset(repl_repl, false, sizeof(repl_repl));
7984 	if (newOptions != (Datum) 0)
7985 		repl_val[Anum_pg_attribute_attoptions - 1] = newOptions;
7986 	else
7987 		repl_null[Anum_pg_attribute_attoptions - 1] = true;
7988 	repl_repl[Anum_pg_attribute_attoptions - 1] = true;
7989 	newtuple = heap_modify_tuple(tuple, RelationGetDescr(attrelation),
7990 								 repl_val, repl_null, repl_repl);
7991 
7992 	/* Update system catalog. */
7993 	CatalogTupleUpdate(attrelation, &newtuple->t_self, newtuple);
7994 
7995 	InvokeObjectPostAlterHook(RelationRelationId,
7996 							  RelationGetRelid(rel),
7997 							  attrtuple->attnum);
7998 	ObjectAddressSubSet(address, RelationRelationId,
7999 						RelationGetRelid(rel), attnum);
8000 
8001 	heap_freetuple(newtuple);
8002 
8003 	ReleaseSysCache(tuple);
8004 
8005 	table_close(attrelation, RowExclusiveLock);
8006 
8007 	return address;
8008 }
8009 
8010 /*
8011  * Helper function for ATExecSetStorage and ATExecSetCompression
8012  *
8013  * Set the attstorage and/or attcompression fields for index columns
8014  * associated with the specified table column.
8015  */
8016 static void
SetIndexStorageProperties(Relation rel,Relation attrelation,AttrNumber attnum,bool setstorage,char newstorage,bool setcompression,char newcompression,LOCKMODE lockmode)8017 SetIndexStorageProperties(Relation rel, Relation attrelation,
8018 						  AttrNumber attnum,
8019 						  bool setstorage, char newstorage,
8020 						  bool setcompression, char newcompression,
8021 						  LOCKMODE lockmode)
8022 {
8023 	ListCell   *lc;
8024 
8025 	foreach(lc, RelationGetIndexList(rel))
8026 	{
8027 		Oid			indexoid = lfirst_oid(lc);
8028 		Relation	indrel;
8029 		AttrNumber	indattnum = 0;
8030 		HeapTuple	tuple;
8031 
8032 		indrel = index_open(indexoid, lockmode);
8033 
8034 		for (int i = 0; i < indrel->rd_index->indnatts; i++)
8035 		{
8036 			if (indrel->rd_index->indkey.values[i] == attnum)
8037 			{
8038 				indattnum = i + 1;
8039 				break;
8040 			}
8041 		}
8042 
8043 		if (indattnum == 0)
8044 		{
8045 			index_close(indrel, lockmode);
8046 			continue;
8047 		}
8048 
8049 		tuple = SearchSysCacheCopyAttNum(RelationGetRelid(indrel), indattnum);
8050 
8051 		if (HeapTupleIsValid(tuple))
8052 		{
8053 			Form_pg_attribute attrtuple = (Form_pg_attribute) GETSTRUCT(tuple);
8054 
8055 			if (setstorage)
8056 				attrtuple->attstorage = newstorage;
8057 
8058 			if (setcompression)
8059 				attrtuple->attcompression = newcompression;
8060 
8061 			CatalogTupleUpdate(attrelation, &tuple->t_self, tuple);
8062 
8063 			InvokeObjectPostAlterHook(RelationRelationId,
8064 									  RelationGetRelid(rel),
8065 									  attrtuple->attnum);
8066 
8067 			heap_freetuple(tuple);
8068 		}
8069 
8070 		index_close(indrel, lockmode);
8071 	}
8072 }
8073 
8074 /*
8075  * ALTER TABLE ALTER COLUMN SET STORAGE
8076  *
8077  * Return value is the address of the modified column
8078  */
8079 static ObjectAddress
ATExecSetStorage(Relation rel,const char * colName,Node * newValue,LOCKMODE lockmode)8080 ATExecSetStorage(Relation rel, const char *colName, Node *newValue, LOCKMODE lockmode)
8081 {
8082 	char	   *storagemode;
8083 	char		newstorage;
8084 	Relation	attrelation;
8085 	HeapTuple	tuple;
8086 	Form_pg_attribute attrtuple;
8087 	AttrNumber	attnum;
8088 	ObjectAddress address;
8089 
8090 	Assert(IsA(newValue, String));
8091 	storagemode = strVal(newValue);
8092 
8093 	if (pg_strcasecmp(storagemode, "plain") == 0)
8094 		newstorage = TYPSTORAGE_PLAIN;
8095 	else if (pg_strcasecmp(storagemode, "external") == 0)
8096 		newstorage = TYPSTORAGE_EXTERNAL;
8097 	else if (pg_strcasecmp(storagemode, "extended") == 0)
8098 		newstorage = TYPSTORAGE_EXTENDED;
8099 	else if (pg_strcasecmp(storagemode, "main") == 0)
8100 		newstorage = TYPSTORAGE_MAIN;
8101 	else
8102 	{
8103 		ereport(ERROR,
8104 				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
8105 				 errmsg("invalid storage type \"%s\"",
8106 						storagemode)));
8107 		newstorage = 0;			/* keep compiler quiet */
8108 	}
8109 
8110 	attrelation = table_open(AttributeRelationId, RowExclusiveLock);
8111 
8112 	tuple = SearchSysCacheCopyAttName(RelationGetRelid(rel), colName);
8113 
8114 	if (!HeapTupleIsValid(tuple))
8115 		ereport(ERROR,
8116 				(errcode(ERRCODE_UNDEFINED_COLUMN),
8117 				 errmsg("column \"%s\" of relation \"%s\" does not exist",
8118 						colName, RelationGetRelationName(rel))));
8119 	attrtuple = (Form_pg_attribute) GETSTRUCT(tuple);
8120 
8121 	attnum = attrtuple->attnum;
8122 	if (attnum <= 0)
8123 		ereport(ERROR,
8124 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
8125 				 errmsg("cannot alter system column \"%s\"",
8126 						colName)));
8127 
8128 	/*
8129 	 * safety check: do not allow toasted storage modes unless column datatype
8130 	 * is TOAST-aware.
8131 	 */
8132 	if (newstorage == TYPSTORAGE_PLAIN || TypeIsToastable(attrtuple->atttypid))
8133 		attrtuple->attstorage = newstorage;
8134 	else
8135 		ereport(ERROR,
8136 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
8137 				 errmsg("column data type %s can only have storage PLAIN",
8138 						format_type_be(attrtuple->atttypid))));
8139 
8140 	CatalogTupleUpdate(attrelation, &tuple->t_self, tuple);
8141 
8142 	InvokeObjectPostAlterHook(RelationRelationId,
8143 							  RelationGetRelid(rel),
8144 							  attrtuple->attnum);
8145 
8146 	heap_freetuple(tuple);
8147 
8148 	/*
8149 	 * Apply the change to indexes as well (only for simple index columns,
8150 	 * matching behavior of index.c ConstructTupleDescriptor()).
8151 	 */
8152 	SetIndexStorageProperties(rel, attrelation, attnum,
8153 							  true, newstorage,
8154 							  false, 0,
8155 							  lockmode);
8156 
8157 	table_close(attrelation, RowExclusiveLock);
8158 
8159 	ObjectAddressSubSet(address, RelationRelationId,
8160 						RelationGetRelid(rel), attnum);
8161 	return address;
8162 }
8163 
8164 
8165 /*
8166  * ALTER TABLE DROP COLUMN
8167  *
8168  * DROP COLUMN cannot use the normal ALTER TABLE recursion mechanism,
8169  * because we have to decide at runtime whether to recurse or not depending
8170  * on whether attinhcount goes to zero or not.  (We can't check this in a
8171  * static pre-pass because it won't handle multiple inheritance situations
8172  * correctly.)
8173  */
8174 static void
ATPrepDropColumn(List ** wqueue,Relation rel,bool recurse,bool recursing,AlterTableCmd * cmd,LOCKMODE lockmode,AlterTableUtilityContext * context)8175 ATPrepDropColumn(List **wqueue, Relation rel, bool recurse, bool recursing,
8176 				 AlterTableCmd *cmd, LOCKMODE lockmode,
8177 				 AlterTableUtilityContext *context)
8178 {
8179 	if (rel->rd_rel->reloftype && !recursing)
8180 		ereport(ERROR,
8181 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
8182 				 errmsg("cannot drop column from typed table")));
8183 
8184 	if (rel->rd_rel->relkind == RELKIND_COMPOSITE_TYPE)
8185 		ATTypedTableRecursion(wqueue, rel, cmd, lockmode, context);
8186 
8187 	if (recurse)
8188 		cmd->subtype = AT_DropColumnRecurse;
8189 }
8190 
8191 /*
8192  * Drops column 'colName' from relation 'rel' and returns the address of the
8193  * dropped column.  The column is also dropped (or marked as no longer
8194  * inherited from relation) from the relation's inheritance children, if any.
8195  *
8196  * In the recursive invocations for inheritance child relations, instead of
8197  * dropping the column directly (if to be dropped at all), its object address
8198  * is added to 'addrs', which must be non-NULL in such invocations.  All
8199  * columns are dropped at the same time after all the children have been
8200  * checked recursively.
8201  */
8202 static ObjectAddress
ATExecDropColumn(List ** wqueue,Relation rel,const char * colName,DropBehavior behavior,bool recurse,bool recursing,bool missing_ok,LOCKMODE lockmode,ObjectAddresses * addrs)8203 ATExecDropColumn(List **wqueue, Relation rel, const char *colName,
8204 				 DropBehavior behavior,
8205 				 bool recurse, bool recursing,
8206 				 bool missing_ok, LOCKMODE lockmode,
8207 				 ObjectAddresses *addrs)
8208 {
8209 	HeapTuple	tuple;
8210 	Form_pg_attribute targetatt;
8211 	AttrNumber	attnum;
8212 	List	   *children;
8213 	ObjectAddress object;
8214 	bool		is_expr;
8215 
8216 	/* At top level, permission check was done in ATPrepCmd, else do it */
8217 	if (recursing)
8218 		ATSimplePermissions(rel, ATT_TABLE | ATT_FOREIGN_TABLE);
8219 
8220 	/* Initialize addrs on the first invocation */
8221 	Assert(!recursing || addrs != NULL);
8222 	if (!recursing)
8223 		addrs = new_object_addresses();
8224 
8225 	/*
8226 	 * get the number of the attribute
8227 	 */
8228 	tuple = SearchSysCacheAttName(RelationGetRelid(rel), colName);
8229 	if (!HeapTupleIsValid(tuple))
8230 	{
8231 		if (!missing_ok)
8232 		{
8233 			ereport(ERROR,
8234 					(errcode(ERRCODE_UNDEFINED_COLUMN),
8235 					 errmsg("column \"%s\" of relation \"%s\" does not exist",
8236 							colName, RelationGetRelationName(rel))));
8237 		}
8238 		else
8239 		{
8240 			ereport(NOTICE,
8241 					(errmsg("column \"%s\" of relation \"%s\" does not exist, skipping",
8242 							colName, RelationGetRelationName(rel))));
8243 			return InvalidObjectAddress;
8244 		}
8245 	}
8246 	targetatt = (Form_pg_attribute) GETSTRUCT(tuple);
8247 
8248 	attnum = targetatt->attnum;
8249 
8250 	/* Can't drop a system attribute */
8251 	if (attnum <= 0)
8252 		ereport(ERROR,
8253 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
8254 				 errmsg("cannot drop system column \"%s\"",
8255 						colName)));
8256 
8257 	/*
8258 	 * Don't drop inherited columns, unless recursing (presumably from a drop
8259 	 * of the parent column)
8260 	 */
8261 	if (targetatt->attinhcount > 0 && !recursing)
8262 		ereport(ERROR,
8263 				(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
8264 				 errmsg("cannot drop inherited column \"%s\"",
8265 						colName)));
8266 
8267 	/*
8268 	 * Don't drop columns used in the partition key, either.  (If we let this
8269 	 * go through, the key column's dependencies would cause a cascaded drop
8270 	 * of the whole table, which is surely not what the user expected.)
8271 	 */
8272 	if (has_partition_attrs(rel,
8273 							bms_make_singleton(attnum - FirstLowInvalidHeapAttributeNumber),
8274 							&is_expr))
8275 		ereport(ERROR,
8276 				(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
8277 				 errmsg("cannot drop column \"%s\" because it is part of the partition key of relation \"%s\"",
8278 						colName, RelationGetRelationName(rel))));
8279 
8280 	ReleaseSysCache(tuple);
8281 
8282 	/*
8283 	 * Propagate to children as appropriate.  Unlike most other ALTER
8284 	 * routines, we have to do this one level of recursion at a time; we can't
8285 	 * use find_all_inheritors to do it in one pass.
8286 	 */
8287 	children =
8288 		find_inheritance_children(RelationGetRelid(rel), lockmode);
8289 
8290 	if (children)
8291 	{
8292 		Relation	attr_rel;
8293 		ListCell   *child;
8294 
8295 		/*
8296 		 * In case of a partitioned table, the column must be dropped from the
8297 		 * partitions as well.
8298 		 */
8299 		if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE && !recurse)
8300 			ereport(ERROR,
8301 					(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
8302 					 errmsg("cannot drop column from only the partitioned table when partitions exist"),
8303 					 errhint("Do not specify the ONLY keyword.")));
8304 
8305 		attr_rel = table_open(AttributeRelationId, RowExclusiveLock);
8306 		foreach(child, children)
8307 		{
8308 			Oid			childrelid = lfirst_oid(child);
8309 			Relation	childrel;
8310 			Form_pg_attribute childatt;
8311 
8312 			/* find_inheritance_children already got lock */
8313 			childrel = table_open(childrelid, NoLock);
8314 			CheckTableNotInUse(childrel, "ALTER TABLE");
8315 
8316 			tuple = SearchSysCacheCopyAttName(childrelid, colName);
8317 			if (!HeapTupleIsValid(tuple))	/* shouldn't happen */
8318 				elog(ERROR, "cache lookup failed for attribute \"%s\" of relation %u",
8319 					 colName, childrelid);
8320 			childatt = (Form_pg_attribute) GETSTRUCT(tuple);
8321 
8322 			if (childatt->attinhcount <= 0) /* shouldn't happen */
8323 				elog(ERROR, "relation %u has non-inherited attribute \"%s\"",
8324 					 childrelid, colName);
8325 
8326 			if (recurse)
8327 			{
8328 				/*
8329 				 * If the child column has other definition sources, just
8330 				 * decrement its inheritance count; if not, recurse to delete
8331 				 * it.
8332 				 */
8333 				if (childatt->attinhcount == 1 && !childatt->attislocal)
8334 				{
8335 					/* Time to delete this child column, too */
8336 					ATExecDropColumn(wqueue, childrel, colName,
8337 									 behavior, true, true,
8338 									 false, lockmode, addrs);
8339 				}
8340 				else
8341 				{
8342 					/* Child column must survive my deletion */
8343 					childatt->attinhcount--;
8344 
8345 					CatalogTupleUpdate(attr_rel, &tuple->t_self, tuple);
8346 
8347 					/* Make update visible */
8348 					CommandCounterIncrement();
8349 				}
8350 			}
8351 			else
8352 			{
8353 				/*
8354 				 * If we were told to drop ONLY in this table (no recursion),
8355 				 * we need to mark the inheritors' attributes as locally
8356 				 * defined rather than inherited.
8357 				 */
8358 				childatt->attinhcount--;
8359 				childatt->attislocal = true;
8360 
8361 				CatalogTupleUpdate(attr_rel, &tuple->t_self, tuple);
8362 
8363 				/* Make update visible */
8364 				CommandCounterIncrement();
8365 			}
8366 
8367 			heap_freetuple(tuple);
8368 
8369 			table_close(childrel, NoLock);
8370 		}
8371 		table_close(attr_rel, RowExclusiveLock);
8372 	}
8373 
8374 	/* Add object to delete */
8375 	object.classId = RelationRelationId;
8376 	object.objectId = RelationGetRelid(rel);
8377 	object.objectSubId = attnum;
8378 	add_exact_object_address(&object, addrs);
8379 
8380 	if (!recursing)
8381 	{
8382 		/* Recursion has ended, drop everything that was collected */
8383 		performMultipleDeletions(addrs, behavior, 0);
8384 		free_object_addresses(addrs);
8385 	}
8386 
8387 	return object;
8388 }
8389 
8390 /*
8391  * ALTER TABLE ADD INDEX
8392  *
8393  * There is no such command in the grammar, but parse_utilcmd.c converts
8394  * UNIQUE and PRIMARY KEY constraints into AT_AddIndex subcommands.  This lets
8395  * us schedule creation of the index at the appropriate time during ALTER.
8396  *
8397  * Return value is the address of the new index.
8398  */
8399 static ObjectAddress
ATExecAddIndex(AlteredTableInfo * tab,Relation rel,IndexStmt * stmt,bool is_rebuild,LOCKMODE lockmode)8400 ATExecAddIndex(AlteredTableInfo *tab, Relation rel,
8401 			   IndexStmt *stmt, bool is_rebuild, LOCKMODE lockmode)
8402 {
8403 	bool		check_rights;
8404 	bool		skip_build;
8405 	bool		quiet;
8406 	ObjectAddress address;
8407 
8408 	Assert(IsA(stmt, IndexStmt));
8409 	Assert(!stmt->concurrent);
8410 
8411 	/* The IndexStmt has already been through transformIndexStmt */
8412 	Assert(stmt->transformed);
8413 
8414 	/* suppress schema rights check when rebuilding existing index */
8415 	check_rights = !is_rebuild;
8416 	/* skip index build if phase 3 will do it or we're reusing an old one */
8417 	skip_build = tab->rewrite > 0 || OidIsValid(stmt->oldNode);
8418 	/* suppress notices when rebuilding existing index */
8419 	quiet = is_rebuild;
8420 
8421 	address = DefineIndex(RelationGetRelid(rel),
8422 						  stmt,
8423 						  InvalidOid,	/* no predefined OID */
8424 						  InvalidOid,	/* no parent index */
8425 						  InvalidOid,	/* no parent constraint */
8426 						  true, /* is_alter_table */
8427 						  check_rights,
8428 						  false,	/* check_not_in_use - we did it already */
8429 						  skip_build,
8430 						  quiet);
8431 
8432 	/*
8433 	 * If TryReuseIndex() stashed a relfilenode for us, we used it for the new
8434 	 * index instead of building from scratch.  Restore associated fields.
8435 	 * This may store InvalidSubTransactionId in both fields, in which case
8436 	 * relcache.c will assume it can rebuild the relcache entry.  Hence, do
8437 	 * this after the CCI that made catalog rows visible to any rebuild.  The
8438 	 * DROP of the old edition of this index will have scheduled the storage
8439 	 * for deletion at commit, so cancel that pending deletion.
8440 	 */
8441 	if (OidIsValid(stmt->oldNode))
8442 	{
8443 		Relation	irel = index_open(address.objectId, NoLock);
8444 
8445 		irel->rd_createSubid = stmt->oldCreateSubid;
8446 		irel->rd_firstRelfilenodeSubid = stmt->oldFirstRelfilenodeSubid;
8447 		RelationPreserveStorage(irel->rd_node, true);
8448 		index_close(irel, NoLock);
8449 	}
8450 
8451 	return address;
8452 }
8453 
8454 /*
8455  * ALTER TABLE ADD STATISTICS
8456  *
8457  * This is no such command in the grammar, but we use this internally to add
8458  * AT_ReAddStatistics subcommands to rebuild extended statistics after a table
8459  * column type change.
8460  */
8461 static ObjectAddress
ATExecAddStatistics(AlteredTableInfo * tab,Relation rel,CreateStatsStmt * stmt,bool is_rebuild,LOCKMODE lockmode)8462 ATExecAddStatistics(AlteredTableInfo *tab, Relation rel,
8463 					CreateStatsStmt *stmt, bool is_rebuild, LOCKMODE lockmode)
8464 {
8465 	ObjectAddress address;
8466 
8467 	Assert(IsA(stmt, CreateStatsStmt));
8468 
8469 	/* The CreateStatsStmt has already been through transformStatsStmt */
8470 	Assert(stmt->transformed);
8471 
8472 	address = CreateStatistics(stmt);
8473 
8474 	return address;
8475 }
8476 
8477 /*
8478  * ALTER TABLE ADD CONSTRAINT USING INDEX
8479  *
8480  * Returns the address of the new constraint.
8481  */
8482 static ObjectAddress
ATExecAddIndexConstraint(AlteredTableInfo * tab,Relation rel,IndexStmt * stmt,LOCKMODE lockmode)8483 ATExecAddIndexConstraint(AlteredTableInfo *tab, Relation rel,
8484 						 IndexStmt *stmt, LOCKMODE lockmode)
8485 {
8486 	Oid			index_oid = stmt->indexOid;
8487 	Relation	indexRel;
8488 	char	   *indexName;
8489 	IndexInfo  *indexInfo;
8490 	char	   *constraintName;
8491 	char		constraintType;
8492 	ObjectAddress address;
8493 	bits16		flags;
8494 
8495 	Assert(IsA(stmt, IndexStmt));
8496 	Assert(OidIsValid(index_oid));
8497 	Assert(stmt->isconstraint);
8498 
8499 	/*
8500 	 * Doing this on partitioned tables is not a simple feature to implement,
8501 	 * so let's punt for now.
8502 	 */
8503 	if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
8504 		ereport(ERROR,
8505 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
8506 				 errmsg("ALTER TABLE / ADD CONSTRAINT USING INDEX is not supported on partitioned tables")));
8507 
8508 	indexRel = index_open(index_oid, AccessShareLock);
8509 
8510 	indexName = pstrdup(RelationGetRelationName(indexRel));
8511 
8512 	indexInfo = BuildIndexInfo(indexRel);
8513 
8514 	/* this should have been checked at parse time */
8515 	if (!indexInfo->ii_Unique)
8516 		elog(ERROR, "index \"%s\" is not unique", indexName);
8517 
8518 	/*
8519 	 * Determine name to assign to constraint.  We require a constraint to
8520 	 * have the same name as the underlying index; therefore, use the index's
8521 	 * existing name as the default constraint name, and if the user
8522 	 * explicitly gives some other name for the constraint, rename the index
8523 	 * to match.
8524 	 */
8525 	constraintName = stmt->idxname;
8526 	if (constraintName == NULL)
8527 		constraintName = indexName;
8528 	else if (strcmp(constraintName, indexName) != 0)
8529 	{
8530 		ereport(NOTICE,
8531 				(errmsg("ALTER TABLE / ADD CONSTRAINT USING INDEX will rename index \"%s\" to \"%s\"",
8532 						indexName, constraintName)));
8533 		RenameRelationInternal(index_oid, constraintName, false, true);
8534 	}
8535 
8536 	/* Extra checks needed if making primary key */
8537 	if (stmt->primary)
8538 		index_check_primary_key(rel, indexInfo, true, stmt);
8539 
8540 	/* Note we currently don't support EXCLUSION constraints here */
8541 	if (stmt->primary)
8542 		constraintType = CONSTRAINT_PRIMARY;
8543 	else
8544 		constraintType = CONSTRAINT_UNIQUE;
8545 
8546 	/* Create the catalog entries for the constraint */
8547 	flags = INDEX_CONSTR_CREATE_UPDATE_INDEX |
8548 		INDEX_CONSTR_CREATE_REMOVE_OLD_DEPS |
8549 		(stmt->initdeferred ? INDEX_CONSTR_CREATE_INIT_DEFERRED : 0) |
8550 		(stmt->deferrable ? INDEX_CONSTR_CREATE_DEFERRABLE : 0) |
8551 		(stmt->primary ? INDEX_CONSTR_CREATE_MARK_AS_PRIMARY : 0);
8552 
8553 	address = index_constraint_create(rel,
8554 									  index_oid,
8555 									  InvalidOid,
8556 									  indexInfo,
8557 									  constraintName,
8558 									  constraintType,
8559 									  flags,
8560 									  allowSystemTableMods,
8561 									  false);	/* is_internal */
8562 
8563 	index_close(indexRel, NoLock);
8564 
8565 	return address;
8566 }
8567 
8568 /*
8569  * ALTER TABLE ADD CONSTRAINT
8570  *
8571  * Return value is the address of the new constraint; if no constraint was
8572  * added, InvalidObjectAddress is returned.
8573  */
8574 static ObjectAddress
ATExecAddConstraint(List ** wqueue,AlteredTableInfo * tab,Relation rel,Constraint * newConstraint,bool recurse,bool is_readd,LOCKMODE lockmode)8575 ATExecAddConstraint(List **wqueue, AlteredTableInfo *tab, Relation rel,
8576 					Constraint *newConstraint, bool recurse, bool is_readd,
8577 					LOCKMODE lockmode)
8578 {
8579 	ObjectAddress address = InvalidObjectAddress;
8580 
8581 	Assert(IsA(newConstraint, Constraint));
8582 
8583 	/*
8584 	 * Currently, we only expect to see CONSTR_CHECK and CONSTR_FOREIGN nodes
8585 	 * arriving here (see the preprocessing done in parse_utilcmd.c).  Use a
8586 	 * switch anyway to make it easier to add more code later.
8587 	 */
8588 	switch (newConstraint->contype)
8589 	{
8590 		case CONSTR_CHECK:
8591 			address =
8592 				ATAddCheckConstraint(wqueue, tab, rel,
8593 									 newConstraint, recurse, false, is_readd,
8594 									 lockmode);
8595 			break;
8596 
8597 		case CONSTR_FOREIGN:
8598 
8599 			/*
8600 			 * Assign or validate constraint name
8601 			 */
8602 			if (newConstraint->conname)
8603 			{
8604 				if (ConstraintNameIsUsed(CONSTRAINT_RELATION,
8605 										 RelationGetRelid(rel),
8606 										 newConstraint->conname))
8607 					ereport(ERROR,
8608 							(errcode(ERRCODE_DUPLICATE_OBJECT),
8609 							 errmsg("constraint \"%s\" for relation \"%s\" already exists",
8610 									newConstraint->conname,
8611 									RelationGetRelationName(rel))));
8612 			}
8613 			else
8614 				newConstraint->conname =
8615 					ChooseConstraintName(RelationGetRelationName(rel),
8616 										 ChooseForeignKeyConstraintNameAddition(newConstraint->fk_attrs),
8617 										 "fkey",
8618 										 RelationGetNamespace(rel),
8619 										 NIL);
8620 
8621 			address = ATAddForeignKeyConstraint(wqueue, tab, rel,
8622 												newConstraint,
8623 												recurse, false,
8624 												lockmode);
8625 			break;
8626 
8627 		default:
8628 			elog(ERROR, "unrecognized constraint type: %d",
8629 				 (int) newConstraint->contype);
8630 	}
8631 
8632 	return address;
8633 }
8634 
8635 /*
8636  * Generate the column-name portion of the constraint name for a new foreign
8637  * key given the list of column names that reference the referenced
8638  * table.  This will be passed to ChooseConstraintName along with the parent
8639  * table name and the "fkey" suffix.
8640  *
8641  * We know that less than NAMEDATALEN characters will actually be used, so we
8642  * can truncate the result once we've generated that many.
8643  *
8644  * XXX see also ChooseExtendedStatisticNameAddition and
8645  * ChooseIndexNameAddition.
8646  */
8647 static char *
ChooseForeignKeyConstraintNameAddition(List * colnames)8648 ChooseForeignKeyConstraintNameAddition(List *colnames)
8649 {
8650 	char		buf[NAMEDATALEN * 2];
8651 	int			buflen = 0;
8652 	ListCell   *lc;
8653 
8654 	buf[0] = '\0';
8655 	foreach(lc, colnames)
8656 	{
8657 		const char *name = strVal(lfirst(lc));
8658 
8659 		if (buflen > 0)
8660 			buf[buflen++] = '_';	/* insert _ between names */
8661 
8662 		/*
8663 		 * At this point we have buflen <= NAMEDATALEN.  name should be less
8664 		 * than NAMEDATALEN already, but use strlcpy for paranoia.
8665 		 */
8666 		strlcpy(buf + buflen, name, NAMEDATALEN);
8667 		buflen += strlen(buf + buflen);
8668 		if (buflen >= NAMEDATALEN)
8669 			break;
8670 	}
8671 	return pstrdup(buf);
8672 }
8673 
8674 /*
8675  * Add a check constraint to a single table and its children.  Returns the
8676  * address of the constraint added to the parent relation, if one gets added,
8677  * or InvalidObjectAddress otherwise.
8678  *
8679  * Subroutine for ATExecAddConstraint.
8680  *
8681  * We must recurse to child tables during execution, rather than using
8682  * ALTER TABLE's normal prep-time recursion.  The reason is that all the
8683  * constraints *must* be given the same name, else they won't be seen as
8684  * related later.  If the user didn't explicitly specify a name, then
8685  * AddRelationNewConstraints would normally assign different names to the
8686  * child constraints.  To fix that, we must capture the name assigned at
8687  * the parent table and pass that down.
8688  */
8689 static ObjectAddress
ATAddCheckConstraint(List ** wqueue,AlteredTableInfo * tab,Relation rel,Constraint * constr,bool recurse,bool recursing,bool is_readd,LOCKMODE lockmode)8690 ATAddCheckConstraint(List **wqueue, AlteredTableInfo *tab, Relation rel,
8691 					 Constraint *constr, bool recurse, bool recursing,
8692 					 bool is_readd, LOCKMODE lockmode)
8693 {
8694 	List	   *newcons;
8695 	ListCell   *lcon;
8696 	List	   *children;
8697 	ListCell   *child;
8698 	ObjectAddress address = InvalidObjectAddress;
8699 
8700 	/* At top level, permission check was done in ATPrepCmd, else do it */
8701 	if (recursing)
8702 		ATSimplePermissions(rel, ATT_TABLE | ATT_FOREIGN_TABLE);
8703 
8704 	/*
8705 	 * Call AddRelationNewConstraints to do the work, making sure it works on
8706 	 * a copy of the Constraint so transformExpr can't modify the original. It
8707 	 * returns a list of cooked constraints.
8708 	 *
8709 	 * If the constraint ends up getting merged with a pre-existing one, it's
8710 	 * omitted from the returned list, which is what we want: we do not need
8711 	 * to do any validation work.  That can only happen at child tables,
8712 	 * though, since we disallow merging at the top level.
8713 	 */
8714 	newcons = AddRelationNewConstraints(rel, NIL,
8715 										list_make1(copyObject(constr)),
8716 										recursing | is_readd,	/* allow_merge */
8717 										!recursing, /* is_local */
8718 										is_readd,	/* is_internal */
8719 										NULL);	/* queryString not available
8720 												 * here */
8721 
8722 	/* we don't expect more than one constraint here */
8723 	Assert(list_length(newcons) <= 1);
8724 
8725 	/* Add each to-be-validated constraint to Phase 3's queue */
8726 	foreach(lcon, newcons)
8727 	{
8728 		CookedConstraint *ccon = (CookedConstraint *) lfirst(lcon);
8729 
8730 		if (!ccon->skip_validation)
8731 		{
8732 			NewConstraint *newcon;
8733 
8734 			newcon = (NewConstraint *) palloc0(sizeof(NewConstraint));
8735 			newcon->name = ccon->name;
8736 			newcon->contype = ccon->contype;
8737 			newcon->qual = ccon->expr;
8738 
8739 			tab->constraints = lappend(tab->constraints, newcon);
8740 		}
8741 
8742 		/* Save the actually assigned name if it was defaulted */
8743 		if (constr->conname == NULL)
8744 			constr->conname = ccon->name;
8745 
8746 		ObjectAddressSet(address, ConstraintRelationId, ccon->conoid);
8747 	}
8748 
8749 	/* At this point we must have a locked-down name to use */
8750 	Assert(constr->conname != NULL);
8751 
8752 	/* Advance command counter in case same table is visited multiple times */
8753 	CommandCounterIncrement();
8754 
8755 	/*
8756 	 * If the constraint got merged with an existing constraint, we're done.
8757 	 * We mustn't recurse to child tables in this case, because they've
8758 	 * already got the constraint, and visiting them again would lead to an
8759 	 * incorrect value for coninhcount.
8760 	 */
8761 	if (newcons == NIL)
8762 		return address;
8763 
8764 	/*
8765 	 * If adding a NO INHERIT constraint, no need to find our children.
8766 	 */
8767 	if (constr->is_no_inherit)
8768 		return address;
8769 
8770 	/*
8771 	 * Propagate to children as appropriate.  Unlike most other ALTER
8772 	 * routines, we have to do this one level of recursion at a time; we can't
8773 	 * use find_all_inheritors to do it in one pass.
8774 	 */
8775 	children =
8776 		find_inheritance_children(RelationGetRelid(rel), lockmode);
8777 
8778 	/*
8779 	 * Check if ONLY was specified with ALTER TABLE.  If so, allow the
8780 	 * constraint creation only if there are no children currently.  Error out
8781 	 * otherwise.
8782 	 */
8783 	if (!recurse && children != NIL)
8784 		ereport(ERROR,
8785 				(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
8786 				 errmsg("constraint must be added to child tables too")));
8787 
8788 	foreach(child, children)
8789 	{
8790 		Oid			childrelid = lfirst_oid(child);
8791 		Relation	childrel;
8792 		AlteredTableInfo *childtab;
8793 
8794 		/* find_inheritance_children already got lock */
8795 		childrel = table_open(childrelid, NoLock);
8796 		CheckTableNotInUse(childrel, "ALTER TABLE");
8797 
8798 		/* Find or create work queue entry for this table */
8799 		childtab = ATGetQueueEntry(wqueue, childrel);
8800 
8801 		/* Recurse to child */
8802 		ATAddCheckConstraint(wqueue, childtab, childrel,
8803 							 constr, recurse, true, is_readd, lockmode);
8804 
8805 		table_close(childrel, NoLock);
8806 	}
8807 
8808 	return address;
8809 }
8810 
8811 /*
8812  * Add a foreign-key constraint to a single table; return the new constraint's
8813  * address.
8814  *
8815  * Subroutine for ATExecAddConstraint.  Must already hold exclusive
8816  * lock on the rel, and have done appropriate validity checks for it.
8817  * We do permissions checks here, however.
8818  *
8819  * When the referenced or referencing tables (or both) are partitioned,
8820  * multiple pg_constraint rows are required -- one for each partitioned table
8821  * and each partition on each side (fortunately, not one for every combination
8822  * thereof).  We also need action triggers on each leaf partition on the
8823  * referenced side, and check triggers on each leaf partition on the
8824  * referencing side.
8825  */
8826 static ObjectAddress
ATAddForeignKeyConstraint(List ** wqueue,AlteredTableInfo * tab,Relation rel,Constraint * fkconstraint,bool recurse,bool recursing,LOCKMODE lockmode)8827 ATAddForeignKeyConstraint(List **wqueue, AlteredTableInfo *tab, Relation rel,
8828 						  Constraint *fkconstraint,
8829 						  bool recurse, bool recursing, LOCKMODE lockmode)
8830 {
8831 	Relation	pkrel;
8832 	int16		pkattnum[INDEX_MAX_KEYS];
8833 	int16		fkattnum[INDEX_MAX_KEYS];
8834 	Oid			pktypoid[INDEX_MAX_KEYS];
8835 	Oid			fktypoid[INDEX_MAX_KEYS];
8836 	Oid			opclasses[INDEX_MAX_KEYS];
8837 	Oid			pfeqoperators[INDEX_MAX_KEYS];
8838 	Oid			ppeqoperators[INDEX_MAX_KEYS];
8839 	Oid			ffeqoperators[INDEX_MAX_KEYS];
8840 	int			i;
8841 	int			numfks,
8842 				numpks;
8843 	Oid			indexOid;
8844 	bool		old_check_ok;
8845 	ObjectAddress address;
8846 	ListCell   *old_pfeqop_item = list_head(fkconstraint->old_conpfeqop);
8847 
8848 	/*
8849 	 * Grab ShareRowExclusiveLock on the pk table, so that someone doesn't
8850 	 * delete rows out from under us.
8851 	 */
8852 	if (OidIsValid(fkconstraint->old_pktable_oid))
8853 		pkrel = table_open(fkconstraint->old_pktable_oid, ShareRowExclusiveLock);
8854 	else
8855 		pkrel = table_openrv(fkconstraint->pktable, ShareRowExclusiveLock);
8856 
8857 	/*
8858 	 * Validity checks (permission checks wait till we have the column
8859 	 * numbers)
8860 	 */
8861 	if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
8862 	{
8863 		if (!recurse)
8864 			ereport(ERROR,
8865 					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
8866 					 errmsg("cannot use ONLY for foreign key on partitioned table \"%s\" referencing relation \"%s\"",
8867 							RelationGetRelationName(rel),
8868 							RelationGetRelationName(pkrel))));
8869 		if (fkconstraint->skip_validation && !fkconstraint->initially_valid)
8870 			ereport(ERROR,
8871 					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
8872 					 errmsg("cannot add NOT VALID foreign key on partitioned table \"%s\" referencing relation \"%s\"",
8873 							RelationGetRelationName(rel),
8874 							RelationGetRelationName(pkrel)),
8875 					 errdetail("This feature is not yet supported on partitioned tables.")));
8876 	}
8877 
8878 	if (pkrel->rd_rel->relkind != RELKIND_RELATION &&
8879 		pkrel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
8880 		ereport(ERROR,
8881 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
8882 				 errmsg("referenced relation \"%s\" is not a table",
8883 						RelationGetRelationName(pkrel))));
8884 
8885 	if (!allowSystemTableMods && IsSystemRelation(pkrel))
8886 		ereport(ERROR,
8887 				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
8888 				 errmsg("permission denied: \"%s\" is a system catalog",
8889 						RelationGetRelationName(pkrel))));
8890 
8891 	/*
8892 	 * References from permanent or unlogged tables to temp tables, and from
8893 	 * permanent tables to unlogged tables, are disallowed because the
8894 	 * referenced data can vanish out from under us.  References from temp
8895 	 * tables to any other table type are also disallowed, because other
8896 	 * backends might need to run the RI triggers on the perm table, but they
8897 	 * can't reliably see tuples in the local buffers of other backends.
8898 	 */
8899 	switch (rel->rd_rel->relpersistence)
8900 	{
8901 		case RELPERSISTENCE_PERMANENT:
8902 			if (!RelationIsPermanent(pkrel))
8903 				ereport(ERROR,
8904 						(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
8905 						 errmsg("constraints on permanent tables may reference only permanent tables")));
8906 			break;
8907 		case RELPERSISTENCE_UNLOGGED:
8908 			if (!RelationIsPermanent(pkrel)
8909 				&& pkrel->rd_rel->relpersistence != RELPERSISTENCE_UNLOGGED)
8910 				ereport(ERROR,
8911 						(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
8912 						 errmsg("constraints on unlogged tables may reference only permanent or unlogged tables")));
8913 			break;
8914 		case RELPERSISTENCE_TEMP:
8915 			if (pkrel->rd_rel->relpersistence != RELPERSISTENCE_TEMP)
8916 				ereport(ERROR,
8917 						(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
8918 						 errmsg("constraints on temporary tables may reference only temporary tables")));
8919 			if (!pkrel->rd_islocaltemp || !rel->rd_islocaltemp)
8920 				ereport(ERROR,
8921 						(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
8922 						 errmsg("constraints on temporary tables must involve temporary tables of this session")));
8923 			break;
8924 	}
8925 
8926 	/*
8927 	 * Look up the referencing attributes to make sure they exist, and record
8928 	 * their attnums and type OIDs.
8929 	 */
8930 	MemSet(pkattnum, 0, sizeof(pkattnum));
8931 	MemSet(fkattnum, 0, sizeof(fkattnum));
8932 	MemSet(pktypoid, 0, sizeof(pktypoid));
8933 	MemSet(fktypoid, 0, sizeof(fktypoid));
8934 	MemSet(opclasses, 0, sizeof(opclasses));
8935 	MemSet(pfeqoperators, 0, sizeof(pfeqoperators));
8936 	MemSet(ppeqoperators, 0, sizeof(ppeqoperators));
8937 	MemSet(ffeqoperators, 0, sizeof(ffeqoperators));
8938 
8939 	numfks = transformColumnNameList(RelationGetRelid(rel),
8940 									 fkconstraint->fk_attrs,
8941 									 fkattnum, fktypoid);
8942 
8943 	/*
8944 	 * If the attribute list for the referenced table was omitted, lookup the
8945 	 * definition of the primary key and use it.  Otherwise, validate the
8946 	 * supplied attribute list.  In either case, discover the index OID and
8947 	 * index opclasses, and the attnums and type OIDs of the attributes.
8948 	 */
8949 	if (fkconstraint->pk_attrs == NIL)
8950 	{
8951 		numpks = transformFkeyGetPrimaryKey(pkrel, &indexOid,
8952 											&fkconstraint->pk_attrs,
8953 											pkattnum, pktypoid,
8954 											opclasses);
8955 	}
8956 	else
8957 	{
8958 		numpks = transformColumnNameList(RelationGetRelid(pkrel),
8959 										 fkconstraint->pk_attrs,
8960 										 pkattnum, pktypoid);
8961 		/* Look for an index matching the column list */
8962 		indexOid = transformFkeyCheckAttrs(pkrel, numpks, pkattnum,
8963 										   opclasses);
8964 	}
8965 
8966 	/*
8967 	 * Now we can check permissions.
8968 	 */
8969 	checkFkeyPermissions(pkrel, pkattnum, numpks);
8970 
8971 	/*
8972 	 * Check some things for generated columns.
8973 	 */
8974 	for (i = 0; i < numfks; i++)
8975 	{
8976 		char		attgenerated = TupleDescAttr(RelationGetDescr(rel), fkattnum[i] - 1)->attgenerated;
8977 
8978 		if (attgenerated)
8979 		{
8980 			/*
8981 			 * Check restrictions on UPDATE/DELETE actions, per SQL standard
8982 			 */
8983 			if (fkconstraint->fk_upd_action == FKCONSTR_ACTION_SETNULL ||
8984 				fkconstraint->fk_upd_action == FKCONSTR_ACTION_SETDEFAULT ||
8985 				fkconstraint->fk_upd_action == FKCONSTR_ACTION_CASCADE)
8986 				ereport(ERROR,
8987 						(errcode(ERRCODE_SYNTAX_ERROR),
8988 						 errmsg("invalid %s action for foreign key constraint containing generated column",
8989 								"ON UPDATE")));
8990 			if (fkconstraint->fk_del_action == FKCONSTR_ACTION_SETNULL ||
8991 				fkconstraint->fk_del_action == FKCONSTR_ACTION_SETDEFAULT)
8992 				ereport(ERROR,
8993 						(errcode(ERRCODE_SYNTAX_ERROR),
8994 						 errmsg("invalid %s action for foreign key constraint containing generated column",
8995 								"ON DELETE")));
8996 		}
8997 	}
8998 
8999 	/*
9000 	 * Look up the equality operators to use in the constraint.
9001 	 *
9002 	 * Note that we have to be careful about the difference between the actual
9003 	 * PK column type and the opclass' declared input type, which might be
9004 	 * only binary-compatible with it.  The declared opcintype is the right
9005 	 * thing to probe pg_amop with.
9006 	 */
9007 	if (numfks != numpks)
9008 		ereport(ERROR,
9009 				(errcode(ERRCODE_INVALID_FOREIGN_KEY),
9010 				 errmsg("number of referencing and referenced columns for foreign key disagree")));
9011 
9012 	/*
9013 	 * On the strength of a previous constraint, we might avoid scanning
9014 	 * tables to validate this one.  See below.
9015 	 */
9016 	old_check_ok = (fkconstraint->old_conpfeqop != NIL);
9017 	Assert(!old_check_ok || numfks == list_length(fkconstraint->old_conpfeqop));
9018 
9019 	for (i = 0; i < numpks; i++)
9020 	{
9021 		Oid			pktype = pktypoid[i];
9022 		Oid			fktype = fktypoid[i];
9023 		Oid			fktyped;
9024 		HeapTuple	cla_ht;
9025 		Form_pg_opclass cla_tup;
9026 		Oid			amid;
9027 		Oid			opfamily;
9028 		Oid			opcintype;
9029 		Oid			pfeqop;
9030 		Oid			ppeqop;
9031 		Oid			ffeqop;
9032 		int16		eqstrategy;
9033 		Oid			pfeqop_right;
9034 
9035 		/* We need several fields out of the pg_opclass entry */
9036 		cla_ht = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclasses[i]));
9037 		if (!HeapTupleIsValid(cla_ht))
9038 			elog(ERROR, "cache lookup failed for opclass %u", opclasses[i]);
9039 		cla_tup = (Form_pg_opclass) GETSTRUCT(cla_ht);
9040 		amid = cla_tup->opcmethod;
9041 		opfamily = cla_tup->opcfamily;
9042 		opcintype = cla_tup->opcintype;
9043 		ReleaseSysCache(cla_ht);
9044 
9045 		/*
9046 		 * Check it's a btree; currently this can never fail since no other
9047 		 * index AMs support unique indexes.  If we ever did have other types
9048 		 * of unique indexes, we'd need a way to determine which operator
9049 		 * strategy number is equality.  (Is it reasonable to insist that
9050 		 * every such index AM use btree's number for equality?)
9051 		 */
9052 		if (amid != BTREE_AM_OID)
9053 			elog(ERROR, "only b-tree indexes are supported for foreign keys");
9054 		eqstrategy = BTEqualStrategyNumber;
9055 
9056 		/*
9057 		 * There had better be a primary equality operator for the index.
9058 		 * We'll use it for PK = PK comparisons.
9059 		 */
9060 		ppeqop = get_opfamily_member(opfamily, opcintype, opcintype,
9061 									 eqstrategy);
9062 
9063 		if (!OidIsValid(ppeqop))
9064 			elog(ERROR, "missing operator %d(%u,%u) in opfamily %u",
9065 				 eqstrategy, opcintype, opcintype, opfamily);
9066 
9067 		/*
9068 		 * Are there equality operators that take exactly the FK type? Assume
9069 		 * we should look through any domain here.
9070 		 */
9071 		fktyped = getBaseType(fktype);
9072 
9073 		pfeqop = get_opfamily_member(opfamily, opcintype, fktyped,
9074 									 eqstrategy);
9075 		if (OidIsValid(pfeqop))
9076 		{
9077 			pfeqop_right = fktyped;
9078 			ffeqop = get_opfamily_member(opfamily, fktyped, fktyped,
9079 										 eqstrategy);
9080 		}
9081 		else
9082 		{
9083 			/* keep compiler quiet */
9084 			pfeqop_right = InvalidOid;
9085 			ffeqop = InvalidOid;
9086 		}
9087 
9088 		if (!(OidIsValid(pfeqop) && OidIsValid(ffeqop)))
9089 		{
9090 			/*
9091 			 * Otherwise, look for an implicit cast from the FK type to the
9092 			 * opcintype, and if found, use the primary equality operator.
9093 			 * This is a bit tricky because opcintype might be a polymorphic
9094 			 * type such as ANYARRAY or ANYENUM; so what we have to test is
9095 			 * whether the two actual column types can be concurrently cast to
9096 			 * that type.  (Otherwise, we'd fail to reject combinations such
9097 			 * as int[] and point[].)
9098 			 */
9099 			Oid			input_typeids[2];
9100 			Oid			target_typeids[2];
9101 
9102 			input_typeids[0] = pktype;
9103 			input_typeids[1] = fktype;
9104 			target_typeids[0] = opcintype;
9105 			target_typeids[1] = opcintype;
9106 			if (can_coerce_type(2, input_typeids, target_typeids,
9107 								COERCION_IMPLICIT))
9108 			{
9109 				pfeqop = ffeqop = ppeqop;
9110 				pfeqop_right = opcintype;
9111 			}
9112 		}
9113 
9114 		if (!(OidIsValid(pfeqop) && OidIsValid(ffeqop)))
9115 			ereport(ERROR,
9116 					(errcode(ERRCODE_DATATYPE_MISMATCH),
9117 					 errmsg("foreign key constraint \"%s\" cannot be implemented",
9118 							fkconstraint->conname),
9119 					 errdetail("Key columns \"%s\" and \"%s\" "
9120 							   "are of incompatible types: %s and %s.",
9121 							   strVal(list_nth(fkconstraint->fk_attrs, i)),
9122 							   strVal(list_nth(fkconstraint->pk_attrs, i)),
9123 							   format_type_be(fktype),
9124 							   format_type_be(pktype))));
9125 
9126 		if (old_check_ok)
9127 		{
9128 			/*
9129 			 * When a pfeqop changes, revalidate the constraint.  We could
9130 			 * permit intra-opfamily changes, but that adds subtle complexity
9131 			 * without any concrete benefit for core types.  We need not
9132 			 * assess ppeqop or ffeqop, which RI_Initial_Check() does not use.
9133 			 */
9134 			old_check_ok = (pfeqop == lfirst_oid(old_pfeqop_item));
9135 			old_pfeqop_item = lnext(fkconstraint->old_conpfeqop,
9136 									old_pfeqop_item);
9137 		}
9138 		if (old_check_ok)
9139 		{
9140 			Oid			old_fktype;
9141 			Oid			new_fktype;
9142 			CoercionPathType old_pathtype;
9143 			CoercionPathType new_pathtype;
9144 			Oid			old_castfunc;
9145 			Oid			new_castfunc;
9146 			Form_pg_attribute attr = TupleDescAttr(tab->oldDesc,
9147 												   fkattnum[i] - 1);
9148 
9149 			/*
9150 			 * Identify coercion pathways from each of the old and new FK-side
9151 			 * column types to the right (foreign) operand type of the pfeqop.
9152 			 * We may assume that pg_constraint.conkey is not changing.
9153 			 */
9154 			old_fktype = attr->atttypid;
9155 			new_fktype = fktype;
9156 			old_pathtype = findFkeyCast(pfeqop_right, old_fktype,
9157 										&old_castfunc);
9158 			new_pathtype = findFkeyCast(pfeqop_right, new_fktype,
9159 										&new_castfunc);
9160 
9161 			/*
9162 			 * Upon a change to the cast from the FK column to its pfeqop
9163 			 * operand, revalidate the constraint.  For this evaluation, a
9164 			 * binary coercion cast is equivalent to no cast at all.  While
9165 			 * type implementors should design implicit casts with an eye
9166 			 * toward consistency of operations like equality, we cannot
9167 			 * assume here that they have done so.
9168 			 *
9169 			 * A function with a polymorphic argument could change behavior
9170 			 * arbitrarily in response to get_fn_expr_argtype().  Therefore,
9171 			 * when the cast destination is polymorphic, we only avoid
9172 			 * revalidation if the input type has not changed at all.  Given
9173 			 * just the core data types and operator classes, this requirement
9174 			 * prevents no would-be optimizations.
9175 			 *
9176 			 * If the cast converts from a base type to a domain thereon, then
9177 			 * that domain type must be the opcintype of the unique index.
9178 			 * Necessarily, the primary key column must then be of the domain
9179 			 * type.  Since the constraint was previously valid, all values on
9180 			 * the foreign side necessarily exist on the primary side and in
9181 			 * turn conform to the domain.  Consequently, we need not treat
9182 			 * domains specially here.
9183 			 *
9184 			 * Since we require that all collations share the same notion of
9185 			 * equality (which they do, because texteq reduces to bitwise
9186 			 * equality), we don't compare collation here.
9187 			 *
9188 			 * We need not directly consider the PK type.  It's necessarily
9189 			 * binary coercible to the opcintype of the unique index column,
9190 			 * and ri_triggers.c will only deal with PK datums in terms of
9191 			 * that opcintype.  Changing the opcintype also changes pfeqop.
9192 			 */
9193 			old_check_ok = (new_pathtype == old_pathtype &&
9194 							new_castfunc == old_castfunc &&
9195 							(!IsPolymorphicType(pfeqop_right) ||
9196 							 new_fktype == old_fktype));
9197 		}
9198 
9199 		pfeqoperators[i] = pfeqop;
9200 		ppeqoperators[i] = ppeqop;
9201 		ffeqoperators[i] = ffeqop;
9202 	}
9203 
9204 	/*
9205 	 * Create all the constraint and trigger objects, recursing to partitions
9206 	 * as necessary.  First handle the referenced side.
9207 	 */
9208 	address = addFkRecurseReferenced(wqueue, fkconstraint, rel, pkrel,
9209 									 indexOid,
9210 									 InvalidOid,	/* no parent constraint */
9211 									 numfks,
9212 									 pkattnum,
9213 									 fkattnum,
9214 									 pfeqoperators,
9215 									 ppeqoperators,
9216 									 ffeqoperators,
9217 									 old_check_ok);
9218 
9219 	/* Now handle the referencing side. */
9220 	addFkRecurseReferencing(wqueue, fkconstraint, rel, pkrel,
9221 							indexOid,
9222 							address.objectId,
9223 							numfks,
9224 							pkattnum,
9225 							fkattnum,
9226 							pfeqoperators,
9227 							ppeqoperators,
9228 							ffeqoperators,
9229 							old_check_ok,
9230 							lockmode);
9231 
9232 	/*
9233 	 * Done.  Close pk table, but keep lock until we've committed.
9234 	 */
9235 	table_close(pkrel, NoLock);
9236 
9237 	return address;
9238 }
9239 
9240 /*
9241  * addFkRecurseReferenced
9242  *		subroutine for ATAddForeignKeyConstraint; recurses on the referenced
9243  *		side of the constraint
9244  *
9245  * Create pg_constraint rows for the referenced side of the constraint,
9246  * referencing the parent of the referencing side; also create action triggers
9247  * on leaf partitions.  If the table is partitioned, recurse to handle each
9248  * partition.
9249  *
9250  * wqueue is the ALTER TABLE work queue; can be NULL when not running as part
9251  * of an ALTER TABLE sequence.
9252  * fkconstraint is the constraint being added.
9253  * rel is the root referencing relation.
9254  * pkrel is the referenced relation; might be a partition, if recursing.
9255  * indexOid is the OID of the index (on pkrel) implementing this constraint.
9256  * parentConstr is the OID of a parent constraint; InvalidOid if this is a
9257  * top-level constraint.
9258  * numfks is the number of columns in the foreign key
9259  * pkattnum is the attnum array of referenced attributes.
9260  * fkattnum is the attnum array of referencing attributes.
9261  * pf/pp/ffeqoperators are OID array of operators between columns.
9262  * old_check_ok signals that this constraint replaces an existing one that
9263  * was already validated (thus this one doesn't need validation).
9264  */
9265 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,bool old_check_ok)9266 addFkRecurseReferenced(List **wqueue, Constraint *fkconstraint, Relation rel,
9267 					   Relation pkrel, Oid indexOid, Oid parentConstr,
9268 					   int numfks,
9269 					   int16 *pkattnum, int16 *fkattnum, Oid *pfeqoperators,
9270 					   Oid *ppeqoperators, Oid *ffeqoperators, bool old_check_ok)
9271 {
9272 	ObjectAddress address;
9273 	Oid			constrOid;
9274 	char	   *conname;
9275 	bool		conislocal;
9276 	int			coninhcount;
9277 	bool		connoinherit;
9278 
9279 	/*
9280 	 * Verify relkind for each referenced partition.  At the top level, this
9281 	 * is redundant with a previous check, but we need it when recursing.
9282 	 */
9283 	if (pkrel->rd_rel->relkind != RELKIND_RELATION &&
9284 		pkrel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
9285 		ereport(ERROR,
9286 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
9287 				 errmsg("referenced relation \"%s\" is not a table",
9288 						RelationGetRelationName(pkrel))));
9289 
9290 	/*
9291 	 * Caller supplies us with a constraint name; however, it may be used in
9292 	 * this partition, so come up with a different one in that case.
9293 	 */
9294 	if (ConstraintNameIsUsed(CONSTRAINT_RELATION,
9295 							 RelationGetRelid(rel),
9296 							 fkconstraint->conname))
9297 		conname = ChooseConstraintName(RelationGetRelationName(rel),
9298 									   ChooseForeignKeyConstraintNameAddition(fkconstraint->fk_attrs),
9299 									   "fkey",
9300 									   RelationGetNamespace(rel), NIL);
9301 	else
9302 		conname = fkconstraint->conname;
9303 
9304 	if (OidIsValid(parentConstr))
9305 	{
9306 		conislocal = false;
9307 		coninhcount = 1;
9308 		connoinherit = false;
9309 	}
9310 	else
9311 	{
9312 		conislocal = true;
9313 		coninhcount = 0;
9314 
9315 		/*
9316 		 * always inherit for partitioned tables, never for legacy inheritance
9317 		 */
9318 		connoinherit = rel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE;
9319 	}
9320 
9321 	/*
9322 	 * Record the FK constraint in pg_constraint.
9323 	 */
9324 	constrOid = CreateConstraintEntry(conname,
9325 									  RelationGetNamespace(rel),
9326 									  CONSTRAINT_FOREIGN,
9327 									  fkconstraint->deferrable,
9328 									  fkconstraint->initdeferred,
9329 									  fkconstraint->initially_valid,
9330 									  parentConstr,
9331 									  RelationGetRelid(rel),
9332 									  fkattnum,
9333 									  numfks,
9334 									  numfks,
9335 									  InvalidOid,	/* not a domain constraint */
9336 									  indexOid,
9337 									  RelationGetRelid(pkrel),
9338 									  pkattnum,
9339 									  pfeqoperators,
9340 									  ppeqoperators,
9341 									  ffeqoperators,
9342 									  numfks,
9343 									  fkconstraint->fk_upd_action,
9344 									  fkconstraint->fk_del_action,
9345 									  fkconstraint->fk_matchtype,
9346 									  NULL, /* no exclusion constraint */
9347 									  NULL, /* no check constraint */
9348 									  NULL,
9349 									  conislocal,	/* islocal */
9350 									  coninhcount,	/* inhcount */
9351 									  connoinherit, /* conNoInherit */
9352 									  false);	/* is_internal */
9353 
9354 	ObjectAddressSet(address, ConstraintRelationId, constrOid);
9355 
9356 	/*
9357 	 * Mark the child constraint as part of the parent constraint; it must not
9358 	 * be dropped on its own.  (This constraint is deleted when the partition
9359 	 * is detached, but a special check needs to occur that the partition
9360 	 * contains no referenced values.)
9361 	 */
9362 	if (OidIsValid(parentConstr))
9363 	{
9364 		ObjectAddress referenced;
9365 
9366 		ObjectAddressSet(referenced, ConstraintRelationId, parentConstr);
9367 		recordDependencyOn(&address, &referenced, DEPENDENCY_INTERNAL);
9368 	}
9369 
9370 	/* make new constraint visible, in case we add more */
9371 	CommandCounterIncrement();
9372 
9373 	/*
9374 	 * If the referenced table is a plain relation, create the action triggers
9375 	 * that enforce the constraint.
9376 	 */
9377 	if (pkrel->rd_rel->relkind == RELKIND_RELATION)
9378 	{
9379 		createForeignKeyActionTriggers(rel, RelationGetRelid(pkrel),
9380 									   fkconstraint,
9381 									   constrOid, indexOid);
9382 	}
9383 
9384 	/*
9385 	 * If the referenced table is partitioned, recurse on ourselves to handle
9386 	 * each partition.  We need one pg_constraint row created for each
9387 	 * partition in addition to the pg_constraint row for the parent table.
9388 	 */
9389 	if (pkrel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
9390 	{
9391 		PartitionDesc pd = RelationGetPartitionDesc(pkrel, true);
9392 
9393 		for (int i = 0; i < pd->nparts; i++)
9394 		{
9395 			Relation	partRel;
9396 			AttrMap    *map;
9397 			AttrNumber *mapped_pkattnum;
9398 			Oid			partIndexId;
9399 
9400 			partRel = table_open(pd->oids[i], ShareRowExclusiveLock);
9401 
9402 			/*
9403 			 * Map the attribute numbers in the referenced side of the FK
9404 			 * definition to match the partition's column layout.
9405 			 */
9406 			map = build_attrmap_by_name_if_req(RelationGetDescr(partRel),
9407 											   RelationGetDescr(pkrel));
9408 			if (map)
9409 			{
9410 				mapped_pkattnum = palloc(sizeof(AttrNumber) * numfks);
9411 				for (int j = 0; j < numfks; j++)
9412 					mapped_pkattnum[j] = map->attnums[pkattnum[j] - 1];
9413 			}
9414 			else
9415 				mapped_pkattnum = pkattnum;
9416 
9417 			/* do the deed */
9418 			partIndexId = index_get_partition(partRel, indexOid);
9419 			if (!OidIsValid(partIndexId))
9420 				elog(ERROR, "index for %u not found in partition %s",
9421 					 indexOid, RelationGetRelationName(partRel));
9422 			addFkRecurseReferenced(wqueue, fkconstraint, rel, partRel,
9423 								   partIndexId, constrOid, numfks,
9424 								   mapped_pkattnum, fkattnum,
9425 								   pfeqoperators, ppeqoperators, ffeqoperators,
9426 								   old_check_ok);
9427 
9428 			/* Done -- clean up (but keep the lock) */
9429 			table_close(partRel, NoLock);
9430 			if (map)
9431 			{
9432 				pfree(mapped_pkattnum);
9433 				free_attrmap(map);
9434 			}
9435 		}
9436 	}
9437 
9438 	return address;
9439 }
9440 
9441 /*
9442  * addFkRecurseReferencing
9443  *		subroutine for ATAddForeignKeyConstraint and CloneFkReferencing
9444  *
9445  * If the referencing relation is a plain relation, create the necessary check
9446  * triggers that implement the constraint, and set up for Phase 3 constraint
9447  * verification.  If the referencing relation is a partitioned table, then
9448  * we create a pg_constraint row for it and recurse on this routine for each
9449  * partition.
9450  *
9451  * We assume that the referenced relation is locked against concurrent
9452  * deletions.  If it's a partitioned relation, every partition must be so
9453  * locked.
9454  *
9455  * wqueue is the ALTER TABLE work queue; can be NULL when not running as part
9456  * of an ALTER TABLE sequence.
9457  * fkconstraint is the constraint being added.
9458  * rel is the referencing relation; might be a partition, if recursing.
9459  * pkrel is the root referenced relation.
9460  * indexOid is the OID of the index (on pkrel) implementing this constraint.
9461  * parentConstr is the OID of the parent constraint (there is always one).
9462  * numfks is the number of columns in the foreign key
9463  * pkattnum is the attnum array of referenced attributes.
9464  * fkattnum is the attnum array of referencing attributes.
9465  * pf/pp/ffeqoperators are OID array of operators between columns.
9466  * old_check_ok signals that this constraint replaces an existing one that
9467  *		was already validated (thus this one doesn't need validation).
9468  * lockmode is the lockmode to acquire on partitions when recursing.
9469  */
9470 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,bool old_check_ok,LOCKMODE lockmode)9471 addFkRecurseReferencing(List **wqueue, Constraint *fkconstraint, Relation rel,
9472 						Relation pkrel, Oid indexOid, Oid parentConstr,
9473 						int numfks, int16 *pkattnum, int16 *fkattnum,
9474 						Oid *pfeqoperators, Oid *ppeqoperators, Oid *ffeqoperators,
9475 						bool old_check_ok, LOCKMODE lockmode)
9476 {
9477 	AssertArg(OidIsValid(parentConstr));
9478 
9479 	if (rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
9480 		ereport(ERROR,
9481 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
9482 				 errmsg("foreign key constraints are not supported on foreign tables")));
9483 
9484 	/*
9485 	 * If the referencing relation is a plain table, add the check triggers to
9486 	 * it and, if necessary, schedule it to be checked in Phase 3.
9487 	 *
9488 	 * If the relation is partitioned, drill down to do it to its partitions.
9489 	 */
9490 	if (rel->rd_rel->relkind == RELKIND_RELATION)
9491 	{
9492 		createForeignKeyCheckTriggers(RelationGetRelid(rel),
9493 									  RelationGetRelid(pkrel),
9494 									  fkconstraint,
9495 									  parentConstr,
9496 									  indexOid);
9497 
9498 		/*
9499 		 * Tell Phase 3 to check that the constraint is satisfied by existing
9500 		 * rows. We can skip this during table creation, when requested
9501 		 * explicitly by specifying NOT VALID in an ADD FOREIGN KEY command,
9502 		 * and when we're recreating a constraint following a SET DATA TYPE
9503 		 * operation that did not impugn its validity.
9504 		 */
9505 		if (wqueue && !old_check_ok && !fkconstraint->skip_validation)
9506 		{
9507 			NewConstraint *newcon;
9508 			AlteredTableInfo *tab;
9509 
9510 			tab = ATGetQueueEntry(wqueue, rel);
9511 
9512 			newcon = (NewConstraint *) palloc0(sizeof(NewConstraint));
9513 			newcon->name = get_constraint_name(parentConstr);
9514 			newcon->contype = CONSTR_FOREIGN;
9515 			newcon->refrelid = RelationGetRelid(pkrel);
9516 			newcon->refindid = indexOid;
9517 			newcon->conid = parentConstr;
9518 			newcon->qual = (Node *) fkconstraint;
9519 
9520 			tab->constraints = lappend(tab->constraints, newcon);
9521 		}
9522 	}
9523 	else if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
9524 	{
9525 		PartitionDesc pd = RelationGetPartitionDesc(rel, true);
9526 
9527 		/*
9528 		 * Recurse to take appropriate action on each partition; either we
9529 		 * find an existing constraint to reparent to ours, or we create a new
9530 		 * one.
9531 		 */
9532 		for (int i = 0; i < pd->nparts; i++)
9533 		{
9534 			Oid			partitionId = pd->oids[i];
9535 			Relation	partition = table_open(partitionId, lockmode);
9536 			List	   *partFKs;
9537 			AttrMap    *attmap;
9538 			AttrNumber	mapped_fkattnum[INDEX_MAX_KEYS];
9539 			bool		attached;
9540 			char	   *conname;
9541 			Oid			constrOid;
9542 			ObjectAddress address,
9543 						referenced;
9544 			ListCell   *cell;
9545 
9546 			CheckTableNotInUse(partition, "ALTER TABLE");
9547 
9548 			attmap = build_attrmap_by_name(RelationGetDescr(partition),
9549 										   RelationGetDescr(rel));
9550 			for (int j = 0; j < numfks; j++)
9551 				mapped_fkattnum[j] = attmap->attnums[fkattnum[j] - 1];
9552 
9553 			/* Check whether an existing constraint can be repurposed */
9554 			partFKs = copyObject(RelationGetFKeyList(partition));
9555 			attached = false;
9556 			foreach(cell, partFKs)
9557 			{
9558 				ForeignKeyCacheInfo *fk;
9559 
9560 				fk = lfirst_node(ForeignKeyCacheInfo, cell);
9561 				if (tryAttachPartitionForeignKey(fk,
9562 												 partitionId,
9563 												 parentConstr,
9564 												 numfks,
9565 												 mapped_fkattnum,
9566 												 pkattnum,
9567 												 pfeqoperators))
9568 				{
9569 					attached = true;
9570 					break;
9571 				}
9572 			}
9573 			if (attached)
9574 			{
9575 				table_close(partition, NoLock);
9576 				continue;
9577 			}
9578 
9579 			/*
9580 			 * No luck finding a good constraint to reuse; create our own.
9581 			 */
9582 			if (ConstraintNameIsUsed(CONSTRAINT_RELATION,
9583 									 RelationGetRelid(partition),
9584 									 fkconstraint->conname))
9585 				conname = ChooseConstraintName(RelationGetRelationName(partition),
9586 											   ChooseForeignKeyConstraintNameAddition(fkconstraint->fk_attrs),
9587 											   "fkey",
9588 											   RelationGetNamespace(partition), NIL);
9589 			else
9590 				conname = fkconstraint->conname;
9591 			constrOid =
9592 				CreateConstraintEntry(conname,
9593 									  RelationGetNamespace(partition),
9594 									  CONSTRAINT_FOREIGN,
9595 									  fkconstraint->deferrable,
9596 									  fkconstraint->initdeferred,
9597 									  fkconstraint->initially_valid,
9598 									  parentConstr,
9599 									  partitionId,
9600 									  mapped_fkattnum,
9601 									  numfks,
9602 									  numfks,
9603 									  InvalidOid,
9604 									  indexOid,
9605 									  RelationGetRelid(pkrel),
9606 									  pkattnum,
9607 									  pfeqoperators,
9608 									  ppeqoperators,
9609 									  ffeqoperators,
9610 									  numfks,
9611 									  fkconstraint->fk_upd_action,
9612 									  fkconstraint->fk_del_action,
9613 									  fkconstraint->fk_matchtype,
9614 									  NULL,
9615 									  NULL,
9616 									  NULL,
9617 									  false,
9618 									  1,
9619 									  false,
9620 									  false);
9621 
9622 			/*
9623 			 * Give this constraint partition-type dependencies on the parent
9624 			 * constraint as well as the table.
9625 			 */
9626 			ObjectAddressSet(address, ConstraintRelationId, constrOid);
9627 			ObjectAddressSet(referenced, ConstraintRelationId, parentConstr);
9628 			recordDependencyOn(&address, &referenced, DEPENDENCY_PARTITION_PRI);
9629 			ObjectAddressSet(referenced, RelationRelationId, partitionId);
9630 			recordDependencyOn(&address, &referenced, DEPENDENCY_PARTITION_SEC);
9631 
9632 			/* Make all this visible before recursing */
9633 			CommandCounterIncrement();
9634 
9635 			/* call ourselves to finalize the creation and we're done */
9636 			addFkRecurseReferencing(wqueue, fkconstraint, partition, pkrel,
9637 									indexOid,
9638 									constrOid,
9639 									numfks,
9640 									pkattnum,
9641 									mapped_fkattnum,
9642 									pfeqoperators,
9643 									ppeqoperators,
9644 									ffeqoperators,
9645 									old_check_ok,
9646 									lockmode);
9647 
9648 			table_close(partition, NoLock);
9649 		}
9650 	}
9651 }
9652 
9653 /*
9654  * CloneForeignKeyConstraints
9655  *		Clone foreign keys from a partitioned table to a newly acquired
9656  *		partition.
9657  *
9658  * partitionRel is a partition of parentRel, so we can be certain that it has
9659  * the same columns with the same datatypes.  The columns may be in different
9660  * order, though.
9661  *
9662  * wqueue must be passed to set up phase 3 constraint checking, unless the
9663  * referencing-side partition is known to be empty (such as in CREATE TABLE /
9664  * PARTITION OF).
9665  */
9666 static void
CloneForeignKeyConstraints(List ** wqueue,Relation parentRel,Relation partitionRel)9667 CloneForeignKeyConstraints(List **wqueue, Relation parentRel,
9668 						   Relation partitionRel)
9669 {
9670 	/* This only works for declarative partitioning */
9671 	Assert(parentRel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
9672 
9673 	/*
9674 	 * Clone constraints for which the parent is on the referenced side.
9675 	 */
9676 	CloneFkReferenced(parentRel, partitionRel);
9677 
9678 	/*
9679 	 * Now clone constraints where the parent is on the referencing side.
9680 	 */
9681 	CloneFkReferencing(wqueue, parentRel, partitionRel);
9682 }
9683 
9684 /*
9685  * CloneFkReferenced
9686  *		Subroutine for CloneForeignKeyConstraints
9687  *
9688  * Find all the FKs that have the parent relation on the referenced side;
9689  * clone those constraints to the given partition.  This is to be called
9690  * when the partition is being created or attached.
9691  *
9692  * This recurses to partitions, if the relation being attached is partitioned.
9693  * Recursion is done by calling addFkRecurseReferenced.
9694  */
9695 static void
CloneFkReferenced(Relation parentRel,Relation partitionRel)9696 CloneFkReferenced(Relation parentRel, Relation partitionRel)
9697 {
9698 	Relation	pg_constraint;
9699 	AttrMap    *attmap;
9700 	ListCell   *cell;
9701 	SysScanDesc scan;
9702 	ScanKeyData key[2];
9703 	HeapTuple	tuple;
9704 	List	   *clone = NIL;
9705 
9706 	/*
9707 	 * Search for any constraints where this partition's parent is in the
9708 	 * referenced side.  However, we must not clone any constraint whose
9709 	 * parent constraint is also going to be cloned, to avoid duplicates.  So
9710 	 * do it in two steps: first construct the list of constraints to clone,
9711 	 * then go over that list cloning those whose parents are not in the list.
9712 	 * (We must not rely on the parent being seen first, since the catalog
9713 	 * scan could return children first.)
9714 	 */
9715 	pg_constraint = table_open(ConstraintRelationId, RowShareLock);
9716 	ScanKeyInit(&key[0],
9717 				Anum_pg_constraint_confrelid, BTEqualStrategyNumber,
9718 				F_OIDEQ, ObjectIdGetDatum(RelationGetRelid(parentRel)));
9719 	ScanKeyInit(&key[1],
9720 				Anum_pg_constraint_contype, BTEqualStrategyNumber,
9721 				F_CHAREQ, CharGetDatum(CONSTRAINT_FOREIGN));
9722 	/* This is a seqscan, as we don't have a usable index ... */
9723 	scan = systable_beginscan(pg_constraint, InvalidOid, true,
9724 							  NULL, 2, key);
9725 	while ((tuple = systable_getnext(scan)) != NULL)
9726 	{
9727 		Form_pg_constraint constrForm = (Form_pg_constraint) GETSTRUCT(tuple);
9728 
9729 		clone = lappend_oid(clone, constrForm->oid);
9730 	}
9731 	systable_endscan(scan);
9732 	table_close(pg_constraint, RowShareLock);
9733 
9734 	attmap = build_attrmap_by_name(RelationGetDescr(partitionRel),
9735 								   RelationGetDescr(parentRel));
9736 	foreach(cell, clone)
9737 	{
9738 		Oid			constrOid = lfirst_oid(cell);
9739 		Form_pg_constraint constrForm;
9740 		Relation	fkRel;
9741 		Oid			indexOid;
9742 		Oid			partIndexId;
9743 		int			numfks;
9744 		AttrNumber	conkey[INDEX_MAX_KEYS];
9745 		AttrNumber	mapped_confkey[INDEX_MAX_KEYS];
9746 		AttrNumber	confkey[INDEX_MAX_KEYS];
9747 		Oid			conpfeqop[INDEX_MAX_KEYS];
9748 		Oid			conppeqop[INDEX_MAX_KEYS];
9749 		Oid			conffeqop[INDEX_MAX_KEYS];
9750 		Constraint *fkconstraint;
9751 
9752 		tuple = SearchSysCache1(CONSTROID, constrOid);
9753 		if (!HeapTupleIsValid(tuple))
9754 			elog(ERROR, "cache lookup failed for constraint %u", constrOid);
9755 		constrForm = (Form_pg_constraint) GETSTRUCT(tuple);
9756 
9757 		/*
9758 		 * As explained above: don't try to clone a constraint for which we're
9759 		 * going to clone the parent.
9760 		 */
9761 		if (list_member_oid(clone, constrForm->conparentid))
9762 		{
9763 			ReleaseSysCache(tuple);
9764 			continue;
9765 		}
9766 
9767 		/*
9768 		 * Because we're only expanding the key space at the referenced side,
9769 		 * we don't need to prevent any operation in the referencing table, so
9770 		 * AccessShareLock suffices (assumes that dropping the constraint
9771 		 * acquires AEL).
9772 		 */
9773 		fkRel = table_open(constrForm->conrelid, AccessShareLock);
9774 
9775 		indexOid = constrForm->conindid;
9776 		DeconstructFkConstraintRow(tuple,
9777 								   &numfks,
9778 								   conkey,
9779 								   confkey,
9780 								   conpfeqop,
9781 								   conppeqop,
9782 								   conffeqop);
9783 
9784 		for (int i = 0; i < numfks; i++)
9785 			mapped_confkey[i] = attmap->attnums[confkey[i] - 1];
9786 
9787 		fkconstraint = makeNode(Constraint);
9788 		/* for now this is all we need */
9789 		fkconstraint->conname = NameStr(constrForm->conname);
9790 		fkconstraint->fk_upd_action = constrForm->confupdtype;
9791 		fkconstraint->fk_del_action = constrForm->confdeltype;
9792 		fkconstraint->deferrable = constrForm->condeferrable;
9793 		fkconstraint->initdeferred = constrForm->condeferred;
9794 		fkconstraint->initially_valid = true;
9795 		fkconstraint->fk_matchtype = constrForm->confmatchtype;
9796 
9797 		/* set up colnames that are used to generate the constraint name */
9798 		for (int i = 0; i < numfks; i++)
9799 		{
9800 			Form_pg_attribute att;
9801 
9802 			att = TupleDescAttr(RelationGetDescr(fkRel),
9803 								conkey[i] - 1);
9804 			fkconstraint->fk_attrs = lappend(fkconstraint->fk_attrs,
9805 											 makeString(NameStr(att->attname)));
9806 		}
9807 
9808 		/*
9809 		 * Add the new foreign key constraint pointing to the new partition.
9810 		 * Because this new partition appears in the referenced side of the
9811 		 * constraint, we don't need to set up for Phase 3 check.
9812 		 */
9813 		partIndexId = index_get_partition(partitionRel, indexOid);
9814 		if (!OidIsValid(partIndexId))
9815 			elog(ERROR, "index for %u not found in partition %s",
9816 				 indexOid, RelationGetRelationName(partitionRel));
9817 		addFkRecurseReferenced(NULL,
9818 							   fkconstraint,
9819 							   fkRel,
9820 							   partitionRel,
9821 							   partIndexId,
9822 							   constrOid,
9823 							   numfks,
9824 							   mapped_confkey,
9825 							   conkey,
9826 							   conpfeqop,
9827 							   conppeqop,
9828 							   conffeqop,
9829 							   true);
9830 
9831 		table_close(fkRel, NoLock);
9832 		ReleaseSysCache(tuple);
9833 	}
9834 }
9835 
9836 /*
9837  * CloneFkReferencing
9838  *		Subroutine for CloneForeignKeyConstraints
9839  *
9840  * For each FK constraint of the parent relation in the given list, find an
9841  * equivalent constraint in its partition relation that can be reparented;
9842  * if one cannot be found, create a new constraint in the partition as its
9843  * child.
9844  *
9845  * If wqueue is given, it is used to set up phase-3 verification for each
9846  * cloned constraint; if omitted, we assume that such verification is not
9847  * needed (example: the partition is being created anew).
9848  */
9849 static void
CloneFkReferencing(List ** wqueue,Relation parentRel,Relation partRel)9850 CloneFkReferencing(List **wqueue, Relation parentRel, Relation partRel)
9851 {
9852 	AttrMap    *attmap;
9853 	List	   *partFKs;
9854 	List	   *clone = NIL;
9855 	ListCell   *cell;
9856 
9857 	/* obtain a list of constraints that we need to clone */
9858 	foreach(cell, RelationGetFKeyList(parentRel))
9859 	{
9860 		ForeignKeyCacheInfo *fk = lfirst(cell);
9861 
9862 		clone = lappend_oid(clone, fk->conoid);
9863 	}
9864 
9865 	/*
9866 	 * Silently do nothing if there's nothing to do.  In particular, this
9867 	 * avoids throwing a spurious error for foreign tables.
9868 	 */
9869 	if (clone == NIL)
9870 		return;
9871 
9872 	if (partRel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
9873 		ereport(ERROR,
9874 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
9875 				 errmsg("foreign key constraints are not supported on foreign tables")));
9876 
9877 	/*
9878 	 * The constraint key may differ, if the columns in the partition are
9879 	 * different.  This map is used to convert them.
9880 	 */
9881 	attmap = build_attrmap_by_name(RelationGetDescr(partRel),
9882 								   RelationGetDescr(parentRel));
9883 
9884 	partFKs = copyObject(RelationGetFKeyList(partRel));
9885 
9886 	foreach(cell, clone)
9887 	{
9888 		Oid			parentConstrOid = lfirst_oid(cell);
9889 		Form_pg_constraint constrForm;
9890 		Relation	pkrel;
9891 		HeapTuple	tuple;
9892 		int			numfks;
9893 		AttrNumber	conkey[INDEX_MAX_KEYS];
9894 		AttrNumber	mapped_conkey[INDEX_MAX_KEYS];
9895 		AttrNumber	confkey[INDEX_MAX_KEYS];
9896 		Oid			conpfeqop[INDEX_MAX_KEYS];
9897 		Oid			conppeqop[INDEX_MAX_KEYS];
9898 		Oid			conffeqop[INDEX_MAX_KEYS];
9899 		Constraint *fkconstraint;
9900 		bool		attached;
9901 		Oid			indexOid;
9902 		Oid			constrOid;
9903 		ObjectAddress address,
9904 					referenced;
9905 		ListCell   *cell;
9906 
9907 		tuple = SearchSysCache1(CONSTROID, parentConstrOid);
9908 		if (!HeapTupleIsValid(tuple))
9909 			elog(ERROR, "cache lookup failed for constraint %u",
9910 				 parentConstrOid);
9911 		constrForm = (Form_pg_constraint) GETSTRUCT(tuple);
9912 
9913 		/* Don't clone constraints whose parents are being cloned */
9914 		if (list_member_oid(clone, constrForm->conparentid))
9915 		{
9916 			ReleaseSysCache(tuple);
9917 			continue;
9918 		}
9919 
9920 		/*
9921 		 * Need to prevent concurrent deletions.  If pkrel is a partitioned
9922 		 * relation, that means to lock all partitions.
9923 		 */
9924 		pkrel = table_open(constrForm->confrelid, ShareRowExclusiveLock);
9925 		if (pkrel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
9926 			(void) find_all_inheritors(RelationGetRelid(pkrel),
9927 									   ShareRowExclusiveLock, NULL);
9928 
9929 		DeconstructFkConstraintRow(tuple, &numfks, conkey, confkey,
9930 								   conpfeqop, conppeqop, conffeqop);
9931 		for (int i = 0; i < numfks; i++)
9932 			mapped_conkey[i] = attmap->attnums[conkey[i] - 1];
9933 
9934 		/*
9935 		 * Before creating a new constraint, see whether any existing FKs are
9936 		 * fit for the purpose.  If one is, attach the parent constraint to
9937 		 * it, and don't clone anything.  This way we avoid the expensive
9938 		 * verification step and don't end up with a duplicate FK, and we
9939 		 * don't need to recurse to partitions for this constraint.
9940 		 */
9941 		attached = false;
9942 		foreach(cell, partFKs)
9943 		{
9944 			ForeignKeyCacheInfo *fk = lfirst_node(ForeignKeyCacheInfo, cell);
9945 
9946 			if (tryAttachPartitionForeignKey(fk,
9947 											 RelationGetRelid(partRel),
9948 											 parentConstrOid,
9949 											 numfks,
9950 											 mapped_conkey,
9951 											 confkey,
9952 											 conpfeqop))
9953 			{
9954 				attached = true;
9955 				table_close(pkrel, NoLock);
9956 				break;
9957 			}
9958 		}
9959 		if (attached)
9960 		{
9961 			ReleaseSysCache(tuple);
9962 			continue;
9963 		}
9964 
9965 		/* No dice.  Set up to create our own constraint */
9966 		fkconstraint = makeNode(Constraint);
9967 		if (ConstraintNameIsUsed(CONSTRAINT_RELATION,
9968 								 RelationGetRelid(partRel),
9969 								 NameStr(constrForm->conname)))
9970 			fkconstraint->conname =
9971 				ChooseConstraintName(RelationGetRelationName(partRel),
9972 									 ChooseForeignKeyConstraintNameAddition(fkconstraint->fk_attrs),
9973 									 "fkey",
9974 									 RelationGetNamespace(partRel), NIL);
9975 		else
9976 			fkconstraint->conname = pstrdup(NameStr(constrForm->conname));
9977 		fkconstraint->fk_upd_action = constrForm->confupdtype;
9978 		fkconstraint->fk_del_action = constrForm->confdeltype;
9979 		fkconstraint->deferrable = constrForm->condeferrable;
9980 		fkconstraint->initdeferred = constrForm->condeferred;
9981 		fkconstraint->fk_matchtype = constrForm->confmatchtype;
9982 		for (int i = 0; i < numfks; i++)
9983 		{
9984 			Form_pg_attribute att;
9985 
9986 			att = TupleDescAttr(RelationGetDescr(partRel),
9987 								mapped_conkey[i] - 1);
9988 			fkconstraint->fk_attrs = lappend(fkconstraint->fk_attrs,
9989 											 makeString(NameStr(att->attname)));
9990 		}
9991 
9992 		indexOid = constrForm->conindid;
9993 		constrOid =
9994 			CreateConstraintEntry(fkconstraint->conname,
9995 								  constrForm->connamespace,
9996 								  CONSTRAINT_FOREIGN,
9997 								  fkconstraint->deferrable,
9998 								  fkconstraint->initdeferred,
9999 								  constrForm->convalidated,
10000 								  parentConstrOid,
10001 								  RelationGetRelid(partRel),
10002 								  mapped_conkey,
10003 								  numfks,
10004 								  numfks,
10005 								  InvalidOid,	/* not a domain constraint */
10006 								  indexOid,
10007 								  constrForm->confrelid,	/* same foreign rel */
10008 								  confkey,
10009 								  conpfeqop,
10010 								  conppeqop,
10011 								  conffeqop,
10012 								  numfks,
10013 								  fkconstraint->fk_upd_action,
10014 								  fkconstraint->fk_del_action,
10015 								  fkconstraint->fk_matchtype,
10016 								  NULL,
10017 								  NULL,
10018 								  NULL,
10019 								  false,	/* islocal */
10020 								  1,	/* inhcount */
10021 								  false,	/* conNoInherit */
10022 								  true);
10023 
10024 		/* Set up partition dependencies for the new constraint */
10025 		ObjectAddressSet(address, ConstraintRelationId, constrOid);
10026 		ObjectAddressSet(referenced, ConstraintRelationId, parentConstrOid);
10027 		recordDependencyOn(&address, &referenced, DEPENDENCY_PARTITION_PRI);
10028 		ObjectAddressSet(referenced, RelationRelationId,
10029 						 RelationGetRelid(partRel));
10030 		recordDependencyOn(&address, &referenced, DEPENDENCY_PARTITION_SEC);
10031 
10032 		/* Done with the cloned constraint's tuple */
10033 		ReleaseSysCache(tuple);
10034 
10035 		/* Make all this visible before recursing */
10036 		CommandCounterIncrement();
10037 
10038 		addFkRecurseReferencing(wqueue,
10039 								fkconstraint,
10040 								partRel,
10041 								pkrel,
10042 								indexOid,
10043 								constrOid,
10044 								numfks,
10045 								confkey,
10046 								mapped_conkey,
10047 								conpfeqop,
10048 								conppeqop,
10049 								conffeqop,
10050 								false,	/* no old check exists */
10051 								AccessExclusiveLock);
10052 		table_close(pkrel, NoLock);
10053 	}
10054 }
10055 
10056 /*
10057  * When the parent of a partition receives [the referencing side of] a foreign
10058  * key, we must propagate that foreign key to the partition.  However, the
10059  * partition might already have an equivalent foreign key; this routine
10060  * compares the given ForeignKeyCacheInfo (in the partition) to the FK defined
10061  * by the other parameters.  If they are equivalent, create the link between
10062  * the two constraints and return true.
10063  *
10064  * If the given FK does not match the one defined by rest of the params,
10065  * return false.
10066  */
10067 static bool
tryAttachPartitionForeignKey(ForeignKeyCacheInfo * fk,Oid partRelid,Oid parentConstrOid,int numfks,AttrNumber * mapped_conkey,AttrNumber * confkey,Oid * conpfeqop)10068 tryAttachPartitionForeignKey(ForeignKeyCacheInfo *fk,
10069 							 Oid partRelid,
10070 							 Oid parentConstrOid,
10071 							 int numfks,
10072 							 AttrNumber *mapped_conkey,
10073 							 AttrNumber *confkey,
10074 							 Oid *conpfeqop)
10075 {
10076 	HeapTuple	parentConstrTup;
10077 	Form_pg_constraint parentConstr;
10078 	HeapTuple	partcontup;
10079 	Form_pg_constraint partConstr;
10080 	Relation	trigrel;
10081 	ScanKeyData key;
10082 	SysScanDesc scan;
10083 	HeapTuple	trigtup;
10084 
10085 	parentConstrTup = SearchSysCache1(CONSTROID,
10086 									  ObjectIdGetDatum(parentConstrOid));
10087 	if (!HeapTupleIsValid(parentConstrTup))
10088 		elog(ERROR, "cache lookup failed for constraint %u", parentConstrOid);
10089 	parentConstr = (Form_pg_constraint) GETSTRUCT(parentConstrTup);
10090 
10091 	/*
10092 	 * Do some quick & easy initial checks.  If any of these fail, we cannot
10093 	 * use this constraint.
10094 	 */
10095 	if (fk->confrelid != parentConstr->confrelid || fk->nkeys != numfks)
10096 	{
10097 		ReleaseSysCache(parentConstrTup);
10098 		return false;
10099 	}
10100 	for (int i = 0; i < numfks; i++)
10101 	{
10102 		if (fk->conkey[i] != mapped_conkey[i] ||
10103 			fk->confkey[i] != confkey[i] ||
10104 			fk->conpfeqop[i] != conpfeqop[i])
10105 		{
10106 			ReleaseSysCache(parentConstrTup);
10107 			return false;
10108 		}
10109 	}
10110 
10111 	/*
10112 	 * Looks good so far; do some more extensive checks.  Presumably the check
10113 	 * for 'convalidated' could be dropped, since we don't really care about
10114 	 * that, but let's be careful for now.
10115 	 */
10116 	partcontup = SearchSysCache1(CONSTROID,
10117 								 ObjectIdGetDatum(fk->conoid));
10118 	if (!HeapTupleIsValid(partcontup))
10119 		elog(ERROR, "cache lookup failed for constraint %u", fk->conoid);
10120 	partConstr = (Form_pg_constraint) GETSTRUCT(partcontup);
10121 	if (OidIsValid(partConstr->conparentid) ||
10122 		!partConstr->convalidated ||
10123 		partConstr->condeferrable != parentConstr->condeferrable ||
10124 		partConstr->condeferred != parentConstr->condeferred ||
10125 		partConstr->confupdtype != parentConstr->confupdtype ||
10126 		partConstr->confdeltype != parentConstr->confdeltype ||
10127 		partConstr->confmatchtype != parentConstr->confmatchtype)
10128 	{
10129 		ReleaseSysCache(parentConstrTup);
10130 		ReleaseSysCache(partcontup);
10131 		return false;
10132 	}
10133 
10134 	ReleaseSysCache(partcontup);
10135 	ReleaseSysCache(parentConstrTup);
10136 
10137 	/*
10138 	 * Looks good!  Attach this constraint.  The action triggers in the new
10139 	 * partition become redundant -- the parent table already has equivalent
10140 	 * ones, and those will be able to reach the partition.  Remove the ones
10141 	 * in the partition.  We identify them because they have our constraint
10142 	 * OID, as well as being on the referenced rel.
10143 	 */
10144 	trigrel = table_open(TriggerRelationId, RowExclusiveLock);
10145 	ScanKeyInit(&key,
10146 				Anum_pg_trigger_tgconstraint,
10147 				BTEqualStrategyNumber, F_OIDEQ,
10148 				ObjectIdGetDatum(fk->conoid));
10149 
10150 	scan = systable_beginscan(trigrel, TriggerConstraintIndexId, true,
10151 							  NULL, 1, &key);
10152 	while ((trigtup = systable_getnext(scan)) != NULL)
10153 	{
10154 		Form_pg_trigger trgform = (Form_pg_trigger) GETSTRUCT(trigtup);
10155 		ObjectAddress trigger;
10156 
10157 		if (trgform->tgconstrrelid != fk->conrelid)
10158 			continue;
10159 		if (trgform->tgrelid != fk->confrelid)
10160 			continue;
10161 
10162 		/*
10163 		 * The constraint is originally set up to contain this trigger as an
10164 		 * implementation object, so there's a dependency record that links
10165 		 * the two; however, since the trigger is no longer needed, we remove
10166 		 * the dependency link in order to be able to drop the trigger while
10167 		 * keeping the constraint intact.
10168 		 */
10169 		deleteDependencyRecordsFor(TriggerRelationId,
10170 								   trgform->oid,
10171 								   false);
10172 		/* make dependency deletion visible to performDeletion */
10173 		CommandCounterIncrement();
10174 		ObjectAddressSet(trigger, TriggerRelationId,
10175 						 trgform->oid);
10176 		performDeletion(&trigger, DROP_RESTRICT, 0);
10177 		/* make trigger drop visible, in case the loop iterates */
10178 		CommandCounterIncrement();
10179 	}
10180 
10181 	systable_endscan(scan);
10182 	table_close(trigrel, RowExclusiveLock);
10183 
10184 	ConstraintSetParentConstraint(fk->conoid, parentConstrOid, partRelid);
10185 	CommandCounterIncrement();
10186 	return true;
10187 }
10188 
10189 
10190 /*
10191  * ALTER TABLE ALTER CONSTRAINT
10192  *
10193  * Update the attributes of a constraint.
10194  *
10195  * Currently only works for Foreign Key constraints.
10196  *
10197  * If the constraint is modified, returns its address; otherwise, return
10198  * InvalidObjectAddress.
10199  */
10200 static ObjectAddress
ATExecAlterConstraint(Relation rel,AlterTableCmd * cmd,bool recurse,bool recursing,LOCKMODE lockmode)10201 ATExecAlterConstraint(Relation rel, AlterTableCmd *cmd, bool recurse,
10202 					  bool recursing, LOCKMODE lockmode)
10203 {
10204 	Constraint *cmdcon;
10205 	Relation	conrel;
10206 	Relation	tgrel;
10207 	SysScanDesc scan;
10208 	ScanKeyData skey[3];
10209 	HeapTuple	contuple;
10210 	Form_pg_constraint currcon;
10211 	ObjectAddress address;
10212 	List	   *otherrelids = NIL;
10213 	ListCell   *lc;
10214 
10215 	cmdcon = castNode(Constraint, cmd->def);
10216 
10217 	conrel = table_open(ConstraintRelationId, RowExclusiveLock);
10218 	tgrel = table_open(TriggerRelationId, RowExclusiveLock);
10219 
10220 	/*
10221 	 * Find and check the target constraint
10222 	 */
10223 	ScanKeyInit(&skey[0],
10224 				Anum_pg_constraint_conrelid,
10225 				BTEqualStrategyNumber, F_OIDEQ,
10226 				ObjectIdGetDatum(RelationGetRelid(rel)));
10227 	ScanKeyInit(&skey[1],
10228 				Anum_pg_constraint_contypid,
10229 				BTEqualStrategyNumber, F_OIDEQ,
10230 				ObjectIdGetDatum(InvalidOid));
10231 	ScanKeyInit(&skey[2],
10232 				Anum_pg_constraint_conname,
10233 				BTEqualStrategyNumber, F_NAMEEQ,
10234 				CStringGetDatum(cmdcon->conname));
10235 	scan = systable_beginscan(conrel, ConstraintRelidTypidNameIndexId,
10236 							  true, NULL, 3, skey);
10237 
10238 	/* There can be at most one matching row */
10239 	if (!HeapTupleIsValid(contuple = systable_getnext(scan)))
10240 		ereport(ERROR,
10241 				(errcode(ERRCODE_UNDEFINED_OBJECT),
10242 				 errmsg("constraint \"%s\" of relation \"%s\" does not exist",
10243 						cmdcon->conname, RelationGetRelationName(rel))));
10244 
10245 	currcon = (Form_pg_constraint) GETSTRUCT(contuple);
10246 	if (currcon->contype != CONSTRAINT_FOREIGN)
10247 		ereport(ERROR,
10248 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
10249 				 errmsg("constraint \"%s\" of relation \"%s\" is not a foreign key constraint",
10250 						cmdcon->conname, RelationGetRelationName(rel))));
10251 
10252 	/*
10253 	 * If it's not the topmost constraint, raise an error.
10254 	 *
10255 	 * Altering a non-topmost constraint leaves some triggers untouched, since
10256 	 * they are not directly connected to this constraint; also, pg_dump would
10257 	 * ignore the deferrability status of the individual constraint, since it
10258 	 * only dumps topmost constraints.  Avoid these problems by refusing this
10259 	 * operation and telling the user to alter the parent constraint instead.
10260 	 */
10261 	if (OidIsValid(currcon->conparentid))
10262 	{
10263 		HeapTuple	tp;
10264 		Oid			parent = currcon->conparentid;
10265 		char	   *ancestorname = NULL;
10266 		char	   *ancestortable = NULL;
10267 
10268 		/* Loop to find the topmost constraint */
10269 		while (HeapTupleIsValid(tp = SearchSysCache1(CONSTROID, ObjectIdGetDatum(parent))))
10270 		{
10271 			Form_pg_constraint contup = (Form_pg_constraint) GETSTRUCT(tp);
10272 
10273 			/* If no parent, this is the constraint we want */
10274 			if (!OidIsValid(contup->conparentid))
10275 			{
10276 				ancestorname = pstrdup(NameStr(contup->conname));
10277 				ancestortable = get_rel_name(contup->conrelid);
10278 				ReleaseSysCache(tp);
10279 				break;
10280 			}
10281 
10282 			parent = contup->conparentid;
10283 			ReleaseSysCache(tp);
10284 		}
10285 
10286 		ereport(ERROR,
10287 				(errmsg("cannot alter constraint \"%s\" on relation \"%s\"",
10288 						cmdcon->conname, RelationGetRelationName(rel)),
10289 				 ancestorname && ancestortable ?
10290 				 errdetail("Constraint \"%s\" is derived from constraint \"%s\" of relation \"%s\".",
10291 						   cmdcon->conname, ancestorname, ancestortable) : 0,
10292 				 errhint("You may alter the constraint it derives from, instead.")));
10293 	}
10294 
10295 	/*
10296 	 * Do the actual catalog work.  We can skip changing if already in the
10297 	 * desired state, but not if a partitioned table: partitions need to be
10298 	 * processed regardless, in case they had the constraint locally changed.
10299 	 */
10300 	address = InvalidObjectAddress;
10301 	if (currcon->condeferrable != cmdcon->deferrable ||
10302 		currcon->condeferred != cmdcon->initdeferred ||
10303 		rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
10304 	{
10305 		if (ATExecAlterConstrRecurse(cmdcon, conrel, tgrel, rel, contuple,
10306 									 &otherrelids, lockmode))
10307 			ObjectAddressSet(address, ConstraintRelationId, currcon->oid);
10308 	}
10309 
10310 	/*
10311 	 * ATExecConstrRecurse already invalidated relcache for the relations
10312 	 * having the constraint itself; here we also invalidate for relations
10313 	 * that have any triggers that are part of the constraint.
10314 	 */
10315 	foreach(lc, otherrelids)
10316 		CacheInvalidateRelcacheByRelid(lfirst_oid(lc));
10317 
10318 	systable_endscan(scan);
10319 
10320 	table_close(tgrel, RowExclusiveLock);
10321 	table_close(conrel, RowExclusiveLock);
10322 
10323 	return address;
10324 }
10325 
10326 /*
10327  * Recursive subroutine of ATExecAlterConstraint.  Returns true if the
10328  * constraint is altered.
10329  *
10330  * *otherrelids is appended OIDs of relations containing affected triggers.
10331  *
10332  * Note that we must recurse even when the values are correct, in case
10333  * indirect descendants have had their constraints altered locally.
10334  * (This could be avoided if we forbade altering constraints in partitions
10335  * but existing releases don't do that.)
10336  */
10337 static bool
ATExecAlterConstrRecurse(Constraint * cmdcon,Relation conrel,Relation tgrel,Relation rel,HeapTuple contuple,List ** otherrelids,LOCKMODE lockmode)10338 ATExecAlterConstrRecurse(Constraint *cmdcon, Relation conrel, Relation tgrel,
10339 						 Relation rel, HeapTuple contuple, List **otherrelids,
10340 						 LOCKMODE lockmode)
10341 {
10342 	Form_pg_constraint currcon;
10343 	Oid			conoid;
10344 	Oid			refrelid;
10345 	bool		changed = false;
10346 
10347 	currcon = (Form_pg_constraint) GETSTRUCT(contuple);
10348 	conoid = currcon->oid;
10349 	refrelid = currcon->confrelid;
10350 
10351 	/*
10352 	 * Update pg_constraint with the flags from cmdcon.
10353 	 *
10354 	 * If called to modify a constraint that's already in the desired state,
10355 	 * silently do nothing.
10356 	 */
10357 	if (currcon->condeferrable != cmdcon->deferrable ||
10358 		currcon->condeferred != cmdcon->initdeferred)
10359 	{
10360 		HeapTuple	copyTuple;
10361 		Form_pg_constraint copy_con;
10362 		HeapTuple	tgtuple;
10363 		ScanKeyData tgkey;
10364 		SysScanDesc tgscan;
10365 
10366 		copyTuple = heap_copytuple(contuple);
10367 		copy_con = (Form_pg_constraint) GETSTRUCT(copyTuple);
10368 		copy_con->condeferrable = cmdcon->deferrable;
10369 		copy_con->condeferred = cmdcon->initdeferred;
10370 		CatalogTupleUpdate(conrel, &copyTuple->t_self, copyTuple);
10371 
10372 		InvokeObjectPostAlterHook(ConstraintRelationId,
10373 								  conoid, 0);
10374 
10375 		heap_freetuple(copyTuple);
10376 		changed = true;
10377 
10378 		/* Make new constraint flags visible to others */
10379 		CacheInvalidateRelcache(rel);
10380 
10381 		/*
10382 		 * Now we need to update the multiple entries in pg_trigger that
10383 		 * implement the constraint.
10384 		 */
10385 		ScanKeyInit(&tgkey,
10386 					Anum_pg_trigger_tgconstraint,
10387 					BTEqualStrategyNumber, F_OIDEQ,
10388 					ObjectIdGetDatum(conoid));
10389 		tgscan = systable_beginscan(tgrel, TriggerConstraintIndexId, true,
10390 									NULL, 1, &tgkey);
10391 		while (HeapTupleIsValid(tgtuple = systable_getnext(tgscan)))
10392 		{
10393 			Form_pg_trigger tgform = (Form_pg_trigger) GETSTRUCT(tgtuple);
10394 			Form_pg_trigger copy_tg;
10395 			HeapTuple	copyTuple;
10396 
10397 			/*
10398 			 * Remember OIDs of other relation(s) involved in FK constraint.
10399 			 * (Note: it's likely that we could skip forcing a relcache inval
10400 			 * for other rels that don't have a trigger whose properties
10401 			 * change, but let's be conservative.)
10402 			 */
10403 			if (tgform->tgrelid != RelationGetRelid(rel))
10404 				*otherrelids = list_append_unique_oid(*otherrelids,
10405 													  tgform->tgrelid);
10406 
10407 			/*
10408 			 * Update deferrability of RI_FKey_noaction_del,
10409 			 * RI_FKey_noaction_upd, RI_FKey_check_ins and RI_FKey_check_upd
10410 			 * triggers, but not others; see createForeignKeyActionTriggers
10411 			 * and CreateFKCheckTrigger.
10412 			 */
10413 			if (tgform->tgfoid != F_RI_FKEY_NOACTION_DEL &&
10414 				tgform->tgfoid != F_RI_FKEY_NOACTION_UPD &&
10415 				tgform->tgfoid != F_RI_FKEY_CHECK_INS &&
10416 				tgform->tgfoid != F_RI_FKEY_CHECK_UPD)
10417 				continue;
10418 
10419 			copyTuple = heap_copytuple(tgtuple);
10420 			copy_tg = (Form_pg_trigger) GETSTRUCT(copyTuple);
10421 
10422 			copy_tg->tgdeferrable = cmdcon->deferrable;
10423 			copy_tg->tginitdeferred = cmdcon->initdeferred;
10424 			CatalogTupleUpdate(tgrel, &copyTuple->t_self, copyTuple);
10425 
10426 			InvokeObjectPostAlterHook(TriggerRelationId, tgform->oid, 0);
10427 
10428 			heap_freetuple(copyTuple);
10429 		}
10430 
10431 		systable_endscan(tgscan);
10432 	}
10433 
10434 	/*
10435 	 * If the table at either end of the constraint is partitioned, we need to
10436 	 * recurse and handle every constraint that is a child of this one.
10437 	 *
10438 	 * (This assumes that the recurse flag is forcibly set for partitioned
10439 	 * tables, and not set for legacy inheritance, though we don't check for
10440 	 * that here.)
10441 	 */
10442 	if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE ||
10443 		get_rel_relkind(refrelid) == RELKIND_PARTITIONED_TABLE)
10444 	{
10445 		ScanKeyData pkey;
10446 		SysScanDesc pscan;
10447 		HeapTuple	childtup;
10448 
10449 		ScanKeyInit(&pkey,
10450 					Anum_pg_constraint_conparentid,
10451 					BTEqualStrategyNumber, F_OIDEQ,
10452 					ObjectIdGetDatum(conoid));
10453 
10454 		pscan = systable_beginscan(conrel, ConstraintParentIndexId,
10455 								   true, NULL, 1, &pkey);
10456 
10457 		while (HeapTupleIsValid(childtup = systable_getnext(pscan)))
10458 		{
10459 			Form_pg_constraint childcon = (Form_pg_constraint) GETSTRUCT(childtup);
10460 			Relation	childrel;
10461 
10462 			childrel = table_open(childcon->conrelid, lockmode);
10463 			ATExecAlterConstrRecurse(cmdcon, conrel, tgrel, childrel, childtup,
10464 									 otherrelids, lockmode);
10465 			table_close(childrel, NoLock);
10466 		}
10467 
10468 		systable_endscan(pscan);
10469 	}
10470 
10471 	return changed;
10472 }
10473 
10474 /*
10475  * ALTER TABLE VALIDATE CONSTRAINT
10476  *
10477  * XXX The reason we handle recursion here rather than at Phase 1 is because
10478  * there's no good way to skip recursing when handling foreign keys: there is
10479  * no need to lock children in that case, yet we wouldn't be able to avoid
10480  * doing so at that level.
10481  *
10482  * Return value is the address of the validated constraint.  If the constraint
10483  * was already validated, InvalidObjectAddress is returned.
10484  */
10485 static ObjectAddress
ATExecValidateConstraint(List ** wqueue,Relation rel,char * constrName,bool recurse,bool recursing,LOCKMODE lockmode)10486 ATExecValidateConstraint(List **wqueue, Relation rel, char *constrName,
10487 						 bool recurse, bool recursing, LOCKMODE lockmode)
10488 {
10489 	Relation	conrel;
10490 	SysScanDesc scan;
10491 	ScanKeyData skey[3];
10492 	HeapTuple	tuple;
10493 	Form_pg_constraint con;
10494 	ObjectAddress address;
10495 
10496 	conrel = table_open(ConstraintRelationId, RowExclusiveLock);
10497 
10498 	/*
10499 	 * Find and check the target constraint
10500 	 */
10501 	ScanKeyInit(&skey[0],
10502 				Anum_pg_constraint_conrelid,
10503 				BTEqualStrategyNumber, F_OIDEQ,
10504 				ObjectIdGetDatum(RelationGetRelid(rel)));
10505 	ScanKeyInit(&skey[1],
10506 				Anum_pg_constraint_contypid,
10507 				BTEqualStrategyNumber, F_OIDEQ,
10508 				ObjectIdGetDatum(InvalidOid));
10509 	ScanKeyInit(&skey[2],
10510 				Anum_pg_constraint_conname,
10511 				BTEqualStrategyNumber, F_NAMEEQ,
10512 				CStringGetDatum(constrName));
10513 	scan = systable_beginscan(conrel, ConstraintRelidTypidNameIndexId,
10514 							  true, NULL, 3, skey);
10515 
10516 	/* There can be at most one matching row */
10517 	if (!HeapTupleIsValid(tuple = systable_getnext(scan)))
10518 		ereport(ERROR,
10519 				(errcode(ERRCODE_UNDEFINED_OBJECT),
10520 				 errmsg("constraint \"%s\" of relation \"%s\" does not exist",
10521 						constrName, RelationGetRelationName(rel))));
10522 
10523 	con = (Form_pg_constraint) GETSTRUCT(tuple);
10524 	if (con->contype != CONSTRAINT_FOREIGN &&
10525 		con->contype != CONSTRAINT_CHECK)
10526 		ereport(ERROR,
10527 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
10528 				 errmsg("constraint \"%s\" of relation \"%s\" is not a foreign key or check constraint",
10529 						constrName, RelationGetRelationName(rel))));
10530 
10531 	if (!con->convalidated)
10532 	{
10533 		AlteredTableInfo *tab;
10534 		HeapTuple	copyTuple;
10535 		Form_pg_constraint copy_con;
10536 
10537 		if (con->contype == CONSTRAINT_FOREIGN)
10538 		{
10539 			NewConstraint *newcon;
10540 			Constraint *fkconstraint;
10541 
10542 			/* Queue validation for phase 3 */
10543 			fkconstraint = makeNode(Constraint);
10544 			/* for now this is all we need */
10545 			fkconstraint->conname = constrName;
10546 
10547 			newcon = (NewConstraint *) palloc0(sizeof(NewConstraint));
10548 			newcon->name = constrName;
10549 			newcon->contype = CONSTR_FOREIGN;
10550 			newcon->refrelid = con->confrelid;
10551 			newcon->refindid = con->conindid;
10552 			newcon->conid = con->oid;
10553 			newcon->qual = (Node *) fkconstraint;
10554 
10555 			/* Find or create work queue entry for this table */
10556 			tab = ATGetQueueEntry(wqueue, rel);
10557 			tab->constraints = lappend(tab->constraints, newcon);
10558 
10559 			/*
10560 			 * We disallow creating invalid foreign keys to or from
10561 			 * partitioned tables, so ignoring the recursion bit is okay.
10562 			 */
10563 		}
10564 		else if (con->contype == CONSTRAINT_CHECK)
10565 		{
10566 			List	   *children = NIL;
10567 			ListCell   *child;
10568 			NewConstraint *newcon;
10569 			bool		isnull;
10570 			Datum		val;
10571 			char	   *conbin;
10572 
10573 			/*
10574 			 * If we're recursing, the parent has already done this, so skip
10575 			 * it.  Also, if the constraint is a NO INHERIT constraint, we
10576 			 * shouldn't try to look for it in the children.
10577 			 */
10578 			if (!recursing && !con->connoinherit)
10579 				children = find_all_inheritors(RelationGetRelid(rel),
10580 											   lockmode, NULL);
10581 
10582 			/*
10583 			 * For CHECK constraints, we must ensure that we only mark the
10584 			 * constraint as validated on the parent if it's already validated
10585 			 * on the children.
10586 			 *
10587 			 * We recurse before validating on the parent, to reduce risk of
10588 			 * deadlocks.
10589 			 */
10590 			foreach(child, children)
10591 			{
10592 				Oid			childoid = lfirst_oid(child);
10593 				Relation	childrel;
10594 
10595 				if (childoid == RelationGetRelid(rel))
10596 					continue;
10597 
10598 				/*
10599 				 * If we are told not to recurse, there had better not be any
10600 				 * child tables, because we can't mark the constraint on the
10601 				 * parent valid unless it is valid for all child tables.
10602 				 */
10603 				if (!recurse)
10604 					ereport(ERROR,
10605 							(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
10606 							 errmsg("constraint must be validated on child tables too")));
10607 
10608 				/* find_all_inheritors already got lock */
10609 				childrel = table_open(childoid, NoLock);
10610 
10611 				ATExecValidateConstraint(wqueue, childrel, constrName, false,
10612 										 true, lockmode);
10613 				table_close(childrel, NoLock);
10614 			}
10615 
10616 			/* Queue validation for phase 3 */
10617 			newcon = (NewConstraint *) palloc0(sizeof(NewConstraint));
10618 			newcon->name = constrName;
10619 			newcon->contype = CONSTR_CHECK;
10620 			newcon->refrelid = InvalidOid;
10621 			newcon->refindid = InvalidOid;
10622 			newcon->conid = con->oid;
10623 
10624 			val = SysCacheGetAttr(CONSTROID, tuple,
10625 								  Anum_pg_constraint_conbin, &isnull);
10626 			if (isnull)
10627 				elog(ERROR, "null conbin for constraint %u", con->oid);
10628 
10629 			conbin = TextDatumGetCString(val);
10630 			newcon->qual = (Node *) stringToNode(conbin);
10631 
10632 			/* Find or create work queue entry for this table */
10633 			tab = ATGetQueueEntry(wqueue, rel);
10634 			tab->constraints = lappend(tab->constraints, newcon);
10635 
10636 			/*
10637 			 * Invalidate relcache so that others see the new validated
10638 			 * constraint.
10639 			 */
10640 			CacheInvalidateRelcache(rel);
10641 		}
10642 
10643 		/*
10644 		 * Now update the catalog, while we have the door open.
10645 		 */
10646 		copyTuple = heap_copytuple(tuple);
10647 		copy_con = (Form_pg_constraint) GETSTRUCT(copyTuple);
10648 		copy_con->convalidated = true;
10649 		CatalogTupleUpdate(conrel, &copyTuple->t_self, copyTuple);
10650 
10651 		InvokeObjectPostAlterHook(ConstraintRelationId, con->oid, 0);
10652 
10653 		heap_freetuple(copyTuple);
10654 
10655 		ObjectAddressSet(address, ConstraintRelationId, con->oid);
10656 	}
10657 	else
10658 		address = InvalidObjectAddress; /* already validated */
10659 
10660 	systable_endscan(scan);
10661 
10662 	table_close(conrel, RowExclusiveLock);
10663 
10664 	return address;
10665 }
10666 
10667 
10668 /*
10669  * transformColumnNameList - transform list of column names
10670  *
10671  * Lookup each name and return its attnum and type OID
10672  */
10673 static int
transformColumnNameList(Oid relId,List * colList,int16 * attnums,Oid * atttypids)10674 transformColumnNameList(Oid relId, List *colList,
10675 						int16 *attnums, Oid *atttypids)
10676 {
10677 	ListCell   *l;
10678 	int			attnum;
10679 
10680 	attnum = 0;
10681 	foreach(l, colList)
10682 	{
10683 		char	   *attname = strVal(lfirst(l));
10684 		HeapTuple	atttuple;
10685 
10686 		atttuple = SearchSysCacheAttName(relId, attname);
10687 		if (!HeapTupleIsValid(atttuple))
10688 			ereport(ERROR,
10689 					(errcode(ERRCODE_UNDEFINED_COLUMN),
10690 					 errmsg("column \"%s\" referenced in foreign key constraint does not exist",
10691 							attname)));
10692 		if (attnum >= INDEX_MAX_KEYS)
10693 			ereport(ERROR,
10694 					(errcode(ERRCODE_TOO_MANY_COLUMNS),
10695 					 errmsg("cannot have more than %d keys in a foreign key",
10696 							INDEX_MAX_KEYS)));
10697 		attnums[attnum] = ((Form_pg_attribute) GETSTRUCT(atttuple))->attnum;
10698 		atttypids[attnum] = ((Form_pg_attribute) GETSTRUCT(atttuple))->atttypid;
10699 		ReleaseSysCache(atttuple);
10700 		attnum++;
10701 	}
10702 
10703 	return attnum;
10704 }
10705 
10706 /*
10707  * transformFkeyGetPrimaryKey -
10708  *
10709  *	Look up the names, attnums, and types of the primary key attributes
10710  *	for the pkrel.  Also return the index OID and index opclasses of the
10711  *	index supporting the primary key.
10712  *
10713  *	All parameters except pkrel are output parameters.  Also, the function
10714  *	return value is the number of attributes in the primary key.
10715  *
10716  *	Used when the column list in the REFERENCES specification is omitted.
10717  */
10718 static int
transformFkeyGetPrimaryKey(Relation pkrel,Oid * indexOid,List ** attnamelist,int16 * attnums,Oid * atttypids,Oid * opclasses)10719 transformFkeyGetPrimaryKey(Relation pkrel, Oid *indexOid,
10720 						   List **attnamelist,
10721 						   int16 *attnums, Oid *atttypids,
10722 						   Oid *opclasses)
10723 {
10724 	List	   *indexoidlist;
10725 	ListCell   *indexoidscan;
10726 	HeapTuple	indexTuple = NULL;
10727 	Form_pg_index indexStruct = NULL;
10728 	Datum		indclassDatum;
10729 	bool		isnull;
10730 	oidvector  *indclass;
10731 	int			i;
10732 
10733 	/*
10734 	 * Get the list of index OIDs for the table from the relcache, and look up
10735 	 * each one in the pg_index syscache until we find one marked primary key
10736 	 * (hopefully there isn't more than one such).  Insist it's valid, too.
10737 	 */
10738 	*indexOid = InvalidOid;
10739 
10740 	indexoidlist = RelationGetIndexList(pkrel);
10741 
10742 	foreach(indexoidscan, indexoidlist)
10743 	{
10744 		Oid			indexoid = lfirst_oid(indexoidscan);
10745 
10746 		indexTuple = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(indexoid));
10747 		if (!HeapTupleIsValid(indexTuple))
10748 			elog(ERROR, "cache lookup failed for index %u", indexoid);
10749 		indexStruct = (Form_pg_index) GETSTRUCT(indexTuple);
10750 		if (indexStruct->indisprimary && indexStruct->indisvalid)
10751 		{
10752 			/*
10753 			 * Refuse to use a deferrable primary key.  This is per SQL spec,
10754 			 * and there would be a lot of interesting semantic problems if we
10755 			 * tried to allow it.
10756 			 */
10757 			if (!indexStruct->indimmediate)
10758 				ereport(ERROR,
10759 						(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
10760 						 errmsg("cannot use a deferrable primary key for referenced table \"%s\"",
10761 								RelationGetRelationName(pkrel))));
10762 
10763 			*indexOid = indexoid;
10764 			break;
10765 		}
10766 		ReleaseSysCache(indexTuple);
10767 	}
10768 
10769 	list_free(indexoidlist);
10770 
10771 	/*
10772 	 * Check that we found it
10773 	 */
10774 	if (!OidIsValid(*indexOid))
10775 		ereport(ERROR,
10776 				(errcode(ERRCODE_UNDEFINED_OBJECT),
10777 				 errmsg("there is no primary key for referenced table \"%s\"",
10778 						RelationGetRelationName(pkrel))));
10779 
10780 	/* Must get indclass the hard way */
10781 	indclassDatum = SysCacheGetAttr(INDEXRELID, indexTuple,
10782 									Anum_pg_index_indclass, &isnull);
10783 	Assert(!isnull);
10784 	indclass = (oidvector *) DatumGetPointer(indclassDatum);
10785 
10786 	/*
10787 	 * Now build the list of PK attributes from the indkey definition (we
10788 	 * assume a primary key cannot have expressional elements)
10789 	 */
10790 	*attnamelist = NIL;
10791 	for (i = 0; i < indexStruct->indnkeyatts; i++)
10792 	{
10793 		int			pkattno = indexStruct->indkey.values[i];
10794 
10795 		attnums[i] = pkattno;
10796 		atttypids[i] = attnumTypeId(pkrel, pkattno);
10797 		opclasses[i] = indclass->values[i];
10798 		*attnamelist = lappend(*attnamelist,
10799 							   makeString(pstrdup(NameStr(*attnumAttName(pkrel, pkattno)))));
10800 	}
10801 
10802 	ReleaseSysCache(indexTuple);
10803 
10804 	return i;
10805 }
10806 
10807 /*
10808  * transformFkeyCheckAttrs -
10809  *
10810  *	Make sure that the attributes of a referenced table belong to a unique
10811  *	(or primary key) constraint.  Return the OID of the index supporting
10812  *	the constraint, as well as the opclasses associated with the index
10813  *	columns.
10814  */
10815 static Oid
transformFkeyCheckAttrs(Relation pkrel,int numattrs,int16 * attnums,Oid * opclasses)10816 transformFkeyCheckAttrs(Relation pkrel,
10817 						int numattrs, int16 *attnums,
10818 						Oid *opclasses) /* output parameter */
10819 {
10820 	Oid			indexoid = InvalidOid;
10821 	bool		found = false;
10822 	bool		found_deferrable = false;
10823 	List	   *indexoidlist;
10824 	ListCell   *indexoidscan;
10825 	int			i,
10826 				j;
10827 
10828 	/*
10829 	 * Reject duplicate appearances of columns in the referenced-columns list.
10830 	 * Such a case is forbidden by the SQL standard, and even if we thought it
10831 	 * useful to allow it, there would be ambiguity about how to match the
10832 	 * list to unique indexes (in particular, it'd be unclear which index
10833 	 * opclass goes with which FK column).
10834 	 */
10835 	for (i = 0; i < numattrs; i++)
10836 	{
10837 		for (j = i + 1; j < numattrs; j++)
10838 		{
10839 			if (attnums[i] == attnums[j])
10840 				ereport(ERROR,
10841 						(errcode(ERRCODE_INVALID_FOREIGN_KEY),
10842 						 errmsg("foreign key referenced-columns list must not contain duplicates")));
10843 		}
10844 	}
10845 
10846 	/*
10847 	 * Get the list of index OIDs for the table from the relcache, and look up
10848 	 * each one in the pg_index syscache, and match unique indexes to the list
10849 	 * of attnums we are given.
10850 	 */
10851 	indexoidlist = RelationGetIndexList(pkrel);
10852 
10853 	foreach(indexoidscan, indexoidlist)
10854 	{
10855 		HeapTuple	indexTuple;
10856 		Form_pg_index indexStruct;
10857 
10858 		indexoid = lfirst_oid(indexoidscan);
10859 		indexTuple = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(indexoid));
10860 		if (!HeapTupleIsValid(indexTuple))
10861 			elog(ERROR, "cache lookup failed for index %u", indexoid);
10862 		indexStruct = (Form_pg_index) GETSTRUCT(indexTuple);
10863 
10864 		/*
10865 		 * Must have the right number of columns; must be unique and not a
10866 		 * partial index; forget it if there are any expressions, too. Invalid
10867 		 * indexes are out as well.
10868 		 */
10869 		if (indexStruct->indnkeyatts == numattrs &&
10870 			indexStruct->indisunique &&
10871 			indexStruct->indisvalid &&
10872 			heap_attisnull(indexTuple, Anum_pg_index_indpred, NULL) &&
10873 			heap_attisnull(indexTuple, Anum_pg_index_indexprs, NULL))
10874 		{
10875 			Datum		indclassDatum;
10876 			bool		isnull;
10877 			oidvector  *indclass;
10878 
10879 			/* Must get indclass the hard way */
10880 			indclassDatum = SysCacheGetAttr(INDEXRELID, indexTuple,
10881 											Anum_pg_index_indclass, &isnull);
10882 			Assert(!isnull);
10883 			indclass = (oidvector *) DatumGetPointer(indclassDatum);
10884 
10885 			/*
10886 			 * The given attnum list may match the index columns in any order.
10887 			 * Check for a match, and extract the appropriate opclasses while
10888 			 * we're at it.
10889 			 *
10890 			 * We know that attnums[] is duplicate-free per the test at the
10891 			 * start of this function, and we checked above that the number of
10892 			 * index columns agrees, so if we find a match for each attnums[]
10893 			 * entry then we must have a one-to-one match in some order.
10894 			 */
10895 			for (i = 0; i < numattrs; i++)
10896 			{
10897 				found = false;
10898 				for (j = 0; j < numattrs; j++)
10899 				{
10900 					if (attnums[i] == indexStruct->indkey.values[j])
10901 					{
10902 						opclasses[i] = indclass->values[j];
10903 						found = true;
10904 						break;
10905 					}
10906 				}
10907 				if (!found)
10908 					break;
10909 			}
10910 
10911 			/*
10912 			 * Refuse to use a deferrable unique/primary key.  This is per SQL
10913 			 * spec, and there would be a lot of interesting semantic problems
10914 			 * if we tried to allow it.
10915 			 */
10916 			if (found && !indexStruct->indimmediate)
10917 			{
10918 				/*
10919 				 * Remember that we found an otherwise matching index, so that
10920 				 * we can generate a more appropriate error message.
10921 				 */
10922 				found_deferrable = true;
10923 				found = false;
10924 			}
10925 		}
10926 		ReleaseSysCache(indexTuple);
10927 		if (found)
10928 			break;
10929 	}
10930 
10931 	if (!found)
10932 	{
10933 		if (found_deferrable)
10934 			ereport(ERROR,
10935 					(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
10936 					 errmsg("cannot use a deferrable unique constraint for referenced table \"%s\"",
10937 							RelationGetRelationName(pkrel))));
10938 		else
10939 			ereport(ERROR,
10940 					(errcode(ERRCODE_INVALID_FOREIGN_KEY),
10941 					 errmsg("there is no unique constraint matching given keys for referenced table \"%s\"",
10942 							RelationGetRelationName(pkrel))));
10943 	}
10944 
10945 	list_free(indexoidlist);
10946 
10947 	return indexoid;
10948 }
10949 
10950 /*
10951  * findFkeyCast -
10952  *
10953  *	Wrapper around find_coercion_pathway() for ATAddForeignKeyConstraint().
10954  *	Caller has equal regard for binary coercibility and for an exact match.
10955 */
10956 static CoercionPathType
findFkeyCast(Oid targetTypeId,Oid sourceTypeId,Oid * funcid)10957 findFkeyCast(Oid targetTypeId, Oid sourceTypeId, Oid *funcid)
10958 {
10959 	CoercionPathType ret;
10960 
10961 	if (targetTypeId == sourceTypeId)
10962 	{
10963 		ret = COERCION_PATH_RELABELTYPE;
10964 		*funcid = InvalidOid;
10965 	}
10966 	else
10967 	{
10968 		ret = find_coercion_pathway(targetTypeId, sourceTypeId,
10969 									COERCION_IMPLICIT, funcid);
10970 		if (ret == COERCION_PATH_NONE)
10971 			/* A previously-relied-upon cast is now gone. */
10972 			elog(ERROR, "could not find cast from %u to %u",
10973 				 sourceTypeId, targetTypeId);
10974 	}
10975 
10976 	return ret;
10977 }
10978 
10979 /*
10980  * Permissions checks on the referenced table for ADD FOREIGN KEY
10981  *
10982  * Note: we have already checked that the user owns the referencing table,
10983  * else we'd have failed much earlier; no additional checks are needed for it.
10984  */
10985 static void
checkFkeyPermissions(Relation rel,int16 * attnums,int natts)10986 checkFkeyPermissions(Relation rel, int16 *attnums, int natts)
10987 {
10988 	Oid			roleid = GetUserId();
10989 	AclResult	aclresult;
10990 	int			i;
10991 
10992 	/* Okay if we have relation-level REFERENCES permission */
10993 	aclresult = pg_class_aclcheck(RelationGetRelid(rel), roleid,
10994 								  ACL_REFERENCES);
10995 	if (aclresult == ACLCHECK_OK)
10996 		return;
10997 	/* Else we must have REFERENCES on each column */
10998 	for (i = 0; i < natts; i++)
10999 	{
11000 		aclresult = pg_attribute_aclcheck(RelationGetRelid(rel), attnums[i],
11001 										  roleid, ACL_REFERENCES);
11002 		if (aclresult != ACLCHECK_OK)
11003 			aclcheck_error(aclresult, get_relkind_objtype(rel->rd_rel->relkind),
11004 						   RelationGetRelationName(rel));
11005 	}
11006 }
11007 
11008 /*
11009  * Scan the existing rows in a table to verify they meet a proposed FK
11010  * constraint.
11011  *
11012  * Caller must have opened and locked both relations appropriately.
11013  */
11014 static void
validateForeignKeyConstraint(char * conname,Relation rel,Relation pkrel,Oid pkindOid,Oid constraintOid)11015 validateForeignKeyConstraint(char *conname,
11016 							 Relation rel,
11017 							 Relation pkrel,
11018 							 Oid pkindOid,
11019 							 Oid constraintOid)
11020 {
11021 	TupleTableSlot *slot;
11022 	TableScanDesc scan;
11023 	Trigger		trig;
11024 	Snapshot	snapshot;
11025 	MemoryContext oldcxt;
11026 	MemoryContext perTupCxt;
11027 
11028 	ereport(DEBUG1,
11029 			(errmsg_internal("validating foreign key constraint \"%s\"", conname)));
11030 
11031 	/*
11032 	 * Build a trigger call structure; we'll need it either way.
11033 	 */
11034 	MemSet(&trig, 0, sizeof(trig));
11035 	trig.tgoid = InvalidOid;
11036 	trig.tgname = conname;
11037 	trig.tgenabled = TRIGGER_FIRES_ON_ORIGIN;
11038 	trig.tgisinternal = true;
11039 	trig.tgconstrrelid = RelationGetRelid(pkrel);
11040 	trig.tgconstrindid = pkindOid;
11041 	trig.tgconstraint = constraintOid;
11042 	trig.tgdeferrable = false;
11043 	trig.tginitdeferred = false;
11044 	/* we needn't fill in remaining fields */
11045 
11046 	/*
11047 	 * See if we can do it with a single LEFT JOIN query.  A false result
11048 	 * indicates we must proceed with the fire-the-trigger method.
11049 	 */
11050 	if (RI_Initial_Check(&trig, rel, pkrel))
11051 		return;
11052 
11053 	/*
11054 	 * Scan through each tuple, calling RI_FKey_check_ins (insert trigger) as
11055 	 * if that tuple had just been inserted.  If any of those fail, it should
11056 	 * ereport(ERROR) and that's that.
11057 	 */
11058 	snapshot = RegisterSnapshot(GetLatestSnapshot());
11059 	slot = table_slot_create(rel, NULL);
11060 	scan = table_beginscan(rel, snapshot, 0, NULL);
11061 
11062 	perTupCxt = AllocSetContextCreate(CurrentMemoryContext,
11063 									  "validateForeignKeyConstraint",
11064 									  ALLOCSET_SMALL_SIZES);
11065 	oldcxt = MemoryContextSwitchTo(perTupCxt);
11066 
11067 	while (table_scan_getnextslot(scan, ForwardScanDirection, slot))
11068 	{
11069 		LOCAL_FCINFO(fcinfo, 0);
11070 		TriggerData trigdata = {0};
11071 
11072 		CHECK_FOR_INTERRUPTS();
11073 
11074 		/*
11075 		 * Make a call to the trigger function
11076 		 *
11077 		 * No parameters are passed, but we do set a context
11078 		 */
11079 		MemSet(fcinfo, 0, SizeForFunctionCallInfo(0));
11080 
11081 		/*
11082 		 * We assume RI_FKey_check_ins won't look at flinfo...
11083 		 */
11084 		trigdata.type = T_TriggerData;
11085 		trigdata.tg_event = TRIGGER_EVENT_INSERT | TRIGGER_EVENT_ROW;
11086 		trigdata.tg_relation = rel;
11087 		trigdata.tg_trigtuple = ExecFetchSlotHeapTuple(slot, false, NULL);
11088 		trigdata.tg_trigslot = slot;
11089 		trigdata.tg_trigger = &trig;
11090 
11091 		fcinfo->context = (Node *) &trigdata;
11092 
11093 		RI_FKey_check_ins(fcinfo);
11094 
11095 		MemoryContextReset(perTupCxt);
11096 	}
11097 
11098 	MemoryContextSwitchTo(oldcxt);
11099 	MemoryContextDelete(perTupCxt);
11100 	table_endscan(scan);
11101 	UnregisterSnapshot(snapshot);
11102 	ExecDropSingleTupleTableSlot(slot);
11103 }
11104 
11105 static void
CreateFKCheckTrigger(Oid myRelOid,Oid refRelOid,Constraint * fkconstraint,Oid constraintOid,Oid indexOid,bool on_insert)11106 CreateFKCheckTrigger(Oid myRelOid, Oid refRelOid, Constraint *fkconstraint,
11107 					 Oid constraintOid, Oid indexOid, bool on_insert)
11108 {
11109 	CreateTrigStmt *fk_trigger;
11110 
11111 	/*
11112 	 * Note: for a self-referential FK (referencing and referenced tables are
11113 	 * the same), it is important that the ON UPDATE action fires before the
11114 	 * CHECK action, since both triggers will fire on the same row during an
11115 	 * UPDATE event; otherwise the CHECK trigger will be checking a non-final
11116 	 * state of the row.  Triggers fire in name order, so we ensure this by
11117 	 * using names like "RI_ConstraintTrigger_a_NNNN" for the action triggers
11118 	 * and "RI_ConstraintTrigger_c_NNNN" for the check triggers.
11119 	 */
11120 	fk_trigger = makeNode(CreateTrigStmt);
11121 	fk_trigger->replace = false;
11122 	fk_trigger->isconstraint = true;
11123 	fk_trigger->trigname = "RI_ConstraintTrigger_c";
11124 	fk_trigger->relation = NULL;
11125 
11126 	/* Either ON INSERT or ON UPDATE */
11127 	if (on_insert)
11128 	{
11129 		fk_trigger->funcname = SystemFuncName("RI_FKey_check_ins");
11130 		fk_trigger->events = TRIGGER_TYPE_INSERT;
11131 	}
11132 	else
11133 	{
11134 		fk_trigger->funcname = SystemFuncName("RI_FKey_check_upd");
11135 		fk_trigger->events = TRIGGER_TYPE_UPDATE;
11136 	}
11137 
11138 	fk_trigger->args = NIL;
11139 	fk_trigger->row = true;
11140 	fk_trigger->timing = TRIGGER_TYPE_AFTER;
11141 	fk_trigger->columns = NIL;
11142 	fk_trigger->whenClause = NULL;
11143 	fk_trigger->transitionRels = NIL;
11144 	fk_trigger->deferrable = fkconstraint->deferrable;
11145 	fk_trigger->initdeferred = fkconstraint->initdeferred;
11146 	fk_trigger->constrrel = NULL;
11147 
11148 	(void) CreateTrigger(fk_trigger, NULL, myRelOid, refRelOid, constraintOid,
11149 						 indexOid, InvalidOid, InvalidOid, NULL, true, false);
11150 
11151 	/* Make changes-so-far visible */
11152 	CommandCounterIncrement();
11153 }
11154 
11155 /*
11156  * createForeignKeyActionTriggers
11157  *		Create the referenced-side "action" triggers that implement a foreign
11158  *		key.
11159  */
11160 static void
createForeignKeyActionTriggers(Relation rel,Oid refRelOid,Constraint * fkconstraint,Oid constraintOid,Oid indexOid)11161 createForeignKeyActionTriggers(Relation rel, Oid refRelOid, Constraint *fkconstraint,
11162 							   Oid constraintOid, Oid indexOid)
11163 {
11164 	CreateTrigStmt *fk_trigger;
11165 
11166 	/*
11167 	 * Build and execute a CREATE CONSTRAINT TRIGGER statement for the ON
11168 	 * DELETE action on the referenced table.
11169 	 */
11170 	fk_trigger = makeNode(CreateTrigStmt);
11171 	fk_trigger->replace = false;
11172 	fk_trigger->isconstraint = true;
11173 	fk_trigger->trigname = "RI_ConstraintTrigger_a";
11174 	fk_trigger->relation = NULL;
11175 	fk_trigger->args = NIL;
11176 	fk_trigger->row = true;
11177 	fk_trigger->timing = TRIGGER_TYPE_AFTER;
11178 	fk_trigger->events = TRIGGER_TYPE_DELETE;
11179 	fk_trigger->columns = NIL;
11180 	fk_trigger->whenClause = NULL;
11181 	fk_trigger->transitionRels = NIL;
11182 	fk_trigger->constrrel = NULL;
11183 	switch (fkconstraint->fk_del_action)
11184 	{
11185 		case FKCONSTR_ACTION_NOACTION:
11186 			fk_trigger->deferrable = fkconstraint->deferrable;
11187 			fk_trigger->initdeferred = fkconstraint->initdeferred;
11188 			fk_trigger->funcname = SystemFuncName("RI_FKey_noaction_del");
11189 			break;
11190 		case FKCONSTR_ACTION_RESTRICT:
11191 			fk_trigger->deferrable = false;
11192 			fk_trigger->initdeferred = false;
11193 			fk_trigger->funcname = SystemFuncName("RI_FKey_restrict_del");
11194 			break;
11195 		case FKCONSTR_ACTION_CASCADE:
11196 			fk_trigger->deferrable = false;
11197 			fk_trigger->initdeferred = false;
11198 			fk_trigger->funcname = SystemFuncName("RI_FKey_cascade_del");
11199 			break;
11200 		case FKCONSTR_ACTION_SETNULL:
11201 			fk_trigger->deferrable = false;
11202 			fk_trigger->initdeferred = false;
11203 			fk_trigger->funcname = SystemFuncName("RI_FKey_setnull_del");
11204 			break;
11205 		case FKCONSTR_ACTION_SETDEFAULT:
11206 			fk_trigger->deferrable = false;
11207 			fk_trigger->initdeferred = false;
11208 			fk_trigger->funcname = SystemFuncName("RI_FKey_setdefault_del");
11209 			break;
11210 		default:
11211 			elog(ERROR, "unrecognized FK action type: %d",
11212 				 (int) fkconstraint->fk_del_action);
11213 			break;
11214 	}
11215 
11216 	(void) CreateTrigger(fk_trigger, NULL, refRelOid, RelationGetRelid(rel),
11217 						 constraintOid,
11218 						 indexOid, InvalidOid, InvalidOid, NULL, true, false);
11219 
11220 	/* Make changes-so-far visible */
11221 	CommandCounterIncrement();
11222 
11223 	/*
11224 	 * Build and execute a CREATE CONSTRAINT TRIGGER statement for the ON
11225 	 * UPDATE action on the referenced table.
11226 	 */
11227 	fk_trigger = makeNode(CreateTrigStmt);
11228 	fk_trigger->replace = false;
11229 	fk_trigger->isconstraint = true;
11230 	fk_trigger->trigname = "RI_ConstraintTrigger_a";
11231 	fk_trigger->relation = NULL;
11232 	fk_trigger->args = NIL;
11233 	fk_trigger->row = true;
11234 	fk_trigger->timing = TRIGGER_TYPE_AFTER;
11235 	fk_trigger->events = TRIGGER_TYPE_UPDATE;
11236 	fk_trigger->columns = NIL;
11237 	fk_trigger->whenClause = NULL;
11238 	fk_trigger->transitionRels = NIL;
11239 	fk_trigger->constrrel = NULL;
11240 	switch (fkconstraint->fk_upd_action)
11241 	{
11242 		case FKCONSTR_ACTION_NOACTION:
11243 			fk_trigger->deferrable = fkconstraint->deferrable;
11244 			fk_trigger->initdeferred = fkconstraint->initdeferred;
11245 			fk_trigger->funcname = SystemFuncName("RI_FKey_noaction_upd");
11246 			break;
11247 		case FKCONSTR_ACTION_RESTRICT:
11248 			fk_trigger->deferrable = false;
11249 			fk_trigger->initdeferred = false;
11250 			fk_trigger->funcname = SystemFuncName("RI_FKey_restrict_upd");
11251 			break;
11252 		case FKCONSTR_ACTION_CASCADE:
11253 			fk_trigger->deferrable = false;
11254 			fk_trigger->initdeferred = false;
11255 			fk_trigger->funcname = SystemFuncName("RI_FKey_cascade_upd");
11256 			break;
11257 		case FKCONSTR_ACTION_SETNULL:
11258 			fk_trigger->deferrable = false;
11259 			fk_trigger->initdeferred = false;
11260 			fk_trigger->funcname = SystemFuncName("RI_FKey_setnull_upd");
11261 			break;
11262 		case FKCONSTR_ACTION_SETDEFAULT:
11263 			fk_trigger->deferrable = false;
11264 			fk_trigger->initdeferred = false;
11265 			fk_trigger->funcname = SystemFuncName("RI_FKey_setdefault_upd");
11266 			break;
11267 		default:
11268 			elog(ERROR, "unrecognized FK action type: %d",
11269 				 (int) fkconstraint->fk_upd_action);
11270 			break;
11271 	}
11272 
11273 	(void) CreateTrigger(fk_trigger, NULL, refRelOid, RelationGetRelid(rel),
11274 						 constraintOid,
11275 						 indexOid, InvalidOid, InvalidOid, NULL, true, false);
11276 }
11277 
11278 /*
11279  * createForeignKeyCheckTriggers
11280  *		Create the referencing-side "check" triggers that implement a foreign
11281  *		key.
11282  */
11283 static void
createForeignKeyCheckTriggers(Oid myRelOid,Oid refRelOid,Constraint * fkconstraint,Oid constraintOid,Oid indexOid)11284 createForeignKeyCheckTriggers(Oid myRelOid, Oid refRelOid,
11285 							  Constraint *fkconstraint, Oid constraintOid,
11286 							  Oid indexOid)
11287 {
11288 	CreateFKCheckTrigger(myRelOid, refRelOid, fkconstraint, constraintOid,
11289 						 indexOid, true);
11290 	CreateFKCheckTrigger(myRelOid, refRelOid, fkconstraint, constraintOid,
11291 						 indexOid, false);
11292 }
11293 
11294 /*
11295  * ALTER TABLE DROP CONSTRAINT
11296  *
11297  * Like DROP COLUMN, we can't use the normal ALTER TABLE recursion mechanism.
11298  */
11299 static void
ATExecDropConstraint(Relation rel,const char * constrName,DropBehavior behavior,bool recurse,bool recursing,bool missing_ok,LOCKMODE lockmode)11300 ATExecDropConstraint(Relation rel, const char *constrName,
11301 					 DropBehavior behavior,
11302 					 bool recurse, bool recursing,
11303 					 bool missing_ok, LOCKMODE lockmode)
11304 {
11305 	List	   *children;
11306 	ListCell   *child;
11307 	Relation	conrel;
11308 	Form_pg_constraint con;
11309 	SysScanDesc scan;
11310 	ScanKeyData skey[3];
11311 	HeapTuple	tuple;
11312 	bool		found = false;
11313 	bool		is_no_inherit_constraint = false;
11314 	char		contype;
11315 
11316 	/* At top level, permission check was done in ATPrepCmd, else do it */
11317 	if (recursing)
11318 		ATSimplePermissions(rel, ATT_TABLE | ATT_FOREIGN_TABLE);
11319 
11320 	conrel = table_open(ConstraintRelationId, RowExclusiveLock);
11321 
11322 	/*
11323 	 * Find and drop the target constraint
11324 	 */
11325 	ScanKeyInit(&skey[0],
11326 				Anum_pg_constraint_conrelid,
11327 				BTEqualStrategyNumber, F_OIDEQ,
11328 				ObjectIdGetDatum(RelationGetRelid(rel)));
11329 	ScanKeyInit(&skey[1],
11330 				Anum_pg_constraint_contypid,
11331 				BTEqualStrategyNumber, F_OIDEQ,
11332 				ObjectIdGetDatum(InvalidOid));
11333 	ScanKeyInit(&skey[2],
11334 				Anum_pg_constraint_conname,
11335 				BTEqualStrategyNumber, F_NAMEEQ,
11336 				CStringGetDatum(constrName));
11337 	scan = systable_beginscan(conrel, ConstraintRelidTypidNameIndexId,
11338 							  true, NULL, 3, skey);
11339 
11340 	/* There can be at most one matching row */
11341 	if (HeapTupleIsValid(tuple = systable_getnext(scan)))
11342 	{
11343 		ObjectAddress conobj;
11344 
11345 		con = (Form_pg_constraint) GETSTRUCT(tuple);
11346 
11347 		/* Don't drop inherited constraints */
11348 		if (con->coninhcount > 0 && !recursing)
11349 			ereport(ERROR,
11350 					(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
11351 					 errmsg("cannot drop inherited constraint \"%s\" of relation \"%s\"",
11352 							constrName, RelationGetRelationName(rel))));
11353 
11354 		is_no_inherit_constraint = con->connoinherit;
11355 		contype = con->contype;
11356 
11357 		/*
11358 		 * If it's a foreign-key constraint, we'd better lock the referenced
11359 		 * table and check that that's not in use, just as we've already done
11360 		 * for the constrained table (else we might, eg, be dropping a trigger
11361 		 * that has unfired events).  But we can/must skip that in the
11362 		 * self-referential case.
11363 		 */
11364 		if (contype == CONSTRAINT_FOREIGN &&
11365 			con->confrelid != RelationGetRelid(rel))
11366 		{
11367 			Relation	frel;
11368 
11369 			/* Must match lock taken by RemoveTriggerById: */
11370 			frel = table_open(con->confrelid, AccessExclusiveLock);
11371 			CheckTableNotInUse(frel, "ALTER TABLE");
11372 			table_close(frel, NoLock);
11373 		}
11374 
11375 		/*
11376 		 * Perform the actual constraint deletion
11377 		 */
11378 		conobj.classId = ConstraintRelationId;
11379 		conobj.objectId = con->oid;
11380 		conobj.objectSubId = 0;
11381 
11382 		performDeletion(&conobj, behavior, 0);
11383 
11384 		found = true;
11385 	}
11386 
11387 	systable_endscan(scan);
11388 
11389 	if (!found)
11390 	{
11391 		if (!missing_ok)
11392 		{
11393 			ereport(ERROR,
11394 					(errcode(ERRCODE_UNDEFINED_OBJECT),
11395 					 errmsg("constraint \"%s\" of relation \"%s\" does not exist",
11396 							constrName, RelationGetRelationName(rel))));
11397 		}
11398 		else
11399 		{
11400 			ereport(NOTICE,
11401 					(errmsg("constraint \"%s\" of relation \"%s\" does not exist, skipping",
11402 							constrName, RelationGetRelationName(rel))));
11403 			table_close(conrel, RowExclusiveLock);
11404 			return;
11405 		}
11406 	}
11407 
11408 	/*
11409 	 * For partitioned tables, non-CHECK inherited constraints are dropped via
11410 	 * the dependency mechanism, so we're done here.
11411 	 */
11412 	if (contype != CONSTRAINT_CHECK &&
11413 		rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
11414 	{
11415 		table_close(conrel, RowExclusiveLock);
11416 		return;
11417 	}
11418 
11419 	/*
11420 	 * Propagate to children as appropriate.  Unlike most other ALTER
11421 	 * routines, we have to do this one level of recursion at a time; we can't
11422 	 * use find_all_inheritors to do it in one pass.
11423 	 */
11424 	if (!is_no_inherit_constraint)
11425 		children = find_inheritance_children(RelationGetRelid(rel), lockmode);
11426 	else
11427 		children = NIL;
11428 
11429 	/*
11430 	 * For a partitioned table, if partitions exist and we are told not to
11431 	 * recurse, it's a user error.  It doesn't make sense to have a constraint
11432 	 * be defined only on the parent, especially if it's a partitioned table.
11433 	 */
11434 	if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE &&
11435 		children != NIL && !recurse)
11436 		ereport(ERROR,
11437 				(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
11438 				 errmsg("cannot remove constraint from only the partitioned table when partitions exist"),
11439 				 errhint("Do not specify the ONLY keyword.")));
11440 
11441 	foreach(child, children)
11442 	{
11443 		Oid			childrelid = lfirst_oid(child);
11444 		Relation	childrel;
11445 		HeapTuple	copy_tuple;
11446 
11447 		/* find_inheritance_children already got lock */
11448 		childrel = table_open(childrelid, NoLock);
11449 		CheckTableNotInUse(childrel, "ALTER TABLE");
11450 
11451 		ScanKeyInit(&skey[0],
11452 					Anum_pg_constraint_conrelid,
11453 					BTEqualStrategyNumber, F_OIDEQ,
11454 					ObjectIdGetDatum(childrelid));
11455 		ScanKeyInit(&skey[1],
11456 					Anum_pg_constraint_contypid,
11457 					BTEqualStrategyNumber, F_OIDEQ,
11458 					ObjectIdGetDatum(InvalidOid));
11459 		ScanKeyInit(&skey[2],
11460 					Anum_pg_constraint_conname,
11461 					BTEqualStrategyNumber, F_NAMEEQ,
11462 					CStringGetDatum(constrName));
11463 		scan = systable_beginscan(conrel, ConstraintRelidTypidNameIndexId,
11464 								  true, NULL, 3, skey);
11465 
11466 		/* There can be at most one matching row */
11467 		if (!HeapTupleIsValid(tuple = systable_getnext(scan)))
11468 			ereport(ERROR,
11469 					(errcode(ERRCODE_UNDEFINED_OBJECT),
11470 					 errmsg("constraint \"%s\" of relation \"%s\" does not exist",
11471 							constrName,
11472 							RelationGetRelationName(childrel))));
11473 
11474 		copy_tuple = heap_copytuple(tuple);
11475 
11476 		systable_endscan(scan);
11477 
11478 		con = (Form_pg_constraint) GETSTRUCT(copy_tuple);
11479 
11480 		/* Right now only CHECK constraints can be inherited */
11481 		if (con->contype != CONSTRAINT_CHECK)
11482 			elog(ERROR, "inherited constraint is not a CHECK constraint");
11483 
11484 		if (con->coninhcount <= 0)	/* shouldn't happen */
11485 			elog(ERROR, "relation %u has non-inherited constraint \"%s\"",
11486 				 childrelid, constrName);
11487 
11488 		if (recurse)
11489 		{
11490 			/*
11491 			 * If the child constraint has other definition sources, just
11492 			 * decrement its inheritance count; if not, recurse to delete it.
11493 			 */
11494 			if (con->coninhcount == 1 && !con->conislocal)
11495 			{
11496 				/* Time to delete this child constraint, too */
11497 				ATExecDropConstraint(childrel, constrName, behavior,
11498 									 true, true,
11499 									 false, lockmode);
11500 			}
11501 			else
11502 			{
11503 				/* Child constraint must survive my deletion */
11504 				con->coninhcount--;
11505 				CatalogTupleUpdate(conrel, &copy_tuple->t_self, copy_tuple);
11506 
11507 				/* Make update visible */
11508 				CommandCounterIncrement();
11509 			}
11510 		}
11511 		else
11512 		{
11513 			/*
11514 			 * If we were told to drop ONLY in this table (no recursion), we
11515 			 * need to mark the inheritors' constraints as locally defined
11516 			 * rather than inherited.
11517 			 */
11518 			con->coninhcount--;
11519 			con->conislocal = true;
11520 
11521 			CatalogTupleUpdate(conrel, &copy_tuple->t_self, copy_tuple);
11522 
11523 			/* Make update visible */
11524 			CommandCounterIncrement();
11525 		}
11526 
11527 		heap_freetuple(copy_tuple);
11528 
11529 		table_close(childrel, NoLock);
11530 	}
11531 
11532 	table_close(conrel, RowExclusiveLock);
11533 }
11534 
11535 /*
11536  * ALTER COLUMN TYPE
11537  *
11538  * Unlike other subcommand types, we do parse transformation for ALTER COLUMN
11539  * TYPE during phase 1 --- the AlterTableCmd passed in here is already
11540  * transformed (and must be, because we rely on some transformed fields).
11541  *
11542  * The point of this is that the execution of all ALTER COLUMN TYPEs for a
11543  * table will be done "in parallel" during phase 3, so all the USING
11544  * expressions should be parsed assuming the original column types.  Also,
11545  * this allows a USING expression to refer to a field that will be dropped.
11546  *
11547  * To make this work safely, AT_PASS_DROP then AT_PASS_ALTER_TYPE must be
11548  * the first two execution steps in phase 2; they must not see the effects
11549  * of any other subcommand types, since the USING expressions are parsed
11550  * against the unmodified table's state.
11551  */
11552 static void
ATPrepAlterColumnType(List ** wqueue,AlteredTableInfo * tab,Relation rel,bool recurse,bool recursing,AlterTableCmd * cmd,LOCKMODE lockmode,AlterTableUtilityContext * context)11553 ATPrepAlterColumnType(List **wqueue,
11554 					  AlteredTableInfo *tab, Relation rel,
11555 					  bool recurse, bool recursing,
11556 					  AlterTableCmd *cmd, LOCKMODE lockmode,
11557 					  AlterTableUtilityContext *context)
11558 {
11559 	char	   *colName = cmd->name;
11560 	ColumnDef  *def = (ColumnDef *) cmd->def;
11561 	TypeName   *typeName = def->typeName;
11562 	Node	   *transform = def->cooked_default;
11563 	HeapTuple	tuple;
11564 	Form_pg_attribute attTup;
11565 	AttrNumber	attnum;
11566 	Oid			targettype;
11567 	int32		targettypmod;
11568 	Oid			targetcollid;
11569 	NewColumnValue *newval;
11570 	ParseState *pstate = make_parsestate(NULL);
11571 	AclResult	aclresult;
11572 	bool		is_expr;
11573 
11574 	if (rel->rd_rel->reloftype && !recursing)
11575 		ereport(ERROR,
11576 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
11577 				 errmsg("cannot alter column type of typed table")));
11578 
11579 	/* lookup the attribute so we can check inheritance status */
11580 	tuple = SearchSysCacheAttName(RelationGetRelid(rel), colName);
11581 	if (!HeapTupleIsValid(tuple))
11582 		ereport(ERROR,
11583 				(errcode(ERRCODE_UNDEFINED_COLUMN),
11584 				 errmsg("column \"%s\" of relation \"%s\" does not exist",
11585 						colName, RelationGetRelationName(rel))));
11586 	attTup = (Form_pg_attribute) GETSTRUCT(tuple);
11587 	attnum = attTup->attnum;
11588 
11589 	/* Can't alter a system attribute */
11590 	if (attnum <= 0)
11591 		ereport(ERROR,
11592 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
11593 				 errmsg("cannot alter system column \"%s\"",
11594 						colName)));
11595 
11596 	/*
11597 	 * Don't alter inherited columns.  At outer level, there had better not be
11598 	 * any inherited definition; when recursing, we assume this was checked at
11599 	 * the parent level (see below).
11600 	 */
11601 	if (attTup->attinhcount > 0 && !recursing)
11602 		ereport(ERROR,
11603 				(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
11604 				 errmsg("cannot alter inherited column \"%s\"",
11605 						colName)));
11606 
11607 	/* Don't alter columns used in the partition key */
11608 	if (has_partition_attrs(rel,
11609 							bms_make_singleton(attnum - FirstLowInvalidHeapAttributeNumber),
11610 							&is_expr))
11611 		ereport(ERROR,
11612 				(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
11613 				 errmsg("cannot alter column \"%s\" because it is part of the partition key of relation \"%s\"",
11614 						colName, RelationGetRelationName(rel))));
11615 
11616 	/* Look up the target type */
11617 	typenameTypeIdAndMod(NULL, typeName, &targettype, &targettypmod);
11618 
11619 	aclresult = pg_type_aclcheck(targettype, GetUserId(), ACL_USAGE);
11620 	if (aclresult != ACLCHECK_OK)
11621 		aclcheck_error_type(aclresult, targettype);
11622 
11623 	/* And the collation */
11624 	targetcollid = GetColumnDefCollation(NULL, def, targettype);
11625 
11626 	/* make sure datatype is legal for a column */
11627 	CheckAttributeType(colName, targettype, targetcollid,
11628 					   list_make1_oid(rel->rd_rel->reltype),
11629 					   0);
11630 
11631 	if (tab->relkind == RELKIND_RELATION ||
11632 		tab->relkind == RELKIND_PARTITIONED_TABLE)
11633 	{
11634 		/*
11635 		 * Set up an expression to transform the old data value to the new
11636 		 * type. If a USING option was given, use the expression as
11637 		 * transformed by transformAlterTableStmt, else just take the old
11638 		 * value and try to coerce it.  We do this first so that type
11639 		 * incompatibility can be detected before we waste effort, and because
11640 		 * we need the expression to be parsed against the original table row
11641 		 * type.
11642 		 */
11643 		if (!transform)
11644 		{
11645 			transform = (Node *) makeVar(1, attnum,
11646 										 attTup->atttypid, attTup->atttypmod,
11647 										 attTup->attcollation,
11648 										 0);
11649 		}
11650 
11651 		transform = coerce_to_target_type(pstate,
11652 										  transform, exprType(transform),
11653 										  targettype, targettypmod,
11654 										  COERCION_ASSIGNMENT,
11655 										  COERCE_IMPLICIT_CAST,
11656 										  -1);
11657 		if (transform == NULL)
11658 		{
11659 			/* error text depends on whether USING was specified or not */
11660 			if (def->cooked_default != NULL)
11661 				ereport(ERROR,
11662 						(errcode(ERRCODE_DATATYPE_MISMATCH),
11663 						 errmsg("result of USING clause for column \"%s\""
11664 								" cannot be cast automatically to type %s",
11665 								colName, format_type_be(targettype)),
11666 						 errhint("You might need to add an explicit cast.")));
11667 			else
11668 				ereport(ERROR,
11669 						(errcode(ERRCODE_DATATYPE_MISMATCH),
11670 						 errmsg("column \"%s\" cannot be cast automatically to type %s",
11671 								colName, format_type_be(targettype)),
11672 				/* translator: USING is SQL, don't translate it */
11673 						 errhint("You might need to specify \"USING %s::%s\".",
11674 								 quote_identifier(colName),
11675 								 format_type_with_typemod(targettype,
11676 														  targettypmod))));
11677 		}
11678 
11679 		/* Fix collations after all else */
11680 		assign_expr_collations(pstate, transform);
11681 
11682 		/* Plan the expr now so we can accurately assess the need to rewrite. */
11683 		transform = (Node *) expression_planner((Expr *) transform);
11684 
11685 		/*
11686 		 * Add a work queue item to make ATRewriteTable update the column
11687 		 * contents.
11688 		 */
11689 		newval = (NewColumnValue *) palloc0(sizeof(NewColumnValue));
11690 		newval->attnum = attnum;
11691 		newval->expr = (Expr *) transform;
11692 		newval->is_generated = false;
11693 
11694 		tab->newvals = lappend(tab->newvals, newval);
11695 		if (ATColumnChangeRequiresRewrite(transform, attnum))
11696 			tab->rewrite |= AT_REWRITE_COLUMN_REWRITE;
11697 	}
11698 	else if (transform)
11699 		ereport(ERROR,
11700 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
11701 				 errmsg("\"%s\" is not a table",
11702 						RelationGetRelationName(rel))));
11703 
11704 	if (tab->relkind == RELKIND_COMPOSITE_TYPE ||
11705 		tab->relkind == RELKIND_FOREIGN_TABLE)
11706 	{
11707 		/*
11708 		 * For composite types and foreign tables, do this check now.  Regular
11709 		 * tables will check it later when the table is being rewritten.
11710 		 */
11711 		find_composite_type_dependencies(rel->rd_rel->reltype, rel, NULL);
11712 	}
11713 
11714 	ReleaseSysCache(tuple);
11715 
11716 	/*
11717 	 * Recurse manually by queueing a new command for each child, if
11718 	 * necessary. We cannot apply ATSimpleRecursion here because we need to
11719 	 * remap attribute numbers in the USING expression, if any.
11720 	 *
11721 	 * If we are told not to recurse, there had better not be any child
11722 	 * tables; else the alter would put them out of step.
11723 	 */
11724 	if (recurse)
11725 	{
11726 		Oid			relid = RelationGetRelid(rel);
11727 		List	   *child_oids,
11728 				   *child_numparents;
11729 		ListCell   *lo,
11730 				   *li;
11731 
11732 		child_oids = find_all_inheritors(relid, lockmode,
11733 										 &child_numparents);
11734 
11735 		/*
11736 		 * find_all_inheritors does the recursive search of the inheritance
11737 		 * hierarchy, so all we have to do is process all of the relids in the
11738 		 * list that it returns.
11739 		 */
11740 		forboth(lo, child_oids, li, child_numparents)
11741 		{
11742 			Oid			childrelid = lfirst_oid(lo);
11743 			int			numparents = lfirst_int(li);
11744 			Relation	childrel;
11745 			HeapTuple	childtuple;
11746 			Form_pg_attribute childattTup;
11747 
11748 			if (childrelid == relid)
11749 				continue;
11750 
11751 			/* find_all_inheritors already got lock */
11752 			childrel = relation_open(childrelid, NoLock);
11753 			CheckTableNotInUse(childrel, "ALTER TABLE");
11754 
11755 			/*
11756 			 * Verify that the child doesn't have any inherited definitions of
11757 			 * this column that came from outside this inheritance hierarchy.
11758 			 * (renameatt makes a similar test, though in a different way
11759 			 * because of its different recursion mechanism.)
11760 			 */
11761 			childtuple = SearchSysCacheAttName(RelationGetRelid(childrel),
11762 											   colName);
11763 			if (!HeapTupleIsValid(childtuple))
11764 				ereport(ERROR,
11765 						(errcode(ERRCODE_UNDEFINED_COLUMN),
11766 						 errmsg("column \"%s\" of relation \"%s\" does not exist",
11767 								colName, RelationGetRelationName(childrel))));
11768 			childattTup = (Form_pg_attribute) GETSTRUCT(childtuple);
11769 
11770 			if (childattTup->attinhcount > numparents)
11771 				ereport(ERROR,
11772 						(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
11773 						 errmsg("cannot alter inherited column \"%s\" of relation \"%s\"",
11774 								colName, RelationGetRelationName(childrel))));
11775 
11776 			ReleaseSysCache(childtuple);
11777 
11778 			/*
11779 			 * Remap the attribute numbers.  If no USING expression was
11780 			 * specified, there is no need for this step.
11781 			 */
11782 			if (def->cooked_default)
11783 			{
11784 				AttrMap    *attmap;
11785 				bool		found_whole_row;
11786 
11787 				/* create a copy to scribble on */
11788 				cmd = copyObject(cmd);
11789 
11790 				attmap = build_attrmap_by_name(RelationGetDescr(childrel),
11791 											   RelationGetDescr(rel));
11792 				((ColumnDef *) cmd->def)->cooked_default =
11793 					map_variable_attnos(def->cooked_default,
11794 										1, 0,
11795 										attmap,
11796 										InvalidOid, &found_whole_row);
11797 				if (found_whole_row)
11798 					ereport(ERROR,
11799 							(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
11800 							 errmsg("cannot convert whole-row table reference"),
11801 							 errdetail("USING expression contains a whole-row table reference.")));
11802 				pfree(attmap);
11803 			}
11804 			ATPrepCmd(wqueue, childrel, cmd, false, true, lockmode, context);
11805 			relation_close(childrel, NoLock);
11806 		}
11807 	}
11808 	else if (!recursing &&
11809 			 find_inheritance_children(RelationGetRelid(rel), NoLock) != NIL)
11810 		ereport(ERROR,
11811 				(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
11812 				 errmsg("type of inherited column \"%s\" must be changed in child tables too",
11813 						colName)));
11814 
11815 	if (tab->relkind == RELKIND_COMPOSITE_TYPE)
11816 		ATTypedTableRecursion(wqueue, rel, cmd, lockmode, context);
11817 }
11818 
11819 /*
11820  * When the data type of a column is changed, a rewrite might not be required
11821  * if the new type is sufficiently identical to the old one, and the USING
11822  * clause isn't trying to insert some other value.  It's safe to skip the
11823  * rewrite in these cases:
11824  *
11825  * - the old type is binary coercible to the new type
11826  * - the new type is an unconstrained domain over the old type
11827  * - {NEW,OLD} or {OLD,NEW} is {timestamptz,timestamp} and the timezone is UTC
11828  *
11829  * In the case of a constrained domain, we could get by with scanning the
11830  * table and checking the constraint rather than actually rewriting it, but we
11831  * don't currently try to do that.
11832  */
11833 static bool
ATColumnChangeRequiresRewrite(Node * expr,AttrNumber varattno)11834 ATColumnChangeRequiresRewrite(Node *expr, AttrNumber varattno)
11835 {
11836 	Assert(expr != NULL);
11837 
11838 	for (;;)
11839 	{
11840 		/* only one varno, so no need to check that */
11841 		if (IsA(expr, Var) && ((Var *) expr)->varattno == varattno)
11842 			return false;
11843 		else if (IsA(expr, RelabelType))
11844 			expr = (Node *) ((RelabelType *) expr)->arg;
11845 		else if (IsA(expr, CoerceToDomain))
11846 		{
11847 			CoerceToDomain *d = (CoerceToDomain *) expr;
11848 
11849 			if (DomainHasConstraints(d->resulttype))
11850 				return true;
11851 			expr = (Node *) d->arg;
11852 		}
11853 		else if (IsA(expr, FuncExpr))
11854 		{
11855 			FuncExpr   *f = (FuncExpr *) expr;
11856 
11857 			switch (f->funcid)
11858 			{
11859 				case F_TIMESTAMPTZ_TIMESTAMP:
11860 				case F_TIMESTAMP_TIMESTAMPTZ:
11861 					if (TimestampTimestampTzRequiresRewrite())
11862 						return true;
11863 					else
11864 						expr = linitial(f->args);
11865 					break;
11866 				default:
11867 					return true;
11868 			}
11869 		}
11870 		else
11871 			return true;
11872 	}
11873 }
11874 
11875 /*
11876  * ALTER COLUMN .. SET DATA TYPE
11877  *
11878  * Return the address of the modified column.
11879  */
11880 static ObjectAddress
ATExecAlterColumnType(AlteredTableInfo * tab,Relation rel,AlterTableCmd * cmd,LOCKMODE lockmode)11881 ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel,
11882 					  AlterTableCmd *cmd, LOCKMODE lockmode)
11883 {
11884 	char	   *colName = cmd->name;
11885 	ColumnDef  *def = (ColumnDef *) cmd->def;
11886 	TypeName   *typeName = def->typeName;
11887 	HeapTuple	heapTup;
11888 	Form_pg_attribute attTup,
11889 				attOldTup;
11890 	AttrNumber	attnum;
11891 	HeapTuple	typeTuple;
11892 	Form_pg_type tform;
11893 	Oid			targettype;
11894 	int32		targettypmod;
11895 	Oid			targetcollid;
11896 	Node	   *defaultexpr;
11897 	Relation	attrelation;
11898 	Relation	depRel;
11899 	ScanKeyData key[3];
11900 	SysScanDesc scan;
11901 	HeapTuple	depTup;
11902 	ObjectAddress address;
11903 
11904 	/*
11905 	 * Clear all the missing values if we're rewriting the table, since this
11906 	 * renders them pointless.
11907 	 */
11908 	if (tab->rewrite)
11909 	{
11910 		Relation	newrel;
11911 
11912 		newrel = table_open(RelationGetRelid(rel), NoLock);
11913 		RelationClearMissing(newrel);
11914 		relation_close(newrel, NoLock);
11915 		/* make sure we don't conflict with later attribute modifications */
11916 		CommandCounterIncrement();
11917 	}
11918 
11919 	attrelation = table_open(AttributeRelationId, RowExclusiveLock);
11920 
11921 	/* Look up the target column */
11922 	heapTup = SearchSysCacheCopyAttName(RelationGetRelid(rel), colName);
11923 	if (!HeapTupleIsValid(heapTup)) /* shouldn't happen */
11924 		ereport(ERROR,
11925 				(errcode(ERRCODE_UNDEFINED_COLUMN),
11926 				 errmsg("column \"%s\" of relation \"%s\" does not exist",
11927 						colName, RelationGetRelationName(rel))));
11928 	attTup = (Form_pg_attribute) GETSTRUCT(heapTup);
11929 	attnum = attTup->attnum;
11930 	attOldTup = TupleDescAttr(tab->oldDesc, attnum - 1);
11931 
11932 	/* Check for multiple ALTER TYPE on same column --- can't cope */
11933 	if (attTup->atttypid != attOldTup->atttypid ||
11934 		attTup->atttypmod != attOldTup->atttypmod)
11935 		ereport(ERROR,
11936 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
11937 				 errmsg("cannot alter type of column \"%s\" twice",
11938 						colName)));
11939 
11940 	/* Look up the target type (should not fail, since prep found it) */
11941 	typeTuple = typenameType(NULL, typeName, &targettypmod);
11942 	tform = (Form_pg_type) GETSTRUCT(typeTuple);
11943 	targettype = tform->oid;
11944 	/* And the collation */
11945 	targetcollid = GetColumnDefCollation(NULL, def, targettype);
11946 
11947 	/*
11948 	 * If there is a default expression for the column, get it and ensure we
11949 	 * can coerce it to the new datatype.  (We must do this before changing
11950 	 * the column type, because build_column_default itself will try to
11951 	 * coerce, and will not issue the error message we want if it fails.)
11952 	 *
11953 	 * We remove any implicit coercion steps at the top level of the old
11954 	 * default expression; this has been agreed to satisfy the principle of
11955 	 * least surprise.  (The conversion to the new column type should act like
11956 	 * it started from what the user sees as the stored expression, and the
11957 	 * implicit coercions aren't going to be shown.)
11958 	 */
11959 	if (attTup->atthasdef)
11960 	{
11961 		defaultexpr = build_column_default(rel, attnum);
11962 		Assert(defaultexpr);
11963 		defaultexpr = strip_implicit_coercions(defaultexpr);
11964 		defaultexpr = coerce_to_target_type(NULL,	/* no UNKNOWN params */
11965 											defaultexpr, exprType(defaultexpr),
11966 											targettype, targettypmod,
11967 											COERCION_ASSIGNMENT,
11968 											COERCE_IMPLICIT_CAST,
11969 											-1);
11970 		if (defaultexpr == NULL)
11971 		{
11972 			if (attTup->attgenerated)
11973 				ereport(ERROR,
11974 						(errcode(ERRCODE_DATATYPE_MISMATCH),
11975 						 errmsg("generation expression for column \"%s\" cannot be cast automatically to type %s",
11976 								colName, format_type_be(targettype))));
11977 			else
11978 				ereport(ERROR,
11979 						(errcode(ERRCODE_DATATYPE_MISMATCH),
11980 						 errmsg("default for column \"%s\" cannot be cast automatically to type %s",
11981 								colName, format_type_be(targettype))));
11982 		}
11983 	}
11984 	else
11985 		defaultexpr = NULL;
11986 
11987 	/*
11988 	 * Find everything that depends on the column (constraints, indexes, etc),
11989 	 * and record enough information to let us recreate the objects.
11990 	 *
11991 	 * The actual recreation does not happen here, but only after we have
11992 	 * performed all the individual ALTER TYPE operations.  We have to save
11993 	 * the info before executing ALTER TYPE, though, else the deparser will
11994 	 * get confused.
11995 	 */
11996 	depRel = table_open(DependRelationId, RowExclusiveLock);
11997 
11998 	ScanKeyInit(&key[0],
11999 				Anum_pg_depend_refclassid,
12000 				BTEqualStrategyNumber, F_OIDEQ,
12001 				ObjectIdGetDatum(RelationRelationId));
12002 	ScanKeyInit(&key[1],
12003 				Anum_pg_depend_refobjid,
12004 				BTEqualStrategyNumber, F_OIDEQ,
12005 				ObjectIdGetDatum(RelationGetRelid(rel)));
12006 	ScanKeyInit(&key[2],
12007 				Anum_pg_depend_refobjsubid,
12008 				BTEqualStrategyNumber, F_INT4EQ,
12009 				Int32GetDatum((int32) attnum));
12010 
12011 	scan = systable_beginscan(depRel, DependReferenceIndexId, true,
12012 							  NULL, 3, key);
12013 
12014 	while (HeapTupleIsValid(depTup = systable_getnext(scan)))
12015 	{
12016 		Form_pg_depend foundDep = (Form_pg_depend) GETSTRUCT(depTup);
12017 		ObjectAddress foundObject;
12018 
12019 		/* We don't expect any PIN dependencies on columns */
12020 		if (foundDep->deptype == DEPENDENCY_PIN)
12021 			elog(ERROR, "cannot alter type of a pinned column");
12022 
12023 		foundObject.classId = foundDep->classid;
12024 		foundObject.objectId = foundDep->objid;
12025 		foundObject.objectSubId = foundDep->objsubid;
12026 
12027 		switch (getObjectClass(&foundObject))
12028 		{
12029 			case OCLASS_CLASS:
12030 				{
12031 					char		relKind = get_rel_relkind(foundObject.objectId);
12032 
12033 					if (relKind == RELKIND_INDEX ||
12034 						relKind == RELKIND_PARTITIONED_INDEX)
12035 					{
12036 						Assert(foundObject.objectSubId == 0);
12037 						RememberIndexForRebuilding(foundObject.objectId, tab);
12038 					}
12039 					else if (relKind == RELKIND_SEQUENCE)
12040 					{
12041 						/*
12042 						 * This must be a SERIAL column's sequence.  We need
12043 						 * not do anything to it.
12044 						 */
12045 						Assert(foundObject.objectSubId == 0);
12046 					}
12047 					else if (relKind == RELKIND_RELATION &&
12048 							 foundObject.objectSubId != 0 &&
12049 							 get_attgenerated(foundObject.objectId, foundObject.objectSubId))
12050 					{
12051 						/*
12052 						 * Changing the type of a column that is used by a
12053 						 * generated column is not allowed by SQL standard. It
12054 						 * might be doable with some thinking and effort.
12055 						 */
12056 						ereport(ERROR,
12057 								(errcode(ERRCODE_SYNTAX_ERROR),
12058 								 errmsg("cannot alter type of a column used by a generated column"),
12059 								 errdetail("Column \"%s\" is used by generated column \"%s\".",
12060 										   colName, get_attname(foundObject.objectId, foundObject.objectSubId, false))));
12061 					}
12062 					else
12063 					{
12064 						/* Not expecting any other direct dependencies... */
12065 						elog(ERROR, "unexpected object depending on column: %s",
12066 							 getObjectDescription(&foundObject, false));
12067 					}
12068 					break;
12069 				}
12070 
12071 			case OCLASS_CONSTRAINT:
12072 				Assert(foundObject.objectSubId == 0);
12073 				RememberConstraintForRebuilding(foundObject.objectId, tab);
12074 				break;
12075 
12076 			case OCLASS_REWRITE:
12077 				/* XXX someday see if we can cope with revising views */
12078 				ereport(ERROR,
12079 						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
12080 						 errmsg("cannot alter type of a column used by a view or rule"),
12081 						 errdetail("%s depends on column \"%s\"",
12082 								   getObjectDescription(&foundObject, false),
12083 								   colName)));
12084 				break;
12085 
12086 			case OCLASS_TRIGGER:
12087 
12088 				/*
12089 				 * A trigger can depend on a column because the column is
12090 				 * specified as an update target, or because the column is
12091 				 * used in the trigger's WHEN condition.  The first case would
12092 				 * not require any extra work, but the second case would
12093 				 * require updating the WHEN expression, which will take a
12094 				 * significant amount of new code.  Since we can't easily tell
12095 				 * which case applies, we punt for both.  FIXME someday.
12096 				 */
12097 				ereport(ERROR,
12098 						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
12099 						 errmsg("cannot alter type of a column used in a trigger definition"),
12100 						 errdetail("%s depends on column \"%s\"",
12101 								   getObjectDescription(&foundObject, false),
12102 								   colName)));
12103 				break;
12104 
12105 			case OCLASS_POLICY:
12106 
12107 				/*
12108 				 * A policy can depend on a column because the column is
12109 				 * specified in the policy's USING or WITH CHECK qual
12110 				 * expressions.  It might be possible to rewrite and recheck
12111 				 * the policy expression, but punt for now.  It's certainly
12112 				 * easy enough to remove and recreate the policy; still, FIXME
12113 				 * someday.
12114 				 */
12115 				ereport(ERROR,
12116 						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
12117 						 errmsg("cannot alter type of a column used in a policy definition"),
12118 						 errdetail("%s depends on column \"%s\"",
12119 								   getObjectDescription(&foundObject, false),
12120 								   colName)));
12121 				break;
12122 
12123 			case OCLASS_DEFAULT:
12124 
12125 				/*
12126 				 * Ignore the column's default expression, since we will fix
12127 				 * it below.
12128 				 */
12129 				Assert(defaultexpr);
12130 				break;
12131 
12132 			case OCLASS_STATISTIC_EXT:
12133 
12134 				/*
12135 				 * Give the extended-stats machinery a chance to fix anything
12136 				 * that this column type change would break.
12137 				 */
12138 				RememberStatisticsForRebuilding(foundObject.objectId, tab);
12139 				break;
12140 
12141 			case OCLASS_PROC:
12142 			case OCLASS_TYPE:
12143 			case OCLASS_CAST:
12144 			case OCLASS_COLLATION:
12145 			case OCLASS_CONVERSION:
12146 			case OCLASS_LANGUAGE:
12147 			case OCLASS_LARGEOBJECT:
12148 			case OCLASS_OPERATOR:
12149 			case OCLASS_OPCLASS:
12150 			case OCLASS_OPFAMILY:
12151 			case OCLASS_AM:
12152 			case OCLASS_AMOP:
12153 			case OCLASS_AMPROC:
12154 			case OCLASS_SCHEMA:
12155 			case OCLASS_TSPARSER:
12156 			case OCLASS_TSDICT:
12157 			case OCLASS_TSTEMPLATE:
12158 			case OCLASS_TSCONFIG:
12159 			case OCLASS_ROLE:
12160 			case OCLASS_DATABASE:
12161 			case OCLASS_TBLSPACE:
12162 			case OCLASS_FDW:
12163 			case OCLASS_FOREIGN_SERVER:
12164 			case OCLASS_USER_MAPPING:
12165 			case OCLASS_DEFACL:
12166 			case OCLASS_EXTENSION:
12167 			case OCLASS_EVENT_TRIGGER:
12168 			case OCLASS_PUBLICATION:
12169 			case OCLASS_PUBLICATION_REL:
12170 			case OCLASS_SUBSCRIPTION:
12171 			case OCLASS_TRANSFORM:
12172 
12173 				/*
12174 				 * We don't expect any of these sorts of objects to depend on
12175 				 * a column.
12176 				 */
12177 				elog(ERROR, "unexpected object depending on column: %s",
12178 					 getObjectDescription(&foundObject, false));
12179 				break;
12180 
12181 				/*
12182 				 * There's intentionally no default: case here; we want the
12183 				 * compiler to warn if a new OCLASS hasn't been handled above.
12184 				 */
12185 		}
12186 	}
12187 
12188 	systable_endscan(scan);
12189 
12190 	/*
12191 	 * Now scan for dependencies of this column on other things.  The only
12192 	 * thing we should find is the dependency on the column datatype, which we
12193 	 * want to remove, possibly a collation dependency, and dependencies on
12194 	 * other columns if it is a generated column.
12195 	 */
12196 	ScanKeyInit(&key[0],
12197 				Anum_pg_depend_classid,
12198 				BTEqualStrategyNumber, F_OIDEQ,
12199 				ObjectIdGetDatum(RelationRelationId));
12200 	ScanKeyInit(&key[1],
12201 				Anum_pg_depend_objid,
12202 				BTEqualStrategyNumber, F_OIDEQ,
12203 				ObjectIdGetDatum(RelationGetRelid(rel)));
12204 	ScanKeyInit(&key[2],
12205 				Anum_pg_depend_objsubid,
12206 				BTEqualStrategyNumber, F_INT4EQ,
12207 				Int32GetDatum((int32) attnum));
12208 
12209 	scan = systable_beginscan(depRel, DependDependerIndexId, true,
12210 							  NULL, 3, key);
12211 
12212 	while (HeapTupleIsValid(depTup = systable_getnext(scan)))
12213 	{
12214 		Form_pg_depend foundDep = (Form_pg_depend) GETSTRUCT(depTup);
12215 		ObjectAddress foundObject;
12216 
12217 		foundObject.classId = foundDep->refclassid;
12218 		foundObject.objectId = foundDep->refobjid;
12219 		foundObject.objectSubId = foundDep->refobjsubid;
12220 
12221 		if (foundDep->deptype != DEPENDENCY_NORMAL &&
12222 			foundDep->deptype != DEPENDENCY_AUTO)
12223 			elog(ERROR, "found unexpected dependency type '%c'",
12224 				 foundDep->deptype);
12225 		if (!(foundDep->refclassid == TypeRelationId &&
12226 			  foundDep->refobjid == attTup->atttypid) &&
12227 			!(foundDep->refclassid == CollationRelationId &&
12228 			  foundDep->refobjid == attTup->attcollation) &&
12229 			!(foundDep->refclassid == RelationRelationId &&
12230 			  foundDep->refobjid == RelationGetRelid(rel) &&
12231 			  foundDep->refobjsubid != 0)
12232 			)
12233 			elog(ERROR, "found unexpected dependency for column: %s",
12234 				 getObjectDescription(&foundObject, false));
12235 
12236 		CatalogTupleDelete(depRel, &depTup->t_self);
12237 	}
12238 
12239 	systable_endscan(scan);
12240 
12241 	table_close(depRel, RowExclusiveLock);
12242 
12243 	/*
12244 	 * Here we go --- change the recorded column type and collation.  (Note
12245 	 * heapTup is a copy of the syscache entry, so okay to scribble on.) First
12246 	 * fix up the missing value if any.
12247 	 */
12248 	if (attTup->atthasmissing)
12249 	{
12250 		Datum		missingval;
12251 		bool		missingNull;
12252 
12253 		/* if rewrite is true the missing value should already be cleared */
12254 		Assert(tab->rewrite == 0);
12255 
12256 		/* Get the missing value datum */
12257 		missingval = heap_getattr(heapTup,
12258 								  Anum_pg_attribute_attmissingval,
12259 								  attrelation->rd_att,
12260 								  &missingNull);
12261 
12262 		/* if it's a null array there is nothing to do */
12263 
12264 		if (!missingNull)
12265 		{
12266 			/*
12267 			 * Get the datum out of the array and repack it in a new array
12268 			 * built with the new type data. We assume that since the table
12269 			 * doesn't need rewriting, the actual Datum doesn't need to be
12270 			 * changed, only the array metadata.
12271 			 */
12272 
12273 			int			one = 1;
12274 			bool		isNull;
12275 			Datum		valuesAtt[Natts_pg_attribute];
12276 			bool		nullsAtt[Natts_pg_attribute];
12277 			bool		replacesAtt[Natts_pg_attribute];
12278 			HeapTuple	newTup;
12279 
12280 			MemSet(valuesAtt, 0, sizeof(valuesAtt));
12281 			MemSet(nullsAtt, false, sizeof(nullsAtt));
12282 			MemSet(replacesAtt, false, sizeof(replacesAtt));
12283 
12284 			missingval = array_get_element(missingval,
12285 										   1,
12286 										   &one,
12287 										   0,
12288 										   attTup->attlen,
12289 										   attTup->attbyval,
12290 										   attTup->attalign,
12291 										   &isNull);
12292 			missingval = PointerGetDatum(construct_array(&missingval,
12293 														 1,
12294 														 targettype,
12295 														 tform->typlen,
12296 														 tform->typbyval,
12297 														 tform->typalign));
12298 
12299 			valuesAtt[Anum_pg_attribute_attmissingval - 1] = missingval;
12300 			replacesAtt[Anum_pg_attribute_attmissingval - 1] = true;
12301 			nullsAtt[Anum_pg_attribute_attmissingval - 1] = false;
12302 
12303 			newTup = heap_modify_tuple(heapTup, RelationGetDescr(attrelation),
12304 									   valuesAtt, nullsAtt, replacesAtt);
12305 			heap_freetuple(heapTup);
12306 			heapTup = newTup;
12307 			attTup = (Form_pg_attribute) GETSTRUCT(heapTup);
12308 		}
12309 	}
12310 
12311 	attTup->atttypid = targettype;
12312 	attTup->atttypmod = targettypmod;
12313 	attTup->attcollation = targetcollid;
12314 	attTup->attndims = list_length(typeName->arrayBounds);
12315 	attTup->attlen = tform->typlen;
12316 	attTup->attbyval = tform->typbyval;
12317 	attTup->attalign = tform->typalign;
12318 	attTup->attstorage = tform->typstorage;
12319 	attTup->attcompression = InvalidCompressionMethod;
12320 
12321 	ReleaseSysCache(typeTuple);
12322 
12323 	CatalogTupleUpdate(attrelation, &heapTup->t_self, heapTup);
12324 
12325 	table_close(attrelation, RowExclusiveLock);
12326 
12327 	/* Install dependencies on new datatype and collation */
12328 	add_column_datatype_dependency(RelationGetRelid(rel), attnum, targettype);
12329 	add_column_collation_dependency(RelationGetRelid(rel), attnum, targetcollid);
12330 
12331 	/*
12332 	 * Drop any pg_statistic entry for the column, since it's now wrong type
12333 	 */
12334 	RemoveStatistics(RelationGetRelid(rel), attnum);
12335 
12336 	InvokeObjectPostAlterHook(RelationRelationId,
12337 							  RelationGetRelid(rel), attnum);
12338 
12339 	/*
12340 	 * Update the default, if present, by brute force --- remove and re-add
12341 	 * the default.  Probably unsafe to take shortcuts, since the new version
12342 	 * may well have additional dependencies.  (It's okay to do this now,
12343 	 * rather than after other ALTER TYPE commands, since the default won't
12344 	 * depend on other column types.)
12345 	 */
12346 	if (defaultexpr)
12347 	{
12348 		/* Must make new row visible since it will be updated again */
12349 		CommandCounterIncrement();
12350 
12351 		/*
12352 		 * We use RESTRICT here for safety, but at present we do not expect
12353 		 * anything to depend on the default.
12354 		 */
12355 		RemoveAttrDefault(RelationGetRelid(rel), attnum, DROP_RESTRICT, true,
12356 						  true);
12357 
12358 		StoreAttrDefault(rel, attnum, defaultexpr, true, false);
12359 	}
12360 
12361 	ObjectAddressSubSet(address, RelationRelationId,
12362 						RelationGetRelid(rel), attnum);
12363 
12364 	/* Cleanup */
12365 	heap_freetuple(heapTup);
12366 
12367 	return address;
12368 }
12369 
12370 /*
12371  * Subroutine for ATExecAlterColumnType: remember that a replica identity
12372  * needs to be reset.
12373  */
12374 static void
RememberReplicaIdentityForRebuilding(Oid indoid,AlteredTableInfo * tab)12375 RememberReplicaIdentityForRebuilding(Oid indoid, AlteredTableInfo *tab)
12376 {
12377 	if (!get_index_isreplident(indoid))
12378 		return;
12379 
12380 	if (tab->replicaIdentityIndex)
12381 		elog(ERROR, "relation %u has multiple indexes marked as replica identity", tab->relid);
12382 
12383 	tab->replicaIdentityIndex = get_rel_name(indoid);
12384 }
12385 
12386 /*
12387  * Subroutine for ATExecAlterColumnType: remember any clustered index.
12388  */
12389 static void
RememberClusterOnForRebuilding(Oid indoid,AlteredTableInfo * tab)12390 RememberClusterOnForRebuilding(Oid indoid, AlteredTableInfo *tab)
12391 {
12392 	if (!get_index_isclustered(indoid))
12393 		return;
12394 
12395 	if (tab->clusterOnIndex)
12396 		elog(ERROR, "relation %u has multiple clustered indexes", tab->relid);
12397 
12398 	tab->clusterOnIndex = get_rel_name(indoid);
12399 }
12400 
12401 /*
12402  * Subroutine for ATExecAlterColumnType: remember that a constraint needs
12403  * to be rebuilt (which we might already know).
12404  */
12405 static void
RememberConstraintForRebuilding(Oid conoid,AlteredTableInfo * tab)12406 RememberConstraintForRebuilding(Oid conoid, AlteredTableInfo *tab)
12407 {
12408 	/*
12409 	 * This de-duplication check is critical for two independent reasons: we
12410 	 * mustn't try to recreate the same constraint twice, and if a constraint
12411 	 * depends on more than one column whose type is to be altered, we must
12412 	 * capture its definition string before applying any of the column type
12413 	 * changes.  ruleutils.c will get confused if we ask again later.
12414 	 */
12415 	if (!list_member_oid(tab->changedConstraintOids, conoid))
12416 	{
12417 		/* OK, capture the constraint's existing definition string */
12418 		char	   *defstring = pg_get_constraintdef_command(conoid);
12419 		Oid			indoid;
12420 
12421 		tab->changedConstraintOids = lappend_oid(tab->changedConstraintOids,
12422 												 conoid);
12423 		tab->changedConstraintDefs = lappend(tab->changedConstraintDefs,
12424 											 defstring);
12425 
12426 		/*
12427 		 * For the index of a constraint, if any, remember if it is used for
12428 		 * the table's replica identity or if it is a clustered index, so that
12429 		 * ATPostAlterTypeCleanup() can queue up commands necessary to restore
12430 		 * those properties.
12431 		 */
12432 		indoid = get_constraint_index(conoid);
12433 		if (OidIsValid(indoid))
12434 		{
12435 			RememberReplicaIdentityForRebuilding(indoid, tab);
12436 			RememberClusterOnForRebuilding(indoid, tab);
12437 		}
12438 	}
12439 }
12440 
12441 /*
12442  * Subroutine for ATExecAlterColumnType: remember that an index needs
12443  * to be rebuilt (which we might already know).
12444  */
12445 static void
RememberIndexForRebuilding(Oid indoid,AlteredTableInfo * tab)12446 RememberIndexForRebuilding(Oid indoid, AlteredTableInfo *tab)
12447 {
12448 	/*
12449 	 * This de-duplication check is critical for two independent reasons: we
12450 	 * mustn't try to recreate the same index twice, and if an index depends
12451 	 * on more than one column whose type is to be altered, we must capture
12452 	 * its definition string before applying any of the column type changes.
12453 	 * ruleutils.c will get confused if we ask again later.
12454 	 */
12455 	if (!list_member_oid(tab->changedIndexOids, indoid))
12456 	{
12457 		/*
12458 		 * Before adding it as an index-to-rebuild, we'd better see if it
12459 		 * belongs to a constraint, and if so rebuild the constraint instead.
12460 		 * Typically this check fails, because constraint indexes normally
12461 		 * have only dependencies on their constraint.  But it's possible for
12462 		 * such an index to also have direct dependencies on table columns,
12463 		 * for example with a partial exclusion constraint.
12464 		 */
12465 		Oid			conoid = get_index_constraint(indoid);
12466 
12467 		if (OidIsValid(conoid))
12468 		{
12469 			RememberConstraintForRebuilding(conoid, tab);
12470 		}
12471 		else
12472 		{
12473 			/* OK, capture the index's existing definition string */
12474 			char	   *defstring = pg_get_indexdef_string(indoid);
12475 
12476 			tab->changedIndexOids = lappend_oid(tab->changedIndexOids,
12477 												indoid);
12478 			tab->changedIndexDefs = lappend(tab->changedIndexDefs,
12479 											defstring);
12480 
12481 			/*
12482 			 * Remember if this index is used for the table's replica identity
12483 			 * or if it is a clustered index, so that ATPostAlterTypeCleanup()
12484 			 * can queue up commands necessary to restore those properties.
12485 			 */
12486 			RememberReplicaIdentityForRebuilding(indoid, tab);
12487 			RememberClusterOnForRebuilding(indoid, tab);
12488 		}
12489 	}
12490 }
12491 
12492 /*
12493  * Subroutine for ATExecAlterColumnType: remember that a statistics object
12494  * needs to be rebuilt (which we might already know).
12495  */
12496 static void
RememberStatisticsForRebuilding(Oid stxoid,AlteredTableInfo * tab)12497 RememberStatisticsForRebuilding(Oid stxoid, AlteredTableInfo *tab)
12498 {
12499 	/*
12500 	 * This de-duplication check is critical for two independent reasons: we
12501 	 * mustn't try to recreate the same statistics object twice, and if the
12502 	 * statistics object depends on more than one column whose type is to be
12503 	 * altered, we must capture its definition string before applying any of
12504 	 * the type changes. ruleutils.c will get confused if we ask again later.
12505 	 */
12506 	if (!list_member_oid(tab->changedStatisticsOids, stxoid))
12507 	{
12508 		/* OK, capture the statistics object's existing definition string */
12509 		char	   *defstring = pg_get_statisticsobjdef_string(stxoid);
12510 
12511 		tab->changedStatisticsOids = lappend_oid(tab->changedStatisticsOids,
12512 												 stxoid);
12513 		tab->changedStatisticsDefs = lappend(tab->changedStatisticsDefs,
12514 											 defstring);
12515 	}
12516 }
12517 
12518 /*
12519  * Cleanup after we've finished all the ALTER TYPE operations for a
12520  * particular relation.  We have to drop and recreate all the indexes
12521  * and constraints that depend on the altered columns.  We do the
12522  * actual dropping here, but re-creation is managed by adding work
12523  * queue entries to do those steps later.
12524  */
12525 static void
ATPostAlterTypeCleanup(List ** wqueue,AlteredTableInfo * tab,LOCKMODE lockmode)12526 ATPostAlterTypeCleanup(List **wqueue, AlteredTableInfo *tab, LOCKMODE lockmode)
12527 {
12528 	ObjectAddress obj;
12529 	ObjectAddresses *objects;
12530 	ListCell   *def_item;
12531 	ListCell   *oid_item;
12532 
12533 	/*
12534 	 * Collect all the constraints and indexes to drop so we can process them
12535 	 * in a single call.  That way we don't have to worry about dependencies
12536 	 * among them.
12537 	 */
12538 	objects = new_object_addresses();
12539 
12540 	/*
12541 	 * Re-parse the index and constraint definitions, and attach them to the
12542 	 * appropriate work queue entries.  We do this before dropping because in
12543 	 * the case of a FOREIGN KEY constraint, we might not yet have exclusive
12544 	 * lock on the table the constraint is attached to, and we need to get
12545 	 * that before reparsing/dropping.
12546 	 *
12547 	 * We can't rely on the output of deparsing to tell us which relation to
12548 	 * operate on, because concurrent activity might have made the name
12549 	 * resolve differently.  Instead, we've got to use the OID of the
12550 	 * constraint or index we're processing to figure out which relation to
12551 	 * operate on.
12552 	 */
12553 	forboth(oid_item, tab->changedConstraintOids,
12554 			def_item, tab->changedConstraintDefs)
12555 	{
12556 		Oid			oldId = lfirst_oid(oid_item);
12557 		HeapTuple	tup;
12558 		Form_pg_constraint con;
12559 		Oid			relid;
12560 		Oid			confrelid;
12561 		char		contype;
12562 		bool		conislocal;
12563 
12564 		tup = SearchSysCache1(CONSTROID, ObjectIdGetDatum(oldId));
12565 		if (!HeapTupleIsValid(tup)) /* should not happen */
12566 			elog(ERROR, "cache lookup failed for constraint %u", oldId);
12567 		con = (Form_pg_constraint) GETSTRUCT(tup);
12568 		if (OidIsValid(con->conrelid))
12569 			relid = con->conrelid;
12570 		else
12571 		{
12572 			/* must be a domain constraint */
12573 			relid = get_typ_typrelid(getBaseType(con->contypid));
12574 			if (!OidIsValid(relid))
12575 				elog(ERROR, "could not identify relation associated with constraint %u", oldId);
12576 		}
12577 		confrelid = con->confrelid;
12578 		contype = con->contype;
12579 		conislocal = con->conislocal;
12580 		ReleaseSysCache(tup);
12581 
12582 		ObjectAddressSet(obj, ConstraintRelationId, oldId);
12583 		add_exact_object_address(&obj, objects);
12584 
12585 		/*
12586 		 * If the constraint is inherited (only), we don't want to inject a
12587 		 * new definition here; it'll get recreated when ATAddCheckConstraint
12588 		 * recurses from adding the parent table's constraint.  But we had to
12589 		 * carry the info this far so that we can drop the constraint below.
12590 		 */
12591 		if (!conislocal)
12592 			continue;
12593 
12594 		/*
12595 		 * When rebuilding an FK constraint that references the table we're
12596 		 * modifying, we might not yet have any lock on the FK's table, so get
12597 		 * one now.  We'll need AccessExclusiveLock for the DROP CONSTRAINT
12598 		 * step, so there's no value in asking for anything weaker.
12599 		 */
12600 		if (relid != tab->relid && contype == CONSTRAINT_FOREIGN)
12601 			LockRelationOid(relid, AccessExclusiveLock);
12602 
12603 		ATPostAlterTypeParse(oldId, relid, confrelid,
12604 							 (char *) lfirst(def_item),
12605 							 wqueue, lockmode, tab->rewrite);
12606 	}
12607 	forboth(oid_item, tab->changedIndexOids,
12608 			def_item, tab->changedIndexDefs)
12609 	{
12610 		Oid			oldId = lfirst_oid(oid_item);
12611 		Oid			relid;
12612 
12613 		relid = IndexGetRelation(oldId, false);
12614 		ATPostAlterTypeParse(oldId, relid, InvalidOid,
12615 							 (char *) lfirst(def_item),
12616 							 wqueue, lockmode, tab->rewrite);
12617 
12618 		ObjectAddressSet(obj, RelationRelationId, oldId);
12619 		add_exact_object_address(&obj, objects);
12620 	}
12621 
12622 	/* add dependencies for new statistics */
12623 	forboth(oid_item, tab->changedStatisticsOids,
12624 			def_item, tab->changedStatisticsDefs)
12625 	{
12626 		Oid			oldId = lfirst_oid(oid_item);
12627 		Oid			relid;
12628 
12629 		relid = StatisticsGetRelation(oldId, false);
12630 		ATPostAlterTypeParse(oldId, relid, InvalidOid,
12631 							 (char *) lfirst(def_item),
12632 							 wqueue, lockmode, tab->rewrite);
12633 
12634 		ObjectAddressSet(obj, StatisticExtRelationId, oldId);
12635 		add_exact_object_address(&obj, objects);
12636 	}
12637 
12638 	/*
12639 	 * Queue up command to restore replica identity index marking
12640 	 */
12641 	if (tab->replicaIdentityIndex)
12642 	{
12643 		AlterTableCmd *cmd = makeNode(AlterTableCmd);
12644 		ReplicaIdentityStmt *subcmd = makeNode(ReplicaIdentityStmt);
12645 
12646 		subcmd->identity_type = REPLICA_IDENTITY_INDEX;
12647 		subcmd->name = tab->replicaIdentityIndex;
12648 		cmd->subtype = AT_ReplicaIdentity;
12649 		cmd->def = (Node *) subcmd;
12650 
12651 		/* do it after indexes and constraints */
12652 		tab->subcmds[AT_PASS_OLD_CONSTR] =
12653 			lappend(tab->subcmds[AT_PASS_OLD_CONSTR], cmd);
12654 	}
12655 
12656 	/*
12657 	 * Queue up command to restore marking of index used for cluster.
12658 	 */
12659 	if (tab->clusterOnIndex)
12660 	{
12661 		AlterTableCmd *cmd = makeNode(AlterTableCmd);
12662 
12663 		cmd->subtype = AT_ClusterOn;
12664 		cmd->name = tab->clusterOnIndex;
12665 
12666 		/* do it after indexes and constraints */
12667 		tab->subcmds[AT_PASS_OLD_CONSTR] =
12668 			lappend(tab->subcmds[AT_PASS_OLD_CONSTR], cmd);
12669 	}
12670 
12671 	/*
12672 	 * It should be okay to use DROP_RESTRICT here, since nothing else should
12673 	 * be depending on these objects.
12674 	 */
12675 	performMultipleDeletions(objects, DROP_RESTRICT, PERFORM_DELETION_INTERNAL);
12676 
12677 	free_object_addresses(objects);
12678 
12679 	/*
12680 	 * The objects will get recreated during subsequent passes over the work
12681 	 * queue.
12682 	 */
12683 }
12684 
12685 /*
12686  * Parse the previously-saved definition string for a constraint, index or
12687  * statistics object against the newly-established column data type(s), and
12688  * queue up the resulting command parsetrees for execution.
12689  *
12690  * This might fail if, for example, you have a WHERE clause that uses an
12691  * operator that's not available for the new column type.
12692  */
12693 static void
ATPostAlterTypeParse(Oid oldId,Oid oldRelId,Oid refRelId,char * cmd,List ** wqueue,LOCKMODE lockmode,bool rewrite)12694 ATPostAlterTypeParse(Oid oldId, Oid oldRelId, Oid refRelId, char *cmd,
12695 					 List **wqueue, LOCKMODE lockmode, bool rewrite)
12696 {
12697 	List	   *raw_parsetree_list;
12698 	List	   *querytree_list;
12699 	ListCell   *list_item;
12700 	Relation	rel;
12701 
12702 	/*
12703 	 * We expect that we will get only ALTER TABLE and CREATE INDEX
12704 	 * statements. Hence, there is no need to pass them through
12705 	 * parse_analyze() or the rewriter, but instead we need to pass them
12706 	 * through parse_utilcmd.c to make them ready for execution.
12707 	 */
12708 	raw_parsetree_list = raw_parser(cmd, RAW_PARSE_DEFAULT);
12709 	querytree_list = NIL;
12710 	foreach(list_item, raw_parsetree_list)
12711 	{
12712 		RawStmt    *rs = lfirst_node(RawStmt, list_item);
12713 		Node	   *stmt = rs->stmt;
12714 
12715 		if (IsA(stmt, IndexStmt))
12716 			querytree_list = lappend(querytree_list,
12717 									 transformIndexStmt(oldRelId,
12718 														(IndexStmt *) stmt,
12719 														cmd));
12720 		else if (IsA(stmt, AlterTableStmt))
12721 		{
12722 			List	   *beforeStmts;
12723 			List	   *afterStmts;
12724 
12725 			stmt = (Node *) transformAlterTableStmt(oldRelId,
12726 													(AlterTableStmt *) stmt,
12727 													cmd,
12728 													&beforeStmts,
12729 													&afterStmts);
12730 			querytree_list = list_concat(querytree_list, beforeStmts);
12731 			querytree_list = lappend(querytree_list, stmt);
12732 			querytree_list = list_concat(querytree_list, afterStmts);
12733 		}
12734 		else if (IsA(stmt, CreateStatsStmt))
12735 			querytree_list = lappend(querytree_list,
12736 									 transformStatsStmt(oldRelId,
12737 														(CreateStatsStmt *) stmt,
12738 														cmd));
12739 		else
12740 			querytree_list = lappend(querytree_list, stmt);
12741 	}
12742 
12743 	/* Caller should already have acquired whatever lock we need. */
12744 	rel = relation_open(oldRelId, NoLock);
12745 
12746 	/*
12747 	 * Attach each generated command to the proper place in the work queue.
12748 	 * Note this could result in creation of entirely new work-queue entries.
12749 	 *
12750 	 * Also note that we have to tweak the command subtypes, because it turns
12751 	 * out that re-creation of indexes and constraints has to act a bit
12752 	 * differently from initial creation.
12753 	 */
12754 	foreach(list_item, querytree_list)
12755 	{
12756 		Node	   *stm = (Node *) lfirst(list_item);
12757 		AlteredTableInfo *tab;
12758 
12759 		tab = ATGetQueueEntry(wqueue, rel);
12760 
12761 		if (IsA(stm, IndexStmt))
12762 		{
12763 			IndexStmt  *stmt = (IndexStmt *) stm;
12764 			AlterTableCmd *newcmd;
12765 
12766 			if (!rewrite)
12767 				TryReuseIndex(oldId, stmt);
12768 			stmt->reset_default_tblspc = true;
12769 			/* keep the index's comment */
12770 			stmt->idxcomment = GetComment(oldId, RelationRelationId, 0);
12771 
12772 			newcmd = makeNode(AlterTableCmd);
12773 			newcmd->subtype = AT_ReAddIndex;
12774 			newcmd->def = (Node *) stmt;
12775 			tab->subcmds[AT_PASS_OLD_INDEX] =
12776 				lappend(tab->subcmds[AT_PASS_OLD_INDEX], newcmd);
12777 		}
12778 		else if (IsA(stm, AlterTableStmt))
12779 		{
12780 			AlterTableStmt *stmt = (AlterTableStmt *) stm;
12781 			ListCell   *lcmd;
12782 
12783 			foreach(lcmd, stmt->cmds)
12784 			{
12785 				AlterTableCmd *cmd = castNode(AlterTableCmd, lfirst(lcmd));
12786 
12787 				if (cmd->subtype == AT_AddIndex)
12788 				{
12789 					IndexStmt  *indstmt;
12790 					Oid			indoid;
12791 
12792 					indstmt = castNode(IndexStmt, cmd->def);
12793 					indoid = get_constraint_index(oldId);
12794 
12795 					if (!rewrite)
12796 						TryReuseIndex(indoid, indstmt);
12797 					/* keep any comment on the index */
12798 					indstmt->idxcomment = GetComment(indoid,
12799 													 RelationRelationId, 0);
12800 					indstmt->reset_default_tblspc = true;
12801 
12802 					cmd->subtype = AT_ReAddIndex;
12803 					tab->subcmds[AT_PASS_OLD_INDEX] =
12804 						lappend(tab->subcmds[AT_PASS_OLD_INDEX], cmd);
12805 
12806 					/* recreate any comment on the constraint */
12807 					RebuildConstraintComment(tab,
12808 											 AT_PASS_OLD_INDEX,
12809 											 oldId,
12810 											 rel,
12811 											 NIL,
12812 											 indstmt->idxname);
12813 				}
12814 				else if (cmd->subtype == AT_AddConstraint)
12815 				{
12816 					Constraint *con = castNode(Constraint, cmd->def);
12817 
12818 					con->old_pktable_oid = refRelId;
12819 					/* rewriting neither side of a FK */
12820 					if (con->contype == CONSTR_FOREIGN &&
12821 						!rewrite && tab->rewrite == 0)
12822 						TryReuseForeignKey(oldId, con);
12823 					con->reset_default_tblspc = true;
12824 					cmd->subtype = AT_ReAddConstraint;
12825 					tab->subcmds[AT_PASS_OLD_CONSTR] =
12826 						lappend(tab->subcmds[AT_PASS_OLD_CONSTR], cmd);
12827 
12828 					/* recreate any comment on the constraint */
12829 					RebuildConstraintComment(tab,
12830 											 AT_PASS_OLD_CONSTR,
12831 											 oldId,
12832 											 rel,
12833 											 NIL,
12834 											 con->conname);
12835 				}
12836 				else if (cmd->subtype == AT_SetNotNull)
12837 				{
12838 					/*
12839 					 * The parser will create AT_SetNotNull subcommands for
12840 					 * columns of PRIMARY KEY indexes/constraints, but we need
12841 					 * not do anything with them here, because the columns'
12842 					 * NOT NULL marks will already have been propagated into
12843 					 * the new table definition.
12844 					 */
12845 				}
12846 				else
12847 					elog(ERROR, "unexpected statement subtype: %d",
12848 						 (int) cmd->subtype);
12849 			}
12850 		}
12851 		else if (IsA(stm, AlterDomainStmt))
12852 		{
12853 			AlterDomainStmt *stmt = (AlterDomainStmt *) stm;
12854 
12855 			if (stmt->subtype == 'C')	/* ADD CONSTRAINT */
12856 			{
12857 				Constraint *con = castNode(Constraint, stmt->def);
12858 				AlterTableCmd *cmd = makeNode(AlterTableCmd);
12859 
12860 				cmd->subtype = AT_ReAddDomainConstraint;
12861 				cmd->def = (Node *) stmt;
12862 				tab->subcmds[AT_PASS_OLD_CONSTR] =
12863 					lappend(tab->subcmds[AT_PASS_OLD_CONSTR], cmd);
12864 
12865 				/* recreate any comment on the constraint */
12866 				RebuildConstraintComment(tab,
12867 										 AT_PASS_OLD_CONSTR,
12868 										 oldId,
12869 										 NULL,
12870 										 stmt->typeName,
12871 										 con->conname);
12872 			}
12873 			else
12874 				elog(ERROR, "unexpected statement subtype: %d",
12875 					 (int) stmt->subtype);
12876 		}
12877 		else if (IsA(stm, CreateStatsStmt))
12878 		{
12879 			CreateStatsStmt *stmt = (CreateStatsStmt *) stm;
12880 			AlterTableCmd *newcmd;
12881 
12882 			/* keep the statistics object's comment */
12883 			stmt->stxcomment = GetComment(oldId, StatisticExtRelationId, 0);
12884 
12885 			newcmd = makeNode(AlterTableCmd);
12886 			newcmd->subtype = AT_ReAddStatistics;
12887 			newcmd->def = (Node *) stmt;
12888 			tab->subcmds[AT_PASS_MISC] =
12889 				lappend(tab->subcmds[AT_PASS_MISC], newcmd);
12890 		}
12891 		else
12892 			elog(ERROR, "unexpected statement type: %d",
12893 				 (int) nodeTag(stm));
12894 	}
12895 
12896 	relation_close(rel, NoLock);
12897 }
12898 
12899 /*
12900  * Subroutine for ATPostAlterTypeParse() to recreate any existing comment
12901  * for a table or domain constraint that is being rebuilt.
12902  *
12903  * objid is the OID of the constraint.
12904  * Pass "rel" for a table constraint, or "domname" (domain's qualified name
12905  * as a string list) for a domain constraint.
12906  * (We could dig that info, as well as the conname, out of the pg_constraint
12907  * entry; but callers already have them so might as well pass them.)
12908  */
12909 static void
RebuildConstraintComment(AlteredTableInfo * tab,int pass,Oid objid,Relation rel,List * domname,const char * conname)12910 RebuildConstraintComment(AlteredTableInfo *tab, int pass, Oid objid,
12911 						 Relation rel, List *domname,
12912 						 const char *conname)
12913 {
12914 	CommentStmt *cmd;
12915 	char	   *comment_str;
12916 	AlterTableCmd *newcmd;
12917 
12918 	/* Look for comment for object wanted, and leave if none */
12919 	comment_str = GetComment(objid, ConstraintRelationId, 0);
12920 	if (comment_str == NULL)
12921 		return;
12922 
12923 	/* Build CommentStmt node, copying all input data for safety */
12924 	cmd = makeNode(CommentStmt);
12925 	if (rel)
12926 	{
12927 		cmd->objtype = OBJECT_TABCONSTRAINT;
12928 		cmd->object = (Node *)
12929 			list_make3(makeString(get_namespace_name(RelationGetNamespace(rel))),
12930 					   makeString(pstrdup(RelationGetRelationName(rel))),
12931 					   makeString(pstrdup(conname)));
12932 	}
12933 	else
12934 	{
12935 		cmd->objtype = OBJECT_DOMCONSTRAINT;
12936 		cmd->object = (Node *)
12937 			list_make2(makeTypeNameFromNameList(copyObject(domname)),
12938 					   makeString(pstrdup(conname)));
12939 	}
12940 	cmd->comment = comment_str;
12941 
12942 	/* Append it to list of commands */
12943 	newcmd = makeNode(AlterTableCmd);
12944 	newcmd->subtype = AT_ReAddComment;
12945 	newcmd->def = (Node *) cmd;
12946 	tab->subcmds[pass] = lappend(tab->subcmds[pass], newcmd);
12947 }
12948 
12949 /*
12950  * Subroutine for ATPostAlterTypeParse().  Calls out to CheckIndexCompatible()
12951  * for the real analysis, then mutates the IndexStmt based on that verdict.
12952  */
12953 static void
TryReuseIndex(Oid oldId,IndexStmt * stmt)12954 TryReuseIndex(Oid oldId, IndexStmt *stmt)
12955 {
12956 	if (CheckIndexCompatible(oldId,
12957 							 stmt->accessMethod,
12958 							 stmt->indexParams,
12959 							 stmt->excludeOpNames))
12960 	{
12961 		Relation	irel = index_open(oldId, NoLock);
12962 
12963 		/* If it's a partitioned index, there is no storage to share. */
12964 		if (irel->rd_rel->relkind != RELKIND_PARTITIONED_INDEX)
12965 		{
12966 			stmt->oldNode = irel->rd_node.relNode;
12967 			stmt->oldCreateSubid = irel->rd_createSubid;
12968 			stmt->oldFirstRelfilenodeSubid = irel->rd_firstRelfilenodeSubid;
12969 		}
12970 		index_close(irel, NoLock);
12971 	}
12972 }
12973 
12974 /*
12975  * Subroutine for ATPostAlterTypeParse().
12976  *
12977  * Stash the old P-F equality operator into the Constraint node, for possible
12978  * use by ATAddForeignKeyConstraint() in determining whether revalidation of
12979  * this constraint can be skipped.
12980  */
12981 static void
TryReuseForeignKey(Oid oldId,Constraint * con)12982 TryReuseForeignKey(Oid oldId, Constraint *con)
12983 {
12984 	HeapTuple	tup;
12985 	Datum		adatum;
12986 	bool		isNull;
12987 	ArrayType  *arr;
12988 	Oid		   *rawarr;
12989 	int			numkeys;
12990 	int			i;
12991 
12992 	Assert(con->contype == CONSTR_FOREIGN);
12993 	Assert(con->old_conpfeqop == NIL);	/* already prepared this node */
12994 
12995 	tup = SearchSysCache1(CONSTROID, ObjectIdGetDatum(oldId));
12996 	if (!HeapTupleIsValid(tup)) /* should not happen */
12997 		elog(ERROR, "cache lookup failed for constraint %u", oldId);
12998 
12999 	adatum = SysCacheGetAttr(CONSTROID, tup,
13000 							 Anum_pg_constraint_conpfeqop, &isNull);
13001 	if (isNull)
13002 		elog(ERROR, "null conpfeqop for constraint %u", oldId);
13003 	arr = DatumGetArrayTypeP(adatum);	/* ensure not toasted */
13004 	numkeys = ARR_DIMS(arr)[0];
13005 	/* test follows the one in ri_FetchConstraintInfo() */
13006 	if (ARR_NDIM(arr) != 1 ||
13007 		ARR_HASNULL(arr) ||
13008 		ARR_ELEMTYPE(arr) != OIDOID)
13009 		elog(ERROR, "conpfeqop is not a 1-D Oid array");
13010 	rawarr = (Oid *) ARR_DATA_PTR(arr);
13011 
13012 	/* stash a List of the operator Oids in our Constraint node */
13013 	for (i = 0; i < numkeys; i++)
13014 		con->old_conpfeqop = lappend_oid(con->old_conpfeqop, rawarr[i]);
13015 
13016 	ReleaseSysCache(tup);
13017 }
13018 
13019 /*
13020  * ALTER COLUMN .. OPTIONS ( ... )
13021  *
13022  * Returns the address of the modified column
13023  */
13024 static ObjectAddress
ATExecAlterColumnGenericOptions(Relation rel,const char * colName,List * options,LOCKMODE lockmode)13025 ATExecAlterColumnGenericOptions(Relation rel,
13026 								const char *colName,
13027 								List *options,
13028 								LOCKMODE lockmode)
13029 {
13030 	Relation	ftrel;
13031 	Relation	attrel;
13032 	ForeignServer *server;
13033 	ForeignDataWrapper *fdw;
13034 	HeapTuple	tuple;
13035 	HeapTuple	newtuple;
13036 	bool		isnull;
13037 	Datum		repl_val[Natts_pg_attribute];
13038 	bool		repl_null[Natts_pg_attribute];
13039 	bool		repl_repl[Natts_pg_attribute];
13040 	Datum		datum;
13041 	Form_pg_foreign_table fttableform;
13042 	Form_pg_attribute atttableform;
13043 	AttrNumber	attnum;
13044 	ObjectAddress address;
13045 
13046 	if (options == NIL)
13047 		return InvalidObjectAddress;
13048 
13049 	/* First, determine FDW validator associated to the foreign table. */
13050 	ftrel = table_open(ForeignTableRelationId, AccessShareLock);
13051 	tuple = SearchSysCache1(FOREIGNTABLEREL, rel->rd_id);
13052 	if (!HeapTupleIsValid(tuple))
13053 		ereport(ERROR,
13054 				(errcode(ERRCODE_UNDEFINED_OBJECT),
13055 				 errmsg("foreign table \"%s\" does not exist",
13056 						RelationGetRelationName(rel))));
13057 	fttableform = (Form_pg_foreign_table) GETSTRUCT(tuple);
13058 	server = GetForeignServer(fttableform->ftserver);
13059 	fdw = GetForeignDataWrapper(server->fdwid);
13060 
13061 	table_close(ftrel, AccessShareLock);
13062 	ReleaseSysCache(tuple);
13063 
13064 	attrel = table_open(AttributeRelationId, RowExclusiveLock);
13065 	tuple = SearchSysCacheAttName(RelationGetRelid(rel), colName);
13066 	if (!HeapTupleIsValid(tuple))
13067 		ereport(ERROR,
13068 				(errcode(ERRCODE_UNDEFINED_COLUMN),
13069 				 errmsg("column \"%s\" of relation \"%s\" does not exist",
13070 						colName, RelationGetRelationName(rel))));
13071 
13072 	/* Prevent them from altering a system attribute */
13073 	atttableform = (Form_pg_attribute) GETSTRUCT(tuple);
13074 	attnum = atttableform->attnum;
13075 	if (attnum <= 0)
13076 		ereport(ERROR,
13077 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
13078 				 errmsg("cannot alter system column \"%s\"", colName)));
13079 
13080 
13081 	/* Initialize buffers for new tuple values */
13082 	memset(repl_val, 0, sizeof(repl_val));
13083 	memset(repl_null, false, sizeof(repl_null));
13084 	memset(repl_repl, false, sizeof(repl_repl));
13085 
13086 	/* Extract the current options */
13087 	datum = SysCacheGetAttr(ATTNAME,
13088 							tuple,
13089 							Anum_pg_attribute_attfdwoptions,
13090 							&isnull);
13091 	if (isnull)
13092 		datum = PointerGetDatum(NULL);
13093 
13094 	/* Transform the options */
13095 	datum = transformGenericOptions(AttributeRelationId,
13096 									datum,
13097 									options,
13098 									fdw->fdwvalidator);
13099 
13100 	if (PointerIsValid(DatumGetPointer(datum)))
13101 		repl_val[Anum_pg_attribute_attfdwoptions - 1] = datum;
13102 	else
13103 		repl_null[Anum_pg_attribute_attfdwoptions - 1] = true;
13104 
13105 	repl_repl[Anum_pg_attribute_attfdwoptions - 1] = true;
13106 
13107 	/* Everything looks good - update the tuple */
13108 
13109 	newtuple = heap_modify_tuple(tuple, RelationGetDescr(attrel),
13110 								 repl_val, repl_null, repl_repl);
13111 
13112 	CatalogTupleUpdate(attrel, &newtuple->t_self, newtuple);
13113 
13114 	InvokeObjectPostAlterHook(RelationRelationId,
13115 							  RelationGetRelid(rel),
13116 							  atttableform->attnum);
13117 	ObjectAddressSubSet(address, RelationRelationId,
13118 						RelationGetRelid(rel), attnum);
13119 
13120 	ReleaseSysCache(tuple);
13121 
13122 	table_close(attrel, RowExclusiveLock);
13123 
13124 	heap_freetuple(newtuple);
13125 
13126 	return address;
13127 }
13128 
13129 /*
13130  * ALTER TABLE OWNER
13131  *
13132  * recursing is true if we are recursing from a table to its indexes,
13133  * sequences, or toast table.  We don't allow the ownership of those things to
13134  * be changed separately from the parent table.  Also, we can skip permission
13135  * checks (this is necessary not just an optimization, else we'd fail to
13136  * handle toast tables properly).
13137  *
13138  * recursing is also true if ALTER TYPE OWNER is calling us to fix up a
13139  * free-standing composite type.
13140  */
13141 void
ATExecChangeOwner(Oid relationOid,Oid newOwnerId,bool recursing,LOCKMODE lockmode)13142 ATExecChangeOwner(Oid relationOid, Oid newOwnerId, bool recursing, LOCKMODE lockmode)
13143 {
13144 	Relation	target_rel;
13145 	Relation	class_rel;
13146 	HeapTuple	tuple;
13147 	Form_pg_class tuple_class;
13148 
13149 	/*
13150 	 * Get exclusive lock till end of transaction on the target table. Use
13151 	 * relation_open so that we can work on indexes and sequences.
13152 	 */
13153 	target_rel = relation_open(relationOid, lockmode);
13154 
13155 	/* Get its pg_class tuple, too */
13156 	class_rel = table_open(RelationRelationId, RowExclusiveLock);
13157 
13158 	tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relationOid));
13159 	if (!HeapTupleIsValid(tuple))
13160 		elog(ERROR, "cache lookup failed for relation %u", relationOid);
13161 	tuple_class = (Form_pg_class) GETSTRUCT(tuple);
13162 
13163 	/* Can we change the ownership of this tuple? */
13164 	switch (tuple_class->relkind)
13165 	{
13166 		case RELKIND_RELATION:
13167 		case RELKIND_VIEW:
13168 		case RELKIND_MATVIEW:
13169 		case RELKIND_FOREIGN_TABLE:
13170 		case RELKIND_PARTITIONED_TABLE:
13171 			/* ok to change owner */
13172 			break;
13173 		case RELKIND_INDEX:
13174 			if (!recursing)
13175 			{
13176 				/*
13177 				 * Because ALTER INDEX OWNER used to be allowed, and in fact
13178 				 * is generated by old versions of pg_dump, we give a warning
13179 				 * and do nothing rather than erroring out.  Also, to avoid
13180 				 * unnecessary chatter while restoring those old dumps, say
13181 				 * nothing at all if the command would be a no-op anyway.
13182 				 */
13183 				if (tuple_class->relowner != newOwnerId)
13184 					ereport(WARNING,
13185 							(errcode(ERRCODE_WRONG_OBJECT_TYPE),
13186 							 errmsg("cannot change owner of index \"%s\"",
13187 									NameStr(tuple_class->relname)),
13188 							 errhint("Change the ownership of the index's table, instead.")));
13189 				/* quick hack to exit via the no-op path */
13190 				newOwnerId = tuple_class->relowner;
13191 			}
13192 			break;
13193 		case RELKIND_PARTITIONED_INDEX:
13194 			if (recursing)
13195 				break;
13196 			ereport(ERROR,
13197 					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
13198 					 errmsg("cannot change owner of index \"%s\"",
13199 							NameStr(tuple_class->relname)),
13200 					 errhint("Change the ownership of the index's table, instead.")));
13201 			break;
13202 		case RELKIND_SEQUENCE:
13203 			if (!recursing &&
13204 				tuple_class->relowner != newOwnerId)
13205 			{
13206 				/* if it's an owned sequence, disallow changing it by itself */
13207 				Oid			tableId;
13208 				int32		colId;
13209 
13210 				if (sequenceIsOwned(relationOid, DEPENDENCY_AUTO, &tableId, &colId) ||
13211 					sequenceIsOwned(relationOid, DEPENDENCY_INTERNAL, &tableId, &colId))
13212 					ereport(ERROR,
13213 							(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
13214 							 errmsg("cannot change owner of sequence \"%s\"",
13215 									NameStr(tuple_class->relname)),
13216 							 errdetail("Sequence \"%s\" is linked to table \"%s\".",
13217 									   NameStr(tuple_class->relname),
13218 									   get_rel_name(tableId))));
13219 			}
13220 			break;
13221 		case RELKIND_COMPOSITE_TYPE:
13222 			if (recursing)
13223 				break;
13224 			ereport(ERROR,
13225 					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
13226 					 errmsg("\"%s\" is a composite type",
13227 							NameStr(tuple_class->relname)),
13228 					 errhint("Use ALTER TYPE instead.")));
13229 			break;
13230 		case RELKIND_TOASTVALUE:
13231 			if (recursing)
13232 				break;
13233 			/* FALL THRU */
13234 		default:
13235 			ereport(ERROR,
13236 					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
13237 					 errmsg("\"%s\" is not a table, view, sequence, or foreign table",
13238 							NameStr(tuple_class->relname))));
13239 	}
13240 
13241 	/*
13242 	 * If the new owner is the same as the existing owner, consider the
13243 	 * command to have succeeded.  This is for dump restoration purposes.
13244 	 */
13245 	if (tuple_class->relowner != newOwnerId)
13246 	{
13247 		Datum		repl_val[Natts_pg_class];
13248 		bool		repl_null[Natts_pg_class];
13249 		bool		repl_repl[Natts_pg_class];
13250 		Acl		   *newAcl;
13251 		Datum		aclDatum;
13252 		bool		isNull;
13253 		HeapTuple	newtuple;
13254 
13255 		/* skip permission checks when recursing to index or toast table */
13256 		if (!recursing)
13257 		{
13258 			/* Superusers can always do it */
13259 			if (!superuser())
13260 			{
13261 				Oid			namespaceOid = tuple_class->relnamespace;
13262 				AclResult	aclresult;
13263 
13264 				/* Otherwise, must be owner of the existing object */
13265 				if (!pg_class_ownercheck(relationOid, GetUserId()))
13266 					aclcheck_error(ACLCHECK_NOT_OWNER, get_relkind_objtype(get_rel_relkind(relationOid)),
13267 								   RelationGetRelationName(target_rel));
13268 
13269 				/* Must be able to become new owner */
13270 				check_is_member_of_role(GetUserId(), newOwnerId);
13271 
13272 				/* New owner must have CREATE privilege on namespace */
13273 				aclresult = pg_namespace_aclcheck(namespaceOid, newOwnerId,
13274 												  ACL_CREATE);
13275 				if (aclresult != ACLCHECK_OK)
13276 					aclcheck_error(aclresult, OBJECT_SCHEMA,
13277 								   get_namespace_name(namespaceOid));
13278 			}
13279 		}
13280 
13281 		memset(repl_null, false, sizeof(repl_null));
13282 		memset(repl_repl, false, sizeof(repl_repl));
13283 
13284 		repl_repl[Anum_pg_class_relowner - 1] = true;
13285 		repl_val[Anum_pg_class_relowner - 1] = ObjectIdGetDatum(newOwnerId);
13286 
13287 		/*
13288 		 * Determine the modified ACL for the new owner.  This is only
13289 		 * necessary when the ACL is non-null.
13290 		 */
13291 		aclDatum = SysCacheGetAttr(RELOID, tuple,
13292 								   Anum_pg_class_relacl,
13293 								   &isNull);
13294 		if (!isNull)
13295 		{
13296 			newAcl = aclnewowner(DatumGetAclP(aclDatum),
13297 								 tuple_class->relowner, newOwnerId);
13298 			repl_repl[Anum_pg_class_relacl - 1] = true;
13299 			repl_val[Anum_pg_class_relacl - 1] = PointerGetDatum(newAcl);
13300 		}
13301 
13302 		newtuple = heap_modify_tuple(tuple, RelationGetDescr(class_rel), repl_val, repl_null, repl_repl);
13303 
13304 		CatalogTupleUpdate(class_rel, &newtuple->t_self, newtuple);
13305 
13306 		heap_freetuple(newtuple);
13307 
13308 		/*
13309 		 * We must similarly update any per-column ACLs to reflect the new
13310 		 * owner; for neatness reasons that's split out as a subroutine.
13311 		 */
13312 		change_owner_fix_column_acls(relationOid,
13313 									 tuple_class->relowner,
13314 									 newOwnerId);
13315 
13316 		/*
13317 		 * Update owner dependency reference, if any.  A composite type has
13318 		 * none, because it's tracked for the pg_type entry instead of here;
13319 		 * indexes and TOAST tables don't have their own entries either.
13320 		 */
13321 		if (tuple_class->relkind != RELKIND_COMPOSITE_TYPE &&
13322 			tuple_class->relkind != RELKIND_INDEX &&
13323 			tuple_class->relkind != RELKIND_PARTITIONED_INDEX &&
13324 			tuple_class->relkind != RELKIND_TOASTVALUE)
13325 			changeDependencyOnOwner(RelationRelationId, relationOid,
13326 									newOwnerId);
13327 
13328 		/*
13329 		 * Also change the ownership of the table's row type, if it has one
13330 		 */
13331 		if (OidIsValid(tuple_class->reltype))
13332 			AlterTypeOwnerInternal(tuple_class->reltype, newOwnerId);
13333 
13334 		/*
13335 		 * If we are operating on a table or materialized view, also change
13336 		 * the ownership of any indexes and sequences that belong to the
13337 		 * relation, as well as its toast table (if it has one).
13338 		 */
13339 		if (tuple_class->relkind == RELKIND_RELATION ||
13340 			tuple_class->relkind == RELKIND_PARTITIONED_TABLE ||
13341 			tuple_class->relkind == RELKIND_MATVIEW ||
13342 			tuple_class->relkind == RELKIND_TOASTVALUE)
13343 		{
13344 			List	   *index_oid_list;
13345 			ListCell   *i;
13346 
13347 			/* Find all the indexes belonging to this relation */
13348 			index_oid_list = RelationGetIndexList(target_rel);
13349 
13350 			/* For each index, recursively change its ownership */
13351 			foreach(i, index_oid_list)
13352 				ATExecChangeOwner(lfirst_oid(i), newOwnerId, true, lockmode);
13353 
13354 			list_free(index_oid_list);
13355 		}
13356 
13357 		/* If it has a toast table, recurse to change its ownership */
13358 		if (tuple_class->reltoastrelid != InvalidOid)
13359 			ATExecChangeOwner(tuple_class->reltoastrelid, newOwnerId,
13360 							  true, lockmode);
13361 
13362 		/* If it has dependent sequences, recurse to change them too */
13363 		change_owner_recurse_to_sequences(relationOid, newOwnerId, lockmode);
13364 	}
13365 
13366 	InvokeObjectPostAlterHook(RelationRelationId, relationOid, 0);
13367 
13368 	ReleaseSysCache(tuple);
13369 	table_close(class_rel, RowExclusiveLock);
13370 	relation_close(target_rel, NoLock);
13371 }
13372 
13373 /*
13374  * change_owner_fix_column_acls
13375  *
13376  * Helper function for ATExecChangeOwner.  Scan the columns of the table
13377  * and fix any non-null column ACLs to reflect the new owner.
13378  */
13379 static void
change_owner_fix_column_acls(Oid relationOid,Oid oldOwnerId,Oid newOwnerId)13380 change_owner_fix_column_acls(Oid relationOid, Oid oldOwnerId, Oid newOwnerId)
13381 {
13382 	Relation	attRelation;
13383 	SysScanDesc scan;
13384 	ScanKeyData key[1];
13385 	HeapTuple	attributeTuple;
13386 
13387 	attRelation = table_open(AttributeRelationId, RowExclusiveLock);
13388 	ScanKeyInit(&key[0],
13389 				Anum_pg_attribute_attrelid,
13390 				BTEqualStrategyNumber, F_OIDEQ,
13391 				ObjectIdGetDatum(relationOid));
13392 	scan = systable_beginscan(attRelation, AttributeRelidNumIndexId,
13393 							  true, NULL, 1, key);
13394 	while (HeapTupleIsValid(attributeTuple = systable_getnext(scan)))
13395 	{
13396 		Form_pg_attribute att = (Form_pg_attribute) GETSTRUCT(attributeTuple);
13397 		Datum		repl_val[Natts_pg_attribute];
13398 		bool		repl_null[Natts_pg_attribute];
13399 		bool		repl_repl[Natts_pg_attribute];
13400 		Acl		   *newAcl;
13401 		Datum		aclDatum;
13402 		bool		isNull;
13403 		HeapTuple	newtuple;
13404 
13405 		/* Ignore dropped columns */
13406 		if (att->attisdropped)
13407 			continue;
13408 
13409 		aclDatum = heap_getattr(attributeTuple,
13410 								Anum_pg_attribute_attacl,
13411 								RelationGetDescr(attRelation),
13412 								&isNull);
13413 		/* Null ACLs do not require changes */
13414 		if (isNull)
13415 			continue;
13416 
13417 		memset(repl_null, false, sizeof(repl_null));
13418 		memset(repl_repl, false, sizeof(repl_repl));
13419 
13420 		newAcl = aclnewowner(DatumGetAclP(aclDatum),
13421 							 oldOwnerId, newOwnerId);
13422 		repl_repl[Anum_pg_attribute_attacl - 1] = true;
13423 		repl_val[Anum_pg_attribute_attacl - 1] = PointerGetDatum(newAcl);
13424 
13425 		newtuple = heap_modify_tuple(attributeTuple,
13426 									 RelationGetDescr(attRelation),
13427 									 repl_val, repl_null, repl_repl);
13428 
13429 		CatalogTupleUpdate(attRelation, &newtuple->t_self, newtuple);
13430 
13431 		heap_freetuple(newtuple);
13432 	}
13433 	systable_endscan(scan);
13434 	table_close(attRelation, RowExclusiveLock);
13435 }
13436 
13437 /*
13438  * change_owner_recurse_to_sequences
13439  *
13440  * Helper function for ATExecChangeOwner.  Examines pg_depend searching
13441  * for sequences that are dependent on serial columns, and changes their
13442  * ownership.
13443  */
13444 static void
change_owner_recurse_to_sequences(Oid relationOid,Oid newOwnerId,LOCKMODE lockmode)13445 change_owner_recurse_to_sequences(Oid relationOid, Oid newOwnerId, LOCKMODE lockmode)
13446 {
13447 	Relation	depRel;
13448 	SysScanDesc scan;
13449 	ScanKeyData key[2];
13450 	HeapTuple	tup;
13451 
13452 	/*
13453 	 * SERIAL sequences are those having an auto dependency on one of the
13454 	 * table's columns (we don't care *which* column, exactly).
13455 	 */
13456 	depRel = table_open(DependRelationId, AccessShareLock);
13457 
13458 	ScanKeyInit(&key[0],
13459 				Anum_pg_depend_refclassid,
13460 				BTEqualStrategyNumber, F_OIDEQ,
13461 				ObjectIdGetDatum(RelationRelationId));
13462 	ScanKeyInit(&key[1],
13463 				Anum_pg_depend_refobjid,
13464 				BTEqualStrategyNumber, F_OIDEQ,
13465 				ObjectIdGetDatum(relationOid));
13466 	/* we leave refobjsubid unspecified */
13467 
13468 	scan = systable_beginscan(depRel, DependReferenceIndexId, true,
13469 							  NULL, 2, key);
13470 
13471 	while (HeapTupleIsValid(tup = systable_getnext(scan)))
13472 	{
13473 		Form_pg_depend depForm = (Form_pg_depend) GETSTRUCT(tup);
13474 		Relation	seqRel;
13475 
13476 		/* skip dependencies other than auto dependencies on columns */
13477 		if (depForm->refobjsubid == 0 ||
13478 			depForm->classid != RelationRelationId ||
13479 			depForm->objsubid != 0 ||
13480 			!(depForm->deptype == DEPENDENCY_AUTO || depForm->deptype == DEPENDENCY_INTERNAL))
13481 			continue;
13482 
13483 		/* Use relation_open just in case it's an index */
13484 		seqRel = relation_open(depForm->objid, lockmode);
13485 
13486 		/* skip non-sequence relations */
13487 		if (RelationGetForm(seqRel)->relkind != RELKIND_SEQUENCE)
13488 		{
13489 			/* No need to keep the lock */
13490 			relation_close(seqRel, lockmode);
13491 			continue;
13492 		}
13493 
13494 		/* We don't need to close the sequence while we alter it. */
13495 		ATExecChangeOwner(depForm->objid, newOwnerId, true, lockmode);
13496 
13497 		/* Now we can close it.  Keep the lock till end of transaction. */
13498 		relation_close(seqRel, NoLock);
13499 	}
13500 
13501 	systable_endscan(scan);
13502 
13503 	relation_close(depRel, AccessShareLock);
13504 }
13505 
13506 /*
13507  * ALTER TABLE CLUSTER ON
13508  *
13509  * The only thing we have to do is to change the indisclustered bits.
13510  *
13511  * Return the address of the new clustering index.
13512  */
13513 static ObjectAddress
ATExecClusterOn(Relation rel,const char * indexName,LOCKMODE lockmode)13514 ATExecClusterOn(Relation rel, const char *indexName, LOCKMODE lockmode)
13515 {
13516 	Oid			indexOid;
13517 	ObjectAddress address;
13518 
13519 	indexOid = get_relname_relid(indexName, rel->rd_rel->relnamespace);
13520 
13521 	if (!OidIsValid(indexOid))
13522 		ereport(ERROR,
13523 				(errcode(ERRCODE_UNDEFINED_OBJECT),
13524 				 errmsg("index \"%s\" for table \"%s\" does not exist",
13525 						indexName, RelationGetRelationName(rel))));
13526 
13527 	/* Check index is valid to cluster on */
13528 	check_index_is_clusterable(rel, indexOid, false, lockmode);
13529 
13530 	/* And do the work */
13531 	mark_index_clustered(rel, indexOid, false);
13532 
13533 	ObjectAddressSet(address,
13534 					 RelationRelationId, indexOid);
13535 
13536 	return address;
13537 }
13538 
13539 /*
13540  * ALTER TABLE SET WITHOUT CLUSTER
13541  *
13542  * We have to find any indexes on the table that have indisclustered bit
13543  * set and turn it off.
13544  */
13545 static void
ATExecDropCluster(Relation rel,LOCKMODE lockmode)13546 ATExecDropCluster(Relation rel, LOCKMODE lockmode)
13547 {
13548 	mark_index_clustered(rel, InvalidOid, false);
13549 }
13550 
13551 /*
13552  * ALTER TABLE SET TABLESPACE
13553  */
13554 static void
ATPrepSetTableSpace(AlteredTableInfo * tab,Relation rel,const char * tablespacename,LOCKMODE lockmode)13555 ATPrepSetTableSpace(AlteredTableInfo *tab, Relation rel, const char *tablespacename, LOCKMODE lockmode)
13556 {
13557 	Oid			tablespaceId;
13558 
13559 	/* Check that the tablespace exists */
13560 	tablespaceId = get_tablespace_oid(tablespacename, false);
13561 
13562 	/* Check permissions except when moving to database's default */
13563 	if (OidIsValid(tablespaceId) && tablespaceId != MyDatabaseTableSpace)
13564 	{
13565 		AclResult	aclresult;
13566 
13567 		aclresult = pg_tablespace_aclcheck(tablespaceId, GetUserId(), ACL_CREATE);
13568 		if (aclresult != ACLCHECK_OK)
13569 			aclcheck_error(aclresult, OBJECT_TABLESPACE, tablespacename);
13570 	}
13571 
13572 	/* Save info for Phase 3 to do the real work */
13573 	if (OidIsValid(tab->newTableSpace))
13574 		ereport(ERROR,
13575 				(errcode(ERRCODE_SYNTAX_ERROR),
13576 				 errmsg("cannot have multiple SET TABLESPACE subcommands")));
13577 
13578 	tab->newTableSpace = tablespaceId;
13579 }
13580 
13581 /*
13582  * Set, reset, or replace reloptions.
13583  */
13584 static void
ATExecSetRelOptions(Relation rel,List * defList,AlterTableType operation,LOCKMODE lockmode)13585 ATExecSetRelOptions(Relation rel, List *defList, AlterTableType operation,
13586 					LOCKMODE lockmode)
13587 {
13588 	Oid			relid;
13589 	Relation	pgclass;
13590 	HeapTuple	tuple;
13591 	HeapTuple	newtuple;
13592 	Datum		datum;
13593 	bool		isnull;
13594 	Datum		newOptions;
13595 	Datum		repl_val[Natts_pg_class];
13596 	bool		repl_null[Natts_pg_class];
13597 	bool		repl_repl[Natts_pg_class];
13598 	static char *validnsps[] = HEAP_RELOPT_NAMESPACES;
13599 
13600 	if (defList == NIL && operation != AT_ReplaceRelOptions)
13601 		return;					/* nothing to do */
13602 
13603 	pgclass = table_open(RelationRelationId, RowExclusiveLock);
13604 
13605 	/* Fetch heap tuple */
13606 	relid = RelationGetRelid(rel);
13607 	tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
13608 	if (!HeapTupleIsValid(tuple))
13609 		elog(ERROR, "cache lookup failed for relation %u", relid);
13610 
13611 	if (operation == AT_ReplaceRelOptions)
13612 	{
13613 		/*
13614 		 * If we're supposed to replace the reloptions list, we just pretend
13615 		 * there were none before.
13616 		 */
13617 		datum = (Datum) 0;
13618 		isnull = true;
13619 	}
13620 	else
13621 	{
13622 		/* Get the old reloptions */
13623 		datum = SysCacheGetAttr(RELOID, tuple, Anum_pg_class_reloptions,
13624 								&isnull);
13625 	}
13626 
13627 	/* Generate new proposed reloptions (text array) */
13628 	newOptions = transformRelOptions(isnull ? (Datum) 0 : datum,
13629 									 defList, NULL, validnsps, false,
13630 									 operation == AT_ResetRelOptions);
13631 
13632 	/* Validate */
13633 	switch (rel->rd_rel->relkind)
13634 	{
13635 		case RELKIND_RELATION:
13636 		case RELKIND_TOASTVALUE:
13637 		case RELKIND_MATVIEW:
13638 			(void) heap_reloptions(rel->rd_rel->relkind, newOptions, true);
13639 			break;
13640 		case RELKIND_PARTITIONED_TABLE:
13641 			(void) partitioned_table_reloptions(newOptions, true);
13642 			break;
13643 		case RELKIND_VIEW:
13644 			(void) view_reloptions(newOptions, true);
13645 			break;
13646 		case RELKIND_INDEX:
13647 		case RELKIND_PARTITIONED_INDEX:
13648 			(void) index_reloptions(rel->rd_indam->amoptions, newOptions, true);
13649 			break;
13650 		default:
13651 			ereport(ERROR,
13652 					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
13653 					 errmsg("\"%s\" is not a table, view, materialized view, index, or TOAST table",
13654 							RelationGetRelationName(rel))));
13655 			break;
13656 	}
13657 
13658 	/* Special-case validation of view options */
13659 	if (rel->rd_rel->relkind == RELKIND_VIEW)
13660 	{
13661 		Query	   *view_query = get_view_query(rel);
13662 		List	   *view_options = untransformRelOptions(newOptions);
13663 		ListCell   *cell;
13664 		bool		check_option = false;
13665 
13666 		foreach(cell, view_options)
13667 		{
13668 			DefElem    *defel = (DefElem *) lfirst(cell);
13669 
13670 			if (strcmp(defel->defname, "check_option") == 0)
13671 				check_option = true;
13672 		}
13673 
13674 		/*
13675 		 * If the check option is specified, look to see if the view is
13676 		 * actually auto-updatable or not.
13677 		 */
13678 		if (check_option)
13679 		{
13680 			const char *view_updatable_error =
13681 			view_query_is_auto_updatable(view_query, true);
13682 
13683 			if (view_updatable_error)
13684 				ereport(ERROR,
13685 						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
13686 						 errmsg("WITH CHECK OPTION is supported only on automatically updatable views"),
13687 						 errhint("%s", _(view_updatable_error))));
13688 		}
13689 	}
13690 
13691 	/*
13692 	 * All we need do here is update the pg_class row; the new options will be
13693 	 * propagated into relcaches during post-commit cache inval.
13694 	 */
13695 	memset(repl_val, 0, sizeof(repl_val));
13696 	memset(repl_null, false, sizeof(repl_null));
13697 	memset(repl_repl, false, sizeof(repl_repl));
13698 
13699 	if (newOptions != (Datum) 0)
13700 		repl_val[Anum_pg_class_reloptions - 1] = newOptions;
13701 	else
13702 		repl_null[Anum_pg_class_reloptions - 1] = true;
13703 
13704 	repl_repl[Anum_pg_class_reloptions - 1] = true;
13705 
13706 	newtuple = heap_modify_tuple(tuple, RelationGetDescr(pgclass),
13707 								 repl_val, repl_null, repl_repl);
13708 
13709 	CatalogTupleUpdate(pgclass, &newtuple->t_self, newtuple);
13710 
13711 	InvokeObjectPostAlterHook(RelationRelationId, RelationGetRelid(rel), 0);
13712 
13713 	heap_freetuple(newtuple);
13714 
13715 	ReleaseSysCache(tuple);
13716 
13717 	/* repeat the whole exercise for the toast table, if there's one */
13718 	if (OidIsValid(rel->rd_rel->reltoastrelid))
13719 	{
13720 		Relation	toastrel;
13721 		Oid			toastid = rel->rd_rel->reltoastrelid;
13722 
13723 		toastrel = table_open(toastid, lockmode);
13724 
13725 		/* Fetch heap tuple */
13726 		tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(toastid));
13727 		if (!HeapTupleIsValid(tuple))
13728 			elog(ERROR, "cache lookup failed for relation %u", toastid);
13729 
13730 		if (operation == AT_ReplaceRelOptions)
13731 		{
13732 			/*
13733 			 * If we're supposed to replace the reloptions list, we just
13734 			 * pretend there were none before.
13735 			 */
13736 			datum = (Datum) 0;
13737 			isnull = true;
13738 		}
13739 		else
13740 		{
13741 			/* Get the old reloptions */
13742 			datum = SysCacheGetAttr(RELOID, tuple, Anum_pg_class_reloptions,
13743 									&isnull);
13744 		}
13745 
13746 		newOptions = transformRelOptions(isnull ? (Datum) 0 : datum,
13747 										 defList, "toast", validnsps, false,
13748 										 operation == AT_ResetRelOptions);
13749 
13750 		(void) heap_reloptions(RELKIND_TOASTVALUE, newOptions, true);
13751 
13752 		memset(repl_val, 0, sizeof(repl_val));
13753 		memset(repl_null, false, sizeof(repl_null));
13754 		memset(repl_repl, false, sizeof(repl_repl));
13755 
13756 		if (newOptions != (Datum) 0)
13757 			repl_val[Anum_pg_class_reloptions - 1] = newOptions;
13758 		else
13759 			repl_null[Anum_pg_class_reloptions - 1] = true;
13760 
13761 		repl_repl[Anum_pg_class_reloptions - 1] = true;
13762 
13763 		newtuple = heap_modify_tuple(tuple, RelationGetDescr(pgclass),
13764 									 repl_val, repl_null, repl_repl);
13765 
13766 		CatalogTupleUpdate(pgclass, &newtuple->t_self, newtuple);
13767 
13768 		InvokeObjectPostAlterHookArg(RelationRelationId,
13769 									 RelationGetRelid(toastrel), 0,
13770 									 InvalidOid, true);
13771 
13772 		heap_freetuple(newtuple);
13773 
13774 		ReleaseSysCache(tuple);
13775 
13776 		table_close(toastrel, NoLock);
13777 	}
13778 
13779 	table_close(pgclass, RowExclusiveLock);
13780 }
13781 
13782 /*
13783  * Execute ALTER TABLE SET TABLESPACE for cases where there is no tuple
13784  * rewriting to be done, so we just want to copy the data as fast as possible.
13785  */
13786 static void
ATExecSetTableSpace(Oid tableOid,Oid newTableSpace,LOCKMODE lockmode)13787 ATExecSetTableSpace(Oid tableOid, Oid newTableSpace, LOCKMODE lockmode)
13788 {
13789 	Relation	rel;
13790 	Oid			reltoastrelid;
13791 	Oid			newrelfilenode;
13792 	RelFileNode newrnode;
13793 	List	   *reltoastidxids = NIL;
13794 	ListCell   *lc;
13795 
13796 	/*
13797 	 * Need lock here in case we are recursing to toast table or index
13798 	 */
13799 	rel = relation_open(tableOid, lockmode);
13800 
13801 	/* Check first if relation can be moved to new tablespace */
13802 	if (!CheckRelationTableSpaceMove(rel, newTableSpace))
13803 	{
13804 		InvokeObjectPostAlterHook(RelationRelationId,
13805 								  RelationGetRelid(rel), 0);
13806 		relation_close(rel, NoLock);
13807 		return;
13808 	}
13809 
13810 	reltoastrelid = rel->rd_rel->reltoastrelid;
13811 	/* Fetch the list of indexes on toast relation if necessary */
13812 	if (OidIsValid(reltoastrelid))
13813 	{
13814 		Relation	toastRel = relation_open(reltoastrelid, lockmode);
13815 
13816 		reltoastidxids = RelationGetIndexList(toastRel);
13817 		relation_close(toastRel, lockmode);
13818 	}
13819 
13820 	/*
13821 	 * Relfilenodes are not unique in databases across tablespaces, so we need
13822 	 * to allocate a new one in the new tablespace.
13823 	 */
13824 	newrelfilenode = GetNewRelFileNode(newTableSpace, NULL,
13825 									   rel->rd_rel->relpersistence);
13826 
13827 	/* Open old and new relation */
13828 	newrnode = rel->rd_node;
13829 	newrnode.relNode = newrelfilenode;
13830 	newrnode.spcNode = newTableSpace;
13831 
13832 	/* hand off to AM to actually create the new filenode and copy the data */
13833 	if (rel->rd_rel->relkind == RELKIND_INDEX)
13834 	{
13835 		index_copy_data(rel, newrnode);
13836 	}
13837 	else
13838 	{
13839 		Assert(rel->rd_rel->relkind == RELKIND_RELATION ||
13840 			   rel->rd_rel->relkind == RELKIND_MATVIEW ||
13841 			   rel->rd_rel->relkind == RELKIND_TOASTVALUE);
13842 		table_relation_copy_data(rel, &newrnode);
13843 	}
13844 
13845 	/*
13846 	 * Update the pg_class row.
13847 	 *
13848 	 * NB: This wouldn't work if ATExecSetTableSpace() were allowed to be
13849 	 * executed on pg_class or its indexes (the above copy wouldn't contain
13850 	 * the updated pg_class entry), but that's forbidden with
13851 	 * CheckRelationTableSpaceMove().
13852 	 */
13853 	SetRelationTableSpace(rel, newTableSpace, newrelfilenode);
13854 
13855 	InvokeObjectPostAlterHook(RelationRelationId, RelationGetRelid(rel), 0);
13856 
13857 	RelationAssumeNewRelfilenode(rel);
13858 
13859 	relation_close(rel, NoLock);
13860 
13861 	/* Make sure the reltablespace change is visible */
13862 	CommandCounterIncrement();
13863 
13864 	/* Move associated toast relation and/or indexes, too */
13865 	if (OidIsValid(reltoastrelid))
13866 		ATExecSetTableSpace(reltoastrelid, newTableSpace, lockmode);
13867 	foreach(lc, reltoastidxids)
13868 		ATExecSetTableSpace(lfirst_oid(lc), newTableSpace, lockmode);
13869 
13870 	/* Clean up */
13871 	list_free(reltoastidxids);
13872 }
13873 
13874 /*
13875  * Special handling of ALTER TABLE SET TABLESPACE for relations with no
13876  * storage that have an interest in preserving tablespace.
13877  *
13878  * Since these have no storage the tablespace can be updated with a simple
13879  * metadata only operation to update the tablespace.
13880  */
13881 static void
ATExecSetTableSpaceNoStorage(Relation rel,Oid newTableSpace)13882 ATExecSetTableSpaceNoStorage(Relation rel, Oid newTableSpace)
13883 {
13884 	/*
13885 	 * Shouldn't be called on relations having storage; these are processed in
13886 	 * phase 3.
13887 	 */
13888 	Assert(!RELKIND_HAS_STORAGE(rel->rd_rel->relkind));
13889 
13890 	/* check if relation can be moved to its new tablespace */
13891 	if (!CheckRelationTableSpaceMove(rel, newTableSpace))
13892 	{
13893 		InvokeObjectPostAlterHook(RelationRelationId,
13894 								  RelationGetRelid(rel),
13895 								  0);
13896 		return;
13897 	}
13898 
13899 	/* Update can be done, so change reltablespace */
13900 	SetRelationTableSpace(rel, newTableSpace, InvalidOid);
13901 
13902 	InvokeObjectPostAlterHook(RelationRelationId, RelationGetRelid(rel), 0);
13903 
13904 	/* Make sure the reltablespace change is visible */
13905 	CommandCounterIncrement();
13906 }
13907 
13908 /*
13909  * Alter Table ALL ... SET TABLESPACE
13910  *
13911  * Allows a user to move all objects of some type in a given tablespace in the
13912  * current database to another tablespace.  Objects can be chosen based on the
13913  * owner of the object also, to allow users to move only their objects.
13914  * The user must have CREATE rights on the new tablespace, as usual.   The main
13915  * permissions handling is done by the lower-level table move function.
13916  *
13917  * All to-be-moved objects are locked first. If NOWAIT is specified and the
13918  * lock can't be acquired then we ereport(ERROR).
13919  */
13920 Oid
AlterTableMoveAll(AlterTableMoveAllStmt * stmt)13921 AlterTableMoveAll(AlterTableMoveAllStmt *stmt)
13922 {
13923 	List	   *relations = NIL;
13924 	ListCell   *l;
13925 	ScanKeyData key[1];
13926 	Relation	rel;
13927 	TableScanDesc scan;
13928 	HeapTuple	tuple;
13929 	Oid			orig_tablespaceoid;
13930 	Oid			new_tablespaceoid;
13931 	List	   *role_oids = roleSpecsToIds(stmt->roles);
13932 
13933 	/* Ensure we were not asked to move something we can't */
13934 	if (stmt->objtype != OBJECT_TABLE && stmt->objtype != OBJECT_INDEX &&
13935 		stmt->objtype != OBJECT_MATVIEW)
13936 		ereport(ERROR,
13937 				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
13938 				 errmsg("only tables, indexes, and materialized views exist in tablespaces")));
13939 
13940 	/* Get the orig and new tablespace OIDs */
13941 	orig_tablespaceoid = get_tablespace_oid(stmt->orig_tablespacename, false);
13942 	new_tablespaceoid = get_tablespace_oid(stmt->new_tablespacename, false);
13943 
13944 	/* Can't move shared relations in to or out of pg_global */
13945 	/* This is also checked by ATExecSetTableSpace, but nice to stop earlier */
13946 	if (orig_tablespaceoid == GLOBALTABLESPACE_OID ||
13947 		new_tablespaceoid == GLOBALTABLESPACE_OID)
13948 		ereport(ERROR,
13949 				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
13950 				 errmsg("cannot move relations in to or out of pg_global tablespace")));
13951 
13952 	/*
13953 	 * Must have CREATE rights on the new tablespace, unless it is the
13954 	 * database default tablespace (which all users implicitly have CREATE
13955 	 * rights on).
13956 	 */
13957 	if (OidIsValid(new_tablespaceoid) && new_tablespaceoid != MyDatabaseTableSpace)
13958 	{
13959 		AclResult	aclresult;
13960 
13961 		aclresult = pg_tablespace_aclcheck(new_tablespaceoid, GetUserId(),
13962 										   ACL_CREATE);
13963 		if (aclresult != ACLCHECK_OK)
13964 			aclcheck_error(aclresult, OBJECT_TABLESPACE,
13965 						   get_tablespace_name(new_tablespaceoid));
13966 	}
13967 
13968 	/*
13969 	 * Now that the checks are done, check if we should set either to
13970 	 * InvalidOid because it is our database's default tablespace.
13971 	 */
13972 	if (orig_tablespaceoid == MyDatabaseTableSpace)
13973 		orig_tablespaceoid = InvalidOid;
13974 
13975 	if (new_tablespaceoid == MyDatabaseTableSpace)
13976 		new_tablespaceoid = InvalidOid;
13977 
13978 	/* no-op */
13979 	if (orig_tablespaceoid == new_tablespaceoid)
13980 		return new_tablespaceoid;
13981 
13982 	/*
13983 	 * Walk the list of objects in the tablespace and move them. This will
13984 	 * only find objects in our database, of course.
13985 	 */
13986 	ScanKeyInit(&key[0],
13987 				Anum_pg_class_reltablespace,
13988 				BTEqualStrategyNumber, F_OIDEQ,
13989 				ObjectIdGetDatum(orig_tablespaceoid));
13990 
13991 	rel = table_open(RelationRelationId, AccessShareLock);
13992 	scan = table_beginscan_catalog(rel, 1, key);
13993 	while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
13994 	{
13995 		Form_pg_class relForm = (Form_pg_class) GETSTRUCT(tuple);
13996 		Oid			relOid = relForm->oid;
13997 
13998 		/*
13999 		 * Do not move objects in pg_catalog as part of this, if an admin
14000 		 * really wishes to do so, they can issue the individual ALTER
14001 		 * commands directly.
14002 		 *
14003 		 * Also, explicitly avoid any shared tables, temp tables, or TOAST
14004 		 * (TOAST will be moved with the main table).
14005 		 */
14006 		if (IsCatalogNamespace(relForm->relnamespace) ||
14007 			relForm->relisshared ||
14008 			isAnyTempNamespace(relForm->relnamespace) ||
14009 			IsToastNamespace(relForm->relnamespace))
14010 			continue;
14011 
14012 		/* Only move the object type requested */
14013 		if ((stmt->objtype == OBJECT_TABLE &&
14014 			 relForm->relkind != RELKIND_RELATION &&
14015 			 relForm->relkind != RELKIND_PARTITIONED_TABLE) ||
14016 			(stmt->objtype == OBJECT_INDEX &&
14017 			 relForm->relkind != RELKIND_INDEX &&
14018 			 relForm->relkind != RELKIND_PARTITIONED_INDEX) ||
14019 			(stmt->objtype == OBJECT_MATVIEW &&
14020 			 relForm->relkind != RELKIND_MATVIEW))
14021 			continue;
14022 
14023 		/* Check if we are only moving objects owned by certain roles */
14024 		if (role_oids != NIL && !list_member_oid(role_oids, relForm->relowner))
14025 			continue;
14026 
14027 		/*
14028 		 * Handle permissions-checking here since we are locking the tables
14029 		 * and also to avoid doing a bunch of work only to fail part-way. Note
14030 		 * that permissions will also be checked by AlterTableInternal().
14031 		 *
14032 		 * Caller must be considered an owner on the table to move it.
14033 		 */
14034 		if (!pg_class_ownercheck(relOid, GetUserId()))
14035 			aclcheck_error(ACLCHECK_NOT_OWNER, get_relkind_objtype(get_rel_relkind(relOid)),
14036 						   NameStr(relForm->relname));
14037 
14038 		if (stmt->nowait &&
14039 			!ConditionalLockRelationOid(relOid, AccessExclusiveLock))
14040 			ereport(ERROR,
14041 					(errcode(ERRCODE_OBJECT_IN_USE),
14042 					 errmsg("aborting because lock on relation \"%s.%s\" is not available",
14043 							get_namespace_name(relForm->relnamespace),
14044 							NameStr(relForm->relname))));
14045 		else
14046 			LockRelationOid(relOid, AccessExclusiveLock);
14047 
14048 		/* Add to our list of objects to move */
14049 		relations = lappend_oid(relations, relOid);
14050 	}
14051 
14052 	table_endscan(scan);
14053 	table_close(rel, AccessShareLock);
14054 
14055 	if (relations == NIL)
14056 		ereport(NOTICE,
14057 				(errcode(ERRCODE_NO_DATA_FOUND),
14058 				 errmsg("no matching relations in tablespace \"%s\" found",
14059 						orig_tablespaceoid == InvalidOid ? "(database default)" :
14060 						get_tablespace_name(orig_tablespaceoid))));
14061 
14062 	/* Everything is locked, loop through and move all of the relations. */
14063 	foreach(l, relations)
14064 	{
14065 		List	   *cmds = NIL;
14066 		AlterTableCmd *cmd = makeNode(AlterTableCmd);
14067 
14068 		cmd->subtype = AT_SetTableSpace;
14069 		cmd->name = stmt->new_tablespacename;
14070 
14071 		cmds = lappend(cmds, cmd);
14072 
14073 		EventTriggerAlterTableStart((Node *) stmt);
14074 		/* OID is set by AlterTableInternal */
14075 		AlterTableInternal(lfirst_oid(l), cmds, false);
14076 		EventTriggerAlterTableEnd();
14077 	}
14078 
14079 	return new_tablespaceoid;
14080 }
14081 
14082 static void
index_copy_data(Relation rel,RelFileNode newrnode)14083 index_copy_data(Relation rel, RelFileNode newrnode)
14084 {
14085 	SMgrRelation dstrel;
14086 
14087 	dstrel = smgropen(newrnode, rel->rd_backend);
14088 	RelationOpenSmgr(rel);
14089 
14090 	/*
14091 	 * Since we copy the file directly without looking at the shared buffers,
14092 	 * we'd better first flush out any pages of the source relation that are
14093 	 * in shared buffers.  We assume no new changes will be made while we are
14094 	 * holding exclusive lock on the rel.
14095 	 */
14096 	FlushRelationBuffers(rel);
14097 
14098 	/*
14099 	 * Create and copy all forks of the relation, and schedule unlinking of
14100 	 * old physical files.
14101 	 *
14102 	 * NOTE: any conflict in relfilenode value will be caught in
14103 	 * RelationCreateStorage().
14104 	 */
14105 	RelationCreateStorage(newrnode, rel->rd_rel->relpersistence);
14106 
14107 	/* copy main fork */
14108 	RelationCopyStorage(rel->rd_smgr, dstrel, MAIN_FORKNUM,
14109 						rel->rd_rel->relpersistence);
14110 
14111 	/* copy those extra forks that exist */
14112 	for (ForkNumber forkNum = MAIN_FORKNUM + 1;
14113 		 forkNum <= MAX_FORKNUM; forkNum++)
14114 	{
14115 		if (smgrexists(rel->rd_smgr, forkNum))
14116 		{
14117 			smgrcreate(dstrel, forkNum, false);
14118 
14119 			/*
14120 			 * WAL log creation if the relation is persistent, or this is the
14121 			 * init fork of an unlogged relation.
14122 			 */
14123 			if (RelationIsPermanent(rel) ||
14124 				(rel->rd_rel->relpersistence == RELPERSISTENCE_UNLOGGED &&
14125 				 forkNum == INIT_FORKNUM))
14126 				log_smgrcreate(&newrnode, forkNum);
14127 			RelationCopyStorage(rel->rd_smgr, dstrel, forkNum,
14128 								rel->rd_rel->relpersistence);
14129 		}
14130 	}
14131 
14132 	/* drop old relation, and close new one */
14133 	RelationDropStorage(rel);
14134 	smgrclose(dstrel);
14135 }
14136 
14137 /*
14138  * ALTER TABLE ENABLE/DISABLE TRIGGER
14139  *
14140  * We just pass this off to trigger.c.
14141  */
14142 static void
ATExecEnableDisableTrigger(Relation rel,const char * trigname,char fires_when,bool skip_system,LOCKMODE lockmode)14143 ATExecEnableDisableTrigger(Relation rel, const char *trigname,
14144 						   char fires_when, bool skip_system, LOCKMODE lockmode)
14145 {
14146 	EnableDisableTrigger(rel, trigname, fires_when, skip_system, lockmode);
14147 }
14148 
14149 /*
14150  * ALTER TABLE ENABLE/DISABLE RULE
14151  *
14152  * We just pass this off to rewriteDefine.c.
14153  */
14154 static void
ATExecEnableDisableRule(Relation rel,const char * rulename,char fires_when,LOCKMODE lockmode)14155 ATExecEnableDisableRule(Relation rel, const char *rulename,
14156 						char fires_when, LOCKMODE lockmode)
14157 {
14158 	EnableDisableRule(rel, rulename, fires_when);
14159 }
14160 
14161 /*
14162  * ALTER TABLE INHERIT
14163  *
14164  * Add a parent to the child's parents. This verifies that all the columns and
14165  * check constraints of the parent appear in the child and that they have the
14166  * same data types and expressions.
14167  */
14168 static void
ATPrepAddInherit(Relation child_rel)14169 ATPrepAddInherit(Relation child_rel)
14170 {
14171 	if (child_rel->rd_rel->reloftype)
14172 		ereport(ERROR,
14173 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
14174 				 errmsg("cannot change inheritance of typed table")));
14175 
14176 	if (child_rel->rd_rel->relispartition)
14177 		ereport(ERROR,
14178 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
14179 				 errmsg("cannot change inheritance of a partition")));
14180 
14181 	if (child_rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
14182 		ereport(ERROR,
14183 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
14184 				 errmsg("cannot change inheritance of partitioned table")));
14185 }
14186 
14187 /*
14188  * Return the address of the new parent relation.
14189  */
14190 static ObjectAddress
ATExecAddInherit(Relation child_rel,RangeVar * parent,LOCKMODE lockmode)14191 ATExecAddInherit(Relation child_rel, RangeVar *parent, LOCKMODE lockmode)
14192 {
14193 	Relation	parent_rel;
14194 	List	   *children;
14195 	ObjectAddress address;
14196 	const char *trigger_name;
14197 
14198 	/*
14199 	 * A self-exclusive lock is needed here.  See the similar case in
14200 	 * MergeAttributes() for a full explanation.
14201 	 */
14202 	parent_rel = table_openrv(parent, ShareUpdateExclusiveLock);
14203 
14204 	/*
14205 	 * Must be owner of both parent and child -- child was checked by
14206 	 * ATSimplePermissions call in ATPrepCmd
14207 	 */
14208 	ATSimplePermissions(parent_rel, ATT_TABLE | ATT_FOREIGN_TABLE);
14209 
14210 	/* Permanent rels cannot inherit from temporary ones */
14211 	if (parent_rel->rd_rel->relpersistence == RELPERSISTENCE_TEMP &&
14212 		child_rel->rd_rel->relpersistence != RELPERSISTENCE_TEMP)
14213 		ereport(ERROR,
14214 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
14215 				 errmsg("cannot inherit from temporary relation \"%s\"",
14216 						RelationGetRelationName(parent_rel))));
14217 
14218 	/* If parent rel is temp, it must belong to this session */
14219 	if (parent_rel->rd_rel->relpersistence == RELPERSISTENCE_TEMP &&
14220 		!parent_rel->rd_islocaltemp)
14221 		ereport(ERROR,
14222 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
14223 				 errmsg("cannot inherit from temporary relation of another session")));
14224 
14225 	/* Ditto for the child */
14226 	if (child_rel->rd_rel->relpersistence == RELPERSISTENCE_TEMP &&
14227 		!child_rel->rd_islocaltemp)
14228 		ereport(ERROR,
14229 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
14230 				 errmsg("cannot inherit to temporary relation of another session")));
14231 
14232 	/* Prevent partitioned tables from becoming inheritance parents */
14233 	if (parent_rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
14234 		ereport(ERROR,
14235 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
14236 				 errmsg("cannot inherit from partitioned table \"%s\"",
14237 						parent->relname)));
14238 
14239 	/* Likewise for partitions */
14240 	if (parent_rel->rd_rel->relispartition)
14241 		ereport(ERROR,
14242 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
14243 				 errmsg("cannot inherit from a partition")));
14244 
14245 	/*
14246 	 * Prevent circularity by seeing if proposed parent inherits from child.
14247 	 * (In particular, this disallows making a rel inherit from itself.)
14248 	 *
14249 	 * This is not completely bulletproof because of race conditions: in
14250 	 * multi-level inheritance trees, someone else could concurrently be
14251 	 * making another inheritance link that closes the loop but does not join
14252 	 * either of the rels we have locked.  Preventing that seems to require
14253 	 * exclusive locks on the entire inheritance tree, which is a cure worse
14254 	 * than the disease.  find_all_inheritors() will cope with circularity
14255 	 * anyway, so don't sweat it too much.
14256 	 *
14257 	 * We use weakest lock we can on child's children, namely AccessShareLock.
14258 	 */
14259 	children = find_all_inheritors(RelationGetRelid(child_rel),
14260 								   AccessShareLock, NULL);
14261 
14262 	if (list_member_oid(children, RelationGetRelid(parent_rel)))
14263 		ereport(ERROR,
14264 				(errcode(ERRCODE_DUPLICATE_TABLE),
14265 				 errmsg("circular inheritance not allowed"),
14266 				 errdetail("\"%s\" is already a child of \"%s\".",
14267 						   parent->relname,
14268 						   RelationGetRelationName(child_rel))));
14269 
14270 	/*
14271 	 * If child_rel has row-level triggers with transition tables, we
14272 	 * currently don't allow it to become an inheritance child.  See also
14273 	 * prohibitions in ATExecAttachPartition() and CreateTrigger().
14274 	 */
14275 	trigger_name = FindTriggerIncompatibleWithInheritance(child_rel->trigdesc);
14276 	if (trigger_name != NULL)
14277 		ereport(ERROR,
14278 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
14279 				 errmsg("trigger \"%s\" prevents table \"%s\" from becoming an inheritance child",
14280 						trigger_name, RelationGetRelationName(child_rel)),
14281 				 errdetail("ROW triggers with transition tables are not supported in inheritance hierarchies.")));
14282 
14283 	/* OK to create inheritance */
14284 	CreateInheritance(child_rel, parent_rel);
14285 
14286 	ObjectAddressSet(address, RelationRelationId,
14287 					 RelationGetRelid(parent_rel));
14288 
14289 	/* keep our lock on the parent relation until commit */
14290 	table_close(parent_rel, NoLock);
14291 
14292 	return address;
14293 }
14294 
14295 /*
14296  * CreateInheritance
14297  *		Catalog manipulation portion of creating inheritance between a child
14298  *		table and a parent table.
14299  *
14300  * Common to ATExecAddInherit() and ATExecAttachPartition().
14301  */
14302 static void
CreateInheritance(Relation child_rel,Relation parent_rel)14303 CreateInheritance(Relation child_rel, Relation parent_rel)
14304 {
14305 	Relation	catalogRelation;
14306 	SysScanDesc scan;
14307 	ScanKeyData key;
14308 	HeapTuple	inheritsTuple;
14309 	int32		inhseqno;
14310 
14311 	/* Note: get RowExclusiveLock because we will write pg_inherits below. */
14312 	catalogRelation = table_open(InheritsRelationId, RowExclusiveLock);
14313 
14314 	/*
14315 	 * Check for duplicates in the list of parents, and determine the highest
14316 	 * inhseqno already present; we'll use the next one for the new parent.
14317 	 * Also, if proposed child is a partition, it cannot already be
14318 	 * inheriting.
14319 	 *
14320 	 * Note: we do not reject the case where the child already inherits from
14321 	 * the parent indirectly; CREATE TABLE doesn't reject comparable cases.
14322 	 */
14323 	ScanKeyInit(&key,
14324 				Anum_pg_inherits_inhrelid,
14325 				BTEqualStrategyNumber, F_OIDEQ,
14326 				ObjectIdGetDatum(RelationGetRelid(child_rel)));
14327 	scan = systable_beginscan(catalogRelation, InheritsRelidSeqnoIndexId,
14328 							  true, NULL, 1, &key);
14329 
14330 	/* inhseqno sequences start at 1 */
14331 	inhseqno = 0;
14332 	while (HeapTupleIsValid(inheritsTuple = systable_getnext(scan)))
14333 	{
14334 		Form_pg_inherits inh = (Form_pg_inherits) GETSTRUCT(inheritsTuple);
14335 
14336 		if (inh->inhparent == RelationGetRelid(parent_rel))
14337 			ereport(ERROR,
14338 					(errcode(ERRCODE_DUPLICATE_TABLE),
14339 					 errmsg("relation \"%s\" would be inherited from more than once",
14340 							RelationGetRelationName(parent_rel))));
14341 
14342 		if (inh->inhseqno > inhseqno)
14343 			inhseqno = inh->inhseqno;
14344 	}
14345 	systable_endscan(scan);
14346 
14347 	/* Match up the columns and bump attinhcount as needed */
14348 	MergeAttributesIntoExisting(child_rel, parent_rel);
14349 
14350 	/* Match up the constraints and bump coninhcount as needed */
14351 	MergeConstraintsIntoExisting(child_rel, parent_rel);
14352 
14353 	/*
14354 	 * OK, it looks valid.  Make the catalog entries that show inheritance.
14355 	 */
14356 	StoreCatalogInheritance1(RelationGetRelid(child_rel),
14357 							 RelationGetRelid(parent_rel),
14358 							 inhseqno + 1,
14359 							 catalogRelation,
14360 							 parent_rel->rd_rel->relkind ==
14361 							 RELKIND_PARTITIONED_TABLE);
14362 
14363 	/* Now we're done with pg_inherits */
14364 	table_close(catalogRelation, RowExclusiveLock);
14365 }
14366 
14367 /*
14368  * Obtain the source-text form of the constraint expression for a check
14369  * constraint, given its pg_constraint tuple
14370  */
14371 static char *
decompile_conbin(HeapTuple contup,TupleDesc tupdesc)14372 decompile_conbin(HeapTuple contup, TupleDesc tupdesc)
14373 {
14374 	Form_pg_constraint con;
14375 	bool		isnull;
14376 	Datum		attr;
14377 	Datum		expr;
14378 
14379 	con = (Form_pg_constraint) GETSTRUCT(contup);
14380 	attr = heap_getattr(contup, Anum_pg_constraint_conbin, tupdesc, &isnull);
14381 	if (isnull)
14382 		elog(ERROR, "null conbin for constraint %u", con->oid);
14383 
14384 	expr = DirectFunctionCall2(pg_get_expr, attr,
14385 							   ObjectIdGetDatum(con->conrelid));
14386 	return TextDatumGetCString(expr);
14387 }
14388 
14389 /*
14390  * Determine whether two check constraints are functionally equivalent
14391  *
14392  * The test we apply is to see whether they reverse-compile to the same
14393  * source string.  This insulates us from issues like whether attributes
14394  * have the same physical column numbers in parent and child relations.
14395  */
14396 static bool
constraints_equivalent(HeapTuple a,HeapTuple b,TupleDesc tupleDesc)14397 constraints_equivalent(HeapTuple a, HeapTuple b, TupleDesc tupleDesc)
14398 {
14399 	Form_pg_constraint acon = (Form_pg_constraint) GETSTRUCT(a);
14400 	Form_pg_constraint bcon = (Form_pg_constraint) GETSTRUCT(b);
14401 
14402 	if (acon->condeferrable != bcon->condeferrable ||
14403 		acon->condeferred != bcon->condeferred ||
14404 		strcmp(decompile_conbin(a, tupleDesc),
14405 			   decompile_conbin(b, tupleDesc)) != 0)
14406 		return false;
14407 	else
14408 		return true;
14409 }
14410 
14411 /*
14412  * Check columns in child table match up with columns in parent, and increment
14413  * their attinhcount.
14414  *
14415  * Called by CreateInheritance
14416  *
14417  * Currently all parent columns must be found in child. Missing columns are an
14418  * error.  One day we might consider creating new columns like CREATE TABLE
14419  * does.  However, that is widely unpopular --- in the common use case of
14420  * partitioned tables it's a foot-gun.
14421  *
14422  * The data type must match exactly. If the parent column is NOT NULL then
14423  * the child must be as well. Defaults are not compared, however.
14424  */
14425 static void
MergeAttributesIntoExisting(Relation child_rel,Relation parent_rel)14426 MergeAttributesIntoExisting(Relation child_rel, Relation parent_rel)
14427 {
14428 	Relation	attrrel;
14429 	AttrNumber	parent_attno;
14430 	int			parent_natts;
14431 	TupleDesc	tupleDesc;
14432 	HeapTuple	tuple;
14433 	bool		child_is_partition = false;
14434 
14435 	attrrel = table_open(AttributeRelationId, RowExclusiveLock);
14436 
14437 	tupleDesc = RelationGetDescr(parent_rel);
14438 	parent_natts = tupleDesc->natts;
14439 
14440 	/* If parent_rel is a partitioned table, child_rel must be a partition */
14441 	if (parent_rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
14442 		child_is_partition = true;
14443 
14444 	for (parent_attno = 1; parent_attno <= parent_natts; parent_attno++)
14445 	{
14446 		Form_pg_attribute attribute = TupleDescAttr(tupleDesc,
14447 													parent_attno - 1);
14448 		char	   *attributeName = NameStr(attribute->attname);
14449 
14450 		/* Ignore dropped columns in the parent. */
14451 		if (attribute->attisdropped)
14452 			continue;
14453 
14454 		/* Find same column in child (matching on column name). */
14455 		tuple = SearchSysCacheCopyAttName(RelationGetRelid(child_rel),
14456 										  attributeName);
14457 		if (HeapTupleIsValid(tuple))
14458 		{
14459 			/* Check they are same type, typmod, and collation */
14460 			Form_pg_attribute childatt = (Form_pg_attribute) GETSTRUCT(tuple);
14461 
14462 			if (attribute->atttypid != childatt->atttypid ||
14463 				attribute->atttypmod != childatt->atttypmod)
14464 				ereport(ERROR,
14465 						(errcode(ERRCODE_DATATYPE_MISMATCH),
14466 						 errmsg("child table \"%s\" has different type for column \"%s\"",
14467 								RelationGetRelationName(child_rel),
14468 								attributeName)));
14469 
14470 			if (attribute->attcollation != childatt->attcollation)
14471 				ereport(ERROR,
14472 						(errcode(ERRCODE_COLLATION_MISMATCH),
14473 						 errmsg("child table \"%s\" has different collation for column \"%s\"",
14474 								RelationGetRelationName(child_rel),
14475 								attributeName)));
14476 
14477 			/*
14478 			 * Check child doesn't discard NOT NULL property.  (Other
14479 			 * constraints are checked elsewhere.)
14480 			 */
14481 			if (attribute->attnotnull && !childatt->attnotnull)
14482 				ereport(ERROR,
14483 						(errcode(ERRCODE_DATATYPE_MISMATCH),
14484 						 errmsg("column \"%s\" in child table must be marked NOT NULL",
14485 								attributeName)));
14486 
14487 			/*
14488 			 * If parent column is generated, child column must be, too.
14489 			 */
14490 			if (attribute->attgenerated && !childatt->attgenerated)
14491 				ereport(ERROR,
14492 						(errcode(ERRCODE_DATATYPE_MISMATCH),
14493 						 errmsg("column \"%s\" in child table must be a generated column",
14494 								attributeName)));
14495 
14496 			/*
14497 			 * Check that both generation expressions match.
14498 			 *
14499 			 * The test we apply is to see whether they reverse-compile to the
14500 			 * same source string.  This insulates us from issues like whether
14501 			 * attributes have the same physical column numbers in parent and
14502 			 * child relations.  (See also constraints_equivalent().)
14503 			 */
14504 			if (attribute->attgenerated && childatt->attgenerated)
14505 			{
14506 				TupleConstr *child_constr = child_rel->rd_att->constr;
14507 				TupleConstr *parent_constr = parent_rel->rd_att->constr;
14508 				char	   *child_expr = NULL;
14509 				char	   *parent_expr = NULL;
14510 
14511 				Assert(child_constr != NULL);
14512 				Assert(parent_constr != NULL);
14513 
14514 				for (int i = 0; i < child_constr->num_defval; i++)
14515 				{
14516 					if (child_constr->defval[i].adnum == childatt->attnum)
14517 					{
14518 						child_expr =
14519 							TextDatumGetCString(DirectFunctionCall2(pg_get_expr,
14520 																	CStringGetTextDatum(child_constr->defval[i].adbin),
14521 																	ObjectIdGetDatum(child_rel->rd_id)));
14522 						break;
14523 					}
14524 				}
14525 				Assert(child_expr != NULL);
14526 
14527 				for (int i = 0; i < parent_constr->num_defval; i++)
14528 				{
14529 					if (parent_constr->defval[i].adnum == attribute->attnum)
14530 					{
14531 						parent_expr =
14532 							TextDatumGetCString(DirectFunctionCall2(pg_get_expr,
14533 																	CStringGetTextDatum(parent_constr->defval[i].adbin),
14534 																	ObjectIdGetDatum(parent_rel->rd_id)));
14535 						break;
14536 					}
14537 				}
14538 				Assert(parent_expr != NULL);
14539 
14540 				if (strcmp(child_expr, parent_expr) != 0)
14541 					ereport(ERROR,
14542 							(errcode(ERRCODE_DATATYPE_MISMATCH),
14543 							 errmsg("column \"%s\" in child table has a conflicting generation expression",
14544 									attributeName)));
14545 			}
14546 
14547 			/*
14548 			 * OK, bump the child column's inheritance count.  (If we fail
14549 			 * later on, this change will just roll back.)
14550 			 */
14551 			childatt->attinhcount++;
14552 
14553 			/*
14554 			 * In case of partitions, we must enforce that value of attislocal
14555 			 * is same in all partitions. (Note: there are only inherited
14556 			 * attributes in partitions)
14557 			 */
14558 			if (child_is_partition)
14559 			{
14560 				Assert(childatt->attinhcount == 1);
14561 				childatt->attislocal = false;
14562 			}
14563 
14564 			CatalogTupleUpdate(attrrel, &tuple->t_self, tuple);
14565 			heap_freetuple(tuple);
14566 		}
14567 		else
14568 		{
14569 			ereport(ERROR,
14570 					(errcode(ERRCODE_DATATYPE_MISMATCH),
14571 					 errmsg("child table is missing column \"%s\"",
14572 							attributeName)));
14573 		}
14574 	}
14575 
14576 	table_close(attrrel, RowExclusiveLock);
14577 }
14578 
14579 /*
14580  * Check constraints in child table match up with constraints in parent,
14581  * and increment their coninhcount.
14582  *
14583  * Constraints that are marked ONLY in the parent are ignored.
14584  *
14585  * Called by CreateInheritance
14586  *
14587  * Currently all constraints in parent must be present in the child. One day we
14588  * may consider adding new constraints like CREATE TABLE does.
14589  *
14590  * XXX This is O(N^2) which may be an issue with tables with hundreds of
14591  * constraints. As long as tables have more like 10 constraints it shouldn't be
14592  * a problem though. Even 100 constraints ought not be the end of the world.
14593  *
14594  * XXX See MergeWithExistingConstraint too if you change this code.
14595  */
14596 static void
MergeConstraintsIntoExisting(Relation child_rel,Relation parent_rel)14597 MergeConstraintsIntoExisting(Relation child_rel, Relation parent_rel)
14598 {
14599 	Relation	catalog_relation;
14600 	TupleDesc	tuple_desc;
14601 	SysScanDesc parent_scan;
14602 	ScanKeyData parent_key;
14603 	HeapTuple	parent_tuple;
14604 	bool		child_is_partition = false;
14605 
14606 	catalog_relation = table_open(ConstraintRelationId, RowExclusiveLock);
14607 	tuple_desc = RelationGetDescr(catalog_relation);
14608 
14609 	/* If parent_rel is a partitioned table, child_rel must be a partition */
14610 	if (parent_rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
14611 		child_is_partition = true;
14612 
14613 	/* Outer loop scans through the parent's constraint definitions */
14614 	ScanKeyInit(&parent_key,
14615 				Anum_pg_constraint_conrelid,
14616 				BTEqualStrategyNumber, F_OIDEQ,
14617 				ObjectIdGetDatum(RelationGetRelid(parent_rel)));
14618 	parent_scan = systable_beginscan(catalog_relation, ConstraintRelidTypidNameIndexId,
14619 									 true, NULL, 1, &parent_key);
14620 
14621 	while (HeapTupleIsValid(parent_tuple = systable_getnext(parent_scan)))
14622 	{
14623 		Form_pg_constraint parent_con = (Form_pg_constraint) GETSTRUCT(parent_tuple);
14624 		SysScanDesc child_scan;
14625 		ScanKeyData child_key;
14626 		HeapTuple	child_tuple;
14627 		bool		found = false;
14628 
14629 		if (parent_con->contype != CONSTRAINT_CHECK)
14630 			continue;
14631 
14632 		/* if the parent's constraint is marked NO INHERIT, it's not inherited */
14633 		if (parent_con->connoinherit)
14634 			continue;
14635 
14636 		/* Search for a child constraint matching this one */
14637 		ScanKeyInit(&child_key,
14638 					Anum_pg_constraint_conrelid,
14639 					BTEqualStrategyNumber, F_OIDEQ,
14640 					ObjectIdGetDatum(RelationGetRelid(child_rel)));
14641 		child_scan = systable_beginscan(catalog_relation, ConstraintRelidTypidNameIndexId,
14642 										true, NULL, 1, &child_key);
14643 
14644 		while (HeapTupleIsValid(child_tuple = systable_getnext(child_scan)))
14645 		{
14646 			Form_pg_constraint child_con = (Form_pg_constraint) GETSTRUCT(child_tuple);
14647 			HeapTuple	child_copy;
14648 
14649 			if (child_con->contype != CONSTRAINT_CHECK)
14650 				continue;
14651 
14652 			if (strcmp(NameStr(parent_con->conname),
14653 					   NameStr(child_con->conname)) != 0)
14654 				continue;
14655 
14656 			if (!constraints_equivalent(parent_tuple, child_tuple, tuple_desc))
14657 				ereport(ERROR,
14658 						(errcode(ERRCODE_DATATYPE_MISMATCH),
14659 						 errmsg("child table \"%s\" has different definition for check constraint \"%s\"",
14660 								RelationGetRelationName(child_rel),
14661 								NameStr(parent_con->conname))));
14662 
14663 			/* If the child constraint is "no inherit" then cannot merge */
14664 			if (child_con->connoinherit)
14665 				ereport(ERROR,
14666 						(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
14667 						 errmsg("constraint \"%s\" conflicts with non-inherited constraint on child table \"%s\"",
14668 								NameStr(child_con->conname),
14669 								RelationGetRelationName(child_rel))));
14670 
14671 			/*
14672 			 * If the child constraint is "not valid" then cannot merge with a
14673 			 * valid parent constraint
14674 			 */
14675 			if (parent_con->convalidated && !child_con->convalidated)
14676 				ereport(ERROR,
14677 						(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
14678 						 errmsg("constraint \"%s\" conflicts with NOT VALID constraint on child table \"%s\"",
14679 								NameStr(child_con->conname),
14680 								RelationGetRelationName(child_rel))));
14681 
14682 			/*
14683 			 * OK, bump the child constraint's inheritance count.  (If we fail
14684 			 * later on, this change will just roll back.)
14685 			 */
14686 			child_copy = heap_copytuple(child_tuple);
14687 			child_con = (Form_pg_constraint) GETSTRUCT(child_copy);
14688 			child_con->coninhcount++;
14689 
14690 			/*
14691 			 * In case of partitions, an inherited constraint must be
14692 			 * inherited only once since it cannot have multiple parents and
14693 			 * it is never considered local.
14694 			 */
14695 			if (child_is_partition)
14696 			{
14697 				Assert(child_con->coninhcount == 1);
14698 				child_con->conislocal = false;
14699 			}
14700 
14701 			CatalogTupleUpdate(catalog_relation, &child_copy->t_self, child_copy);
14702 			heap_freetuple(child_copy);
14703 
14704 			found = true;
14705 			break;
14706 		}
14707 
14708 		systable_endscan(child_scan);
14709 
14710 		if (!found)
14711 			ereport(ERROR,
14712 					(errcode(ERRCODE_DATATYPE_MISMATCH),
14713 					 errmsg("child table is missing constraint \"%s\"",
14714 							NameStr(parent_con->conname))));
14715 	}
14716 
14717 	systable_endscan(parent_scan);
14718 	table_close(catalog_relation, RowExclusiveLock);
14719 }
14720 
14721 /*
14722  * ALTER TABLE NO INHERIT
14723  *
14724  * Return value is the address of the relation that is no longer parent.
14725  */
14726 static ObjectAddress
ATExecDropInherit(Relation rel,RangeVar * parent,LOCKMODE lockmode)14727 ATExecDropInherit(Relation rel, RangeVar *parent, LOCKMODE lockmode)
14728 {
14729 	ObjectAddress address;
14730 	Relation	parent_rel;
14731 
14732 	if (rel->rd_rel->relispartition)
14733 		ereport(ERROR,
14734 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
14735 				 errmsg("cannot change inheritance of a partition")));
14736 
14737 	/*
14738 	 * AccessShareLock on the parent is probably enough, seeing that DROP
14739 	 * TABLE doesn't lock parent tables at all.  We need some lock since we'll
14740 	 * be inspecting the parent's schema.
14741 	 */
14742 	parent_rel = table_openrv(parent, AccessShareLock);
14743 
14744 	/*
14745 	 * We don't bother to check ownership of the parent table --- ownership of
14746 	 * the child is presumed enough rights.
14747 	 */
14748 
14749 	/* Off to RemoveInheritance() where most of the work happens */
14750 	RemoveInheritance(rel, parent_rel, false);
14751 
14752 	ObjectAddressSet(address, RelationRelationId,
14753 					 RelationGetRelid(parent_rel));
14754 
14755 	/* keep our lock on the parent relation until commit */
14756 	table_close(parent_rel, NoLock);
14757 
14758 	return address;
14759 }
14760 
14761 /*
14762  * MarkInheritDetached
14763  *
14764  * Set inhdetachpending for a partition, for ATExecDetachPartition
14765  * in concurrent mode.  While at it, verify that no other partition is
14766  * already pending detach.
14767  */
14768 static void
MarkInheritDetached(Relation child_rel,Relation parent_rel)14769 MarkInheritDetached(Relation child_rel, Relation parent_rel)
14770 {
14771 	Relation	catalogRelation;
14772 	SysScanDesc scan;
14773 	ScanKeyData key;
14774 	HeapTuple	inheritsTuple;
14775 	bool		found = false;
14776 
14777 	Assert(child_rel->rd_rel->relkind == RELKIND_RELATION ||
14778 		   child_rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
14779 	Assert(parent_rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
14780 
14781 	/*
14782 	 * Find pg_inherits entries by inhparent.  (We need to scan them all in
14783 	 * order to verify that no other partition is pending detach.)
14784 	 */
14785 	catalogRelation = table_open(InheritsRelationId, RowExclusiveLock);
14786 	ScanKeyInit(&key,
14787 				Anum_pg_inherits_inhparent,
14788 				BTEqualStrategyNumber, F_OIDEQ,
14789 				ObjectIdGetDatum(RelationGetRelid(parent_rel)));
14790 	scan = systable_beginscan(catalogRelation, InheritsParentIndexId,
14791 							  true, NULL, 1, &key);
14792 
14793 	while (HeapTupleIsValid(inheritsTuple = systable_getnext(scan)))
14794 	{
14795 		Form_pg_inherits inhForm;
14796 
14797 		inhForm = (Form_pg_inherits) GETSTRUCT(inheritsTuple);
14798 		if (inhForm->inhdetachpending)
14799 			ereport(ERROR,
14800 					errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
14801 					errmsg("partition \"%s\" already pending detach in partitioned table \"%s.%s\"",
14802 						   get_rel_name(inhForm->inhrelid),
14803 						   get_namespace_name(parent_rel->rd_rel->relnamespace),
14804 						   RelationGetRelationName(parent_rel)),
14805 					errhint("Use ALTER TABLE ... DETACH PARTITION ... FINALIZE to complete the pending detach operation."));
14806 
14807 		if (inhForm->inhrelid == RelationGetRelid(child_rel))
14808 		{
14809 			HeapTuple	newtup;
14810 
14811 			newtup = heap_copytuple(inheritsTuple);
14812 			((Form_pg_inherits) GETSTRUCT(newtup))->inhdetachpending = true;
14813 
14814 			CatalogTupleUpdate(catalogRelation,
14815 							   &inheritsTuple->t_self,
14816 							   newtup);
14817 			found = true;
14818 			heap_freetuple(newtup);
14819 			/* keep looking, to ensure we catch others pending detach */
14820 		}
14821 	}
14822 
14823 	/* Done */
14824 	systable_endscan(scan);
14825 	table_close(catalogRelation, RowExclusiveLock);
14826 
14827 	if (!found)
14828 		ereport(ERROR,
14829 				(errcode(ERRCODE_UNDEFINED_TABLE),
14830 				 errmsg("relation \"%s\" is not a partition of relation \"%s\"",
14831 						RelationGetRelationName(child_rel),
14832 						RelationGetRelationName(parent_rel))));
14833 }
14834 
14835 /*
14836  * RemoveInheritance
14837  *
14838  * Drop a parent from the child's parents. This just adjusts the attinhcount
14839  * and attislocal of the columns and removes the pg_inherit and pg_depend
14840  * entries.  expect_detached is passed down to DeleteInheritsTuple, q.v..
14841  *
14842  * If attinhcount goes to 0 then attislocal gets set to true. If it goes back
14843  * up attislocal stays true, which means if a child is ever removed from a
14844  * parent then its columns will never be automatically dropped which may
14845  * surprise. But at least we'll never surprise by dropping columns someone
14846  * isn't expecting to be dropped which would actually mean data loss.
14847  *
14848  * coninhcount and conislocal for inherited constraints are adjusted in
14849  * exactly the same way.
14850  *
14851  * Common to ATExecDropInherit() and ATExecDetachPartition().
14852  */
14853 static void
RemoveInheritance(Relation child_rel,Relation parent_rel,bool expect_detached)14854 RemoveInheritance(Relation child_rel, Relation parent_rel, bool expect_detached)
14855 {
14856 	Relation	catalogRelation;
14857 	SysScanDesc scan;
14858 	ScanKeyData key[3];
14859 	HeapTuple	attributeTuple,
14860 				constraintTuple;
14861 	List	   *connames;
14862 	bool		found;
14863 	bool		child_is_partition = false;
14864 
14865 	/* If parent_rel is a partitioned table, child_rel must be a partition */
14866 	if (parent_rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
14867 		child_is_partition = true;
14868 
14869 	found = DeleteInheritsTuple(RelationGetRelid(child_rel),
14870 								RelationGetRelid(parent_rel),
14871 								expect_detached,
14872 								RelationGetRelationName(child_rel));
14873 	if (!found)
14874 	{
14875 		if (child_is_partition)
14876 			ereport(ERROR,
14877 					(errcode(ERRCODE_UNDEFINED_TABLE),
14878 					 errmsg("relation \"%s\" is not a partition of relation \"%s\"",
14879 							RelationGetRelationName(child_rel),
14880 							RelationGetRelationName(parent_rel))));
14881 		else
14882 			ereport(ERROR,
14883 					(errcode(ERRCODE_UNDEFINED_TABLE),
14884 					 errmsg("relation \"%s\" is not a parent of relation \"%s\"",
14885 							RelationGetRelationName(parent_rel),
14886 							RelationGetRelationName(child_rel))));
14887 	}
14888 
14889 	/*
14890 	 * Search through child columns looking for ones matching parent rel
14891 	 */
14892 	catalogRelation = table_open(AttributeRelationId, RowExclusiveLock);
14893 	ScanKeyInit(&key[0],
14894 				Anum_pg_attribute_attrelid,
14895 				BTEqualStrategyNumber, F_OIDEQ,
14896 				ObjectIdGetDatum(RelationGetRelid(child_rel)));
14897 	scan = systable_beginscan(catalogRelation, AttributeRelidNumIndexId,
14898 							  true, NULL, 1, key);
14899 	while (HeapTupleIsValid(attributeTuple = systable_getnext(scan)))
14900 	{
14901 		Form_pg_attribute att = (Form_pg_attribute) GETSTRUCT(attributeTuple);
14902 
14903 		/* Ignore if dropped or not inherited */
14904 		if (att->attisdropped)
14905 			continue;
14906 		if (att->attinhcount <= 0)
14907 			continue;
14908 
14909 		if (SearchSysCacheExistsAttName(RelationGetRelid(parent_rel),
14910 										NameStr(att->attname)))
14911 		{
14912 			/* Decrement inhcount and possibly set islocal to true */
14913 			HeapTuple	copyTuple = heap_copytuple(attributeTuple);
14914 			Form_pg_attribute copy_att = (Form_pg_attribute) GETSTRUCT(copyTuple);
14915 
14916 			copy_att->attinhcount--;
14917 			if (copy_att->attinhcount == 0)
14918 				copy_att->attislocal = true;
14919 
14920 			CatalogTupleUpdate(catalogRelation, &copyTuple->t_self, copyTuple);
14921 			heap_freetuple(copyTuple);
14922 		}
14923 	}
14924 	systable_endscan(scan);
14925 	table_close(catalogRelation, RowExclusiveLock);
14926 
14927 	/*
14928 	 * Likewise, find inherited check constraints and disinherit them. To do
14929 	 * this, we first need a list of the names of the parent's check
14930 	 * constraints.  (We cheat a bit by only checking for name matches,
14931 	 * assuming that the expressions will match.)
14932 	 */
14933 	catalogRelation = table_open(ConstraintRelationId, RowExclusiveLock);
14934 	ScanKeyInit(&key[0],
14935 				Anum_pg_constraint_conrelid,
14936 				BTEqualStrategyNumber, F_OIDEQ,
14937 				ObjectIdGetDatum(RelationGetRelid(parent_rel)));
14938 	scan = systable_beginscan(catalogRelation, ConstraintRelidTypidNameIndexId,
14939 							  true, NULL, 1, key);
14940 
14941 	connames = NIL;
14942 
14943 	while (HeapTupleIsValid(constraintTuple = systable_getnext(scan)))
14944 	{
14945 		Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(constraintTuple);
14946 
14947 		if (con->contype == CONSTRAINT_CHECK)
14948 			connames = lappend(connames, pstrdup(NameStr(con->conname)));
14949 	}
14950 
14951 	systable_endscan(scan);
14952 
14953 	/* Now scan the child's constraints */
14954 	ScanKeyInit(&key[0],
14955 				Anum_pg_constraint_conrelid,
14956 				BTEqualStrategyNumber, F_OIDEQ,
14957 				ObjectIdGetDatum(RelationGetRelid(child_rel)));
14958 	scan = systable_beginscan(catalogRelation, ConstraintRelidTypidNameIndexId,
14959 							  true, NULL, 1, key);
14960 
14961 	while (HeapTupleIsValid(constraintTuple = systable_getnext(scan)))
14962 	{
14963 		Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(constraintTuple);
14964 		bool		match;
14965 		ListCell   *lc;
14966 
14967 		if (con->contype != CONSTRAINT_CHECK)
14968 			continue;
14969 
14970 		match = false;
14971 		foreach(lc, connames)
14972 		{
14973 			if (strcmp(NameStr(con->conname), (char *) lfirst(lc)) == 0)
14974 			{
14975 				match = true;
14976 				break;
14977 			}
14978 		}
14979 
14980 		if (match)
14981 		{
14982 			/* Decrement inhcount and possibly set islocal to true */
14983 			HeapTuple	copyTuple = heap_copytuple(constraintTuple);
14984 			Form_pg_constraint copy_con = (Form_pg_constraint) GETSTRUCT(copyTuple);
14985 
14986 			if (copy_con->coninhcount <= 0) /* shouldn't happen */
14987 				elog(ERROR, "relation %u has non-inherited constraint \"%s\"",
14988 					 RelationGetRelid(child_rel), NameStr(copy_con->conname));
14989 
14990 			copy_con->coninhcount--;
14991 			if (copy_con->coninhcount == 0)
14992 				copy_con->conislocal = true;
14993 
14994 			CatalogTupleUpdate(catalogRelation, &copyTuple->t_self, copyTuple);
14995 			heap_freetuple(copyTuple);
14996 		}
14997 	}
14998 
14999 	systable_endscan(scan);
15000 	table_close(catalogRelation, RowExclusiveLock);
15001 
15002 	drop_parent_dependency(RelationGetRelid(child_rel),
15003 						   RelationRelationId,
15004 						   RelationGetRelid(parent_rel),
15005 						   child_dependency_type(child_is_partition));
15006 
15007 	/*
15008 	 * Post alter hook of this inherits. Since object_access_hook doesn't take
15009 	 * multiple object identifiers, we relay oid of parent relation using
15010 	 * auxiliary_id argument.
15011 	 */
15012 	InvokeObjectPostAlterHookArg(InheritsRelationId,
15013 								 RelationGetRelid(child_rel), 0,
15014 								 RelationGetRelid(parent_rel), false);
15015 }
15016 
15017 /*
15018  * Drop the dependency created by StoreCatalogInheritance1 (CREATE TABLE
15019  * INHERITS/ALTER TABLE INHERIT -- refclassid will be RelationRelationId) or
15020  * heap_create_with_catalog (CREATE TABLE OF/ALTER TABLE OF -- refclassid will
15021  * be TypeRelationId).  There's no convenient way to do this, so go trawling
15022  * through pg_depend.
15023  */
15024 static void
drop_parent_dependency(Oid relid,Oid refclassid,Oid refobjid,DependencyType deptype)15025 drop_parent_dependency(Oid relid, Oid refclassid, Oid refobjid,
15026 					   DependencyType deptype)
15027 {
15028 	Relation	catalogRelation;
15029 	SysScanDesc scan;
15030 	ScanKeyData key[3];
15031 	HeapTuple	depTuple;
15032 
15033 	catalogRelation = table_open(DependRelationId, RowExclusiveLock);
15034 
15035 	ScanKeyInit(&key[0],
15036 				Anum_pg_depend_classid,
15037 				BTEqualStrategyNumber, F_OIDEQ,
15038 				ObjectIdGetDatum(RelationRelationId));
15039 	ScanKeyInit(&key[1],
15040 				Anum_pg_depend_objid,
15041 				BTEqualStrategyNumber, F_OIDEQ,
15042 				ObjectIdGetDatum(relid));
15043 	ScanKeyInit(&key[2],
15044 				Anum_pg_depend_objsubid,
15045 				BTEqualStrategyNumber, F_INT4EQ,
15046 				Int32GetDatum(0));
15047 
15048 	scan = systable_beginscan(catalogRelation, DependDependerIndexId, true,
15049 							  NULL, 3, key);
15050 
15051 	while (HeapTupleIsValid(depTuple = systable_getnext(scan)))
15052 	{
15053 		Form_pg_depend dep = (Form_pg_depend) GETSTRUCT(depTuple);
15054 
15055 		if (dep->refclassid == refclassid &&
15056 			dep->refobjid == refobjid &&
15057 			dep->refobjsubid == 0 &&
15058 			dep->deptype == deptype)
15059 			CatalogTupleDelete(catalogRelation, &depTuple->t_self);
15060 	}
15061 
15062 	systable_endscan(scan);
15063 	table_close(catalogRelation, RowExclusiveLock);
15064 }
15065 
15066 /*
15067  * ALTER TABLE OF
15068  *
15069  * Attach a table to a composite type, as though it had been created with CREATE
15070  * TABLE OF.  All attname, atttypid, atttypmod and attcollation must match.  The
15071  * subject table must not have inheritance parents.  These restrictions ensure
15072  * that you cannot create a configuration impossible with CREATE TABLE OF alone.
15073  *
15074  * The address of the type is returned.
15075  */
15076 static ObjectAddress
ATExecAddOf(Relation rel,const TypeName * ofTypename,LOCKMODE lockmode)15077 ATExecAddOf(Relation rel, const TypeName *ofTypename, LOCKMODE lockmode)
15078 {
15079 	Oid			relid = RelationGetRelid(rel);
15080 	Type		typetuple;
15081 	Form_pg_type typeform;
15082 	Oid			typeid;
15083 	Relation	inheritsRelation,
15084 				relationRelation;
15085 	SysScanDesc scan;
15086 	ScanKeyData key;
15087 	AttrNumber	table_attno,
15088 				type_attno;
15089 	TupleDesc	typeTupleDesc,
15090 				tableTupleDesc;
15091 	ObjectAddress tableobj,
15092 				typeobj;
15093 	HeapTuple	classtuple;
15094 
15095 	/* Validate the type. */
15096 	typetuple = typenameType(NULL, ofTypename, NULL);
15097 	check_of_type(typetuple);
15098 	typeform = (Form_pg_type) GETSTRUCT(typetuple);
15099 	typeid = typeform->oid;
15100 
15101 	/* Fail if the table has any inheritance parents. */
15102 	inheritsRelation = table_open(InheritsRelationId, AccessShareLock);
15103 	ScanKeyInit(&key,
15104 				Anum_pg_inherits_inhrelid,
15105 				BTEqualStrategyNumber, F_OIDEQ,
15106 				ObjectIdGetDatum(relid));
15107 	scan = systable_beginscan(inheritsRelation, InheritsRelidSeqnoIndexId,
15108 							  true, NULL, 1, &key);
15109 	if (HeapTupleIsValid(systable_getnext(scan)))
15110 		ereport(ERROR,
15111 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
15112 				 errmsg("typed tables cannot inherit")));
15113 	systable_endscan(scan);
15114 	table_close(inheritsRelation, AccessShareLock);
15115 
15116 	/*
15117 	 * Check the tuple descriptors for compatibility.  Unlike inheritance, we
15118 	 * require that the order also match.  However, attnotnull need not match.
15119 	 */
15120 	typeTupleDesc = lookup_rowtype_tupdesc(typeid, -1);
15121 	tableTupleDesc = RelationGetDescr(rel);
15122 	table_attno = 1;
15123 	for (type_attno = 1; type_attno <= typeTupleDesc->natts; type_attno++)
15124 	{
15125 		Form_pg_attribute type_attr,
15126 					table_attr;
15127 		const char *type_attname,
15128 				   *table_attname;
15129 
15130 		/* Get the next non-dropped type attribute. */
15131 		type_attr = TupleDescAttr(typeTupleDesc, type_attno - 1);
15132 		if (type_attr->attisdropped)
15133 			continue;
15134 		type_attname = NameStr(type_attr->attname);
15135 
15136 		/* Get the next non-dropped table attribute. */
15137 		do
15138 		{
15139 			if (table_attno > tableTupleDesc->natts)
15140 				ereport(ERROR,
15141 						(errcode(ERRCODE_DATATYPE_MISMATCH),
15142 						 errmsg("table is missing column \"%s\"",
15143 								type_attname)));
15144 			table_attr = TupleDescAttr(tableTupleDesc, table_attno - 1);
15145 			table_attno++;
15146 		} while (table_attr->attisdropped);
15147 		table_attname = NameStr(table_attr->attname);
15148 
15149 		/* Compare name. */
15150 		if (strncmp(table_attname, type_attname, NAMEDATALEN) != 0)
15151 			ereport(ERROR,
15152 					(errcode(ERRCODE_DATATYPE_MISMATCH),
15153 					 errmsg("table has column \"%s\" where type requires \"%s\"",
15154 							table_attname, type_attname)));
15155 
15156 		/* Compare type. */
15157 		if (table_attr->atttypid != type_attr->atttypid ||
15158 			table_attr->atttypmod != type_attr->atttypmod ||
15159 			table_attr->attcollation != type_attr->attcollation)
15160 			ereport(ERROR,
15161 					(errcode(ERRCODE_DATATYPE_MISMATCH),
15162 					 errmsg("table \"%s\" has different type for column \"%s\"",
15163 							RelationGetRelationName(rel), type_attname)));
15164 	}
15165 	DecrTupleDescRefCount(typeTupleDesc);
15166 
15167 	/* Any remaining columns at the end of the table had better be dropped. */
15168 	for (; table_attno <= tableTupleDesc->natts; table_attno++)
15169 	{
15170 		Form_pg_attribute table_attr = TupleDescAttr(tableTupleDesc,
15171 													 table_attno - 1);
15172 
15173 		if (!table_attr->attisdropped)
15174 			ereport(ERROR,
15175 					(errcode(ERRCODE_DATATYPE_MISMATCH),
15176 					 errmsg("table has extra column \"%s\"",
15177 							NameStr(table_attr->attname))));
15178 	}
15179 
15180 	/* If the table was already typed, drop the existing dependency. */
15181 	if (rel->rd_rel->reloftype)
15182 		drop_parent_dependency(relid, TypeRelationId, rel->rd_rel->reloftype,
15183 							   DEPENDENCY_NORMAL);
15184 
15185 	/* Record a dependency on the new type. */
15186 	tableobj.classId = RelationRelationId;
15187 	tableobj.objectId = relid;
15188 	tableobj.objectSubId = 0;
15189 	typeobj.classId = TypeRelationId;
15190 	typeobj.objectId = typeid;
15191 	typeobj.objectSubId = 0;
15192 	recordDependencyOn(&tableobj, &typeobj, DEPENDENCY_NORMAL);
15193 
15194 	/* Update pg_class.reloftype */
15195 	relationRelation = table_open(RelationRelationId, RowExclusiveLock);
15196 	classtuple = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
15197 	if (!HeapTupleIsValid(classtuple))
15198 		elog(ERROR, "cache lookup failed for relation %u", relid);
15199 	((Form_pg_class) GETSTRUCT(classtuple))->reloftype = typeid;
15200 	CatalogTupleUpdate(relationRelation, &classtuple->t_self, classtuple);
15201 
15202 	InvokeObjectPostAlterHook(RelationRelationId, relid, 0);
15203 
15204 	heap_freetuple(classtuple);
15205 	table_close(relationRelation, RowExclusiveLock);
15206 
15207 	ReleaseSysCache(typetuple);
15208 
15209 	return typeobj;
15210 }
15211 
15212 /*
15213  * ALTER TABLE NOT OF
15214  *
15215  * Detach a typed table from its originating type.  Just clear reloftype and
15216  * remove the dependency.
15217  */
15218 static void
ATExecDropOf(Relation rel,LOCKMODE lockmode)15219 ATExecDropOf(Relation rel, LOCKMODE lockmode)
15220 {
15221 	Oid			relid = RelationGetRelid(rel);
15222 	Relation	relationRelation;
15223 	HeapTuple	tuple;
15224 
15225 	if (!OidIsValid(rel->rd_rel->reloftype))
15226 		ereport(ERROR,
15227 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
15228 				 errmsg("\"%s\" is not a typed table",
15229 						RelationGetRelationName(rel))));
15230 
15231 	/*
15232 	 * We don't bother to check ownership of the type --- ownership of the
15233 	 * table is presumed enough rights.  No lock required on the type, either.
15234 	 */
15235 
15236 	drop_parent_dependency(relid, TypeRelationId, rel->rd_rel->reloftype,
15237 						   DEPENDENCY_NORMAL);
15238 
15239 	/* Clear pg_class.reloftype */
15240 	relationRelation = table_open(RelationRelationId, RowExclusiveLock);
15241 	tuple = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
15242 	if (!HeapTupleIsValid(tuple))
15243 		elog(ERROR, "cache lookup failed for relation %u", relid);
15244 	((Form_pg_class) GETSTRUCT(tuple))->reloftype = InvalidOid;
15245 	CatalogTupleUpdate(relationRelation, &tuple->t_self, tuple);
15246 
15247 	InvokeObjectPostAlterHook(RelationRelationId, relid, 0);
15248 
15249 	heap_freetuple(tuple);
15250 	table_close(relationRelation, RowExclusiveLock);
15251 }
15252 
15253 /*
15254  * relation_mark_replica_identity: Update a table's replica identity
15255  *
15256  * Iff ri_type = REPLICA_IDENTITY_INDEX, indexOid must be the Oid of a suitable
15257  * index. Otherwise, it should be InvalidOid.
15258  */
15259 static void
relation_mark_replica_identity(Relation rel,char ri_type,Oid indexOid,bool is_internal)15260 relation_mark_replica_identity(Relation rel, char ri_type, Oid indexOid,
15261 							   bool is_internal)
15262 {
15263 	Relation	pg_index;
15264 	Relation	pg_class;
15265 	HeapTuple	pg_class_tuple;
15266 	HeapTuple	pg_index_tuple;
15267 	Form_pg_class pg_class_form;
15268 	Form_pg_index pg_index_form;
15269 
15270 	ListCell   *index;
15271 
15272 	/*
15273 	 * Check whether relreplident has changed, and update it if so.
15274 	 */
15275 	pg_class = table_open(RelationRelationId, RowExclusiveLock);
15276 	pg_class_tuple = SearchSysCacheCopy1(RELOID,
15277 										 ObjectIdGetDatum(RelationGetRelid(rel)));
15278 	if (!HeapTupleIsValid(pg_class_tuple))
15279 		elog(ERROR, "cache lookup failed for relation \"%s\"",
15280 			 RelationGetRelationName(rel));
15281 	pg_class_form = (Form_pg_class) GETSTRUCT(pg_class_tuple);
15282 	if (pg_class_form->relreplident != ri_type)
15283 	{
15284 		pg_class_form->relreplident = ri_type;
15285 		CatalogTupleUpdate(pg_class, &pg_class_tuple->t_self, pg_class_tuple);
15286 	}
15287 	table_close(pg_class, RowExclusiveLock);
15288 	heap_freetuple(pg_class_tuple);
15289 
15290 	/*
15291 	 * Check whether the correct index is marked indisreplident; if so, we're
15292 	 * done.
15293 	 */
15294 	if (OidIsValid(indexOid))
15295 	{
15296 		Assert(ri_type == REPLICA_IDENTITY_INDEX);
15297 
15298 		pg_index_tuple = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(indexOid));
15299 		if (!HeapTupleIsValid(pg_index_tuple))
15300 			elog(ERROR, "cache lookup failed for index %u", indexOid);
15301 		pg_index_form = (Form_pg_index) GETSTRUCT(pg_index_tuple);
15302 
15303 		if (pg_index_form->indisreplident)
15304 		{
15305 			ReleaseSysCache(pg_index_tuple);
15306 			return;
15307 		}
15308 		ReleaseSysCache(pg_index_tuple);
15309 	}
15310 
15311 	/*
15312 	 * Clear the indisreplident flag from any index that had it previously,
15313 	 * and set it for any index that should have it now.
15314 	 */
15315 	pg_index = table_open(IndexRelationId, RowExclusiveLock);
15316 	foreach(index, RelationGetIndexList(rel))
15317 	{
15318 		Oid			thisIndexOid = lfirst_oid(index);
15319 		bool		dirty = false;
15320 
15321 		pg_index_tuple = SearchSysCacheCopy1(INDEXRELID,
15322 											 ObjectIdGetDatum(thisIndexOid));
15323 		if (!HeapTupleIsValid(pg_index_tuple))
15324 			elog(ERROR, "cache lookup failed for index %u", thisIndexOid);
15325 		pg_index_form = (Form_pg_index) GETSTRUCT(pg_index_tuple);
15326 
15327 		/*
15328 		 * Unset the bit if set.  We know it's wrong because we checked this
15329 		 * earlier.
15330 		 */
15331 		if (pg_index_form->indisreplident)
15332 		{
15333 			dirty = true;
15334 			pg_index_form->indisreplident = false;
15335 		}
15336 		else if (thisIndexOid == indexOid)
15337 		{
15338 			dirty = true;
15339 			pg_index_form->indisreplident = true;
15340 		}
15341 
15342 		if (dirty)
15343 		{
15344 			CatalogTupleUpdate(pg_index, &pg_index_tuple->t_self, pg_index_tuple);
15345 			InvokeObjectPostAlterHookArg(IndexRelationId, thisIndexOid, 0,
15346 										 InvalidOid, is_internal);
15347 		}
15348 		heap_freetuple(pg_index_tuple);
15349 	}
15350 
15351 	table_close(pg_index, RowExclusiveLock);
15352 }
15353 
15354 /*
15355  * ALTER TABLE <name> REPLICA IDENTITY ...
15356  */
15357 static void
ATExecReplicaIdentity(Relation rel,ReplicaIdentityStmt * stmt,LOCKMODE lockmode)15358 ATExecReplicaIdentity(Relation rel, ReplicaIdentityStmt *stmt, LOCKMODE lockmode)
15359 {
15360 	Oid			indexOid;
15361 	Relation	indexRel;
15362 	int			key;
15363 
15364 	if (stmt->identity_type == REPLICA_IDENTITY_DEFAULT)
15365 	{
15366 		relation_mark_replica_identity(rel, stmt->identity_type, InvalidOid, true);
15367 		return;
15368 	}
15369 	else if (stmt->identity_type == REPLICA_IDENTITY_FULL)
15370 	{
15371 		relation_mark_replica_identity(rel, stmt->identity_type, InvalidOid, true);
15372 		return;
15373 	}
15374 	else if (stmt->identity_type == REPLICA_IDENTITY_NOTHING)
15375 	{
15376 		relation_mark_replica_identity(rel, stmt->identity_type, InvalidOid, true);
15377 		return;
15378 	}
15379 	else if (stmt->identity_type == REPLICA_IDENTITY_INDEX)
15380 	{
15381 		 /* fallthrough */ ;
15382 	}
15383 	else
15384 		elog(ERROR, "unexpected identity type %u", stmt->identity_type);
15385 
15386 
15387 	/* Check that the index exists */
15388 	indexOid = get_relname_relid(stmt->name, rel->rd_rel->relnamespace);
15389 	if (!OidIsValid(indexOid))
15390 		ereport(ERROR,
15391 				(errcode(ERRCODE_UNDEFINED_OBJECT),
15392 				 errmsg("index \"%s\" for table \"%s\" does not exist",
15393 						stmt->name, RelationGetRelationName(rel))));
15394 
15395 	indexRel = index_open(indexOid, ShareLock);
15396 
15397 	/* Check that the index is on the relation we're altering. */
15398 	if (indexRel->rd_index == NULL ||
15399 		indexRel->rd_index->indrelid != RelationGetRelid(rel))
15400 		ereport(ERROR,
15401 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
15402 				 errmsg("\"%s\" is not an index for table \"%s\"",
15403 						RelationGetRelationName(indexRel),
15404 						RelationGetRelationName(rel))));
15405 	/* The AM must support uniqueness, and the index must in fact be unique. */
15406 	if (!indexRel->rd_indam->amcanunique ||
15407 		!indexRel->rd_index->indisunique)
15408 		ereport(ERROR,
15409 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
15410 				 errmsg("cannot use non-unique index \"%s\" as replica identity",
15411 						RelationGetRelationName(indexRel))));
15412 	/* Deferred indexes are not guaranteed to be always unique. */
15413 	if (!indexRel->rd_index->indimmediate)
15414 		ereport(ERROR,
15415 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
15416 				 errmsg("cannot use non-immediate index \"%s\" as replica identity",
15417 						RelationGetRelationName(indexRel))));
15418 	/* Expression indexes aren't supported. */
15419 	if (RelationGetIndexExpressions(indexRel) != NIL)
15420 		ereport(ERROR,
15421 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
15422 				 errmsg("cannot use expression index \"%s\" as replica identity",
15423 						RelationGetRelationName(indexRel))));
15424 	/* Predicate indexes aren't supported. */
15425 	if (RelationGetIndexPredicate(indexRel) != NIL)
15426 		ereport(ERROR,
15427 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
15428 				 errmsg("cannot use partial index \"%s\" as replica identity",
15429 						RelationGetRelationName(indexRel))));
15430 	/* And neither are invalid indexes. */
15431 	if (!indexRel->rd_index->indisvalid)
15432 		ereport(ERROR,
15433 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
15434 				 errmsg("cannot use invalid index \"%s\" as replica identity",
15435 						RelationGetRelationName(indexRel))));
15436 
15437 	/* Check index for nullable columns. */
15438 	for (key = 0; key < IndexRelationGetNumberOfKeyAttributes(indexRel); key++)
15439 	{
15440 		int16		attno = indexRel->rd_index->indkey.values[key];
15441 		Form_pg_attribute attr;
15442 
15443 		/*
15444 		 * Reject any other system columns.  (Going forward, we'll disallow
15445 		 * indexes containing such columns in the first place, but they might
15446 		 * exist in older branches.)
15447 		 */
15448 		if (attno <= 0)
15449 			ereport(ERROR,
15450 					(errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
15451 					 errmsg("index \"%s\" cannot be used as replica identity because column %d is a system column",
15452 							RelationGetRelationName(indexRel), attno)));
15453 
15454 		attr = TupleDescAttr(rel->rd_att, attno - 1);
15455 		if (!attr->attnotnull)
15456 			ereport(ERROR,
15457 					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
15458 					 errmsg("index \"%s\" cannot be used as replica identity because column \"%s\" is nullable",
15459 							RelationGetRelationName(indexRel),
15460 							NameStr(attr->attname))));
15461 	}
15462 
15463 	/* This index is suitable for use as a replica identity. Mark it. */
15464 	relation_mark_replica_identity(rel, stmt->identity_type, indexOid, true);
15465 
15466 	index_close(indexRel, NoLock);
15467 }
15468 
15469 /*
15470  * ALTER TABLE ENABLE/DISABLE ROW LEVEL SECURITY
15471  */
15472 static void
ATExecSetRowSecurity(Relation rel,bool rls)15473 ATExecSetRowSecurity(Relation rel, bool rls)
15474 {
15475 	Relation	pg_class;
15476 	Oid			relid;
15477 	HeapTuple	tuple;
15478 
15479 	relid = RelationGetRelid(rel);
15480 
15481 	/* Pull the record for this relation and update it */
15482 	pg_class = table_open(RelationRelationId, RowExclusiveLock);
15483 
15484 	tuple = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
15485 
15486 	if (!HeapTupleIsValid(tuple))
15487 		elog(ERROR, "cache lookup failed for relation %u", relid);
15488 
15489 	((Form_pg_class) GETSTRUCT(tuple))->relrowsecurity = rls;
15490 	CatalogTupleUpdate(pg_class, &tuple->t_self, tuple);
15491 
15492 	table_close(pg_class, RowExclusiveLock);
15493 	heap_freetuple(tuple);
15494 }
15495 
15496 /*
15497  * ALTER TABLE FORCE/NO FORCE ROW LEVEL SECURITY
15498  */
15499 static void
ATExecForceNoForceRowSecurity(Relation rel,bool force_rls)15500 ATExecForceNoForceRowSecurity(Relation rel, bool force_rls)
15501 {
15502 	Relation	pg_class;
15503 	Oid			relid;
15504 	HeapTuple	tuple;
15505 
15506 	relid = RelationGetRelid(rel);
15507 
15508 	pg_class = table_open(RelationRelationId, RowExclusiveLock);
15509 
15510 	tuple = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
15511 
15512 	if (!HeapTupleIsValid(tuple))
15513 		elog(ERROR, "cache lookup failed for relation %u", relid);
15514 
15515 	((Form_pg_class) GETSTRUCT(tuple))->relforcerowsecurity = force_rls;
15516 	CatalogTupleUpdate(pg_class, &tuple->t_self, tuple);
15517 
15518 	table_close(pg_class, RowExclusiveLock);
15519 	heap_freetuple(tuple);
15520 }
15521 
15522 /*
15523  * ALTER FOREIGN TABLE <name> OPTIONS (...)
15524  */
15525 static void
ATExecGenericOptions(Relation rel,List * options)15526 ATExecGenericOptions(Relation rel, List *options)
15527 {
15528 	Relation	ftrel;
15529 	ForeignServer *server;
15530 	ForeignDataWrapper *fdw;
15531 	HeapTuple	tuple;
15532 	bool		isnull;
15533 	Datum		repl_val[Natts_pg_foreign_table];
15534 	bool		repl_null[Natts_pg_foreign_table];
15535 	bool		repl_repl[Natts_pg_foreign_table];
15536 	Datum		datum;
15537 	Form_pg_foreign_table tableform;
15538 
15539 	if (options == NIL)
15540 		return;
15541 
15542 	ftrel = table_open(ForeignTableRelationId, RowExclusiveLock);
15543 
15544 	tuple = SearchSysCacheCopy1(FOREIGNTABLEREL, rel->rd_id);
15545 	if (!HeapTupleIsValid(tuple))
15546 		ereport(ERROR,
15547 				(errcode(ERRCODE_UNDEFINED_OBJECT),
15548 				 errmsg("foreign table \"%s\" does not exist",
15549 						RelationGetRelationName(rel))));
15550 	tableform = (Form_pg_foreign_table) GETSTRUCT(tuple);
15551 	server = GetForeignServer(tableform->ftserver);
15552 	fdw = GetForeignDataWrapper(server->fdwid);
15553 
15554 	memset(repl_val, 0, sizeof(repl_val));
15555 	memset(repl_null, false, sizeof(repl_null));
15556 	memset(repl_repl, false, sizeof(repl_repl));
15557 
15558 	/* Extract the current options */
15559 	datum = SysCacheGetAttr(FOREIGNTABLEREL,
15560 							tuple,
15561 							Anum_pg_foreign_table_ftoptions,
15562 							&isnull);
15563 	if (isnull)
15564 		datum = PointerGetDatum(NULL);
15565 
15566 	/* Transform the options */
15567 	datum = transformGenericOptions(ForeignTableRelationId,
15568 									datum,
15569 									options,
15570 									fdw->fdwvalidator);
15571 
15572 	if (PointerIsValid(DatumGetPointer(datum)))
15573 		repl_val[Anum_pg_foreign_table_ftoptions - 1] = datum;
15574 	else
15575 		repl_null[Anum_pg_foreign_table_ftoptions - 1] = true;
15576 
15577 	repl_repl[Anum_pg_foreign_table_ftoptions - 1] = true;
15578 
15579 	/* Everything looks good - update the tuple */
15580 
15581 	tuple = heap_modify_tuple(tuple, RelationGetDescr(ftrel),
15582 							  repl_val, repl_null, repl_repl);
15583 
15584 	CatalogTupleUpdate(ftrel, &tuple->t_self, tuple);
15585 
15586 	/*
15587 	 * Invalidate relcache so that all sessions will refresh any cached plans
15588 	 * that might depend on the old options.
15589 	 */
15590 	CacheInvalidateRelcache(rel);
15591 
15592 	InvokeObjectPostAlterHook(ForeignTableRelationId,
15593 							  RelationGetRelid(rel), 0);
15594 
15595 	table_close(ftrel, RowExclusiveLock);
15596 
15597 	heap_freetuple(tuple);
15598 }
15599 
15600 /*
15601  * ALTER TABLE ALTER COLUMN SET COMPRESSION
15602  *
15603  * Return value is the address of the modified column
15604  */
15605 static ObjectAddress
ATExecSetCompression(AlteredTableInfo * tab,Relation rel,const char * column,Node * newValue,LOCKMODE lockmode)15606 ATExecSetCompression(AlteredTableInfo *tab,
15607 					 Relation rel,
15608 					 const char *column,
15609 					 Node *newValue,
15610 					 LOCKMODE lockmode)
15611 {
15612 	Relation	attrel;
15613 	HeapTuple	tuple;
15614 	Form_pg_attribute atttableform;
15615 	AttrNumber	attnum;
15616 	char	   *compression;
15617 	char		cmethod;
15618 	ObjectAddress address;
15619 
15620 	Assert(IsA(newValue, String));
15621 	compression = strVal(newValue);
15622 
15623 	attrel = table_open(AttributeRelationId, RowExclusiveLock);
15624 
15625 	/* copy the cache entry so we can scribble on it below */
15626 	tuple = SearchSysCacheCopyAttName(RelationGetRelid(rel), column);
15627 	if (!HeapTupleIsValid(tuple))
15628 		ereport(ERROR,
15629 				(errcode(ERRCODE_UNDEFINED_COLUMN),
15630 				 errmsg("column \"%s\" of relation \"%s\" does not exist",
15631 						column, RelationGetRelationName(rel))));
15632 
15633 	/* prevent them from altering a system attribute */
15634 	atttableform = (Form_pg_attribute) GETSTRUCT(tuple);
15635 	attnum = atttableform->attnum;
15636 	if (attnum <= 0)
15637 		ereport(ERROR,
15638 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
15639 				 errmsg("cannot alter system column \"%s\"", column)));
15640 
15641 	/*
15642 	 * Check that column type is compressible, then get the attribute
15643 	 * compression method code
15644 	 */
15645 	cmethod = GetAttributeCompression(atttableform->atttypid, compression);
15646 
15647 	/* update pg_attribute entry */
15648 	atttableform->attcompression = cmethod;
15649 	CatalogTupleUpdate(attrel, &tuple->t_self, tuple);
15650 
15651 	InvokeObjectPostAlterHook(RelationRelationId,
15652 							  RelationGetRelid(rel),
15653 							  attnum);
15654 
15655 	/*
15656 	 * Apply the change to indexes as well (only for simple index columns,
15657 	 * matching behavior of index.c ConstructTupleDescriptor()).
15658 	 */
15659 	SetIndexStorageProperties(rel, attrel, attnum,
15660 							  false, 0,
15661 							  true, cmethod,
15662 							  lockmode);
15663 
15664 	heap_freetuple(tuple);
15665 
15666 	table_close(attrel, RowExclusiveLock);
15667 
15668 	/* make changes visible */
15669 	CommandCounterIncrement();
15670 
15671 	ObjectAddressSubSet(address, RelationRelationId,
15672 						RelationGetRelid(rel), attnum);
15673 	return address;
15674 }
15675 
15676 
15677 /*
15678  * Preparation phase for SET LOGGED/UNLOGGED
15679  *
15680  * This verifies that we're not trying to change a temp table.  Also,
15681  * existing foreign key constraints are checked to avoid ending up with
15682  * permanent tables referencing unlogged tables.
15683  *
15684  * Return value is false if the operation is a no-op (in which case the
15685  * checks are skipped), otherwise true.
15686  */
15687 static bool
ATPrepChangePersistence(Relation rel,bool toLogged)15688 ATPrepChangePersistence(Relation rel, bool toLogged)
15689 {
15690 	Relation	pg_constraint;
15691 	HeapTuple	tuple;
15692 	SysScanDesc scan;
15693 	ScanKeyData skey[1];
15694 
15695 	/*
15696 	 * Disallow changing status for a temp table.  Also verify whether we can
15697 	 * get away with doing nothing; in such cases we don't need to run the
15698 	 * checks below, either.
15699 	 */
15700 	switch (rel->rd_rel->relpersistence)
15701 	{
15702 		case RELPERSISTENCE_TEMP:
15703 			ereport(ERROR,
15704 					(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
15705 					 errmsg("cannot change logged status of table \"%s\" because it is temporary",
15706 							RelationGetRelationName(rel)),
15707 					 errtable(rel)));
15708 			break;
15709 		case RELPERSISTENCE_PERMANENT:
15710 			if (toLogged)
15711 				/* nothing to do */
15712 				return false;
15713 			break;
15714 		case RELPERSISTENCE_UNLOGGED:
15715 			if (!toLogged)
15716 				/* nothing to do */
15717 				return false;
15718 			break;
15719 	}
15720 
15721 	/*
15722 	 * Check that the table is not part any publication when changing to
15723 	 * UNLOGGED as UNLOGGED tables can't be published.
15724 	 */
15725 	if (!toLogged &&
15726 		list_length(GetRelationPublications(RelationGetRelid(rel))) > 0)
15727 		ereport(ERROR,
15728 				(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
15729 				 errmsg("cannot change table \"%s\" to unlogged because it is part of a publication",
15730 						RelationGetRelationName(rel)),
15731 				 errdetail("Unlogged relations cannot be replicated.")));
15732 
15733 	/*
15734 	 * Check existing foreign key constraints to preserve the invariant that
15735 	 * permanent tables cannot reference unlogged ones.  Self-referencing
15736 	 * foreign keys can safely be ignored.
15737 	 */
15738 	pg_constraint = table_open(ConstraintRelationId, AccessShareLock);
15739 
15740 	/*
15741 	 * Scan conrelid if changing to permanent, else confrelid.  This also
15742 	 * determines whether a useful index exists.
15743 	 */
15744 	ScanKeyInit(&skey[0],
15745 				toLogged ? Anum_pg_constraint_conrelid :
15746 				Anum_pg_constraint_confrelid,
15747 				BTEqualStrategyNumber, F_OIDEQ,
15748 				ObjectIdGetDatum(RelationGetRelid(rel)));
15749 	scan = systable_beginscan(pg_constraint,
15750 							  toLogged ? ConstraintRelidTypidNameIndexId : InvalidOid,
15751 							  true, NULL, 1, skey);
15752 
15753 	while (HeapTupleIsValid(tuple = systable_getnext(scan)))
15754 	{
15755 		Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(tuple);
15756 
15757 		if (con->contype == CONSTRAINT_FOREIGN)
15758 		{
15759 			Oid			foreignrelid;
15760 			Relation	foreignrel;
15761 
15762 			/* the opposite end of what we used as scankey */
15763 			foreignrelid = toLogged ? con->confrelid : con->conrelid;
15764 
15765 			/* ignore if self-referencing */
15766 			if (RelationGetRelid(rel) == foreignrelid)
15767 				continue;
15768 
15769 			foreignrel = relation_open(foreignrelid, AccessShareLock);
15770 
15771 			if (toLogged)
15772 			{
15773 				if (!RelationIsPermanent(foreignrel))
15774 					ereport(ERROR,
15775 							(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
15776 							 errmsg("could not change table \"%s\" to logged because it references unlogged table \"%s\"",
15777 									RelationGetRelationName(rel),
15778 									RelationGetRelationName(foreignrel)),
15779 							 errtableconstraint(rel, NameStr(con->conname))));
15780 			}
15781 			else
15782 			{
15783 				if (RelationIsPermanent(foreignrel))
15784 					ereport(ERROR,
15785 							(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
15786 							 errmsg("could not change table \"%s\" to unlogged because it references logged table \"%s\"",
15787 									RelationGetRelationName(rel),
15788 									RelationGetRelationName(foreignrel)),
15789 							 errtableconstraint(rel, NameStr(con->conname))));
15790 			}
15791 
15792 			relation_close(foreignrel, AccessShareLock);
15793 		}
15794 	}
15795 
15796 	systable_endscan(scan);
15797 
15798 	table_close(pg_constraint, AccessShareLock);
15799 
15800 	return true;
15801 }
15802 
15803 /*
15804  * Execute ALTER TABLE SET SCHEMA
15805  */
15806 ObjectAddress
AlterTableNamespace(AlterObjectSchemaStmt * stmt,Oid * oldschema)15807 AlterTableNamespace(AlterObjectSchemaStmt *stmt, Oid *oldschema)
15808 {
15809 	Relation	rel;
15810 	Oid			relid;
15811 	Oid			oldNspOid;
15812 	Oid			nspOid;
15813 	RangeVar   *newrv;
15814 	ObjectAddresses *objsMoved;
15815 	ObjectAddress myself;
15816 
15817 	relid = RangeVarGetRelidExtended(stmt->relation, AccessExclusiveLock,
15818 									 stmt->missing_ok ? RVR_MISSING_OK : 0,
15819 									 RangeVarCallbackForAlterRelation,
15820 									 (void *) stmt);
15821 
15822 	if (!OidIsValid(relid))
15823 	{
15824 		ereport(NOTICE,
15825 				(errmsg("relation \"%s\" does not exist, skipping",
15826 						stmt->relation->relname)));
15827 		return InvalidObjectAddress;
15828 	}
15829 
15830 	rel = relation_open(relid, NoLock);
15831 
15832 	oldNspOid = RelationGetNamespace(rel);
15833 
15834 	/* If it's an owned sequence, disallow moving it by itself. */
15835 	if (rel->rd_rel->relkind == RELKIND_SEQUENCE)
15836 	{
15837 		Oid			tableId;
15838 		int32		colId;
15839 
15840 		if (sequenceIsOwned(relid, DEPENDENCY_AUTO, &tableId, &colId) ||
15841 			sequenceIsOwned(relid, DEPENDENCY_INTERNAL, &tableId, &colId))
15842 			ereport(ERROR,
15843 					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
15844 					 errmsg("cannot move an owned sequence into another schema"),
15845 					 errdetail("Sequence \"%s\" is linked to table \"%s\".",
15846 							   RelationGetRelationName(rel),
15847 							   get_rel_name(tableId))));
15848 	}
15849 
15850 	/* Get and lock schema OID and check its permissions. */
15851 	newrv = makeRangeVar(stmt->newschema, RelationGetRelationName(rel), -1);
15852 	nspOid = RangeVarGetAndCheckCreationNamespace(newrv, NoLock, NULL);
15853 
15854 	/* common checks on switching namespaces */
15855 	CheckSetNamespace(oldNspOid, nspOid);
15856 
15857 	objsMoved = new_object_addresses();
15858 	AlterTableNamespaceInternal(rel, oldNspOid, nspOid, objsMoved);
15859 	free_object_addresses(objsMoved);
15860 
15861 	ObjectAddressSet(myself, RelationRelationId, relid);
15862 
15863 	if (oldschema)
15864 		*oldschema = oldNspOid;
15865 
15866 	/* close rel, but keep lock until commit */
15867 	relation_close(rel, NoLock);
15868 
15869 	return myself;
15870 }
15871 
15872 /*
15873  * The guts of relocating a table or materialized view to another namespace:
15874  * besides moving the relation itself, its dependent objects are relocated to
15875  * the new schema.
15876  */
15877 void
AlterTableNamespaceInternal(Relation rel,Oid oldNspOid,Oid nspOid,ObjectAddresses * objsMoved)15878 AlterTableNamespaceInternal(Relation rel, Oid oldNspOid, Oid nspOid,
15879 							ObjectAddresses *objsMoved)
15880 {
15881 	Relation	classRel;
15882 
15883 	Assert(objsMoved != NULL);
15884 
15885 	/* OK, modify the pg_class row and pg_depend entry */
15886 	classRel = table_open(RelationRelationId, RowExclusiveLock);
15887 
15888 	AlterRelationNamespaceInternal(classRel, RelationGetRelid(rel), oldNspOid,
15889 								   nspOid, true, objsMoved);
15890 
15891 	/* Fix the table's row type too, if it has one */
15892 	if (OidIsValid(rel->rd_rel->reltype))
15893 		AlterTypeNamespaceInternal(rel->rd_rel->reltype,
15894 								   nspOid, false, false, objsMoved);
15895 
15896 	/* Fix other dependent stuff */
15897 	if (rel->rd_rel->relkind == RELKIND_RELATION ||
15898 		rel->rd_rel->relkind == RELKIND_MATVIEW ||
15899 		rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
15900 	{
15901 		AlterIndexNamespaces(classRel, rel, oldNspOid, nspOid, objsMoved);
15902 		AlterSeqNamespaces(classRel, rel, oldNspOid, nspOid,
15903 						   objsMoved, AccessExclusiveLock);
15904 		AlterConstraintNamespaces(RelationGetRelid(rel), oldNspOid, nspOid,
15905 								  false, objsMoved);
15906 	}
15907 
15908 	table_close(classRel, RowExclusiveLock);
15909 }
15910 
15911 /*
15912  * The guts of relocating a relation to another namespace: fix the pg_class
15913  * entry, and the pg_depend entry if any.  Caller must already have
15914  * opened and write-locked pg_class.
15915  */
15916 void
AlterRelationNamespaceInternal(Relation classRel,Oid relOid,Oid oldNspOid,Oid newNspOid,bool hasDependEntry,ObjectAddresses * objsMoved)15917 AlterRelationNamespaceInternal(Relation classRel, Oid relOid,
15918 							   Oid oldNspOid, Oid newNspOid,
15919 							   bool hasDependEntry,
15920 							   ObjectAddresses *objsMoved)
15921 {
15922 	HeapTuple	classTup;
15923 	Form_pg_class classForm;
15924 	ObjectAddress thisobj;
15925 	bool		already_done = false;
15926 
15927 	classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relOid));
15928 	if (!HeapTupleIsValid(classTup))
15929 		elog(ERROR, "cache lookup failed for relation %u", relOid);
15930 	classForm = (Form_pg_class) GETSTRUCT(classTup);
15931 
15932 	Assert(classForm->relnamespace == oldNspOid);
15933 
15934 	thisobj.classId = RelationRelationId;
15935 	thisobj.objectId = relOid;
15936 	thisobj.objectSubId = 0;
15937 
15938 	/*
15939 	 * If the object has already been moved, don't move it again.  If it's
15940 	 * already in the right place, don't move it, but still fire the object
15941 	 * access hook.
15942 	 */
15943 	already_done = object_address_present(&thisobj, objsMoved);
15944 	if (!already_done && oldNspOid != newNspOid)
15945 	{
15946 		/* check for duplicate name (more friendly than unique-index failure) */
15947 		if (get_relname_relid(NameStr(classForm->relname),
15948 							  newNspOid) != InvalidOid)
15949 			ereport(ERROR,
15950 					(errcode(ERRCODE_DUPLICATE_TABLE),
15951 					 errmsg("relation \"%s\" already exists in schema \"%s\"",
15952 							NameStr(classForm->relname),
15953 							get_namespace_name(newNspOid))));
15954 
15955 		/* classTup is a copy, so OK to scribble on */
15956 		classForm->relnamespace = newNspOid;
15957 
15958 		CatalogTupleUpdate(classRel, &classTup->t_self, classTup);
15959 
15960 		/* Update dependency on schema if caller said so */
15961 		if (hasDependEntry &&
15962 			changeDependencyFor(RelationRelationId,
15963 								relOid,
15964 								NamespaceRelationId,
15965 								oldNspOid,
15966 								newNspOid) != 1)
15967 			elog(ERROR, "failed to change schema dependency for relation \"%s\"",
15968 				 NameStr(classForm->relname));
15969 	}
15970 	if (!already_done)
15971 	{
15972 		add_exact_object_address(&thisobj, objsMoved);
15973 
15974 		InvokeObjectPostAlterHook(RelationRelationId, relOid, 0);
15975 	}
15976 
15977 	heap_freetuple(classTup);
15978 }
15979 
15980 /*
15981  * Move all indexes for the specified relation to another namespace.
15982  *
15983  * Note: we assume adequate permission checking was done by the caller,
15984  * and that the caller has a suitable lock on the owning relation.
15985  */
15986 static void
AlterIndexNamespaces(Relation classRel,Relation rel,Oid oldNspOid,Oid newNspOid,ObjectAddresses * objsMoved)15987 AlterIndexNamespaces(Relation classRel, Relation rel,
15988 					 Oid oldNspOid, Oid newNspOid, ObjectAddresses *objsMoved)
15989 {
15990 	List	   *indexList;
15991 	ListCell   *l;
15992 
15993 	indexList = RelationGetIndexList(rel);
15994 
15995 	foreach(l, indexList)
15996 	{
15997 		Oid			indexOid = lfirst_oid(l);
15998 		ObjectAddress thisobj;
15999 
16000 		thisobj.classId = RelationRelationId;
16001 		thisobj.objectId = indexOid;
16002 		thisobj.objectSubId = 0;
16003 
16004 		/*
16005 		 * Note: currently, the index will not have its own dependency on the
16006 		 * namespace, so we don't need to do changeDependencyFor(). There's no
16007 		 * row type in pg_type, either.
16008 		 *
16009 		 * XXX this objsMoved test may be pointless -- surely we have a single
16010 		 * dependency link from a relation to each index?
16011 		 */
16012 		if (!object_address_present(&thisobj, objsMoved))
16013 		{
16014 			AlterRelationNamespaceInternal(classRel, indexOid,
16015 										   oldNspOid, newNspOid,
16016 										   false, objsMoved);
16017 			add_exact_object_address(&thisobj, objsMoved);
16018 		}
16019 	}
16020 
16021 	list_free(indexList);
16022 }
16023 
16024 /*
16025  * Move all identity and SERIAL-column sequences of the specified relation to another
16026  * namespace.
16027  *
16028  * Note: we assume adequate permission checking was done by the caller,
16029  * and that the caller has a suitable lock on the owning relation.
16030  */
16031 static void
AlterSeqNamespaces(Relation classRel,Relation rel,Oid oldNspOid,Oid newNspOid,ObjectAddresses * objsMoved,LOCKMODE lockmode)16032 AlterSeqNamespaces(Relation classRel, Relation rel,
16033 				   Oid oldNspOid, Oid newNspOid, ObjectAddresses *objsMoved,
16034 				   LOCKMODE lockmode)
16035 {
16036 	Relation	depRel;
16037 	SysScanDesc scan;
16038 	ScanKeyData key[2];
16039 	HeapTuple	tup;
16040 
16041 	/*
16042 	 * SERIAL sequences are those having an auto dependency on one of the
16043 	 * table's columns (we don't care *which* column, exactly).
16044 	 */
16045 	depRel = table_open(DependRelationId, AccessShareLock);
16046 
16047 	ScanKeyInit(&key[0],
16048 				Anum_pg_depend_refclassid,
16049 				BTEqualStrategyNumber, F_OIDEQ,
16050 				ObjectIdGetDatum(RelationRelationId));
16051 	ScanKeyInit(&key[1],
16052 				Anum_pg_depend_refobjid,
16053 				BTEqualStrategyNumber, F_OIDEQ,
16054 				ObjectIdGetDatum(RelationGetRelid(rel)));
16055 	/* we leave refobjsubid unspecified */
16056 
16057 	scan = systable_beginscan(depRel, DependReferenceIndexId, true,
16058 							  NULL, 2, key);
16059 
16060 	while (HeapTupleIsValid(tup = systable_getnext(scan)))
16061 	{
16062 		Form_pg_depend depForm = (Form_pg_depend) GETSTRUCT(tup);
16063 		Relation	seqRel;
16064 
16065 		/* skip dependencies other than auto dependencies on columns */
16066 		if (depForm->refobjsubid == 0 ||
16067 			depForm->classid != RelationRelationId ||
16068 			depForm->objsubid != 0 ||
16069 			!(depForm->deptype == DEPENDENCY_AUTO || depForm->deptype == DEPENDENCY_INTERNAL))
16070 			continue;
16071 
16072 		/* Use relation_open just in case it's an index */
16073 		seqRel = relation_open(depForm->objid, lockmode);
16074 
16075 		/* skip non-sequence relations */
16076 		if (RelationGetForm(seqRel)->relkind != RELKIND_SEQUENCE)
16077 		{
16078 			/* No need to keep the lock */
16079 			relation_close(seqRel, lockmode);
16080 			continue;
16081 		}
16082 
16083 		/* Fix the pg_class and pg_depend entries */
16084 		AlterRelationNamespaceInternal(classRel, depForm->objid,
16085 									   oldNspOid, newNspOid,
16086 									   true, objsMoved);
16087 
16088 		/*
16089 		 * Sequences used to have entries in pg_type, but no longer do.  If we
16090 		 * ever re-instate that, we'll need to move the pg_type entry to the
16091 		 * new namespace, too (using AlterTypeNamespaceInternal).
16092 		 */
16093 		Assert(RelationGetForm(seqRel)->reltype == InvalidOid);
16094 
16095 		/* Now we can close it.  Keep the lock till end of transaction. */
16096 		relation_close(seqRel, NoLock);
16097 	}
16098 
16099 	systable_endscan(scan);
16100 
16101 	relation_close(depRel, AccessShareLock);
16102 }
16103 
16104 
16105 /*
16106  * This code supports
16107  *	CREATE TEMP TABLE ... ON COMMIT { DROP | PRESERVE ROWS | DELETE ROWS }
16108  *
16109  * Because we only support this for TEMP tables, it's sufficient to remember
16110  * the state in a backend-local data structure.
16111  */
16112 
16113 /*
16114  * Register a newly-created relation's ON COMMIT action.
16115  */
16116 void
register_on_commit_action(Oid relid,OnCommitAction action)16117 register_on_commit_action(Oid relid, OnCommitAction action)
16118 {
16119 	OnCommitItem *oc;
16120 	MemoryContext oldcxt;
16121 
16122 	/*
16123 	 * We needn't bother registering the relation unless there is an ON COMMIT
16124 	 * action we need to take.
16125 	 */
16126 	if (action == ONCOMMIT_NOOP || action == ONCOMMIT_PRESERVE_ROWS)
16127 		return;
16128 
16129 	oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
16130 
16131 	oc = (OnCommitItem *) palloc(sizeof(OnCommitItem));
16132 	oc->relid = relid;
16133 	oc->oncommit = action;
16134 	oc->creating_subid = GetCurrentSubTransactionId();
16135 	oc->deleting_subid = InvalidSubTransactionId;
16136 
16137 	/*
16138 	 * We use lcons() here so that ON COMMIT actions are processed in reverse
16139 	 * order of registration.  That might not be essential but it seems
16140 	 * reasonable.
16141 	 */
16142 	on_commits = lcons(oc, on_commits);
16143 
16144 	MemoryContextSwitchTo(oldcxt);
16145 }
16146 
16147 /*
16148  * Unregister any ON COMMIT action when a relation is deleted.
16149  *
16150  * Actually, we only mark the OnCommitItem entry as to be deleted after commit.
16151  */
16152 void
remove_on_commit_action(Oid relid)16153 remove_on_commit_action(Oid relid)
16154 {
16155 	ListCell   *l;
16156 
16157 	foreach(l, on_commits)
16158 	{
16159 		OnCommitItem *oc = (OnCommitItem *) lfirst(l);
16160 
16161 		if (oc->relid == relid)
16162 		{
16163 			oc->deleting_subid = GetCurrentSubTransactionId();
16164 			break;
16165 		}
16166 	}
16167 }
16168 
16169 /*
16170  * Perform ON COMMIT actions.
16171  *
16172  * This is invoked just before actually committing, since it's possible
16173  * to encounter errors.
16174  */
16175 void
PreCommit_on_commit_actions(void)16176 PreCommit_on_commit_actions(void)
16177 {
16178 	ListCell   *l;
16179 	List	   *oids_to_truncate = NIL;
16180 	List	   *oids_to_drop = NIL;
16181 
16182 	foreach(l, on_commits)
16183 	{
16184 		OnCommitItem *oc = (OnCommitItem *) lfirst(l);
16185 
16186 		/* Ignore entry if already dropped in this xact */
16187 		if (oc->deleting_subid != InvalidSubTransactionId)
16188 			continue;
16189 
16190 		switch (oc->oncommit)
16191 		{
16192 			case ONCOMMIT_NOOP:
16193 			case ONCOMMIT_PRESERVE_ROWS:
16194 				/* Do nothing (there shouldn't be such entries, actually) */
16195 				break;
16196 			case ONCOMMIT_DELETE_ROWS:
16197 
16198 				/*
16199 				 * If this transaction hasn't accessed any temporary
16200 				 * relations, we can skip truncating ON COMMIT DELETE ROWS
16201 				 * tables, as they must still be empty.
16202 				 */
16203 				if ((MyXactFlags & XACT_FLAGS_ACCESSEDTEMPNAMESPACE))
16204 					oids_to_truncate = lappend_oid(oids_to_truncate, oc->relid);
16205 				break;
16206 			case ONCOMMIT_DROP:
16207 				oids_to_drop = lappend_oid(oids_to_drop, oc->relid);
16208 				break;
16209 		}
16210 	}
16211 
16212 	/*
16213 	 * Truncate relations before dropping so that all dependencies between
16214 	 * relations are removed after they are worked on.  Doing it like this
16215 	 * might be a waste as it is possible that a relation being truncated will
16216 	 * be dropped anyway due to its parent being dropped, but this makes the
16217 	 * code more robust because of not having to re-check that the relation
16218 	 * exists at truncation time.
16219 	 */
16220 	if (oids_to_truncate != NIL)
16221 		heap_truncate(oids_to_truncate);
16222 
16223 	if (oids_to_drop != NIL)
16224 	{
16225 		ObjectAddresses *targetObjects = new_object_addresses();
16226 		ListCell   *l;
16227 
16228 		foreach(l, oids_to_drop)
16229 		{
16230 			ObjectAddress object;
16231 
16232 			object.classId = RelationRelationId;
16233 			object.objectId = lfirst_oid(l);
16234 			object.objectSubId = 0;
16235 
16236 			Assert(!object_address_present(&object, targetObjects));
16237 
16238 			add_exact_object_address(&object, targetObjects);
16239 		}
16240 
16241 		/*
16242 		 * Since this is an automatic drop, rather than one directly initiated
16243 		 * by the user, we pass the PERFORM_DELETION_INTERNAL flag.
16244 		 */
16245 		performMultipleDeletions(targetObjects, DROP_CASCADE,
16246 								 PERFORM_DELETION_INTERNAL | PERFORM_DELETION_QUIETLY);
16247 
16248 #ifdef USE_ASSERT_CHECKING
16249 
16250 		/*
16251 		 * Note that table deletion will call remove_on_commit_action, so the
16252 		 * entry should get marked as deleted.
16253 		 */
16254 		foreach(l, on_commits)
16255 		{
16256 			OnCommitItem *oc = (OnCommitItem *) lfirst(l);
16257 
16258 			if (oc->oncommit != ONCOMMIT_DROP)
16259 				continue;
16260 
16261 			Assert(oc->deleting_subid != InvalidSubTransactionId);
16262 		}
16263 #endif
16264 	}
16265 }
16266 
16267 /*
16268  * Post-commit or post-abort cleanup for ON COMMIT management.
16269  *
16270  * All we do here is remove no-longer-needed OnCommitItem entries.
16271  *
16272  * During commit, remove entries that were deleted during this transaction;
16273  * during abort, remove those created during this transaction.
16274  */
16275 void
AtEOXact_on_commit_actions(bool isCommit)16276 AtEOXact_on_commit_actions(bool isCommit)
16277 {
16278 	ListCell   *cur_item;
16279 
16280 	foreach(cur_item, on_commits)
16281 	{
16282 		OnCommitItem *oc = (OnCommitItem *) lfirst(cur_item);
16283 
16284 		if (isCommit ? oc->deleting_subid != InvalidSubTransactionId :
16285 			oc->creating_subid != InvalidSubTransactionId)
16286 		{
16287 			/* cur_item must be removed */
16288 			on_commits = foreach_delete_current(on_commits, cur_item);
16289 			pfree(oc);
16290 		}
16291 		else
16292 		{
16293 			/* cur_item must be preserved */
16294 			oc->creating_subid = InvalidSubTransactionId;
16295 			oc->deleting_subid = InvalidSubTransactionId;
16296 		}
16297 	}
16298 }
16299 
16300 /*
16301  * Post-subcommit or post-subabort cleanup for ON COMMIT management.
16302  *
16303  * During subabort, we can immediately remove entries created during this
16304  * subtransaction.  During subcommit, just relabel entries marked during
16305  * this subtransaction as being the parent's responsibility.
16306  */
16307 void
AtEOSubXact_on_commit_actions(bool isCommit,SubTransactionId mySubid,SubTransactionId parentSubid)16308 AtEOSubXact_on_commit_actions(bool isCommit, SubTransactionId mySubid,
16309 							  SubTransactionId parentSubid)
16310 {
16311 	ListCell   *cur_item;
16312 
16313 	foreach(cur_item, on_commits)
16314 	{
16315 		OnCommitItem *oc = (OnCommitItem *) lfirst(cur_item);
16316 
16317 		if (!isCommit && oc->creating_subid == mySubid)
16318 		{
16319 			/* cur_item must be removed */
16320 			on_commits = foreach_delete_current(on_commits, cur_item);
16321 			pfree(oc);
16322 		}
16323 		else
16324 		{
16325 			/* cur_item must be preserved */
16326 			if (oc->creating_subid == mySubid)
16327 				oc->creating_subid = parentSubid;
16328 			if (oc->deleting_subid == mySubid)
16329 				oc->deleting_subid = isCommit ? parentSubid : InvalidSubTransactionId;
16330 		}
16331 	}
16332 }
16333 
16334 /*
16335  * This is intended as a callback for RangeVarGetRelidExtended().  It allows
16336  * the relation to be locked only if (1) it's a plain table, materialized
16337  * view, or TOAST table and (2) the current user is the owner (or the
16338  * superuser).  This meets the permission-checking needs of CLUSTER, REINDEX
16339  * TABLE, and REFRESH MATERIALIZED VIEW; we expose it here so that it can be
16340  * used by all.
16341  */
16342 void
RangeVarCallbackOwnsTable(const RangeVar * relation,Oid relId,Oid oldRelId,void * arg)16343 RangeVarCallbackOwnsTable(const RangeVar *relation,
16344 						  Oid relId, Oid oldRelId, void *arg)
16345 {
16346 	char		relkind;
16347 
16348 	/* Nothing to do if the relation was not found. */
16349 	if (!OidIsValid(relId))
16350 		return;
16351 
16352 	/*
16353 	 * If the relation does exist, check whether it's an index.  But note that
16354 	 * the relation might have been dropped between the time we did the name
16355 	 * lookup and now.  In that case, there's nothing to do.
16356 	 */
16357 	relkind = get_rel_relkind(relId);
16358 	if (!relkind)
16359 		return;
16360 	if (relkind != RELKIND_RELATION && relkind != RELKIND_TOASTVALUE &&
16361 		relkind != RELKIND_MATVIEW && relkind != RELKIND_PARTITIONED_TABLE)
16362 		ereport(ERROR,
16363 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
16364 				 errmsg("\"%s\" is not a table or materialized view", relation->relname)));
16365 
16366 	/* Check permissions */
16367 	if (!pg_class_ownercheck(relId, GetUserId()))
16368 		aclcheck_error(ACLCHECK_NOT_OWNER, get_relkind_objtype(get_rel_relkind(relId)), relation->relname);
16369 }
16370 
16371 /*
16372  * Callback to RangeVarGetRelidExtended() for TRUNCATE processing.
16373  */
16374 static void
RangeVarCallbackForTruncate(const RangeVar * relation,Oid relId,Oid oldRelId,void * arg)16375 RangeVarCallbackForTruncate(const RangeVar *relation,
16376 							Oid relId, Oid oldRelId, void *arg)
16377 {
16378 	HeapTuple	tuple;
16379 
16380 	/* Nothing to do if the relation was not found. */
16381 	if (!OidIsValid(relId))
16382 		return;
16383 
16384 	tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relId));
16385 	if (!HeapTupleIsValid(tuple))	/* should not happen */
16386 		elog(ERROR, "cache lookup failed for relation %u", relId);
16387 
16388 	truncate_check_rel(relId, (Form_pg_class) GETSTRUCT(tuple));
16389 	truncate_check_perms(relId, (Form_pg_class) GETSTRUCT(tuple));
16390 
16391 	ReleaseSysCache(tuple);
16392 }
16393 
16394 /*
16395  * Callback to RangeVarGetRelidExtended(), similar to
16396  * RangeVarCallbackOwnsTable() but without checks on the type of the relation.
16397  */
16398 void
RangeVarCallbackOwnsRelation(const RangeVar * relation,Oid relId,Oid oldRelId,void * arg)16399 RangeVarCallbackOwnsRelation(const RangeVar *relation,
16400 							 Oid relId, Oid oldRelId, void *arg)
16401 {
16402 	HeapTuple	tuple;
16403 
16404 	/* Nothing to do if the relation was not found. */
16405 	if (!OidIsValid(relId))
16406 		return;
16407 
16408 	tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relId));
16409 	if (!HeapTupleIsValid(tuple))	/* should not happen */
16410 		elog(ERROR, "cache lookup failed for relation %u", relId);
16411 
16412 	if (!pg_class_ownercheck(relId, GetUserId()))
16413 		aclcheck_error(ACLCHECK_NOT_OWNER, get_relkind_objtype(get_rel_relkind(relId)),
16414 					   relation->relname);
16415 
16416 	if (!allowSystemTableMods &&
16417 		IsSystemClass(relId, (Form_pg_class) GETSTRUCT(tuple)))
16418 		ereport(ERROR,
16419 				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
16420 				 errmsg("permission denied: \"%s\" is a system catalog",
16421 						relation->relname)));
16422 
16423 	ReleaseSysCache(tuple);
16424 }
16425 
16426 /*
16427  * Common RangeVarGetRelid callback for rename, set schema, and alter table
16428  * processing.
16429  */
16430 static void
RangeVarCallbackForAlterRelation(const RangeVar * rv,Oid relid,Oid oldrelid,void * arg)16431 RangeVarCallbackForAlterRelation(const RangeVar *rv, Oid relid, Oid oldrelid,
16432 								 void *arg)
16433 {
16434 	Node	   *stmt = (Node *) arg;
16435 	ObjectType	reltype;
16436 	HeapTuple	tuple;
16437 	Form_pg_class classform;
16438 	AclResult	aclresult;
16439 	char		relkind;
16440 
16441 	tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
16442 	if (!HeapTupleIsValid(tuple))
16443 		return;					/* concurrently dropped */
16444 	classform = (Form_pg_class) GETSTRUCT(tuple);
16445 	relkind = classform->relkind;
16446 
16447 	/* Must own relation. */
16448 	if (!pg_class_ownercheck(relid, GetUserId()))
16449 		aclcheck_error(ACLCHECK_NOT_OWNER, get_relkind_objtype(get_rel_relkind(relid)), rv->relname);
16450 
16451 	/* No system table modifications unless explicitly allowed. */
16452 	if (!allowSystemTableMods && IsSystemClass(relid, classform))
16453 		ereport(ERROR,
16454 				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
16455 				 errmsg("permission denied: \"%s\" is a system catalog",
16456 						rv->relname)));
16457 
16458 	/*
16459 	 * Extract the specified relation type from the statement parse tree.
16460 	 *
16461 	 * Also, for ALTER .. RENAME, check permissions: the user must (still)
16462 	 * have CREATE rights on the containing namespace.
16463 	 */
16464 	if (IsA(stmt, RenameStmt))
16465 	{
16466 		aclresult = pg_namespace_aclcheck(classform->relnamespace,
16467 										  GetUserId(), ACL_CREATE);
16468 		if (aclresult != ACLCHECK_OK)
16469 			aclcheck_error(aclresult, OBJECT_SCHEMA,
16470 						   get_namespace_name(classform->relnamespace));
16471 		reltype = ((RenameStmt *) stmt)->renameType;
16472 	}
16473 	else if (IsA(stmt, AlterObjectSchemaStmt))
16474 		reltype = ((AlterObjectSchemaStmt *) stmt)->objectType;
16475 
16476 	else if (IsA(stmt, AlterTableStmt))
16477 		reltype = ((AlterTableStmt *) stmt)->objtype;
16478 	else
16479 	{
16480 		elog(ERROR, "unrecognized node type: %d", (int) nodeTag(stmt));
16481 		reltype = OBJECT_TABLE; /* placate compiler */
16482 	}
16483 
16484 	/*
16485 	 * For compatibility with prior releases, we allow ALTER TABLE to be used
16486 	 * with most other types of relations (but not composite types). We allow
16487 	 * similar flexibility for ALTER INDEX in the case of RENAME, but not
16488 	 * otherwise.  Otherwise, the user must select the correct form of the
16489 	 * command for the relation at issue.
16490 	 */
16491 	if (reltype == OBJECT_SEQUENCE && relkind != RELKIND_SEQUENCE)
16492 		ereport(ERROR,
16493 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
16494 				 errmsg("\"%s\" is not a sequence", rv->relname)));
16495 
16496 	if (reltype == OBJECT_VIEW && relkind != RELKIND_VIEW)
16497 		ereport(ERROR,
16498 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
16499 				 errmsg("\"%s\" is not a view", rv->relname)));
16500 
16501 	if (reltype == OBJECT_MATVIEW && relkind != RELKIND_MATVIEW)
16502 		ereport(ERROR,
16503 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
16504 				 errmsg("\"%s\" is not a materialized view", rv->relname)));
16505 
16506 	if (reltype == OBJECT_FOREIGN_TABLE && relkind != RELKIND_FOREIGN_TABLE)
16507 		ereport(ERROR,
16508 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
16509 				 errmsg("\"%s\" is not a foreign table", rv->relname)));
16510 
16511 	if (reltype == OBJECT_TYPE && relkind != RELKIND_COMPOSITE_TYPE)
16512 		ereport(ERROR,
16513 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
16514 				 errmsg("\"%s\" is not a composite type", rv->relname)));
16515 
16516 	if (reltype == OBJECT_INDEX && relkind != RELKIND_INDEX &&
16517 		relkind != RELKIND_PARTITIONED_INDEX
16518 		&& !IsA(stmt, RenameStmt))
16519 		ereport(ERROR,
16520 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
16521 				 errmsg("\"%s\" is not an index", rv->relname)));
16522 
16523 	/*
16524 	 * Don't allow ALTER TABLE on composite types. We want people to use ALTER
16525 	 * TYPE for that.
16526 	 */
16527 	if (reltype != OBJECT_TYPE && relkind == RELKIND_COMPOSITE_TYPE)
16528 		ereport(ERROR,
16529 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
16530 				 errmsg("\"%s\" is a composite type", rv->relname),
16531 				 errhint("Use ALTER TYPE instead.")));
16532 
16533 	/*
16534 	 * Don't allow ALTER TABLE .. SET SCHEMA on relations that can't be moved
16535 	 * to a different schema, such as indexes and TOAST tables.
16536 	 */
16537 	if (IsA(stmt, AlterObjectSchemaStmt) &&
16538 		relkind != RELKIND_RELATION &&
16539 		relkind != RELKIND_VIEW &&
16540 		relkind != RELKIND_MATVIEW &&
16541 		relkind != RELKIND_SEQUENCE &&
16542 		relkind != RELKIND_FOREIGN_TABLE &&
16543 		relkind != RELKIND_PARTITIONED_TABLE)
16544 		ereport(ERROR,
16545 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
16546 				 errmsg("\"%s\" is not a table, view, materialized view, sequence, or foreign table",
16547 						rv->relname)));
16548 
16549 	ReleaseSysCache(tuple);
16550 }
16551 
16552 /*
16553  * Transform any expressions present in the partition key
16554  *
16555  * Returns a transformed PartitionSpec, as well as the strategy code
16556  */
16557 static PartitionSpec *
transformPartitionSpec(Relation rel,PartitionSpec * partspec,char * strategy)16558 transformPartitionSpec(Relation rel, PartitionSpec *partspec, char *strategy)
16559 {
16560 	PartitionSpec *newspec;
16561 	ParseState *pstate;
16562 	ParseNamespaceItem *nsitem;
16563 	ListCell   *l;
16564 
16565 	newspec = makeNode(PartitionSpec);
16566 
16567 	newspec->strategy = partspec->strategy;
16568 	newspec->partParams = NIL;
16569 	newspec->location = partspec->location;
16570 
16571 	/* Parse partitioning strategy name */
16572 	if (pg_strcasecmp(partspec->strategy, "hash") == 0)
16573 		*strategy = PARTITION_STRATEGY_HASH;
16574 	else if (pg_strcasecmp(partspec->strategy, "list") == 0)
16575 		*strategy = PARTITION_STRATEGY_LIST;
16576 	else if (pg_strcasecmp(partspec->strategy, "range") == 0)
16577 		*strategy = PARTITION_STRATEGY_RANGE;
16578 	else
16579 		ereport(ERROR,
16580 				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
16581 				 errmsg("unrecognized partitioning strategy \"%s\"",
16582 						partspec->strategy)));
16583 
16584 	/* Check valid number of columns for strategy */
16585 	if (*strategy == PARTITION_STRATEGY_LIST &&
16586 		list_length(partspec->partParams) != 1)
16587 		ereport(ERROR,
16588 				(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
16589 				 errmsg("cannot use \"list\" partition strategy with more than one column")));
16590 
16591 	/*
16592 	 * Create a dummy ParseState and insert the target relation as its sole
16593 	 * rangetable entry.  We need a ParseState for transformExpr.
16594 	 */
16595 	pstate = make_parsestate(NULL);
16596 	nsitem = addRangeTableEntryForRelation(pstate, rel, AccessShareLock,
16597 										   NULL, false, true);
16598 	addNSItemToQuery(pstate, nsitem, true, true, true);
16599 
16600 	/* take care of any partition expressions */
16601 	foreach(l, partspec->partParams)
16602 	{
16603 		PartitionElem *pelem = castNode(PartitionElem, lfirst(l));
16604 
16605 		if (pelem->expr)
16606 		{
16607 			/* Copy, to avoid scribbling on the input */
16608 			pelem = copyObject(pelem);
16609 
16610 			/* Now do parse transformation of the expression */
16611 			pelem->expr = transformExpr(pstate, pelem->expr,
16612 										EXPR_KIND_PARTITION_EXPRESSION);
16613 
16614 			/* we have to fix its collations too */
16615 			assign_expr_collations(pstate, pelem->expr);
16616 		}
16617 
16618 		newspec->partParams = lappend(newspec->partParams, pelem);
16619 	}
16620 
16621 	return newspec;
16622 }
16623 
16624 /*
16625  * Compute per-partition-column information from a list of PartitionElems.
16626  * Expressions in the PartitionElems must be parse-analyzed already.
16627  */
16628 static void
ComputePartitionAttrs(ParseState * pstate,Relation rel,List * partParams,AttrNumber * partattrs,List ** partexprs,Oid * partopclass,Oid * partcollation,char strategy)16629 ComputePartitionAttrs(ParseState *pstate, Relation rel, List *partParams, AttrNumber *partattrs,
16630 					  List **partexprs, Oid *partopclass, Oid *partcollation,
16631 					  char strategy)
16632 {
16633 	int			attn;
16634 	ListCell   *lc;
16635 	Oid			am_oid;
16636 
16637 	attn = 0;
16638 	foreach(lc, partParams)
16639 	{
16640 		PartitionElem *pelem = castNode(PartitionElem, lfirst(lc));
16641 		Oid			atttype;
16642 		Oid			attcollation;
16643 
16644 		if (pelem->name != NULL)
16645 		{
16646 			/* Simple attribute reference */
16647 			HeapTuple	atttuple;
16648 			Form_pg_attribute attform;
16649 
16650 			atttuple = SearchSysCacheAttName(RelationGetRelid(rel),
16651 											 pelem->name);
16652 			if (!HeapTupleIsValid(atttuple))
16653 				ereport(ERROR,
16654 						(errcode(ERRCODE_UNDEFINED_COLUMN),
16655 						 errmsg("column \"%s\" named in partition key does not exist",
16656 								pelem->name),
16657 						 parser_errposition(pstate, pelem->location)));
16658 			attform = (Form_pg_attribute) GETSTRUCT(atttuple);
16659 
16660 			if (attform->attnum <= 0)
16661 				ereport(ERROR,
16662 						(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
16663 						 errmsg("cannot use system column \"%s\" in partition key",
16664 								pelem->name),
16665 						 parser_errposition(pstate, pelem->location)));
16666 
16667 			/*
16668 			 * Generated columns cannot work: They are computed after BEFORE
16669 			 * triggers, but partition routing is done before all triggers.
16670 			 */
16671 			if (attform->attgenerated)
16672 				ereport(ERROR,
16673 						(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
16674 						 errmsg("cannot use generated column in partition key"),
16675 						 errdetail("Column \"%s\" is a generated column.",
16676 								   pelem->name),
16677 						 parser_errposition(pstate, pelem->location)));
16678 
16679 			partattrs[attn] = attform->attnum;
16680 			atttype = attform->atttypid;
16681 			attcollation = attform->attcollation;
16682 			ReleaseSysCache(atttuple);
16683 		}
16684 		else
16685 		{
16686 			/* Expression */
16687 			Node	   *expr = pelem->expr;
16688 			char		partattname[16];
16689 
16690 			Assert(expr != NULL);
16691 			atttype = exprType(expr);
16692 			attcollation = exprCollation(expr);
16693 
16694 			/*
16695 			 * The expression must be of a storable type (e.g., not RECORD).
16696 			 * The test is the same as for whether a table column is of a safe
16697 			 * type (which is why we needn't check for the non-expression
16698 			 * case).
16699 			 */
16700 			snprintf(partattname, sizeof(partattname), "%d", attn + 1);
16701 			CheckAttributeType(partattname,
16702 							   atttype, attcollation,
16703 							   NIL, CHKATYPE_IS_PARTKEY);
16704 
16705 			/*
16706 			 * Strip any top-level COLLATE clause.  This ensures that we treat
16707 			 * "x COLLATE y" and "(x COLLATE y)" alike.
16708 			 */
16709 			while (IsA(expr, CollateExpr))
16710 				expr = (Node *) ((CollateExpr *) expr)->arg;
16711 
16712 			if (IsA(expr, Var) &&
16713 				((Var *) expr)->varattno > 0)
16714 			{
16715 				/*
16716 				 * User wrote "(column)" or "(column COLLATE something)".
16717 				 * Treat it like simple attribute anyway.
16718 				 */
16719 				partattrs[attn] = ((Var *) expr)->varattno;
16720 			}
16721 			else
16722 			{
16723 				Bitmapset  *expr_attrs = NULL;
16724 				int			i;
16725 
16726 				partattrs[attn] = 0;	/* marks the column as expression */
16727 				*partexprs = lappend(*partexprs, expr);
16728 
16729 				/*
16730 				 * Try to simplify the expression before checking for
16731 				 * mutability.  The main practical value of doing it in this
16732 				 * order is that an inline-able SQL-language function will be
16733 				 * accepted if its expansion is immutable, whether or not the
16734 				 * function itself is marked immutable.
16735 				 *
16736 				 * Note that expression_planner does not change the passed in
16737 				 * expression destructively and we have already saved the
16738 				 * expression to be stored into the catalog above.
16739 				 */
16740 				expr = (Node *) expression_planner((Expr *) expr);
16741 
16742 				/*
16743 				 * Partition expression cannot contain mutable functions,
16744 				 * because a given row must always map to the same partition
16745 				 * as long as there is no change in the partition boundary
16746 				 * structure.
16747 				 */
16748 				if (contain_mutable_functions(expr))
16749 					ereport(ERROR,
16750 							(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
16751 							 errmsg("functions in partition key expression must be marked IMMUTABLE")));
16752 
16753 				/*
16754 				 * transformPartitionSpec() should have already rejected
16755 				 * subqueries, aggregates, window functions, and SRFs, based
16756 				 * on the EXPR_KIND_ for partition expressions.
16757 				 */
16758 
16759 				/*
16760 				 * Cannot allow system column references, since that would
16761 				 * make partition routing impossible: their values won't be
16762 				 * known yet when we need to do that.
16763 				 */
16764 				pull_varattnos(expr, 1, &expr_attrs);
16765 				for (i = FirstLowInvalidHeapAttributeNumber; i < 0; i++)
16766 				{
16767 					if (bms_is_member(i - FirstLowInvalidHeapAttributeNumber,
16768 									  expr_attrs))
16769 						ereport(ERROR,
16770 								(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
16771 								 errmsg("partition key expressions cannot contain system column references")));
16772 				}
16773 
16774 				/*
16775 				 * Generated columns cannot work: They are computed after
16776 				 * BEFORE triggers, but partition routing is done before all
16777 				 * triggers.
16778 				 */
16779 				i = -1;
16780 				while ((i = bms_next_member(expr_attrs, i)) >= 0)
16781 				{
16782 					AttrNumber	attno = i + FirstLowInvalidHeapAttributeNumber;
16783 
16784 					if (attno > 0 &&
16785 						TupleDescAttr(RelationGetDescr(rel), attno - 1)->attgenerated)
16786 						ereport(ERROR,
16787 								(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
16788 								 errmsg("cannot use generated column in partition key"),
16789 								 errdetail("Column \"%s\" is a generated column.",
16790 										   get_attname(RelationGetRelid(rel), attno, false)),
16791 								 parser_errposition(pstate, pelem->location)));
16792 				}
16793 
16794 				/*
16795 				 * While it is not exactly *wrong* for a partition expression
16796 				 * to be a constant, it seems better to reject such keys.
16797 				 */
16798 				if (IsA(expr, Const))
16799 					ereport(ERROR,
16800 							(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
16801 							 errmsg("cannot use constant expression as partition key")));
16802 			}
16803 		}
16804 
16805 		/*
16806 		 * Apply collation override if any
16807 		 */
16808 		if (pelem->collation)
16809 			attcollation = get_collation_oid(pelem->collation, false);
16810 
16811 		/*
16812 		 * Check we have a collation iff it's a collatable type.  The only
16813 		 * expected failures here are (1) COLLATE applied to a noncollatable
16814 		 * type, or (2) partition expression had an unresolved collation. But
16815 		 * we might as well code this to be a complete consistency check.
16816 		 */
16817 		if (type_is_collatable(atttype))
16818 		{
16819 			if (!OidIsValid(attcollation))
16820 				ereport(ERROR,
16821 						(errcode(ERRCODE_INDETERMINATE_COLLATION),
16822 						 errmsg("could not determine which collation to use for partition expression"),
16823 						 errhint("Use the COLLATE clause to set the collation explicitly.")));
16824 		}
16825 		else
16826 		{
16827 			if (OidIsValid(attcollation))
16828 				ereport(ERROR,
16829 						(errcode(ERRCODE_DATATYPE_MISMATCH),
16830 						 errmsg("collations are not supported by type %s",
16831 								format_type_be(atttype))));
16832 		}
16833 
16834 		partcollation[attn] = attcollation;
16835 
16836 		/*
16837 		 * Identify the appropriate operator class.  For list and range
16838 		 * partitioning, we use a btree operator class; hash partitioning uses
16839 		 * a hash operator class.
16840 		 */
16841 		if (strategy == PARTITION_STRATEGY_HASH)
16842 			am_oid = HASH_AM_OID;
16843 		else
16844 			am_oid = BTREE_AM_OID;
16845 
16846 		if (!pelem->opclass)
16847 		{
16848 			partopclass[attn] = GetDefaultOpClass(atttype, am_oid);
16849 
16850 			if (!OidIsValid(partopclass[attn]))
16851 			{
16852 				if (strategy == PARTITION_STRATEGY_HASH)
16853 					ereport(ERROR,
16854 							(errcode(ERRCODE_UNDEFINED_OBJECT),
16855 							 errmsg("data type %s has no default operator class for access method \"%s\"",
16856 									format_type_be(atttype), "hash"),
16857 							 errhint("You must specify a hash operator class or define a default hash operator class for the data type.")));
16858 				else
16859 					ereport(ERROR,
16860 							(errcode(ERRCODE_UNDEFINED_OBJECT),
16861 							 errmsg("data type %s has no default operator class for access method \"%s\"",
16862 									format_type_be(atttype), "btree"),
16863 							 errhint("You must specify a btree operator class or define a default btree operator class for the data type.")));
16864 
16865 			}
16866 		}
16867 		else
16868 			partopclass[attn] = ResolveOpClass(pelem->opclass,
16869 											   atttype,
16870 											   am_oid == HASH_AM_OID ? "hash" : "btree",
16871 											   am_oid);
16872 
16873 		attn++;
16874 	}
16875 }
16876 
16877 /*
16878  * PartConstraintImpliedByRelConstraint
16879  *		Do scanrel's existing constraints imply the partition constraint?
16880  *
16881  * "Existing constraints" include its check constraints and column-level
16882  * NOT NULL constraints.  partConstraint describes the partition constraint,
16883  * in implicit-AND form.
16884  */
16885 bool
PartConstraintImpliedByRelConstraint(Relation scanrel,List * partConstraint)16886 PartConstraintImpliedByRelConstraint(Relation scanrel,
16887 									 List *partConstraint)
16888 {
16889 	List	   *existConstraint = NIL;
16890 	TupleConstr *constr = RelationGetDescr(scanrel)->constr;
16891 	int			i;
16892 
16893 	if (constr && constr->has_not_null)
16894 	{
16895 		int			natts = scanrel->rd_att->natts;
16896 
16897 		for (i = 1; i <= natts; i++)
16898 		{
16899 			Form_pg_attribute att = TupleDescAttr(scanrel->rd_att, i - 1);
16900 
16901 			if (att->attnotnull && !att->attisdropped)
16902 			{
16903 				NullTest   *ntest = makeNode(NullTest);
16904 
16905 				ntest->arg = (Expr *) makeVar(1,
16906 											  i,
16907 											  att->atttypid,
16908 											  att->atttypmod,
16909 											  att->attcollation,
16910 											  0);
16911 				ntest->nulltesttype = IS_NOT_NULL;
16912 
16913 				/*
16914 				 * argisrow=false is correct even for a composite column,
16915 				 * because attnotnull does not represent a SQL-spec IS NOT
16916 				 * NULL test in such a case, just IS DISTINCT FROM NULL.
16917 				 */
16918 				ntest->argisrow = false;
16919 				ntest->location = -1;
16920 				existConstraint = lappend(existConstraint, ntest);
16921 			}
16922 		}
16923 	}
16924 
16925 	return ConstraintImpliedByRelConstraint(scanrel, partConstraint, existConstraint);
16926 }
16927 
16928 /*
16929  * ConstraintImpliedByRelConstraint
16930  *		Do scanrel's existing constraints imply the given constraint?
16931  *
16932  * testConstraint is the constraint to validate. provenConstraint is a
16933  * caller-provided list of conditions which this function may assume
16934  * to be true. Both provenConstraint and testConstraint must be in
16935  * implicit-AND form, must only contain immutable clauses, and must
16936  * contain only Vars with varno = 1.
16937  */
16938 bool
ConstraintImpliedByRelConstraint(Relation scanrel,List * testConstraint,List * provenConstraint)16939 ConstraintImpliedByRelConstraint(Relation scanrel, List *testConstraint, List *provenConstraint)
16940 {
16941 	List	   *existConstraint = list_copy(provenConstraint);
16942 	TupleConstr *constr = RelationGetDescr(scanrel)->constr;
16943 	int			num_check,
16944 				i;
16945 
16946 	num_check = (constr != NULL) ? constr->num_check : 0;
16947 	for (i = 0; i < num_check; i++)
16948 	{
16949 		Node	   *cexpr;
16950 
16951 		/*
16952 		 * If this constraint hasn't been fully validated yet, we must ignore
16953 		 * it here.
16954 		 */
16955 		if (!constr->check[i].ccvalid)
16956 			continue;
16957 
16958 		cexpr = stringToNode(constr->check[i].ccbin);
16959 
16960 		/*
16961 		 * Run each expression through const-simplification and
16962 		 * canonicalization.  It is necessary, because we will be comparing it
16963 		 * to similarly-processed partition constraint expressions, and may
16964 		 * fail to detect valid matches without this.
16965 		 */
16966 		cexpr = eval_const_expressions(NULL, cexpr);
16967 		cexpr = (Node *) canonicalize_qual((Expr *) cexpr, true);
16968 
16969 		existConstraint = list_concat(existConstraint,
16970 									  make_ands_implicit((Expr *) cexpr));
16971 	}
16972 
16973 	/*
16974 	 * Try to make the proof.  Since we are comparing CHECK constraints, we
16975 	 * need to use weak implication, i.e., we assume existConstraint is
16976 	 * not-false and try to prove the same for testConstraint.
16977 	 *
16978 	 * Note that predicate_implied_by assumes its first argument is known
16979 	 * immutable.  That should always be true for both NOT NULL and partition
16980 	 * constraints, so we don't test it here.
16981 	 */
16982 	return predicate_implied_by(testConstraint, existConstraint, true);
16983 }
16984 
16985 /*
16986  * QueuePartitionConstraintValidation
16987  *
16988  * Add an entry to wqueue to have the given partition constraint validated by
16989  * Phase 3, for the given relation, and all its children.
16990  *
16991  * We first verify whether the given constraint is implied by pre-existing
16992  * relation constraints; if it is, there's no need to scan the table to
16993  * validate, so don't queue in that case.
16994  */
16995 static void
QueuePartitionConstraintValidation(List ** wqueue,Relation scanrel,List * partConstraint,bool validate_default)16996 QueuePartitionConstraintValidation(List **wqueue, Relation scanrel,
16997 								   List *partConstraint,
16998 								   bool validate_default)
16999 {
17000 	/*
17001 	 * Based on the table's existing constraints, determine whether or not we
17002 	 * may skip scanning the table.
17003 	 */
17004 	if (PartConstraintImpliedByRelConstraint(scanrel, partConstraint))
17005 	{
17006 		if (!validate_default)
17007 			ereport(DEBUG1,
17008 					(errmsg_internal("partition constraint for table \"%s\" is implied by existing constraints",
17009 									 RelationGetRelationName(scanrel))));
17010 		else
17011 			ereport(DEBUG1,
17012 					(errmsg_internal("updated partition constraint for default partition \"%s\" is implied by existing constraints",
17013 									 RelationGetRelationName(scanrel))));
17014 		return;
17015 	}
17016 
17017 	/*
17018 	 * Constraints proved insufficient. For plain relations, queue a
17019 	 * validation item now; for partitioned tables, recurse to process each
17020 	 * partition.
17021 	 */
17022 	if (scanrel->rd_rel->relkind == RELKIND_RELATION)
17023 	{
17024 		AlteredTableInfo *tab;
17025 
17026 		/* Grab a work queue entry. */
17027 		tab = ATGetQueueEntry(wqueue, scanrel);
17028 		Assert(tab->partition_constraint == NULL);
17029 		tab->partition_constraint = (Expr *) linitial(partConstraint);
17030 		tab->validate_default = validate_default;
17031 	}
17032 	else if (scanrel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
17033 	{
17034 		PartitionDesc partdesc = RelationGetPartitionDesc(scanrel, true);
17035 		int			i;
17036 
17037 		for (i = 0; i < partdesc->nparts; i++)
17038 		{
17039 			Relation	part_rel;
17040 			List	   *thisPartConstraint;
17041 
17042 			/*
17043 			 * This is the minimum lock we need to prevent deadlocks.
17044 			 */
17045 			part_rel = table_open(partdesc->oids[i], AccessExclusiveLock);
17046 
17047 			/*
17048 			 * Adjust the constraint for scanrel so that it matches this
17049 			 * partition's attribute numbers.
17050 			 */
17051 			thisPartConstraint =
17052 				map_partition_varattnos(partConstraint, 1,
17053 										part_rel, scanrel);
17054 
17055 			QueuePartitionConstraintValidation(wqueue, part_rel,
17056 											   thisPartConstraint,
17057 											   validate_default);
17058 			table_close(part_rel, NoLock);	/* keep lock till commit */
17059 		}
17060 	}
17061 }
17062 
17063 /*
17064  * ALTER TABLE <name> ATTACH PARTITION <partition-name> FOR VALUES
17065  *
17066  * Return the address of the newly attached partition.
17067  */
17068 static ObjectAddress
ATExecAttachPartition(List ** wqueue,Relation rel,PartitionCmd * cmd,AlterTableUtilityContext * context)17069 ATExecAttachPartition(List **wqueue, Relation rel, PartitionCmd *cmd,
17070 					  AlterTableUtilityContext *context)
17071 {
17072 	Relation	attachrel,
17073 				catalog;
17074 	List	   *attachrel_children;
17075 	List	   *partConstraint;
17076 	SysScanDesc scan;
17077 	ScanKeyData skey;
17078 	AttrNumber	attno;
17079 	int			natts;
17080 	TupleDesc	tupleDesc;
17081 	ObjectAddress address;
17082 	const char *trigger_name;
17083 	Oid			defaultPartOid;
17084 	List	   *partBoundConstraint;
17085 	ParseState *pstate = make_parsestate(NULL);
17086 
17087 	pstate->p_sourcetext = context->queryString;
17088 
17089 	/*
17090 	 * We must lock the default partition if one exists, because attaching a
17091 	 * new partition will change its partition constraint.
17092 	 */
17093 	defaultPartOid =
17094 		get_default_oid_from_partdesc(RelationGetPartitionDesc(rel, true));
17095 	if (OidIsValid(defaultPartOid))
17096 		LockRelationOid(defaultPartOid, AccessExclusiveLock);
17097 
17098 	attachrel = table_openrv(cmd->name, AccessExclusiveLock);
17099 
17100 	/*
17101 	 * XXX I think it'd be a good idea to grab locks on all tables referenced
17102 	 * by FKs at this point also.
17103 	 */
17104 
17105 	/*
17106 	 * Must be owner of both parent and source table -- parent was checked by
17107 	 * ATSimplePermissions call in ATPrepCmd
17108 	 */
17109 	ATSimplePermissions(attachrel, ATT_TABLE | ATT_FOREIGN_TABLE);
17110 
17111 	/* A partition can only have one parent */
17112 	if (attachrel->rd_rel->relispartition)
17113 		ereport(ERROR,
17114 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
17115 				 errmsg("\"%s\" is already a partition",
17116 						RelationGetRelationName(attachrel))));
17117 
17118 	if (OidIsValid(attachrel->rd_rel->reloftype))
17119 		ereport(ERROR,
17120 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
17121 				 errmsg("cannot attach a typed table as partition")));
17122 
17123 	/*
17124 	 * Table being attached should not already be part of inheritance; either
17125 	 * as a child table...
17126 	 */
17127 	catalog = table_open(InheritsRelationId, AccessShareLock);
17128 	ScanKeyInit(&skey,
17129 				Anum_pg_inherits_inhrelid,
17130 				BTEqualStrategyNumber, F_OIDEQ,
17131 				ObjectIdGetDatum(RelationGetRelid(attachrel)));
17132 	scan = systable_beginscan(catalog, InheritsRelidSeqnoIndexId, true,
17133 							  NULL, 1, &skey);
17134 	if (HeapTupleIsValid(systable_getnext(scan)))
17135 		ereport(ERROR,
17136 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
17137 				 errmsg("cannot attach inheritance child as partition")));
17138 	systable_endscan(scan);
17139 
17140 	/* ...or as a parent table (except the case when it is partitioned) */
17141 	ScanKeyInit(&skey,
17142 				Anum_pg_inherits_inhparent,
17143 				BTEqualStrategyNumber, F_OIDEQ,
17144 				ObjectIdGetDatum(RelationGetRelid(attachrel)));
17145 	scan = systable_beginscan(catalog, InheritsParentIndexId, true, NULL,
17146 							  1, &skey);
17147 	if (HeapTupleIsValid(systable_getnext(scan)) &&
17148 		attachrel->rd_rel->relkind == RELKIND_RELATION)
17149 		ereport(ERROR,
17150 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
17151 				 errmsg("cannot attach inheritance parent as partition")));
17152 	systable_endscan(scan);
17153 	table_close(catalog, AccessShareLock);
17154 
17155 	/*
17156 	 * Prevent circularity by seeing if rel is a partition of attachrel. (In
17157 	 * particular, this disallows making a rel a partition of itself.)
17158 	 *
17159 	 * We do that by checking if rel is a member of the list of attachrel's
17160 	 * partitions provided the latter is partitioned at all.  We want to avoid
17161 	 * having to construct this list again, so we request the strongest lock
17162 	 * on all partitions.  We need the strongest lock, because we may decide
17163 	 * to scan them if we find out that the table being attached (or its leaf
17164 	 * partitions) may contain rows that violate the partition constraint. If
17165 	 * the table has a constraint that would prevent such rows, which by
17166 	 * definition is present in all the partitions, we need not scan the
17167 	 * table, nor its partitions.  But we cannot risk a deadlock by taking a
17168 	 * weaker lock now and the stronger one only when needed.
17169 	 */
17170 	attachrel_children = find_all_inheritors(RelationGetRelid(attachrel),
17171 											 AccessExclusiveLock, NULL);
17172 	if (list_member_oid(attachrel_children, RelationGetRelid(rel)))
17173 		ereport(ERROR,
17174 				(errcode(ERRCODE_DUPLICATE_TABLE),
17175 				 errmsg("circular inheritance not allowed"),
17176 				 errdetail("\"%s\" is already a child of \"%s\".",
17177 						   RelationGetRelationName(rel),
17178 						   RelationGetRelationName(attachrel))));
17179 
17180 	/* If the parent is permanent, so must be all of its partitions. */
17181 	if (rel->rd_rel->relpersistence != RELPERSISTENCE_TEMP &&
17182 		attachrel->rd_rel->relpersistence == RELPERSISTENCE_TEMP)
17183 		ereport(ERROR,
17184 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
17185 				 errmsg("cannot attach a temporary relation as partition of permanent relation \"%s\"",
17186 						RelationGetRelationName(rel))));
17187 
17188 	/* Temp parent cannot have a partition that is itself not a temp */
17189 	if (rel->rd_rel->relpersistence == RELPERSISTENCE_TEMP &&
17190 		attachrel->rd_rel->relpersistence != RELPERSISTENCE_TEMP)
17191 		ereport(ERROR,
17192 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
17193 				 errmsg("cannot attach a permanent relation as partition of temporary relation \"%s\"",
17194 						RelationGetRelationName(rel))));
17195 
17196 	/* If the parent is temp, it must belong to this session */
17197 	if (rel->rd_rel->relpersistence == RELPERSISTENCE_TEMP &&
17198 		!rel->rd_islocaltemp)
17199 		ereport(ERROR,
17200 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
17201 				 errmsg("cannot attach as partition of temporary relation of another session")));
17202 
17203 	/* Ditto for the partition */
17204 	if (attachrel->rd_rel->relpersistence == RELPERSISTENCE_TEMP &&
17205 		!attachrel->rd_islocaltemp)
17206 		ereport(ERROR,
17207 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
17208 				 errmsg("cannot attach temporary relation of another session as partition")));
17209 
17210 	/* Check if there are any columns in attachrel that aren't in the parent */
17211 	tupleDesc = RelationGetDescr(attachrel);
17212 	natts = tupleDesc->natts;
17213 	for (attno = 1; attno <= natts; attno++)
17214 	{
17215 		Form_pg_attribute attribute = TupleDescAttr(tupleDesc, attno - 1);
17216 		char	   *attributeName = NameStr(attribute->attname);
17217 
17218 		/* Ignore dropped */
17219 		if (attribute->attisdropped)
17220 			continue;
17221 
17222 		/* Try to find the column in parent (matching on column name) */
17223 		if (!SearchSysCacheExists2(ATTNAME,
17224 								   ObjectIdGetDatum(RelationGetRelid(rel)),
17225 								   CStringGetDatum(attributeName)))
17226 			ereport(ERROR,
17227 					(errcode(ERRCODE_DATATYPE_MISMATCH),
17228 					 errmsg("table \"%s\" contains column \"%s\" not found in parent \"%s\"",
17229 							RelationGetRelationName(attachrel), attributeName,
17230 							RelationGetRelationName(rel)),
17231 					 errdetail("The new partition may contain only the columns present in parent.")));
17232 	}
17233 
17234 	/*
17235 	 * If child_rel has row-level triggers with transition tables, we
17236 	 * currently don't allow it to become a partition.  See also prohibitions
17237 	 * in ATExecAddInherit() and CreateTrigger().
17238 	 */
17239 	trigger_name = FindTriggerIncompatibleWithInheritance(attachrel->trigdesc);
17240 	if (trigger_name != NULL)
17241 		ereport(ERROR,
17242 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
17243 				 errmsg("trigger \"%s\" prevents table \"%s\" from becoming a partition",
17244 						trigger_name, RelationGetRelationName(attachrel)),
17245 				 errdetail("ROW triggers with transition tables are not supported on partitions")));
17246 
17247 	/*
17248 	 * Check that the new partition's bound is valid and does not overlap any
17249 	 * of existing partitions of the parent - note that it does not return on
17250 	 * error.
17251 	 */
17252 	check_new_partition_bound(RelationGetRelationName(attachrel), rel,
17253 							  cmd->bound, pstate);
17254 
17255 	/* OK to create inheritance.  Rest of the checks performed there */
17256 	CreateInheritance(attachrel, rel);
17257 
17258 	/* Update the pg_class entry. */
17259 	StorePartitionBound(attachrel, rel, cmd->bound);
17260 
17261 	/* Ensure there exists a correct set of indexes in the partition. */
17262 	AttachPartitionEnsureIndexes(rel, attachrel);
17263 
17264 	/* and triggers */
17265 	CloneRowTriggersToPartition(rel, attachrel);
17266 
17267 	/*
17268 	 * Clone foreign key constraints.  Callee is responsible for setting up
17269 	 * for phase 3 constraint verification.
17270 	 */
17271 	CloneForeignKeyConstraints(wqueue, rel, attachrel);
17272 
17273 	/*
17274 	 * Generate partition constraint from the partition bound specification.
17275 	 * If the parent itself is a partition, make sure to include its
17276 	 * constraint as well.
17277 	 */
17278 	partBoundConstraint = get_qual_from_partbound(attachrel, rel, cmd->bound);
17279 	partConstraint = list_concat(partBoundConstraint,
17280 								 RelationGetPartitionQual(rel));
17281 
17282 	/* Skip validation if there are no constraints to validate. */
17283 	if (partConstraint)
17284 	{
17285 		/*
17286 		 * Run the partition quals through const-simplification similar to
17287 		 * check constraints.  We skip canonicalize_qual, though, because
17288 		 * partition quals should be in canonical form already.
17289 		 */
17290 		partConstraint =
17291 			(List *) eval_const_expressions(NULL,
17292 											(Node *) partConstraint);
17293 
17294 		/* XXX this sure looks wrong */
17295 		partConstraint = list_make1(make_ands_explicit(partConstraint));
17296 
17297 		/*
17298 		 * Adjust the generated constraint to match this partition's attribute
17299 		 * numbers.
17300 		 */
17301 		partConstraint = map_partition_varattnos(partConstraint, 1, attachrel,
17302 												 rel);
17303 
17304 		/* Validate partition constraints against the table being attached. */
17305 		QueuePartitionConstraintValidation(wqueue, attachrel, partConstraint,
17306 										   false);
17307 	}
17308 
17309 	/*
17310 	 * If we're attaching a partition other than the default partition and a
17311 	 * default one exists, then that partition's partition constraint changes,
17312 	 * so add an entry to the work queue to validate it, too.  (We must not do
17313 	 * this when the partition being attached is the default one; we already
17314 	 * did it above!)
17315 	 */
17316 	if (OidIsValid(defaultPartOid))
17317 	{
17318 		Relation	defaultrel;
17319 		List	   *defPartConstraint;
17320 
17321 		Assert(!cmd->bound->is_default);
17322 
17323 		/* we already hold a lock on the default partition */
17324 		defaultrel = table_open(defaultPartOid, NoLock);
17325 		defPartConstraint =
17326 			get_proposed_default_constraint(partBoundConstraint);
17327 
17328 		/*
17329 		 * Map the Vars in the constraint expression from rel's attnos to
17330 		 * defaultrel's.
17331 		 */
17332 		defPartConstraint =
17333 			map_partition_varattnos(defPartConstraint,
17334 									1, defaultrel, rel);
17335 		QueuePartitionConstraintValidation(wqueue, defaultrel,
17336 										   defPartConstraint, true);
17337 
17338 		/* keep our lock until commit. */
17339 		table_close(defaultrel, NoLock);
17340 	}
17341 
17342 	ObjectAddressSet(address, RelationRelationId, RelationGetRelid(attachrel));
17343 
17344 	/*
17345 	 * If the partition we just attached is partitioned itself, invalidate
17346 	 * relcache for all descendent partitions too to ensure that their
17347 	 * rd_partcheck expression trees are rebuilt; partitions already locked
17348 	 * at the beginning of this function.
17349 	 */
17350 	if (attachrel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
17351 	{
17352 		ListCell *l;
17353 
17354 		foreach(l, attachrel_children)
17355 		{
17356 			CacheInvalidateRelcacheByRelid(lfirst_oid(l));
17357 		}
17358 	}
17359 
17360 	/* keep our lock until commit */
17361 	table_close(attachrel, NoLock);
17362 
17363 	return address;
17364 }
17365 
17366 /*
17367  * AttachPartitionEnsureIndexes
17368  *		subroutine for ATExecAttachPartition to create/match indexes
17369  *
17370  * Enforce the indexing rule for partitioned tables during ALTER TABLE / ATTACH
17371  * PARTITION: every partition must have an index attached to each index on the
17372  * partitioned table.
17373  */
17374 static void
AttachPartitionEnsureIndexes(Relation rel,Relation attachrel)17375 AttachPartitionEnsureIndexes(Relation rel, Relation attachrel)
17376 {
17377 	List	   *idxes;
17378 	List	   *attachRelIdxs;
17379 	Relation   *attachrelIdxRels;
17380 	IndexInfo **attachInfos;
17381 	int			i;
17382 	ListCell   *cell;
17383 	MemoryContext cxt;
17384 	MemoryContext oldcxt;
17385 
17386 	cxt = AllocSetContextCreate(CurrentMemoryContext,
17387 								"AttachPartitionEnsureIndexes",
17388 								ALLOCSET_DEFAULT_SIZES);
17389 	oldcxt = MemoryContextSwitchTo(cxt);
17390 
17391 	idxes = RelationGetIndexList(rel);
17392 	attachRelIdxs = RelationGetIndexList(attachrel);
17393 	attachrelIdxRels = palloc(sizeof(Relation) * list_length(attachRelIdxs));
17394 	attachInfos = palloc(sizeof(IndexInfo *) * list_length(attachRelIdxs));
17395 
17396 	/* Build arrays of all existing indexes and their IndexInfos */
17397 	i = 0;
17398 	foreach(cell, attachRelIdxs)
17399 	{
17400 		Oid			cldIdxId = lfirst_oid(cell);
17401 
17402 		attachrelIdxRels[i] = index_open(cldIdxId, AccessShareLock);
17403 		attachInfos[i] = BuildIndexInfo(attachrelIdxRels[i]);
17404 		i++;
17405 	}
17406 
17407 	/*
17408 	 * If we're attaching a foreign table, we must fail if any of the indexes
17409 	 * is a constraint index; otherwise, there's nothing to do here.  Do this
17410 	 * before starting work, to avoid wasting the effort of building a few
17411 	 * non-unique indexes before coming across a unique one.
17412 	 */
17413 	if (attachrel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
17414 	{
17415 		foreach(cell, idxes)
17416 		{
17417 			Oid			idx = lfirst_oid(cell);
17418 			Relation	idxRel = index_open(idx, AccessShareLock);
17419 
17420 			if (idxRel->rd_index->indisunique ||
17421 				idxRel->rd_index->indisprimary)
17422 				ereport(ERROR,
17423 						(errcode(ERRCODE_WRONG_OBJECT_TYPE),
17424 						 errmsg("cannot attach foreign table \"%s\" as partition of partitioned table \"%s\"",
17425 								RelationGetRelationName(attachrel),
17426 								RelationGetRelationName(rel)),
17427 						 errdetail("Partitioned table \"%s\" contains unique indexes.",
17428 								   RelationGetRelationName(rel))));
17429 			index_close(idxRel, AccessShareLock);
17430 		}
17431 
17432 		goto out;
17433 	}
17434 
17435 	/*
17436 	 * For each index on the partitioned table, find a matching one in the
17437 	 * partition-to-be; if one is not found, create one.
17438 	 */
17439 	foreach(cell, idxes)
17440 	{
17441 		Oid			idx = lfirst_oid(cell);
17442 		Relation	idxRel = index_open(idx, AccessShareLock);
17443 		IndexInfo  *info;
17444 		AttrMap    *attmap;
17445 		bool		found = false;
17446 		Oid			constraintOid;
17447 
17448 		/*
17449 		 * Ignore indexes in the partitioned table other than partitioned
17450 		 * indexes.
17451 		 */
17452 		if (idxRel->rd_rel->relkind != RELKIND_PARTITIONED_INDEX)
17453 		{
17454 			index_close(idxRel, AccessShareLock);
17455 			continue;
17456 		}
17457 
17458 		/* construct an indexinfo to compare existing indexes against */
17459 		info = BuildIndexInfo(idxRel);
17460 		attmap = build_attrmap_by_name(RelationGetDescr(attachrel),
17461 									   RelationGetDescr(rel));
17462 		constraintOid = get_relation_idx_constraint_oid(RelationGetRelid(rel), idx);
17463 
17464 		/*
17465 		 * Scan the list of existing indexes in the partition-to-be, and mark
17466 		 * the first matching, unattached one we find, if any, as partition of
17467 		 * the parent index.  If we find one, we're done.
17468 		 */
17469 		for (i = 0; i < list_length(attachRelIdxs); i++)
17470 		{
17471 			Oid			cldIdxId = RelationGetRelid(attachrelIdxRels[i]);
17472 			Oid			cldConstrOid = InvalidOid;
17473 
17474 			/* does this index have a parent?  if so, can't use it */
17475 			if (attachrelIdxRels[i]->rd_rel->relispartition)
17476 				continue;
17477 
17478 			if (CompareIndexInfo(attachInfos[i], info,
17479 								 attachrelIdxRels[i]->rd_indcollation,
17480 								 idxRel->rd_indcollation,
17481 								 attachrelIdxRels[i]->rd_opfamily,
17482 								 idxRel->rd_opfamily,
17483 								 attmap))
17484 			{
17485 				/*
17486 				 * If this index is being created in the parent because of a
17487 				 * constraint, then the child needs to have a constraint also,
17488 				 * so look for one.  If there is no such constraint, this
17489 				 * index is no good, so keep looking.
17490 				 */
17491 				if (OidIsValid(constraintOid))
17492 				{
17493 					cldConstrOid =
17494 						get_relation_idx_constraint_oid(RelationGetRelid(attachrel),
17495 														cldIdxId);
17496 					/* no dice */
17497 					if (!OidIsValid(cldConstrOid))
17498 						continue;
17499 				}
17500 
17501 				/* bingo. */
17502 				IndexSetParentIndex(attachrelIdxRels[i], idx);
17503 				if (OidIsValid(constraintOid))
17504 					ConstraintSetParentConstraint(cldConstrOid, constraintOid,
17505 												  RelationGetRelid(attachrel));
17506 				found = true;
17507 
17508 				CommandCounterIncrement();
17509 				break;
17510 			}
17511 		}
17512 
17513 		/*
17514 		 * If no suitable index was found in the partition-to-be, create one
17515 		 * now.
17516 		 */
17517 		if (!found)
17518 		{
17519 			IndexStmt  *stmt;
17520 			Oid			constraintOid;
17521 
17522 			stmt = generateClonedIndexStmt(NULL,
17523 										   idxRel, attmap,
17524 										   &constraintOid);
17525 			DefineIndex(RelationGetRelid(attachrel), stmt, InvalidOid,
17526 						RelationGetRelid(idxRel),
17527 						constraintOid,
17528 						true, false, false, false, false);
17529 		}
17530 
17531 		index_close(idxRel, AccessShareLock);
17532 	}
17533 
17534 out:
17535 	/* Clean up. */
17536 	for (i = 0; i < list_length(attachRelIdxs); i++)
17537 		index_close(attachrelIdxRels[i], AccessShareLock);
17538 	MemoryContextSwitchTo(oldcxt);
17539 	MemoryContextDelete(cxt);
17540 }
17541 
17542 /*
17543  * CloneRowTriggersToPartition
17544  *		subroutine for ATExecAttachPartition/DefineRelation to create row
17545  *		triggers on partitions
17546  */
17547 static void
CloneRowTriggersToPartition(Relation parent,Relation partition)17548 CloneRowTriggersToPartition(Relation parent, Relation partition)
17549 {
17550 	Relation	pg_trigger;
17551 	ScanKeyData key;
17552 	SysScanDesc scan;
17553 	HeapTuple	tuple;
17554 	MemoryContext perTupCxt;
17555 
17556 	ScanKeyInit(&key, Anum_pg_trigger_tgrelid, BTEqualStrategyNumber,
17557 				F_OIDEQ, ObjectIdGetDatum(RelationGetRelid(parent)));
17558 	pg_trigger = table_open(TriggerRelationId, RowExclusiveLock);
17559 	scan = systable_beginscan(pg_trigger, TriggerRelidNameIndexId,
17560 							  true, NULL, 1, &key);
17561 
17562 	perTupCxt = AllocSetContextCreate(CurrentMemoryContext,
17563 									  "clone trig", ALLOCSET_SMALL_SIZES);
17564 
17565 	while (HeapTupleIsValid(tuple = systable_getnext(scan)))
17566 	{
17567 		Form_pg_trigger trigForm = (Form_pg_trigger) GETSTRUCT(tuple);
17568 		CreateTrigStmt *trigStmt;
17569 		Node	   *qual = NULL;
17570 		Datum		value;
17571 		bool		isnull;
17572 		List	   *cols = NIL;
17573 		List	   *trigargs = NIL;
17574 		MemoryContext oldcxt;
17575 
17576 		/*
17577 		 * Ignore statement-level triggers; those are not cloned.
17578 		 */
17579 		if (!TRIGGER_FOR_ROW(trigForm->tgtype))
17580 			continue;
17581 
17582 		/*
17583 		 * Internal triggers require careful examination.  Ideally, we don't
17584 		 * clone them.  However, if our parent is itself a partition, there
17585 		 * might be internal triggers that must not be skipped; for example,
17586 		 * triggers on our parent that are in turn clones from its parent (our
17587 		 * grandparent) are marked internal, yet they are to be cloned.
17588 		 *
17589 		 * Note we dare not verify that the other trigger belongs to an
17590 		 * ancestor relation of our parent, because that creates deadlock
17591 		 * opportunities.
17592 		 */
17593 		if (trigForm->tgisinternal &&
17594 			(!parent->rd_rel->relispartition ||
17595 			 !OidIsValid(trigForm->tgparentid)))
17596 			continue;
17597 
17598 		/*
17599 		 * Complain if we find an unexpected trigger type.
17600 		 */
17601 		if (!TRIGGER_FOR_BEFORE(trigForm->tgtype) &&
17602 			!TRIGGER_FOR_AFTER(trigForm->tgtype))
17603 			elog(ERROR, "unexpected trigger \"%s\" found",
17604 				 NameStr(trigForm->tgname));
17605 
17606 		/* Use short-lived context for CREATE TRIGGER */
17607 		oldcxt = MemoryContextSwitchTo(perTupCxt);
17608 
17609 		/*
17610 		 * If there is a WHEN clause, generate a 'cooked' version of it that's
17611 		 * appropriate for the partition.
17612 		 */
17613 		value = heap_getattr(tuple, Anum_pg_trigger_tgqual,
17614 							 RelationGetDescr(pg_trigger), &isnull);
17615 		if (!isnull)
17616 		{
17617 			qual = stringToNode(TextDatumGetCString(value));
17618 			qual = (Node *) map_partition_varattnos((List *) qual, PRS2_OLD_VARNO,
17619 													partition, parent);
17620 			qual = (Node *) map_partition_varattnos((List *) qual, PRS2_NEW_VARNO,
17621 													partition, parent);
17622 		}
17623 
17624 		/*
17625 		 * If there is a column list, transform it to a list of column names.
17626 		 * Note we don't need to map this list in any way ...
17627 		 */
17628 		if (trigForm->tgattr.dim1 > 0)
17629 		{
17630 			int			i;
17631 
17632 			for (i = 0; i < trigForm->tgattr.dim1; i++)
17633 			{
17634 				Form_pg_attribute col;
17635 
17636 				col = TupleDescAttr(parent->rd_att,
17637 									trigForm->tgattr.values[i] - 1);
17638 				cols = lappend(cols,
17639 							   makeString(pstrdup(NameStr(col->attname))));
17640 			}
17641 		}
17642 
17643 		/* Reconstruct trigger arguments list. */
17644 		if (trigForm->tgnargs > 0)
17645 		{
17646 			char	   *p;
17647 
17648 			value = heap_getattr(tuple, Anum_pg_trigger_tgargs,
17649 								 RelationGetDescr(pg_trigger), &isnull);
17650 			if (isnull)
17651 				elog(ERROR, "tgargs is null for trigger \"%s\" in partition \"%s\"",
17652 					 NameStr(trigForm->tgname), RelationGetRelationName(partition));
17653 
17654 			p = (char *) VARDATA_ANY(DatumGetByteaPP(value));
17655 
17656 			for (int i = 0; i < trigForm->tgnargs; i++)
17657 			{
17658 				trigargs = lappend(trigargs, makeString(pstrdup(p)));
17659 				p += strlen(p) + 1;
17660 			}
17661 		}
17662 
17663 		trigStmt = makeNode(CreateTrigStmt);
17664 		trigStmt->replace = false;
17665 		trigStmt->isconstraint = OidIsValid(trigForm->tgconstraint);
17666 		trigStmt->trigname = NameStr(trigForm->tgname);
17667 		trigStmt->relation = NULL;
17668 		trigStmt->funcname = NULL;	/* passed separately */
17669 		trigStmt->args = trigargs;
17670 		trigStmt->row = true;
17671 		trigStmt->timing = trigForm->tgtype & TRIGGER_TYPE_TIMING_MASK;
17672 		trigStmt->events = trigForm->tgtype & TRIGGER_TYPE_EVENT_MASK;
17673 		trigStmt->columns = cols;
17674 		trigStmt->whenClause = NULL;	/* passed separately */
17675 		trigStmt->transitionRels = NIL; /* not supported at present */
17676 		trigStmt->deferrable = trigForm->tgdeferrable;
17677 		trigStmt->initdeferred = trigForm->tginitdeferred;
17678 		trigStmt->constrrel = NULL; /* passed separately */
17679 
17680 		CreateTriggerFiringOn(trigStmt, NULL, RelationGetRelid(partition),
17681 							  trigForm->tgconstrrelid, InvalidOid, InvalidOid,
17682 							  trigForm->tgfoid, trigForm->oid, qual,
17683 							  false, true, trigForm->tgenabled);
17684 
17685 		MemoryContextSwitchTo(oldcxt);
17686 		MemoryContextReset(perTupCxt);
17687 	}
17688 
17689 	MemoryContextDelete(perTupCxt);
17690 
17691 	systable_endscan(scan);
17692 	table_close(pg_trigger, RowExclusiveLock);
17693 }
17694 
17695 /*
17696  * ALTER TABLE DETACH PARTITION
17697  *
17698  * Return the address of the relation that is no longer a partition of rel.
17699  *
17700  * If concurrent mode is requested, we run in two transactions.  A side-
17701  * effect is that this command cannot run in a multi-part ALTER TABLE.
17702  * Currently, that's enforced by the grammar.
17703  *
17704  * The strategy for concurrency is to first modify the partition's
17705  * pg_inherit catalog row to make it visible to everyone that the
17706  * partition is detached, lock the partition against writes, and commit
17707  * the transaction; anyone who requests the partition descriptor from
17708  * that point onwards has to ignore such a partition.  In a second
17709  * transaction, we wait until all transactions that could have seen the
17710  * partition as attached are gone, then we remove the rest of partition
17711  * metadata (pg_inherits and pg_class.relpartbounds).
17712  */
17713 static ObjectAddress
ATExecDetachPartition(List ** wqueue,AlteredTableInfo * tab,Relation rel,RangeVar * name,bool concurrent)17714 ATExecDetachPartition(List **wqueue, AlteredTableInfo *tab, Relation rel,
17715 					  RangeVar *name, bool concurrent)
17716 {
17717 	Relation	partRel;
17718 	ObjectAddress address;
17719 	Oid			defaultPartOid;
17720 
17721 	/*
17722 	 * We must lock the default partition, because detaching this partition
17723 	 * will change its partition constraint.
17724 	 */
17725 	defaultPartOid =
17726 		get_default_oid_from_partdesc(RelationGetPartitionDesc(rel, true));
17727 	if (OidIsValid(defaultPartOid))
17728 	{
17729 		/*
17730 		 * Concurrent detaching when a default partition exists is not
17731 		 * supported. The main problem is that the default partition
17732 		 * constraint would change.  And there's a definitional problem: what
17733 		 * should happen to the tuples that are being inserted that belong to
17734 		 * the partition being detached?  Putting them on the partition being
17735 		 * detached would be wrong, since they'd become "lost" after the but
17736 		 * we cannot put them in the default partition either until we alter
17737 		 * its partition constraint.
17738 		 *
17739 		 * I think we could solve this problem if we effected the constraint
17740 		 * change before committing the first transaction.  But the lock would
17741 		 * have to remain AEL and it would cause concurrent query planning to
17742 		 * be blocked, so changing it that way would be even worse.
17743 		 */
17744 		if (concurrent)
17745 			ereport(ERROR,
17746 					(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
17747 					 errmsg("cannot detach partitions concurrently when a default partition exists")));
17748 		LockRelationOid(defaultPartOid, AccessExclusiveLock);
17749 	}
17750 
17751 	/*
17752 	 * In concurrent mode, the partition is locked with share-update-exclusive
17753 	 * in the first transaction.  This allows concurrent transactions to be
17754 	 * doing DML to the partition.
17755 	 */
17756 	partRel = table_openrv(name, concurrent ? ShareUpdateExclusiveLock :
17757 						   AccessExclusiveLock);
17758 
17759 	/*
17760 	 * Check inheritance conditions and either delete the pg_inherits row (in
17761 	 * non-concurrent mode) or just set the inhdetachpending flag.
17762 	 */
17763 	if (!concurrent)
17764 		RemoveInheritance(partRel, rel, false);
17765 	else
17766 		MarkInheritDetached(partRel, rel);
17767 
17768 	/*
17769 	 * Ensure that foreign keys still hold after this detach.  This keeps
17770 	 * locks on the referencing tables, which prevents concurrent transactions
17771 	 * from adding rows that we wouldn't see.  For this to work in concurrent
17772 	 * mode, it is critical that the partition appears as no longer attached
17773 	 * for the RI queries as soon as the first transaction commits.
17774 	 */
17775 	ATDetachCheckNoForeignKeyRefs(partRel);
17776 
17777 	/*
17778 	 * Concurrent mode has to work harder; first we add a new constraint to
17779 	 * the partition that matches the partition constraint.  Then we close our
17780 	 * existing transaction, and in a new one wait for all processes to catch
17781 	 * up on the catalog updates we've done so far; at that point we can
17782 	 * complete the operation.
17783 	 */
17784 	if (concurrent)
17785 	{
17786 		Oid			partrelid,
17787 					parentrelid;
17788 		LOCKTAG		tag;
17789 		char	   *parentrelname;
17790 		char	   *partrelname;
17791 
17792 		/*
17793 		 * Add a new constraint to the partition being detached, which
17794 		 * supplants the partition constraint (unless there is one already).
17795 		 */
17796 		DetachAddConstraintIfNeeded(wqueue, partRel);
17797 
17798 		/*
17799 		 * We're almost done now; the only traces that remain are the
17800 		 * pg_inherits tuple and the partition's relpartbounds.  Before we can
17801 		 * remove those, we need to wait until all transactions that know that
17802 		 * this is a partition are gone.
17803 		 */
17804 
17805 		/*
17806 		 * Remember relation OIDs to re-acquire them later; and relation names
17807 		 * too, for error messages if something is dropped in between.
17808 		 */
17809 		partrelid = RelationGetRelid(partRel);
17810 		parentrelid = RelationGetRelid(rel);
17811 		parentrelname = MemoryContextStrdup(PortalContext,
17812 											RelationGetRelationName(rel));
17813 		partrelname = MemoryContextStrdup(PortalContext,
17814 										  RelationGetRelationName(partRel));
17815 
17816 		/* Invalidate relcache entries for the parent -- must be before close */
17817 		CacheInvalidateRelcache(rel);
17818 
17819 		table_close(partRel, NoLock);
17820 		table_close(rel, NoLock);
17821 		tab->rel = NULL;
17822 
17823 		/* Make updated catalog entry visible */
17824 		PopActiveSnapshot();
17825 		CommitTransactionCommand();
17826 
17827 		StartTransactionCommand();
17828 
17829 		/*
17830 		 * Now wait.  This ensures that all queries that were planned
17831 		 * including the partition are finished before we remove the rest of
17832 		 * catalog entries.  We don't need or indeed want to acquire this
17833 		 * lock, though -- that would block later queries.
17834 		 *
17835 		 * We don't need to concern ourselves with waiting for a lock on the
17836 		 * partition itself, since we will acquire AccessExclusiveLock below.
17837 		 */
17838 		SET_LOCKTAG_RELATION(tag, MyDatabaseId, parentrelid);
17839 		WaitForLockersMultiple(list_make1(&tag), AccessExclusiveLock, false);
17840 
17841 		/*
17842 		 * Now acquire locks in both relations again.  Note they may have been
17843 		 * removed in the meantime, so care is required.
17844 		 */
17845 		rel = try_relation_open(parentrelid, ShareUpdateExclusiveLock);
17846 		partRel = try_relation_open(partrelid, AccessExclusiveLock);
17847 
17848 		/* If the relations aren't there, something bad happened; bail out */
17849 		if (rel == NULL)
17850 		{
17851 			if (partRel != NULL)	/* shouldn't happen */
17852 				elog(WARNING, "dangling partition \"%s\" remains, can't fix",
17853 					 partrelname);
17854 			ereport(ERROR,
17855 					(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
17856 					 errmsg("partitioned table \"%s\" was removed concurrently",
17857 							parentrelname)));
17858 		}
17859 		if (partRel == NULL)
17860 			ereport(ERROR,
17861 					(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
17862 					 errmsg("partition \"%s\" was removed concurrently", partrelname)));
17863 
17864 		tab->rel = rel;
17865 	}
17866 
17867 	/* Do the final part of detaching */
17868 	DetachPartitionFinalize(rel, partRel, concurrent, defaultPartOid);
17869 
17870 	ObjectAddressSet(address, RelationRelationId, RelationGetRelid(partRel));
17871 
17872 	/* keep our lock until commit */
17873 	table_close(partRel, NoLock);
17874 
17875 	return address;
17876 }
17877 
17878 /*
17879  * Second part of ALTER TABLE .. DETACH.
17880  *
17881  * This is separate so that it can be run independently when the second
17882  * transaction of the concurrent algorithm fails (crash or abort).
17883  */
17884 static void
DetachPartitionFinalize(Relation rel,Relation partRel,bool concurrent,Oid defaultPartOid)17885 DetachPartitionFinalize(Relation rel, Relation partRel, bool concurrent,
17886 						Oid defaultPartOid)
17887 {
17888 	Relation	classRel;
17889 	List	   *fks;
17890 	ListCell   *cell;
17891 	List	   *indexes;
17892 	Datum		new_val[Natts_pg_class];
17893 	bool		new_null[Natts_pg_class],
17894 				new_repl[Natts_pg_class];
17895 	HeapTuple	tuple,
17896 				newtuple;
17897 
17898 	if (concurrent)
17899 	{
17900 		/*
17901 		 * We can remove the pg_inherits row now. (In the non-concurrent case,
17902 		 * this was already done).
17903 		 */
17904 		RemoveInheritance(partRel, rel, true);
17905 	}
17906 
17907 	/* Drop any triggers that were cloned on creation/attach. */
17908 	DropClonedTriggersFromPartition(RelationGetRelid(partRel));
17909 
17910 	/*
17911 	 * Detach any foreign keys that are inherited.  This includes creating
17912 	 * additional action triggers.
17913 	 */
17914 	fks = copyObject(RelationGetFKeyList(partRel));
17915 	foreach(cell, fks)
17916 	{
17917 		ForeignKeyCacheInfo *fk = lfirst(cell);
17918 		HeapTuple	contup;
17919 		Form_pg_constraint conform;
17920 		Constraint *fkconstraint;
17921 
17922 		contup = SearchSysCache1(CONSTROID, ObjectIdGetDatum(fk->conoid));
17923 		if (!HeapTupleIsValid(contup))
17924 			elog(ERROR, "cache lookup failed for constraint %u", fk->conoid);
17925 		conform = (Form_pg_constraint) GETSTRUCT(contup);
17926 
17927 		/* consider only the inherited foreign keys */
17928 		if (conform->contype != CONSTRAINT_FOREIGN ||
17929 			!OidIsValid(conform->conparentid))
17930 		{
17931 			ReleaseSysCache(contup);
17932 			continue;
17933 		}
17934 
17935 		/* unset conparentid and adjust conislocal, coninhcount, etc. */
17936 		ConstraintSetParentConstraint(fk->conoid, InvalidOid, InvalidOid);
17937 
17938 		/*
17939 		 * Make the action triggers on the referenced relation.  When this was
17940 		 * a partition the action triggers pointed to the parent rel (they
17941 		 * still do), but now we need separate ones of our own.
17942 		 */
17943 		fkconstraint = makeNode(Constraint);
17944 		fkconstraint->conname = pstrdup(NameStr(conform->conname));
17945 		fkconstraint->fk_upd_action = conform->confupdtype;
17946 		fkconstraint->fk_del_action = conform->confdeltype;
17947 		fkconstraint->deferrable = conform->condeferrable;
17948 		fkconstraint->initdeferred = conform->condeferred;
17949 
17950 		createForeignKeyActionTriggers(partRel, conform->confrelid,
17951 									   fkconstraint, fk->conoid,
17952 									   conform->conindid);
17953 
17954 		ReleaseSysCache(contup);
17955 	}
17956 	list_free_deep(fks);
17957 
17958 	/*
17959 	 * Any sub-constraints that are in the referenced-side of a larger
17960 	 * constraint have to be removed.  This partition is no longer part of the
17961 	 * key space of the constraint.
17962 	 */
17963 	foreach(cell, GetParentedForeignKeyRefs(partRel))
17964 	{
17965 		Oid			constrOid = lfirst_oid(cell);
17966 		ObjectAddress constraint;
17967 
17968 		ConstraintSetParentConstraint(constrOid, InvalidOid, InvalidOid);
17969 		deleteDependencyRecordsForClass(ConstraintRelationId,
17970 										constrOid,
17971 										ConstraintRelationId,
17972 										DEPENDENCY_INTERNAL);
17973 		CommandCounterIncrement();
17974 
17975 		ObjectAddressSet(constraint, ConstraintRelationId, constrOid);
17976 		performDeletion(&constraint, DROP_RESTRICT, 0);
17977 	}
17978 
17979 	/* Now we can detach indexes */
17980 	indexes = RelationGetIndexList(partRel);
17981 	foreach(cell, indexes)
17982 	{
17983 		Oid			idxid = lfirst_oid(cell);
17984 		Relation	idx;
17985 		Oid			constrOid;
17986 
17987 		if (!has_superclass(idxid))
17988 			continue;
17989 
17990 		Assert((IndexGetRelation(get_partition_parent(idxid, false), false) ==
17991 				RelationGetRelid(rel)));
17992 
17993 		idx = index_open(idxid, AccessExclusiveLock);
17994 		IndexSetParentIndex(idx, InvalidOid);
17995 
17996 		/* If there's a constraint associated with the index, detach it too */
17997 		constrOid = get_relation_idx_constraint_oid(RelationGetRelid(partRel),
17998 													idxid);
17999 		if (OidIsValid(constrOid))
18000 			ConstraintSetParentConstraint(constrOid, InvalidOid, InvalidOid);
18001 
18002 		index_close(idx, NoLock);
18003 	}
18004 
18005 	/* Update pg_class tuple */
18006 	classRel = table_open(RelationRelationId, RowExclusiveLock);
18007 	tuple = SearchSysCacheCopy1(RELOID,
18008 								ObjectIdGetDatum(RelationGetRelid(partRel)));
18009 	if (!HeapTupleIsValid(tuple))
18010 		elog(ERROR, "cache lookup failed for relation %u",
18011 			 RelationGetRelid(partRel));
18012 	Assert(((Form_pg_class) GETSTRUCT(tuple))->relispartition);
18013 
18014 	/* Clear relpartbound and reset relispartition */
18015 	memset(new_val, 0, sizeof(new_val));
18016 	memset(new_null, false, sizeof(new_null));
18017 	memset(new_repl, false, sizeof(new_repl));
18018 	new_val[Anum_pg_class_relpartbound - 1] = (Datum) 0;
18019 	new_null[Anum_pg_class_relpartbound - 1] = true;
18020 	new_repl[Anum_pg_class_relpartbound - 1] = true;
18021 	newtuple = heap_modify_tuple(tuple, RelationGetDescr(classRel),
18022 								 new_val, new_null, new_repl);
18023 
18024 	((Form_pg_class) GETSTRUCT(newtuple))->relispartition = false;
18025 	CatalogTupleUpdate(classRel, &newtuple->t_self, newtuple);
18026 	heap_freetuple(newtuple);
18027 	table_close(classRel, RowExclusiveLock);
18028 
18029 	if (OidIsValid(defaultPartOid))
18030 	{
18031 		/*
18032 		 * If the relation being detached is the default partition itself,
18033 		 * remove it from the parent's pg_partitioned_table entry.
18034 		 *
18035 		 * If not, we must invalidate default partition's relcache entry, as
18036 		 * in StorePartitionBound: its partition constraint depends on every
18037 		 * other partition's partition constraint.
18038 		 */
18039 		if (RelationGetRelid(partRel) == defaultPartOid)
18040 			update_default_partition_oid(RelationGetRelid(rel), InvalidOid);
18041 		else
18042 			CacheInvalidateRelcacheByRelid(defaultPartOid);
18043 	}
18044 
18045 	/*
18046 	 * Invalidate the parent's relcache so that the partition is no longer
18047 	 * included in its partition descriptor.
18048 	 */
18049 	CacheInvalidateRelcache(rel);
18050 
18051 	/*
18052 	 * If the partition we just detached is partitioned itself, invalidate
18053 	 * relcache for all descendent partitions too to ensure that their
18054 	 * rd_partcheck expression trees are rebuilt; must lock partitions
18055 	 * before doing so, using the same lockmode as what partRel has been
18056 	 * locked with by the caller.
18057 	 */
18058 	if (partRel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
18059 	{
18060 		List   *children;
18061 
18062 		children = find_all_inheritors(RelationGetRelid(partRel),
18063 									   AccessExclusiveLock, NULL);
18064 		foreach(cell, children)
18065 		{
18066 			CacheInvalidateRelcacheByRelid(lfirst_oid(cell));
18067 		}
18068 	}
18069 }
18070 
18071 /*
18072  * ALTER TABLE ... DETACH PARTITION ... FINALIZE
18073  *
18074  * To use when a DETACH PARTITION command previously did not run to
18075  * completion; this completes the detaching process.
18076  */
18077 static ObjectAddress
ATExecDetachPartitionFinalize(Relation rel,RangeVar * name)18078 ATExecDetachPartitionFinalize(Relation rel, RangeVar *name)
18079 {
18080 	Relation	partRel;
18081 	ObjectAddress address;
18082 	Snapshot	snap = GetActiveSnapshot();
18083 
18084 	partRel = table_openrv(name, AccessExclusiveLock);
18085 
18086 	/*
18087 	 * Wait until existing snapshots are gone.  This is important if the
18088 	 * second transaction of DETACH PARTITION CONCURRENTLY is canceled: the
18089 	 * user could immediately run DETACH FINALIZE without actually waiting for
18090 	 * existing transactions.  We must not complete the detach action until
18091 	 * all such queries are complete (otherwise we would present them with an
18092 	 * inconsistent view of catalogs).
18093 	 */
18094 	WaitForOlderSnapshots(snap->xmin, false);
18095 
18096 	DetachPartitionFinalize(rel, partRel, true, InvalidOid);
18097 
18098 	ObjectAddressSet(address, RelationRelationId, RelationGetRelid(partRel));
18099 
18100 	table_close(partRel, NoLock);
18101 
18102 	return address;
18103 }
18104 
18105 /*
18106  * DetachAddConstraintIfNeeded
18107  *		Subroutine for ATExecDetachPartition.  Create a constraint that
18108  *		takes the place of the partition constraint, but avoid creating
18109  *		a dupe if an constraint already exists which implies the needed
18110  *		constraint.
18111  */
18112 static void
DetachAddConstraintIfNeeded(List ** wqueue,Relation partRel)18113 DetachAddConstraintIfNeeded(List **wqueue, Relation partRel)
18114 {
18115 	List	   *constraintExpr;
18116 
18117 	constraintExpr = RelationGetPartitionQual(partRel);
18118 	constraintExpr = (List *) eval_const_expressions(NULL, (Node *) constraintExpr);
18119 
18120 	/*
18121 	 * Avoid adding a new constraint if the needed constraint is implied by an
18122 	 * existing constraint
18123 	 */
18124 	if (!PartConstraintImpliedByRelConstraint(partRel, constraintExpr))
18125 	{
18126 		AlteredTableInfo *tab;
18127 		Constraint *n;
18128 
18129 		tab = ATGetQueueEntry(wqueue, partRel);
18130 
18131 		/* Add constraint on partition, equivalent to the partition constraint */
18132 		n = makeNode(Constraint);
18133 		n->contype = CONSTR_CHECK;
18134 		n->conname = NULL;
18135 		n->location = -1;
18136 		n->is_no_inherit = false;
18137 		n->raw_expr = NULL;
18138 		n->cooked_expr = nodeToString(make_ands_explicit(constraintExpr));
18139 		n->initially_valid = true;
18140 		n->skip_validation = true;
18141 		/* It's a re-add, since it nominally already exists */
18142 		ATAddCheckConstraint(wqueue, tab, partRel, n,
18143 							 true, false, true, ShareUpdateExclusiveLock);
18144 	}
18145 }
18146 
18147 /*
18148  * DropClonedTriggersFromPartition
18149  *		subroutine for ATExecDetachPartition to remove any triggers that were
18150  *		cloned to the partition when it was created-as-partition or attached.
18151  *		This undoes what CloneRowTriggersToPartition did.
18152  */
18153 static void
DropClonedTriggersFromPartition(Oid partitionId)18154 DropClonedTriggersFromPartition(Oid partitionId)
18155 {
18156 	ScanKeyData skey;
18157 	SysScanDesc scan;
18158 	HeapTuple	trigtup;
18159 	Relation	tgrel;
18160 	ObjectAddresses *objects;
18161 
18162 	objects = new_object_addresses();
18163 
18164 	/*
18165 	 * Scan pg_trigger to search for all triggers on this rel.
18166 	 */
18167 	ScanKeyInit(&skey, Anum_pg_trigger_tgrelid, BTEqualStrategyNumber,
18168 				F_OIDEQ, ObjectIdGetDatum(partitionId));
18169 	tgrel = table_open(TriggerRelationId, RowExclusiveLock);
18170 	scan = systable_beginscan(tgrel, TriggerRelidNameIndexId,
18171 							  true, NULL, 1, &skey);
18172 	while (HeapTupleIsValid(trigtup = systable_getnext(scan)))
18173 	{
18174 		Form_pg_trigger pg_trigger = (Form_pg_trigger) GETSTRUCT(trigtup);
18175 		ObjectAddress trig;
18176 
18177 		/* Ignore triggers that weren't cloned */
18178 		if (!OidIsValid(pg_trigger->tgparentid))
18179 			continue;
18180 
18181 		/*
18182 		 * This is ugly, but necessary: remove the dependency markings on the
18183 		 * trigger so that it can be removed.
18184 		 */
18185 		deleteDependencyRecordsForClass(TriggerRelationId, pg_trigger->oid,
18186 										TriggerRelationId,
18187 										DEPENDENCY_PARTITION_PRI);
18188 		deleteDependencyRecordsForClass(TriggerRelationId, pg_trigger->oid,
18189 										RelationRelationId,
18190 										DEPENDENCY_PARTITION_SEC);
18191 
18192 		/* remember this trigger to remove it below */
18193 		ObjectAddressSet(trig, TriggerRelationId, pg_trigger->oid);
18194 		add_exact_object_address(&trig, objects);
18195 	}
18196 
18197 	/* make the dependency removal visible to the deletion below */
18198 	CommandCounterIncrement();
18199 	performMultipleDeletions(objects, DROP_RESTRICT, PERFORM_DELETION_INTERNAL);
18200 
18201 	/* done */
18202 	free_object_addresses(objects);
18203 	systable_endscan(scan);
18204 	table_close(tgrel, RowExclusiveLock);
18205 }
18206 
18207 /*
18208  * Before acquiring lock on an index, acquire the same lock on the owning
18209  * table.
18210  */
18211 struct AttachIndexCallbackState
18212 {
18213 	Oid			partitionOid;
18214 	Oid			parentTblOid;
18215 	bool		lockedParentTbl;
18216 };
18217 
18218 static void
RangeVarCallbackForAttachIndex(const RangeVar * rv,Oid relOid,Oid oldRelOid,void * arg)18219 RangeVarCallbackForAttachIndex(const RangeVar *rv, Oid relOid, Oid oldRelOid,
18220 							   void *arg)
18221 {
18222 	struct AttachIndexCallbackState *state;
18223 	Form_pg_class classform;
18224 	HeapTuple	tuple;
18225 
18226 	state = (struct AttachIndexCallbackState *) arg;
18227 
18228 	if (!state->lockedParentTbl)
18229 	{
18230 		LockRelationOid(state->parentTblOid, AccessShareLock);
18231 		state->lockedParentTbl = true;
18232 	}
18233 
18234 	/*
18235 	 * If we previously locked some other heap, and the name we're looking up
18236 	 * no longer refers to an index on that relation, release the now-useless
18237 	 * lock.  XXX maybe we should do *after* we verify whether the index does
18238 	 * not actually belong to the same relation ...
18239 	 */
18240 	if (relOid != oldRelOid && OidIsValid(state->partitionOid))
18241 	{
18242 		UnlockRelationOid(state->partitionOid, AccessShareLock);
18243 		state->partitionOid = InvalidOid;
18244 	}
18245 
18246 	/* Didn't find a relation, so no need for locking or permission checks. */
18247 	if (!OidIsValid(relOid))
18248 		return;
18249 
18250 	tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relOid));
18251 	if (!HeapTupleIsValid(tuple))
18252 		return;					/* concurrently dropped, so nothing to do */
18253 	classform = (Form_pg_class) GETSTRUCT(tuple);
18254 	if (classform->relkind != RELKIND_PARTITIONED_INDEX &&
18255 		classform->relkind != RELKIND_INDEX)
18256 		ereport(ERROR,
18257 				(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
18258 				 errmsg("\"%s\" is not an index", rv->relname)));
18259 	ReleaseSysCache(tuple);
18260 
18261 	/*
18262 	 * Since we need only examine the heap's tupledesc, an access share lock
18263 	 * on it (preventing any DDL) is sufficient.
18264 	 */
18265 	state->partitionOid = IndexGetRelation(relOid, false);
18266 	LockRelationOid(state->partitionOid, AccessShareLock);
18267 }
18268 
18269 /*
18270  * ALTER INDEX i1 ATTACH PARTITION i2
18271  */
18272 static ObjectAddress
ATExecAttachPartitionIdx(List ** wqueue,Relation parentIdx,RangeVar * name)18273 ATExecAttachPartitionIdx(List **wqueue, Relation parentIdx, RangeVar *name)
18274 {
18275 	Relation	partIdx;
18276 	Relation	partTbl;
18277 	Relation	parentTbl;
18278 	ObjectAddress address;
18279 	Oid			partIdxId;
18280 	Oid			currParent;
18281 	struct AttachIndexCallbackState state;
18282 
18283 	/*
18284 	 * We need to obtain lock on the index 'name' to modify it, but we also
18285 	 * need to read its owning table's tuple descriptor -- so we need to lock
18286 	 * both.  To avoid deadlocks, obtain lock on the table before doing so on
18287 	 * the index.  Furthermore, we need to examine the parent table of the
18288 	 * partition, so lock that one too.
18289 	 */
18290 	state.partitionOid = InvalidOid;
18291 	state.parentTblOid = parentIdx->rd_index->indrelid;
18292 	state.lockedParentTbl = false;
18293 	partIdxId =
18294 		RangeVarGetRelidExtended(name, AccessExclusiveLock, 0,
18295 								 RangeVarCallbackForAttachIndex,
18296 								 (void *) &state);
18297 	/* Not there? */
18298 	if (!OidIsValid(partIdxId))
18299 		ereport(ERROR,
18300 				(errcode(ERRCODE_UNDEFINED_OBJECT),
18301 				 errmsg("index \"%s\" does not exist", name->relname)));
18302 
18303 	/* no deadlock risk: RangeVarGetRelidExtended already acquired the lock */
18304 	partIdx = relation_open(partIdxId, AccessExclusiveLock);
18305 
18306 	/* we already hold locks on both tables, so this is safe: */
18307 	parentTbl = relation_open(parentIdx->rd_index->indrelid, AccessShareLock);
18308 	partTbl = relation_open(partIdx->rd_index->indrelid, NoLock);
18309 
18310 	ObjectAddressSet(address, RelationRelationId, RelationGetRelid(partIdx));
18311 
18312 	/* Silently do nothing if already in the right state */
18313 	currParent = partIdx->rd_rel->relispartition ?
18314 		get_partition_parent(partIdxId, false) : InvalidOid;
18315 	if (currParent != RelationGetRelid(parentIdx))
18316 	{
18317 		IndexInfo  *childInfo;
18318 		IndexInfo  *parentInfo;
18319 		AttrMap    *attmap;
18320 		bool		found;
18321 		int			i;
18322 		PartitionDesc partDesc;
18323 		Oid			constraintOid,
18324 					cldConstrId = InvalidOid;
18325 
18326 		/*
18327 		 * If this partition already has an index attached, refuse the
18328 		 * operation.
18329 		 */
18330 		refuseDupeIndexAttach(parentIdx, partIdx, partTbl);
18331 
18332 		if (OidIsValid(currParent))
18333 			ereport(ERROR,
18334 					(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
18335 					 errmsg("cannot attach index \"%s\" as a partition of index \"%s\"",
18336 							RelationGetRelationName(partIdx),
18337 							RelationGetRelationName(parentIdx)),
18338 					 errdetail("Index \"%s\" is already attached to another index.",
18339 							   RelationGetRelationName(partIdx))));
18340 
18341 		/* Make sure it indexes a partition of the other index's table */
18342 		partDesc = RelationGetPartitionDesc(parentTbl, true);
18343 		found = false;
18344 		for (i = 0; i < partDesc->nparts; i++)
18345 		{
18346 			if (partDesc->oids[i] == state.partitionOid)
18347 			{
18348 				found = true;
18349 				break;
18350 			}
18351 		}
18352 		if (!found)
18353 			ereport(ERROR,
18354 					(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
18355 					 errmsg("cannot attach index \"%s\" as a partition of index \"%s\"",
18356 							RelationGetRelationName(partIdx),
18357 							RelationGetRelationName(parentIdx)),
18358 					 errdetail("Index \"%s\" is not an index on any partition of table \"%s\".",
18359 							   RelationGetRelationName(partIdx),
18360 							   RelationGetRelationName(parentTbl))));
18361 
18362 		/* Ensure the indexes are compatible */
18363 		childInfo = BuildIndexInfo(partIdx);
18364 		parentInfo = BuildIndexInfo(parentIdx);
18365 		attmap = build_attrmap_by_name(RelationGetDescr(partTbl),
18366 									   RelationGetDescr(parentTbl));
18367 		if (!CompareIndexInfo(childInfo, parentInfo,
18368 							  partIdx->rd_indcollation,
18369 							  parentIdx->rd_indcollation,
18370 							  partIdx->rd_opfamily,
18371 							  parentIdx->rd_opfamily,
18372 							  attmap))
18373 			ereport(ERROR,
18374 					(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
18375 					 errmsg("cannot attach index \"%s\" as a partition of index \"%s\"",
18376 							RelationGetRelationName(partIdx),
18377 							RelationGetRelationName(parentIdx)),
18378 					 errdetail("The index definitions do not match.")));
18379 
18380 		/*
18381 		 * If there is a constraint in the parent, make sure there is one in
18382 		 * the child too.
18383 		 */
18384 		constraintOid = get_relation_idx_constraint_oid(RelationGetRelid(parentTbl),
18385 														RelationGetRelid(parentIdx));
18386 
18387 		if (OidIsValid(constraintOid))
18388 		{
18389 			cldConstrId = get_relation_idx_constraint_oid(RelationGetRelid(partTbl),
18390 														  partIdxId);
18391 			if (!OidIsValid(cldConstrId))
18392 				ereport(ERROR,
18393 						(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
18394 						 errmsg("cannot attach index \"%s\" as a partition of index \"%s\"",
18395 								RelationGetRelationName(partIdx),
18396 								RelationGetRelationName(parentIdx)),
18397 						 errdetail("The index \"%s\" belongs to a constraint in table \"%s\" but no constraint exists for index \"%s\".",
18398 								   RelationGetRelationName(parentIdx),
18399 								   RelationGetRelationName(parentTbl),
18400 								   RelationGetRelationName(partIdx))));
18401 		}
18402 
18403 		/* All good -- do it */
18404 		IndexSetParentIndex(partIdx, RelationGetRelid(parentIdx));
18405 		if (OidIsValid(constraintOid))
18406 			ConstraintSetParentConstraint(cldConstrId, constraintOid,
18407 										  RelationGetRelid(partTbl));
18408 
18409 		free_attrmap(attmap);
18410 
18411 		validatePartitionedIndex(parentIdx, parentTbl);
18412 	}
18413 
18414 	relation_close(parentTbl, AccessShareLock);
18415 	/* keep these locks till commit */
18416 	relation_close(partTbl, NoLock);
18417 	relation_close(partIdx, NoLock);
18418 
18419 	return address;
18420 }
18421 
18422 /*
18423  * Verify whether the given partition already contains an index attached
18424  * to the given partitioned index.  If so, raise an error.
18425  */
18426 static void
refuseDupeIndexAttach(Relation parentIdx,Relation partIdx,Relation partitionTbl)18427 refuseDupeIndexAttach(Relation parentIdx, Relation partIdx, Relation partitionTbl)
18428 {
18429 	Oid			existingIdx;
18430 
18431 	existingIdx = index_get_partition(partitionTbl,
18432 									  RelationGetRelid(parentIdx));
18433 	if (OidIsValid(existingIdx))
18434 		ereport(ERROR,
18435 				(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
18436 				 errmsg("cannot attach index \"%s\" as a partition of index \"%s\"",
18437 						RelationGetRelationName(partIdx),
18438 						RelationGetRelationName(parentIdx)),
18439 				 errdetail("Another index is already attached for partition \"%s\".",
18440 						   RelationGetRelationName(partitionTbl))));
18441 }
18442 
18443 /*
18444  * Verify whether the set of attached partition indexes to a parent index on
18445  * a partitioned table is complete.  If it is, mark the parent index valid.
18446  *
18447  * This should be called each time a partition index is attached.
18448  */
18449 static void
validatePartitionedIndex(Relation partedIdx,Relation partedTbl)18450 validatePartitionedIndex(Relation partedIdx, Relation partedTbl)
18451 {
18452 	Relation	inheritsRel;
18453 	SysScanDesc scan;
18454 	ScanKeyData key;
18455 	int			tuples = 0;
18456 	HeapTuple	inhTup;
18457 	bool		updated = false;
18458 
18459 	Assert(partedIdx->rd_rel->relkind == RELKIND_PARTITIONED_INDEX);
18460 
18461 	/*
18462 	 * Scan pg_inherits for this parent index.  Count each valid index we find
18463 	 * (verifying the pg_index entry for each), and if we reach the total
18464 	 * amount we expect, we can mark this parent index as valid.
18465 	 */
18466 	inheritsRel = table_open(InheritsRelationId, AccessShareLock);
18467 	ScanKeyInit(&key, Anum_pg_inherits_inhparent,
18468 				BTEqualStrategyNumber, F_OIDEQ,
18469 				ObjectIdGetDatum(RelationGetRelid(partedIdx)));
18470 	scan = systable_beginscan(inheritsRel, InheritsParentIndexId, true,
18471 							  NULL, 1, &key);
18472 	while ((inhTup = systable_getnext(scan)) != NULL)
18473 	{
18474 		Form_pg_inherits inhForm = (Form_pg_inherits) GETSTRUCT(inhTup);
18475 		HeapTuple	indTup;
18476 		Form_pg_index indexForm;
18477 
18478 		indTup = SearchSysCache1(INDEXRELID,
18479 								 ObjectIdGetDatum(inhForm->inhrelid));
18480 		if (!HeapTupleIsValid(indTup))
18481 			elog(ERROR, "cache lookup failed for index %u", inhForm->inhrelid);
18482 		indexForm = (Form_pg_index) GETSTRUCT(indTup);
18483 		if (indexForm->indisvalid)
18484 			tuples += 1;
18485 		ReleaseSysCache(indTup);
18486 	}
18487 
18488 	/* Done with pg_inherits */
18489 	systable_endscan(scan);
18490 	table_close(inheritsRel, AccessShareLock);
18491 
18492 	/*
18493 	 * If we found as many inherited indexes as the partitioned table has
18494 	 * partitions, we're good; update pg_index to set indisvalid.
18495 	 */
18496 	if (tuples == RelationGetPartitionDesc(partedTbl, true)->nparts)
18497 	{
18498 		Relation	idxRel;
18499 		HeapTuple	newtup;
18500 
18501 		idxRel = table_open(IndexRelationId, RowExclusiveLock);
18502 
18503 		newtup = heap_copytuple(partedIdx->rd_indextuple);
18504 		((Form_pg_index) GETSTRUCT(newtup))->indisvalid = true;
18505 		updated = true;
18506 
18507 		CatalogTupleUpdate(idxRel, &partedIdx->rd_indextuple->t_self, newtup);
18508 
18509 		table_close(idxRel, RowExclusiveLock);
18510 	}
18511 
18512 	/*
18513 	 * If this index is in turn a partition of a larger index, validating it
18514 	 * might cause the parent to become valid also.  Try that.
18515 	 */
18516 	if (updated && partedIdx->rd_rel->relispartition)
18517 	{
18518 		Oid			parentIdxId,
18519 					parentTblId;
18520 		Relation	parentIdx,
18521 					parentTbl;
18522 
18523 		/* make sure we see the validation we just did */
18524 		CommandCounterIncrement();
18525 
18526 		parentIdxId = get_partition_parent(RelationGetRelid(partedIdx), false);
18527 		parentTblId = get_partition_parent(RelationGetRelid(partedTbl), false);
18528 		parentIdx = relation_open(parentIdxId, AccessExclusiveLock);
18529 		parentTbl = relation_open(parentTblId, AccessExclusiveLock);
18530 		Assert(!parentIdx->rd_index->indisvalid);
18531 
18532 		validatePartitionedIndex(parentIdx, parentTbl);
18533 
18534 		relation_close(parentIdx, AccessExclusiveLock);
18535 		relation_close(parentTbl, AccessExclusiveLock);
18536 	}
18537 }
18538 
18539 /*
18540  * Return an OID list of constraints that reference the given relation
18541  * that are marked as having a parent constraints.
18542  */
18543 static List *
GetParentedForeignKeyRefs(Relation partition)18544 GetParentedForeignKeyRefs(Relation partition)
18545 {
18546 	Relation	pg_constraint;
18547 	HeapTuple	tuple;
18548 	SysScanDesc scan;
18549 	ScanKeyData key[2];
18550 	List	   *constraints = NIL;
18551 
18552 	/*
18553 	 * If no indexes, or no columns are referenceable by FKs, we can avoid the
18554 	 * scan.
18555 	 */
18556 	if (RelationGetIndexList(partition) == NIL ||
18557 		bms_is_empty(RelationGetIndexAttrBitmap(partition,
18558 												INDEX_ATTR_BITMAP_KEY)))
18559 		return NIL;
18560 
18561 	/* Search for constraints referencing this table */
18562 	pg_constraint = table_open(ConstraintRelationId, AccessShareLock);
18563 	ScanKeyInit(&key[0],
18564 				Anum_pg_constraint_confrelid, BTEqualStrategyNumber,
18565 				F_OIDEQ, ObjectIdGetDatum(RelationGetRelid(partition)));
18566 	ScanKeyInit(&key[1],
18567 				Anum_pg_constraint_contype, BTEqualStrategyNumber,
18568 				F_CHAREQ, CharGetDatum(CONSTRAINT_FOREIGN));
18569 
18570 	/* XXX This is a seqscan, as we don't have a usable index */
18571 	scan = systable_beginscan(pg_constraint, InvalidOid, true, NULL, 2, key);
18572 	while ((tuple = systable_getnext(scan)) != NULL)
18573 	{
18574 		Form_pg_constraint constrForm = (Form_pg_constraint) GETSTRUCT(tuple);
18575 
18576 		/*
18577 		 * We only need to process constraints that are part of larger ones.
18578 		 */
18579 		if (!OidIsValid(constrForm->conparentid))
18580 			continue;
18581 
18582 		constraints = lappend_oid(constraints, constrForm->oid);
18583 	}
18584 
18585 	systable_endscan(scan);
18586 	table_close(pg_constraint, AccessShareLock);
18587 
18588 	return constraints;
18589 }
18590 
18591 /*
18592  * During DETACH PARTITION, verify that any foreign keys pointing to the
18593  * partitioned table would not become invalid.  An error is raised if any
18594  * referenced values exist.
18595  */
18596 static void
ATDetachCheckNoForeignKeyRefs(Relation partition)18597 ATDetachCheckNoForeignKeyRefs(Relation partition)
18598 {
18599 	List	   *constraints;
18600 	ListCell   *cell;
18601 
18602 	constraints = GetParentedForeignKeyRefs(partition);
18603 
18604 	foreach(cell, constraints)
18605 	{
18606 		Oid			constrOid = lfirst_oid(cell);
18607 		HeapTuple	tuple;
18608 		Form_pg_constraint constrForm;
18609 		Relation	rel;
18610 		Trigger		trig;
18611 
18612 		tuple = SearchSysCache1(CONSTROID, ObjectIdGetDatum(constrOid));
18613 		if (!HeapTupleIsValid(tuple))
18614 			elog(ERROR, "cache lookup failed for constraint %u", constrOid);
18615 		constrForm = (Form_pg_constraint) GETSTRUCT(tuple);
18616 
18617 		Assert(OidIsValid(constrForm->conparentid));
18618 		Assert(constrForm->confrelid == RelationGetRelid(partition));
18619 
18620 		/* prevent data changes into the referencing table until commit */
18621 		rel = table_open(constrForm->conrelid, ShareLock);
18622 
18623 		MemSet(&trig, 0, sizeof(trig));
18624 		trig.tgoid = InvalidOid;
18625 		trig.tgname = NameStr(constrForm->conname);
18626 		trig.tgenabled = TRIGGER_FIRES_ON_ORIGIN;
18627 		trig.tgisinternal = true;
18628 		trig.tgconstrrelid = RelationGetRelid(partition);
18629 		trig.tgconstrindid = constrForm->conindid;
18630 		trig.tgconstraint = constrForm->oid;
18631 		trig.tgdeferrable = false;
18632 		trig.tginitdeferred = false;
18633 		/* we needn't fill in remaining fields */
18634 
18635 		RI_PartitionRemove_Check(&trig, rel, partition);
18636 
18637 		ReleaseSysCache(tuple);
18638 
18639 		table_close(rel, NoLock);
18640 	}
18641 }
18642 
18643 /*
18644  * resolve column compression specification to compression method.
18645  */
18646 static char
GetAttributeCompression(Oid atttypid,char * compression)18647 GetAttributeCompression(Oid atttypid, char *compression)
18648 {
18649 	char		cmethod;
18650 
18651 	if (compression == NULL || strcmp(compression, "default") == 0)
18652 		return InvalidCompressionMethod;
18653 
18654 	/*
18655 	 * To specify a nondefault method, the column data type must be toastable.
18656 	 * Note this says nothing about whether the column's attstorage setting
18657 	 * permits compression; we intentionally allow attstorage and
18658 	 * attcompression to be independent.  But with a non-toastable type,
18659 	 * attstorage could not be set to a value that would permit compression.
18660 	 *
18661 	 * We don't actually need to enforce this, since nothing bad would happen
18662 	 * if attcompression were non-default; it would never be consulted.  But
18663 	 * it seems more user-friendly to complain about a certainly-useless
18664 	 * attempt to set the property.
18665 	 */
18666 	if (!TypeIsToastable(atttypid))
18667 		ereport(ERROR,
18668 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
18669 				 errmsg("column data type %s does not support compression",
18670 						format_type_be(atttypid))));
18671 
18672 	cmethod = CompressionNameToMethod(compression);
18673 	if (!CompressionMethodIsValid(cmethod))
18674 		ereport(ERROR,
18675 				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
18676 				 errmsg("invalid compression method \"%s\"", compression)));
18677 
18678 	return cmethod;
18679 }
18680