1 /*-------------------------------------------------------------------------
2  *
3  * tablecmds.c
4  *	  Commands for creating and altering table structures and settings
5  *
6  * Portions Copyright (c) 1996-2018, 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/genam.h"
18 #include "access/heapam.h"
19 #include "access/heapam_xlog.h"
20 #include "access/multixact.h"
21 #include "access/reloptions.h"
22 #include "access/relscan.h"
23 #include "access/sysattr.h"
24 #include "access/tupconvert.h"
25 #include "access/xact.h"
26 #include "access/xlog.h"
27 #include "catalog/catalog.h"
28 #include "catalog/dependency.h"
29 #include "catalog/heap.h"
30 #include "catalog/index.h"
31 #include "catalog/indexing.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_trigger.h"
45 #include "catalog/pg_type.h"
46 #include "catalog/storage.h"
47 #include "catalog/storage_xlog.h"
48 #include "catalog/toasting.h"
49 #include "commands/cluster.h"
50 #include "commands/comment.h"
51 #include "commands/defrem.h"
52 #include "commands/event_trigger.h"
53 #include "commands/policy.h"
54 #include "commands/sequence.h"
55 #include "commands/tablecmds.h"
56 #include "commands/tablespace.h"
57 #include "commands/trigger.h"
58 #include "commands/typecmds.h"
59 #include "commands/user.h"
60 #include "executor/executor.h"
61 #include "foreign/foreign.h"
62 #include "miscadmin.h"
63 #include "nodes/makefuncs.h"
64 #include "nodes/nodeFuncs.h"
65 #include "nodes/parsenodes.h"
66 #include "optimizer/clauses.h"
67 #include "optimizer/planner.h"
68 #include "optimizer/predtest.h"
69 #include "optimizer/prep.h"
70 #include "optimizer/var.h"
71 #include "parser/parse_clause.h"
72 #include "parser/parse_coerce.h"
73 #include "parser/parse_collate.h"
74 #include "parser/parse_expr.h"
75 #include "parser/parse_oper.h"
76 #include "parser/parse_relation.h"
77 #include "parser/parse_type.h"
78 #include "parser/parse_utilcmd.h"
79 #include "parser/parser.h"
80 #include "partitioning/partbounds.h"
81 #include "pgstat.h"
82 #include "rewrite/rewriteDefine.h"
83 #include "rewrite/rewriteHandler.h"
84 #include "rewrite/rewriteManip.h"
85 #include "storage/bufmgr.h"
86 #include "storage/lmgr.h"
87 #include "storage/lock.h"
88 #include "storage/predicate.h"
89 #include "storage/smgr.h"
90 #include "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/tqual.h"
102 #include "utils/typcache.h"
103 
104 
105 /*
106  * ON COMMIT action list
107  */
108 typedef struct OnCommitItem
109 {
110 	Oid			relid;			/* relid of relation */
111 	OnCommitAction oncommit;	/* what to do at end of xact */
112 
113 	/*
114 	 * If this entry was created during the current transaction,
115 	 * creating_subid is the ID of the creating subxact; if created in a prior
116 	 * transaction, creating_subid is zero.  If deleted during the current
117 	 * transaction, deleting_subid is the ID of the deleting subxact; if no
118 	 * deletion request is pending, deleting_subid is zero.
119 	 */
120 	SubTransactionId creating_subid;
121 	SubTransactionId deleting_subid;
122 } OnCommitItem;
123 
124 static List *on_commits = NIL;
125 
126 
127 /*
128  * State information for ALTER TABLE
129  *
130  * The pending-work queue for an ALTER TABLE is a List of AlteredTableInfo
131  * structs, one for each table modified by the operation (the named table
132  * plus any child tables that are affected).  We save lists of subcommands
133  * to apply to this table (possibly modified by parse transformation steps);
134  * these lists will be executed in Phase 2.  If a Phase 3 step is needed,
135  * necessary information is stored in the constraints and newvals lists.
136  *
137  * Phase 2 is divided into multiple passes; subcommands are executed in
138  * a pass determined by subcommand type.
139  */
140 
141 #define AT_PASS_UNSET			-1	/* UNSET will cause ERROR */
142 #define AT_PASS_DROP			0	/* DROP (all flavors) */
143 #define AT_PASS_ALTER_TYPE		1	/* ALTER COLUMN TYPE */
144 #define AT_PASS_OLD_INDEX		2	/* re-add existing indexes */
145 #define AT_PASS_OLD_CONSTR		3	/* re-add existing constraints */
146 #define AT_PASS_COL_ATTRS		4	/* set other column attributes */
147 /* We could support a RENAME COLUMN pass here, but not currently used */
148 #define AT_PASS_ADD_COL			5	/* ADD COLUMN */
149 #define AT_PASS_ADD_INDEX		6	/* ADD indexes */
150 #define AT_PASS_ADD_CONSTR		7	/* ADD constraints, defaults */
151 #define AT_PASS_MISC			8	/* other stuff */
152 #define AT_NUM_PASSES			9
153 
154 typedef struct AlteredTableInfo
155 {
156 	/* Information saved before any work commences: */
157 	Oid			relid;			/* Relation to work on */
158 	char		relkind;		/* Its relkind */
159 	TupleDesc	oldDesc;		/* Pre-modification tuple descriptor */
160 	/* Information saved by Phase 1 for Phase 2: */
161 	List	   *subcmds[AT_NUM_PASSES]; /* Lists of AlterTableCmd */
162 	/* Information saved by Phases 1/2 for Phase 3: */
163 	List	   *constraints;	/* List of NewConstraint */
164 	List	   *newvals;		/* List of NewColumnValue */
165 	bool		new_notnull;	/* T if we added new NOT NULL constraints */
166 	int			rewrite;		/* Reason for forced rewrite, if any */
167 	Oid			newTableSpace;	/* new tablespace; 0 means no change */
168 	bool		chgPersistence; /* T if SET LOGGED/UNLOGGED is used */
169 	char		newrelpersistence;	/* if above is true */
170 	Expr	   *partition_constraint;	/* for attach partition validation */
171 	/* true, if validating default due to some other attach/detach */
172 	bool		validate_default;
173 	/* Objects to rebuild after completing ALTER TYPE operations */
174 	List	   *changedConstraintOids;	/* OIDs of constraints to rebuild */
175 	List	   *changedConstraintDefs;	/* string definitions of same */
176 	List	   *changedIndexOids;	/* OIDs of indexes to rebuild */
177 	List	   *changedIndexDefs;	/* string definitions of same */
178 	char	   *replicaIdentityIndex;	/* index to reset as REPLICA IDENTITY */
179 	char	   *clusterOnIndex;	/* index to use for CLUSTER */
180 } AlteredTableInfo;
181 
182 /* Struct describing one new constraint to check in Phase 3 scan */
183 /* Note: new NOT NULL constraints are handled elsewhere */
184 typedef struct NewConstraint
185 {
186 	char	   *name;			/* Constraint name, or NULL if none */
187 	ConstrType	contype;		/* CHECK or FOREIGN */
188 	Oid			refrelid;		/* PK rel, if FOREIGN */
189 	Oid			refindid;		/* OID of PK's index, if FOREIGN */
190 	Oid			conid;			/* OID of pg_constraint entry, if FOREIGN */
191 	Node	   *qual;			/* Check expr or CONSTR_FOREIGN Constraint */
192 	ExprState  *qualstate;		/* Execution state for CHECK expr */
193 } NewConstraint;
194 
195 /*
196  * Struct describing one new column value that needs to be computed during
197  * Phase 3 copy (this could be either a new column with a non-null default, or
198  * a column that we're changing the type of).  Columns without such an entry
199  * are just copied from the old table during ATRewriteTable.  Note that the
200  * expr is an expression over *old* table values.
201  */
202 typedef struct NewColumnValue
203 {
204 	AttrNumber	attnum;			/* which column */
205 	Expr	   *expr;			/* expression to compute */
206 	ExprState  *exprstate;		/* execution state */
207 } NewColumnValue;
208 
209 /*
210  * Error-reporting support for RemoveRelations
211  */
212 struct dropmsgstrings
213 {
214 	char		kind;
215 	int			nonexistent_code;
216 	const char *nonexistent_msg;
217 	const char *skipping_msg;
218 	const char *nota_msg;
219 	const char *drophint_msg;
220 };
221 
222 static const struct dropmsgstrings dropmsgstringarray[] = {
223 	{RELKIND_RELATION,
224 		ERRCODE_UNDEFINED_TABLE,
225 		gettext_noop("table \"%s\" does not exist"),
226 		gettext_noop("table \"%s\" does not exist, skipping"),
227 		gettext_noop("\"%s\" is not a table"),
228 	gettext_noop("Use DROP TABLE to remove a table.")},
229 	{RELKIND_SEQUENCE,
230 		ERRCODE_UNDEFINED_TABLE,
231 		gettext_noop("sequence \"%s\" does not exist"),
232 		gettext_noop("sequence \"%s\" does not exist, skipping"),
233 		gettext_noop("\"%s\" is not a sequence"),
234 	gettext_noop("Use DROP SEQUENCE to remove a sequence.")},
235 	{RELKIND_VIEW,
236 		ERRCODE_UNDEFINED_TABLE,
237 		gettext_noop("view \"%s\" does not exist"),
238 		gettext_noop("view \"%s\" does not exist, skipping"),
239 		gettext_noop("\"%s\" is not a view"),
240 	gettext_noop("Use DROP VIEW to remove a view.")},
241 	{RELKIND_MATVIEW,
242 		ERRCODE_UNDEFINED_TABLE,
243 		gettext_noop("materialized view \"%s\" does not exist"),
244 		gettext_noop("materialized view \"%s\" does not exist, skipping"),
245 		gettext_noop("\"%s\" is not a materialized view"),
246 	gettext_noop("Use DROP MATERIALIZED VIEW to remove a materialized view.")},
247 	{RELKIND_INDEX,
248 		ERRCODE_UNDEFINED_OBJECT,
249 		gettext_noop("index \"%s\" does not exist"),
250 		gettext_noop("index \"%s\" does not exist, skipping"),
251 		gettext_noop("\"%s\" is not an index"),
252 	gettext_noop("Use DROP INDEX to remove an index.")},
253 	{RELKIND_COMPOSITE_TYPE,
254 		ERRCODE_UNDEFINED_OBJECT,
255 		gettext_noop("type \"%s\" does not exist"),
256 		gettext_noop("type \"%s\" does not exist, skipping"),
257 		gettext_noop("\"%s\" is not a type"),
258 	gettext_noop("Use DROP TYPE to remove a type.")},
259 	{RELKIND_FOREIGN_TABLE,
260 		ERRCODE_UNDEFINED_OBJECT,
261 		gettext_noop("foreign table \"%s\" does not exist"),
262 		gettext_noop("foreign table \"%s\" does not exist, skipping"),
263 		gettext_noop("\"%s\" is not a foreign table"),
264 	gettext_noop("Use DROP FOREIGN TABLE to remove a foreign table.")},
265 	{RELKIND_PARTITIONED_TABLE,
266 		ERRCODE_UNDEFINED_TABLE,
267 		gettext_noop("table \"%s\" does not exist"),
268 		gettext_noop("table \"%s\" does not exist, skipping"),
269 		gettext_noop("\"%s\" is not a table"),
270 	gettext_noop("Use DROP TABLE to remove a table.")},
271 	{RELKIND_PARTITIONED_INDEX,
272 		ERRCODE_UNDEFINED_OBJECT,
273 		gettext_noop("index \"%s\" does not exist"),
274 		gettext_noop("index \"%s\" does not exist, skipping"),
275 		gettext_noop("\"%s\" is not an index"),
276 	gettext_noop("Use DROP INDEX to remove an index.")},
277 	{'\0', 0, NULL, NULL, NULL, NULL}
278 };
279 
280 struct DropRelationCallbackState
281 {
282 	char		relkind;
283 	Oid			heapOid;
284 	Oid			partParentOid;
285 	bool		concurrent;
286 };
287 
288 /* Alter table target-type flags for ATSimplePermissions */
289 #define		ATT_TABLE				0x0001
290 #define		ATT_VIEW				0x0002
291 #define		ATT_MATVIEW				0x0004
292 #define		ATT_INDEX				0x0008
293 #define		ATT_COMPOSITE_TYPE		0x0010
294 #define		ATT_FOREIGN_TABLE		0x0020
295 #define		ATT_PARTITIONED_INDEX	0x0040
296 
297 /*
298  * Partition tables are expected to be dropped when the parent partitioned
299  * table gets dropped. Hence for partitioning we use AUTO dependency.
300  * Otherwise, for regular inheritance use NORMAL dependency.
301  */
302 #define child_dependency_type(child_is_partition)	\
303 	((child_is_partition) ? DEPENDENCY_AUTO : DEPENDENCY_NORMAL)
304 
305 static void truncate_check_rel(Relation rel);
306 static List *MergeAttributes(List *schema, List *supers, char relpersistence,
307 				bool is_partition, List **supOids, List **supconstr,
308 				int *supOidCount);
309 static bool MergeCheckConstraint(List *constraints, char *name, Node *expr);
310 static void MergeAttributesIntoExisting(Relation child_rel, Relation parent_rel);
311 static void MergeConstraintsIntoExisting(Relation child_rel, Relation parent_rel);
312 static void StoreCatalogInheritance(Oid relationId, List *supers,
313 						bool child_is_partition);
314 static void StoreCatalogInheritance1(Oid relationId, Oid parentOid,
315 						 int32 seqNumber, Relation inhRelation,
316 						 bool child_is_partition);
317 static int	findAttrByName(const char *attributeName, List *schema);
318 static void AlterIndexNamespaces(Relation classRel, Relation rel,
319 					 Oid oldNspOid, Oid newNspOid, ObjectAddresses *objsMoved);
320 static void AlterSeqNamespaces(Relation classRel, Relation rel,
321 				   Oid oldNspOid, Oid newNspOid, ObjectAddresses *objsMoved,
322 				   LOCKMODE lockmode);
323 static ObjectAddress ATExecAlterConstraint(Relation rel, AlterTableCmd *cmd,
324 					  bool recurse, bool recursing, LOCKMODE lockmode);
325 static bool ATExecAlterConstrRecurse(Constraint *cmdcon, Relation conrel,
326 						 Relation tgrel, Relation rel, HeapTuple contuple,
327 						 List **otherrelids, LOCKMODE lockmode);
328 static ObjectAddress ATExecValidateConstraint(List **wqueue, Relation rel,
329 						 char *constrName, bool recurse, bool recursing,
330 						 LOCKMODE lockmode);
331 static int transformColumnNameList(Oid relId, List *colList,
332 						int16 *attnums, Oid *atttypids);
333 static int transformFkeyGetPrimaryKey(Relation pkrel, Oid *indexOid,
334 						   List **attnamelist,
335 						   int16 *attnums, Oid *atttypids,
336 						   Oid *opclasses);
337 static Oid transformFkeyCheckAttrs(Relation pkrel,
338 						int numattrs, int16 *attnums,
339 						Oid *opclasses);
340 static void checkFkeyPermissions(Relation rel, int16 *attnums, int natts);
341 static CoercionPathType findFkeyCast(Oid targetTypeId, Oid sourceTypeId,
342 			 Oid *funcid);
343 static void validateForeignKeyConstraint(char *conname,
344 							 Relation rel, Relation pkrel,
345 							 Oid pkindOid, Oid constraintOid);
346 static void ATController(AlterTableStmt *parsetree,
347 			 Relation rel, List *cmds, bool recurse, LOCKMODE lockmode);
348 static void ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd,
349 		  bool recurse, bool recursing, LOCKMODE lockmode);
350 static void ATRewriteCatalogs(List **wqueue, LOCKMODE lockmode);
351 static void ATExecCmd(List **wqueue, AlteredTableInfo *tab, Relation rel,
352 		  AlterTableCmd *cmd, LOCKMODE lockmode);
353 static void ATRewriteTables(AlterTableStmt *parsetree,
354 				List **wqueue, LOCKMODE lockmode);
355 static void ATRewriteTable(AlteredTableInfo *tab, Oid OIDNewHeap, LOCKMODE lockmode);
356 static AlteredTableInfo *ATGetQueueEntry(List **wqueue, Relation rel);
357 static void ATSimplePermissions(Relation rel, int allowed_targets);
358 static void ATWrongRelkindError(Relation rel, int allowed_targets);
359 static void ATSimpleRecursion(List **wqueue, Relation rel,
360 				  AlterTableCmd *cmd, bool recurse, LOCKMODE lockmode);
361 static void ATCheckPartitionsNotInUse(Relation rel, LOCKMODE lockmode);
362 static void ATTypedTableRecursion(List **wqueue, Relation rel, AlterTableCmd *cmd,
363 					  LOCKMODE lockmode);
364 static List *find_typed_table_dependencies(Oid typeOid, const char *typeName,
365 							  DropBehavior behavior);
366 static void ATPrepAddColumn(List **wqueue, Relation rel, bool recurse, bool recursing,
367 				bool is_view, AlterTableCmd *cmd, LOCKMODE lockmode);
368 static ObjectAddress ATExecAddColumn(List **wqueue, AlteredTableInfo *tab,
369 				Relation rel, ColumnDef *colDef, bool isOid,
370 				bool recurse, bool recursing,
371 				bool if_not_exists, LOCKMODE lockmode);
372 static bool check_for_column_name_collision(Relation rel, const char *colname,
373 								bool if_not_exists);
374 static void add_column_datatype_dependency(Oid relid, int32 attnum, Oid typid);
375 static void add_column_collation_dependency(Oid relid, int32 attnum, Oid collid);
376 static void ATPrepAddOids(List **wqueue, Relation rel, bool recurse,
377 			  AlterTableCmd *cmd, LOCKMODE lockmode);
378 static void ATPrepDropNotNull(Relation rel, bool recurse, bool recursing);
379 static ObjectAddress ATExecDropNotNull(Relation rel, const char *colName, LOCKMODE lockmode);
380 static void ATPrepSetNotNull(Relation rel, bool recurse, bool recursing);
381 static ObjectAddress ATExecSetNotNull(AlteredTableInfo *tab, Relation rel,
382 				 const char *colName, LOCKMODE lockmode);
383 static ObjectAddress ATExecColumnDefault(Relation rel, const char *colName,
384 					Node *newDefault, LOCKMODE lockmode);
385 static ObjectAddress ATExecAddIdentity(Relation rel, const char *colName,
386 				  Node *def, LOCKMODE lockmode);
387 static ObjectAddress ATExecSetIdentity(Relation rel, const char *colName,
388 				  Node *def, LOCKMODE lockmode);
389 static ObjectAddress ATExecDropIdentity(Relation rel, const char *colName, bool missing_ok, LOCKMODE lockmode);
390 static void ATPrepSetStatistics(Relation rel, const char *colName, int16 colNum,
391 					Node *newValue, LOCKMODE lockmode);
392 static ObjectAddress ATExecSetStatistics(Relation rel, const char *colName, int16 colNum,
393 					Node *newValue, LOCKMODE lockmode);
394 static ObjectAddress ATExecSetOptions(Relation rel, const char *colName,
395 				 Node *options, bool isReset, LOCKMODE lockmode);
396 static ObjectAddress ATExecSetStorage(Relation rel, const char *colName,
397 				 Node *newValue, LOCKMODE lockmode);
398 static void ATPrepDropColumn(List **wqueue, Relation rel, bool recurse, bool recursing,
399 				 AlterTableCmd *cmd, LOCKMODE lockmode);
400 static ObjectAddress ATExecDropColumn(List **wqueue, Relation rel, const char *colName,
401 				 DropBehavior behavior,
402 				 bool recurse, bool recursing,
403 				 bool missing_ok, LOCKMODE lockmode);
404 static ObjectAddress ATExecAddIndex(AlteredTableInfo *tab, Relation rel,
405 			   IndexStmt *stmt, bool is_rebuild, LOCKMODE lockmode);
406 static ObjectAddress ATExecAddConstraint(List **wqueue,
407 					AlteredTableInfo *tab, Relation rel,
408 					Constraint *newConstraint, bool recurse, bool is_readd,
409 					LOCKMODE lockmode);
410 static ObjectAddress ATExecAddIndexConstraint(AlteredTableInfo *tab, Relation rel,
411 						 IndexStmt *stmt, LOCKMODE lockmode);
412 static ObjectAddress ATAddCheckConstraint(List **wqueue,
413 					 AlteredTableInfo *tab, Relation rel,
414 					 Constraint *constr,
415 					 bool recurse, bool recursing, bool is_readd,
416 					 LOCKMODE lockmode);
417 static ObjectAddress ATAddForeignKeyConstraint(List **wqueue, AlteredTableInfo *tab,
418 						  Relation rel, Constraint *fkconstraint, Oid parentConstr,
419 						  bool recurse, bool recursing,
420 						  LOCKMODE lockmode);
421 static void CloneFkReferencing(Relation pg_constraint, Relation parentRel,
422 				   Relation partRel, List *clone, List **cloned);
423 static void ATExecDropConstraint(Relation rel, const char *constrName,
424 					 DropBehavior behavior,
425 					 bool recurse, bool recursing,
426 					 bool missing_ok, LOCKMODE lockmode);
427 static void ATPrepAlterColumnType(List **wqueue,
428 					  AlteredTableInfo *tab, Relation rel,
429 					  bool recurse, bool recursing,
430 					  AlterTableCmd *cmd, LOCKMODE lockmode);
431 static bool ATColumnChangeRequiresRewrite(Node *expr, AttrNumber varattno);
432 static ObjectAddress ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel,
433 					  AlterTableCmd *cmd, LOCKMODE lockmode);
434 static void RememberConstraintForRebuilding(Oid conoid, AlteredTableInfo *tab);
435 static void RememberIndexForRebuilding(Oid indoid, AlteredTableInfo *tab);
436 static ObjectAddress ATExecAlterColumnGenericOptions(Relation rel, const char *colName,
437 								List *options, LOCKMODE lockmode);
438 static void ATPostAlterTypeCleanup(List **wqueue, AlteredTableInfo *tab,
439 					   LOCKMODE lockmode);
440 static void ATPostAlterTypeParse(Oid oldId, Oid oldRelId, Oid refRelId,
441 					 char *cmd, List **wqueue, LOCKMODE lockmode,
442 					 bool rewrite);
443 static void RebuildConstraintComment(AlteredTableInfo *tab, int pass,
444 						 Oid objid, Relation rel, List *domname,
445 						 const char *conname);
446 static void TryReuseIndex(Oid oldId, IndexStmt *stmt);
447 static void TryReuseForeignKey(Oid oldId, Constraint *con);
448 static void change_owner_fix_column_acls(Oid relationOid,
449 							 Oid oldOwnerId, Oid newOwnerId);
450 static void change_owner_recurse_to_sequences(Oid relationOid,
451 								  Oid newOwnerId, LOCKMODE lockmode);
452 static ObjectAddress ATExecClusterOn(Relation rel, const char *indexName,
453 				LOCKMODE lockmode);
454 static void ATExecDropCluster(Relation rel, LOCKMODE lockmode);
455 static bool ATPrepChangePersistence(Relation rel, bool toLogged);
456 static void ATPrepSetTableSpace(AlteredTableInfo *tab, Relation rel,
457 					const char *tablespacename, LOCKMODE lockmode);
458 static void ATExecSetTableSpace(Oid tableOid, Oid newTableSpace, LOCKMODE lockmode);
459 static void ATExecPartedIdxSetTableSpace(Relation rel, Oid newTableSpace);
460 static void ATExecSetRelOptions(Relation rel, List *defList,
461 					AlterTableType operation,
462 					LOCKMODE lockmode);
463 static void ATExecEnableDisableTrigger(Relation rel, const char *trigname,
464 						   char fires_when, bool skip_system, LOCKMODE lockmode);
465 static void ATExecEnableDisableRule(Relation rel, const char *rulename,
466 						char fires_when, LOCKMODE lockmode);
467 static void ATPrepAddInherit(Relation child_rel);
468 static ObjectAddress ATExecAddInherit(Relation child_rel, RangeVar *parent, LOCKMODE lockmode);
469 static ObjectAddress ATExecDropInherit(Relation rel, RangeVar *parent, LOCKMODE lockmode);
470 static void drop_parent_dependency(Oid relid, Oid refclassid, Oid refobjid,
471 					   DependencyType deptype);
472 static ObjectAddress ATExecAddOf(Relation rel, const TypeName *ofTypename, LOCKMODE lockmode);
473 static void ATExecDropOf(Relation rel, LOCKMODE lockmode);
474 static void ATExecReplicaIdentity(Relation rel, ReplicaIdentityStmt *stmt, LOCKMODE lockmode);
475 static void ATExecGenericOptions(Relation rel, List *options);
476 static void ATExecEnableRowSecurity(Relation rel);
477 static void ATExecDisableRowSecurity(Relation rel);
478 static void ATExecForceNoForceRowSecurity(Relation rel, bool force_rls);
479 
480 static void copy_relation_data(SMgrRelation rel, SMgrRelation dst,
481 				   ForkNumber forkNum, char relpersistence);
482 static const char *storage_name(char c);
483 
484 static void RangeVarCallbackForDropRelation(const RangeVar *rel, Oid relOid,
485 								Oid oldRelOid, void *arg);
486 static void RangeVarCallbackForAlterRelation(const RangeVar *rv, Oid relid,
487 								 Oid oldrelid, void *arg);
488 static PartitionSpec *transformPartitionSpec(Relation rel, PartitionSpec *partspec, char *strategy);
489 static void ComputePartitionAttrs(Relation rel, List *partParams, AttrNumber *partattrs,
490 					  List **partexprs, Oid *partopclass, Oid *partcollation, char strategy);
491 static void CreateInheritance(Relation child_rel, Relation parent_rel);
492 static void RemoveInheritance(Relation child_rel, Relation parent_rel);
493 static ObjectAddress ATExecAttachPartition(List **wqueue, Relation rel,
494 					  PartitionCmd *cmd);
495 static void AttachPartitionEnsureIndexes(Relation rel, Relation attachrel);
496 static void QueuePartitionConstraintValidation(List **wqueue, Relation scanrel,
497 								   List *partConstraint,
498 								   bool validate_default);
499 static void CloneRowTriggersToPartition(Relation parent, Relation partition);
500 static void DropClonedTriggersFromPartition(Oid partitionId);
501 static ObjectAddress ATExecDetachPartition(Relation rel, RangeVar *name);
502 static ObjectAddress ATExecAttachPartitionIdx(List **wqueue, Relation rel,
503 						 RangeVar *name);
504 static void validatePartitionedIndex(Relation partedIdx, Relation partedTbl);
505 static void refuseDupeIndexAttach(Relation parentIdx, Relation partIdx,
506 					  Relation partitionTbl);
507 
508 
509 /* ----------------------------------------------------------------
510  *		DefineRelation
511  *				Creates a new relation.
512  *
513  * stmt carries parsetree information from an ordinary CREATE TABLE statement.
514  * The other arguments are used to extend the behavior for other cases:
515  * relkind: relkind to assign to the new relation
516  * ownerId: if not InvalidOid, use this as the new relation's owner.
517  * typaddress: if not null, it's set to the pg_type entry's address.
518  * queryString: for error reporting
519  *
520  * Note that permissions checks are done against current user regardless of
521  * ownerId.  A nonzero ownerId is used when someone is creating a relation
522  * "on behalf of" someone else, so we still want to see that the current user
523  * has permissions to do it.
524  *
525  * If successful, returns the address of the new relation.
526  * ----------------------------------------------------------------
527  */
528 ObjectAddress
DefineRelation(CreateStmt * stmt,char relkind,Oid ownerId,ObjectAddress * typaddress,const char * queryString)529 DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId,
530 			   ObjectAddress *typaddress, const char *queryString)
531 {
532 	char		relname[NAMEDATALEN];
533 	Oid			namespaceId;
534 	Oid			relationId;
535 	Oid			tablespaceId;
536 	Relation	rel;
537 	TupleDesc	descriptor;
538 	List	   *inheritOids;
539 	List	   *old_constraints;
540 	bool		localHasOids;
541 	int			parentOidCount;
542 	List	   *rawDefaults;
543 	List	   *cookedDefaults;
544 	Datum		reloptions;
545 	ListCell   *listptr;
546 	AttrNumber	attnum;
547 	static char *validnsps[] = HEAP_RELOPT_NAMESPACES;
548 	Oid			ofTypeId;
549 	ObjectAddress address;
550 
551 	/*
552 	 * Truncate relname to appropriate length (probably a waste of time, as
553 	 * parser should have done this already).
554 	 */
555 	StrNCpy(relname, stmt->relation->relname, NAMEDATALEN);
556 
557 	/*
558 	 * Check consistency of arguments
559 	 */
560 	if (stmt->oncommit != ONCOMMIT_NOOP
561 		&& stmt->relation->relpersistence != RELPERSISTENCE_TEMP)
562 		ereport(ERROR,
563 				(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
564 				 errmsg("ON COMMIT can only be used on temporary tables")));
565 
566 	if (stmt->partspec != NULL)
567 	{
568 		if (relkind != RELKIND_RELATION)
569 			elog(ERROR, "unexpected relkind: %d", (int) relkind);
570 
571 		relkind = RELKIND_PARTITIONED_TABLE;
572 	}
573 
574 	/*
575 	 * Look up the namespace in which we are supposed to create the relation,
576 	 * check we have permission to create there, lock it against concurrent
577 	 * drop, and mark stmt->relation as RELPERSISTENCE_TEMP if a temporary
578 	 * namespace is selected.
579 	 */
580 	namespaceId =
581 		RangeVarGetAndCheckCreationNamespace(stmt->relation, NoLock, NULL);
582 
583 	/*
584 	 * Security check: disallow creating temp tables from security-restricted
585 	 * code.  This is needed because calling code might not expect untrusted
586 	 * tables to appear in pg_temp at the front of its search path.
587 	 */
588 	if (stmt->relation->relpersistence == RELPERSISTENCE_TEMP
589 		&& InSecurityRestrictedOperation())
590 		ereport(ERROR,
591 				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
592 				 errmsg("cannot create temporary table within security-restricted operation")));
593 
594 	/*
595 	 * Select tablespace to use.  If not specified, use default tablespace
596 	 * (which may in turn default to database's default).
597 	 */
598 	if (stmt->tablespacename)
599 	{
600 		tablespaceId = get_tablespace_oid(stmt->tablespacename, false);
601 	}
602 	else
603 	{
604 		tablespaceId = GetDefaultTablespace(stmt->relation->relpersistence);
605 		/* note InvalidOid is OK in this case */
606 	}
607 
608 	/* Check permissions except when using database's default */
609 	if (OidIsValid(tablespaceId) && tablespaceId != MyDatabaseTableSpace)
610 	{
611 		AclResult	aclresult;
612 
613 		aclresult = pg_tablespace_aclcheck(tablespaceId, GetUserId(),
614 										   ACL_CREATE);
615 		if (aclresult != ACLCHECK_OK)
616 			aclcheck_error(aclresult, OBJECT_TABLESPACE,
617 						   get_tablespace_name(tablespaceId));
618 	}
619 
620 	/* In all cases disallow placing user relations in pg_global */
621 	if (tablespaceId == GLOBALTABLESPACE_OID)
622 		ereport(ERROR,
623 				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
624 				 errmsg("only shared relations can be placed in pg_global tablespace")));
625 
626 	/* Identify user ID that will own the table */
627 	if (!OidIsValid(ownerId))
628 		ownerId = GetUserId();
629 
630 	/*
631 	 * Parse and validate reloptions, if any.
632 	 */
633 	reloptions = transformRelOptions((Datum) 0, stmt->options, NULL, validnsps,
634 									 true, false);
635 
636 	if (relkind == RELKIND_VIEW)
637 		(void) view_reloptions(reloptions, true);
638 	else
639 		(void) heap_reloptions(relkind, reloptions, true);
640 
641 	if (stmt->ofTypename)
642 	{
643 		AclResult	aclresult;
644 
645 		ofTypeId = typenameTypeId(NULL, stmt->ofTypename);
646 
647 		aclresult = pg_type_aclcheck(ofTypeId, GetUserId(), ACL_USAGE);
648 		if (aclresult != ACLCHECK_OK)
649 			aclcheck_error_type(aclresult, ofTypeId);
650 	}
651 	else
652 		ofTypeId = InvalidOid;
653 
654 	/*
655 	 * Look up inheritance ancestors and generate relation schema, including
656 	 * inherited attributes.  (Note that stmt->tableElts is destructively
657 	 * modified by MergeAttributes.)
658 	 */
659 	stmt->tableElts =
660 		MergeAttributes(stmt->tableElts, stmt->inhRelations,
661 						stmt->relation->relpersistence,
662 						stmt->partbound != NULL,
663 						&inheritOids, &old_constraints, &parentOidCount);
664 
665 	/*
666 	 * Create a tuple descriptor from the relation schema.  Note that this
667 	 * deals with column names, types, and NOT NULL constraints, but not
668 	 * default values or CHECK constraints; we handle those below.
669 	 */
670 	descriptor = BuildDescForRelation(stmt->tableElts);
671 
672 	/*
673 	 * Notice that we allow OIDs here only for plain tables and partitioned
674 	 * tables, even though some other relkinds can support them.  This is
675 	 * necessary because the default_with_oids GUC must apply only to plain
676 	 * tables and not any other relkind; doing otherwise would break existing
677 	 * pg_dump files.  We could allow explicit "WITH OIDS" while not allowing
678 	 * default_with_oids to affect other relkinds, but it would complicate
679 	 * interpretOidsOption().
680 	 */
681 	localHasOids = interpretOidsOption(stmt->options,
682 									   (relkind == RELKIND_RELATION ||
683 										relkind == RELKIND_PARTITIONED_TABLE));
684 	descriptor->tdhasoid = (localHasOids || parentOidCount > 0);
685 
686 	/*
687 	 * If a partitioned table doesn't have the system OID column, then none of
688 	 * its partitions should have it.
689 	 */
690 	if (stmt->partbound && parentOidCount == 0 && localHasOids)
691 		ereport(ERROR,
692 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
693 				 errmsg("cannot create table with OIDs as partition of table without OIDs")));
694 
695 	/*
696 	 * Find columns with default values and prepare for insertion of the
697 	 * defaults.  Pre-cooked (that is, inherited) defaults go into a list of
698 	 * CookedConstraint structs that we'll pass to heap_create_with_catalog,
699 	 * while raw defaults go into a list of RawColumnDefault structs that will
700 	 * be processed by AddRelationNewConstraints.  (We can't deal with raw
701 	 * expressions until we can do transformExpr.)
702 	 *
703 	 * We can set the atthasdef flags now in the tuple descriptor; this just
704 	 * saves StoreAttrDefault from having to do an immediate update of the
705 	 * pg_attribute rows.
706 	 */
707 	rawDefaults = NIL;
708 	cookedDefaults = NIL;
709 	attnum = 0;
710 
711 	foreach(listptr, stmt->tableElts)
712 	{
713 		ColumnDef  *colDef = lfirst(listptr);
714 		Form_pg_attribute attr;
715 
716 		attnum++;
717 		attr = TupleDescAttr(descriptor, attnum - 1);
718 
719 		if (colDef->raw_default != NULL)
720 		{
721 			RawColumnDefault *rawEnt;
722 
723 			Assert(colDef->cooked_default == NULL);
724 
725 			rawEnt = (RawColumnDefault *) palloc(sizeof(RawColumnDefault));
726 			rawEnt->attnum = attnum;
727 			rawEnt->raw_default = colDef->raw_default;
728 			rawEnt->missingMode = false;
729 			rawDefaults = lappend(rawDefaults, rawEnt);
730 			attr->atthasdef = true;
731 		}
732 		else if (colDef->cooked_default != NULL)
733 		{
734 			CookedConstraint *cooked;
735 
736 			cooked = (CookedConstraint *) palloc(sizeof(CookedConstraint));
737 			cooked->contype = CONSTR_DEFAULT;
738 			cooked->conoid = InvalidOid;	/* until created */
739 			cooked->name = NULL;
740 			cooked->attnum = attnum;
741 			cooked->expr = colDef->cooked_default;
742 			cooked->skip_validation = false;
743 			cooked->is_local = true;	/* not used for defaults */
744 			cooked->inhcount = 0;	/* ditto */
745 			cooked->is_no_inherit = false;
746 			cookedDefaults = lappend(cookedDefaults, cooked);
747 			attr->atthasdef = true;
748 		}
749 
750 		if (colDef->identity)
751 			attr->attidentity = colDef->identity;
752 	}
753 
754 	/*
755 	 * Create the relation.  Inherited defaults and constraints are passed in
756 	 * for immediate handling --- since they don't need parsing, they can be
757 	 * stored immediately.
758 	 */
759 	relationId = heap_create_with_catalog(relname,
760 										  namespaceId,
761 										  tablespaceId,
762 										  InvalidOid,
763 										  InvalidOid,
764 										  ofTypeId,
765 										  ownerId,
766 										  descriptor,
767 										  list_concat(cookedDefaults,
768 													  old_constraints),
769 										  relkind,
770 										  stmt->relation->relpersistence,
771 										  false,
772 										  false,
773 										  localHasOids,
774 										  parentOidCount,
775 										  stmt->oncommit,
776 										  reloptions,
777 										  true,
778 										  allowSystemTableMods,
779 										  false,
780 										  InvalidOid,
781 										  typaddress);
782 
783 	/*
784 	 * We must bump the command counter to make the newly-created relation
785 	 * tuple visible for opening.
786 	 */
787 	CommandCounterIncrement();
788 
789 	/*
790 	 * Open the new relation and acquire exclusive lock on it.  This isn't
791 	 * really necessary for locking out other backends (since they can't see
792 	 * the new rel anyway until we commit), but it keeps the lock manager from
793 	 * complaining about deadlock risks.
794 	 */
795 	rel = relation_open(relationId, AccessExclusiveLock);
796 
797 	/* Process and store partition bound, if any. */
798 	if (stmt->partbound)
799 	{
800 		PartitionBoundSpec *bound;
801 		ParseState *pstate;
802 		Oid			parentId = linitial_oid(inheritOids),
803 					defaultPartOid;
804 		Relation	parent,
805 					defaultRel = NULL;
806 
807 		/* Already have strong enough lock on the parent */
808 		parent = heap_open(parentId, NoLock);
809 
810 		/*
811 		 * We are going to try to validate the partition bound specification
812 		 * against the partition key of parentRel, so it better have one.
813 		 */
814 		if (parent->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
815 			ereport(ERROR,
816 					(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
817 					 errmsg("\"%s\" is not partitioned",
818 							RelationGetRelationName(parent))));
819 
820 		/*
821 		 * The partition constraint of the default partition depends on the
822 		 * partition bounds of every other partition. It is possible that
823 		 * another backend might be about to execute a query on the default
824 		 * partition table, and that the query relies on previously cached
825 		 * default partition constraints. We must therefore take a table lock
826 		 * strong enough to prevent all queries on the default partition from
827 		 * proceeding until we commit and send out a shared-cache-inval notice
828 		 * that will make them update their index lists.
829 		 *
830 		 * Order of locking: The relation being added won't be visible to
831 		 * other backends until it is committed, hence here in
832 		 * DefineRelation() the order of locking the default partition and the
833 		 * relation being added does not matter. But at all other places we
834 		 * need to lock the default relation before we lock the relation being
835 		 * added or removed i.e. we should take the lock in same order at all
836 		 * the places such that lock parent, lock default partition and then
837 		 * lock the partition so as to avoid a deadlock.
838 		 */
839 		defaultPartOid =
840 			get_default_oid_from_partdesc(RelationGetPartitionDesc(parent));
841 		if (OidIsValid(defaultPartOid))
842 			defaultRel = heap_open(defaultPartOid, AccessExclusiveLock);
843 
844 		/* Tranform the bound values */
845 		pstate = make_parsestate(NULL);
846 		pstate->p_sourcetext = queryString;
847 
848 		bound = transformPartitionBound(pstate, parent, stmt->partbound);
849 
850 		/*
851 		 * Check first that the new partition's bound is valid and does not
852 		 * overlap with any of existing partitions of the parent.
853 		 */
854 		check_new_partition_bound(relname, parent, bound);
855 
856 		/*
857 		 * If the default partition exists, its partition constraints will
858 		 * change after the addition of this new partition such that it won't
859 		 * allow any row that qualifies for this new partition. So, check that
860 		 * the existing data in the default partition satisfies the constraint
861 		 * as it will exist after adding this partition.
862 		 */
863 		if (OidIsValid(defaultPartOid))
864 		{
865 			check_default_partition_contents(parent, defaultRel, bound);
866 			/* Keep the lock until commit. */
867 			heap_close(defaultRel, NoLock);
868 		}
869 
870 		/* Update the pg_class entry. */
871 		StorePartitionBound(rel, parent, bound);
872 
873 		heap_close(parent, NoLock);
874 	}
875 
876 	/* Store inheritance information for new rel. */
877 	StoreCatalogInheritance(relationId, inheritOids, stmt->partbound != NULL);
878 
879 	/*
880 	 * Process the partitioning specification (if any) and store the partition
881 	 * key information into the catalog.
882 	 */
883 	if (stmt->partspec)
884 	{
885 		char		strategy;
886 		int			partnatts;
887 		AttrNumber	partattrs[PARTITION_MAX_KEYS];
888 		Oid			partopclass[PARTITION_MAX_KEYS];
889 		Oid			partcollation[PARTITION_MAX_KEYS];
890 		List	   *partexprs = NIL;
891 
892 		partnatts = list_length(stmt->partspec->partParams);
893 
894 		/* Protect fixed-size arrays here and in executor */
895 		if (partnatts > PARTITION_MAX_KEYS)
896 			ereport(ERROR,
897 					(errcode(ERRCODE_TOO_MANY_COLUMNS),
898 					 errmsg("cannot partition using more than %d columns",
899 							PARTITION_MAX_KEYS)));
900 
901 		/*
902 		 * We need to transform the raw parsetrees corresponding to partition
903 		 * expressions into executable expression trees.  Like column defaults
904 		 * and CHECK constraints, we could not have done the transformation
905 		 * earlier.
906 		 */
907 		stmt->partspec = transformPartitionSpec(rel, stmt->partspec,
908 												&strategy);
909 
910 		ComputePartitionAttrs(rel, stmt->partspec->partParams,
911 							  partattrs, &partexprs, partopclass,
912 							  partcollation, strategy);
913 
914 		StorePartitionKey(rel, strategy, partnatts, partattrs, partexprs,
915 						  partopclass, partcollation);
916 
917 		/* make it all visible */
918 		CommandCounterIncrement();
919 	}
920 
921 	/*
922 	 * If we're creating a partition, create now all the indexes, triggers,
923 	 * FKs defined in the parent.
924 	 *
925 	 * We can't do it earlier, because DefineIndex wants to know the partition
926 	 * key which we just stored.
927 	 */
928 	if (stmt->partbound)
929 	{
930 		Oid			parentId = linitial_oid(inheritOids);
931 		Relation	parent;
932 		List	   *idxlist;
933 		ListCell   *cell;
934 
935 		/* Already have strong enough lock on the parent */
936 		parent = heap_open(parentId, NoLock);
937 		idxlist = RelationGetIndexList(parent);
938 
939 		/*
940 		 * For each index in the parent table, create one in the partition
941 		 */
942 		foreach(cell, idxlist)
943 		{
944 			Relation	idxRel = index_open(lfirst_oid(cell), AccessShareLock);
945 			AttrNumber *attmap;
946 			IndexStmt  *idxstmt;
947 			Oid			constraintOid;
948 
949 			if (rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
950 			{
951 				if (idxRel->rd_index->indisunique)
952 					ereport(ERROR,
953 							(errcode(ERRCODE_WRONG_OBJECT_TYPE),
954 							 errmsg("cannot create foreign partition of partitioned table \"%s\"",
955 									RelationGetRelationName(parent)),
956 							 errdetail("Table \"%s\" contains indexes that are unique.",
957 									RelationGetRelationName(parent))));
958 				else
959 				{
960 					index_close(idxRel, AccessShareLock);
961 					continue;
962 				}
963 			}
964 
965 			attmap = convert_tuples_by_name_map(RelationGetDescr(rel),
966 												RelationGetDescr(parent),
967 												gettext_noop("could not convert row type"));
968 			idxstmt =
969 				generateClonedIndexStmt(NULL, RelationGetRelid(rel), idxRel,
970 										attmap, RelationGetDescr(parent)->natts,
971 										&constraintOid);
972 			DefineIndex(RelationGetRelid(rel),
973 						idxstmt,
974 						InvalidOid,
975 						RelationGetRelid(idxRel),
976 						constraintOid,
977 						false, false, false, false, false);
978 
979 			index_close(idxRel, AccessShareLock);
980 		}
981 
982 		list_free(idxlist);
983 
984 		/*
985 		 * If there are any row-level triggers, clone them to the new
986 		 * partition.
987 		 */
988 		if (parent->trigdesc != NULL)
989 			CloneRowTriggersToPartition(parent, rel);
990 
991 		/*
992 		 * And foreign keys too.  Note that because we're freshly creating the
993 		 * table, there is no need to verify these new constraints.
994 		 */
995 		CloneForeignKeyConstraints(parentId, relationId, NULL);
996 
997 		heap_close(parent, NoLock);
998 	}
999 
1000 	/*
1001 	 * Now add any newly specified column default values and CHECK constraints
1002 	 * to the new relation.  These are passed to us in the form of raw
1003 	 * parsetrees; we need to transform them to executable expression trees
1004 	 * before they can be added. The most convenient way to do that is to
1005 	 * apply the parser's transformExpr routine, but transformExpr doesn't
1006 	 * work unless we have a pre-existing relation. So, the transformation has
1007 	 * to be postponed to this final step of CREATE TABLE.
1008 	 */
1009 	if (rawDefaults || stmt->constraints)
1010 		AddRelationNewConstraints(rel, rawDefaults, stmt->constraints,
1011 								  true, true, false);
1012 
1013 	ObjectAddressSet(address, RelationRelationId, relationId);
1014 
1015 	/*
1016 	 * Clean up.  We keep lock on new relation (although it shouldn't be
1017 	 * visible to anyone else anyway, until commit).
1018 	 */
1019 	relation_close(rel, NoLock);
1020 
1021 	return address;
1022 }
1023 
1024 /*
1025  * Emit the right error or warning message for a "DROP" command issued on a
1026  * non-existent relation
1027  */
1028 static void
DropErrorMsgNonExistent(RangeVar * rel,char rightkind,bool missing_ok)1029 DropErrorMsgNonExistent(RangeVar *rel, char rightkind, bool missing_ok)
1030 {
1031 	const struct dropmsgstrings *rentry;
1032 
1033 	if (rel->schemaname != NULL &&
1034 		!OidIsValid(LookupNamespaceNoError(rel->schemaname)))
1035 	{
1036 		if (!missing_ok)
1037 		{
1038 			ereport(ERROR,
1039 					(errcode(ERRCODE_UNDEFINED_SCHEMA),
1040 					 errmsg("schema \"%s\" does not exist", rel->schemaname)));
1041 		}
1042 		else
1043 		{
1044 			ereport(NOTICE,
1045 					(errmsg("schema \"%s\" does not exist, skipping",
1046 							rel->schemaname)));
1047 		}
1048 		return;
1049 	}
1050 
1051 	for (rentry = dropmsgstringarray; rentry->kind != '\0'; rentry++)
1052 	{
1053 		if (rentry->kind == rightkind)
1054 		{
1055 			if (!missing_ok)
1056 			{
1057 				ereport(ERROR,
1058 						(errcode(rentry->nonexistent_code),
1059 						 errmsg(rentry->nonexistent_msg, rel->relname)));
1060 			}
1061 			else
1062 			{
1063 				ereport(NOTICE, (errmsg(rentry->skipping_msg, rel->relname)));
1064 				break;
1065 			}
1066 		}
1067 	}
1068 
1069 	Assert(rentry->kind != '\0');	/* Should be impossible */
1070 }
1071 
1072 /*
1073  * Emit the right error message for a "DROP" command issued on a
1074  * relation of the wrong type
1075  */
1076 static void
DropErrorMsgWrongType(const char * relname,char wrongkind,char rightkind)1077 DropErrorMsgWrongType(const char *relname, char wrongkind, char rightkind)
1078 {
1079 	const struct dropmsgstrings *rentry;
1080 	const struct dropmsgstrings *wentry;
1081 
1082 	for (rentry = dropmsgstringarray; rentry->kind != '\0'; rentry++)
1083 		if (rentry->kind == rightkind)
1084 			break;
1085 	Assert(rentry->kind != '\0');
1086 
1087 	for (wentry = dropmsgstringarray; wentry->kind != '\0'; wentry++)
1088 		if (wentry->kind == wrongkind)
1089 			break;
1090 	/* wrongkind could be something we don't have in our table... */
1091 
1092 	ereport(ERROR,
1093 			(errcode(ERRCODE_WRONG_OBJECT_TYPE),
1094 			 errmsg(rentry->nota_msg, relname),
1095 			 (wentry->kind != '\0') ? errhint("%s", _(wentry->drophint_msg)) : 0));
1096 }
1097 
1098 /*
1099  * RemoveRelations
1100  *		Implements DROP TABLE, DROP INDEX, DROP SEQUENCE, DROP VIEW,
1101  *		DROP MATERIALIZED VIEW, DROP FOREIGN TABLE
1102  */
1103 void
RemoveRelations(DropStmt * drop)1104 RemoveRelations(DropStmt *drop)
1105 {
1106 	ObjectAddresses *objects;
1107 	char		relkind;
1108 	ListCell   *cell;
1109 	int			flags = 0;
1110 	LOCKMODE	lockmode = AccessExclusiveLock;
1111 
1112 	/* DROP CONCURRENTLY uses a weaker lock, and has some restrictions */
1113 	if (drop->concurrent)
1114 	{
1115 		/*
1116 		 * Note that for temporary relations this lock may get upgraded
1117 		 * later on, but as no other session can access a temporary
1118 		 * relation, this is actually fine.
1119 		 */
1120 		lockmode = ShareUpdateExclusiveLock;
1121 		Assert(drop->removeType == OBJECT_INDEX);
1122 		if (list_length(drop->objects) != 1)
1123 			ereport(ERROR,
1124 					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1125 					 errmsg("DROP INDEX CONCURRENTLY does not support dropping multiple objects")));
1126 		if (drop->behavior == DROP_CASCADE)
1127 			ereport(ERROR,
1128 					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1129 					 errmsg("DROP INDEX CONCURRENTLY does not support CASCADE")));
1130 	}
1131 
1132 	/*
1133 	 * First we identify all the relations, then we delete them in a single
1134 	 * performMultipleDeletions() call.  This is to avoid unwanted DROP
1135 	 * RESTRICT errors if one of the relations depends on another.
1136 	 */
1137 
1138 	/* Determine required relkind */
1139 	switch (drop->removeType)
1140 	{
1141 		case OBJECT_TABLE:
1142 			relkind = RELKIND_RELATION;
1143 			break;
1144 
1145 		case OBJECT_INDEX:
1146 			relkind = RELKIND_INDEX;
1147 			break;
1148 
1149 		case OBJECT_SEQUENCE:
1150 			relkind = RELKIND_SEQUENCE;
1151 			break;
1152 
1153 		case OBJECT_VIEW:
1154 			relkind = RELKIND_VIEW;
1155 			break;
1156 
1157 		case OBJECT_MATVIEW:
1158 			relkind = RELKIND_MATVIEW;
1159 			break;
1160 
1161 		case OBJECT_FOREIGN_TABLE:
1162 			relkind = RELKIND_FOREIGN_TABLE;
1163 			break;
1164 
1165 		default:
1166 			elog(ERROR, "unrecognized drop object type: %d",
1167 				 (int) drop->removeType);
1168 			relkind = 0;		/* keep compiler quiet */
1169 			break;
1170 	}
1171 
1172 	/* Lock and validate each relation; build a list of object addresses */
1173 	objects = new_object_addresses();
1174 
1175 	foreach(cell, drop->objects)
1176 	{
1177 		RangeVar   *rel = makeRangeVarFromNameList((List *) lfirst(cell));
1178 		Oid			relOid;
1179 		ObjectAddress obj;
1180 		struct DropRelationCallbackState state;
1181 
1182 		/*
1183 		 * These next few steps are a great deal like relation_openrv, but we
1184 		 * don't bother building a relcache entry since we don't need it.
1185 		 *
1186 		 * Check for shared-cache-inval messages before trying to access the
1187 		 * relation.  This is needed to cover the case where the name
1188 		 * identifies a rel that has been dropped and recreated since the
1189 		 * start of our transaction: if we don't flush the old syscache entry,
1190 		 * then we'll latch onto that entry and suffer an error later.
1191 		 */
1192 		AcceptInvalidationMessages();
1193 
1194 		/* Look up the appropriate relation using namespace search. */
1195 		state.relkind = relkind;
1196 		state.heapOid = InvalidOid;
1197 		state.partParentOid = InvalidOid;
1198 		state.concurrent = drop->concurrent;
1199 		relOid = RangeVarGetRelidExtended(rel, lockmode, RVR_MISSING_OK,
1200 										  RangeVarCallbackForDropRelation,
1201 										  (void *) &state);
1202 
1203 		/* Not there? */
1204 		if (!OidIsValid(relOid))
1205 		{
1206 			DropErrorMsgNonExistent(rel, relkind, drop->missing_ok);
1207 			continue;
1208 		}
1209 
1210 		/*
1211 		 * Decide if concurrent mode needs to be used here or not.  The
1212 		 * relation persistence cannot be known without its OID.
1213 		 */
1214 		if (drop->concurrent &&
1215 			get_rel_persistence(relOid) != RELPERSISTENCE_TEMP)
1216 		{
1217 			Assert(list_length(drop->objects) == 1 &&
1218 				   drop->removeType == OBJECT_INDEX);
1219 			flags |= PERFORM_DELETION_CONCURRENTLY;
1220 		}
1221 
1222 		/*
1223 		 * Concurrent index drop cannot be used with partitioned indexes,
1224 		 * either.
1225 		 */
1226 		if ((flags & PERFORM_DELETION_CONCURRENTLY) != 0 &&
1227 			get_rel_relkind(relOid) == RELKIND_PARTITIONED_INDEX)
1228 			ereport(ERROR,
1229 					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1230 					 errmsg("cannot drop partitioned index \"%s\" concurrently",
1231 							rel->relname)));
1232 
1233 		/* OK, we're ready to delete this one */
1234 		obj.classId = RelationRelationId;
1235 		obj.objectId = relOid;
1236 		obj.objectSubId = 0;
1237 
1238 		add_exact_object_address(&obj, objects);
1239 	}
1240 
1241 	performMultipleDeletions(objects, drop->behavior, flags);
1242 
1243 	free_object_addresses(objects);
1244 }
1245 
1246 /*
1247  * Before acquiring a table lock, check whether we have sufficient rights.
1248  * In the case of DROP INDEX, also try to lock the table before the index.
1249  * Also, if the table to be dropped is a partition, we try to lock the parent
1250  * first.
1251  */
1252 static void
RangeVarCallbackForDropRelation(const RangeVar * rel,Oid relOid,Oid oldRelOid,void * arg)1253 RangeVarCallbackForDropRelation(const RangeVar *rel, Oid relOid, Oid oldRelOid,
1254 								void *arg)
1255 {
1256 	HeapTuple	tuple;
1257 	struct DropRelationCallbackState *state;
1258 	char		relkind;
1259 	char		expected_relkind;
1260 	bool		is_partition;
1261 	Form_pg_class classform;
1262 	LOCKMODE	heap_lockmode;
1263 
1264 	state = (struct DropRelationCallbackState *) arg;
1265 	relkind = state->relkind;
1266 	heap_lockmode = state->concurrent ?
1267 		ShareUpdateExclusiveLock : AccessExclusiveLock;
1268 
1269 	/*
1270 	 * If we previously locked some other index's heap, and the name we're
1271 	 * looking up no longer refers to that relation, release the now-useless
1272 	 * lock.
1273 	 */
1274 	if (relOid != oldRelOid && OidIsValid(state->heapOid))
1275 	{
1276 		UnlockRelationOid(state->heapOid, heap_lockmode);
1277 		state->heapOid = InvalidOid;
1278 	}
1279 
1280 	/*
1281 	 * Similarly, if we previously locked some other partition's heap, and the
1282 	 * name we're looking up no longer refers to that relation, release the
1283 	 * now-useless lock.
1284 	 */
1285 	if (relOid != oldRelOid && OidIsValid(state->partParentOid))
1286 	{
1287 		UnlockRelationOid(state->partParentOid, AccessExclusiveLock);
1288 		state->partParentOid = InvalidOid;
1289 	}
1290 
1291 	/* Didn't find a relation, so no need for locking or permission checks. */
1292 	if (!OidIsValid(relOid))
1293 		return;
1294 
1295 	tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relOid));
1296 	if (!HeapTupleIsValid(tuple))
1297 		return;					/* concurrently dropped, so nothing to do */
1298 	classform = (Form_pg_class) GETSTRUCT(tuple);
1299 	is_partition = classform->relispartition;
1300 
1301 	/*
1302 	 * Both RELKIND_RELATION and RELKIND_PARTITIONED_TABLE are OBJECT_TABLE,
1303 	 * but RemoveRelations() can only pass one relkind for a given relation.
1304 	 * It chooses RELKIND_RELATION for both regular and partitioned tables.
1305 	 * That means we must be careful before giving the wrong type error when
1306 	 * the relation is RELKIND_PARTITIONED_TABLE.  An equivalent problem
1307 	 * exists with indexes.
1308 	 */
1309 	if (classform->relkind == RELKIND_PARTITIONED_TABLE)
1310 		expected_relkind = RELKIND_RELATION;
1311 	else if (classform->relkind == RELKIND_PARTITIONED_INDEX)
1312 		expected_relkind = RELKIND_INDEX;
1313 	else
1314 		expected_relkind = classform->relkind;
1315 
1316 	if (relkind != expected_relkind)
1317 		DropErrorMsgWrongType(rel->relname, classform->relkind, relkind);
1318 
1319 	/* Allow DROP to either table owner or schema owner */
1320 	if (!pg_class_ownercheck(relOid, GetUserId()) &&
1321 		!pg_namespace_ownercheck(classform->relnamespace, GetUserId()))
1322 		aclcheck_error(ACLCHECK_NOT_OWNER, get_relkind_objtype(get_rel_relkind(relOid)),
1323 					   rel->relname);
1324 
1325 	if (!allowSystemTableMods && IsSystemClass(relOid, classform))
1326 		ereport(ERROR,
1327 				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1328 				 errmsg("permission denied: \"%s\" is a system catalog",
1329 						rel->relname)));
1330 
1331 	ReleaseSysCache(tuple);
1332 
1333 	/*
1334 	 * In DROP INDEX, attempt to acquire lock on the parent table before
1335 	 * locking the index.  index_drop() will need this anyway, and since
1336 	 * regular queries lock tables before their indexes, we risk deadlock if
1337 	 * we do it the other way around.  No error if we don't find a pg_index
1338 	 * entry, though --- the relation may have been dropped.
1339 	 */
1340 	if ((relkind == RELKIND_INDEX || relkind == RELKIND_PARTITIONED_INDEX) &&
1341 		relOid != oldRelOid)
1342 	{
1343 		state->heapOid = IndexGetRelation(relOid, true);
1344 		if (OidIsValid(state->heapOid))
1345 			LockRelationOid(state->heapOid, heap_lockmode);
1346 	}
1347 
1348 	/*
1349 	 * Similarly, if the relation is a partition, we must acquire lock on its
1350 	 * parent before locking the partition.  That's because queries lock the
1351 	 * parent before its partitions, so we risk deadlock it we do it the other
1352 	 * way around.
1353 	 */
1354 	if (is_partition && relOid != oldRelOid)
1355 	{
1356 		state->partParentOid = get_partition_parent(relOid);
1357 		if (OidIsValid(state->partParentOid))
1358 			LockRelationOid(state->partParentOid, AccessExclusiveLock);
1359 	}
1360 }
1361 
1362 /*
1363  * ExecuteTruncate
1364  *		Executes a TRUNCATE command.
1365  *
1366  * This is a multi-relation truncate.  We first open and grab exclusive
1367  * lock on all relations involved, checking permissions and otherwise
1368  * verifying that the relation is OK for truncation.  In CASCADE mode,
1369  * relations having FK references to the targeted relations are automatically
1370  * added to the group; in RESTRICT mode, we check that all FK references are
1371  * internal to the group that's being truncated.  Finally all the relations
1372  * are truncated and reindexed.
1373  */
1374 void
ExecuteTruncate(TruncateStmt * stmt)1375 ExecuteTruncate(TruncateStmt *stmt)
1376 {
1377 	List	   *rels = NIL;
1378 	List	   *relids = NIL;
1379 	List	   *relids_logged = NIL;
1380 	ListCell   *cell;
1381 
1382 	/*
1383 	 * Open, exclusive-lock, and check all the explicitly-specified relations
1384 	 */
1385 	foreach(cell, stmt->relations)
1386 	{
1387 		RangeVar   *rv = lfirst(cell);
1388 		Relation	rel;
1389 		bool		recurse = rv->inh;
1390 		Oid			myrelid;
1391 		LOCKMODE	lockmode = AccessExclusiveLock;
1392 
1393 		rel = heap_openrv(rv, lockmode);
1394 		myrelid = RelationGetRelid(rel);
1395 		/* don't throw error for "TRUNCATE foo, foo" */
1396 		if (list_member_oid(relids, myrelid))
1397 		{
1398 			heap_close(rel, lockmode);
1399 			continue;
1400 		}
1401 		truncate_check_rel(rel);
1402 		rels = lappend(rels, rel);
1403 		relids = lappend_oid(relids, myrelid);
1404 		/* Log this relation only if needed for logical decoding */
1405 		if (RelationIsLogicallyLogged(rel))
1406 			relids_logged = lappend_oid(relids_logged, myrelid);
1407 
1408 		if (recurse)
1409 		{
1410 			ListCell   *child;
1411 			List	   *children;
1412 
1413 			children = find_all_inheritors(myrelid, lockmode, NULL);
1414 
1415 			foreach(child, children)
1416 			{
1417 				Oid			childrelid = lfirst_oid(child);
1418 
1419 				if (list_member_oid(relids, childrelid))
1420 					continue;
1421 
1422 				/* find_all_inheritors already got lock */
1423 				rel = heap_open(childrelid, NoLock);
1424 
1425 				/*
1426 				 * It is possible that the parent table has children that are
1427 				 * temp tables of other backends.  We cannot safely access
1428 				 * such tables (because of buffering issues), and the best
1429 				 * thing to do is to silently ignore them.  Note that this
1430 				 * check is the same as one of the checks done in
1431 				 * truncate_check_rel() called below, still it is kept
1432 				 * here for simplicity.
1433 				 */
1434 				if (RELATION_IS_OTHER_TEMP(rel))
1435 				{
1436 					heap_close(rel, lockmode);
1437 					continue;
1438 				}
1439 
1440 				truncate_check_rel(rel);
1441 				rels = lappend(rels, rel);
1442 				relids = lappend_oid(relids, childrelid);
1443 				/* Log this relation only if needed for logical decoding */
1444 				if (RelationIsLogicallyLogged(rel))
1445 					relids_logged = lappend_oid(relids_logged, childrelid);
1446 			}
1447 		}
1448 		else if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
1449 			ereport(ERROR,
1450 					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
1451 					 errmsg("cannot truncate only a partitioned table"),
1452 					 errhint("Do not specify the ONLY keyword, or use TRUNCATE ONLY on the partitions directly.")));
1453 	}
1454 
1455 	ExecuteTruncateGuts(rels, relids, relids_logged,
1456 						stmt->behavior, stmt->restart_seqs);
1457 
1458 	/* And close the rels */
1459 	foreach(cell, rels)
1460 	{
1461 		Relation	rel = (Relation) lfirst(cell);
1462 
1463 		heap_close(rel, NoLock);
1464 	}
1465 }
1466 
1467 /*
1468  * ExecuteTruncateGuts
1469  *
1470  * Internal implementation of TRUNCATE.  This is called by the actual TRUNCATE
1471  * command (see above) as well as replication subscribers that execute a
1472  * replicated TRUNCATE action.
1473  *
1474  * explicit_rels is the list of Relations to truncate that the command
1475  * specified.  relids is the list of Oids corresponding to explicit_rels.
1476  * relids_logged is the list of Oids (a subset of relids) that require
1477  * WAL-logging.  This is all a bit redundant, but the existing callers have
1478  * this information handy in this form.
1479  */
1480 void
ExecuteTruncateGuts(List * explicit_rels,List * relids,List * relids_logged,DropBehavior behavior,bool restart_seqs)1481 ExecuteTruncateGuts(List *explicit_rels, List *relids, List *relids_logged,
1482 					DropBehavior behavior, bool restart_seqs)
1483 {
1484 	List	   *rels;
1485 	List	   *seq_relids = NIL;
1486 	EState	   *estate;
1487 	ResultRelInfo *resultRelInfos;
1488 	ResultRelInfo *resultRelInfo;
1489 	SubTransactionId mySubid;
1490 	ListCell   *cell;
1491 	Oid		   *logrelids;
1492 
1493 	/*
1494 	 * Check the explicitly-specified relations.
1495 	 *
1496 	 * In CASCADE mode, suck in all referencing relations as well.  This
1497 	 * requires multiple iterations to find indirectly-dependent relations. At
1498 	 * each phase, we need to exclusive-lock new rels before looking for their
1499 	 * dependencies, else we might miss something.  Also, we check each rel as
1500 	 * soon as we open it, to avoid a faux pas such as holding lock for a long
1501 	 * time on a rel we have no permissions for.
1502 	 */
1503 	rels = list_copy(explicit_rels);
1504 	if (behavior == DROP_CASCADE)
1505 	{
1506 		for (;;)
1507 		{
1508 			List	   *newrelids;
1509 
1510 			newrelids = heap_truncate_find_FKs(relids);
1511 			if (newrelids == NIL)
1512 				break;			/* nothing else to add */
1513 
1514 			foreach(cell, newrelids)
1515 			{
1516 				Oid			relid = lfirst_oid(cell);
1517 				Relation	rel;
1518 
1519 				rel = heap_open(relid, AccessExclusiveLock);
1520 				ereport(NOTICE,
1521 						(errmsg("truncate cascades to table \"%s\"",
1522 								RelationGetRelationName(rel))));
1523 				truncate_check_rel(rel);
1524 				rels = lappend(rels, rel);
1525 				relids = lappend_oid(relids, relid);
1526 				/* Log this relation only if needed for logical decoding */
1527 				if (RelationIsLogicallyLogged(rel))
1528 					relids_logged = lappend_oid(relids_logged, relid);
1529 			}
1530 		}
1531 	}
1532 
1533 	/*
1534 	 * Check foreign key references.  In CASCADE mode, this should be
1535 	 * unnecessary since we just pulled in all the references; but as a
1536 	 * cross-check, do it anyway if in an Assert-enabled build.
1537 	 */
1538 #ifdef USE_ASSERT_CHECKING
1539 	heap_truncate_check_FKs(rels, false);
1540 #else
1541 	if (behavior == DROP_RESTRICT)
1542 		heap_truncate_check_FKs(rels, false);
1543 #endif
1544 
1545 	/*
1546 	 * If we are asked to restart sequences, find all the sequences, lock them
1547 	 * (we need AccessExclusiveLock for ResetSequence), and check permissions.
1548 	 * We want to do this early since it's pointless to do all the truncation
1549 	 * work only to fail on sequence permissions.
1550 	 */
1551 	if (restart_seqs)
1552 	{
1553 		foreach(cell, rels)
1554 		{
1555 			Relation	rel = (Relation) lfirst(cell);
1556 			List	   *seqlist = getOwnedSequences(RelationGetRelid(rel), 0);
1557 			ListCell   *seqcell;
1558 
1559 			foreach(seqcell, seqlist)
1560 			{
1561 				Oid			seq_relid = lfirst_oid(seqcell);
1562 				Relation	seq_rel;
1563 
1564 				seq_rel = relation_open(seq_relid, AccessExclusiveLock);
1565 
1566 				/* This check must match AlterSequence! */
1567 				if (!pg_class_ownercheck(seq_relid, GetUserId()))
1568 					aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_SEQUENCE,
1569 								   RelationGetRelationName(seq_rel));
1570 
1571 				seq_relids = lappend_oid(seq_relids, seq_relid);
1572 
1573 				relation_close(seq_rel, NoLock);
1574 			}
1575 		}
1576 	}
1577 
1578 	/* Prepare to catch AFTER triggers. */
1579 	AfterTriggerBeginQuery();
1580 
1581 	/*
1582 	 * To fire triggers, we'll need an EState as well as a ResultRelInfo for
1583 	 * each relation.  We don't need to call ExecOpenIndices, though.
1584 	 */
1585 	estate = CreateExecutorState();
1586 	resultRelInfos = (ResultRelInfo *)
1587 		palloc(list_length(rels) * sizeof(ResultRelInfo));
1588 	resultRelInfo = resultRelInfos;
1589 	foreach(cell, rels)
1590 	{
1591 		Relation	rel = (Relation) lfirst(cell);
1592 
1593 		InitResultRelInfo(resultRelInfo,
1594 						  rel,
1595 						  0,	/* dummy rangetable index */
1596 						  NULL,
1597 						  0);
1598 		resultRelInfo++;
1599 	}
1600 	estate->es_result_relations = resultRelInfos;
1601 	estate->es_num_result_relations = list_length(rels);
1602 
1603 	/*
1604 	 * Process all BEFORE STATEMENT TRUNCATE triggers before we begin
1605 	 * truncating (this is because one of them might throw an error). Also, if
1606 	 * we were to allow them to prevent statement execution, that would need
1607 	 * to be handled here.
1608 	 */
1609 	resultRelInfo = resultRelInfos;
1610 	foreach(cell, rels)
1611 	{
1612 		estate->es_result_relation_info = resultRelInfo;
1613 		ExecBSTruncateTriggers(estate, resultRelInfo);
1614 		resultRelInfo++;
1615 	}
1616 
1617 	/*
1618 	 * OK, truncate each table.
1619 	 */
1620 	mySubid = GetCurrentSubTransactionId();
1621 
1622 	foreach(cell, rels)
1623 	{
1624 		Relation	rel = (Relation) lfirst(cell);
1625 
1626 		/* Skip partitioned tables as there is nothing to do */
1627 		if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
1628 			continue;
1629 
1630 		/*
1631 		 * Normally, we need a transaction-safe truncation here.  However, if
1632 		 * the table was either created in the current (sub)transaction or has
1633 		 * a new relfilenode in the current (sub)transaction, then we can just
1634 		 * truncate it in-place, because a rollback would cause the whole
1635 		 * table or the current physical file to be thrown away anyway.
1636 		 */
1637 		if (rel->rd_createSubid == mySubid ||
1638 			rel->rd_newRelfilenodeSubid == mySubid)
1639 		{
1640 			/* Immediate, non-rollbackable truncation is OK */
1641 			heap_truncate_one_rel(rel);
1642 		}
1643 		else
1644 		{
1645 			Oid			heap_relid;
1646 			Oid			toast_relid;
1647 			MultiXactId minmulti;
1648 
1649 			/*
1650 			 * This effectively deletes all rows in the table, and may be done
1651 			 * in a serializable transaction.  In that case we must record a
1652 			 * rw-conflict in to this transaction from each transaction
1653 			 * holding a predicate lock on the table.
1654 			 */
1655 			CheckTableForSerializableConflictIn(rel);
1656 
1657 			minmulti = GetOldestMultiXactId();
1658 
1659 			/*
1660 			 * Need the full transaction-safe pushups.
1661 			 *
1662 			 * Create a new empty storage file for the relation, and assign it
1663 			 * as the relfilenode value. The old storage file is scheduled for
1664 			 * deletion at commit.
1665 			 */
1666 			RelationSetNewRelfilenode(rel, rel->rd_rel->relpersistence,
1667 									  RecentXmin, minmulti);
1668 			if (rel->rd_rel->relpersistence == RELPERSISTENCE_UNLOGGED)
1669 				heap_create_init_fork(rel);
1670 
1671 			heap_relid = RelationGetRelid(rel);
1672 
1673 			/*
1674 			 * The same for the toast table, if any.
1675 			 */
1676 			toast_relid = rel->rd_rel->reltoastrelid;
1677 			if (OidIsValid(toast_relid))
1678 			{
1679 				Relation	toastrel = relation_open(toast_relid,
1680 													 AccessExclusiveLock);
1681 
1682 				RelationSetNewRelfilenode(toastrel,
1683 										  toastrel->rd_rel->relpersistence,
1684 										  RecentXmin, minmulti);
1685 				if (toastrel->rd_rel->relpersistence == RELPERSISTENCE_UNLOGGED)
1686 					heap_create_init_fork(toastrel);
1687 				heap_close(toastrel, NoLock);
1688 			}
1689 
1690 			/*
1691 			 * Reconstruct the indexes to match, and we're done.
1692 			 */
1693 			reindex_relation(heap_relid, REINDEX_REL_PROCESS_TOAST, 0);
1694 		}
1695 
1696 		pgstat_count_truncate(rel);
1697 	}
1698 
1699 	/*
1700 	 * Restart owned sequences if we were asked to.
1701 	 */
1702 	foreach(cell, seq_relids)
1703 	{
1704 		Oid			seq_relid = lfirst_oid(cell);
1705 
1706 		ResetSequence(seq_relid);
1707 	}
1708 
1709 	/*
1710 	 * Write a WAL record to allow this set of actions to be logically
1711 	 * decoded.
1712 	 *
1713 	 * Assemble an array of relids so we can write a single WAL record for the
1714 	 * whole action.
1715 	 */
1716 	if (list_length(relids_logged) > 0)
1717 	{
1718 		xl_heap_truncate xlrec;
1719 		int			i = 0;
1720 
1721 		/* should only get here if wal_level >= logical */
1722 		Assert(XLogLogicalInfoActive());
1723 
1724 		logrelids = palloc(list_length(relids_logged) * sizeof(Oid));
1725 		foreach(cell, relids_logged)
1726 			logrelids[i++] = lfirst_oid(cell);
1727 
1728 		xlrec.dbId = MyDatabaseId;
1729 		xlrec.nrelids = list_length(relids_logged);
1730 		xlrec.flags = 0;
1731 		if (behavior == DROP_CASCADE)
1732 			xlrec.flags |= XLH_TRUNCATE_CASCADE;
1733 		if (restart_seqs)
1734 			xlrec.flags |= XLH_TRUNCATE_RESTART_SEQS;
1735 
1736 		XLogBeginInsert();
1737 		XLogRegisterData((char *) &xlrec, SizeOfHeapTruncate);
1738 		XLogRegisterData((char *) logrelids, list_length(relids_logged) * sizeof(Oid));
1739 
1740 		XLogSetRecordFlags(XLOG_INCLUDE_ORIGIN);
1741 
1742 		(void) XLogInsert(RM_HEAP_ID, XLOG_HEAP_TRUNCATE);
1743 	}
1744 
1745 	/*
1746 	 * Process all AFTER STATEMENT TRUNCATE triggers.
1747 	 */
1748 	resultRelInfo = resultRelInfos;
1749 	foreach(cell, rels)
1750 	{
1751 		estate->es_result_relation_info = resultRelInfo;
1752 		ExecASTruncateTriggers(estate, resultRelInfo);
1753 		resultRelInfo++;
1754 	}
1755 
1756 	/* Handle queued AFTER triggers */
1757 	AfterTriggerEndQuery(estate);
1758 
1759 	/* We can clean up the EState now */
1760 	FreeExecutorState(estate);
1761 
1762 	/*
1763 	 * Close any rels opened by CASCADE (can't do this while EState still
1764 	 * holds refs)
1765 	 */
1766 	rels = list_difference_ptr(rels, explicit_rels);
1767 	foreach(cell, rels)
1768 	{
1769 		Relation	rel = (Relation) lfirst(cell);
1770 
1771 		heap_close(rel, NoLock);
1772 	}
1773 }
1774 
1775 /*
1776  * Check that a given rel is safe to truncate.  Subroutine for ExecuteTruncate
1777  */
1778 static void
truncate_check_rel(Relation rel)1779 truncate_check_rel(Relation rel)
1780 {
1781 	AclResult	aclresult;
1782 
1783 	/*
1784 	 * Only allow truncate on regular tables and partitioned tables (although,
1785 	 * the latter are only being included here for the following checks; no
1786 	 * physical truncation will occur in their case.)
1787 	 */
1788 	if (rel->rd_rel->relkind != RELKIND_RELATION &&
1789 		rel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
1790 		ereport(ERROR,
1791 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
1792 				 errmsg("\"%s\" is not a table",
1793 						RelationGetRelationName(rel))));
1794 
1795 	/* Permissions checks */
1796 	aclresult = pg_class_aclcheck(RelationGetRelid(rel), GetUserId(),
1797 								  ACL_TRUNCATE);
1798 	if (aclresult != ACLCHECK_OK)
1799 		aclcheck_error(aclresult, get_relkind_objtype(rel->rd_rel->relkind),
1800 					   RelationGetRelationName(rel));
1801 
1802 	if (!allowSystemTableMods && IsSystemRelation(rel))
1803 		ereport(ERROR,
1804 				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1805 				 errmsg("permission denied: \"%s\" is a system catalog",
1806 						RelationGetRelationName(rel))));
1807 
1808 	/*
1809 	 * Don't allow truncate on temp tables of other backends ... their local
1810 	 * buffer manager is not going to cope.
1811 	 */
1812 	if (RELATION_IS_OTHER_TEMP(rel))
1813 		ereport(ERROR,
1814 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1815 				 errmsg("cannot truncate temporary tables of other sessions")));
1816 
1817 	/*
1818 	 * Also check for active uses of the relation in the current transaction,
1819 	 * including open scans and pending AFTER trigger events.
1820 	 */
1821 	CheckTableNotInUse(rel, "TRUNCATE");
1822 }
1823 
1824 /*
1825  * storage_name
1826  *	  returns the name corresponding to a typstorage/attstorage enum value
1827  */
1828 static const char *
storage_name(char c)1829 storage_name(char c)
1830 {
1831 	switch (c)
1832 	{
1833 		case 'p':
1834 			return "PLAIN";
1835 		case 'm':
1836 			return "MAIN";
1837 		case 'x':
1838 			return "EXTENDED";
1839 		case 'e':
1840 			return "EXTERNAL";
1841 		default:
1842 			return "???";
1843 	}
1844 }
1845 
1846 /*----------
1847  * MergeAttributes
1848  *		Returns new schema given initial schema and superclasses.
1849  *
1850  * Input arguments:
1851  * 'schema' is the column/attribute definition for the table. (It's a list
1852  *		of ColumnDef's.) It is destructively changed.
1853  * 'supers' is a list of names (as RangeVar nodes) of parent relations.
1854  * 'relpersistence' is a persistence type of the table.
1855  * 'is_partition' tells if the table is a partition
1856  *
1857  * Output arguments:
1858  * 'supOids' receives a list of the OIDs of the parent relations.
1859  * 'supconstr' receives a list of constraints belonging to the parents,
1860  *		updated as necessary to be valid for the child.
1861  * 'supOidCount' is set to the number of parents that have OID columns.
1862  *
1863  * Return value:
1864  * Completed schema list.
1865  *
1866  * Notes:
1867  *	  The order in which the attributes are inherited is very important.
1868  *	  Intuitively, the inherited attributes should come first. If a table
1869  *	  inherits from multiple parents, the order of those attributes are
1870  *	  according to the order of the parents specified in CREATE TABLE.
1871  *
1872  *	  Here's an example:
1873  *
1874  *		create table person (name text, age int4, location point);
1875  *		create table emp (salary int4, manager text) inherits(person);
1876  *		create table student (gpa float8) inherits (person);
1877  *		create table stud_emp (percent int4) inherits (emp, student);
1878  *
1879  *	  The order of the attributes of stud_emp is:
1880  *
1881  *							person {1:name, 2:age, 3:location}
1882  *							/	 \
1883  *			   {6:gpa}	student   emp {4:salary, 5:manager}
1884  *							\	 /
1885  *						   stud_emp {7:percent}
1886  *
1887  *	   If the same attribute name appears multiple times, then it appears
1888  *	   in the result table in the proper location for its first appearance.
1889  *
1890  *	   Constraints (including NOT NULL constraints) for the child table
1891  *	   are the union of all relevant constraints, from both the child schema
1892  *	   and parent tables.
1893  *
1894  *	   The default value for a child column is defined as:
1895  *		(1) If the child schema specifies a default, that value is used.
1896  *		(2) If neither the child nor any parent specifies a default, then
1897  *			the column will not have a default.
1898  *		(3) If conflicting defaults are inherited from different parents
1899  *			(and not overridden by the child), an error is raised.
1900  *		(4) Otherwise the inherited default is used.
1901  *		Rule (3) is new in Postgres 7.1; in earlier releases you got a
1902  *		rather arbitrary choice of which parent default to use.
1903  *----------
1904  */
1905 static List *
MergeAttributes(List * schema,List * supers,char relpersistence,bool is_partition,List ** supOids,List ** supconstr,int * supOidCount)1906 MergeAttributes(List *schema, List *supers, char relpersistence,
1907 				bool is_partition, List **supOids, List **supconstr,
1908 				int *supOidCount)
1909 {
1910 	ListCell   *entry;
1911 	List	   *inhSchema = NIL;
1912 	List	   *parentOids = NIL;
1913 	List	   *constraints = NIL;
1914 	int			parentsWithOids = 0;
1915 	bool		have_bogus_defaults = false;
1916 	int			child_attno;
1917 	static Node bogus_marker = {0}; /* marks conflicting defaults */
1918 	List	   *saved_schema = NIL;
1919 
1920 	/*
1921 	 * Check for and reject tables with too many columns. We perform this
1922 	 * check relatively early for two reasons: (a) we don't run the risk of
1923 	 * overflowing an AttrNumber in subsequent code (b) an O(n^2) algorithm is
1924 	 * okay if we're processing <= 1600 columns, but could take minutes to
1925 	 * execute if the user attempts to create a table with hundreds of
1926 	 * thousands of columns.
1927 	 *
1928 	 * Note that we also need to check that we do not exceed this figure after
1929 	 * including columns from inherited relations.
1930 	 */
1931 	if (list_length(schema) > MaxHeapAttributeNumber)
1932 		ereport(ERROR,
1933 				(errcode(ERRCODE_TOO_MANY_COLUMNS),
1934 				 errmsg("tables can have at most %d columns",
1935 						MaxHeapAttributeNumber)));
1936 
1937 	/*
1938 	 * Check for duplicate names in the explicit list of attributes.
1939 	 *
1940 	 * Although we might consider merging such entries in the same way that we
1941 	 * handle name conflicts for inherited attributes, it seems to make more
1942 	 * sense to assume such conflicts are errors.
1943 	 */
1944 	foreach(entry, schema)
1945 	{
1946 		ColumnDef  *coldef = lfirst(entry);
1947 		ListCell   *rest = lnext(entry);
1948 		ListCell   *prev = entry;
1949 
1950 		if (!is_partition && coldef->typeName == NULL)
1951 		{
1952 			/*
1953 			 * Typed table column option that does not belong to a column from
1954 			 * the type.  This works because the columns from the type come
1955 			 * first in the list.  (We omit this check for partition column
1956 			 * lists; those are processed separately below.)
1957 			 */
1958 			ereport(ERROR,
1959 					(errcode(ERRCODE_UNDEFINED_COLUMN),
1960 					 errmsg("column \"%s\" does not exist",
1961 							coldef->colname)));
1962 		}
1963 
1964 		while (rest != NULL)
1965 		{
1966 			ColumnDef  *restdef = lfirst(rest);
1967 			ListCell   *next = lnext(rest); /* need to save it in case we
1968 											 * delete it */
1969 
1970 			if (strcmp(coldef->colname, restdef->colname) == 0)
1971 			{
1972 				if (coldef->is_from_type)
1973 				{
1974 					/*
1975 					 * merge the column options into the column from the type
1976 					 */
1977 					coldef->is_not_null = restdef->is_not_null;
1978 					coldef->raw_default = restdef->raw_default;
1979 					coldef->cooked_default = restdef->cooked_default;
1980 					coldef->constraints = restdef->constraints;
1981 					coldef->is_from_type = false;
1982 					list_delete_cell(schema, rest, prev);
1983 				}
1984 				else
1985 					ereport(ERROR,
1986 							(errcode(ERRCODE_DUPLICATE_COLUMN),
1987 							 errmsg("column \"%s\" specified more than once",
1988 									coldef->colname)));
1989 			}
1990 			prev = rest;
1991 			rest = next;
1992 		}
1993 	}
1994 
1995 	/*
1996 	 * In case of a partition, there are no new column definitions, only dummy
1997 	 * ColumnDefs created for column constraints.  Set them aside for now and
1998 	 * process them at the end.
1999 	 */
2000 	if (is_partition)
2001 	{
2002 		saved_schema = schema;
2003 		schema = NIL;
2004 	}
2005 
2006 	/*
2007 	 * Scan the parents left-to-right, and merge their attributes to form a
2008 	 * list of inherited attributes (inhSchema).  Also check to see if we need
2009 	 * to inherit an OID column.
2010 	 */
2011 	child_attno = 0;
2012 	foreach(entry, supers)
2013 	{
2014 		RangeVar   *parent = (RangeVar *) lfirst(entry);
2015 		Relation	relation;
2016 		TupleDesc	tupleDesc;
2017 		TupleConstr *constr;
2018 		AttrNumber *newattno;
2019 		AttrNumber	parent_attno;
2020 
2021 		/*
2022 		 * A self-exclusive lock is needed here.  If two backends attempt to
2023 		 * add children to the same parent simultaneously, and that parent has
2024 		 * no pre-existing children, then both will attempt to update the
2025 		 * parent's relhassubclass field, leading to a "tuple concurrently
2026 		 * updated" error.  Also, this interlocks against a concurrent ANALYZE
2027 		 * on the parent table, which might otherwise be attempting to clear
2028 		 * the parent's relhassubclass field, if its previous children were
2029 		 * recently dropped.
2030 		 *
2031 		 * If the child table is a partition, then we instead grab an
2032 		 * exclusive lock on the parent because its partition descriptor will
2033 		 * be changed by addition of the new partition.
2034 		 */
2035 		if (!is_partition)
2036 			relation = heap_openrv(parent, ShareUpdateExclusiveLock);
2037 		else
2038 			relation = heap_openrv(parent, AccessExclusiveLock);
2039 
2040 		/*
2041 		 * Check for active uses of the parent partitioned table in the
2042 		 * current transaction, such as being used in some manner by an
2043 		 * enclosing command.
2044 		 */
2045 		if (is_partition)
2046 			CheckTableNotInUse(relation, "CREATE TABLE .. PARTITION OF");
2047 
2048 		/*
2049 		 * We do not allow partitioned tables and partitions to participate in
2050 		 * regular inheritance.
2051 		 */
2052 		if (relation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE &&
2053 			!is_partition)
2054 			ereport(ERROR,
2055 					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
2056 					 errmsg("cannot inherit from partitioned table \"%s\"",
2057 							parent->relname)));
2058 		if (relation->rd_rel->relispartition && !is_partition)
2059 			ereport(ERROR,
2060 					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
2061 					 errmsg("cannot inherit from partition \"%s\"",
2062 							parent->relname)));
2063 
2064 		if (relation->rd_rel->relkind != RELKIND_RELATION &&
2065 			relation->rd_rel->relkind != RELKIND_FOREIGN_TABLE &&
2066 			relation->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
2067 			ereport(ERROR,
2068 					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
2069 					 errmsg("inherited relation \"%s\" is not a table or foreign table",
2070 							parent->relname)));
2071 
2072 		/*
2073 		 * If the parent is permanent, so must be all of its partitions.  Note
2074 		 * that inheritance allows that case.
2075 		 */
2076 		if (is_partition &&
2077 			relation->rd_rel->relpersistence != RELPERSISTENCE_TEMP &&
2078 			relpersistence == RELPERSISTENCE_TEMP)
2079 			ereport(ERROR,
2080 					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
2081 					 errmsg("cannot create a temporary relation as partition of permanent relation \"%s\"",
2082 							RelationGetRelationName(relation))));
2083 
2084 		/* Permanent rels cannot inherit from temporary ones */
2085 		if (relpersistence != RELPERSISTENCE_TEMP &&
2086 			relation->rd_rel->relpersistence == RELPERSISTENCE_TEMP)
2087 			ereport(ERROR,
2088 					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
2089 					 errmsg(!is_partition
2090 							? "cannot inherit from temporary relation \"%s\""
2091 							: "cannot create a permanent relation as partition of temporary relation \"%s\"",
2092 							parent->relname)));
2093 
2094 		/* If existing rel is temp, it must belong to this session */
2095 		if (relation->rd_rel->relpersistence == RELPERSISTENCE_TEMP &&
2096 			!relation->rd_islocaltemp)
2097 			ereport(ERROR,
2098 					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
2099 					 errmsg(!is_partition
2100 							? "cannot inherit from temporary relation of another session"
2101 							: "cannot create as partition of temporary relation of another session")));
2102 
2103 		/*
2104 		 * We should have an UNDER permission flag for this, but for now,
2105 		 * demand that creator of a child table own the parent.
2106 		 */
2107 		if (!pg_class_ownercheck(RelationGetRelid(relation), GetUserId()))
2108 			aclcheck_error(ACLCHECK_NOT_OWNER, get_relkind_objtype(relation->rd_rel->relkind),
2109 						   RelationGetRelationName(relation));
2110 
2111 		/*
2112 		 * Reject duplications in the list of parents.
2113 		 */
2114 		if (list_member_oid(parentOids, RelationGetRelid(relation)))
2115 			ereport(ERROR,
2116 					(errcode(ERRCODE_DUPLICATE_TABLE),
2117 					 errmsg("relation \"%s\" would be inherited from more than once",
2118 							parent->relname)));
2119 
2120 		parentOids = lappend_oid(parentOids, RelationGetRelid(relation));
2121 
2122 		if (relation->rd_rel->relhasoids)
2123 			parentsWithOids++;
2124 
2125 		tupleDesc = RelationGetDescr(relation);
2126 		constr = tupleDesc->constr;
2127 
2128 		/*
2129 		 * newattno[] will contain the child-table attribute numbers for the
2130 		 * attributes of this parent table.  (They are not the same for
2131 		 * parents after the first one, nor if we have dropped columns.)
2132 		 */
2133 		newattno = (AttrNumber *)
2134 			palloc0(tupleDesc->natts * sizeof(AttrNumber));
2135 
2136 		for (parent_attno = 1; parent_attno <= tupleDesc->natts;
2137 			 parent_attno++)
2138 		{
2139 			Form_pg_attribute attribute = TupleDescAttr(tupleDesc,
2140 														parent_attno - 1);
2141 			char	   *attributeName = NameStr(attribute->attname);
2142 			int			exist_attno;
2143 			ColumnDef  *def;
2144 
2145 			/*
2146 			 * Ignore dropped columns in the parent.
2147 			 */
2148 			if (attribute->attisdropped)
2149 				continue;		/* leave newattno entry as zero */
2150 
2151 			/*
2152 			 * Does it conflict with some previously inherited column?
2153 			 */
2154 			exist_attno = findAttrByName(attributeName, inhSchema);
2155 			if (exist_attno > 0)
2156 			{
2157 				Oid			defTypeId;
2158 				int32		deftypmod;
2159 				Oid			defCollId;
2160 
2161 				/*
2162 				 * Yes, try to merge the two column definitions. They must
2163 				 * have the same type, typmod, and collation.
2164 				 */
2165 				ereport(NOTICE,
2166 						(errmsg("merging multiple inherited definitions of column \"%s\"",
2167 								attributeName)));
2168 				def = (ColumnDef *) list_nth(inhSchema, exist_attno - 1);
2169 				typenameTypeIdAndMod(NULL, def->typeName, &defTypeId, &deftypmod);
2170 				if (defTypeId != attribute->atttypid ||
2171 					deftypmod != attribute->atttypmod)
2172 					ereport(ERROR,
2173 							(errcode(ERRCODE_DATATYPE_MISMATCH),
2174 							 errmsg("inherited column \"%s\" has a type conflict",
2175 									attributeName),
2176 							 errdetail("%s versus %s",
2177 									   format_type_with_typemod(defTypeId,
2178 																deftypmod),
2179 									   format_type_with_typemod(attribute->atttypid,
2180 																attribute->atttypmod))));
2181 				defCollId = GetColumnDefCollation(NULL, def, defTypeId);
2182 				if (defCollId != attribute->attcollation)
2183 					ereport(ERROR,
2184 							(errcode(ERRCODE_COLLATION_MISMATCH),
2185 							 errmsg("inherited column \"%s\" has a collation conflict",
2186 									attributeName),
2187 							 errdetail("\"%s\" versus \"%s\"",
2188 									   get_collation_name(defCollId),
2189 									   get_collation_name(attribute->attcollation))));
2190 
2191 				/* Copy storage parameter */
2192 				if (def->storage == 0)
2193 					def->storage = attribute->attstorage;
2194 				else if (def->storage != attribute->attstorage)
2195 					ereport(ERROR,
2196 							(errcode(ERRCODE_DATATYPE_MISMATCH),
2197 							 errmsg("inherited column \"%s\" has a storage parameter conflict",
2198 									attributeName),
2199 							 errdetail("%s versus %s",
2200 									   storage_name(def->storage),
2201 									   storage_name(attribute->attstorage))));
2202 
2203 				def->inhcount++;
2204 				/* Merge of NOT NULL constraints = OR 'em together */
2205 				def->is_not_null |= attribute->attnotnull;
2206 				/* Default and other constraints are handled below */
2207 				newattno[parent_attno - 1] = exist_attno;
2208 			}
2209 			else
2210 			{
2211 				/*
2212 				 * No, create a new inherited column
2213 				 */
2214 				def = makeNode(ColumnDef);
2215 				def->colname = pstrdup(attributeName);
2216 				def->typeName = makeTypeNameFromOid(attribute->atttypid,
2217 													attribute->atttypmod);
2218 				def->inhcount = 1;
2219 				def->is_local = false;
2220 				def->is_not_null = attribute->attnotnull;
2221 				def->is_from_type = false;
2222 				def->storage = attribute->attstorage;
2223 				def->raw_default = NULL;
2224 				def->cooked_default = NULL;
2225 				def->collClause = NULL;
2226 				def->collOid = attribute->attcollation;
2227 				def->constraints = NIL;
2228 				def->location = -1;
2229 				inhSchema = lappend(inhSchema, def);
2230 				newattno[parent_attno - 1] = ++child_attno;
2231 			}
2232 
2233 			/*
2234 			 * Copy default if any
2235 			 */
2236 			if (attribute->atthasdef)
2237 			{
2238 				Node	   *this_default = NULL;
2239 				AttrDefault *attrdef;
2240 				int			i;
2241 
2242 				/* Find default in constraint structure */
2243 				Assert(constr != NULL);
2244 				attrdef = constr->defval;
2245 				for (i = 0; i < constr->num_defval; i++)
2246 				{
2247 					if (attrdef[i].adnum == parent_attno)
2248 					{
2249 						this_default = stringToNode(attrdef[i].adbin);
2250 						break;
2251 					}
2252 				}
2253 				Assert(this_default != NULL);
2254 
2255 				/*
2256 				 * If default expr could contain any vars, we'd need to fix
2257 				 * 'em, but it can't; so default is ready to apply to child.
2258 				 *
2259 				 * If we already had a default from some prior parent, check
2260 				 * to see if they are the same.  If so, no problem; if not,
2261 				 * mark the column as having a bogus default. Below, we will
2262 				 * complain if the bogus default isn't overridden by the child
2263 				 * schema.
2264 				 */
2265 				Assert(def->raw_default == NULL);
2266 				if (def->cooked_default == NULL)
2267 					def->cooked_default = this_default;
2268 				else if (!equal(def->cooked_default, this_default))
2269 				{
2270 					def->cooked_default = &bogus_marker;
2271 					have_bogus_defaults = true;
2272 				}
2273 			}
2274 		}
2275 
2276 		/*
2277 		 * Now copy the CHECK constraints of this parent, adjusting attnos
2278 		 * using the completed newattno[] map.  Identically named constraints
2279 		 * are merged if possible, else we throw error.
2280 		 */
2281 		if (constr && constr->num_check > 0)
2282 		{
2283 			ConstrCheck *check = constr->check;
2284 			int			i;
2285 
2286 			for (i = 0; i < constr->num_check; i++)
2287 			{
2288 				char	   *name = check[i].ccname;
2289 				Node	   *expr;
2290 				bool		found_whole_row;
2291 
2292 				/* ignore if the constraint is non-inheritable */
2293 				if (check[i].ccnoinherit)
2294 					continue;
2295 
2296 				/* Adjust Vars to match new table's column numbering */
2297 				expr = map_variable_attnos(stringToNode(check[i].ccbin),
2298 										   1, 0,
2299 										   newattno, tupleDesc->natts,
2300 										   InvalidOid, &found_whole_row);
2301 
2302 				/*
2303 				 * For the moment we have to reject whole-row variables. We
2304 				 * could convert them, if we knew the new table's rowtype OID,
2305 				 * but that hasn't been assigned yet.
2306 				 */
2307 				if (found_whole_row)
2308 					ereport(ERROR,
2309 							(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2310 							 errmsg("cannot convert whole-row table reference"),
2311 							 errdetail("Constraint \"%s\" contains a whole-row reference to table \"%s\".",
2312 									   name,
2313 									   RelationGetRelationName(relation))));
2314 
2315 				/* check for duplicate */
2316 				if (!MergeCheckConstraint(constraints, name, expr))
2317 				{
2318 					/* nope, this is a new one */
2319 					CookedConstraint *cooked;
2320 
2321 					cooked = (CookedConstraint *) palloc(sizeof(CookedConstraint));
2322 					cooked->contype = CONSTR_CHECK;
2323 					cooked->conoid = InvalidOid;	/* until created */
2324 					cooked->name = pstrdup(name);
2325 					cooked->attnum = 0; /* not used for constraints */
2326 					cooked->expr = expr;
2327 					cooked->skip_validation = false;
2328 					cooked->is_local = false;
2329 					cooked->inhcount = 1;
2330 					cooked->is_no_inherit = false;
2331 					constraints = lappend(constraints, cooked);
2332 				}
2333 			}
2334 		}
2335 
2336 		pfree(newattno);
2337 
2338 		/*
2339 		 * Close the parent rel, but keep our lock on it until xact commit.
2340 		 * That will prevent someone else from deleting or ALTERing the parent
2341 		 * before the child is committed.
2342 		 */
2343 		heap_close(relation, NoLock);
2344 	}
2345 
2346 	/*
2347 	 * If we had no inherited attributes, the result schema is just the
2348 	 * explicitly declared columns.  Otherwise, we need to merge the declared
2349 	 * columns into the inherited schema list.  Although, we never have any
2350 	 * explicitly declared columns if the table is a partition.
2351 	 */
2352 	if (inhSchema != NIL)
2353 	{
2354 		int			schema_attno = 0;
2355 
2356 		foreach(entry, schema)
2357 		{
2358 			ColumnDef  *newdef = lfirst(entry);
2359 			char	   *attributeName = newdef->colname;
2360 			int			exist_attno;
2361 
2362 			schema_attno++;
2363 
2364 			/*
2365 			 * Does it conflict with some previously inherited column?
2366 			 */
2367 			exist_attno = findAttrByName(attributeName, inhSchema);
2368 			if (exist_attno > 0)
2369 			{
2370 				ColumnDef  *def;
2371 				Oid			defTypeId,
2372 							newTypeId;
2373 				int32		deftypmod,
2374 							newtypmod;
2375 				Oid			defcollid,
2376 							newcollid;
2377 
2378 				/*
2379 				 * Partitions have only one parent and have no column
2380 				 * definitions of their own, so conflict should never occur.
2381 				 */
2382 				Assert(!is_partition);
2383 
2384 				/*
2385 				 * Yes, try to merge the two column definitions. They must
2386 				 * have the same type, typmod, and collation.
2387 				 */
2388 				if (exist_attno == schema_attno)
2389 					ereport(NOTICE,
2390 							(errmsg("merging column \"%s\" with inherited definition",
2391 									attributeName)));
2392 				else
2393 					ereport(NOTICE,
2394 							(errmsg("moving and merging column \"%s\" with inherited definition", attributeName),
2395 							 errdetail("User-specified column moved to the position of the inherited column.")));
2396 				def = (ColumnDef *) list_nth(inhSchema, exist_attno - 1);
2397 				typenameTypeIdAndMod(NULL, def->typeName, &defTypeId, &deftypmod);
2398 				typenameTypeIdAndMod(NULL, newdef->typeName, &newTypeId, &newtypmod);
2399 				if (defTypeId != newTypeId || deftypmod != newtypmod)
2400 					ereport(ERROR,
2401 							(errcode(ERRCODE_DATATYPE_MISMATCH),
2402 							 errmsg("column \"%s\" has a type conflict",
2403 									attributeName),
2404 							 errdetail("%s versus %s",
2405 									   format_type_with_typemod(defTypeId,
2406 																deftypmod),
2407 									   format_type_with_typemod(newTypeId,
2408 																newtypmod))));
2409 				defcollid = GetColumnDefCollation(NULL, def, defTypeId);
2410 				newcollid = GetColumnDefCollation(NULL, newdef, newTypeId);
2411 				if (defcollid != newcollid)
2412 					ereport(ERROR,
2413 							(errcode(ERRCODE_COLLATION_MISMATCH),
2414 							 errmsg("column \"%s\" has a collation conflict",
2415 									attributeName),
2416 							 errdetail("\"%s\" versus \"%s\"",
2417 									   get_collation_name(defcollid),
2418 									   get_collation_name(newcollid))));
2419 
2420 				/*
2421 				 * Identity is never inherited.  The new column can have an
2422 				 * identity definition, so we always just take that one.
2423 				 */
2424 				def->identity = newdef->identity;
2425 
2426 				/* Copy storage parameter */
2427 				if (def->storage == 0)
2428 					def->storage = newdef->storage;
2429 				else if (newdef->storage != 0 && def->storage != newdef->storage)
2430 					ereport(ERROR,
2431 							(errcode(ERRCODE_DATATYPE_MISMATCH),
2432 							 errmsg("column \"%s\" has a storage parameter conflict",
2433 									attributeName),
2434 							 errdetail("%s versus %s",
2435 									   storage_name(def->storage),
2436 									   storage_name(newdef->storage))));
2437 
2438 				/* Mark the column as locally defined */
2439 				def->is_local = true;
2440 				/* Merge of NOT NULL constraints = OR 'em together */
2441 				def->is_not_null |= newdef->is_not_null;
2442 				/* If new def has a default, override previous default */
2443 				if (newdef->raw_default != NULL)
2444 				{
2445 					def->raw_default = newdef->raw_default;
2446 					def->cooked_default = newdef->cooked_default;
2447 				}
2448 			}
2449 			else
2450 			{
2451 				/*
2452 				 * No, attach new column to result schema
2453 				 */
2454 				inhSchema = lappend(inhSchema, newdef);
2455 			}
2456 		}
2457 
2458 		schema = inhSchema;
2459 
2460 		/*
2461 		 * Check that we haven't exceeded the legal # of columns after merging
2462 		 * in inherited columns.
2463 		 */
2464 		if (list_length(schema) > MaxHeapAttributeNumber)
2465 			ereport(ERROR,
2466 					(errcode(ERRCODE_TOO_MANY_COLUMNS),
2467 					 errmsg("tables can have at most %d columns",
2468 							MaxHeapAttributeNumber)));
2469 	}
2470 
2471 	/*
2472 	 * Now that we have the column definition list for a partition, we can
2473 	 * check whether the columns referenced in the column constraint specs
2474 	 * actually exist.  Also, we merge NOT NULL and defaults into each
2475 	 * corresponding column definition.
2476 	 */
2477 	if (is_partition)
2478 	{
2479 		foreach(entry, saved_schema)
2480 		{
2481 			ColumnDef  *restdef = lfirst(entry);
2482 			bool		found = false;
2483 			ListCell   *l;
2484 
2485 			foreach(l, schema)
2486 			{
2487 				ColumnDef  *coldef = lfirst(l);
2488 
2489 				if (strcmp(coldef->colname, restdef->colname) == 0)
2490 				{
2491 					found = true;
2492 					coldef->is_not_null |= restdef->is_not_null;
2493 
2494 					/*
2495 					 * Override the parent's default value for this column
2496 					 * (coldef->cooked_default) with the partition's local
2497 					 * definition (restdef->raw_default), if there's one. It
2498 					 * should be physically impossible to get a cooked default
2499 					 * in the local definition or a raw default in the
2500 					 * inherited definition, but make sure they're nulls, for
2501 					 * future-proofing.
2502 					 */
2503 					Assert(restdef->cooked_default == NULL);
2504 					Assert(coldef->raw_default == NULL);
2505 					if (restdef->raw_default)
2506 					{
2507 						coldef->raw_default = restdef->raw_default;
2508 						coldef->cooked_default = NULL;
2509 					}
2510 				}
2511 			}
2512 
2513 			/* complain for constraints on columns not in parent */
2514 			if (!found)
2515 				ereport(ERROR,
2516 						(errcode(ERRCODE_UNDEFINED_COLUMN),
2517 						 errmsg("column \"%s\" does not exist",
2518 								restdef->colname)));
2519 		}
2520 	}
2521 
2522 	/*
2523 	 * If we found any conflicting parent default values, check to make sure
2524 	 * they were overridden by the child.
2525 	 */
2526 	if (have_bogus_defaults)
2527 	{
2528 		foreach(entry, schema)
2529 		{
2530 			ColumnDef  *def = lfirst(entry);
2531 
2532 			if (def->cooked_default == &bogus_marker)
2533 				ereport(ERROR,
2534 						(errcode(ERRCODE_INVALID_COLUMN_DEFINITION),
2535 						 errmsg("column \"%s\" inherits conflicting default values",
2536 								def->colname),
2537 						 errhint("To resolve the conflict, specify a default explicitly.")));
2538 		}
2539 	}
2540 
2541 	*supOids = parentOids;
2542 	*supconstr = constraints;
2543 	*supOidCount = parentsWithOids;
2544 	return schema;
2545 }
2546 
2547 
2548 /*
2549  * MergeCheckConstraint
2550  *		Try to merge an inherited CHECK constraint with previous ones
2551  *
2552  * If we inherit identically-named constraints from multiple parents, we must
2553  * merge them, or throw an error if they don't have identical definitions.
2554  *
2555  * constraints is a list of CookedConstraint structs for previous constraints.
2556  *
2557  * Returns true if merged (constraint is a duplicate), or false if it's
2558  * got a so-far-unique name, or throws error if conflict.
2559  */
2560 static bool
MergeCheckConstraint(List * constraints,char * name,Node * expr)2561 MergeCheckConstraint(List *constraints, char *name, Node *expr)
2562 {
2563 	ListCell   *lc;
2564 
2565 	foreach(lc, constraints)
2566 	{
2567 		CookedConstraint *ccon = (CookedConstraint *) lfirst(lc);
2568 
2569 		Assert(ccon->contype == CONSTR_CHECK);
2570 
2571 		/* Non-matching names never conflict */
2572 		if (strcmp(ccon->name, name) != 0)
2573 			continue;
2574 
2575 		if (equal(expr, ccon->expr))
2576 		{
2577 			/* OK to merge */
2578 			ccon->inhcount++;
2579 			return true;
2580 		}
2581 
2582 		ereport(ERROR,
2583 				(errcode(ERRCODE_DUPLICATE_OBJECT),
2584 				 errmsg("check constraint name \"%s\" appears multiple times but with different expressions",
2585 						name)));
2586 	}
2587 
2588 	return false;
2589 }
2590 
2591 
2592 /*
2593  * StoreCatalogInheritance
2594  *		Updates the system catalogs with proper inheritance information.
2595  *
2596  * supers is a list of the OIDs of the new relation's direct ancestors.
2597  */
2598 static void
StoreCatalogInheritance(Oid relationId,List * supers,bool child_is_partition)2599 StoreCatalogInheritance(Oid relationId, List *supers,
2600 						bool child_is_partition)
2601 {
2602 	Relation	relation;
2603 	int32		seqNumber;
2604 	ListCell   *entry;
2605 
2606 	/*
2607 	 * sanity checks
2608 	 */
2609 	AssertArg(OidIsValid(relationId));
2610 
2611 	if (supers == NIL)
2612 		return;
2613 
2614 	/*
2615 	 * Store INHERITS information in pg_inherits using direct ancestors only.
2616 	 * Also enter dependencies on the direct ancestors, and make sure they are
2617 	 * marked with relhassubclass = true.
2618 	 *
2619 	 * (Once upon a time, both direct and indirect ancestors were found here
2620 	 * and then entered into pg_ipl.  Since that catalog doesn't exist
2621 	 * anymore, there's no need to look for indirect ancestors.)
2622 	 */
2623 	relation = heap_open(InheritsRelationId, RowExclusiveLock);
2624 
2625 	seqNumber = 1;
2626 	foreach(entry, supers)
2627 	{
2628 		Oid			parentOid = lfirst_oid(entry);
2629 
2630 		StoreCatalogInheritance1(relationId, parentOid, seqNumber, relation,
2631 								 child_is_partition);
2632 		seqNumber++;
2633 	}
2634 
2635 	heap_close(relation, RowExclusiveLock);
2636 }
2637 
2638 /*
2639  * Make catalog entries showing relationId as being an inheritance child
2640  * of parentOid.  inhRelation is the already-opened pg_inherits catalog.
2641  */
2642 static void
StoreCatalogInheritance1(Oid relationId,Oid parentOid,int32 seqNumber,Relation inhRelation,bool child_is_partition)2643 StoreCatalogInheritance1(Oid relationId, Oid parentOid,
2644 						 int32 seqNumber, Relation inhRelation,
2645 						 bool child_is_partition)
2646 {
2647 	ObjectAddress childobject,
2648 				parentobject;
2649 
2650 	/* store the pg_inherits row */
2651 	StoreSingleInheritance(relationId, parentOid, seqNumber);
2652 
2653 	/*
2654 	 * Store a dependency too
2655 	 */
2656 	parentobject.classId = RelationRelationId;
2657 	parentobject.objectId = parentOid;
2658 	parentobject.objectSubId = 0;
2659 	childobject.classId = RelationRelationId;
2660 	childobject.objectId = relationId;
2661 	childobject.objectSubId = 0;
2662 
2663 	recordDependencyOn(&childobject, &parentobject,
2664 					   child_dependency_type(child_is_partition));
2665 
2666 	/*
2667 	 * Post creation hook of this inheritance. Since object_access_hook
2668 	 * doesn't take multiple object identifiers, we relay oid of parent
2669 	 * relation using auxiliary_id argument.
2670 	 */
2671 	InvokeObjectPostAlterHookArg(InheritsRelationId,
2672 								 relationId, 0,
2673 								 parentOid, false);
2674 
2675 	/*
2676 	 * Mark the parent as having subclasses.
2677 	 */
2678 	SetRelationHasSubclass(parentOid, true);
2679 }
2680 
2681 /*
2682  * Look for an existing schema entry with the given name.
2683  *
2684  * Returns the index (starting with 1) if attribute already exists in schema,
2685  * 0 if it doesn't.
2686  */
2687 static int
findAttrByName(const char * attributeName,List * schema)2688 findAttrByName(const char *attributeName, List *schema)
2689 {
2690 	ListCell   *s;
2691 	int			i = 1;
2692 
2693 	foreach(s, schema)
2694 	{
2695 		ColumnDef  *def = lfirst(s);
2696 
2697 		if (strcmp(attributeName, def->colname) == 0)
2698 			return i;
2699 
2700 		i++;
2701 	}
2702 	return 0;
2703 }
2704 
2705 
2706 /*
2707  * SetRelationHasSubclass
2708  *		Set the value of the relation's relhassubclass field in pg_class.
2709  *
2710  * NOTE: caller must be holding an appropriate lock on the relation.
2711  * ShareUpdateExclusiveLock is sufficient.
2712  *
2713  * NOTE: an important side-effect of this operation is that an SI invalidation
2714  * message is sent out to all backends --- including me --- causing plans
2715  * referencing the relation to be rebuilt with the new list of children.
2716  * This must happen even if we find that no change is needed in the pg_class
2717  * row.
2718  */
2719 void
SetRelationHasSubclass(Oid relationId,bool relhassubclass)2720 SetRelationHasSubclass(Oid relationId, bool relhassubclass)
2721 {
2722 	Relation	relationRelation;
2723 	HeapTuple	tuple;
2724 	Form_pg_class classtuple;
2725 
2726 	/*
2727 	 * Fetch a modifiable copy of the tuple, modify it, update pg_class.
2728 	 */
2729 	relationRelation = heap_open(RelationRelationId, RowExclusiveLock);
2730 	tuple = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relationId));
2731 	if (!HeapTupleIsValid(tuple))
2732 		elog(ERROR, "cache lookup failed for relation %u", relationId);
2733 	classtuple = (Form_pg_class) GETSTRUCT(tuple);
2734 
2735 	if (classtuple->relhassubclass != relhassubclass)
2736 	{
2737 		classtuple->relhassubclass = relhassubclass;
2738 		CatalogTupleUpdate(relationRelation, &tuple->t_self, tuple);
2739 	}
2740 	else
2741 	{
2742 		/* no need to change tuple, but force relcache rebuild anyway */
2743 		CacheInvalidateRelcacheByTuple(tuple);
2744 	}
2745 
2746 	heap_freetuple(tuple);
2747 	heap_close(relationRelation, RowExclusiveLock);
2748 }
2749 
2750 /*
2751  *		renameatt_check			- basic sanity checks before attribute rename
2752  */
2753 static void
renameatt_check(Oid myrelid,Form_pg_class classform,bool recursing)2754 renameatt_check(Oid myrelid, Form_pg_class classform, bool recursing)
2755 {
2756 	char		relkind = classform->relkind;
2757 
2758 	if (classform->reloftype && !recursing)
2759 		ereport(ERROR,
2760 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
2761 				 errmsg("cannot rename column of typed table")));
2762 
2763 	/*
2764 	 * Renaming the columns of sequences or toast tables doesn't actually
2765 	 * break anything from the system's point of view, since internal
2766 	 * references are by attnum.  But it doesn't seem right to allow users to
2767 	 * change names that are hardcoded into the system, hence the following
2768 	 * restriction.
2769 	 */
2770 	if (relkind != RELKIND_RELATION &&
2771 		relkind != RELKIND_VIEW &&
2772 		relkind != RELKIND_MATVIEW &&
2773 		relkind != RELKIND_COMPOSITE_TYPE &&
2774 		relkind != RELKIND_INDEX &&
2775 		relkind != RELKIND_PARTITIONED_INDEX &&
2776 		relkind != RELKIND_FOREIGN_TABLE &&
2777 		relkind != RELKIND_PARTITIONED_TABLE)
2778 		ereport(ERROR,
2779 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
2780 				 errmsg("\"%s\" is not a table, view, materialized view, composite type, index, or foreign table",
2781 						NameStr(classform->relname))));
2782 
2783 	/*
2784 	 * permissions checking.  only the owner of a class can change its schema.
2785 	 */
2786 	if (!pg_class_ownercheck(myrelid, GetUserId()))
2787 		aclcheck_error(ACLCHECK_NOT_OWNER, get_relkind_objtype(get_rel_relkind(myrelid)),
2788 					   NameStr(classform->relname));
2789 	if (!allowSystemTableMods && IsSystemClass(myrelid, classform))
2790 		ereport(ERROR,
2791 				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
2792 				 errmsg("permission denied: \"%s\" is a system catalog",
2793 						NameStr(classform->relname))));
2794 }
2795 
2796 /*
2797  *		renameatt_internal		- workhorse for renameatt
2798  *
2799  * Return value is the attribute number in the 'myrelid' relation.
2800  */
2801 static AttrNumber
renameatt_internal(Oid myrelid,const char * oldattname,const char * newattname,bool recurse,bool recursing,int expected_parents,DropBehavior behavior)2802 renameatt_internal(Oid myrelid,
2803 				   const char *oldattname,
2804 				   const char *newattname,
2805 				   bool recurse,
2806 				   bool recursing,
2807 				   int expected_parents,
2808 				   DropBehavior behavior)
2809 {
2810 	Relation	targetrelation;
2811 	Relation	attrelation;
2812 	HeapTuple	atttup;
2813 	Form_pg_attribute attform;
2814 	AttrNumber	attnum;
2815 
2816 	/*
2817 	 * Grab an exclusive lock on the target table, which we will NOT release
2818 	 * until end of transaction.
2819 	 */
2820 	targetrelation = relation_open(myrelid, AccessExclusiveLock);
2821 	renameatt_check(myrelid, RelationGetForm(targetrelation), recursing);
2822 
2823 	/*
2824 	 * if the 'recurse' flag is set then we are supposed to rename this
2825 	 * attribute in all classes that inherit from 'relname' (as well as in
2826 	 * 'relname').
2827 	 *
2828 	 * any permissions or problems with duplicate attributes will cause the
2829 	 * whole transaction to abort, which is what we want -- all or nothing.
2830 	 */
2831 	if (recurse)
2832 	{
2833 		List	   *child_oids,
2834 				   *child_numparents;
2835 		ListCell   *lo,
2836 				   *li;
2837 
2838 		/*
2839 		 * we need the number of parents for each child so that the recursive
2840 		 * calls to renameatt() can determine whether there are any parents
2841 		 * outside the inheritance hierarchy being processed.
2842 		 */
2843 		child_oids = find_all_inheritors(myrelid, AccessExclusiveLock,
2844 										 &child_numparents);
2845 
2846 		/*
2847 		 * find_all_inheritors does the recursive search of the inheritance
2848 		 * hierarchy, so all we have to do is process all of the relids in the
2849 		 * list that it returns.
2850 		 */
2851 		forboth(lo, child_oids, li, child_numparents)
2852 		{
2853 			Oid			childrelid = lfirst_oid(lo);
2854 			int			numparents = lfirst_int(li);
2855 
2856 			if (childrelid == myrelid)
2857 				continue;
2858 			/* note we need not recurse again */
2859 			renameatt_internal(childrelid, oldattname, newattname, false, true, numparents, behavior);
2860 		}
2861 	}
2862 	else
2863 	{
2864 		/*
2865 		 * If we are told not to recurse, there had better not be any child
2866 		 * tables; else the rename would put them out of step.
2867 		 *
2868 		 * expected_parents will only be 0 if we are not already recursing.
2869 		 */
2870 		if (expected_parents == 0 &&
2871 			find_inheritance_children(myrelid, NoLock) != NIL)
2872 			ereport(ERROR,
2873 					(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
2874 					 errmsg("inherited column \"%s\" must be renamed in child tables too",
2875 							oldattname)));
2876 	}
2877 
2878 	/* rename attributes in typed tables of composite type */
2879 	if (targetrelation->rd_rel->relkind == RELKIND_COMPOSITE_TYPE)
2880 	{
2881 		List	   *child_oids;
2882 		ListCell   *lo;
2883 
2884 		child_oids = find_typed_table_dependencies(targetrelation->rd_rel->reltype,
2885 												   RelationGetRelationName(targetrelation),
2886 												   behavior);
2887 
2888 		foreach(lo, child_oids)
2889 			renameatt_internal(lfirst_oid(lo), oldattname, newattname, true, true, 0, behavior);
2890 	}
2891 
2892 	attrelation = heap_open(AttributeRelationId, RowExclusiveLock);
2893 
2894 	atttup = SearchSysCacheCopyAttName(myrelid, oldattname);
2895 	if (!HeapTupleIsValid(atttup))
2896 		ereport(ERROR,
2897 				(errcode(ERRCODE_UNDEFINED_COLUMN),
2898 				 errmsg("column \"%s\" does not exist",
2899 						oldattname)));
2900 	attform = (Form_pg_attribute) GETSTRUCT(atttup);
2901 
2902 	attnum = attform->attnum;
2903 	if (attnum <= 0)
2904 		ereport(ERROR,
2905 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2906 				 errmsg("cannot rename system column \"%s\"",
2907 						oldattname)));
2908 
2909 	/*
2910 	 * if the attribute is inherited, forbid the renaming.  if this is a
2911 	 * top-level call to renameatt(), then expected_parents will be 0, so the
2912 	 * effect of this code will be to prohibit the renaming if the attribute
2913 	 * is inherited at all.  if this is a recursive call to renameatt(),
2914 	 * expected_parents will be the number of parents the current relation has
2915 	 * within the inheritance hierarchy being processed, so we'll prohibit the
2916 	 * renaming only if there are additional parents from elsewhere.
2917 	 */
2918 	if (attform->attinhcount > expected_parents)
2919 		ereport(ERROR,
2920 				(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
2921 				 errmsg("cannot rename inherited column \"%s\"",
2922 						oldattname)));
2923 
2924 	/* new name should not already exist */
2925 	(void) check_for_column_name_collision(targetrelation, newattname, false);
2926 
2927 	/* apply the update */
2928 	namestrcpy(&(attform->attname), newattname);
2929 
2930 	CatalogTupleUpdate(attrelation, &atttup->t_self, atttup);
2931 
2932 	InvokeObjectPostAlterHook(RelationRelationId, myrelid, attnum);
2933 
2934 	heap_freetuple(atttup);
2935 
2936 	heap_close(attrelation, RowExclusiveLock);
2937 
2938 	relation_close(targetrelation, NoLock); /* close rel but keep lock */
2939 
2940 	return attnum;
2941 }
2942 
2943 /*
2944  * Perform permissions and integrity checks before acquiring a relation lock.
2945  */
2946 static void
RangeVarCallbackForRenameAttribute(const RangeVar * rv,Oid relid,Oid oldrelid,void * arg)2947 RangeVarCallbackForRenameAttribute(const RangeVar *rv, Oid relid, Oid oldrelid,
2948 								   void *arg)
2949 {
2950 	HeapTuple	tuple;
2951 	Form_pg_class form;
2952 
2953 	tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
2954 	if (!HeapTupleIsValid(tuple))
2955 		return;					/* concurrently dropped */
2956 	form = (Form_pg_class) GETSTRUCT(tuple);
2957 	renameatt_check(relid, form, false);
2958 	ReleaseSysCache(tuple);
2959 }
2960 
2961 /*
2962  *		renameatt		- changes the name of an attribute in a relation
2963  *
2964  * The returned ObjectAddress is that of the renamed column.
2965  */
2966 ObjectAddress
renameatt(RenameStmt * stmt)2967 renameatt(RenameStmt *stmt)
2968 {
2969 	Oid			relid;
2970 	AttrNumber	attnum;
2971 	ObjectAddress address;
2972 
2973 	/* lock level taken here should match renameatt_internal */
2974 	relid = RangeVarGetRelidExtended(stmt->relation, AccessExclusiveLock,
2975 									 stmt->missing_ok ? RVR_MISSING_OK : 0,
2976 									 RangeVarCallbackForRenameAttribute,
2977 									 NULL);
2978 
2979 	if (!OidIsValid(relid))
2980 	{
2981 		ereport(NOTICE,
2982 				(errmsg("relation \"%s\" does not exist, skipping",
2983 						stmt->relation->relname)));
2984 		return InvalidObjectAddress;
2985 	}
2986 
2987 	attnum =
2988 		renameatt_internal(relid,
2989 						   stmt->subname,	/* old att name */
2990 						   stmt->newname,	/* new att name */
2991 						   stmt->relation->inh, /* recursive? */
2992 						   false,	/* recursing? */
2993 						   0,	/* expected inhcount */
2994 						   stmt->behavior);
2995 
2996 	ObjectAddressSubSet(address, RelationRelationId, relid, attnum);
2997 
2998 	return address;
2999 }
3000 
3001 /*
3002  * same logic as renameatt_internal
3003  */
3004 static ObjectAddress
rename_constraint_internal(Oid myrelid,Oid mytypid,const char * oldconname,const char * newconname,bool recurse,bool recursing,int expected_parents)3005 rename_constraint_internal(Oid myrelid,
3006 						   Oid mytypid,
3007 						   const char *oldconname,
3008 						   const char *newconname,
3009 						   bool recurse,
3010 						   bool recursing,
3011 						   int expected_parents)
3012 {
3013 	Relation	targetrelation = NULL;
3014 	Oid			constraintOid;
3015 	HeapTuple	tuple;
3016 	Form_pg_constraint con;
3017 	ObjectAddress address;
3018 
3019 	AssertArg(!myrelid || !mytypid);
3020 
3021 	if (mytypid)
3022 	{
3023 		constraintOid = get_domain_constraint_oid(mytypid, oldconname, false);
3024 	}
3025 	else
3026 	{
3027 		targetrelation = relation_open(myrelid, AccessExclusiveLock);
3028 
3029 		/*
3030 		 * don't tell it whether we're recursing; we allow changing typed
3031 		 * tables here
3032 		 */
3033 		renameatt_check(myrelid, RelationGetForm(targetrelation), false);
3034 
3035 		constraintOid = get_relation_constraint_oid(myrelid, oldconname, false);
3036 	}
3037 
3038 	tuple = SearchSysCache1(CONSTROID, ObjectIdGetDatum(constraintOid));
3039 	if (!HeapTupleIsValid(tuple))
3040 		elog(ERROR, "cache lookup failed for constraint %u",
3041 			 constraintOid);
3042 	con = (Form_pg_constraint) GETSTRUCT(tuple);
3043 
3044 	if (myrelid && con->contype == CONSTRAINT_CHECK && !con->connoinherit)
3045 	{
3046 		if (recurse)
3047 		{
3048 			List	   *child_oids,
3049 					   *child_numparents;
3050 			ListCell   *lo,
3051 					   *li;
3052 
3053 			child_oids = find_all_inheritors(myrelid, AccessExclusiveLock,
3054 											 &child_numparents);
3055 
3056 			forboth(lo, child_oids, li, child_numparents)
3057 			{
3058 				Oid			childrelid = lfirst_oid(lo);
3059 				int			numparents = lfirst_int(li);
3060 
3061 				if (childrelid == myrelid)
3062 					continue;
3063 
3064 				rename_constraint_internal(childrelid, InvalidOid, oldconname, newconname, false, true, numparents);
3065 			}
3066 		}
3067 		else
3068 		{
3069 			if (expected_parents == 0 &&
3070 				find_inheritance_children(myrelid, NoLock) != NIL)
3071 				ereport(ERROR,
3072 						(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
3073 						 errmsg("inherited constraint \"%s\" must be renamed in child tables too",
3074 								oldconname)));
3075 		}
3076 
3077 		if (con->coninhcount > expected_parents)
3078 			ereport(ERROR,
3079 					(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
3080 					 errmsg("cannot rename inherited constraint \"%s\"",
3081 							oldconname)));
3082 	}
3083 
3084 	if (con->conindid
3085 		&& (con->contype == CONSTRAINT_PRIMARY
3086 			|| con->contype == CONSTRAINT_UNIQUE
3087 			|| con->contype == CONSTRAINT_EXCLUSION))
3088 		/* rename the index; this renames the constraint as well */
3089 		RenameRelationInternal(con->conindid, newconname, false);
3090 	else
3091 		RenameConstraintById(constraintOid, newconname);
3092 
3093 	ObjectAddressSet(address, ConstraintRelationId, constraintOid);
3094 
3095 	ReleaseSysCache(tuple);
3096 
3097 	if (targetrelation)
3098 	{
3099 		/*
3100 		 * Invalidate relcache so as others can see the new constraint name.
3101 		 */
3102 		CacheInvalidateRelcache(targetrelation);
3103 
3104 		relation_close(targetrelation, NoLock); /* close rel but keep lock */
3105 	}
3106 
3107 	return address;
3108 }
3109 
3110 ObjectAddress
RenameConstraint(RenameStmt * stmt)3111 RenameConstraint(RenameStmt *stmt)
3112 {
3113 	Oid			relid = InvalidOid;
3114 	Oid			typid = InvalidOid;
3115 
3116 	if (stmt->renameType == OBJECT_DOMCONSTRAINT)
3117 	{
3118 		Relation	rel;
3119 		HeapTuple	tup;
3120 
3121 		typid = typenameTypeId(NULL, makeTypeNameFromNameList(castNode(List, stmt->object)));
3122 		rel = heap_open(TypeRelationId, RowExclusiveLock);
3123 		tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
3124 		if (!HeapTupleIsValid(tup))
3125 			elog(ERROR, "cache lookup failed for type %u", typid);
3126 		checkDomainOwner(tup);
3127 		ReleaseSysCache(tup);
3128 		heap_close(rel, NoLock);
3129 	}
3130 	else
3131 	{
3132 		/* lock level taken here should match rename_constraint_internal */
3133 		relid = RangeVarGetRelidExtended(stmt->relation, AccessExclusiveLock,
3134 										 stmt->missing_ok ? RVR_MISSING_OK : 0,
3135 										 RangeVarCallbackForRenameAttribute,
3136 										 NULL);
3137 		if (!OidIsValid(relid))
3138 		{
3139 			ereport(NOTICE,
3140 					(errmsg("relation \"%s\" does not exist, skipping",
3141 							stmt->relation->relname)));
3142 			return InvalidObjectAddress;
3143 		}
3144 	}
3145 
3146 	return
3147 		rename_constraint_internal(relid, typid,
3148 								   stmt->subname,
3149 								   stmt->newname,
3150 								   (stmt->relation &&
3151 									stmt->relation->inh),	/* recursive? */
3152 								   false,	/* recursing? */
3153 								   0 /* expected inhcount */ );
3154 
3155 }
3156 
3157 /*
3158  * Execute ALTER TABLE/INDEX/SEQUENCE/VIEW/MATERIALIZED VIEW/FOREIGN TABLE
3159  * RENAME
3160  */
3161 ObjectAddress
RenameRelation(RenameStmt * stmt)3162 RenameRelation(RenameStmt *stmt)
3163 {
3164 	Oid			relid;
3165 	ObjectAddress address;
3166 
3167 	/*
3168 	 * Grab an exclusive lock on the target table, index, sequence, view,
3169 	 * materialized view, or foreign table, which we will NOT release until
3170 	 * end of transaction.
3171 	 *
3172 	 * Lock level used here should match RenameRelationInternal, to avoid lock
3173 	 * escalation.
3174 	 */
3175 	relid = RangeVarGetRelidExtended(stmt->relation, AccessExclusiveLock,
3176 									 stmt->missing_ok ? RVR_MISSING_OK : 0,
3177 									 RangeVarCallbackForAlterRelation,
3178 									 (void *) stmt);
3179 
3180 	if (!OidIsValid(relid))
3181 	{
3182 		ereport(NOTICE,
3183 				(errmsg("relation \"%s\" does not exist, skipping",
3184 						stmt->relation->relname)));
3185 		return InvalidObjectAddress;
3186 	}
3187 
3188 	/* Do the work */
3189 	RenameRelationInternal(relid, stmt->newname, false);
3190 
3191 	ObjectAddressSet(address, RelationRelationId, relid);
3192 
3193 	return address;
3194 }
3195 
3196 /*
3197  *		RenameRelationInternal - change the name of a relation
3198  */
3199 void
RenameRelationInternal(Oid myrelid,const char * newrelname,bool is_internal)3200 RenameRelationInternal(Oid myrelid, const char *newrelname, bool is_internal)
3201 {
3202 	Relation	targetrelation;
3203 	Relation	relrelation;	/* for RELATION relation */
3204 	HeapTuple	reltup;
3205 	Form_pg_class relform;
3206 	Oid			namespaceId;
3207 
3208 	/*
3209 	 * Grab an exclusive lock on the target table, index, sequence, view,
3210 	 * materialized view, or foreign table, which we will NOT release until
3211 	 * end of transaction.
3212 	 */
3213 	targetrelation = relation_open(myrelid, AccessExclusiveLock);
3214 	namespaceId = RelationGetNamespace(targetrelation);
3215 
3216 	/*
3217 	 * Find relation's pg_class tuple, and make sure newrelname isn't in use.
3218 	 */
3219 	relrelation = heap_open(RelationRelationId, RowExclusiveLock);
3220 
3221 	reltup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(myrelid));
3222 	if (!HeapTupleIsValid(reltup))	/* shouldn't happen */
3223 		elog(ERROR, "cache lookup failed for relation %u", myrelid);
3224 	relform = (Form_pg_class) GETSTRUCT(reltup);
3225 
3226 	if (get_relname_relid(newrelname, namespaceId) != InvalidOid)
3227 		ereport(ERROR,
3228 				(errcode(ERRCODE_DUPLICATE_TABLE),
3229 				 errmsg("relation \"%s\" already exists",
3230 						newrelname)));
3231 
3232 	/*
3233 	 * Update pg_class tuple with new relname.  (Scribbling on reltup is OK
3234 	 * because it's a copy...)
3235 	 */
3236 	namestrcpy(&(relform->relname), newrelname);
3237 
3238 	CatalogTupleUpdate(relrelation, &reltup->t_self, reltup);
3239 
3240 	InvokeObjectPostAlterHookArg(RelationRelationId, myrelid, 0,
3241 								 InvalidOid, is_internal);
3242 
3243 	heap_freetuple(reltup);
3244 	heap_close(relrelation, RowExclusiveLock);
3245 
3246 	/*
3247 	 * Also rename the associated type, if any.
3248 	 */
3249 	if (OidIsValid(targetrelation->rd_rel->reltype))
3250 		RenameTypeInternal(targetrelation->rd_rel->reltype,
3251 						   newrelname, namespaceId);
3252 
3253 	/*
3254 	 * Also rename the associated constraint, if any.
3255 	 */
3256 	if (targetrelation->rd_rel->relkind == RELKIND_INDEX ||
3257 		targetrelation->rd_rel->relkind == RELKIND_PARTITIONED_INDEX)
3258 	{
3259 		Oid			constraintId = get_index_constraint(myrelid);
3260 
3261 		if (OidIsValid(constraintId))
3262 			RenameConstraintById(constraintId, newrelname);
3263 	}
3264 
3265 	/*
3266 	 * Close rel, but keep exclusive lock!
3267 	 */
3268 	relation_close(targetrelation, NoLock);
3269 }
3270 
3271 /*
3272  *		ResetRelRewrite - reset relrewrite
3273  */
3274 void
ResetRelRewrite(Oid myrelid)3275 ResetRelRewrite(Oid myrelid)
3276 {
3277 	Relation	relrelation;	/* for RELATION relation */
3278 	HeapTuple	reltup;
3279 	Form_pg_class relform;
3280 
3281 	/*
3282 	 * Find relation's pg_class tuple.
3283 	 */
3284 	relrelation = heap_open(RelationRelationId, RowExclusiveLock);
3285 
3286 	reltup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(myrelid));
3287 	if (!HeapTupleIsValid(reltup))	/* shouldn't happen */
3288 		elog(ERROR, "cache lookup failed for relation %u", myrelid);
3289 	relform = (Form_pg_class) GETSTRUCT(reltup);
3290 
3291 	/*
3292 	 * Update pg_class tuple.
3293 	 */
3294 	relform->relrewrite = InvalidOid;
3295 
3296 	CatalogTupleUpdate(relrelation, &reltup->t_self, reltup);
3297 
3298 	heap_freetuple(reltup);
3299 	heap_close(relrelation, RowExclusiveLock);
3300 }
3301 
3302 /*
3303  * Disallow ALTER TABLE (and similar commands) when the current backend has
3304  * any open reference to the target table besides the one just acquired by
3305  * the calling command; this implies there's an open cursor or active plan.
3306  * We need this check because our lock doesn't protect us against stomping
3307  * on our own foot, only other people's feet!
3308  *
3309  * For ALTER TABLE, the only case known to cause serious trouble is ALTER
3310  * COLUMN TYPE, and some changes are obviously pretty benign, so this could
3311  * possibly be relaxed to only error out for certain types of alterations.
3312  * But the use-case for allowing any of these things is not obvious, so we
3313  * won't work hard at it for now.
3314  *
3315  * We also reject these commands if there are any pending AFTER trigger events
3316  * for the rel.  This is certainly necessary for the rewriting variants of
3317  * ALTER TABLE, because they don't preserve tuple TIDs and so the pending
3318  * events would try to fetch the wrong tuples.  It might be overly cautious
3319  * in other cases, but again it seems better to err on the side of paranoia.
3320  *
3321  * REINDEX calls this with "rel" referencing the index to be rebuilt; here
3322  * we are worried about active indexscans on the index.  The trigger-event
3323  * check can be skipped, since we are doing no damage to the parent table.
3324  *
3325  * The statement name (eg, "ALTER TABLE") is passed for use in error messages.
3326  */
3327 void
CheckTableNotInUse(Relation rel,const char * stmt)3328 CheckTableNotInUse(Relation rel, const char *stmt)
3329 {
3330 	int			expected_refcnt;
3331 
3332 	expected_refcnt = rel->rd_isnailed ? 2 : 1;
3333 	if (rel->rd_refcnt != expected_refcnt)
3334 		ereport(ERROR,
3335 				(errcode(ERRCODE_OBJECT_IN_USE),
3336 		/* translator: first %s is a SQL command, eg ALTER TABLE */
3337 				 errmsg("cannot %s \"%s\" because it is being used by active queries in this session",
3338 						stmt, RelationGetRelationName(rel))));
3339 
3340 	if (rel->rd_rel->relkind != RELKIND_INDEX &&
3341 		rel->rd_rel->relkind != RELKIND_PARTITIONED_INDEX &&
3342 		AfterTriggerPendingOnRel(RelationGetRelid(rel)))
3343 		ereport(ERROR,
3344 				(errcode(ERRCODE_OBJECT_IN_USE),
3345 		/* translator: first %s is a SQL command, eg ALTER TABLE */
3346 				 errmsg("cannot %s \"%s\" because it has pending trigger events",
3347 						stmt, RelationGetRelationName(rel))));
3348 }
3349 
3350 /*
3351  * AlterTableLookupRelation
3352  *		Look up, and lock, the OID for the relation named by an alter table
3353  *		statement.
3354  */
3355 Oid
AlterTableLookupRelation(AlterTableStmt * stmt,LOCKMODE lockmode)3356 AlterTableLookupRelation(AlterTableStmt *stmt, LOCKMODE lockmode)
3357 {
3358 	return RangeVarGetRelidExtended(stmt->relation, lockmode,
3359 									stmt->missing_ok ? RVR_MISSING_OK : 0,
3360 									RangeVarCallbackForAlterRelation,
3361 									(void *) stmt);
3362 }
3363 
3364 /*
3365  * AlterTable
3366  *		Execute ALTER TABLE, which can be a list of subcommands
3367  *
3368  * ALTER TABLE is performed in three phases:
3369  *		1. Examine subcommands and perform pre-transformation checking.
3370  *		2. Update system catalogs.
3371  *		3. Scan table(s) to check new constraints, and optionally recopy
3372  *		   the data into new table(s).
3373  * Phase 3 is not performed unless one or more of the subcommands requires
3374  * it.  The intention of this design is to allow multiple independent
3375  * updates of the table schema to be performed with only one pass over the
3376  * data.
3377  *
3378  * ATPrepCmd performs phase 1.  A "work queue" entry is created for
3379  * each table to be affected (there may be multiple affected tables if the
3380  * commands traverse a table inheritance hierarchy).  Also we do preliminary
3381  * validation of the subcommands, including parse transformation of those
3382  * expressions that need to be evaluated with respect to the old table
3383  * schema.
3384  *
3385  * ATRewriteCatalogs performs phase 2 for each affected table.  (Note that
3386  * phases 2 and 3 normally do no explicit recursion, since phase 1 already
3387  * did it --- although some subcommands have to recurse in phase 2 instead.)
3388  * Certain subcommands need to be performed before others to avoid
3389  * unnecessary conflicts; for example, DROP COLUMN should come before
3390  * ADD COLUMN.  Therefore phase 1 divides the subcommands into multiple
3391  * lists, one for each logical "pass" of phase 2.
3392  *
3393  * ATRewriteTables performs phase 3 for those tables that need it.
3394  *
3395  * Thanks to the magic of MVCC, an error anywhere along the way rolls back
3396  * the whole operation; we don't have to do anything special to clean up.
3397  *
3398  * The caller must lock the relation, with an appropriate lock level
3399  * for the subcommands requested, using AlterTableGetLockLevel(stmt->cmds)
3400  * or higher. We pass the lock level down
3401  * so that we can apply it recursively to inherited tables. Note that the
3402  * lock level we want as we recurse might well be higher than required for
3403  * that specific subcommand. So we pass down the overall lock requirement,
3404  * rather than reassess it at lower levels.
3405  */
3406 void
AlterTable(Oid relid,LOCKMODE lockmode,AlterTableStmt * stmt)3407 AlterTable(Oid relid, LOCKMODE lockmode, AlterTableStmt *stmt)
3408 {
3409 	Relation	rel;
3410 
3411 	/* Caller is required to provide an adequate lock. */
3412 	rel = relation_open(relid, NoLock);
3413 
3414 	CheckTableNotInUse(rel, "ALTER TABLE");
3415 
3416 	ATController(stmt, rel, stmt->cmds, stmt->relation->inh, lockmode);
3417 }
3418 
3419 /*
3420  * AlterTableInternal
3421  *
3422  * ALTER TABLE with target specified by OID
3423  *
3424  * We do not reject if the relation is already open, because it's quite
3425  * likely that one or more layers of caller have it open.  That means it
3426  * is unsafe to use this entry point for alterations that could break
3427  * existing query plans.  On the assumption it's not used for such, we
3428  * don't have to reject pending AFTER triggers, either.
3429  */
3430 void
AlterTableInternal(Oid relid,List * cmds,bool recurse)3431 AlterTableInternal(Oid relid, List *cmds, bool recurse)
3432 {
3433 	Relation	rel;
3434 	LOCKMODE	lockmode = AlterTableGetLockLevel(cmds);
3435 
3436 	rel = relation_open(relid, lockmode);
3437 
3438 	EventTriggerAlterTableRelid(relid);
3439 
3440 	ATController(NULL, rel, cmds, recurse, lockmode);
3441 }
3442 
3443 /*
3444  * AlterTableGetLockLevel
3445  *
3446  * Sets the overall lock level required for the supplied list of subcommands.
3447  * Policy for doing this set according to needs of AlterTable(), see
3448  * comments there for overall explanation.
3449  *
3450  * Function is called before and after parsing, so it must give same
3451  * answer each time it is called. Some subcommands are transformed
3452  * into other subcommand types, so the transform must never be made to a
3453  * lower lock level than previously assigned. All transforms are noted below.
3454  *
3455  * Since this is called before we lock the table we cannot use table metadata
3456  * to influence the type of lock we acquire.
3457  *
3458  * There should be no lockmodes hardcoded into the subcommand functions. All
3459  * lockmode decisions for ALTER TABLE are made here only. The one exception is
3460  * ALTER TABLE RENAME which is treated as a different statement type T_RenameStmt
3461  * and does not travel through this section of code and cannot be combined with
3462  * any of the subcommands given here.
3463  *
3464  * Note that Hot Standby only knows about AccessExclusiveLocks on the master
3465  * so any changes that might affect SELECTs running on standbys need to use
3466  * AccessExclusiveLocks even if you think a lesser lock would do, unless you
3467  * have a solution for that also.
3468  *
3469  * Also note that pg_dump uses only an AccessShareLock, meaning that anything
3470  * that takes a lock less than AccessExclusiveLock can change object definitions
3471  * while pg_dump is running. Be careful to check that the appropriate data is
3472  * derived by pg_dump using an MVCC snapshot, rather than syscache lookups,
3473  * otherwise we might end up with an inconsistent dump that can't restore.
3474  */
3475 LOCKMODE
AlterTableGetLockLevel(List * cmds)3476 AlterTableGetLockLevel(List *cmds)
3477 {
3478 	/*
3479 	 * This only works if we read catalog tables using MVCC snapshots.
3480 	 */
3481 	ListCell   *lcmd;
3482 	LOCKMODE	lockmode = ShareUpdateExclusiveLock;
3483 
3484 	foreach(lcmd, cmds)
3485 	{
3486 		AlterTableCmd *cmd = (AlterTableCmd *) lfirst(lcmd);
3487 		LOCKMODE	cmd_lockmode = AccessExclusiveLock; /* default for compiler */
3488 
3489 		switch (cmd->subtype)
3490 		{
3491 				/*
3492 				 * These subcommands rewrite the heap, so require full locks.
3493 				 */
3494 			case AT_AddColumn:	/* may rewrite heap, in some cases and visible
3495 								 * to SELECT */
3496 			case AT_SetTableSpace:	/* must rewrite heap */
3497 			case AT_AlterColumnType:	/* must rewrite heap */
3498 			case AT_AddOids:	/* must rewrite heap */
3499 				cmd_lockmode = AccessExclusiveLock;
3500 				break;
3501 
3502 				/*
3503 				 * These subcommands may require addition of toast tables. If
3504 				 * we add a toast table to a table currently being scanned, we
3505 				 * might miss data added to the new toast table by concurrent
3506 				 * insert transactions.
3507 				 */
3508 			case AT_SetStorage: /* may add toast tables, see
3509 								 * ATRewriteCatalogs() */
3510 				cmd_lockmode = AccessExclusiveLock;
3511 				break;
3512 
3513 				/*
3514 				 * Removing constraints can affect SELECTs that have been
3515 				 * optimised assuming the constraint holds true.
3516 				 */
3517 			case AT_DropConstraint: /* as DROP INDEX */
3518 			case AT_DropNotNull:	/* may change some SQL plans */
3519 				cmd_lockmode = AccessExclusiveLock;
3520 				break;
3521 
3522 				/*
3523 				 * Subcommands that may be visible to concurrent SELECTs
3524 				 */
3525 			case AT_DropColumn: /* change visible to SELECT */
3526 			case AT_AddColumnToView:	/* CREATE VIEW */
3527 			case AT_DropOids:	/* calls AT_DropColumn */
3528 			case AT_EnableAlwaysRule:	/* may change SELECT rules */
3529 			case AT_EnableReplicaRule:	/* may change SELECT rules */
3530 			case AT_EnableRule: /* may change SELECT rules */
3531 			case AT_DisableRule:	/* may change SELECT rules */
3532 				cmd_lockmode = AccessExclusiveLock;
3533 				break;
3534 
3535 				/*
3536 				 * Changing owner may remove implicit SELECT privileges
3537 				 */
3538 			case AT_ChangeOwner:	/* change visible to SELECT */
3539 				cmd_lockmode = AccessExclusiveLock;
3540 				break;
3541 
3542 				/*
3543 				 * Changing foreign table options may affect optimization.
3544 				 */
3545 			case AT_GenericOptions:
3546 			case AT_AlterColumnGenericOptions:
3547 				cmd_lockmode = AccessExclusiveLock;
3548 				break;
3549 
3550 				/*
3551 				 * These subcommands affect write operations only.
3552 				 */
3553 			case AT_EnableTrig:
3554 			case AT_EnableAlwaysTrig:
3555 			case AT_EnableReplicaTrig:
3556 			case AT_EnableTrigAll:
3557 			case AT_EnableTrigUser:
3558 			case AT_DisableTrig:
3559 			case AT_DisableTrigAll:
3560 			case AT_DisableTrigUser:
3561 				cmd_lockmode = ShareRowExclusiveLock;
3562 				break;
3563 
3564 				/*
3565 				 * These subcommands affect write operations only. XXX
3566 				 * Theoretically, these could be ShareRowExclusiveLock.
3567 				 */
3568 			case AT_ColumnDefault:
3569 			case AT_AlterConstraint:
3570 			case AT_AddIndex:	/* from ADD CONSTRAINT */
3571 			case AT_AddIndexConstraint:
3572 			case AT_ReplicaIdentity:
3573 			case AT_SetNotNull:
3574 			case AT_EnableRowSecurity:
3575 			case AT_DisableRowSecurity:
3576 			case AT_ForceRowSecurity:
3577 			case AT_NoForceRowSecurity:
3578 			case AT_AddIdentity:
3579 			case AT_DropIdentity:
3580 			case AT_SetIdentity:
3581 				cmd_lockmode = AccessExclusiveLock;
3582 				break;
3583 
3584 			case AT_AddConstraint:
3585 			case AT_ProcessedConstraint:	/* becomes AT_AddConstraint */
3586 			case AT_AddConstraintRecurse:	/* becomes AT_AddConstraint */
3587 			case AT_ReAddConstraint:	/* becomes AT_AddConstraint */
3588 			case AT_ReAddDomainConstraint:	/* becomes AT_AddConstraint */
3589 				if (IsA(cmd->def, Constraint))
3590 				{
3591 					Constraint *con = (Constraint *) cmd->def;
3592 
3593 					switch (con->contype)
3594 					{
3595 						case CONSTR_EXCLUSION:
3596 						case CONSTR_PRIMARY:
3597 						case CONSTR_UNIQUE:
3598 
3599 							/*
3600 							 * Cases essentially the same as CREATE INDEX. We
3601 							 * could reduce the lock strength to ShareLock if
3602 							 * we can work out how to allow concurrent catalog
3603 							 * updates. XXX Might be set down to
3604 							 * ShareRowExclusiveLock but requires further
3605 							 * analysis.
3606 							 */
3607 							cmd_lockmode = AccessExclusiveLock;
3608 							break;
3609 						case CONSTR_FOREIGN:
3610 
3611 							/*
3612 							 * We add triggers to both tables when we add a
3613 							 * Foreign Key, so the lock level must be at least
3614 							 * as strong as CREATE TRIGGER.
3615 							 */
3616 							cmd_lockmode = ShareRowExclusiveLock;
3617 							break;
3618 
3619 						default:
3620 							cmd_lockmode = AccessExclusiveLock;
3621 					}
3622 				}
3623 				break;
3624 
3625 				/*
3626 				 * These subcommands affect inheritance behaviour. Queries
3627 				 * started before us will continue to see the old inheritance
3628 				 * behaviour, while queries started after we commit will see
3629 				 * new behaviour. No need to prevent reads or writes to the
3630 				 * subtable while we hook it up though. Changing the TupDesc
3631 				 * may be a problem, so keep highest lock.
3632 				 */
3633 			case AT_AddInherit:
3634 			case AT_DropInherit:
3635 				cmd_lockmode = AccessExclusiveLock;
3636 				break;
3637 
3638 				/*
3639 				 * These subcommands affect implicit row type conversion. They
3640 				 * have affects similar to CREATE/DROP CAST on queries. don't
3641 				 * provide for invalidating parse trees as a result of such
3642 				 * changes, so we keep these at AccessExclusiveLock.
3643 				 */
3644 			case AT_AddOf:
3645 			case AT_DropOf:
3646 				cmd_lockmode = AccessExclusiveLock;
3647 				break;
3648 
3649 				/*
3650 				 * Only used by CREATE OR REPLACE VIEW which must conflict
3651 				 * with an SELECTs currently using the view.
3652 				 */
3653 			case AT_ReplaceRelOptions:
3654 				cmd_lockmode = AccessExclusiveLock;
3655 				break;
3656 
3657 				/*
3658 				 * These subcommands affect general strategies for performance
3659 				 * and maintenance, though don't change the semantic results
3660 				 * from normal data reads and writes. Delaying an ALTER TABLE
3661 				 * behind currently active writes only delays the point where
3662 				 * the new strategy begins to take effect, so there is no
3663 				 * benefit in waiting. In this case the minimum restriction
3664 				 * applies: we don't currently allow concurrent catalog
3665 				 * updates.
3666 				 */
3667 			case AT_SetStatistics:	/* Uses MVCC in getTableAttrs() */
3668 			case AT_ClusterOn:	/* Uses MVCC in getIndexes() */
3669 			case AT_DropCluster:	/* Uses MVCC in getIndexes() */
3670 			case AT_SetOptions: /* Uses MVCC in getTableAttrs() */
3671 			case AT_ResetOptions:	/* Uses MVCC in getTableAttrs() */
3672 				cmd_lockmode = ShareUpdateExclusiveLock;
3673 				break;
3674 
3675 			case AT_SetLogged:
3676 			case AT_SetUnLogged:
3677 				cmd_lockmode = AccessExclusiveLock;
3678 				break;
3679 
3680 			case AT_ValidateConstraint: /* Uses MVCC in getConstraints() */
3681 				cmd_lockmode = ShareUpdateExclusiveLock;
3682 				break;
3683 
3684 				/*
3685 				 * Rel options are more complex than first appears. Options
3686 				 * are set here for tables, views and indexes; for historical
3687 				 * reasons these can all be used with ALTER TABLE, so we can't
3688 				 * decide between them using the basic grammar.
3689 				 */
3690 			case AT_SetRelOptions:	/* Uses MVCC in getIndexes() and
3691 									 * getTables() */
3692 			case AT_ResetRelOptions:	/* Uses MVCC in getIndexes() and
3693 										 * getTables() */
3694 				cmd_lockmode = AlterTableGetRelOptionsLockLevel((List *) cmd->def);
3695 				break;
3696 
3697 			case AT_AttachPartition:
3698 			case AT_DetachPartition:
3699 				cmd_lockmode = AccessExclusiveLock;
3700 				break;
3701 
3702 			default:			/* oops */
3703 				elog(ERROR, "unrecognized alter table type: %d",
3704 					 (int) cmd->subtype);
3705 				break;
3706 		}
3707 
3708 		/*
3709 		 * Take the greatest lockmode from any subcommand
3710 		 */
3711 		if (cmd_lockmode > lockmode)
3712 			lockmode = cmd_lockmode;
3713 	}
3714 
3715 	return lockmode;
3716 }
3717 
3718 /*
3719  * ATController provides top level control over the phases.
3720  *
3721  * parsetree is passed in to allow it to be passed to event triggers
3722  * when requested.
3723  */
3724 static void
ATController(AlterTableStmt * parsetree,Relation rel,List * cmds,bool recurse,LOCKMODE lockmode)3725 ATController(AlterTableStmt *parsetree,
3726 			 Relation rel, List *cmds, bool recurse, LOCKMODE lockmode)
3727 {
3728 	List	   *wqueue = NIL;
3729 	ListCell   *lcmd;
3730 
3731 	/* Phase 1: preliminary examination of commands, create work queue */
3732 	foreach(lcmd, cmds)
3733 	{
3734 		AlterTableCmd *cmd = (AlterTableCmd *) lfirst(lcmd);
3735 
3736 		ATPrepCmd(&wqueue, rel, cmd, recurse, false, lockmode);
3737 	}
3738 
3739 	/* Close the relation, but keep lock until commit */
3740 	relation_close(rel, NoLock);
3741 
3742 	/* Phase 2: update system catalogs */
3743 	ATRewriteCatalogs(&wqueue, lockmode);
3744 
3745 	/* Phase 3: scan/rewrite tables as needed */
3746 	ATRewriteTables(parsetree, &wqueue, lockmode);
3747 }
3748 
3749 /*
3750  * ATPrepCmd
3751  *
3752  * Traffic cop for ALTER TABLE Phase 1 operations, including simple
3753  * recursion and permission checks.
3754  *
3755  * Caller must have acquired appropriate lock type on relation already.
3756  * This lock should be held until commit.
3757  */
3758 static void
ATPrepCmd(List ** wqueue,Relation rel,AlterTableCmd * cmd,bool recurse,bool recursing,LOCKMODE lockmode)3759 ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd,
3760 		  bool recurse, bool recursing, LOCKMODE lockmode)
3761 {
3762 	AlteredTableInfo *tab;
3763 	int			pass = AT_PASS_UNSET;
3764 
3765 	/* Find or create work queue entry for this table */
3766 	tab = ATGetQueueEntry(wqueue, rel);
3767 
3768 	/*
3769 	 * Copy the original subcommand for each table.  This avoids conflicts
3770 	 * when different child tables need to make different parse
3771 	 * transformations (for example, the same column may have different column
3772 	 * numbers in different children).
3773 	 */
3774 	cmd = copyObject(cmd);
3775 
3776 	/*
3777 	 * Do permissions checking, recursion to child tables if needed, and any
3778 	 * additional phase-1 processing needed.
3779 	 */
3780 	switch (cmd->subtype)
3781 	{
3782 		case AT_AddColumn:		/* ADD COLUMN */
3783 			ATSimplePermissions(rel,
3784 								ATT_TABLE | ATT_COMPOSITE_TYPE | ATT_FOREIGN_TABLE);
3785 			ATPrepAddColumn(wqueue, rel, recurse, recursing, false, cmd,
3786 							lockmode);
3787 			/* Recursion occurs during execution phase */
3788 			pass = AT_PASS_ADD_COL;
3789 			break;
3790 		case AT_AddColumnToView:	/* add column via CREATE OR REPLACE VIEW */
3791 			ATSimplePermissions(rel, ATT_VIEW);
3792 			ATPrepAddColumn(wqueue, rel, recurse, recursing, true, cmd,
3793 							lockmode);
3794 			/* Recursion occurs during execution phase */
3795 			pass = AT_PASS_ADD_COL;
3796 			break;
3797 		case AT_ColumnDefault:	/* ALTER COLUMN DEFAULT */
3798 
3799 			/*
3800 			 * We allow defaults on views so that INSERT into a view can have
3801 			 * default-ish behavior.  This works because the rewriter
3802 			 * substitutes default values into INSERTs before it expands
3803 			 * rules.
3804 			 */
3805 			ATSimplePermissions(rel, ATT_TABLE | ATT_VIEW | ATT_FOREIGN_TABLE);
3806 			ATSimpleRecursion(wqueue, rel, cmd, recurse, lockmode);
3807 			/* No command-specific prep needed */
3808 			pass = cmd->def ? AT_PASS_ADD_CONSTR : AT_PASS_DROP;
3809 			break;
3810 		case AT_AddIdentity:
3811 			ATSimplePermissions(rel, ATT_TABLE | ATT_VIEW | ATT_FOREIGN_TABLE);
3812 			/* This command never recurses */
3813 			pass = AT_PASS_ADD_CONSTR;
3814 			break;
3815 		case AT_SetIdentity:
3816 			ATSimplePermissions(rel, ATT_TABLE | ATT_VIEW | ATT_FOREIGN_TABLE);
3817 			/* This command never recurses */
3818 			pass = AT_PASS_COL_ATTRS;
3819 			break;
3820 		case AT_DropIdentity:
3821 			ATSimplePermissions(rel, ATT_TABLE | ATT_VIEW | ATT_FOREIGN_TABLE);
3822 			/* This command never recurses */
3823 			pass = AT_PASS_DROP;
3824 			break;
3825 		case AT_DropNotNull:	/* ALTER COLUMN DROP NOT NULL */
3826 			ATSimplePermissions(rel, ATT_TABLE | ATT_FOREIGN_TABLE);
3827 			ATPrepDropNotNull(rel, recurse, recursing);
3828 			ATSimpleRecursion(wqueue, rel, cmd, recurse, lockmode);
3829 			/* No command-specific prep needed */
3830 			pass = AT_PASS_DROP;
3831 			break;
3832 		case AT_SetNotNull:		/* ALTER COLUMN SET NOT NULL */
3833 			ATSimplePermissions(rel, ATT_TABLE | ATT_FOREIGN_TABLE);
3834 			ATPrepSetNotNull(rel, recurse, recursing);
3835 			ATSimpleRecursion(wqueue, rel, cmd, recurse, lockmode);
3836 			/* No command-specific prep needed */
3837 			pass = AT_PASS_ADD_CONSTR;
3838 			break;
3839 		case AT_SetStatistics:	/* ALTER COLUMN SET STATISTICS */
3840 			ATSimpleRecursion(wqueue, rel, cmd, recurse, lockmode);
3841 			/* Performs own permission checks */
3842 			ATPrepSetStatistics(rel, cmd->name, cmd->num, cmd->def, lockmode);
3843 			pass = AT_PASS_MISC;
3844 			break;
3845 		case AT_SetOptions:		/* ALTER COLUMN SET ( options ) */
3846 		case AT_ResetOptions:	/* ALTER COLUMN RESET ( options ) */
3847 			ATSimplePermissions(rel, ATT_TABLE | ATT_MATVIEW | ATT_INDEX | ATT_FOREIGN_TABLE);
3848 			/* This command never recurses */
3849 			pass = AT_PASS_MISC;
3850 			break;
3851 		case AT_SetStorage:		/* ALTER COLUMN SET STORAGE */
3852 			ATSimplePermissions(rel, ATT_TABLE | ATT_MATVIEW | ATT_FOREIGN_TABLE);
3853 			ATSimpleRecursion(wqueue, rel, cmd, recurse, lockmode);
3854 			/* No command-specific prep needed */
3855 			pass = AT_PASS_MISC;
3856 			break;
3857 		case AT_DropColumn:		/* DROP COLUMN */
3858 			ATSimplePermissions(rel,
3859 								ATT_TABLE | ATT_COMPOSITE_TYPE | ATT_FOREIGN_TABLE);
3860 			ATPrepDropColumn(wqueue, rel, recurse, recursing, cmd, lockmode);
3861 			/* Recursion occurs during execution phase */
3862 			pass = AT_PASS_DROP;
3863 			break;
3864 		case AT_AddIndex:		/* ADD INDEX */
3865 			ATSimplePermissions(rel, ATT_TABLE);
3866 			/* This command never recurses */
3867 			/* No command-specific prep needed */
3868 			pass = AT_PASS_ADD_INDEX;
3869 			break;
3870 		case AT_AddConstraint:	/* ADD CONSTRAINT */
3871 			ATSimplePermissions(rel, ATT_TABLE | ATT_FOREIGN_TABLE);
3872 			/* Recursion occurs during execution phase */
3873 			/* No command-specific prep needed except saving recurse flag */
3874 			if (recurse)
3875 				cmd->subtype = AT_AddConstraintRecurse;
3876 			pass = AT_PASS_ADD_CONSTR;
3877 			break;
3878 		case AT_AddIndexConstraint: /* ADD CONSTRAINT USING INDEX */
3879 			ATSimplePermissions(rel, ATT_TABLE);
3880 			/* This command never recurses */
3881 			/* No command-specific prep needed */
3882 			pass = AT_PASS_ADD_CONSTR;
3883 			break;
3884 		case AT_DropConstraint: /* DROP CONSTRAINT */
3885 			ATSimplePermissions(rel, ATT_TABLE | ATT_FOREIGN_TABLE);
3886 			ATCheckPartitionsNotInUse(rel, lockmode);
3887 			/* Other recursion occurs during execution phase */
3888 			/* No command-specific prep needed except saving recurse flag */
3889 			if (recurse)
3890 				cmd->subtype = AT_DropConstraintRecurse;
3891 			pass = AT_PASS_DROP;
3892 			break;
3893 		case AT_AlterColumnType:	/* ALTER COLUMN TYPE */
3894 			ATSimplePermissions(rel,
3895 								ATT_TABLE | ATT_COMPOSITE_TYPE | ATT_FOREIGN_TABLE);
3896 			/* Performs own recursion */
3897 			ATPrepAlterColumnType(wqueue, tab, rel, recurse, recursing, cmd, lockmode);
3898 			pass = AT_PASS_ALTER_TYPE;
3899 			break;
3900 		case AT_AlterColumnGenericOptions:
3901 			ATSimplePermissions(rel, ATT_FOREIGN_TABLE);
3902 			/* This command never recurses */
3903 			/* No command-specific prep needed */
3904 			pass = AT_PASS_MISC;
3905 			break;
3906 		case AT_ChangeOwner:	/* ALTER OWNER */
3907 			/* This command never recurses */
3908 			/* No command-specific prep needed */
3909 			pass = AT_PASS_MISC;
3910 			break;
3911 		case AT_ClusterOn:		/* CLUSTER ON */
3912 		case AT_DropCluster:	/* SET WITHOUT CLUSTER */
3913 			ATSimplePermissions(rel, ATT_TABLE | ATT_MATVIEW);
3914 			/* These commands never recurse */
3915 			/* No command-specific prep needed */
3916 			pass = AT_PASS_MISC;
3917 			break;
3918 		case AT_SetLogged:		/* SET LOGGED */
3919 			ATSimplePermissions(rel, ATT_TABLE);
3920 			tab->chgPersistence = ATPrepChangePersistence(rel, true);
3921 			/* force rewrite if necessary; see comment in ATRewriteTables */
3922 			if (tab->chgPersistence)
3923 			{
3924 				tab->rewrite |= AT_REWRITE_ALTER_PERSISTENCE;
3925 				tab->newrelpersistence = RELPERSISTENCE_PERMANENT;
3926 			}
3927 			pass = AT_PASS_MISC;
3928 			break;
3929 		case AT_SetUnLogged:	/* SET UNLOGGED */
3930 			ATSimplePermissions(rel, ATT_TABLE);
3931 			tab->chgPersistence = ATPrepChangePersistence(rel, false);
3932 			/* force rewrite if necessary; see comment in ATRewriteTables */
3933 			if (tab->chgPersistence)
3934 			{
3935 				tab->rewrite |= AT_REWRITE_ALTER_PERSISTENCE;
3936 				tab->newrelpersistence = RELPERSISTENCE_UNLOGGED;
3937 			}
3938 			pass = AT_PASS_MISC;
3939 			break;
3940 		case AT_AddOids:		/* SET WITH OIDS */
3941 			ATSimplePermissions(rel, ATT_TABLE | ATT_FOREIGN_TABLE);
3942 			if (!rel->rd_rel->relhasoids || recursing)
3943 				ATPrepAddOids(wqueue, rel, recurse, cmd, lockmode);
3944 			/* Recursion occurs during execution phase */
3945 			pass = AT_PASS_ADD_COL;
3946 			break;
3947 		case AT_DropOids:		/* SET WITHOUT OIDS */
3948 			ATSimplePermissions(rel, ATT_TABLE | ATT_FOREIGN_TABLE);
3949 			/* Performs own recursion */
3950 			if (rel->rd_rel->relhasoids)
3951 			{
3952 				AlterTableCmd *dropCmd = makeNode(AlterTableCmd);
3953 
3954 				dropCmd->subtype = AT_DropColumn;
3955 				dropCmd->name = pstrdup("oid");
3956 				dropCmd->behavior = cmd->behavior;
3957 				ATPrepCmd(wqueue, rel, dropCmd, recurse, false, lockmode);
3958 			}
3959 			pass = AT_PASS_DROP;
3960 			break;
3961 		case AT_SetTableSpace:	/* SET TABLESPACE */
3962 			ATSimplePermissions(rel, ATT_TABLE | ATT_MATVIEW | ATT_INDEX |
3963 								ATT_PARTITIONED_INDEX);
3964 			/* This command never recurses */
3965 			ATPrepSetTableSpace(tab, rel, cmd->name, lockmode);
3966 			pass = AT_PASS_MISC;	/* doesn't actually matter */
3967 			break;
3968 		case AT_SetRelOptions:	/* SET (...) */
3969 		case AT_ResetRelOptions:	/* RESET (...) */
3970 		case AT_ReplaceRelOptions:	/* reset them all, then set just these */
3971 			ATSimplePermissions(rel, ATT_TABLE | ATT_VIEW | ATT_MATVIEW | ATT_INDEX);
3972 			/* This command never recurses */
3973 			/* No command-specific prep needed */
3974 			pass = AT_PASS_MISC;
3975 			break;
3976 		case AT_AddInherit:		/* INHERIT */
3977 			ATSimplePermissions(rel, ATT_TABLE | ATT_FOREIGN_TABLE);
3978 			/* This command never recurses */
3979 			ATPrepAddInherit(rel);
3980 			pass = AT_PASS_MISC;
3981 			break;
3982 		case AT_DropInherit:	/* NO INHERIT */
3983 			ATSimplePermissions(rel, ATT_TABLE | ATT_FOREIGN_TABLE);
3984 			/* This command never recurses */
3985 			/* No command-specific prep needed */
3986 			pass = AT_PASS_MISC;
3987 			break;
3988 		case AT_AlterConstraint:	/* ALTER CONSTRAINT */
3989 			ATSimplePermissions(rel, ATT_TABLE);
3990 			/* Recursion occurs during execution phase */
3991 			pass = AT_PASS_MISC;
3992 			break;
3993 		case AT_ValidateConstraint: /* VALIDATE CONSTRAINT */
3994 			ATSimplePermissions(rel, ATT_TABLE | ATT_FOREIGN_TABLE);
3995 			/* Recursion occurs during execution phase */
3996 			/* No command-specific prep needed except saving recurse flag */
3997 			if (recurse)
3998 				cmd->subtype = AT_ValidateConstraintRecurse;
3999 			pass = AT_PASS_MISC;
4000 			break;
4001 		case AT_ReplicaIdentity:	/* REPLICA IDENTITY ... */
4002 			ATSimplePermissions(rel, ATT_TABLE | ATT_MATVIEW);
4003 			pass = AT_PASS_MISC;
4004 			/* This command never recurses */
4005 			/* No command-specific prep needed */
4006 			break;
4007 		case AT_EnableTrig:		/* ENABLE TRIGGER variants */
4008 		case AT_EnableAlwaysTrig:
4009 		case AT_EnableReplicaTrig:
4010 		case AT_EnableTrigAll:
4011 		case AT_EnableTrigUser:
4012 		case AT_DisableTrig:	/* DISABLE TRIGGER variants */
4013 		case AT_DisableTrigAll:
4014 		case AT_DisableTrigUser:
4015 			ATSimplePermissions(rel, ATT_TABLE | ATT_FOREIGN_TABLE);
4016 			if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
4017 				ATSimpleRecursion(wqueue, rel, cmd, recurse, lockmode);
4018 			pass = AT_PASS_MISC;
4019 			break;
4020 		case AT_EnableRule:		/* ENABLE/DISABLE RULE variants */
4021 		case AT_EnableAlwaysRule:
4022 		case AT_EnableReplicaRule:
4023 		case AT_DisableRule:
4024 		case AT_AddOf:			/* OF */
4025 		case AT_DropOf:			/* NOT OF */
4026 		case AT_EnableRowSecurity:
4027 		case AT_DisableRowSecurity:
4028 		case AT_ForceRowSecurity:
4029 		case AT_NoForceRowSecurity:
4030 			ATSimplePermissions(rel, ATT_TABLE);
4031 			/* These commands never recurse */
4032 			/* No command-specific prep needed */
4033 			pass = AT_PASS_MISC;
4034 			break;
4035 		case AT_GenericOptions:
4036 			ATSimplePermissions(rel, ATT_FOREIGN_TABLE);
4037 			/* No command-specific prep needed */
4038 			pass = AT_PASS_MISC;
4039 			break;
4040 		case AT_AttachPartition:
4041 			ATSimplePermissions(rel, ATT_TABLE | ATT_PARTITIONED_INDEX);
4042 			/* No command-specific prep needed */
4043 			pass = AT_PASS_MISC;
4044 			break;
4045 		case AT_DetachPartition:
4046 			ATSimplePermissions(rel, ATT_TABLE);
4047 			/* No command-specific prep needed */
4048 			pass = AT_PASS_MISC;
4049 			break;
4050 		default:				/* oops */
4051 			elog(ERROR, "unrecognized alter table type: %d",
4052 				 (int) cmd->subtype);
4053 			pass = AT_PASS_UNSET;	/* keep compiler quiet */
4054 			break;
4055 	}
4056 	Assert(pass > AT_PASS_UNSET);
4057 
4058 	/* Add the subcommand to the appropriate list for phase 2 */
4059 	tab->subcmds[pass] = lappend(tab->subcmds[pass], cmd);
4060 }
4061 
4062 /*
4063  * ATRewriteCatalogs
4064  *
4065  * Traffic cop for ALTER TABLE Phase 2 operations.  Subcommands are
4066  * dispatched in a "safe" execution order (designed to avoid unnecessary
4067  * conflicts).
4068  */
4069 static void
ATRewriteCatalogs(List ** wqueue,LOCKMODE lockmode)4070 ATRewriteCatalogs(List **wqueue, LOCKMODE lockmode)
4071 {
4072 	int			pass;
4073 	ListCell   *ltab;
4074 
4075 	/*
4076 	 * We process all the tables "in parallel", one pass at a time.  This is
4077 	 * needed because we may have to propagate work from one table to another
4078 	 * (specifically, ALTER TYPE on a foreign key's PK has to dispatch the
4079 	 * re-adding of the foreign key constraint to the other table).  Work can
4080 	 * only be propagated into later passes, however.
4081 	 */
4082 	for (pass = 0; pass < AT_NUM_PASSES; pass++)
4083 	{
4084 		/* Go through each table that needs to be processed */
4085 		foreach(ltab, *wqueue)
4086 		{
4087 			AlteredTableInfo *tab = (AlteredTableInfo *) lfirst(ltab);
4088 			List	   *subcmds = tab->subcmds[pass];
4089 			Relation	rel;
4090 			ListCell   *lcmd;
4091 
4092 			if (subcmds == NIL)
4093 				continue;
4094 
4095 			/*
4096 			 * Appropriate lock was obtained by phase 1, needn't get it again
4097 			 */
4098 			rel = relation_open(tab->relid, NoLock);
4099 
4100 			foreach(lcmd, subcmds)
4101 				ATExecCmd(wqueue, tab, rel,
4102 						  castNode(AlterTableCmd, lfirst(lcmd)),
4103 						  lockmode);
4104 
4105 			/*
4106 			 * After the ALTER TYPE pass, do cleanup work (this is not done in
4107 			 * ATExecAlterColumnType since it should be done only once if
4108 			 * multiple columns of a table are altered).
4109 			 */
4110 			if (pass == AT_PASS_ALTER_TYPE)
4111 				ATPostAlterTypeCleanup(wqueue, tab, lockmode);
4112 
4113 			relation_close(rel, NoLock);
4114 		}
4115 	}
4116 
4117 	/* Check to see if a toast table must be added. */
4118 	foreach(ltab, *wqueue)
4119 	{
4120 		AlteredTableInfo *tab = (AlteredTableInfo *) lfirst(ltab);
4121 
4122 		/*
4123 		 * If the table is source table of ATTACH PARTITION command, we did
4124 		 * not modify anything about it that will change its toasting
4125 		 * requirement, so no need to check.
4126 		 */
4127 		if (((tab->relkind == RELKIND_RELATION ||
4128 			  tab->relkind == RELKIND_PARTITIONED_TABLE) &&
4129 			 tab->partition_constraint == NULL) ||
4130 			tab->relkind == RELKIND_MATVIEW)
4131 			AlterTableCreateToastTable(tab->relid, (Datum) 0, lockmode);
4132 	}
4133 }
4134 
4135 /*
4136  * ATExecCmd: dispatch a subcommand to appropriate execution routine
4137  */
4138 static void
ATExecCmd(List ** wqueue,AlteredTableInfo * tab,Relation rel,AlterTableCmd * cmd,LOCKMODE lockmode)4139 ATExecCmd(List **wqueue, AlteredTableInfo *tab, Relation rel,
4140 		  AlterTableCmd *cmd, LOCKMODE lockmode)
4141 {
4142 	ObjectAddress address = InvalidObjectAddress;
4143 
4144 	switch (cmd->subtype)
4145 	{
4146 		case AT_AddColumn:		/* ADD COLUMN */
4147 		case AT_AddColumnToView:	/* add column via CREATE OR REPLACE VIEW */
4148 			address = ATExecAddColumn(wqueue, tab, rel, (ColumnDef *) cmd->def,
4149 									  false, false, false,
4150 									  cmd->missing_ok, lockmode);
4151 			break;
4152 		case AT_AddColumnRecurse:
4153 			address = ATExecAddColumn(wqueue, tab, rel, (ColumnDef *) cmd->def,
4154 									  false, true, false,
4155 									  cmd->missing_ok, lockmode);
4156 			break;
4157 		case AT_ColumnDefault:	/* ALTER COLUMN DEFAULT */
4158 			address = ATExecColumnDefault(rel, cmd->name, cmd->def, lockmode);
4159 			break;
4160 		case AT_AddIdentity:
4161 			address = ATExecAddIdentity(rel, cmd->name, cmd->def, lockmode);
4162 			break;
4163 		case AT_SetIdentity:
4164 			address = ATExecSetIdentity(rel, cmd->name, cmd->def, lockmode);
4165 			break;
4166 		case AT_DropIdentity:
4167 			address = ATExecDropIdentity(rel, cmd->name, cmd->missing_ok, lockmode);
4168 			break;
4169 		case AT_DropNotNull:	/* ALTER COLUMN DROP NOT NULL */
4170 			address = ATExecDropNotNull(rel, cmd->name, lockmode);
4171 			break;
4172 		case AT_SetNotNull:		/* ALTER COLUMN SET NOT NULL */
4173 			address = ATExecSetNotNull(tab, rel, cmd->name, lockmode);
4174 			break;
4175 		case AT_SetStatistics:	/* ALTER COLUMN SET STATISTICS */
4176 			address = ATExecSetStatistics(rel, cmd->name, cmd->num, cmd->def, lockmode);
4177 			break;
4178 		case AT_SetOptions:		/* ALTER COLUMN SET ( options ) */
4179 			address = ATExecSetOptions(rel, cmd->name, cmd->def, false, lockmode);
4180 			break;
4181 		case AT_ResetOptions:	/* ALTER COLUMN RESET ( options ) */
4182 			address = ATExecSetOptions(rel, cmd->name, cmd->def, true, lockmode);
4183 			break;
4184 		case AT_SetStorage:		/* ALTER COLUMN SET STORAGE */
4185 			address = ATExecSetStorage(rel, cmd->name, cmd->def, lockmode);
4186 			break;
4187 		case AT_DropColumn:		/* DROP COLUMN */
4188 			address = ATExecDropColumn(wqueue, rel, cmd->name,
4189 									   cmd->behavior, false, false,
4190 									   cmd->missing_ok, lockmode);
4191 			break;
4192 		case AT_DropColumnRecurse:	/* DROP COLUMN with recursion */
4193 			address = ATExecDropColumn(wqueue, rel, cmd->name,
4194 									   cmd->behavior, true, false,
4195 									   cmd->missing_ok, lockmode);
4196 			break;
4197 		case AT_AddIndex:		/* ADD INDEX */
4198 			address = ATExecAddIndex(tab, rel, (IndexStmt *) cmd->def, false,
4199 									 lockmode);
4200 			break;
4201 		case AT_ReAddIndex:		/* ADD INDEX */
4202 			address = ATExecAddIndex(tab, rel, (IndexStmt *) cmd->def, true,
4203 									 lockmode);
4204 			break;
4205 		case AT_AddConstraint:	/* ADD CONSTRAINT */
4206 			address =
4207 				ATExecAddConstraint(wqueue, tab, rel, (Constraint *) cmd->def,
4208 									false, false, lockmode);
4209 			break;
4210 		case AT_AddConstraintRecurse:	/* ADD CONSTRAINT with recursion */
4211 			address =
4212 				ATExecAddConstraint(wqueue, tab, rel, (Constraint *) cmd->def,
4213 									true, false, lockmode);
4214 			break;
4215 		case AT_ReAddConstraint:	/* Re-add pre-existing check constraint */
4216 			address =
4217 				ATExecAddConstraint(wqueue, tab, rel, (Constraint *) cmd->def,
4218 									true, true, lockmode);
4219 			break;
4220 		case AT_ReAddDomainConstraint:	/* Re-add pre-existing domain check
4221 										 * constraint */
4222 			address =
4223 				AlterDomainAddConstraint(((AlterDomainStmt *) cmd->def)->typeName,
4224 										 ((AlterDomainStmt *) cmd->def)->def,
4225 										 NULL);
4226 			break;
4227 		case AT_ReAddComment:	/* Re-add existing comment */
4228 			address = CommentObject((CommentStmt *) cmd->def);
4229 			break;
4230 		case AT_AddIndexConstraint: /* ADD CONSTRAINT USING INDEX */
4231 			address = ATExecAddIndexConstraint(tab, rel, (IndexStmt *) cmd->def,
4232 											   lockmode);
4233 			break;
4234 		case AT_AlterConstraint:	/* ALTER CONSTRAINT */
4235 			address = ATExecAlterConstraint(rel, cmd, false, false, lockmode);
4236 			break;
4237 		case AT_ValidateConstraint: /* VALIDATE CONSTRAINT */
4238 			address = ATExecValidateConstraint(wqueue, rel, cmd->name, false,
4239 											   false, lockmode);
4240 			break;
4241 		case AT_ValidateConstraintRecurse:	/* VALIDATE CONSTRAINT with
4242 											 * recursion */
4243 			address = ATExecValidateConstraint(wqueue, rel, cmd->name, true,
4244 											   false, lockmode);
4245 			break;
4246 		case AT_DropConstraint: /* DROP CONSTRAINT */
4247 			ATExecDropConstraint(rel, cmd->name, cmd->behavior,
4248 								 false, false,
4249 								 cmd->missing_ok, lockmode);
4250 			break;
4251 		case AT_DropConstraintRecurse:	/* DROP CONSTRAINT with recursion */
4252 			ATExecDropConstraint(rel, cmd->name, cmd->behavior,
4253 								 true, false,
4254 								 cmd->missing_ok, lockmode);
4255 			break;
4256 		case AT_AlterColumnType:	/* ALTER COLUMN TYPE */
4257 			address = ATExecAlterColumnType(tab, rel, cmd, lockmode);
4258 			break;
4259 		case AT_AlterColumnGenericOptions:	/* ALTER COLUMN OPTIONS */
4260 			address =
4261 				ATExecAlterColumnGenericOptions(rel, cmd->name,
4262 												(List *) cmd->def, lockmode);
4263 			break;
4264 		case AT_ChangeOwner:	/* ALTER OWNER */
4265 			ATExecChangeOwner(RelationGetRelid(rel),
4266 							  get_rolespec_oid(cmd->newowner, false),
4267 							  false, lockmode);
4268 			break;
4269 		case AT_ClusterOn:		/* CLUSTER ON */
4270 			address = ATExecClusterOn(rel, cmd->name, lockmode);
4271 			break;
4272 		case AT_DropCluster:	/* SET WITHOUT CLUSTER */
4273 			ATExecDropCluster(rel, lockmode);
4274 			break;
4275 		case AT_SetLogged:		/* SET LOGGED */
4276 		case AT_SetUnLogged:	/* SET UNLOGGED */
4277 			break;
4278 		case AT_AddOids:		/* SET WITH OIDS */
4279 			/* Use the ADD COLUMN code, unless prep decided to do nothing */
4280 			if (cmd->def != NULL)
4281 				address =
4282 					ATExecAddColumn(wqueue, tab, rel, (ColumnDef *) cmd->def,
4283 									true, false, false,
4284 									cmd->missing_ok, lockmode);
4285 			break;
4286 		case AT_AddOidsRecurse: /* SET WITH OIDS */
4287 			/* Use the ADD COLUMN code, unless prep decided to do nothing */
4288 			if (cmd->def != NULL)
4289 				address =
4290 					ATExecAddColumn(wqueue, tab, rel, (ColumnDef *) cmd->def,
4291 									true, true, false,
4292 									cmd->missing_ok, lockmode);
4293 			break;
4294 		case AT_DropOids:		/* SET WITHOUT OIDS */
4295 
4296 			/*
4297 			 * Nothing to do here; we'll have generated a DropColumn
4298 			 * subcommand to do the real work
4299 			 */
4300 			break;
4301 		case AT_SetTableSpace:	/* SET TABLESPACE */
4302 			/*
4303 			 * Only do this for partitioned indexes, for which this is just
4304 			 * a catalog change.  Other relation types are handled by Phase 3.
4305 			 */
4306 			if (rel->rd_rel->relkind == RELKIND_PARTITIONED_INDEX)
4307 				ATExecPartedIdxSetTableSpace(rel, tab->newTableSpace);
4308 
4309 			break;
4310 		case AT_SetRelOptions:	/* SET (...) */
4311 		case AT_ResetRelOptions:	/* RESET (...) */
4312 		case AT_ReplaceRelOptions:	/* replace entire option list */
4313 			ATExecSetRelOptions(rel, (List *) cmd->def, cmd->subtype, lockmode);
4314 			break;
4315 		case AT_EnableTrig:		/* ENABLE TRIGGER name */
4316 			ATExecEnableDisableTrigger(rel, cmd->name,
4317 									   TRIGGER_FIRES_ON_ORIGIN, false, lockmode);
4318 			break;
4319 		case AT_EnableAlwaysTrig:	/* ENABLE ALWAYS TRIGGER name */
4320 			ATExecEnableDisableTrigger(rel, cmd->name,
4321 									   TRIGGER_FIRES_ALWAYS, false, lockmode);
4322 			break;
4323 		case AT_EnableReplicaTrig:	/* ENABLE REPLICA TRIGGER name */
4324 			ATExecEnableDisableTrigger(rel, cmd->name,
4325 									   TRIGGER_FIRES_ON_REPLICA, false, lockmode);
4326 			break;
4327 		case AT_DisableTrig:	/* DISABLE TRIGGER name */
4328 			ATExecEnableDisableTrigger(rel, cmd->name,
4329 									   TRIGGER_DISABLED, false, lockmode);
4330 			break;
4331 		case AT_EnableTrigAll:	/* ENABLE TRIGGER ALL */
4332 			ATExecEnableDisableTrigger(rel, NULL,
4333 									   TRIGGER_FIRES_ON_ORIGIN, false, lockmode);
4334 			break;
4335 		case AT_DisableTrigAll: /* DISABLE TRIGGER ALL */
4336 			ATExecEnableDisableTrigger(rel, NULL,
4337 									   TRIGGER_DISABLED, false, lockmode);
4338 			break;
4339 		case AT_EnableTrigUser: /* ENABLE TRIGGER USER */
4340 			ATExecEnableDisableTrigger(rel, NULL,
4341 									   TRIGGER_FIRES_ON_ORIGIN, true, lockmode);
4342 			break;
4343 		case AT_DisableTrigUser:	/* DISABLE TRIGGER USER */
4344 			ATExecEnableDisableTrigger(rel, NULL,
4345 									   TRIGGER_DISABLED, true, lockmode);
4346 			break;
4347 
4348 		case AT_EnableRule:		/* ENABLE RULE name */
4349 			ATExecEnableDisableRule(rel, cmd->name,
4350 									RULE_FIRES_ON_ORIGIN, lockmode);
4351 			break;
4352 		case AT_EnableAlwaysRule:	/* ENABLE ALWAYS RULE name */
4353 			ATExecEnableDisableRule(rel, cmd->name,
4354 									RULE_FIRES_ALWAYS, lockmode);
4355 			break;
4356 		case AT_EnableReplicaRule:	/* ENABLE REPLICA RULE name */
4357 			ATExecEnableDisableRule(rel, cmd->name,
4358 									RULE_FIRES_ON_REPLICA, lockmode);
4359 			break;
4360 		case AT_DisableRule:	/* DISABLE RULE name */
4361 			ATExecEnableDisableRule(rel, cmd->name,
4362 									RULE_DISABLED, lockmode);
4363 			break;
4364 
4365 		case AT_AddInherit:
4366 			address = ATExecAddInherit(rel, (RangeVar *) cmd->def, lockmode);
4367 			break;
4368 		case AT_DropInherit:
4369 			address = ATExecDropInherit(rel, (RangeVar *) cmd->def, lockmode);
4370 			break;
4371 		case AT_AddOf:
4372 			address = ATExecAddOf(rel, (TypeName *) cmd->def, lockmode);
4373 			break;
4374 		case AT_DropOf:
4375 			ATExecDropOf(rel, lockmode);
4376 			break;
4377 		case AT_ReplicaIdentity:
4378 			ATExecReplicaIdentity(rel, (ReplicaIdentityStmt *) cmd->def, lockmode);
4379 			break;
4380 		case AT_EnableRowSecurity:
4381 			ATExecEnableRowSecurity(rel);
4382 			break;
4383 		case AT_DisableRowSecurity:
4384 			ATExecDisableRowSecurity(rel);
4385 			break;
4386 		case AT_ForceRowSecurity:
4387 			ATExecForceNoForceRowSecurity(rel, true);
4388 			break;
4389 		case AT_NoForceRowSecurity:
4390 			ATExecForceNoForceRowSecurity(rel, false);
4391 			break;
4392 		case AT_GenericOptions:
4393 			ATExecGenericOptions(rel, (List *) cmd->def);
4394 			break;
4395 		case AT_AttachPartition:
4396 			if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
4397 				ATExecAttachPartition(wqueue, rel, (PartitionCmd *) cmd->def);
4398 			else
4399 				ATExecAttachPartitionIdx(wqueue, rel,
4400 										 ((PartitionCmd *) cmd->def)->name);
4401 			break;
4402 		case AT_DetachPartition:
4403 			/* ATPrepCmd ensures it must be a table */
4404 			Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
4405 			ATExecDetachPartition(rel, ((PartitionCmd *) cmd->def)->name);
4406 			break;
4407 		default:				/* oops */
4408 			elog(ERROR, "unrecognized alter table type: %d",
4409 				 (int) cmd->subtype);
4410 			break;
4411 	}
4412 
4413 	/*
4414 	 * Report the subcommand to interested event triggers.
4415 	 */
4416 	EventTriggerCollectAlterTableSubcmd((Node *) cmd, address);
4417 
4418 	/*
4419 	 * Bump the command counter to ensure the next subcommand in the sequence
4420 	 * can see the changes so far
4421 	 */
4422 	CommandCounterIncrement();
4423 }
4424 
4425 /*
4426  * ATRewriteTables: ALTER TABLE phase 3
4427  */
4428 static void
ATRewriteTables(AlterTableStmt * parsetree,List ** wqueue,LOCKMODE lockmode)4429 ATRewriteTables(AlterTableStmt *parsetree, List **wqueue, LOCKMODE lockmode)
4430 {
4431 	ListCell   *ltab;
4432 
4433 	/* Go through each table that needs to be checked or rewritten */
4434 	foreach(ltab, *wqueue)
4435 	{
4436 		AlteredTableInfo *tab = (AlteredTableInfo *) lfirst(ltab);
4437 
4438 		/*
4439 		 * Foreign tables have no storage, nor do partitioned tables and
4440 		 * indexes.
4441 		 */
4442 		if (tab->relkind == RELKIND_FOREIGN_TABLE ||
4443 			tab->relkind == RELKIND_PARTITIONED_TABLE ||
4444 			tab->relkind == RELKIND_PARTITIONED_INDEX)
4445 			continue;
4446 
4447 		/*
4448 		 * If we change column data types or add/remove OIDs, the operation
4449 		 * has to be propagated to tables that use this table's rowtype as a
4450 		 * column type.  tab->newvals will also be non-NULL in the case where
4451 		 * we're adding a column with a default.  We choose to forbid that
4452 		 * case as well, since composite types might eventually support
4453 		 * defaults.
4454 		 *
4455 		 * (Eventually we'll probably need to check for composite type
4456 		 * dependencies even when we're just scanning the table without a
4457 		 * rewrite, but at the moment a composite type does not enforce any
4458 		 * constraints, so it's not necessary/appropriate to enforce them just
4459 		 * during ALTER.)
4460 		 */
4461 		if (tab->newvals != NIL || tab->rewrite > 0)
4462 		{
4463 			Relation	rel;
4464 
4465 			rel = heap_open(tab->relid, NoLock);
4466 			find_composite_type_dependencies(rel->rd_rel->reltype, rel, NULL);
4467 			heap_close(rel, NoLock);
4468 		}
4469 
4470 		/*
4471 		 * We only need to rewrite the table if at least one column needs to
4472 		 * be recomputed, we are adding/removing the OID column, or we are
4473 		 * changing its persistence.
4474 		 *
4475 		 * There are two reasons for requiring a rewrite when changing
4476 		 * persistence: on one hand, we need to ensure that the buffers
4477 		 * belonging to each of the two relations are marked with or without
4478 		 * BM_PERMANENT properly.  On the other hand, since rewriting creates
4479 		 * and assigns a new relfilenode, we automatically create or drop an
4480 		 * init fork for the relation as appropriate.
4481 		 */
4482 		if (tab->rewrite > 0)
4483 		{
4484 			/* Build a temporary relation and copy data */
4485 			Relation	OldHeap;
4486 			Oid			OIDNewHeap;
4487 			Oid			NewTableSpace;
4488 			char		persistence;
4489 
4490 			OldHeap = heap_open(tab->relid, NoLock);
4491 
4492 			/*
4493 			 * We don't support rewriting of system catalogs; there are too
4494 			 * many corner cases and too little benefit.  In particular this
4495 			 * is certainly not going to work for mapped catalogs.
4496 			 */
4497 			if (IsSystemRelation(OldHeap))
4498 				ereport(ERROR,
4499 						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
4500 						 errmsg("cannot rewrite system relation \"%s\"",
4501 								RelationGetRelationName(OldHeap))));
4502 
4503 			if (RelationIsUsedAsCatalogTable(OldHeap))
4504 				ereport(ERROR,
4505 						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
4506 						 errmsg("cannot rewrite table \"%s\" used as a catalog table",
4507 								RelationGetRelationName(OldHeap))));
4508 
4509 			/*
4510 			 * Don't allow rewrite on temp tables of other backends ... their
4511 			 * local buffer manager is not going to cope.
4512 			 */
4513 			if (RELATION_IS_OTHER_TEMP(OldHeap))
4514 				ereport(ERROR,
4515 						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
4516 						 errmsg("cannot rewrite temporary tables of other sessions")));
4517 
4518 			/*
4519 			 * Select destination tablespace (same as original unless user
4520 			 * requested a change)
4521 			 */
4522 			if (tab->newTableSpace)
4523 				NewTableSpace = tab->newTableSpace;
4524 			else
4525 				NewTableSpace = OldHeap->rd_rel->reltablespace;
4526 
4527 			/*
4528 			 * Select persistence of transient table (same as original unless
4529 			 * user requested a change)
4530 			 */
4531 			persistence = tab->chgPersistence ?
4532 				tab->newrelpersistence : OldHeap->rd_rel->relpersistence;
4533 
4534 			heap_close(OldHeap, NoLock);
4535 
4536 			/*
4537 			 * Fire off an Event Trigger now, before actually rewriting the
4538 			 * table.
4539 			 *
4540 			 * We don't support Event Trigger for nested commands anywhere,
4541 			 * here included, and parsetree is given NULL when coming from
4542 			 * AlterTableInternal.
4543 			 *
4544 			 * And fire it only once.
4545 			 */
4546 			if (parsetree)
4547 				EventTriggerTableRewrite((Node *) parsetree,
4548 										 tab->relid,
4549 										 tab->rewrite);
4550 
4551 			/*
4552 			 * Create transient table that will receive the modified data.
4553 			 *
4554 			 * Ensure it is marked correctly as logged or unlogged.  We have
4555 			 * to do this here so that buffers for the new relfilenode will
4556 			 * have the right persistence set, and at the same time ensure
4557 			 * that the original filenode's buffers will get read in with the
4558 			 * correct setting (i.e. the original one).  Otherwise a rollback
4559 			 * after the rewrite would possibly result with buffers for the
4560 			 * original filenode having the wrong persistence setting.
4561 			 *
4562 			 * NB: This relies on swap_relation_files() also swapping the
4563 			 * persistence. That wouldn't work for pg_class, but that can't be
4564 			 * unlogged anyway.
4565 			 */
4566 			OIDNewHeap = make_new_heap(tab->relid, NewTableSpace, persistence,
4567 									   lockmode);
4568 
4569 			/*
4570 			 * Copy the heap data into the new table with the desired
4571 			 * modifications, and test the current data within the table
4572 			 * against new constraints generated by ALTER TABLE commands.
4573 			 */
4574 			ATRewriteTable(tab, OIDNewHeap, lockmode);
4575 
4576 			/*
4577 			 * Swap the physical files of the old and new heaps, then rebuild
4578 			 * indexes and discard the old heap.  We can use RecentXmin for
4579 			 * the table's new relfrozenxid because we rewrote all the tuples
4580 			 * in ATRewriteTable, so no older Xid remains in the table.  Also,
4581 			 * we never try to swap toast tables by content, since we have no
4582 			 * interest in letting this code work on system catalogs.
4583 			 */
4584 			finish_heap_swap(tab->relid, OIDNewHeap,
4585 							 false, false, true,
4586 							 !OidIsValid(tab->newTableSpace),
4587 							 RecentXmin,
4588 							 ReadNextMultiXactId(),
4589 							 persistence);
4590 		}
4591 		else
4592 		{
4593 			/*
4594 			 * Test the current data within the table against new constraints
4595 			 * generated by ALTER TABLE commands, but don't rebuild data.
4596 			 */
4597 			if (tab->constraints != NIL || tab->new_notnull ||
4598 				tab->partition_constraint != NULL)
4599 				ATRewriteTable(tab, InvalidOid, lockmode);
4600 
4601 			/*
4602 			 * If we had SET TABLESPACE but no reason to reconstruct tuples,
4603 			 * just do a block-by-block copy.
4604 			 */
4605 			if (tab->newTableSpace)
4606 				ATExecSetTableSpace(tab->relid, tab->newTableSpace, lockmode);
4607 		}
4608 	}
4609 
4610 	/*
4611 	 * Foreign key constraints are checked in a final pass, since (a) it's
4612 	 * generally best to examine each one separately, and (b) it's at least
4613 	 * theoretically possible that we have changed both relations of the
4614 	 * foreign key, and we'd better have finished both rewrites before we try
4615 	 * to read the tables.
4616 	 */
4617 	foreach(ltab, *wqueue)
4618 	{
4619 		AlteredTableInfo *tab = (AlteredTableInfo *) lfirst(ltab);
4620 		Relation	rel = NULL;
4621 		ListCell   *lcon;
4622 
4623 		/*
4624 		 * Foreign tables have no storage, nor do partitioned tables and
4625 		 * indexes.
4626 		 */
4627 		if (tab->relkind == RELKIND_FOREIGN_TABLE ||
4628 			tab->relkind == RELKIND_PARTITIONED_TABLE ||
4629 			tab->relkind == RELKIND_PARTITIONED_INDEX)
4630 			continue;
4631 
4632 		foreach(lcon, tab->constraints)
4633 		{
4634 			NewConstraint *con = lfirst(lcon);
4635 
4636 			if (con->contype == CONSTR_FOREIGN)
4637 			{
4638 				Constraint *fkconstraint = (Constraint *) con->qual;
4639 				Relation	refrel;
4640 
4641 				if (rel == NULL)
4642 				{
4643 					/* Long since locked, no need for another */
4644 					rel = heap_open(tab->relid, NoLock);
4645 				}
4646 
4647 				refrel = heap_open(con->refrelid, RowShareLock);
4648 
4649 				validateForeignKeyConstraint(fkconstraint->conname, rel, refrel,
4650 											 con->refindid,
4651 											 con->conid);
4652 
4653 				/*
4654 				 * No need to mark the constraint row as validated, we did
4655 				 * that when we inserted the row earlier.
4656 				 */
4657 
4658 				heap_close(refrel, NoLock);
4659 			}
4660 		}
4661 
4662 		if (rel)
4663 			heap_close(rel, NoLock);
4664 	}
4665 }
4666 
4667 /*
4668  * ATRewriteTable: scan or rewrite one table
4669  *
4670  * OIDNewHeap is InvalidOid if we don't need to rewrite
4671  */
4672 static void
ATRewriteTable(AlteredTableInfo * tab,Oid OIDNewHeap,LOCKMODE lockmode)4673 ATRewriteTable(AlteredTableInfo *tab, Oid OIDNewHeap, LOCKMODE lockmode)
4674 {
4675 	Relation	oldrel;
4676 	Relation	newrel;
4677 	TupleDesc	oldTupDesc;
4678 	TupleDesc	newTupDesc;
4679 	bool		needscan = false;
4680 	List	   *notnull_attrs;
4681 	int			i;
4682 	ListCell   *l;
4683 	EState	   *estate;
4684 	CommandId	mycid;
4685 	BulkInsertState bistate;
4686 	int			hi_options;
4687 	ExprState  *partqualstate = NULL;
4688 
4689 	/*
4690 	 * Open the relation(s).  We have surely already locked the existing
4691 	 * table.
4692 	 */
4693 	oldrel = heap_open(tab->relid, NoLock);
4694 	oldTupDesc = tab->oldDesc;
4695 	newTupDesc = RelationGetDescr(oldrel);	/* includes all mods */
4696 
4697 	if (OidIsValid(OIDNewHeap))
4698 		newrel = heap_open(OIDNewHeap, lockmode);
4699 	else
4700 		newrel = NULL;
4701 
4702 	/*
4703 	 * Prepare a BulkInsertState and options for heap_insert. Because we're
4704 	 * building a new heap, we can skip WAL-logging and fsync it to disk at
4705 	 * the end instead (unless WAL-logging is required for archiving or
4706 	 * streaming replication). The FSM is empty too, so don't bother using it.
4707 	 */
4708 	if (newrel)
4709 	{
4710 		mycid = GetCurrentCommandId(true);
4711 		bistate = GetBulkInsertState();
4712 
4713 		hi_options = HEAP_INSERT_SKIP_FSM;
4714 		if (!XLogIsNeeded())
4715 			hi_options |= HEAP_INSERT_SKIP_WAL;
4716 	}
4717 	else
4718 	{
4719 		/* keep compiler quiet about using these uninitialized */
4720 		mycid = 0;
4721 		bistate = NULL;
4722 		hi_options = 0;
4723 	}
4724 
4725 	/*
4726 	 * Generate the constraint and default execution states
4727 	 */
4728 
4729 	estate = CreateExecutorState();
4730 
4731 	/* Build the needed expression execution states */
4732 	foreach(l, tab->constraints)
4733 	{
4734 		NewConstraint *con = lfirst(l);
4735 
4736 		switch (con->contype)
4737 		{
4738 			case CONSTR_CHECK:
4739 				needscan = true;
4740 				con->qualstate = ExecPrepareExpr((Expr *) con->qual, estate);
4741 				break;
4742 			case CONSTR_FOREIGN:
4743 				/* Nothing to do here */
4744 				break;
4745 			default:
4746 				elog(ERROR, "unrecognized constraint type: %d",
4747 					 (int) con->contype);
4748 		}
4749 	}
4750 
4751 	/* Build expression execution states for partition check quals */
4752 	if (tab->partition_constraint)
4753 	{
4754 		needscan = true;
4755 		partqualstate = ExecPrepareExpr(tab->partition_constraint, estate);
4756 	}
4757 
4758 	foreach(l, tab->newvals)
4759 	{
4760 		NewColumnValue *ex = lfirst(l);
4761 
4762 		/* expr already planned */
4763 		ex->exprstate = ExecInitExpr((Expr *) ex->expr, NULL);
4764 	}
4765 
4766 	notnull_attrs = NIL;
4767 	if (newrel || tab->new_notnull)
4768 	{
4769 		/*
4770 		 * If we are rebuilding the tuples OR if we added any new NOT NULL
4771 		 * constraints, check all not-null constraints.  This is a bit of
4772 		 * overkill but it minimizes risk of bugs, and heap_attisnull is a
4773 		 * pretty cheap test anyway.
4774 		 */
4775 		for (i = 0; i < newTupDesc->natts; i++)
4776 		{
4777 			Form_pg_attribute attr = TupleDescAttr(newTupDesc, i);
4778 
4779 			if (attr->attnotnull && !attr->attisdropped)
4780 				notnull_attrs = lappend_int(notnull_attrs, i);
4781 		}
4782 		if (notnull_attrs)
4783 			needscan = true;
4784 	}
4785 
4786 	if (newrel || needscan)
4787 	{
4788 		ExprContext *econtext;
4789 		Datum	   *values;
4790 		bool	   *isnull;
4791 		TupleTableSlot *oldslot;
4792 		TupleTableSlot *newslot;
4793 		HeapScanDesc scan;
4794 		HeapTuple	tuple;
4795 		MemoryContext oldCxt;
4796 		List	   *dropped_attrs = NIL;
4797 		ListCell   *lc;
4798 		Snapshot	snapshot;
4799 
4800 		if (newrel)
4801 			ereport(DEBUG1,
4802 					(errmsg("rewriting table \"%s\"",
4803 							RelationGetRelationName(oldrel))));
4804 		else
4805 			ereport(DEBUG1,
4806 					(errmsg("verifying table \"%s\"",
4807 							RelationGetRelationName(oldrel))));
4808 
4809 		if (newrel)
4810 		{
4811 			/*
4812 			 * All predicate locks on the tuples or pages are about to be made
4813 			 * invalid, because we move tuples around.  Promote them to
4814 			 * relation locks.
4815 			 */
4816 			TransferPredicateLocksToHeapRelation(oldrel);
4817 		}
4818 
4819 		econtext = GetPerTupleExprContext(estate);
4820 
4821 		/*
4822 		 * Make tuple slots for old and new tuples.  Note that even when the
4823 		 * tuples are the same, the tupDescs might not be (consider ADD COLUMN
4824 		 * without a default).
4825 		 */
4826 		oldslot = MakeSingleTupleTableSlot(oldTupDesc);
4827 		newslot = MakeSingleTupleTableSlot(newTupDesc);
4828 
4829 		/* Preallocate values/isnull arrays */
4830 		i = Max(newTupDesc->natts, oldTupDesc->natts);
4831 		values = (Datum *) palloc(i * sizeof(Datum));
4832 		isnull = (bool *) palloc(i * sizeof(bool));
4833 		memset(values, 0, i * sizeof(Datum));
4834 		memset(isnull, true, i * sizeof(bool));
4835 
4836 		/*
4837 		 * Any attributes that are dropped according to the new tuple
4838 		 * descriptor can be set to NULL. We precompute the list of dropped
4839 		 * attributes to avoid needing to do so in the per-tuple loop.
4840 		 */
4841 		for (i = 0; i < newTupDesc->natts; i++)
4842 		{
4843 			if (TupleDescAttr(newTupDesc, i)->attisdropped)
4844 				dropped_attrs = lappend_int(dropped_attrs, i);
4845 		}
4846 
4847 		/*
4848 		 * Scan through the rows, generating a new row if needed and then
4849 		 * checking all the constraints.
4850 		 */
4851 		snapshot = RegisterSnapshot(GetLatestSnapshot());
4852 		scan = heap_beginscan(oldrel, snapshot, 0, NULL);
4853 
4854 		/*
4855 		 * Switch to per-tuple memory context and reset it for each tuple
4856 		 * produced, so we don't leak memory.
4857 		 */
4858 		oldCxt = MemoryContextSwitchTo(GetPerTupleMemoryContext(estate));
4859 
4860 		while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
4861 		{
4862 			if (tab->rewrite > 0)
4863 			{
4864 				Oid			tupOid = InvalidOid;
4865 
4866 				/* Extract data from old tuple */
4867 				heap_deform_tuple(tuple, oldTupDesc, values, isnull);
4868 				if (oldTupDesc->tdhasoid)
4869 					tupOid = HeapTupleGetOid(tuple);
4870 
4871 				/* Set dropped attributes to null in new tuple */
4872 				foreach(lc, dropped_attrs)
4873 					isnull[lfirst_int(lc)] = true;
4874 
4875 				/*
4876 				 * Process supplied expressions to replace selected columns.
4877 				 * Expression inputs come from the old tuple.
4878 				 */
4879 				ExecStoreTuple(tuple, oldslot, InvalidBuffer, false);
4880 				econtext->ecxt_scantuple = oldslot;
4881 
4882 				foreach(l, tab->newvals)
4883 				{
4884 					NewColumnValue *ex = lfirst(l);
4885 
4886 					values[ex->attnum - 1] = ExecEvalExpr(ex->exprstate,
4887 														  econtext,
4888 														  &isnull[ex->attnum - 1]);
4889 				}
4890 
4891 				/*
4892 				 * Form the new tuple. Note that we don't explicitly pfree it,
4893 				 * since the per-tuple memory context will be reset shortly.
4894 				 */
4895 				tuple = heap_form_tuple(newTupDesc, values, isnull);
4896 
4897 				/* Preserve OID, if any */
4898 				if (newTupDesc->tdhasoid)
4899 					HeapTupleSetOid(tuple, tupOid);
4900 
4901 				/*
4902 				 * Constraints might reference the tableoid column, so
4903 				 * initialize t_tableOid before evaluating them.
4904 				 */
4905 				tuple->t_tableOid = RelationGetRelid(oldrel);
4906 			}
4907 
4908 			/* Now check any constraints on the possibly-changed tuple */
4909 			ExecStoreTuple(tuple, newslot, InvalidBuffer, false);
4910 			econtext->ecxt_scantuple = newslot;
4911 
4912 			foreach(l, notnull_attrs)
4913 			{
4914 				int			attn = lfirst_int(l);
4915 
4916 				if (heap_attisnull(tuple, attn + 1, newTupDesc))
4917 				{
4918 					Form_pg_attribute attr = TupleDescAttr(newTupDesc, attn);
4919 
4920 					ereport(ERROR,
4921 							(errcode(ERRCODE_NOT_NULL_VIOLATION),
4922 							 errmsg("column \"%s\" contains null values",
4923 									NameStr(attr->attname)),
4924 							 errtablecol(oldrel, attn + 1)));
4925 				}
4926 			}
4927 
4928 			foreach(l, tab->constraints)
4929 			{
4930 				NewConstraint *con = lfirst(l);
4931 
4932 				switch (con->contype)
4933 				{
4934 					case CONSTR_CHECK:
4935 						if (!ExecCheck(con->qualstate, econtext))
4936 							ereport(ERROR,
4937 									(errcode(ERRCODE_CHECK_VIOLATION),
4938 									 errmsg("check constraint \"%s\" is violated by some row",
4939 											con->name),
4940 									 errtableconstraint(oldrel, con->name)));
4941 						break;
4942 					case CONSTR_FOREIGN:
4943 						/* Nothing to do here */
4944 						break;
4945 					default:
4946 						elog(ERROR, "unrecognized constraint type: %d",
4947 							 (int) con->contype);
4948 				}
4949 			}
4950 
4951 			if (partqualstate && !ExecCheck(partqualstate, econtext))
4952 			{
4953 				if (tab->validate_default)
4954 					ereport(ERROR,
4955 							(errcode(ERRCODE_CHECK_VIOLATION),
4956 							 errmsg("updated partition constraint for default partition would be violated by some row")));
4957 				else
4958 					ereport(ERROR,
4959 							(errcode(ERRCODE_CHECK_VIOLATION),
4960 							 errmsg("partition constraint is violated by some row")));
4961 			}
4962 
4963 			/* Write the tuple out to the new relation */
4964 			if (newrel)
4965 				heap_insert(newrel, tuple, mycid, hi_options, bistate);
4966 
4967 			ResetExprContext(econtext);
4968 
4969 			CHECK_FOR_INTERRUPTS();
4970 		}
4971 
4972 		MemoryContextSwitchTo(oldCxt);
4973 		heap_endscan(scan);
4974 		UnregisterSnapshot(snapshot);
4975 
4976 		ExecDropSingleTupleTableSlot(oldslot);
4977 		ExecDropSingleTupleTableSlot(newslot);
4978 	}
4979 
4980 	FreeExecutorState(estate);
4981 
4982 	heap_close(oldrel, NoLock);
4983 	if (newrel)
4984 	{
4985 		FreeBulkInsertState(bistate);
4986 
4987 		/* If we skipped writing WAL, then we need to sync the heap. */
4988 		if (hi_options & HEAP_INSERT_SKIP_WAL)
4989 			heap_sync(newrel);
4990 
4991 		heap_close(newrel, NoLock);
4992 	}
4993 }
4994 
4995 /*
4996  * ATGetQueueEntry: find or create an entry in the ALTER TABLE work queue
4997  */
4998 static AlteredTableInfo *
ATGetQueueEntry(List ** wqueue,Relation rel)4999 ATGetQueueEntry(List **wqueue, Relation rel)
5000 {
5001 	Oid			relid = RelationGetRelid(rel);
5002 	AlteredTableInfo *tab;
5003 	ListCell   *ltab;
5004 
5005 	foreach(ltab, *wqueue)
5006 	{
5007 		tab = (AlteredTableInfo *) lfirst(ltab);
5008 		if (tab->relid == relid)
5009 			return tab;
5010 	}
5011 
5012 	/*
5013 	 * Not there, so add it.  Note that we make a copy of the relation's
5014 	 * existing descriptor before anything interesting can happen to it.
5015 	 */
5016 	tab = (AlteredTableInfo *) palloc0(sizeof(AlteredTableInfo));
5017 	tab->relid = relid;
5018 	tab->relkind = rel->rd_rel->relkind;
5019 	tab->oldDesc = CreateTupleDescCopyConstr(RelationGetDescr(rel));
5020 	tab->newrelpersistence = RELPERSISTENCE_PERMANENT;
5021 	tab->chgPersistence = false;
5022 
5023 	*wqueue = lappend(*wqueue, tab);
5024 
5025 	return tab;
5026 }
5027 
5028 /*
5029  * ATSimplePermissions
5030  *
5031  * - Ensure that it is a relation (or possibly a view)
5032  * - Ensure this user is the owner
5033  * - Ensure that it is not a system table
5034  */
5035 static void
ATSimplePermissions(Relation rel,int allowed_targets)5036 ATSimplePermissions(Relation rel, int allowed_targets)
5037 {
5038 	int			actual_target;
5039 
5040 	switch (rel->rd_rel->relkind)
5041 	{
5042 		case RELKIND_RELATION:
5043 		case RELKIND_PARTITIONED_TABLE:
5044 			actual_target = ATT_TABLE;
5045 			break;
5046 		case RELKIND_VIEW:
5047 			actual_target = ATT_VIEW;
5048 			break;
5049 		case RELKIND_MATVIEW:
5050 			actual_target = ATT_MATVIEW;
5051 			break;
5052 		case RELKIND_INDEX:
5053 			actual_target = ATT_INDEX;
5054 			break;
5055 		case RELKIND_PARTITIONED_INDEX:
5056 			actual_target = ATT_PARTITIONED_INDEX;
5057 			break;
5058 		case RELKIND_COMPOSITE_TYPE:
5059 			actual_target = ATT_COMPOSITE_TYPE;
5060 			break;
5061 		case RELKIND_FOREIGN_TABLE:
5062 			actual_target = ATT_FOREIGN_TABLE;
5063 			break;
5064 		default:
5065 			actual_target = 0;
5066 			break;
5067 	}
5068 
5069 	/* Wrong target type? */
5070 	if ((actual_target & allowed_targets) == 0)
5071 		ATWrongRelkindError(rel, allowed_targets);
5072 
5073 	/* Permissions checks */
5074 	if (!pg_class_ownercheck(RelationGetRelid(rel), GetUserId()))
5075 		aclcheck_error(ACLCHECK_NOT_OWNER, get_relkind_objtype(rel->rd_rel->relkind),
5076 					   RelationGetRelationName(rel));
5077 
5078 	if (!allowSystemTableMods && IsSystemRelation(rel))
5079 		ereport(ERROR,
5080 				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
5081 				 errmsg("permission denied: \"%s\" is a system catalog",
5082 						RelationGetRelationName(rel))));
5083 }
5084 
5085 /*
5086  * ATWrongRelkindError
5087  *
5088  * Throw an error when a relation has been determined to be of the wrong
5089  * type.
5090  */
5091 static void
ATWrongRelkindError(Relation rel,int allowed_targets)5092 ATWrongRelkindError(Relation rel, int allowed_targets)
5093 {
5094 	char	   *msg;
5095 
5096 	switch (allowed_targets)
5097 	{
5098 		case ATT_TABLE:
5099 			msg = _("\"%s\" is not a table");
5100 			break;
5101 		case ATT_TABLE | ATT_VIEW:
5102 			msg = _("\"%s\" is not a table or view");
5103 			break;
5104 		case ATT_TABLE | ATT_VIEW | ATT_FOREIGN_TABLE:
5105 			msg = _("\"%s\" is not a table, view, or foreign table");
5106 			break;
5107 		case ATT_TABLE | ATT_VIEW | ATT_MATVIEW | ATT_INDEX:
5108 			msg = _("\"%s\" is not a table, view, materialized view, or index");
5109 			break;
5110 		case ATT_TABLE | ATT_MATVIEW:
5111 			msg = _("\"%s\" is not a table or materialized view");
5112 			break;
5113 		case ATT_TABLE | ATT_MATVIEW | ATT_INDEX:
5114 			msg = _("\"%s\" is not a table, materialized view, or index");
5115 			break;
5116 		case ATT_TABLE | ATT_MATVIEW | ATT_INDEX | ATT_PARTITIONED_INDEX:
5117 			msg = _("\"%s\" is not a table, materialized view, index, or partitioned index");
5118 			break;
5119 		case ATT_TABLE | ATT_MATVIEW | ATT_FOREIGN_TABLE:
5120 			msg = _("\"%s\" is not a table, materialized view, or foreign table");
5121 			break;
5122 		case ATT_TABLE | ATT_FOREIGN_TABLE:
5123 			msg = _("\"%s\" is not a table or foreign table");
5124 			break;
5125 		case ATT_TABLE | ATT_COMPOSITE_TYPE | ATT_FOREIGN_TABLE:
5126 			msg = _("\"%s\" is not a table, composite type, or foreign table");
5127 			break;
5128 		case ATT_TABLE | ATT_MATVIEW | ATT_INDEX | ATT_FOREIGN_TABLE:
5129 			msg = _("\"%s\" is not a table, materialized view, index, or foreign table");
5130 			break;
5131 		case ATT_TABLE | ATT_PARTITIONED_INDEX:
5132 			msg = _("\"%s\" is not a table or partitioned index");
5133 			break;
5134 		case ATT_VIEW:
5135 			msg = _("\"%s\" is not a view");
5136 			break;
5137 		case ATT_FOREIGN_TABLE:
5138 			msg = _("\"%s\" is not a foreign table");
5139 			break;
5140 		default:
5141 			/* shouldn't get here, add all necessary cases above */
5142 			msg = _("\"%s\" is of the wrong type");
5143 			break;
5144 	}
5145 
5146 	ereport(ERROR,
5147 			(errcode(ERRCODE_WRONG_OBJECT_TYPE),
5148 			 errmsg(msg, RelationGetRelationName(rel))));
5149 }
5150 
5151 /*
5152  * ATSimpleRecursion
5153  *
5154  * Simple table recursion sufficient for most ALTER TABLE operations.
5155  * All direct and indirect children are processed in an unspecified order.
5156  * Note that if a child inherits from the original table via multiple
5157  * inheritance paths, it will be visited just once.
5158  */
5159 static void
ATSimpleRecursion(List ** wqueue,Relation rel,AlterTableCmd * cmd,bool recurse,LOCKMODE lockmode)5160 ATSimpleRecursion(List **wqueue, Relation rel,
5161 				  AlterTableCmd *cmd, bool recurse, LOCKMODE lockmode)
5162 {
5163 	/*
5164 	 * Propagate to children if desired.  Only plain tables, foreign tables
5165 	 * and partitioned tables have children, so no need to search for other
5166 	 * relkinds.
5167 	 */
5168 	if (recurse &&
5169 		(rel->rd_rel->relkind == RELKIND_RELATION ||
5170 		 rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE ||
5171 		 rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE))
5172 	{
5173 		Oid			relid = RelationGetRelid(rel);
5174 		ListCell   *child;
5175 		List	   *children;
5176 
5177 		children = find_all_inheritors(relid, lockmode, NULL);
5178 
5179 		/*
5180 		 * find_all_inheritors does the recursive search of the inheritance
5181 		 * hierarchy, so all we have to do is process all of the relids in the
5182 		 * list that it returns.
5183 		 */
5184 		foreach(child, children)
5185 		{
5186 			Oid			childrelid = lfirst_oid(child);
5187 			Relation	childrel;
5188 
5189 			if (childrelid == relid)
5190 				continue;
5191 			/* find_all_inheritors already got lock */
5192 			childrel = relation_open(childrelid, NoLock);
5193 			CheckTableNotInUse(childrel, "ALTER TABLE");
5194 			ATPrepCmd(wqueue, childrel, cmd, false, true, lockmode);
5195 			relation_close(childrel, NoLock);
5196 		}
5197 	}
5198 }
5199 
5200 /*
5201  * Obtain list of partitions of the given table, locking them all at the given
5202  * lockmode and ensuring that they all pass CheckTableNotInUse.
5203  *
5204  * This function is a no-op if the given relation is not a partitioned table;
5205  * in particular, nothing is done if it's a legacy inheritance parent.
5206  */
5207 static void
ATCheckPartitionsNotInUse(Relation rel,LOCKMODE lockmode)5208 ATCheckPartitionsNotInUse(Relation rel, LOCKMODE lockmode)
5209 {
5210 	if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
5211 	{
5212 		List	   *inh;
5213 		ListCell   *cell;
5214 
5215 		inh = find_all_inheritors(RelationGetRelid(rel), lockmode, NULL);
5216 		/* first element is the parent rel; must ignore it */
5217 		for_each_cell(cell, lnext(list_head(inh)))
5218 		{
5219 			Relation	childrel;
5220 
5221 			/* find_all_inheritors already got lock */
5222 			childrel = heap_open(lfirst_oid(cell), NoLock);
5223 			CheckTableNotInUse(childrel, "ALTER TABLE");
5224 			heap_close(childrel, NoLock);
5225 		}
5226 		list_free(inh);
5227 	}
5228 }
5229 
5230 /*
5231  * ATTypedTableRecursion
5232  *
5233  * Propagate ALTER TYPE operations to the typed tables of that type.
5234  * Also check the RESTRICT/CASCADE behavior.  Given CASCADE, also permit
5235  * recursion to inheritance children of the typed tables.
5236  */
5237 static void
ATTypedTableRecursion(List ** wqueue,Relation rel,AlterTableCmd * cmd,LOCKMODE lockmode)5238 ATTypedTableRecursion(List **wqueue, Relation rel, AlterTableCmd *cmd,
5239 					  LOCKMODE lockmode)
5240 {
5241 	ListCell   *child;
5242 	List	   *children;
5243 
5244 	Assert(rel->rd_rel->relkind == RELKIND_COMPOSITE_TYPE);
5245 
5246 	children = find_typed_table_dependencies(rel->rd_rel->reltype,
5247 											 RelationGetRelationName(rel),
5248 											 cmd->behavior);
5249 
5250 	foreach(child, children)
5251 	{
5252 		Oid			childrelid = lfirst_oid(child);
5253 		Relation	childrel;
5254 
5255 		childrel = relation_open(childrelid, lockmode);
5256 		CheckTableNotInUse(childrel, "ALTER TABLE");
5257 		ATPrepCmd(wqueue, childrel, cmd, true, true, lockmode);
5258 		relation_close(childrel, NoLock);
5259 	}
5260 }
5261 
5262 
5263 /*
5264  * find_composite_type_dependencies
5265  *
5266  * Check to see if the type "typeOid" is being used as a column in some table
5267  * (possibly nested several levels deep in composite types, arrays, etc!).
5268  * Eventually, we'd like to propagate the check or rewrite operation
5269  * into such tables, but for now, just error out if we find any.
5270  *
5271  * Caller should provide either the associated relation of a rowtype,
5272  * or a type name (not both) for use in the error message, if any.
5273  *
5274  * Note that "typeOid" is not necessarily a composite type; it could also be
5275  * another container type such as an array or range, or a domain over one of
5276  * these things.  The name of this function is therefore somewhat historical,
5277  * but it's not worth changing.
5278  *
5279  * We assume that functions and views depending on the type are not reasons
5280  * to reject the ALTER.  (How safe is this really?)
5281  */
5282 void
find_composite_type_dependencies(Oid typeOid,Relation origRelation,const char * origTypeName)5283 find_composite_type_dependencies(Oid typeOid, Relation origRelation,
5284 								 const char *origTypeName)
5285 {
5286 	Relation	depRel;
5287 	ScanKeyData key[2];
5288 	SysScanDesc depScan;
5289 	HeapTuple	depTup;
5290 
5291 	/* since this function recurses, it could be driven to stack overflow */
5292 	check_stack_depth();
5293 
5294 	/*
5295 	 * We scan pg_depend to find those things that depend on the given type.
5296 	 * (We assume we can ignore refobjsubid for a type.)
5297 	 */
5298 	depRel = heap_open(DependRelationId, AccessShareLock);
5299 
5300 	ScanKeyInit(&key[0],
5301 				Anum_pg_depend_refclassid,
5302 				BTEqualStrategyNumber, F_OIDEQ,
5303 				ObjectIdGetDatum(TypeRelationId));
5304 	ScanKeyInit(&key[1],
5305 				Anum_pg_depend_refobjid,
5306 				BTEqualStrategyNumber, F_OIDEQ,
5307 				ObjectIdGetDatum(typeOid));
5308 
5309 	depScan = systable_beginscan(depRel, DependReferenceIndexId, true,
5310 								 NULL, 2, key);
5311 
5312 	while (HeapTupleIsValid(depTup = systable_getnext(depScan)))
5313 	{
5314 		Form_pg_depend pg_depend = (Form_pg_depend) GETSTRUCT(depTup);
5315 		Relation	rel;
5316 		Form_pg_attribute att;
5317 
5318 		/* Check for directly dependent types */
5319 		if (pg_depend->classid == TypeRelationId)
5320 		{
5321 			/*
5322 			 * This must be an array, domain, or range containing the given
5323 			 * type, so recursively check for uses of this type.  Note that
5324 			 * any error message will mention the original type not the
5325 			 * container; this is intentional.
5326 			 */
5327 			find_composite_type_dependencies(pg_depend->objid,
5328 											 origRelation, origTypeName);
5329 			continue;
5330 		}
5331 
5332 		/* Else, ignore dependees that aren't user columns of relations */
5333 		/* (we assume system columns are never of interesting types) */
5334 		if (pg_depend->classid != RelationRelationId ||
5335 			pg_depend->objsubid <= 0)
5336 			continue;
5337 
5338 		rel = relation_open(pg_depend->objid, AccessShareLock);
5339 		att = TupleDescAttr(rel->rd_att, pg_depend->objsubid - 1);
5340 
5341 		if (rel->rd_rel->relkind == RELKIND_RELATION ||
5342 			rel->rd_rel->relkind == RELKIND_MATVIEW ||
5343 			rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
5344 		{
5345 			if (origTypeName)
5346 				ereport(ERROR,
5347 						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
5348 						 errmsg("cannot alter type \"%s\" because column \"%s.%s\" uses it",
5349 								origTypeName,
5350 								RelationGetRelationName(rel),
5351 								NameStr(att->attname))));
5352 			else if (origRelation->rd_rel->relkind == RELKIND_COMPOSITE_TYPE)
5353 				ereport(ERROR,
5354 						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
5355 						 errmsg("cannot alter type \"%s\" because column \"%s.%s\" uses it",
5356 								RelationGetRelationName(origRelation),
5357 								RelationGetRelationName(rel),
5358 								NameStr(att->attname))));
5359 			else if (origRelation->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
5360 				ereport(ERROR,
5361 						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
5362 						 errmsg("cannot alter foreign table \"%s\" because column \"%s.%s\" uses its row type",
5363 								RelationGetRelationName(origRelation),
5364 								RelationGetRelationName(rel),
5365 								NameStr(att->attname))));
5366 			else
5367 				ereport(ERROR,
5368 						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
5369 						 errmsg("cannot alter table \"%s\" because column \"%s.%s\" uses its row type",
5370 								RelationGetRelationName(origRelation),
5371 								RelationGetRelationName(rel),
5372 								NameStr(att->attname))));
5373 		}
5374 		else if (OidIsValid(rel->rd_rel->reltype))
5375 		{
5376 			/*
5377 			 * A view or composite type itself isn't a problem, but we must
5378 			 * recursively check for indirect dependencies via its rowtype.
5379 			 */
5380 			find_composite_type_dependencies(rel->rd_rel->reltype,
5381 											 origRelation, origTypeName);
5382 		}
5383 
5384 		relation_close(rel, AccessShareLock);
5385 	}
5386 
5387 	systable_endscan(depScan);
5388 
5389 	relation_close(depRel, AccessShareLock);
5390 }
5391 
5392 
5393 /*
5394  * find_typed_table_dependencies
5395  *
5396  * Check to see if a composite type is being used as the type of a
5397  * typed table.  Abort if any are found and behavior is RESTRICT.
5398  * Else return the list of tables.
5399  */
5400 static List *
find_typed_table_dependencies(Oid typeOid,const char * typeName,DropBehavior behavior)5401 find_typed_table_dependencies(Oid typeOid, const char *typeName, DropBehavior behavior)
5402 {
5403 	Relation	classRel;
5404 	ScanKeyData key[1];
5405 	HeapScanDesc scan;
5406 	HeapTuple	tuple;
5407 	List	   *result = NIL;
5408 
5409 	classRel = heap_open(RelationRelationId, AccessShareLock);
5410 
5411 	ScanKeyInit(&key[0],
5412 				Anum_pg_class_reloftype,
5413 				BTEqualStrategyNumber, F_OIDEQ,
5414 				ObjectIdGetDatum(typeOid));
5415 
5416 	scan = heap_beginscan_catalog(classRel, 1, key);
5417 
5418 	while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
5419 	{
5420 		if (behavior == DROP_RESTRICT)
5421 			ereport(ERROR,
5422 					(errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
5423 					 errmsg("cannot alter type \"%s\" because it is the type of a typed table",
5424 							typeName),
5425 					 errhint("Use ALTER ... CASCADE to alter the typed tables too.")));
5426 		else
5427 			result = lappend_oid(result, HeapTupleGetOid(tuple));
5428 	}
5429 
5430 	heap_endscan(scan);
5431 	heap_close(classRel, AccessShareLock);
5432 
5433 	return result;
5434 }
5435 
5436 
5437 /*
5438  * check_of_type
5439  *
5440  * Check whether a type is suitable for CREATE TABLE OF/ALTER TABLE OF.  If it
5441  * isn't suitable, throw an error.  Currently, we require that the type
5442  * originated with CREATE TYPE AS.  We could support any row type, but doing so
5443  * would require handling a number of extra corner cases in the DDL commands.
5444  * (Also, allowing domain-over-composite would open up a can of worms about
5445  * whether and how the domain's constraints should apply to derived tables.)
5446  */
5447 void
check_of_type(HeapTuple typetuple)5448 check_of_type(HeapTuple typetuple)
5449 {
5450 	Form_pg_type typ = (Form_pg_type) GETSTRUCT(typetuple);
5451 	bool		typeOk = false;
5452 
5453 	if (typ->typtype == TYPTYPE_COMPOSITE)
5454 	{
5455 		Relation	typeRelation;
5456 
5457 		Assert(OidIsValid(typ->typrelid));
5458 		typeRelation = relation_open(typ->typrelid, AccessShareLock);
5459 		typeOk = (typeRelation->rd_rel->relkind == RELKIND_COMPOSITE_TYPE);
5460 
5461 		/*
5462 		 * Close the parent rel, but keep our AccessShareLock on it until xact
5463 		 * commit.  That will prevent someone else from deleting or ALTERing
5464 		 * the type before the typed table creation/conversion commits.
5465 		 */
5466 		relation_close(typeRelation, NoLock);
5467 	}
5468 	if (!typeOk)
5469 		ereport(ERROR,
5470 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
5471 				 errmsg("type %s is not a composite type",
5472 						format_type_be(HeapTupleGetOid(typetuple)))));
5473 }
5474 
5475 
5476 /*
5477  * ALTER TABLE ADD COLUMN
5478  *
5479  * Adds an additional attribute to a relation making the assumption that
5480  * CHECK, NOT NULL, and FOREIGN KEY constraints will be removed from the
5481  * AT_AddColumn AlterTableCmd by parse_utilcmd.c and added as independent
5482  * AlterTableCmd's.
5483  *
5484  * ADD COLUMN cannot use the normal ALTER TABLE recursion mechanism, because we
5485  * have to decide at runtime whether to recurse or not depending on whether we
5486  * actually add a column or merely merge with an existing column.  (We can't
5487  * check this in a static pre-pass because it won't handle multiple inheritance
5488  * situations correctly.)
5489  */
5490 static void
ATPrepAddColumn(List ** wqueue,Relation rel,bool recurse,bool recursing,bool is_view,AlterTableCmd * cmd,LOCKMODE lockmode)5491 ATPrepAddColumn(List **wqueue, Relation rel, bool recurse, bool recursing,
5492 				bool is_view, AlterTableCmd *cmd, LOCKMODE lockmode)
5493 {
5494 	if (rel->rd_rel->reloftype && !recursing)
5495 		ereport(ERROR,
5496 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
5497 				 errmsg("cannot add column to typed table")));
5498 
5499 	if (rel->rd_rel->relkind == RELKIND_COMPOSITE_TYPE)
5500 		ATTypedTableRecursion(wqueue, rel, cmd, lockmode);
5501 
5502 	if (recurse && !is_view)
5503 		cmd->subtype = AT_AddColumnRecurse;
5504 }
5505 
5506 /*
5507  * Add a column to a table; this handles the AT_AddOids cases as well.  The
5508  * return value is the address of the new column in the parent relation.
5509  */
5510 static ObjectAddress
ATExecAddColumn(List ** wqueue,AlteredTableInfo * tab,Relation rel,ColumnDef * colDef,bool isOid,bool recurse,bool recursing,bool if_not_exists,LOCKMODE lockmode)5511 ATExecAddColumn(List **wqueue, AlteredTableInfo *tab, Relation rel,
5512 				ColumnDef *colDef, bool isOid,
5513 				bool recurse, bool recursing,
5514 				bool if_not_exists, LOCKMODE lockmode)
5515 {
5516 	Oid			myrelid = RelationGetRelid(rel);
5517 	Relation	pgclass,
5518 				attrdesc;
5519 	HeapTuple	reltup;
5520 	FormData_pg_attribute attribute;
5521 	int			newattnum;
5522 	char		relkind;
5523 	HeapTuple	typeTuple;
5524 	Oid			typeOid;
5525 	int32		typmod;
5526 	Oid			collOid;
5527 	Form_pg_type tform;
5528 	Expr	   *defval;
5529 	List	   *children;
5530 	ListCell   *child;
5531 	AclResult	aclresult;
5532 	ObjectAddress address;
5533 
5534 	/* At top level, permission check was done in ATPrepCmd, else do it */
5535 	if (recursing)
5536 		ATSimplePermissions(rel, ATT_TABLE | ATT_FOREIGN_TABLE);
5537 
5538 	if (rel->rd_rel->relispartition && !recursing)
5539 		ereport(ERROR,
5540 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
5541 				 errmsg("cannot add column to a partition")));
5542 
5543 	attrdesc = heap_open(AttributeRelationId, RowExclusiveLock);
5544 
5545 	/*
5546 	 * Are we adding the column to a recursion child?  If so, check whether to
5547 	 * merge with an existing definition for the column.  If we do merge, we
5548 	 * must not recurse.  Children will already have the column, and recursing
5549 	 * into them would mess up attinhcount.
5550 	 */
5551 	if (colDef->inhcount > 0)
5552 	{
5553 		HeapTuple	tuple;
5554 
5555 		/* Does child already have a column by this name? */
5556 		tuple = SearchSysCacheCopyAttName(myrelid, colDef->colname);
5557 		if (HeapTupleIsValid(tuple))
5558 		{
5559 			Form_pg_attribute childatt = (Form_pg_attribute) GETSTRUCT(tuple);
5560 			Oid			ctypeId;
5561 			int32		ctypmod;
5562 			Oid			ccollid;
5563 
5564 			/* Child column must match on type, typmod, and collation */
5565 			typenameTypeIdAndMod(NULL, colDef->typeName, &ctypeId, &ctypmod);
5566 			if (ctypeId != childatt->atttypid ||
5567 				ctypmod != childatt->atttypmod)
5568 				ereport(ERROR,
5569 						(errcode(ERRCODE_DATATYPE_MISMATCH),
5570 						 errmsg("child table \"%s\" has different type for column \"%s\"",
5571 								RelationGetRelationName(rel), colDef->colname)));
5572 			ccollid = GetColumnDefCollation(NULL, colDef, ctypeId);
5573 			if (ccollid != childatt->attcollation)
5574 				ereport(ERROR,
5575 						(errcode(ERRCODE_COLLATION_MISMATCH),
5576 						 errmsg("child table \"%s\" has different collation for column \"%s\"",
5577 								RelationGetRelationName(rel), colDef->colname),
5578 						 errdetail("\"%s\" versus \"%s\"",
5579 								   get_collation_name(ccollid),
5580 								   get_collation_name(childatt->attcollation))));
5581 
5582 			/* If it's OID, child column must actually be OID */
5583 			if (isOid && childatt->attnum != ObjectIdAttributeNumber)
5584 				ereport(ERROR,
5585 						(errcode(ERRCODE_DATATYPE_MISMATCH),
5586 						 errmsg("child table \"%s\" has a conflicting \"%s\" column",
5587 								RelationGetRelationName(rel), colDef->colname)));
5588 
5589 			/* Bump the existing child att's inhcount */
5590 			childatt->attinhcount++;
5591 			CatalogTupleUpdate(attrdesc, &tuple->t_self, tuple);
5592 
5593 			heap_freetuple(tuple);
5594 
5595 			/* Inform the user about the merge */
5596 			ereport(NOTICE,
5597 					(errmsg("merging definition of column \"%s\" for child \"%s\"",
5598 							colDef->colname, RelationGetRelationName(rel))));
5599 
5600 			heap_close(attrdesc, RowExclusiveLock);
5601 			return InvalidObjectAddress;
5602 		}
5603 	}
5604 
5605 	pgclass = heap_open(RelationRelationId, RowExclusiveLock);
5606 
5607 	reltup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(myrelid));
5608 	if (!HeapTupleIsValid(reltup))
5609 		elog(ERROR, "cache lookup failed for relation %u", myrelid);
5610 	relkind = ((Form_pg_class) GETSTRUCT(reltup))->relkind;
5611 
5612 	/*
5613 	 * Cannot add identity column if table has children, because identity does
5614 	 * not inherit.  (Adding column and identity separately will work.)
5615 	 */
5616 	if (colDef->identity &&
5617 		recurse &&
5618 		find_inheritance_children(myrelid, NoLock) != NIL)
5619 		ereport(ERROR,
5620 				(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
5621 				 errmsg("cannot recursively add identity column to table that has child tables")));
5622 
5623 	/* skip if the name already exists and if_not_exists is true */
5624 	if (!check_for_column_name_collision(rel, colDef->colname, if_not_exists))
5625 	{
5626 		heap_close(attrdesc, RowExclusiveLock);
5627 		heap_freetuple(reltup);
5628 		heap_close(pgclass, RowExclusiveLock);
5629 		return InvalidObjectAddress;
5630 	}
5631 
5632 	/* Determine the new attribute's number */
5633 	if (isOid)
5634 		newattnum = ObjectIdAttributeNumber;
5635 	else
5636 	{
5637 		newattnum = ((Form_pg_class) GETSTRUCT(reltup))->relnatts + 1;
5638 		if (newattnum > MaxHeapAttributeNumber)
5639 			ereport(ERROR,
5640 					(errcode(ERRCODE_TOO_MANY_COLUMNS),
5641 					 errmsg("tables can have at most %d columns",
5642 							MaxHeapAttributeNumber)));
5643 	}
5644 
5645 	typeTuple = typenameType(NULL, colDef->typeName, &typmod);
5646 	tform = (Form_pg_type) GETSTRUCT(typeTuple);
5647 	typeOid = HeapTupleGetOid(typeTuple);
5648 
5649 	aclresult = pg_type_aclcheck(typeOid, GetUserId(), ACL_USAGE);
5650 	if (aclresult != ACLCHECK_OK)
5651 		aclcheck_error_type(aclresult, typeOid);
5652 
5653 	collOid = GetColumnDefCollation(NULL, colDef, typeOid);
5654 
5655 	/* make sure datatype is legal for a column */
5656 	CheckAttributeType(colDef->colname, typeOid, collOid,
5657 					   list_make1_oid(rel->rd_rel->reltype),
5658 					   false);
5659 
5660 	/* construct new attribute's pg_attribute entry */
5661 	attribute.attrelid = myrelid;
5662 	namestrcpy(&(attribute.attname), colDef->colname);
5663 	attribute.atttypid = typeOid;
5664 	attribute.attstattarget = (newattnum > 0) ? -1 : 0;
5665 	attribute.attlen = tform->typlen;
5666 	attribute.attcacheoff = -1;
5667 	attribute.atttypmod = typmod;
5668 	attribute.attnum = newattnum;
5669 	attribute.attbyval = tform->typbyval;
5670 	attribute.attndims = list_length(colDef->typeName->arrayBounds);
5671 	attribute.attstorage = tform->typstorage;
5672 	attribute.attalign = tform->typalign;
5673 	attribute.attnotnull = colDef->is_not_null;
5674 	attribute.atthasdef = false;
5675 	attribute.atthasmissing = false;
5676 	attribute.attidentity = colDef->identity;
5677 	attribute.attisdropped = false;
5678 	attribute.attislocal = colDef->is_local;
5679 	attribute.attinhcount = colDef->inhcount;
5680 	attribute.attcollation = collOid;
5681 	/* attribute.attacl is handled by InsertPgAttributeTuple */
5682 
5683 	ReleaseSysCache(typeTuple);
5684 
5685 	InsertPgAttributeTuple(attrdesc, &attribute, NULL);
5686 
5687 	heap_close(attrdesc, RowExclusiveLock);
5688 
5689 	/*
5690 	 * Update pg_class tuple as appropriate
5691 	 */
5692 	if (isOid)
5693 		((Form_pg_class) GETSTRUCT(reltup))->relhasoids = true;
5694 	else
5695 		((Form_pg_class) GETSTRUCT(reltup))->relnatts = newattnum;
5696 
5697 	CatalogTupleUpdate(pgclass, &reltup->t_self, reltup);
5698 
5699 	heap_freetuple(reltup);
5700 
5701 	/* Post creation hook for new attribute */
5702 	InvokeObjectPostCreateHook(RelationRelationId, myrelid, newattnum);
5703 
5704 	heap_close(pgclass, RowExclusiveLock);
5705 
5706 	/* Make the attribute's catalog entry visible */
5707 	CommandCounterIncrement();
5708 
5709 	/*
5710 	 * Store the DEFAULT, if any, in the catalogs
5711 	 */
5712 	if (colDef->raw_default)
5713 	{
5714 		RawColumnDefault *rawEnt;
5715 
5716 		rawEnt = (RawColumnDefault *) palloc(sizeof(RawColumnDefault));
5717 		rawEnt->attnum = attribute.attnum;
5718 		rawEnt->raw_default = copyObject(colDef->raw_default);
5719 
5720 		/*
5721 		 * Attempt to skip a complete table rewrite by storing the specified
5722 		 * DEFAULT value outside of the heap.  This may be disabled inside
5723 		 * AddRelationNewConstraints if the optimization cannot be applied.
5724 		 */
5725 		rawEnt->missingMode = true;
5726 
5727 		/*
5728 		 * This function is intended for CREATE TABLE, so it processes a
5729 		 * _list_ of defaults, but we just do one.
5730 		 */
5731 		AddRelationNewConstraints(rel, list_make1(rawEnt), NIL,
5732 								  false, true, false);
5733 
5734 		/* Make the additional catalog changes visible */
5735 		CommandCounterIncrement();
5736 
5737 		/*
5738 		 * Did the request for a missing value work? If not we'll have to do a
5739 		 * rewrite
5740 		 */
5741 		if (!rawEnt->missingMode)
5742 			tab->rewrite |= AT_REWRITE_DEFAULT_VAL;
5743 	}
5744 
5745 	/*
5746 	 * Tell Phase 3 to fill in the default expression, if there is one.
5747 	 *
5748 	 * If there is no default, Phase 3 doesn't have to do anything, because
5749 	 * that effectively means that the default is NULL.  The heap tuple access
5750 	 * routines always check for attnum > # of attributes in tuple, and return
5751 	 * NULL if so, so without any modification of the tuple data we will get
5752 	 * the effect of NULL values in the new column.
5753 	 *
5754 	 * An exception occurs when the new column is of a domain type: the domain
5755 	 * might have a NOT NULL constraint, or a check constraint that indirectly
5756 	 * rejects nulls.  If there are any domain constraints then we construct
5757 	 * an explicit NULL default value that will be passed through
5758 	 * CoerceToDomain processing.  (This is a tad inefficient, since it causes
5759 	 * rewriting the table which we really don't have to do, but the present
5760 	 * design of domain processing doesn't offer any simple way of checking
5761 	 * the constraints more directly.)
5762 	 *
5763 	 * Note: we use build_column_default, and not just the cooked default
5764 	 * returned by AddRelationNewConstraints, so that the right thing happens
5765 	 * when a datatype's default applies.
5766 	 *
5767 	 * We skip this step completely for views and foreign tables.  For a view,
5768 	 * we can only get here from CREATE OR REPLACE VIEW, which historically
5769 	 * doesn't set up defaults, not even for domain-typed columns.  And in any
5770 	 * case we mustn't invoke Phase 3 on a view or foreign table, since they
5771 	 * have no storage.
5772 	 */
5773 	if (relkind != RELKIND_VIEW && relkind != RELKIND_COMPOSITE_TYPE
5774 		&& relkind != RELKIND_FOREIGN_TABLE && attribute.attnum > 0)
5775 	{
5776 		/*
5777 		 * For an identity column, we can't use build_column_default(),
5778 		 * because the sequence ownership isn't set yet.  So do it manually.
5779 		 */
5780 		if (colDef->identity)
5781 		{
5782 			NextValueExpr *nve = makeNode(NextValueExpr);
5783 
5784 			nve->seqid = RangeVarGetRelid(colDef->identitySequence, NoLock, false);
5785 			nve->typeId = typeOid;
5786 
5787 			defval = (Expr *) nve;
5788 
5789 			/* must do a rewrite for identity columns */
5790 			tab->rewrite |= AT_REWRITE_DEFAULT_VAL;
5791 		}
5792 		else
5793 			defval = (Expr *) build_column_default(rel, attribute.attnum);
5794 
5795 		if (!defval && DomainHasConstraints(typeOid))
5796 		{
5797 			Oid			baseTypeId;
5798 			int32		baseTypeMod;
5799 			Oid			baseTypeColl;
5800 
5801 			baseTypeMod = typmod;
5802 			baseTypeId = getBaseTypeAndTypmod(typeOid, &baseTypeMod);
5803 			baseTypeColl = get_typcollation(baseTypeId);
5804 			defval = (Expr *) makeNullConst(baseTypeId, baseTypeMod, baseTypeColl);
5805 			defval = (Expr *) coerce_to_target_type(NULL,
5806 													(Node *) defval,
5807 													baseTypeId,
5808 													typeOid,
5809 													typmod,
5810 													COERCION_ASSIGNMENT,
5811 													COERCE_IMPLICIT_CAST,
5812 													-1);
5813 			if (defval == NULL) /* should not happen */
5814 				elog(ERROR, "failed to coerce base type to domain");
5815 		}
5816 
5817 		if (defval)
5818 		{
5819 			NewColumnValue *newval;
5820 
5821 			newval = (NewColumnValue *) palloc0(sizeof(NewColumnValue));
5822 			newval->attnum = attribute.attnum;
5823 			newval->expr = expression_planner(defval);
5824 
5825 			tab->newvals = lappend(tab->newvals, newval);
5826 		}
5827 
5828 		if (DomainHasConstraints(typeOid))
5829 			tab->rewrite |= AT_REWRITE_DEFAULT_VAL;
5830 
5831 		if (!TupleDescAttr(rel->rd_att, attribute.attnum - 1)->atthasmissing)
5832 		{
5833 			/*
5834 			 * If the new column is NOT NULL, and there is no missing value,
5835 			 * tell Phase 3 it needs to test that. (Note we don't do this for
5836 			 * an OID column.  OID will be marked not null, but since it's
5837 			 * filled specially, there's no need to test anything.)
5838 			 */
5839 			tab->new_notnull |= colDef->is_not_null;
5840 		}
5841 	}
5842 
5843 	/*
5844 	 * If we are adding an OID column, we have to tell Phase 3 to rewrite the
5845 	 * table to fix that.
5846 	 */
5847 	if (isOid)
5848 		tab->rewrite |= AT_REWRITE_ALTER_OID;
5849 
5850 	/*
5851 	 * Add needed dependency entries for the new column.
5852 	 */
5853 	add_column_datatype_dependency(myrelid, newattnum, attribute.atttypid);
5854 	add_column_collation_dependency(myrelid, newattnum, attribute.attcollation);
5855 
5856 	/*
5857 	 * Propagate to children as appropriate.  Unlike most other ALTER
5858 	 * routines, we have to do this one level of recursion at a time; we can't
5859 	 * use find_all_inheritors to do it in one pass.
5860 	 */
5861 	children = find_inheritance_children(RelationGetRelid(rel), lockmode);
5862 
5863 	/*
5864 	 * If we are told not to recurse, there had better not be any child
5865 	 * tables; else the addition would put them out of step.
5866 	 */
5867 	if (children && !recurse)
5868 		ereport(ERROR,
5869 				(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
5870 				 errmsg("column must be added to child tables too")));
5871 
5872 	/* Children should see column as singly inherited */
5873 	if (!recursing)
5874 	{
5875 		colDef = copyObject(colDef);
5876 		colDef->inhcount = 1;
5877 		colDef->is_local = false;
5878 	}
5879 
5880 	foreach(child, children)
5881 	{
5882 		Oid			childrelid = lfirst_oid(child);
5883 		Relation	childrel;
5884 		AlteredTableInfo *childtab;
5885 
5886 		/* find_inheritance_children already got lock */
5887 		childrel = heap_open(childrelid, NoLock);
5888 		CheckTableNotInUse(childrel, "ALTER TABLE");
5889 
5890 		/* Find or create work queue entry for this table */
5891 		childtab = ATGetQueueEntry(wqueue, childrel);
5892 
5893 		/* Recurse to child; return value is ignored */
5894 		ATExecAddColumn(wqueue, childtab, childrel,
5895 						colDef, isOid, recurse, true,
5896 						if_not_exists, lockmode);
5897 
5898 		heap_close(childrel, NoLock);
5899 	}
5900 
5901 	ObjectAddressSubSet(address, RelationRelationId, myrelid, newattnum);
5902 	return address;
5903 }
5904 
5905 /*
5906  * If a new or renamed column will collide with the name of an existing
5907  * column and if_not_exists is false then error out, else do nothing.
5908  */
5909 static bool
check_for_column_name_collision(Relation rel,const char * colname,bool if_not_exists)5910 check_for_column_name_collision(Relation rel, const char *colname,
5911 								bool if_not_exists)
5912 {
5913 	HeapTuple	attTuple;
5914 	int			attnum;
5915 
5916 	/*
5917 	 * this test is deliberately not attisdropped-aware, since if one tries to
5918 	 * add a column matching a dropped column name, it's gonna fail anyway.
5919 	 */
5920 	attTuple = SearchSysCache2(ATTNAME,
5921 							   ObjectIdGetDatum(RelationGetRelid(rel)),
5922 							   PointerGetDatum(colname));
5923 	if (!HeapTupleIsValid(attTuple))
5924 		return true;
5925 
5926 	attnum = ((Form_pg_attribute) GETSTRUCT(attTuple))->attnum;
5927 	ReleaseSysCache(attTuple);
5928 
5929 	/*
5930 	 * We throw a different error message for conflicts with system column
5931 	 * names, since they are normally not shown and the user might otherwise
5932 	 * be confused about the reason for the conflict.
5933 	 */
5934 	if (attnum <= 0)
5935 		ereport(ERROR,
5936 				(errcode(ERRCODE_DUPLICATE_COLUMN),
5937 				 errmsg("column name \"%s\" conflicts with a system column name",
5938 						colname)));
5939 	else
5940 	{
5941 		if (if_not_exists)
5942 		{
5943 			ereport(NOTICE,
5944 					(errcode(ERRCODE_DUPLICATE_COLUMN),
5945 					 errmsg("column \"%s\" of relation \"%s\" already exists, skipping",
5946 							colname, RelationGetRelationName(rel))));
5947 			return false;
5948 		}
5949 
5950 		ereport(ERROR,
5951 				(errcode(ERRCODE_DUPLICATE_COLUMN),
5952 				 errmsg("column \"%s\" of relation \"%s\" already exists",
5953 						colname, RelationGetRelationName(rel))));
5954 	}
5955 
5956 	return true;
5957 }
5958 
5959 /*
5960  * Install a column's dependency on its datatype.
5961  */
5962 static void
add_column_datatype_dependency(Oid relid,int32 attnum,Oid typid)5963 add_column_datatype_dependency(Oid relid, int32 attnum, Oid typid)
5964 {
5965 	ObjectAddress myself,
5966 				referenced;
5967 
5968 	myself.classId = RelationRelationId;
5969 	myself.objectId = relid;
5970 	myself.objectSubId = attnum;
5971 	referenced.classId = TypeRelationId;
5972 	referenced.objectId = typid;
5973 	referenced.objectSubId = 0;
5974 	recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
5975 }
5976 
5977 /*
5978  * Install a column's dependency on its collation.
5979  */
5980 static void
add_column_collation_dependency(Oid relid,int32 attnum,Oid collid)5981 add_column_collation_dependency(Oid relid, int32 attnum, Oid collid)
5982 {
5983 	ObjectAddress myself,
5984 				referenced;
5985 
5986 	/* We know the default collation is pinned, so don't bother recording it */
5987 	if (OidIsValid(collid) && collid != DEFAULT_COLLATION_OID)
5988 	{
5989 		myself.classId = RelationRelationId;
5990 		myself.objectId = relid;
5991 		myself.objectSubId = attnum;
5992 		referenced.classId = CollationRelationId;
5993 		referenced.objectId = collid;
5994 		referenced.objectSubId = 0;
5995 		recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
5996 	}
5997 }
5998 
5999 /*
6000  * ALTER TABLE SET WITH OIDS
6001  *
6002  * Basically this is an ADD COLUMN for the special OID column.  We have
6003  * to cons up a ColumnDef node because the ADD COLUMN code needs one.
6004  */
6005 static void
ATPrepAddOids(List ** wqueue,Relation rel,bool recurse,AlterTableCmd * cmd,LOCKMODE lockmode)6006 ATPrepAddOids(List **wqueue, Relation rel, bool recurse, AlterTableCmd *cmd, LOCKMODE lockmode)
6007 {
6008 	/* If we're recursing to a child table, the ColumnDef is already set up */
6009 	if (cmd->def == NULL)
6010 	{
6011 		ColumnDef  *cdef = makeNode(ColumnDef);
6012 
6013 		cdef->colname = pstrdup("oid");
6014 		cdef->typeName = makeTypeNameFromOid(OIDOID, -1);
6015 		cdef->inhcount = 0;
6016 		cdef->is_local = true;
6017 		cdef->is_not_null = true;
6018 		cdef->storage = 0;
6019 		cdef->location = -1;
6020 		cmd->def = (Node *) cdef;
6021 	}
6022 	ATPrepAddColumn(wqueue, rel, recurse, false, false, cmd, lockmode);
6023 
6024 	if (recurse)
6025 		cmd->subtype = AT_AddOidsRecurse;
6026 }
6027 
6028 /*
6029  * ALTER TABLE ALTER COLUMN DROP NOT NULL
6030  *
6031  * Return the address of the modified column.  If the column was already
6032  * nullable, InvalidObjectAddress is returned.
6033  */
6034 
6035 static void
ATPrepDropNotNull(Relation rel,bool recurse,bool recursing)6036 ATPrepDropNotNull(Relation rel, bool recurse, bool recursing)
6037 {
6038 	/*
6039 	 * If the parent is a partitioned table, like check constraints, we do not
6040 	 * support removing the NOT NULL while partitions exist.
6041 	 */
6042 	if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
6043 	{
6044 		PartitionDesc partdesc = RelationGetPartitionDesc(rel);
6045 
6046 		Assert(partdesc != NULL);
6047 		if (partdesc->nparts > 0 && !recurse && !recursing)
6048 			ereport(ERROR,
6049 					(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
6050 					 errmsg("cannot remove constraint from only the partitioned table when partitions exist"),
6051 					 errhint("Do not specify the ONLY keyword.")));
6052 	}
6053 }
6054 static ObjectAddress
ATExecDropNotNull(Relation rel,const char * colName,LOCKMODE lockmode)6055 ATExecDropNotNull(Relation rel, const char *colName, LOCKMODE lockmode)
6056 {
6057 	HeapTuple	tuple;
6058 	AttrNumber	attnum;
6059 	Relation	attr_rel;
6060 	List	   *indexoidlist;
6061 	ListCell   *indexoidscan;
6062 	ObjectAddress address;
6063 
6064 	/*
6065 	 * lookup the attribute
6066 	 */
6067 	attr_rel = heap_open(AttributeRelationId, RowExclusiveLock);
6068 
6069 	tuple = SearchSysCacheCopyAttName(RelationGetRelid(rel), colName);
6070 
6071 	if (!HeapTupleIsValid(tuple))
6072 		ereport(ERROR,
6073 				(errcode(ERRCODE_UNDEFINED_COLUMN),
6074 				 errmsg("column \"%s\" of relation \"%s\" does not exist",
6075 						colName, RelationGetRelationName(rel))));
6076 
6077 	attnum = ((Form_pg_attribute) GETSTRUCT(tuple))->attnum;
6078 
6079 	/* Prevent them from altering a system attribute */
6080 	if (attnum <= 0)
6081 		ereport(ERROR,
6082 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
6083 				 errmsg("cannot alter system column \"%s\"",
6084 						colName)));
6085 
6086 	if (get_attidentity(RelationGetRelid(rel), attnum))
6087 		ereport(ERROR,
6088 				(errcode(ERRCODE_SYNTAX_ERROR),
6089 				 errmsg("column \"%s\" of relation \"%s\" is an identity column",
6090 						colName, RelationGetRelationName(rel))));
6091 
6092 	/*
6093 	 * Check that the attribute is not in a primary key
6094 	 *
6095 	 * Note: we'll throw error even if the pkey index is not valid.
6096 	 */
6097 
6098 	/* Loop over all indexes on the relation */
6099 	indexoidlist = RelationGetIndexList(rel);
6100 
6101 	foreach(indexoidscan, indexoidlist)
6102 	{
6103 		Oid			indexoid = lfirst_oid(indexoidscan);
6104 		HeapTuple	indexTuple;
6105 		Form_pg_index indexStruct;
6106 		int			i;
6107 
6108 		indexTuple = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(indexoid));
6109 		if (!HeapTupleIsValid(indexTuple))
6110 			elog(ERROR, "cache lookup failed for index %u", indexoid);
6111 		indexStruct = (Form_pg_index) GETSTRUCT(indexTuple);
6112 
6113 		/* If the index is not a primary key, skip the check */
6114 		if (indexStruct->indisprimary)
6115 		{
6116 			/*
6117 			 * Loop over each attribute in the primary key and see if it
6118 			 * matches the to-be-altered attribute
6119 			 */
6120 			for (i = 0; i < indexStruct->indnkeyatts; i++)
6121 			{
6122 				if (indexStruct->indkey.values[i] == attnum)
6123 					ereport(ERROR,
6124 							(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
6125 							 errmsg("column \"%s\" is in a primary key",
6126 									colName)));
6127 			}
6128 		}
6129 
6130 		ReleaseSysCache(indexTuple);
6131 	}
6132 
6133 	list_free(indexoidlist);
6134 
6135 	/* If rel is partition, shouldn't drop NOT NULL if parent has the same */
6136 	if (rel->rd_rel->relispartition)
6137 	{
6138 		Oid			parentId = get_partition_parent(RelationGetRelid(rel));
6139 		Relation	parent = heap_open(parentId, AccessShareLock);
6140 		TupleDesc	tupDesc = RelationGetDescr(parent);
6141 		AttrNumber	parent_attnum;
6142 
6143 		parent_attnum = get_attnum(parentId, colName);
6144 		if (TupleDescAttr(tupDesc, parent_attnum - 1)->attnotnull)
6145 			ereport(ERROR,
6146 					(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
6147 					 errmsg("column \"%s\" is marked NOT NULL in parent table",
6148 							colName)));
6149 		heap_close(parent, AccessShareLock);
6150 	}
6151 
6152 	/*
6153 	 * Okay, actually perform the catalog change ... if needed
6154 	 */
6155 	if (((Form_pg_attribute) GETSTRUCT(tuple))->attnotnull)
6156 	{
6157 		((Form_pg_attribute) GETSTRUCT(tuple))->attnotnull = false;
6158 
6159 		CatalogTupleUpdate(attr_rel, &tuple->t_self, tuple);
6160 
6161 		ObjectAddressSubSet(address, RelationRelationId,
6162 							RelationGetRelid(rel), attnum);
6163 	}
6164 	else
6165 		address = InvalidObjectAddress;
6166 
6167 	InvokeObjectPostAlterHook(RelationRelationId,
6168 							  RelationGetRelid(rel), attnum);
6169 
6170 	heap_close(attr_rel, RowExclusiveLock);
6171 
6172 	return address;
6173 }
6174 
6175 /*
6176  * ALTER TABLE ALTER COLUMN SET NOT NULL
6177  */
6178 
6179 static void
ATPrepSetNotNull(Relation rel,bool recurse,bool recursing)6180 ATPrepSetNotNull(Relation rel, bool recurse, bool recursing)
6181 {
6182 	/*
6183 	 * If the parent is a partitioned table, like check constraints, NOT NULL
6184 	 * constraints must be added to the child tables.  Complain if requested
6185 	 * otherwise and partitions exist.
6186 	 */
6187 	if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
6188 	{
6189 		PartitionDesc partdesc = RelationGetPartitionDesc(rel);
6190 
6191 		if (partdesc && partdesc->nparts > 0 && !recurse && !recursing)
6192 			ereport(ERROR,
6193 					(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
6194 					 errmsg("cannot add constraint to only the partitioned table when partitions exist"),
6195 					 errhint("Do not specify the ONLY keyword.")));
6196 	}
6197 }
6198 
6199 /*
6200  * Return the address of the modified column.  If the column was already NOT
6201  * NULL, InvalidObjectAddress is returned.
6202  */
6203 static ObjectAddress
ATExecSetNotNull(AlteredTableInfo * tab,Relation rel,const char * colName,LOCKMODE lockmode)6204 ATExecSetNotNull(AlteredTableInfo *tab, Relation rel,
6205 				 const char *colName, LOCKMODE lockmode)
6206 {
6207 	HeapTuple	tuple;
6208 	AttrNumber	attnum;
6209 	Relation	attr_rel;
6210 	ObjectAddress address;
6211 
6212 	/*
6213 	 * lookup the attribute
6214 	 */
6215 	attr_rel = heap_open(AttributeRelationId, RowExclusiveLock);
6216 
6217 	tuple = SearchSysCacheCopyAttName(RelationGetRelid(rel), colName);
6218 
6219 	if (!HeapTupleIsValid(tuple))
6220 		ereport(ERROR,
6221 				(errcode(ERRCODE_UNDEFINED_COLUMN),
6222 				 errmsg("column \"%s\" of relation \"%s\" does not exist",
6223 						colName, RelationGetRelationName(rel))));
6224 
6225 	attnum = ((Form_pg_attribute) GETSTRUCT(tuple))->attnum;
6226 
6227 	/* Prevent them from altering a system attribute */
6228 	if (attnum <= 0)
6229 		ereport(ERROR,
6230 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
6231 				 errmsg("cannot alter system column \"%s\"",
6232 						colName)));
6233 
6234 	/*
6235 	 * Okay, actually perform the catalog change ... if needed
6236 	 */
6237 	if (!((Form_pg_attribute) GETSTRUCT(tuple))->attnotnull)
6238 	{
6239 		((Form_pg_attribute) GETSTRUCT(tuple))->attnotnull = true;
6240 
6241 		CatalogTupleUpdate(attr_rel, &tuple->t_self, tuple);
6242 
6243 		/* Tell Phase 3 it needs to test the constraint */
6244 		tab->new_notnull = true;
6245 
6246 		ObjectAddressSubSet(address, RelationRelationId,
6247 							RelationGetRelid(rel), attnum);
6248 	}
6249 	else
6250 		address = InvalidObjectAddress;
6251 
6252 	InvokeObjectPostAlterHook(RelationRelationId,
6253 							  RelationGetRelid(rel), attnum);
6254 
6255 	heap_close(attr_rel, RowExclusiveLock);
6256 
6257 	return address;
6258 }
6259 
6260 /*
6261  * ALTER TABLE ALTER COLUMN SET/DROP DEFAULT
6262  *
6263  * Return the address of the affected column.
6264  */
6265 static ObjectAddress
ATExecColumnDefault(Relation rel,const char * colName,Node * newDefault,LOCKMODE lockmode)6266 ATExecColumnDefault(Relation rel, const char *colName,
6267 					Node *newDefault, LOCKMODE lockmode)
6268 {
6269 	AttrNumber	attnum;
6270 	ObjectAddress address;
6271 
6272 	/*
6273 	 * get the number of the attribute
6274 	 */
6275 	attnum = get_attnum(RelationGetRelid(rel), colName);
6276 	if (attnum == InvalidAttrNumber)
6277 		ereport(ERROR,
6278 				(errcode(ERRCODE_UNDEFINED_COLUMN),
6279 				 errmsg("column \"%s\" of relation \"%s\" does not exist",
6280 						colName, RelationGetRelationName(rel))));
6281 
6282 	/* Prevent them from altering a system attribute */
6283 	if (attnum <= 0)
6284 		ereport(ERROR,
6285 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
6286 				 errmsg("cannot alter system column \"%s\"",
6287 						colName)));
6288 
6289 	if (get_attidentity(RelationGetRelid(rel), attnum))
6290 		ereport(ERROR,
6291 				(errcode(ERRCODE_SYNTAX_ERROR),
6292 				 errmsg("column \"%s\" of relation \"%s\" is an identity column",
6293 						colName, RelationGetRelationName(rel)),
6294 				 newDefault ? 0 : errhint("Use ALTER TABLE ... ALTER COLUMN ... DROP IDENTITY instead.")));
6295 
6296 	/*
6297 	 * Remove any old default for the column.  We use RESTRICT here for
6298 	 * safety, but at present we do not expect anything to depend on the
6299 	 * default.
6300 	 *
6301 	 * We treat removing the existing default as an internal operation when it
6302 	 * is preparatory to adding a new default, but as a user-initiated
6303 	 * operation when the user asked for a drop.
6304 	 */
6305 	RemoveAttrDefault(RelationGetRelid(rel), attnum, DROP_RESTRICT, false,
6306 					  newDefault == NULL ? false : true);
6307 
6308 	if (newDefault)
6309 	{
6310 		/* SET DEFAULT */
6311 		RawColumnDefault *rawEnt;
6312 
6313 		rawEnt = (RawColumnDefault *) palloc(sizeof(RawColumnDefault));
6314 		rawEnt->attnum = attnum;
6315 		rawEnt->raw_default = newDefault;
6316 		rawEnt->missingMode = false;
6317 
6318 		/*
6319 		 * This function is intended for CREATE TABLE, so it processes a
6320 		 * _list_ of defaults, but we just do one.
6321 		 */
6322 		AddRelationNewConstraints(rel, list_make1(rawEnt), NIL,
6323 								  false, true, false);
6324 	}
6325 
6326 	ObjectAddressSubSet(address, RelationRelationId,
6327 						RelationGetRelid(rel), attnum);
6328 	return address;
6329 }
6330 
6331 /*
6332  * ALTER TABLE ALTER COLUMN ADD IDENTITY
6333  *
6334  * Return the address of the affected column.
6335  */
6336 static ObjectAddress
ATExecAddIdentity(Relation rel,const char * colName,Node * def,LOCKMODE lockmode)6337 ATExecAddIdentity(Relation rel, const char *colName,
6338 				  Node *def, LOCKMODE lockmode)
6339 {
6340 	Relation	attrelation;
6341 	HeapTuple	tuple;
6342 	Form_pg_attribute attTup;
6343 	AttrNumber	attnum;
6344 	ObjectAddress address;
6345 	ColumnDef  *cdef = castNode(ColumnDef, def);
6346 
6347 	attrelation = heap_open(AttributeRelationId, RowExclusiveLock);
6348 
6349 	tuple = SearchSysCacheCopyAttName(RelationGetRelid(rel), colName);
6350 	if (!HeapTupleIsValid(tuple))
6351 		ereport(ERROR,
6352 				(errcode(ERRCODE_UNDEFINED_COLUMN),
6353 				 errmsg("column \"%s\" of relation \"%s\" does not exist",
6354 						colName, RelationGetRelationName(rel))));
6355 	attTup = (Form_pg_attribute) GETSTRUCT(tuple);
6356 	attnum = attTup->attnum;
6357 
6358 	/* Can't alter a system attribute */
6359 	if (attnum <= 0)
6360 		ereport(ERROR,
6361 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
6362 				 errmsg("cannot alter system column \"%s\"",
6363 						colName)));
6364 
6365 	/*
6366 	 * Creating a column as identity implies NOT NULL, so adding the identity
6367 	 * to an existing column that is not NOT NULL would create a state that
6368 	 * cannot be reproduced without contortions.
6369 	 */
6370 	if (!attTup->attnotnull)
6371 		ereport(ERROR,
6372 				(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
6373 				 errmsg("column \"%s\" of relation \"%s\" must be declared NOT NULL before identity can be added",
6374 						colName, RelationGetRelationName(rel))));
6375 
6376 	if (attTup->attidentity)
6377 		ereport(ERROR,
6378 				(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
6379 				 errmsg("column \"%s\" of relation \"%s\" is already an identity column",
6380 						colName, RelationGetRelationName(rel))));
6381 
6382 	if (attTup->atthasdef)
6383 		ereport(ERROR,
6384 				(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
6385 				 errmsg("column \"%s\" of relation \"%s\" already has a default value",
6386 						colName, RelationGetRelationName(rel))));
6387 
6388 	attTup->attidentity = cdef->identity;
6389 	CatalogTupleUpdate(attrelation, &tuple->t_self, tuple);
6390 
6391 	InvokeObjectPostAlterHook(RelationRelationId,
6392 							  RelationGetRelid(rel),
6393 							  attTup->attnum);
6394 	ObjectAddressSubSet(address, RelationRelationId,
6395 						RelationGetRelid(rel), attnum);
6396 	heap_freetuple(tuple);
6397 
6398 	heap_close(attrelation, RowExclusiveLock);
6399 
6400 	return address;
6401 }
6402 
6403 /*
6404  * ALTER TABLE ALTER COLUMN SET { GENERATED or sequence options }
6405  *
6406  * Return the address of the affected column.
6407  */
6408 static ObjectAddress
ATExecSetIdentity(Relation rel,const char * colName,Node * def,LOCKMODE lockmode)6409 ATExecSetIdentity(Relation rel, const char *colName, Node *def, LOCKMODE lockmode)
6410 {
6411 	ListCell   *option;
6412 	DefElem    *generatedEl = NULL;
6413 	HeapTuple	tuple;
6414 	Form_pg_attribute attTup;
6415 	AttrNumber	attnum;
6416 	Relation	attrelation;
6417 	ObjectAddress address;
6418 
6419 	foreach(option, castNode(List, def))
6420 	{
6421 		DefElem    *defel = lfirst_node(DefElem, option);
6422 
6423 		if (strcmp(defel->defname, "generated") == 0)
6424 		{
6425 			if (generatedEl)
6426 				ereport(ERROR,
6427 						(errcode(ERRCODE_SYNTAX_ERROR),
6428 						 errmsg("conflicting or redundant options")));
6429 			generatedEl = defel;
6430 		}
6431 		else
6432 			elog(ERROR, "option \"%s\" not recognized",
6433 				 defel->defname);
6434 	}
6435 
6436 	/*
6437 	 * Even if there is nothing to change here, we run all the checks.  There
6438 	 * will be a subsequent ALTER SEQUENCE that relies on everything being
6439 	 * there.
6440 	 */
6441 
6442 	attrelation = heap_open(AttributeRelationId, RowExclusiveLock);
6443 	tuple = SearchSysCacheCopyAttName(RelationGetRelid(rel), colName);
6444 	if (!HeapTupleIsValid(tuple))
6445 		ereport(ERROR,
6446 				(errcode(ERRCODE_UNDEFINED_COLUMN),
6447 				 errmsg("column \"%s\" of relation \"%s\" does not exist",
6448 						colName, RelationGetRelationName(rel))));
6449 
6450 	attTup = (Form_pg_attribute) GETSTRUCT(tuple);
6451 	attnum = attTup->attnum;
6452 
6453 	if (attnum <= 0)
6454 		ereport(ERROR,
6455 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
6456 				 errmsg("cannot alter system column \"%s\"",
6457 						colName)));
6458 
6459 	if (!attTup->attidentity)
6460 		ereport(ERROR,
6461 				(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
6462 				 errmsg("column \"%s\" of relation \"%s\" is not an identity column",
6463 						colName, RelationGetRelationName(rel))));
6464 
6465 	if (generatedEl)
6466 	{
6467 		attTup->attidentity = defGetInt32(generatedEl);
6468 		CatalogTupleUpdate(attrelation, &tuple->t_self, tuple);
6469 
6470 		InvokeObjectPostAlterHook(RelationRelationId,
6471 								  RelationGetRelid(rel),
6472 								  attTup->attnum);
6473 		ObjectAddressSubSet(address, RelationRelationId,
6474 							RelationGetRelid(rel), attnum);
6475 	}
6476 	else
6477 		address = InvalidObjectAddress;
6478 
6479 	heap_freetuple(tuple);
6480 	heap_close(attrelation, RowExclusiveLock);
6481 
6482 	return address;
6483 }
6484 
6485 /*
6486  * ALTER TABLE ALTER COLUMN DROP IDENTITY
6487  *
6488  * Return the address of the affected column.
6489  */
6490 static ObjectAddress
ATExecDropIdentity(Relation rel,const char * colName,bool missing_ok,LOCKMODE lockmode)6491 ATExecDropIdentity(Relation rel, const char *colName, bool missing_ok, LOCKMODE lockmode)
6492 {
6493 	HeapTuple	tuple;
6494 	Form_pg_attribute attTup;
6495 	AttrNumber	attnum;
6496 	Relation	attrelation;
6497 	ObjectAddress address;
6498 	Oid			seqid;
6499 	ObjectAddress seqaddress;
6500 
6501 	attrelation = heap_open(AttributeRelationId, RowExclusiveLock);
6502 	tuple = SearchSysCacheCopyAttName(RelationGetRelid(rel), colName);
6503 	if (!HeapTupleIsValid(tuple))
6504 		ereport(ERROR,
6505 				(errcode(ERRCODE_UNDEFINED_COLUMN),
6506 				 errmsg("column \"%s\" of relation \"%s\" does not exist",
6507 						colName, RelationGetRelationName(rel))));
6508 
6509 	attTup = (Form_pg_attribute) GETSTRUCT(tuple);
6510 	attnum = attTup->attnum;
6511 
6512 	if (attnum <= 0)
6513 		ereport(ERROR,
6514 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
6515 				 errmsg("cannot alter system column \"%s\"",
6516 						colName)));
6517 
6518 	if (!attTup->attidentity)
6519 	{
6520 		if (!missing_ok)
6521 			ereport(ERROR,
6522 					(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
6523 					 errmsg("column \"%s\" of relation \"%s\" is not an identity column",
6524 							colName, RelationGetRelationName(rel))));
6525 		else
6526 		{
6527 			ereport(NOTICE,
6528 					(errmsg("column \"%s\" of relation \"%s\" is not an identity column, skipping",
6529 							colName, RelationGetRelationName(rel))));
6530 			heap_freetuple(tuple);
6531 			heap_close(attrelation, RowExclusiveLock);
6532 			return InvalidObjectAddress;
6533 		}
6534 	}
6535 
6536 	attTup->attidentity = '\0';
6537 	CatalogTupleUpdate(attrelation, &tuple->t_self, tuple);
6538 
6539 	InvokeObjectPostAlterHook(RelationRelationId,
6540 							  RelationGetRelid(rel),
6541 							  attTup->attnum);
6542 	ObjectAddressSubSet(address, RelationRelationId,
6543 						RelationGetRelid(rel), attnum);
6544 	heap_freetuple(tuple);
6545 
6546 	heap_close(attrelation, RowExclusiveLock);
6547 
6548 	/* drop the internal sequence */
6549 	seqid = getOwnedSequence(RelationGetRelid(rel), attnum);
6550 	deleteDependencyRecordsForClass(RelationRelationId, seqid,
6551 									RelationRelationId, DEPENDENCY_INTERNAL);
6552 	CommandCounterIncrement();
6553 	seqaddress.classId = RelationRelationId;
6554 	seqaddress.objectId = seqid;
6555 	seqaddress.objectSubId = 0;
6556 	performDeletion(&seqaddress, DROP_RESTRICT, PERFORM_DELETION_INTERNAL);
6557 
6558 	return address;
6559 }
6560 
6561 /*
6562  * ALTER TABLE ALTER COLUMN SET STATISTICS
6563  */
6564 static void
ATPrepSetStatistics(Relation rel,const char * colName,int16 colNum,Node * newValue,LOCKMODE lockmode)6565 ATPrepSetStatistics(Relation rel, const char *colName, int16 colNum, Node *newValue, LOCKMODE lockmode)
6566 {
6567 	/*
6568 	 * We do our own permission checking because (a) we want to allow SET
6569 	 * STATISTICS on indexes (for expressional index columns), and (b) we want
6570 	 * to allow SET STATISTICS on system catalogs without requiring
6571 	 * allowSystemTableMods to be turned on.
6572 	 */
6573 	if (rel->rd_rel->relkind != RELKIND_RELATION &&
6574 		rel->rd_rel->relkind != RELKIND_MATVIEW &&
6575 		rel->rd_rel->relkind != RELKIND_INDEX &&
6576 		rel->rd_rel->relkind != RELKIND_PARTITIONED_INDEX &&
6577 		rel->rd_rel->relkind != RELKIND_FOREIGN_TABLE &&
6578 		rel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
6579 		ereport(ERROR,
6580 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
6581 				 errmsg("\"%s\" is not a table, materialized view, index, or foreign table",
6582 						RelationGetRelationName(rel))));
6583 
6584 	/*
6585 	 * We allow referencing columns by numbers only for indexes, since table
6586 	 * column numbers could contain gaps if columns are later dropped.
6587 	 */
6588 	if (rel->rd_rel->relkind != RELKIND_INDEX &&
6589 		rel->rd_rel->relkind != RELKIND_PARTITIONED_INDEX &&
6590 		!colName)
6591 		ereport(ERROR,
6592 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
6593 				 errmsg("cannot refer to non-index column by number")));
6594 
6595 	/* Permissions checks */
6596 	if (!pg_class_ownercheck(RelationGetRelid(rel), GetUserId()))
6597 		aclcheck_error(ACLCHECK_NOT_OWNER, get_relkind_objtype(rel->rd_rel->relkind),
6598 					   RelationGetRelationName(rel));
6599 }
6600 
6601 /*
6602  * Return value is the address of the modified column
6603  */
6604 static ObjectAddress
ATExecSetStatistics(Relation rel,const char * colName,int16 colNum,Node * newValue,LOCKMODE lockmode)6605 ATExecSetStatistics(Relation rel, const char *colName, int16 colNum, Node *newValue, LOCKMODE lockmode)
6606 {
6607 	int			newtarget;
6608 	Relation	attrelation;
6609 	HeapTuple	tuple;
6610 	Form_pg_attribute attrtuple;
6611 	AttrNumber	attnum;
6612 	ObjectAddress address;
6613 
6614 	Assert(IsA(newValue, Integer));
6615 	newtarget = intVal(newValue);
6616 
6617 	/*
6618 	 * Limit target to a sane range
6619 	 */
6620 	if (newtarget < -1)
6621 	{
6622 		ereport(ERROR,
6623 				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
6624 				 errmsg("statistics target %d is too low",
6625 						newtarget)));
6626 	}
6627 	else if (newtarget > 10000)
6628 	{
6629 		newtarget = 10000;
6630 		ereport(WARNING,
6631 				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
6632 				 errmsg("lowering statistics target to %d",
6633 						newtarget)));
6634 	}
6635 
6636 	attrelation = heap_open(AttributeRelationId, RowExclusiveLock);
6637 
6638 	if (colName)
6639 	{
6640 		tuple = SearchSysCacheCopyAttName(RelationGetRelid(rel), colName);
6641 
6642 		if (!HeapTupleIsValid(tuple))
6643 			ereport(ERROR,
6644 					(errcode(ERRCODE_UNDEFINED_COLUMN),
6645 					 errmsg("column \"%s\" of relation \"%s\" does not exist",
6646 							colName, RelationGetRelationName(rel))));
6647 	}
6648 	else
6649 	{
6650 		tuple = SearchSysCacheCopyAttNum(RelationGetRelid(rel), colNum);
6651 
6652 		if (!HeapTupleIsValid(tuple))
6653 			ereport(ERROR,
6654 					(errcode(ERRCODE_UNDEFINED_COLUMN),
6655 					 errmsg("column number %d of relation \"%s\" does not exist",
6656 							colNum, RelationGetRelationName(rel))));
6657 	}
6658 
6659 	attrtuple = (Form_pg_attribute) GETSTRUCT(tuple);
6660 
6661 	attnum = attrtuple->attnum;
6662 	if (attnum <= 0)
6663 		ereport(ERROR,
6664 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
6665 				 errmsg("cannot alter system column \"%s\"",
6666 						colName)));
6667 
6668 	if (rel->rd_rel->relkind == RELKIND_INDEX ||
6669 		rel->rd_rel->relkind == RELKIND_PARTITIONED_INDEX)
6670 	{
6671 		if (attnum > rel->rd_index->indnkeyatts)
6672 			ereport(ERROR,
6673 					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
6674 					 errmsg("cannot alter statistics on included column \"%s\" of index \"%s\"",
6675 							NameStr(attrtuple->attname), RelationGetRelationName(rel))));
6676 		else if (rel->rd_index->indkey.values[attnum - 1] != 0)
6677 			ereport(ERROR,
6678 					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
6679 					 errmsg("cannot alter statistics on non-expression column \"%s\" of index \"%s\"",
6680 							NameStr(attrtuple->attname), RelationGetRelationName(rel)),
6681 					 errhint("Alter statistics on table column instead.")));
6682 	}
6683 
6684 	attrtuple->attstattarget = newtarget;
6685 
6686 	CatalogTupleUpdate(attrelation, &tuple->t_self, tuple);
6687 
6688 	InvokeObjectPostAlterHook(RelationRelationId,
6689 							  RelationGetRelid(rel),
6690 							  attrtuple->attnum);
6691 	ObjectAddressSubSet(address, RelationRelationId,
6692 						RelationGetRelid(rel), attnum);
6693 	heap_freetuple(tuple);
6694 
6695 	heap_close(attrelation, RowExclusiveLock);
6696 
6697 	return address;
6698 }
6699 
6700 /*
6701  * Return value is the address of the modified column
6702  */
6703 static ObjectAddress
ATExecSetOptions(Relation rel,const char * colName,Node * options,bool isReset,LOCKMODE lockmode)6704 ATExecSetOptions(Relation rel, const char *colName, Node *options,
6705 				 bool isReset, LOCKMODE lockmode)
6706 {
6707 	Relation	attrelation;
6708 	HeapTuple	tuple,
6709 				newtuple;
6710 	Form_pg_attribute attrtuple;
6711 	AttrNumber	attnum;
6712 	Datum		datum,
6713 				newOptions;
6714 	bool		isnull;
6715 	ObjectAddress address;
6716 	Datum		repl_val[Natts_pg_attribute];
6717 	bool		repl_null[Natts_pg_attribute];
6718 	bool		repl_repl[Natts_pg_attribute];
6719 
6720 	attrelation = heap_open(AttributeRelationId, RowExclusiveLock);
6721 
6722 	tuple = SearchSysCacheAttName(RelationGetRelid(rel), colName);
6723 
6724 	if (!HeapTupleIsValid(tuple))
6725 		ereport(ERROR,
6726 				(errcode(ERRCODE_UNDEFINED_COLUMN),
6727 				 errmsg("column \"%s\" of relation \"%s\" does not exist",
6728 						colName, RelationGetRelationName(rel))));
6729 	attrtuple = (Form_pg_attribute) GETSTRUCT(tuple);
6730 
6731 	attnum = attrtuple->attnum;
6732 	if (attnum <= 0)
6733 		ereport(ERROR,
6734 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
6735 				 errmsg("cannot alter system column \"%s\"",
6736 						colName)));
6737 
6738 	/* Generate new proposed attoptions (text array) */
6739 	datum = SysCacheGetAttr(ATTNAME, tuple, Anum_pg_attribute_attoptions,
6740 							&isnull);
6741 	newOptions = transformRelOptions(isnull ? (Datum) 0 : datum,
6742 									 castNode(List, options), NULL, NULL,
6743 									 false, isReset);
6744 	/* Validate new options */
6745 	(void) attribute_reloptions(newOptions, true);
6746 
6747 	/* Build new tuple. */
6748 	memset(repl_null, false, sizeof(repl_null));
6749 	memset(repl_repl, false, sizeof(repl_repl));
6750 	if (newOptions != (Datum) 0)
6751 		repl_val[Anum_pg_attribute_attoptions - 1] = newOptions;
6752 	else
6753 		repl_null[Anum_pg_attribute_attoptions - 1] = true;
6754 	repl_repl[Anum_pg_attribute_attoptions - 1] = true;
6755 	newtuple = heap_modify_tuple(tuple, RelationGetDescr(attrelation),
6756 								 repl_val, repl_null, repl_repl);
6757 
6758 	/* Update system catalog. */
6759 	CatalogTupleUpdate(attrelation, &newtuple->t_self, newtuple);
6760 
6761 	InvokeObjectPostAlterHook(RelationRelationId,
6762 							  RelationGetRelid(rel),
6763 							  attrtuple->attnum);
6764 	ObjectAddressSubSet(address, RelationRelationId,
6765 						RelationGetRelid(rel), attnum);
6766 
6767 	heap_freetuple(newtuple);
6768 
6769 	ReleaseSysCache(tuple);
6770 
6771 	heap_close(attrelation, RowExclusiveLock);
6772 
6773 	return address;
6774 }
6775 
6776 /*
6777  * ALTER TABLE ALTER COLUMN SET STORAGE
6778  *
6779  * Return value is the address of the modified column
6780  */
6781 static ObjectAddress
ATExecSetStorage(Relation rel,const char * colName,Node * newValue,LOCKMODE lockmode)6782 ATExecSetStorage(Relation rel, const char *colName, Node *newValue, LOCKMODE lockmode)
6783 {
6784 	char	   *storagemode;
6785 	char		newstorage;
6786 	Relation	attrelation;
6787 	HeapTuple	tuple;
6788 	Form_pg_attribute attrtuple;
6789 	AttrNumber	attnum;
6790 	ObjectAddress address;
6791 	ListCell   *lc;
6792 
6793 	Assert(IsA(newValue, String));
6794 	storagemode = strVal(newValue);
6795 
6796 	if (pg_strcasecmp(storagemode, "plain") == 0)
6797 		newstorage = 'p';
6798 	else if (pg_strcasecmp(storagemode, "external") == 0)
6799 		newstorage = 'e';
6800 	else if (pg_strcasecmp(storagemode, "extended") == 0)
6801 		newstorage = 'x';
6802 	else if (pg_strcasecmp(storagemode, "main") == 0)
6803 		newstorage = 'm';
6804 	else
6805 	{
6806 		ereport(ERROR,
6807 				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
6808 				 errmsg("invalid storage type \"%s\"",
6809 						storagemode)));
6810 		newstorage = 0;			/* keep compiler quiet */
6811 	}
6812 
6813 	attrelation = heap_open(AttributeRelationId, RowExclusiveLock);
6814 
6815 	tuple = SearchSysCacheCopyAttName(RelationGetRelid(rel), colName);
6816 
6817 	if (!HeapTupleIsValid(tuple))
6818 		ereport(ERROR,
6819 				(errcode(ERRCODE_UNDEFINED_COLUMN),
6820 				 errmsg("column \"%s\" of relation \"%s\" does not exist",
6821 						colName, RelationGetRelationName(rel))));
6822 	attrtuple = (Form_pg_attribute) GETSTRUCT(tuple);
6823 
6824 	attnum = attrtuple->attnum;
6825 	if (attnum <= 0)
6826 		ereport(ERROR,
6827 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
6828 				 errmsg("cannot alter system column \"%s\"",
6829 						colName)));
6830 
6831 	/*
6832 	 * safety check: do not allow toasted storage modes unless column datatype
6833 	 * is TOAST-aware.
6834 	 */
6835 	if (newstorage == 'p' || TypeIsToastable(attrtuple->atttypid))
6836 		attrtuple->attstorage = newstorage;
6837 	else
6838 		ereport(ERROR,
6839 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
6840 				 errmsg("column data type %s can only have storage PLAIN",
6841 						format_type_be(attrtuple->atttypid))));
6842 
6843 	CatalogTupleUpdate(attrelation, &tuple->t_self, tuple);
6844 
6845 	InvokeObjectPostAlterHook(RelationRelationId,
6846 							  RelationGetRelid(rel),
6847 							  attrtuple->attnum);
6848 
6849 	heap_freetuple(tuple);
6850 
6851 	/*
6852 	 * Apply the change to indexes as well (only for simple index columns,
6853 	 * matching behavior of index.c ConstructTupleDescriptor()).
6854 	 */
6855 	foreach(lc, RelationGetIndexList(rel))
6856 	{
6857 		Oid         indexoid = lfirst_oid(lc);
6858 		Relation    indrel;
6859 		int			i;
6860 		AttrNumber	indattnum = 0;
6861 
6862 		indrel = index_open(indexoid, lockmode);
6863 
6864 		for (i = 0; i < indrel->rd_index->indnatts; i++)
6865 		{
6866 			if (indrel->rd_index->indkey.values[i] == attnum)
6867 			{
6868 				indattnum = i + 1;
6869 				break;
6870 			}
6871 		}
6872 
6873 		if (indattnum == 0)
6874 		{
6875 			index_close(indrel, lockmode);
6876 			continue;
6877 		}
6878 
6879 		tuple = SearchSysCacheCopyAttNum(RelationGetRelid(indrel), indattnum);
6880 
6881 		if (HeapTupleIsValid(tuple))
6882 		{
6883 			attrtuple = (Form_pg_attribute) GETSTRUCT(tuple);
6884 			attrtuple->attstorage = newstorage;
6885 
6886 			CatalogTupleUpdate(attrelation, &tuple->t_self, tuple);
6887 
6888 			InvokeObjectPostAlterHook(RelationRelationId,
6889 									  RelationGetRelid(rel),
6890 									  attrtuple->attnum);
6891 
6892 			heap_freetuple(tuple);
6893 		}
6894 
6895 		index_close(indrel, lockmode);
6896 	}
6897 
6898 	heap_close(attrelation, RowExclusiveLock);
6899 
6900 	ObjectAddressSubSet(address, RelationRelationId,
6901 						RelationGetRelid(rel), attnum);
6902 	return address;
6903 }
6904 
6905 
6906 /*
6907  * ALTER TABLE DROP COLUMN
6908  *
6909  * DROP COLUMN cannot use the normal ALTER TABLE recursion mechanism,
6910  * because we have to decide at runtime whether to recurse or not depending
6911  * on whether attinhcount goes to zero or not.  (We can't check this in a
6912  * static pre-pass because it won't handle multiple inheritance situations
6913  * correctly.)
6914  */
6915 static void
ATPrepDropColumn(List ** wqueue,Relation rel,bool recurse,bool recursing,AlterTableCmd * cmd,LOCKMODE lockmode)6916 ATPrepDropColumn(List **wqueue, Relation rel, bool recurse, bool recursing,
6917 				 AlterTableCmd *cmd, LOCKMODE lockmode)
6918 {
6919 	if (rel->rd_rel->reloftype && !recursing)
6920 		ereport(ERROR,
6921 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
6922 				 errmsg("cannot drop column from typed table")));
6923 
6924 	if (rel->rd_rel->relkind == RELKIND_COMPOSITE_TYPE)
6925 		ATTypedTableRecursion(wqueue, rel, cmd, lockmode);
6926 
6927 	if (recurse)
6928 		cmd->subtype = AT_DropColumnRecurse;
6929 }
6930 
6931 /*
6932  * Return value is the address of the dropped column.
6933  */
6934 static ObjectAddress
ATExecDropColumn(List ** wqueue,Relation rel,const char * colName,DropBehavior behavior,bool recurse,bool recursing,bool missing_ok,LOCKMODE lockmode)6935 ATExecDropColumn(List **wqueue, Relation rel, const char *colName,
6936 				 DropBehavior behavior,
6937 				 bool recurse, bool recursing,
6938 				 bool missing_ok, LOCKMODE lockmode)
6939 {
6940 	HeapTuple	tuple;
6941 	Form_pg_attribute targetatt;
6942 	AttrNumber	attnum;
6943 	List	   *children;
6944 	ObjectAddress object;
6945 	bool		is_expr;
6946 
6947 	/* At top level, permission check was done in ATPrepCmd, else do it */
6948 	if (recursing)
6949 		ATSimplePermissions(rel, ATT_TABLE | ATT_FOREIGN_TABLE);
6950 
6951 	/*
6952 	 * get the number of the attribute
6953 	 */
6954 	tuple = SearchSysCacheAttName(RelationGetRelid(rel), colName);
6955 	if (!HeapTupleIsValid(tuple))
6956 	{
6957 		if (!missing_ok)
6958 		{
6959 			ereport(ERROR,
6960 					(errcode(ERRCODE_UNDEFINED_COLUMN),
6961 					 errmsg("column \"%s\" of relation \"%s\" does not exist",
6962 							colName, RelationGetRelationName(rel))));
6963 		}
6964 		else
6965 		{
6966 			ereport(NOTICE,
6967 					(errmsg("column \"%s\" of relation \"%s\" does not exist, skipping",
6968 							colName, RelationGetRelationName(rel))));
6969 			return InvalidObjectAddress;
6970 		}
6971 	}
6972 	targetatt = (Form_pg_attribute) GETSTRUCT(tuple);
6973 
6974 	attnum = targetatt->attnum;
6975 
6976 	/* Can't drop a system attribute, except OID */
6977 	if (attnum <= 0 && attnum != ObjectIdAttributeNumber)
6978 		ereport(ERROR,
6979 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
6980 				 errmsg("cannot drop system column \"%s\"",
6981 						colName)));
6982 
6983 	/*
6984 	 * Don't drop inherited columns, unless recursing (presumably from a drop
6985 	 * of the parent column)
6986 	 */
6987 	if (targetatt->attinhcount > 0 && !recursing)
6988 		ereport(ERROR,
6989 				(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
6990 				 errmsg("cannot drop inherited column \"%s\"",
6991 						colName)));
6992 
6993 	/*
6994 	 * Don't drop columns used in the partition key, either.  (If we let this
6995 	 * go through, the key column's dependencies would cause a cascaded drop
6996 	 * of the whole table, which is surely not what the user expected.)
6997 	 */
6998 	if (has_partition_attrs(rel,
6999 							bms_make_singleton(attnum - FirstLowInvalidHeapAttributeNumber),
7000 							&is_expr))
7001 		ereport(ERROR,
7002 				(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
7003 				 errmsg("cannot drop column \"%s\" because it is part of the partition key of relation \"%s\"",
7004 						colName, RelationGetRelationName(rel))));
7005 
7006 	ReleaseSysCache(tuple);
7007 
7008 	/*
7009 	 * Propagate to children as appropriate.  Unlike most other ALTER
7010 	 * routines, we have to do this one level of recursion at a time; we can't
7011 	 * use find_all_inheritors to do it in one pass.
7012 	 */
7013 	children = find_inheritance_children(RelationGetRelid(rel), lockmode);
7014 
7015 	if (children)
7016 	{
7017 		Relation	attr_rel;
7018 		ListCell   *child;
7019 
7020 		/*
7021 		 * In case of a partitioned table, the column must be dropped from the
7022 		 * partitions as well.
7023 		 */
7024 		if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE && !recurse)
7025 			ereport(ERROR,
7026 					(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
7027 					 errmsg("cannot drop column from only the partitioned table when partitions exist"),
7028 					 errhint("Do not specify the ONLY keyword.")));
7029 
7030 		attr_rel = heap_open(AttributeRelationId, RowExclusiveLock);
7031 		foreach(child, children)
7032 		{
7033 			Oid			childrelid = lfirst_oid(child);
7034 			Relation	childrel;
7035 			Form_pg_attribute childatt;
7036 
7037 			/* find_inheritance_children already got lock */
7038 			childrel = heap_open(childrelid, NoLock);
7039 			CheckTableNotInUse(childrel, "ALTER TABLE");
7040 
7041 			tuple = SearchSysCacheCopyAttName(childrelid, colName);
7042 			if (!HeapTupleIsValid(tuple))	/* shouldn't happen */
7043 				elog(ERROR, "cache lookup failed for attribute \"%s\" of relation %u",
7044 					 colName, childrelid);
7045 			childatt = (Form_pg_attribute) GETSTRUCT(tuple);
7046 
7047 			if (childatt->attinhcount <= 0) /* shouldn't happen */
7048 				elog(ERROR, "relation %u has non-inherited attribute \"%s\"",
7049 					 childrelid, colName);
7050 
7051 			if (recurse)
7052 			{
7053 				/*
7054 				 * If the child column has other definition sources, just
7055 				 * decrement its inheritance count; if not, recurse to delete
7056 				 * it.
7057 				 */
7058 				if (childatt->attinhcount == 1 && !childatt->attislocal)
7059 				{
7060 					/* Time to delete this child column, too */
7061 					ATExecDropColumn(wqueue, childrel, colName,
7062 									 behavior, true, true,
7063 									 false, lockmode);
7064 				}
7065 				else
7066 				{
7067 					/* Child column must survive my deletion */
7068 					childatt->attinhcount--;
7069 
7070 					CatalogTupleUpdate(attr_rel, &tuple->t_self, tuple);
7071 
7072 					/* Make update visible */
7073 					CommandCounterIncrement();
7074 				}
7075 			}
7076 			else
7077 			{
7078 				/*
7079 				 * If we were told to drop ONLY in this table (no recursion),
7080 				 * we need to mark the inheritors' attributes as locally
7081 				 * defined rather than inherited.
7082 				 */
7083 				childatt->attinhcount--;
7084 				childatt->attislocal = true;
7085 
7086 				CatalogTupleUpdate(attr_rel, &tuple->t_self, tuple);
7087 
7088 				/* Make update visible */
7089 				CommandCounterIncrement();
7090 			}
7091 
7092 			heap_freetuple(tuple);
7093 
7094 			heap_close(childrel, NoLock);
7095 		}
7096 		heap_close(attr_rel, RowExclusiveLock);
7097 	}
7098 
7099 	/*
7100 	 * Perform the actual column deletion
7101 	 */
7102 	object.classId = RelationRelationId;
7103 	object.objectId = RelationGetRelid(rel);
7104 	object.objectSubId = attnum;
7105 
7106 	performDeletion(&object, behavior, 0);
7107 
7108 	/*
7109 	 * If we dropped the OID column, must adjust pg_class.relhasoids and tell
7110 	 * Phase 3 to physically get rid of the column.  We formerly left the
7111 	 * column in place physically, but this caused subtle problems.  See
7112 	 * http://archives.postgresql.org/pgsql-hackers/2009-02/msg00363.php
7113 	 */
7114 	if (attnum == ObjectIdAttributeNumber)
7115 	{
7116 		Relation	class_rel;
7117 		Form_pg_class tuple_class;
7118 		AlteredTableInfo *tab;
7119 
7120 		class_rel = heap_open(RelationRelationId, RowExclusiveLock);
7121 
7122 		tuple = SearchSysCacheCopy1(RELOID,
7123 									ObjectIdGetDatum(RelationGetRelid(rel)));
7124 		if (!HeapTupleIsValid(tuple))
7125 			elog(ERROR, "cache lookup failed for relation %u",
7126 				 RelationGetRelid(rel));
7127 		tuple_class = (Form_pg_class) GETSTRUCT(tuple);
7128 
7129 		tuple_class->relhasoids = false;
7130 		CatalogTupleUpdate(class_rel, &tuple->t_self, tuple);
7131 
7132 		heap_close(class_rel, RowExclusiveLock);
7133 
7134 		/* Find or create work queue entry for this table */
7135 		tab = ATGetQueueEntry(wqueue, rel);
7136 
7137 		/* Tell Phase 3 to physically remove the OID column */
7138 		tab->rewrite |= AT_REWRITE_ALTER_OID;
7139 	}
7140 
7141 	return object;
7142 }
7143 
7144 /*
7145  * ALTER TABLE ADD INDEX
7146  *
7147  * There is no such command in the grammar, but parse_utilcmd.c converts
7148  * UNIQUE and PRIMARY KEY constraints into AT_AddIndex subcommands.  This lets
7149  * us schedule creation of the index at the appropriate time during ALTER.
7150  *
7151  * Return value is the address of the new index.
7152  */
7153 static ObjectAddress
ATExecAddIndex(AlteredTableInfo * tab,Relation rel,IndexStmt * stmt,bool is_rebuild,LOCKMODE lockmode)7154 ATExecAddIndex(AlteredTableInfo *tab, Relation rel,
7155 			   IndexStmt *stmt, bool is_rebuild, LOCKMODE lockmode)
7156 {
7157 	bool		check_rights;
7158 	bool		skip_build;
7159 	bool		quiet;
7160 	ObjectAddress address;
7161 
7162 	Assert(IsA(stmt, IndexStmt));
7163 	Assert(!stmt->concurrent);
7164 
7165 	/* The IndexStmt has already been through transformIndexStmt */
7166 	Assert(stmt->transformed);
7167 
7168 	/* suppress schema rights check when rebuilding existing index */
7169 	check_rights = !is_rebuild;
7170 	/* skip index build if phase 3 will do it or we're reusing an old one */
7171 	skip_build = tab->rewrite > 0 || OidIsValid(stmt->oldNode);
7172 	/* suppress notices when rebuilding existing index */
7173 	quiet = is_rebuild;
7174 
7175 	address = DefineIndex(RelationGetRelid(rel),
7176 						  stmt,
7177 						  InvalidOid,	/* no predefined OID */
7178 						  InvalidOid,	/* no parent index */
7179 						  InvalidOid,	/* no parent constraint */
7180 						  true, /* is_alter_table */
7181 						  check_rights,
7182 						  false,	/* check_not_in_use - we did it already */
7183 						  skip_build,
7184 						  quiet);
7185 
7186 	/*
7187 	 * If TryReuseIndex() stashed a relfilenode for us, we used it for the new
7188 	 * index instead of building from scratch.  The DROP of the old edition of
7189 	 * this index will have scheduled the storage for deletion at commit, so
7190 	 * cancel that pending deletion.
7191 	 */
7192 	if (OidIsValid(stmt->oldNode))
7193 	{
7194 		Relation	irel = index_open(address.objectId, NoLock);
7195 
7196 		RelationPreserveStorage(irel->rd_node, true);
7197 		index_close(irel, NoLock);
7198 	}
7199 
7200 	return address;
7201 }
7202 
7203 /*
7204  * ALTER TABLE ADD CONSTRAINT USING INDEX
7205  *
7206  * Returns the address of the new constraint.
7207  */
7208 static ObjectAddress
ATExecAddIndexConstraint(AlteredTableInfo * tab,Relation rel,IndexStmt * stmt,LOCKMODE lockmode)7209 ATExecAddIndexConstraint(AlteredTableInfo *tab, Relation rel,
7210 						 IndexStmt *stmt, LOCKMODE lockmode)
7211 {
7212 	Oid			index_oid = stmt->indexOid;
7213 	Relation	indexRel;
7214 	char	   *indexName;
7215 	IndexInfo  *indexInfo;
7216 	char	   *constraintName;
7217 	char		constraintType;
7218 	ObjectAddress address;
7219 	bits16		flags;
7220 
7221 	Assert(IsA(stmt, IndexStmt));
7222 	Assert(OidIsValid(index_oid));
7223 	Assert(stmt->isconstraint);
7224 
7225 	/*
7226 	 * Doing this on partitioned tables is not a simple feature to implement,
7227 	 * so let's punt for now.
7228 	 */
7229 	if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
7230 		ereport(ERROR,
7231 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
7232 				 errmsg("ALTER TABLE / ADD CONSTRAINT USING INDEX is not supported on partitioned tables")));
7233 
7234 	indexRel = index_open(index_oid, AccessShareLock);
7235 
7236 	indexName = pstrdup(RelationGetRelationName(indexRel));
7237 
7238 	indexInfo = BuildIndexInfo(indexRel);
7239 
7240 	/* this should have been checked at parse time */
7241 	if (!indexInfo->ii_Unique)
7242 		elog(ERROR, "index \"%s\" is not unique", indexName);
7243 
7244 	/*
7245 	 * Determine name to assign to constraint.  We require a constraint to
7246 	 * have the same name as the underlying index; therefore, use the index's
7247 	 * existing name as the default constraint name, and if the user
7248 	 * explicitly gives some other name for the constraint, rename the index
7249 	 * to match.
7250 	 */
7251 	constraintName = stmt->idxname;
7252 	if (constraintName == NULL)
7253 		constraintName = indexName;
7254 	else if (strcmp(constraintName, indexName) != 0)
7255 	{
7256 		ereport(NOTICE,
7257 				(errmsg("ALTER TABLE / ADD CONSTRAINT USING INDEX will rename index \"%s\" to \"%s\"",
7258 						indexName, constraintName)));
7259 		RenameRelationInternal(index_oid, constraintName, false);
7260 	}
7261 
7262 	/* Extra checks needed if making primary key */
7263 	if (stmt->primary)
7264 		index_check_primary_key(rel, indexInfo, true, stmt);
7265 
7266 	/* Note we currently don't support EXCLUSION constraints here */
7267 	if (stmt->primary)
7268 		constraintType = CONSTRAINT_PRIMARY;
7269 	else
7270 		constraintType = CONSTRAINT_UNIQUE;
7271 
7272 	/* Create the catalog entries for the constraint */
7273 	flags = INDEX_CONSTR_CREATE_UPDATE_INDEX |
7274 		INDEX_CONSTR_CREATE_REMOVE_OLD_DEPS |
7275 		(stmt->initdeferred ? INDEX_CONSTR_CREATE_INIT_DEFERRED : 0) |
7276 		(stmt->deferrable ? INDEX_CONSTR_CREATE_DEFERRABLE : 0) |
7277 		(stmt->primary ? INDEX_CONSTR_CREATE_MARK_AS_PRIMARY : 0);
7278 
7279 	address = index_constraint_create(rel,
7280 									  index_oid,
7281 									  InvalidOid,
7282 									  indexInfo,
7283 									  constraintName,
7284 									  constraintType,
7285 									  flags,
7286 									  allowSystemTableMods,
7287 									  false);	/* is_internal */
7288 
7289 	index_close(indexRel, NoLock);
7290 
7291 	return address;
7292 }
7293 
7294 /*
7295  * ALTER TABLE ADD CONSTRAINT
7296  *
7297  * Return value is the address of the new constraint; if no constraint was
7298  * added, InvalidObjectAddress is returned.
7299  */
7300 static ObjectAddress
ATExecAddConstraint(List ** wqueue,AlteredTableInfo * tab,Relation rel,Constraint * newConstraint,bool recurse,bool is_readd,LOCKMODE lockmode)7301 ATExecAddConstraint(List **wqueue, AlteredTableInfo *tab, Relation rel,
7302 					Constraint *newConstraint, bool recurse, bool is_readd,
7303 					LOCKMODE lockmode)
7304 {
7305 	ObjectAddress address = InvalidObjectAddress;
7306 
7307 	Assert(IsA(newConstraint, Constraint));
7308 
7309 	/*
7310 	 * Currently, we only expect to see CONSTR_CHECK and CONSTR_FOREIGN nodes
7311 	 * arriving here (see the preprocessing done in parse_utilcmd.c).  Use a
7312 	 * switch anyway to make it easier to add more code later.
7313 	 */
7314 	switch (newConstraint->contype)
7315 	{
7316 		case CONSTR_CHECK:
7317 			address =
7318 				ATAddCheckConstraint(wqueue, tab, rel,
7319 									 newConstraint, recurse, false, is_readd,
7320 									 lockmode);
7321 			break;
7322 
7323 		case CONSTR_FOREIGN:
7324 
7325 			/*
7326 			 * Note that we currently never recurse for FK constraints, so the
7327 			 * "recurse" flag is silently ignored.
7328 			 *
7329 			 * Assign or validate constraint name
7330 			 */
7331 			if (newConstraint->conname)
7332 			{
7333 				if (ConstraintNameIsUsed(CONSTRAINT_RELATION,
7334 										 RelationGetRelid(rel),
7335 										 newConstraint->conname))
7336 					ereport(ERROR,
7337 							(errcode(ERRCODE_DUPLICATE_OBJECT),
7338 							 errmsg("constraint \"%s\" for relation \"%s\" already exists",
7339 									newConstraint->conname,
7340 									RelationGetRelationName(rel))));
7341 			}
7342 			else
7343 				newConstraint->conname =
7344 					ChooseConstraintName(RelationGetRelationName(rel),
7345 										 strVal(linitial(newConstraint->fk_attrs)),
7346 										 "fkey",
7347 										 RelationGetNamespace(rel),
7348 										 NIL);
7349 
7350 			address = ATAddForeignKeyConstraint(wqueue, tab, rel,
7351 												newConstraint, InvalidOid,
7352 												recurse, false,
7353 												lockmode);
7354 			break;
7355 
7356 		default:
7357 			elog(ERROR, "unrecognized constraint type: %d",
7358 				 (int) newConstraint->contype);
7359 	}
7360 
7361 	return address;
7362 }
7363 
7364 /*
7365  * Add a check constraint to a single table and its children.  Returns the
7366  * address of the constraint added to the parent relation, if one gets added,
7367  * or InvalidObjectAddress otherwise.
7368  *
7369  * Subroutine for ATExecAddConstraint.
7370  *
7371  * We must recurse to child tables during execution, rather than using
7372  * ALTER TABLE's normal prep-time recursion.  The reason is that all the
7373  * constraints *must* be given the same name, else they won't be seen as
7374  * related later.  If the user didn't explicitly specify a name, then
7375  * AddRelationNewConstraints would normally assign different names to the
7376  * child constraints.  To fix that, we must capture the name assigned at
7377  * the parent table and pass that down.
7378  */
7379 static ObjectAddress
ATAddCheckConstraint(List ** wqueue,AlteredTableInfo * tab,Relation rel,Constraint * constr,bool recurse,bool recursing,bool is_readd,LOCKMODE lockmode)7380 ATAddCheckConstraint(List **wqueue, AlteredTableInfo *tab, Relation rel,
7381 					 Constraint *constr, bool recurse, bool recursing,
7382 					 bool is_readd, LOCKMODE lockmode)
7383 {
7384 	List	   *newcons;
7385 	ListCell   *lcon;
7386 	List	   *children;
7387 	ListCell   *child;
7388 	ObjectAddress address = InvalidObjectAddress;
7389 
7390 	/* At top level, permission check was done in ATPrepCmd, else do it */
7391 	if (recursing)
7392 		ATSimplePermissions(rel, ATT_TABLE | ATT_FOREIGN_TABLE);
7393 
7394 	/*
7395 	 * Call AddRelationNewConstraints to do the work, making sure it works on
7396 	 * a copy of the Constraint so transformExpr can't modify the original. It
7397 	 * returns a list of cooked constraints.
7398 	 *
7399 	 * If the constraint ends up getting merged with a pre-existing one, it's
7400 	 * omitted from the returned list, which is what we want: we do not need
7401 	 * to do any validation work.  That can only happen at child tables,
7402 	 * though, since we disallow merging at the top level.
7403 	 */
7404 	newcons = AddRelationNewConstraints(rel, NIL,
7405 										list_make1(copyObject(constr)),
7406 										recursing | is_readd,	/* allow_merge */
7407 										!recursing, /* is_local */
7408 										is_readd);	/* is_internal */
7409 
7410 	/* we don't expect more than one constraint here */
7411 	Assert(list_length(newcons) <= 1);
7412 
7413 	/* Add each to-be-validated constraint to Phase 3's queue */
7414 	foreach(lcon, newcons)
7415 	{
7416 		CookedConstraint *ccon = (CookedConstraint *) lfirst(lcon);
7417 
7418 		if (!ccon->skip_validation)
7419 		{
7420 			NewConstraint *newcon;
7421 
7422 			newcon = (NewConstraint *) palloc0(sizeof(NewConstraint));
7423 			newcon->name = ccon->name;
7424 			newcon->contype = ccon->contype;
7425 			newcon->qual = ccon->expr;
7426 
7427 			tab->constraints = lappend(tab->constraints, newcon);
7428 		}
7429 
7430 		/* Save the actually assigned name if it was defaulted */
7431 		if (constr->conname == NULL)
7432 			constr->conname = ccon->name;
7433 
7434 		ObjectAddressSet(address, ConstraintRelationId, ccon->conoid);
7435 	}
7436 
7437 	/* At this point we must have a locked-down name to use */
7438 	Assert(constr->conname != NULL);
7439 
7440 	/* Advance command counter in case same table is visited multiple times */
7441 	CommandCounterIncrement();
7442 
7443 	/*
7444 	 * If the constraint got merged with an existing constraint, we're done.
7445 	 * We mustn't recurse to child tables in this case, because they've
7446 	 * already got the constraint, and visiting them again would lead to an
7447 	 * incorrect value for coninhcount.
7448 	 */
7449 	if (newcons == NIL)
7450 		return address;
7451 
7452 	/*
7453 	 * If adding a NO INHERIT constraint, no need to find our children.
7454 	 */
7455 	if (constr->is_no_inherit)
7456 		return address;
7457 
7458 	/*
7459 	 * Propagate to children as appropriate.  Unlike most other ALTER
7460 	 * routines, we have to do this one level of recursion at a time; we can't
7461 	 * use find_all_inheritors to do it in one pass.
7462 	 */
7463 	children = find_inheritance_children(RelationGetRelid(rel), lockmode);
7464 
7465 	/*
7466 	 * Check if ONLY was specified with ALTER TABLE.  If so, allow the
7467 	 * constraint creation only if there are no children currently.  Error out
7468 	 * otherwise.
7469 	 */
7470 	if (!recurse && children != NIL)
7471 		ereport(ERROR,
7472 				(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
7473 				 errmsg("constraint must be added to child tables too")));
7474 
7475 	foreach(child, children)
7476 	{
7477 		Oid			childrelid = lfirst_oid(child);
7478 		Relation	childrel;
7479 		AlteredTableInfo *childtab;
7480 
7481 		/* find_inheritance_children already got lock */
7482 		childrel = heap_open(childrelid, NoLock);
7483 		CheckTableNotInUse(childrel, "ALTER TABLE");
7484 
7485 		/* Find or create work queue entry for this table */
7486 		childtab = ATGetQueueEntry(wqueue, childrel);
7487 
7488 		/* Recurse to child */
7489 		ATAddCheckConstraint(wqueue, childtab, childrel,
7490 							 constr, recurse, true, is_readd, lockmode);
7491 
7492 		heap_close(childrel, NoLock);
7493 	}
7494 
7495 	return address;
7496 }
7497 
7498 /*
7499  * Add a foreign-key constraint to a single table; return the new constraint's
7500  * address.
7501  *
7502  * Subroutine for ATExecAddConstraint.  Must already hold exclusive
7503  * lock on the rel, and have done appropriate validity checks for it.
7504  * We do permissions checks here, however.
7505  */
7506 static ObjectAddress
ATAddForeignKeyConstraint(List ** wqueue,AlteredTableInfo * tab,Relation rel,Constraint * fkconstraint,Oid parentConstr,bool recurse,bool recursing,LOCKMODE lockmode)7507 ATAddForeignKeyConstraint(List **wqueue, AlteredTableInfo *tab, Relation rel,
7508 						  Constraint *fkconstraint, Oid parentConstr,
7509 						  bool recurse, bool recursing, LOCKMODE lockmode)
7510 {
7511 	Relation	pkrel;
7512 	int16		pkattnum[INDEX_MAX_KEYS];
7513 	int16		fkattnum[INDEX_MAX_KEYS];
7514 	Oid			pktypoid[INDEX_MAX_KEYS];
7515 	Oid			fktypoid[INDEX_MAX_KEYS];
7516 	Oid			opclasses[INDEX_MAX_KEYS];
7517 	Oid			pfeqoperators[INDEX_MAX_KEYS];
7518 	Oid			ppeqoperators[INDEX_MAX_KEYS];
7519 	Oid			ffeqoperators[INDEX_MAX_KEYS];
7520 	bool		connoinherit;
7521 	int			i;
7522 	int			numfks,
7523 				numpks;
7524 	Oid			indexOid;
7525 	Oid			constrOid;
7526 	bool		old_check_ok;
7527 	ObjectAddress address;
7528 	ListCell   *old_pfeqop_item = list_head(fkconstraint->old_conpfeqop);
7529 
7530 	/*
7531 	 * Grab ShareRowExclusiveLock on the pk table, so that someone doesn't
7532 	 * delete rows out from under us.
7533 	 */
7534 	if (OidIsValid(fkconstraint->old_pktable_oid))
7535 		pkrel = heap_open(fkconstraint->old_pktable_oid, ShareRowExclusiveLock);
7536 	else
7537 		pkrel = heap_openrv(fkconstraint->pktable, ShareRowExclusiveLock);
7538 
7539 	/*
7540 	 * Validity checks (permission checks wait till we have the column
7541 	 * numbers)
7542 	 */
7543 	if (pkrel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
7544 		ereport(ERROR,
7545 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
7546 				 errmsg("cannot reference partitioned table \"%s\"",
7547 						RelationGetRelationName(pkrel))));
7548 
7549 	if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
7550 	{
7551 		if (!recurse)
7552 			ereport(ERROR,
7553 					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
7554 					 errmsg("cannot use ONLY for foreign key on partitioned table \"%s\" referencing relation \"%s\"",
7555 							RelationGetRelationName(rel),
7556 							RelationGetRelationName(pkrel))));
7557 		if (fkconstraint->skip_validation && !fkconstraint->initially_valid)
7558 			ereport(ERROR,
7559 					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
7560 					 errmsg("cannot add NOT VALID foreign key on partitioned table \"%s\" referencing relation \"%s\"",
7561 							RelationGetRelationName(rel),
7562 							RelationGetRelationName(pkrel)),
7563 					 errdetail("This feature is not yet supported on partitioned tables.")));
7564 	}
7565 
7566 	if (pkrel->rd_rel->relkind != RELKIND_RELATION)
7567 		ereport(ERROR,
7568 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
7569 				 errmsg("referenced relation \"%s\" is not a table",
7570 						RelationGetRelationName(pkrel))));
7571 
7572 	if (!allowSystemTableMods && IsSystemRelation(pkrel))
7573 		ereport(ERROR,
7574 				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
7575 				 errmsg("permission denied: \"%s\" is a system catalog",
7576 						RelationGetRelationName(pkrel))));
7577 
7578 	/*
7579 	 * References from permanent or unlogged tables to temp tables, and from
7580 	 * permanent tables to unlogged tables, are disallowed because the
7581 	 * referenced data can vanish out from under us.  References from temp
7582 	 * tables to any other table type are also disallowed, because other
7583 	 * backends might need to run the RI triggers on the perm table, but they
7584 	 * can't reliably see tuples in the local buffers of other backends.
7585 	 */
7586 	switch (rel->rd_rel->relpersistence)
7587 	{
7588 		case RELPERSISTENCE_PERMANENT:
7589 			if (pkrel->rd_rel->relpersistence != RELPERSISTENCE_PERMANENT)
7590 				ereport(ERROR,
7591 						(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
7592 						 errmsg("constraints on permanent tables may reference only permanent tables")));
7593 			break;
7594 		case RELPERSISTENCE_UNLOGGED:
7595 			if (pkrel->rd_rel->relpersistence != RELPERSISTENCE_PERMANENT
7596 				&& pkrel->rd_rel->relpersistence != RELPERSISTENCE_UNLOGGED)
7597 				ereport(ERROR,
7598 						(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
7599 						 errmsg("constraints on unlogged tables may reference only permanent or unlogged tables")));
7600 			break;
7601 		case RELPERSISTENCE_TEMP:
7602 			if (pkrel->rd_rel->relpersistence != RELPERSISTENCE_TEMP)
7603 				ereport(ERROR,
7604 						(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
7605 						 errmsg("constraints on temporary tables may reference only temporary tables")));
7606 			if (!pkrel->rd_islocaltemp || !rel->rd_islocaltemp)
7607 				ereport(ERROR,
7608 						(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
7609 						 errmsg("constraints on temporary tables must involve temporary tables of this session")));
7610 			break;
7611 	}
7612 
7613 	/*
7614 	 * Look up the referencing attributes to make sure they exist, and record
7615 	 * their attnums and type OIDs.
7616 	 */
7617 	MemSet(pkattnum, 0, sizeof(pkattnum));
7618 	MemSet(fkattnum, 0, sizeof(fkattnum));
7619 	MemSet(pktypoid, 0, sizeof(pktypoid));
7620 	MemSet(fktypoid, 0, sizeof(fktypoid));
7621 	MemSet(opclasses, 0, sizeof(opclasses));
7622 	MemSet(pfeqoperators, 0, sizeof(pfeqoperators));
7623 	MemSet(ppeqoperators, 0, sizeof(ppeqoperators));
7624 	MemSet(ffeqoperators, 0, sizeof(ffeqoperators));
7625 
7626 	numfks = transformColumnNameList(RelationGetRelid(rel),
7627 									 fkconstraint->fk_attrs,
7628 									 fkattnum, fktypoid);
7629 
7630 	/*
7631 	 * If the attribute list for the referenced table was omitted, lookup the
7632 	 * definition of the primary key and use it.  Otherwise, validate the
7633 	 * supplied attribute list.  In either case, discover the index OID and
7634 	 * index opclasses, and the attnums and type OIDs of the attributes.
7635 	 */
7636 	if (fkconstraint->pk_attrs == NIL)
7637 	{
7638 		numpks = transformFkeyGetPrimaryKey(pkrel, &indexOid,
7639 											&fkconstraint->pk_attrs,
7640 											pkattnum, pktypoid,
7641 											opclasses);
7642 	}
7643 	else
7644 	{
7645 		numpks = transformColumnNameList(RelationGetRelid(pkrel),
7646 										 fkconstraint->pk_attrs,
7647 										 pkattnum, pktypoid);
7648 		/* Look for an index matching the column list */
7649 		indexOid = transformFkeyCheckAttrs(pkrel, numpks, pkattnum,
7650 										   opclasses);
7651 	}
7652 
7653 	/*
7654 	 * Now we can check permissions.
7655 	 */
7656 	checkFkeyPermissions(pkrel, pkattnum, numpks);
7657 
7658 	/*
7659 	 * Look up the equality operators to use in the constraint.
7660 	 *
7661 	 * Note that we have to be careful about the difference between the actual
7662 	 * PK column type and the opclass' declared input type, which might be
7663 	 * only binary-compatible with it.  The declared opcintype is the right
7664 	 * thing to probe pg_amop with.
7665 	 */
7666 	if (numfks != numpks)
7667 		ereport(ERROR,
7668 				(errcode(ERRCODE_INVALID_FOREIGN_KEY),
7669 				 errmsg("number of referencing and referenced columns for foreign key disagree")));
7670 
7671 	/*
7672 	 * On the strength of a previous constraint, we might avoid scanning
7673 	 * tables to validate this one.  See below.
7674 	 */
7675 	old_check_ok = (fkconstraint->old_conpfeqop != NIL);
7676 	Assert(!old_check_ok || numfks == list_length(fkconstraint->old_conpfeqop));
7677 
7678 	for (i = 0; i < numpks; i++)
7679 	{
7680 		Oid			pktype = pktypoid[i];
7681 		Oid			fktype = fktypoid[i];
7682 		Oid			fktyped;
7683 		HeapTuple	cla_ht;
7684 		Form_pg_opclass cla_tup;
7685 		Oid			amid;
7686 		Oid			opfamily;
7687 		Oid			opcintype;
7688 		Oid			pfeqop;
7689 		Oid			ppeqop;
7690 		Oid			ffeqop;
7691 		int16		eqstrategy;
7692 		Oid			pfeqop_right;
7693 
7694 		/* We need several fields out of the pg_opclass entry */
7695 		cla_ht = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclasses[i]));
7696 		if (!HeapTupleIsValid(cla_ht))
7697 			elog(ERROR, "cache lookup failed for opclass %u", opclasses[i]);
7698 		cla_tup = (Form_pg_opclass) GETSTRUCT(cla_ht);
7699 		amid = cla_tup->opcmethod;
7700 		opfamily = cla_tup->opcfamily;
7701 		opcintype = cla_tup->opcintype;
7702 		ReleaseSysCache(cla_ht);
7703 
7704 		/*
7705 		 * Check it's a btree; currently this can never fail since no other
7706 		 * index AMs support unique indexes.  If we ever did have other types
7707 		 * of unique indexes, we'd need a way to determine which operator
7708 		 * strategy number is equality.  (Is it reasonable to insist that
7709 		 * every such index AM use btree's number for equality?)
7710 		 */
7711 		if (amid != BTREE_AM_OID)
7712 			elog(ERROR, "only b-tree indexes are supported for foreign keys");
7713 		eqstrategy = BTEqualStrategyNumber;
7714 
7715 		/*
7716 		 * There had better be a primary equality operator for the index.
7717 		 * We'll use it for PK = PK comparisons.
7718 		 */
7719 		ppeqop = get_opfamily_member(opfamily, opcintype, opcintype,
7720 									 eqstrategy);
7721 
7722 		if (!OidIsValid(ppeqop))
7723 			elog(ERROR, "missing operator %d(%u,%u) in opfamily %u",
7724 				 eqstrategy, opcintype, opcintype, opfamily);
7725 
7726 		/*
7727 		 * Are there equality operators that take exactly the FK type? Assume
7728 		 * we should look through any domain here.
7729 		 */
7730 		fktyped = getBaseType(fktype);
7731 
7732 		pfeqop = get_opfamily_member(opfamily, opcintype, fktyped,
7733 									 eqstrategy);
7734 		if (OidIsValid(pfeqop))
7735 		{
7736 			pfeqop_right = fktyped;
7737 			ffeqop = get_opfamily_member(opfamily, fktyped, fktyped,
7738 										 eqstrategy);
7739 		}
7740 		else
7741 		{
7742 			/* keep compiler quiet */
7743 			pfeqop_right = InvalidOid;
7744 			ffeqop = InvalidOid;
7745 		}
7746 
7747 		if (!(OidIsValid(pfeqop) && OidIsValid(ffeqop)))
7748 		{
7749 			/*
7750 			 * Otherwise, look for an implicit cast from the FK type to the
7751 			 * opcintype, and if found, use the primary equality operator.
7752 			 * This is a bit tricky because opcintype might be a polymorphic
7753 			 * type such as ANYARRAY or ANYENUM; so what we have to test is
7754 			 * whether the two actual column types can be concurrently cast to
7755 			 * that type.  (Otherwise, we'd fail to reject combinations such
7756 			 * as int[] and point[].)
7757 			 */
7758 			Oid			input_typeids[2];
7759 			Oid			target_typeids[2];
7760 
7761 			input_typeids[0] = pktype;
7762 			input_typeids[1] = fktype;
7763 			target_typeids[0] = opcintype;
7764 			target_typeids[1] = opcintype;
7765 			if (can_coerce_type(2, input_typeids, target_typeids,
7766 								COERCION_IMPLICIT))
7767 			{
7768 				pfeqop = ffeqop = ppeqop;
7769 				pfeqop_right = opcintype;
7770 			}
7771 		}
7772 
7773 		if (!(OidIsValid(pfeqop) && OidIsValid(ffeqop)))
7774 			ereport(ERROR,
7775 					(errcode(ERRCODE_DATATYPE_MISMATCH),
7776 					 errmsg("foreign key constraint \"%s\" "
7777 							"cannot be implemented",
7778 							fkconstraint->conname),
7779 					 errdetail("Key columns \"%s\" and \"%s\" "
7780 							   "are of incompatible types: %s and %s.",
7781 							   strVal(list_nth(fkconstraint->fk_attrs, i)),
7782 							   strVal(list_nth(fkconstraint->pk_attrs, i)),
7783 							   format_type_be(fktype),
7784 							   format_type_be(pktype))));
7785 
7786 		if (old_check_ok)
7787 		{
7788 			/*
7789 			 * When a pfeqop changes, revalidate the constraint.  We could
7790 			 * permit intra-opfamily changes, but that adds subtle complexity
7791 			 * without any concrete benefit for core types.  We need not
7792 			 * assess ppeqop or ffeqop, which RI_Initial_Check() does not use.
7793 			 */
7794 			old_check_ok = (pfeqop == lfirst_oid(old_pfeqop_item));
7795 			old_pfeqop_item = lnext(old_pfeqop_item);
7796 		}
7797 		if (old_check_ok)
7798 		{
7799 			Oid			old_fktype;
7800 			Oid			new_fktype;
7801 			CoercionPathType old_pathtype;
7802 			CoercionPathType new_pathtype;
7803 			Oid			old_castfunc;
7804 			Oid			new_castfunc;
7805 			Form_pg_attribute attr = TupleDescAttr(tab->oldDesc,
7806 												   fkattnum[i] - 1);
7807 
7808 			/*
7809 			 * Identify coercion pathways from each of the old and new FK-side
7810 			 * column types to the right (foreign) operand type of the pfeqop.
7811 			 * We may assume that pg_constraint.conkey is not changing.
7812 			 */
7813 			old_fktype = attr->atttypid;
7814 			new_fktype = fktype;
7815 			old_pathtype = findFkeyCast(pfeqop_right, old_fktype,
7816 										&old_castfunc);
7817 			new_pathtype = findFkeyCast(pfeqop_right, new_fktype,
7818 										&new_castfunc);
7819 
7820 			/*
7821 			 * Upon a change to the cast from the FK column to its pfeqop
7822 			 * operand, revalidate the constraint.  For this evaluation, a
7823 			 * binary coercion cast is equivalent to no cast at all.  While
7824 			 * type implementors should design implicit casts with an eye
7825 			 * toward consistency of operations like equality, we cannot
7826 			 * assume here that they have done so.
7827 			 *
7828 			 * A function with a polymorphic argument could change behavior
7829 			 * arbitrarily in response to get_fn_expr_argtype().  Therefore,
7830 			 * when the cast destination is polymorphic, we only avoid
7831 			 * revalidation if the input type has not changed at all.  Given
7832 			 * just the core data types and operator classes, this requirement
7833 			 * prevents no would-be optimizations.
7834 			 *
7835 			 * If the cast converts from a base type to a domain thereon, then
7836 			 * that domain type must be the opcintype of the unique index.
7837 			 * Necessarily, the primary key column must then be of the domain
7838 			 * type.  Since the constraint was previously valid, all values on
7839 			 * the foreign side necessarily exist on the primary side and in
7840 			 * turn conform to the domain.  Consequently, we need not treat
7841 			 * domains specially here.
7842 			 *
7843 			 * Since we require that all collations share the same notion of
7844 			 * equality (which they do, because texteq reduces to bitwise
7845 			 * equality), we don't compare collation here.
7846 			 *
7847 			 * We need not directly consider the PK type.  It's necessarily
7848 			 * binary coercible to the opcintype of the unique index column,
7849 			 * and ri_triggers.c will only deal with PK datums in terms of
7850 			 * that opcintype.  Changing the opcintype also changes pfeqop.
7851 			 */
7852 			old_check_ok = (new_pathtype == old_pathtype &&
7853 							new_castfunc == old_castfunc &&
7854 							(!IsPolymorphicType(pfeqop_right) ||
7855 							 new_fktype == old_fktype));
7856 		}
7857 
7858 		pfeqoperators[i] = pfeqop;
7859 		ppeqoperators[i] = ppeqop;
7860 		ffeqoperators[i] = ffeqop;
7861 	}
7862 
7863 	/*
7864 	 * FKs always inherit for partitioned tables, and never for legacy
7865 	 * inheritance.
7866 	 */
7867 	connoinherit = rel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE;
7868 
7869 	/*
7870 	 * Record the FK constraint in pg_constraint.
7871 	 */
7872 	constrOid = CreateConstraintEntry(fkconstraint->conname,
7873 									  RelationGetNamespace(rel),
7874 									  CONSTRAINT_FOREIGN,
7875 									  fkconstraint->deferrable,
7876 									  fkconstraint->initdeferred,
7877 									  fkconstraint->initially_valid,
7878 									  parentConstr,
7879 									  RelationGetRelid(rel),
7880 									  fkattnum,
7881 									  numfks,
7882 									  numfks,
7883 									  InvalidOid,	/* not a domain constraint */
7884 									  indexOid,
7885 									  RelationGetRelid(pkrel),
7886 									  pkattnum,
7887 									  pfeqoperators,
7888 									  ppeqoperators,
7889 									  ffeqoperators,
7890 									  numpks,
7891 									  fkconstraint->fk_upd_action,
7892 									  fkconstraint->fk_del_action,
7893 									  fkconstraint->fk_matchtype,
7894 									  NULL, /* no exclusion constraint */
7895 									  NULL, /* no check constraint */
7896 									  NULL,
7897 									  NULL,
7898 									  true, /* islocal */
7899 									  0,	/* inhcount */
7900 									  connoinherit,	/* conNoInherit */
7901 									  false);	/* is_internal */
7902 	ObjectAddressSet(address, ConstraintRelationId, constrOid);
7903 
7904 	/*
7905 	 * Create the triggers that will enforce the constraint.  We only want the
7906 	 * action triggers to appear for the parent partitioned relation, even
7907 	 * though the constraints also exist below.
7908 	 */
7909 	createForeignKeyTriggers(rel, RelationGetRelid(pkrel), fkconstraint,
7910 							 constrOid, indexOid, !recursing);
7911 
7912 	/*
7913 	 * Tell Phase 3 to check that the constraint is satisfied by existing
7914 	 * rows. We can skip this during table creation, when requested explicitly
7915 	 * by specifying NOT VALID in an ADD FOREIGN KEY command, and when we're
7916 	 * recreating a constraint following a SET DATA TYPE operation that did
7917 	 * not impugn its validity.
7918 	 */
7919 	if (!old_check_ok && !fkconstraint->skip_validation)
7920 	{
7921 		NewConstraint *newcon;
7922 
7923 		newcon = (NewConstraint *) palloc0(sizeof(NewConstraint));
7924 		newcon->name = fkconstraint->conname;
7925 		newcon->contype = CONSTR_FOREIGN;
7926 		newcon->refrelid = RelationGetRelid(pkrel);
7927 		newcon->refindid = indexOid;
7928 		newcon->conid = constrOid;
7929 		newcon->qual = (Node *) fkconstraint;
7930 
7931 		tab->constraints = lappend(tab->constraints, newcon);
7932 	}
7933 
7934 	/*
7935 	 * When called on a partitioned table, recurse to create the constraint on
7936 	 * the partitions also.
7937 	 */
7938 	if (recurse && rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
7939 	{
7940 		PartitionDesc partdesc;
7941 		Relation	pg_constraint;
7942 		List	   *cloned = NIL;
7943 		ListCell   *cell;
7944 
7945 		pg_constraint = heap_open(ConstraintRelationId, RowExclusiveLock);
7946 		partdesc = RelationGetPartitionDesc(rel);
7947 
7948 		for (i = 0; i < partdesc->nparts; i++)
7949 		{
7950 			Oid			partitionId = partdesc->oids[i];
7951 			Relation	partition = heap_open(partitionId, lockmode);
7952 
7953 			CheckTableNotInUse(partition, "ALTER TABLE");
7954 
7955 			CloneFkReferencing(pg_constraint, rel, partition,
7956 							   list_make1_oid(constrOid),
7957 							   &cloned);
7958 
7959 			heap_close(partition, NoLock);
7960 		}
7961 		heap_close(pg_constraint, RowExclusiveLock);
7962 
7963 		foreach(cell, cloned)
7964 		{
7965 			ClonedConstraint *cc = (ClonedConstraint *) lfirst(cell);
7966 			Relation    partition = heap_open(cc->relid, lockmode);
7967 			AlteredTableInfo *childtab;
7968 			NewConstraint *newcon;
7969 
7970 			/* Find or create work queue entry for this partition */
7971 			childtab = ATGetQueueEntry(wqueue, partition);
7972 
7973 			newcon = (NewConstraint *) palloc0(sizeof(NewConstraint));
7974 			newcon->name = cc->constraint->conname;
7975 			newcon->contype = CONSTR_FOREIGN;
7976 			newcon->refrelid = cc->refrelid;
7977 			newcon->refindid = cc->conindid;
7978 			newcon->conid = cc->conid;
7979 			newcon->qual = (Node *) fkconstraint;
7980 
7981 			childtab->constraints = lappend(childtab->constraints, newcon);
7982 
7983 			heap_close(partition, lockmode);
7984 		}
7985 	}
7986 
7987 	/*
7988 	 * Close pk table, but keep lock until we've committed.
7989 	 */
7990 	heap_close(pkrel, NoLock);
7991 
7992 	return address;
7993 }
7994 
7995 /*
7996  * CloneForeignKeyConstraints
7997  *		Clone foreign keys from a partitioned table to a newly acquired
7998  *		partition.
7999  *
8000  * relationId is a partition of parentId, so we can be certain that it has the
8001  * same columns with the same datatypes.  The columns may be in different
8002  * order, though.
8003  *
8004  * The *cloned list is appended ClonedConstraint elements describing what was
8005  * created, for the purposes of validating the constraint in ALTER TABLE's
8006  * Phase 3.
8007  */
8008 void
CloneForeignKeyConstraints(Oid parentId,Oid relationId,List ** cloned)8009 CloneForeignKeyConstraints(Oid parentId, Oid relationId, List **cloned)
8010 {
8011 	Relation	pg_constraint;
8012 	Relation	parentRel;
8013 	Relation	rel;
8014 	ScanKeyData key;
8015 	SysScanDesc scan;
8016 	HeapTuple	tuple;
8017 	List	   *clone = NIL;
8018 
8019 	parentRel = heap_open(parentId, NoLock);	/* already got lock */
8020 	/* see ATAddForeignKeyConstraint about lock level */
8021 	rel = heap_open(relationId, AccessExclusiveLock);
8022 	pg_constraint = heap_open(ConstraintRelationId, RowShareLock);
8023 
8024 	/* Obtain the list of constraints to clone or attach */
8025 	ScanKeyInit(&key,
8026 				Anum_pg_constraint_conrelid, BTEqualStrategyNumber,
8027 				F_OIDEQ, ObjectIdGetDatum(parentId));
8028 	scan = systable_beginscan(pg_constraint, ConstraintRelidTypidNameIndexId, true,
8029 							  NULL, 1, &key);
8030 	while ((tuple = systable_getnext(scan)) != NULL)
8031 	{
8032 		Oid		oid = HeapTupleGetOid(tuple);
8033 
8034 		clone = lappend_oid(clone, oid);
8035 	}
8036 	systable_endscan(scan);
8037 
8038 	/* Do the actual work, recursing to partitions as needed */
8039 	CloneFkReferencing(pg_constraint, parentRel, rel, clone, cloned);
8040 
8041 	/* We're done.  Clean up */
8042 	heap_close(parentRel, NoLock);
8043 	heap_close(rel, NoLock);	/* keep lock till commit */
8044 	heap_close(pg_constraint, RowShareLock);
8045 }
8046 
8047 /*
8048  * CloneFkReferencing
8049  *		Recursive subroutine for CloneForeignKeyConstraints, referencing side
8050  *
8051  * Clone the given list of FK constraints when a partition is attached on the
8052  * referencing side of those constraints.
8053  *
8054  * When cloning foreign keys to a partition, it may happen that equivalent
8055  * constraints already exist in the partition for some of them.  We can skip
8056  * creating a clone in that case, and instead just attach the existing
8057  * constraint to the one in the parent.
8058  *
8059  * This function recurses to partitions, if the new partition is partitioned;
8060  * of course, only do this for FKs that were actually cloned.
8061  */
8062 static void
CloneFkReferencing(Relation pg_constraint,Relation parentRel,Relation partRel,List * clone,List ** cloned)8063 CloneFkReferencing(Relation pg_constraint, Relation parentRel,
8064 				   Relation partRel, List *clone, List **cloned)
8065 {
8066 	AttrNumber *attmap;
8067 	List	   *partFKs;
8068 	List	   *subclone = NIL;
8069 	ListCell   *cell;
8070 
8071 	/*
8072 	 * The constraint key may differ, if the columns in the partition are
8073 	 * different.  This map is used to convert them.
8074 	 */
8075 	attmap = convert_tuples_by_name_map(RelationGetDescr(partRel),
8076 										RelationGetDescr(parentRel),
8077 										gettext_noop("could not convert row type"));
8078 
8079 	partFKs = copyObject(RelationGetFKeyList(partRel));
8080 
8081 	foreach(cell, clone)
8082 	{
8083 		Oid			parentConstrOid = lfirst_oid(cell);
8084 		Form_pg_constraint constrForm;
8085 		HeapTuple	tuple;
8086 		int			numfks;
8087 		AttrNumber	conkey[INDEX_MAX_KEYS];
8088 		AttrNumber	mapped_conkey[INDEX_MAX_KEYS];
8089 		AttrNumber	confkey[INDEX_MAX_KEYS];
8090 		Oid			conpfeqop[INDEX_MAX_KEYS];
8091 		Oid			conppeqop[INDEX_MAX_KEYS];
8092 		Oid			conffeqop[INDEX_MAX_KEYS];
8093 		Constraint *fkconstraint;
8094 		bool		attach_it;
8095 		Oid			constrOid;
8096 		ObjectAddress parentAddr,
8097 					childAddr;
8098 		ListCell   *cell;
8099 		int			i;
8100 
8101 		tuple = SearchSysCache1(CONSTROID, parentConstrOid);
8102 		if (!HeapTupleIsValid(tuple))
8103 			elog(ERROR, "cache lookup failed for constraint %u",
8104 				 parentConstrOid);
8105 		constrForm = (Form_pg_constraint) GETSTRUCT(tuple);
8106 
8107 		/* only foreign keys */
8108 		if (constrForm->contype != CONSTRAINT_FOREIGN)
8109 		{
8110 			ReleaseSysCache(tuple);
8111 			continue;
8112 		}
8113 
8114 		ObjectAddressSet(parentAddr, ConstraintRelationId, parentConstrOid);
8115 
8116 		DeconstructFkConstraintRow(tuple, &numfks, conkey, confkey,
8117 								   conpfeqop, conppeqop, conffeqop);
8118 		for (i = 0; i < numfks; i++)
8119 			mapped_conkey[i] = attmap[conkey[i] - 1];
8120 
8121 		/*
8122 		 * Before creating a new constraint, see whether any existing FKs are
8123 		 * fit for the purpose.  If one is, attach the parent constraint to it,
8124 		 * and don't clone anything.  This way we avoid the expensive
8125 		 * verification step and don't end up with a duplicate FK.  This also
8126 		 * means we don't consider this constraint when recursing to
8127 		 * partitions.
8128 		 */
8129 		attach_it = false;
8130 		foreach(cell, partFKs)
8131 		{
8132 			ForeignKeyCacheInfo *fk = lfirst_node(ForeignKeyCacheInfo, cell);
8133 			Form_pg_constraint partConstr;
8134 			HeapTuple	partcontup;
8135 			Relation	trigrel;
8136 			HeapTuple	trigtup;
8137 			SysScanDesc scan;
8138 			ScanKeyData key;
8139 
8140 			attach_it = true;
8141 
8142 			/*
8143 			 * Do some quick & easy initial checks.  If any of these fail, we
8144 			 * cannot use this constraint, but keep looking.
8145 			 */
8146 			if (fk->confrelid != constrForm->confrelid || fk->nkeys != numfks)
8147 			{
8148 				attach_it = false;
8149 				continue;
8150 			}
8151 			for (i = 0; i < numfks; i++)
8152 			{
8153 				if (fk->conkey[i] != mapped_conkey[i] ||
8154 					fk->confkey[i] != confkey[i] ||
8155 					fk->conpfeqop[i] != conpfeqop[i])
8156 				{
8157 					attach_it = false;
8158 					break;
8159 				}
8160 			}
8161 			if (!attach_it)
8162 				continue;
8163 
8164 			/*
8165 			 * Looks good so far; do some more extensive checks.  Presumably
8166 			 * the check for 'convalidated' could be dropped, since we don't
8167 			 * really care about that, but let's be careful for now.
8168 			 */
8169 			partcontup = SearchSysCache1(CONSTROID,
8170 										 ObjectIdGetDatum(fk->conoid));
8171 			if (!HeapTupleIsValid(partcontup))
8172 				elog(ERROR, "cache lookup failed for constraint %u",
8173 					 fk->conoid);
8174 			partConstr = (Form_pg_constraint) GETSTRUCT(partcontup);
8175 			if (OidIsValid(partConstr->conparentid) ||
8176 				!partConstr->convalidated ||
8177 				partConstr->condeferrable != constrForm->condeferrable ||
8178 				partConstr->condeferred != constrForm->condeferred ||
8179 				partConstr->confupdtype != constrForm->confupdtype ||
8180 				partConstr->confdeltype != constrForm->confdeltype ||
8181 				partConstr->confmatchtype != constrForm->confmatchtype)
8182 			{
8183 				ReleaseSysCache(partcontup);
8184 				attach_it = false;
8185 				continue;
8186 			}
8187 
8188 			ReleaseSysCache(partcontup);
8189 
8190 			/*
8191 			 * Looks good!  Attach this constraint.  The action triggers in
8192 			 * the new partition become redundant -- the parent table already
8193 			 * has equivalent ones, and those will be able to reach the
8194 			 * partition.  Remove the ones in the partition.  We identify them
8195 			 * because they have our constraint OID, as well as being on the
8196 			 * referenced rel.
8197 			 */
8198 			trigrel = heap_open(TriggerRelationId, RowExclusiveLock);
8199 			ScanKeyInit(&key,
8200 						Anum_pg_trigger_tgconstraint,
8201 						BTEqualStrategyNumber, F_OIDEQ,
8202 						ObjectIdGetDatum(fk->conoid));
8203 
8204 			scan = systable_beginscan(trigrel, TriggerConstraintIndexId, true,
8205 									  NULL, 1, &key);
8206 			while ((trigtup = systable_getnext(scan)) != NULL)
8207 			{
8208 				Form_pg_trigger	trgform = (Form_pg_trigger) GETSTRUCT(trigtup);
8209 				ObjectAddress	trigger;
8210 
8211 				if (trgform->tgconstrrelid != fk->conrelid)
8212 					continue;
8213 				if (trgform->tgrelid != fk->confrelid)
8214 					continue;
8215 
8216 				/*
8217 				 * The constraint is originally set up to contain this trigger
8218 				 * as an implementation object, so there's a dependency record
8219 				 * that links the two; however, since the trigger is no longer
8220 				 * needed, we remove the dependency link in order to be able
8221 				 * to drop the trigger while keeping the constraint intact.
8222 				 */
8223 				deleteDependencyRecordsFor(TriggerRelationId,
8224 										   HeapTupleGetOid(trigtup),
8225 										   false);
8226 				/* make dependency deletion visible to performDeletion */
8227 				CommandCounterIncrement();
8228 				ObjectAddressSet(trigger, TriggerRelationId,
8229 								 HeapTupleGetOid(trigtup));
8230 				performDeletion(&trigger, DROP_RESTRICT, 0);
8231 				/* make trigger drop visible, in case the loop iterates */
8232 				CommandCounterIncrement();
8233 			}
8234 
8235 			systable_endscan(scan);
8236 			heap_close(trigrel, RowExclusiveLock);
8237 
8238 			ConstraintSetParentConstraint(fk->conoid, parentConstrOid);
8239 			CommandCounterIncrement();
8240 			attach_it = true;
8241 			break;
8242 		}
8243 
8244 		/*
8245 		 * If we attached to an existing constraint, there is no need to
8246 		 * create a new one.  In fact, there's no need to recurse for this
8247 		 * constraint to partitions, either.
8248 		 */
8249 		if (attach_it)
8250 		{
8251 			ReleaseSysCache(tuple);
8252 			continue;
8253 		}
8254 
8255 		constrOid =
8256 			CreateConstraintEntry(NameStr(constrForm->conname),
8257 								  constrForm->connamespace,
8258 								  CONSTRAINT_FOREIGN,
8259 								  constrForm->condeferrable,
8260 								  constrForm->condeferred,
8261 								  constrForm->convalidated,
8262 								  parentConstrOid,
8263 								  RelationGetRelid(partRel),
8264 								  mapped_conkey,
8265 								  numfks,
8266 								  numfks,
8267 								  InvalidOid,	/* not a domain constraint */
8268 								  constrForm->conindid, /* same index */
8269 								  constrForm->confrelid,	/* same foreign rel */
8270 								  confkey,
8271 								  conpfeqop,
8272 								  conppeqop,
8273 								  conffeqop,
8274 								  numfks,
8275 								  constrForm->confupdtype,
8276 								  constrForm->confdeltype,
8277 								  constrForm->confmatchtype,
8278 								  NULL,
8279 								  NULL,
8280 								  NULL,
8281 								  NULL,
8282 								  false,
8283 								  1, false, true);
8284 		subclone = lappend_oid(subclone, constrOid);
8285 
8286 		ObjectAddressSet(childAddr, ConstraintRelationId, constrOid);
8287 		recordDependencyOn(&childAddr, &parentAddr, DEPENDENCY_INTERNAL_AUTO);
8288 
8289 		fkconstraint = makeNode(Constraint);
8290 		/* for now this is all we need */
8291 		fkconstraint->conname = pstrdup(NameStr(constrForm->conname));
8292 		fkconstraint->fk_upd_action = constrForm->confupdtype;
8293 		fkconstraint->fk_del_action = constrForm->confdeltype;
8294 		fkconstraint->deferrable = constrForm->condeferrable;
8295 		fkconstraint->initdeferred = constrForm->condeferred;
8296 
8297 		createForeignKeyTriggers(partRel, constrForm->confrelid, fkconstraint,
8298 								 constrOid, constrForm->conindid, false);
8299 
8300 		if (cloned)
8301 		{
8302 			ClonedConstraint *newc;
8303 
8304 			/*
8305 			 * Feed back caller about the constraints we created, so that they
8306 			 * can set up constraint verification.
8307 			 */
8308 			newc = palloc(sizeof(ClonedConstraint));
8309 			newc->relid = RelationGetRelid(partRel);
8310 			newc->refrelid = constrForm->confrelid;
8311 			newc->conindid = constrForm->conindid;
8312 			newc->conid = constrOid;
8313 			newc->constraint = fkconstraint;
8314 
8315 			*cloned = lappend(*cloned, newc);
8316 		}
8317 
8318 		ReleaseSysCache(tuple);
8319 	}
8320 
8321 	pfree(attmap);
8322 	list_free_deep(partFKs);
8323 
8324 	/*
8325 	 * If the partition is partitioned, recurse to handle any constraints that
8326 	 * were cloned.
8327 	 */
8328 	if (partRel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE &&
8329 		subclone != NIL)
8330 	{
8331 		PartitionDesc partdesc = RelationGetPartitionDesc(partRel);
8332 		int			i;
8333 
8334 		for (i = 0; i < partdesc->nparts; i++)
8335 		{
8336 			Relation	childRel;
8337 
8338 			childRel = heap_open(partdesc->oids[i], AccessExclusiveLock);
8339 			CloneFkReferencing(pg_constraint,
8340 							   partRel,
8341 							   childRel,
8342 							   subclone,
8343 							   cloned);
8344 			heap_close(childRel, NoLock);	/* keep lock till commit */
8345 		}
8346 	}
8347 }
8348 
8349 /*
8350  * ALTER TABLE ALTER CONSTRAINT
8351  *
8352  * Update the attributes of a constraint.
8353  *
8354  * Currently only works for Foreign Key constraints.
8355  *
8356  * If the constraint is modified, returns its address; otherwise, return
8357  * InvalidObjectAddress.
8358  */
8359 static ObjectAddress
ATExecAlterConstraint(Relation rel,AlterTableCmd * cmd,bool recurse,bool recursing,LOCKMODE lockmode)8360 ATExecAlterConstraint(Relation rel, AlterTableCmd *cmd, bool recurse,
8361 					  bool recursing, LOCKMODE lockmode)
8362 {
8363 	Constraint *cmdcon;
8364 	Relation	conrel;
8365 	Relation	tgrel;
8366 	SysScanDesc scan;
8367 	ScanKeyData skey[3];
8368 	HeapTuple	contuple;
8369 	Form_pg_constraint currcon;
8370 	ObjectAddress address;
8371 	List	   *otherrelids = NIL;
8372 	ListCell   *lc;
8373 
8374 	cmdcon = castNode(Constraint, cmd->def);
8375 
8376 	conrel = heap_open(ConstraintRelationId, RowExclusiveLock);
8377 	tgrel = heap_open(TriggerRelationId, RowExclusiveLock);
8378 
8379 	/*
8380 	 * Find and check the target constraint
8381 	 */
8382 	ScanKeyInit(&skey[0],
8383 				Anum_pg_constraint_conrelid,
8384 				BTEqualStrategyNumber, F_OIDEQ,
8385 				ObjectIdGetDatum(RelationGetRelid(rel)));
8386 	ScanKeyInit(&skey[1],
8387 				Anum_pg_constraint_contypid,
8388 				BTEqualStrategyNumber, F_OIDEQ,
8389 				ObjectIdGetDatum(InvalidOid));
8390 	ScanKeyInit(&skey[2],
8391 				Anum_pg_constraint_conname,
8392 				BTEqualStrategyNumber, F_NAMEEQ,
8393 				CStringGetDatum(cmdcon->conname));
8394 	scan = systable_beginscan(conrel, ConstraintRelidTypidNameIndexId,
8395 							  true, NULL, 3, skey);
8396 
8397 	/* There can be at most one matching row */
8398 	if (!HeapTupleIsValid(contuple = systable_getnext(scan)))
8399 		ereport(ERROR,
8400 				(errcode(ERRCODE_UNDEFINED_OBJECT),
8401 				 errmsg("constraint \"%s\" of relation \"%s\" does not exist",
8402 						cmdcon->conname, RelationGetRelationName(rel))));
8403 
8404 	currcon = (Form_pg_constraint) GETSTRUCT(contuple);
8405 	if (currcon->contype != CONSTRAINT_FOREIGN)
8406 		ereport(ERROR,
8407 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
8408 				 errmsg("constraint \"%s\" of relation \"%s\" is not a foreign key constraint",
8409 						cmdcon->conname, RelationGetRelationName(rel))));
8410 
8411 	/*
8412 	 * If it's not the topmost constraint, raise an error.
8413 	 *
8414 	 * Altering a non-topmost constraint leaves some triggers untouched, since
8415 	 * they are not directly connected to this constraint; also, pg_dump would
8416 	 * ignore the deferrability status of the individual constraint, since it
8417 	 * only dumps topmost constraints.  Avoid these problems by refusing this
8418 	 * operation and telling the user to alter the parent constraint instead.
8419 	 */
8420 	if (OidIsValid(currcon->conparentid))
8421 	{
8422 		HeapTuple	tp;
8423 		Oid			parent = currcon->conparentid;
8424 		char	   *ancestorname = NULL;
8425 		char	   *ancestortable = NULL;
8426 
8427 		/* Loop to find the topmost constraint */
8428 		while (HeapTupleIsValid(tp = SearchSysCache1(CONSTROID, ObjectIdGetDatum(parent))))
8429 		{
8430 			Form_pg_constraint contup = (Form_pg_constraint) GETSTRUCT(tp);
8431 
8432 			/* If no parent, this is the constraint we want */
8433 			if (!OidIsValid(contup->conparentid))
8434 			{
8435 				ancestorname = pstrdup(NameStr(contup->conname));
8436 				ancestortable = get_rel_name(contup->conrelid);
8437 				ReleaseSysCache(tp);
8438 				break;
8439 			}
8440 
8441 			parent = contup->conparentid;
8442 			ReleaseSysCache(tp);
8443 		}
8444 
8445 		ereport(ERROR,
8446 				(errmsg("cannot alter constraint \"%s\" on relation \"%s\"",
8447 						cmdcon->conname, RelationGetRelationName(rel)),
8448 				 ancestorname && ancestortable ?
8449 				 errdetail("Constraint \"%s\" is derived from constraint \"%s\" of relation \"%s\".",
8450 						   cmdcon->conname, ancestorname, ancestortable) : 0,
8451 				 errhint("You may alter the constraint it derives from, instead.")));
8452 	}
8453 
8454 	/*
8455 	 * Do the actual catalog work.  We can skip changing if already in the
8456 	 * desired state, but not if a partitioned table: partitions need to be
8457 	 * processed regardless, in case they've had it locally changed.
8458 	 */
8459 	address = InvalidObjectAddress;
8460 	if (currcon->condeferrable != cmdcon->deferrable ||
8461 		currcon->condeferred != cmdcon->initdeferred ||
8462 		rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
8463 	{
8464 		if (ATExecAlterConstrRecurse(cmdcon, conrel, tgrel, rel, contuple,
8465 									 &otherrelids, lockmode))
8466 			ObjectAddressSet(address, ConstraintRelationId,
8467 							 HeapTupleGetOid(contuple));
8468 	}
8469 
8470 	/*
8471 	 * ATExecConstrRecurse already invalidated relcache for the relations
8472 	 * having the constraint itself; here we also invalidate for relations
8473 	 * that have any triggers that implement the constraint.
8474 	 */
8475 	foreach(lc, otherrelids)
8476 		CacheInvalidateRelcacheByRelid(lfirst_oid(lc));
8477 
8478 	systable_endscan(scan);
8479 
8480 	heap_close(conrel, RowExclusiveLock);
8481 	heap_close(tgrel, RowExclusiveLock);
8482 
8483 	return address;
8484 }
8485 
8486 /*
8487  * Recursive subroutine of ATExecAlterConstraint.  Returns true if the
8488  * constraint is altered.
8489  *
8490  * *otherrelids is appended OIDs of relations containing affected triggers.
8491  *
8492  * Note that we must recurse even when the values are correct, in case
8493  * indirect descendants have had their constraints altered locally.
8494  * (This could be avoided if we forbade altering constraints in partitions
8495  * but existing releases don't do that.)
8496  */
8497 static bool
ATExecAlterConstrRecurse(Constraint * cmdcon,Relation conrel,Relation tgrel,Relation rel,HeapTuple contuple,List ** otherrelids,LOCKMODE lockmode)8498 ATExecAlterConstrRecurse(Constraint *cmdcon, Relation conrel, Relation tgrel,
8499 						 Relation rel, HeapTuple contuple, List **otherrelids,
8500 						 LOCKMODE lockmode)
8501 {
8502 	Form_pg_constraint currcon;
8503 	Oid			conoid;
8504 	bool		changed = false;
8505 
8506 	currcon = (Form_pg_constraint) GETSTRUCT(contuple);
8507 	conoid = HeapTupleGetOid(contuple);
8508 
8509 	/*
8510 	 * Update pg_constraint with the flags from cmdcon.
8511 	 *
8512 	 * If called to modify a constraint that's already in the desired state,
8513 	 * silently do nothing.
8514 	 */
8515 	if (currcon->condeferrable != cmdcon->deferrable ||
8516 		currcon->condeferred != cmdcon->initdeferred)
8517 	{
8518 		HeapTuple	copyTuple;
8519 		Form_pg_constraint copy_con;
8520 		HeapTuple	tgtuple;
8521 		ScanKeyData tgkey;
8522 		SysScanDesc tgscan;
8523 
8524 		/*
8525 		 * Now update the catalog, while we have the door open.
8526 		 */
8527 		copyTuple = heap_copytuple(contuple);
8528 		copy_con = (Form_pg_constraint) GETSTRUCT(copyTuple);
8529 		copy_con->condeferrable = cmdcon->deferrable;
8530 		copy_con->condeferred = cmdcon->initdeferred;
8531 		CatalogTupleUpdate(conrel, &copyTuple->t_self, copyTuple);
8532 
8533 		InvokeObjectPostAlterHook(ConstraintRelationId,
8534 								  HeapTupleGetOid(contuple), 0);
8535 
8536 		heap_freetuple(copyTuple);
8537 		changed = true;
8538 
8539 		/* Make new constraint flags visible to others */
8540 		CacheInvalidateRelcache(rel);
8541 
8542 		/*
8543 		 * Now we need to update the multiple entries in pg_trigger that
8544 		 * implement the constraint.
8545 		 */
8546 		ScanKeyInit(&tgkey,
8547 					Anum_pg_trigger_tgconstraint,
8548 					BTEqualStrategyNumber, F_OIDEQ,
8549 					ObjectIdGetDatum(HeapTupleGetOid(contuple)));
8550 		tgscan = systable_beginscan(tgrel, TriggerConstraintIndexId, true,
8551 									NULL, 1, &tgkey);
8552 		while (HeapTupleIsValid(tgtuple = systable_getnext(tgscan)))
8553 		{
8554 			Form_pg_trigger tgform = (Form_pg_trigger) GETSTRUCT(tgtuple);
8555 			Form_pg_trigger copy_tg;
8556 			HeapTuple	copyTuple;
8557 
8558 			/*
8559 			 * Remember OIDs of other relation(s) involved in FK constraint.
8560 			 * (Note: it's likely that we could skip forcing a relcache inval
8561 			 * for other rels that don't have a trigger whose properties
8562 			 * change, but let's be conservative.)
8563 			 */
8564 			if (tgform->tgrelid != RelationGetRelid(rel))
8565 				*otherrelids = list_append_unique_oid(*otherrelids,
8566 													  tgform->tgrelid);
8567 
8568 			/*
8569 			 * Update deferrability of RI_FKey_noaction_del,
8570 			 * RI_FKey_noaction_upd, RI_FKey_check_ins and RI_FKey_check_upd
8571 			 * triggers, but not others; see createForeignKeyTriggers and
8572 			 * CreateFKCheckTrigger.
8573 			 */
8574 			if (tgform->tgfoid != F_RI_FKEY_NOACTION_DEL &&
8575 				tgform->tgfoid != F_RI_FKEY_NOACTION_UPD &&
8576 				tgform->tgfoid != F_RI_FKEY_CHECK_INS &&
8577 				tgform->tgfoid != F_RI_FKEY_CHECK_UPD)
8578 				continue;
8579 
8580 			copyTuple = heap_copytuple(tgtuple);
8581 			copy_tg = (Form_pg_trigger) GETSTRUCT(copyTuple);
8582 
8583 			copy_tg->tgdeferrable = cmdcon->deferrable;
8584 			copy_tg->tginitdeferred = cmdcon->initdeferred;
8585 			CatalogTupleUpdate(tgrel, &copyTuple->t_self, copyTuple);
8586 
8587 			InvokeObjectPostAlterHook(TriggerRelationId,
8588 									  HeapTupleGetOid(tgtuple), 0);
8589 
8590 			heap_freetuple(copyTuple);
8591 		}
8592 
8593 		systable_endscan(tgscan);
8594 	}
8595 
8596 	/*
8597 	 * If the referencing table is partitioned, we need to recurse and handle
8598 	 * every constraint that is a child of this one.
8599 	 *
8600 	 * (This assumes that the recurse flag is forcibly set for partitioned
8601 	 * tables, and not set for legacy inheritance, though we don't check for
8602 	 * that here.)
8603 	 */
8604 	if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
8605 	{
8606 		ScanKeyData pkey;
8607 		SysScanDesc pscan;
8608 		HeapTuple	childtup;
8609 
8610 		ScanKeyInit(&pkey,
8611 					Anum_pg_constraint_conparentid,
8612 					BTEqualStrategyNumber, F_OIDEQ,
8613 					ObjectIdGetDatum(conoid));
8614 
8615 		pscan = systable_beginscan(conrel, ConstraintParentIndexId,
8616 								   true, NULL, 1, &pkey);
8617 
8618 		while (HeapTupleIsValid(childtup = systable_getnext(pscan)))
8619 		{
8620 			Form_pg_constraint childcon = (Form_pg_constraint) GETSTRUCT(childtup);
8621 			Relation	childrel;
8622 
8623 			childrel = heap_open(childcon->conrelid, lockmode);
8624 			ATExecAlterConstrRecurse(cmdcon, conrel, tgrel, childrel, childtup,
8625 									 otherrelids, lockmode);
8626 			heap_close(childrel, NoLock);
8627 		}
8628 
8629 		systable_endscan(pscan);
8630 	}
8631 
8632 	return changed;
8633 }
8634 
8635 /*
8636  * ALTER TABLE VALIDATE CONSTRAINT
8637  *
8638  * XXX The reason we handle recursion here rather than at Phase 1 is because
8639  * there's no good way to skip recursing when handling foreign keys: there is
8640  * no need to lock children in that case, yet we wouldn't be able to avoid
8641  * doing so at that level.
8642  *
8643  * Return value is the address of the validated constraint.  If the constraint
8644  * was already validated, InvalidObjectAddress is returned.
8645  */
8646 static ObjectAddress
ATExecValidateConstraint(List ** wqueue,Relation rel,char * constrName,bool recurse,bool recursing,LOCKMODE lockmode)8647 ATExecValidateConstraint(List **wqueue, Relation rel, char *constrName,
8648 						 bool recurse, bool recursing, LOCKMODE lockmode)
8649 {
8650 	Relation	conrel;
8651 	SysScanDesc scan;
8652 	ScanKeyData skey[3];
8653 	HeapTuple	tuple;
8654 	Form_pg_constraint con;
8655 	ObjectAddress address;
8656 
8657 	conrel = heap_open(ConstraintRelationId, RowExclusiveLock);
8658 
8659 	/*
8660 	 * Find and check the target constraint
8661 	 */
8662 	ScanKeyInit(&skey[0],
8663 				Anum_pg_constraint_conrelid,
8664 				BTEqualStrategyNumber, F_OIDEQ,
8665 				ObjectIdGetDatum(RelationGetRelid(rel)));
8666 	ScanKeyInit(&skey[1],
8667 				Anum_pg_constraint_contypid,
8668 				BTEqualStrategyNumber, F_OIDEQ,
8669 				ObjectIdGetDatum(InvalidOid));
8670 	ScanKeyInit(&skey[2],
8671 				Anum_pg_constraint_conname,
8672 				BTEqualStrategyNumber, F_NAMEEQ,
8673 				CStringGetDatum(constrName));
8674 	scan = systable_beginscan(conrel, ConstraintRelidTypidNameIndexId,
8675 							  true, NULL, 3, skey);
8676 
8677 	/* There can be at most one matching row */
8678 	if (!HeapTupleIsValid(tuple = systable_getnext(scan)))
8679 		ereport(ERROR,
8680 				(errcode(ERRCODE_UNDEFINED_OBJECT),
8681 				 errmsg("constraint \"%s\" of relation \"%s\" does not exist",
8682 						constrName, RelationGetRelationName(rel))));
8683 
8684 	con = (Form_pg_constraint) GETSTRUCT(tuple);
8685 	if (con->contype != CONSTRAINT_FOREIGN &&
8686 		con->contype != CONSTRAINT_CHECK)
8687 		ereport(ERROR,
8688 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
8689 				 errmsg("constraint \"%s\" of relation \"%s\" is not a foreign key or check constraint",
8690 						constrName, RelationGetRelationName(rel))));
8691 
8692 	if (!con->convalidated)
8693 	{
8694 		AlteredTableInfo *tab;
8695 		HeapTuple	copyTuple;
8696 		Form_pg_constraint copy_con;
8697 
8698 		if (con->contype == CONSTRAINT_FOREIGN)
8699 		{
8700 			NewConstraint *newcon;
8701 			Constraint *fkconstraint;
8702 
8703 			/* Queue validation for phase 3 */
8704 			fkconstraint = makeNode(Constraint);
8705 			/* for now this is all we need */
8706 			fkconstraint->conname = constrName;
8707 
8708 			newcon = (NewConstraint *) palloc0(sizeof(NewConstraint));
8709 			newcon->name = constrName;
8710 			newcon->contype = CONSTR_FOREIGN;
8711 			newcon->refrelid = con->confrelid;
8712 			newcon->refindid = con->conindid;
8713 			newcon->conid = HeapTupleGetOid(tuple);
8714 			newcon->qual = (Node *) fkconstraint;
8715 
8716 			/* Find or create work queue entry for this table */
8717 			tab = ATGetQueueEntry(wqueue, rel);
8718 			tab->constraints = lappend(tab->constraints, newcon);
8719 
8720 			/*
8721 			 * We disallow creating invalid foreign keys to or from
8722 			 * partitioned tables, so ignoring the recursion bit is okay.
8723 			 */
8724 		}
8725 		else if (con->contype == CONSTRAINT_CHECK)
8726 		{
8727 			List	   *children = NIL;
8728 			ListCell   *child;
8729 			NewConstraint *newcon;
8730 			bool		isnull;
8731 			Datum		val;
8732 			char	   *conbin;
8733 
8734 			/*
8735 			 * If we're recursing, the parent has already done this, so skip
8736 			 * it.  Also, if the constraint is a NO INHERIT constraint, we
8737 			 * shouldn't try to look for it in the children.
8738 			 */
8739 			if (!recursing && !con->connoinherit)
8740 				children = find_all_inheritors(RelationGetRelid(rel),
8741 											   lockmode, NULL);
8742 
8743 			/*
8744 			 * For CHECK constraints, we must ensure that we only mark the
8745 			 * constraint as validated on the parent if it's already validated
8746 			 * on the children.
8747 			 *
8748 			 * We recurse before validating on the parent, to reduce risk of
8749 			 * deadlocks.
8750 			 */
8751 			foreach(child, children)
8752 			{
8753 				Oid			childoid = lfirst_oid(child);
8754 				Relation	childrel;
8755 
8756 				if (childoid == RelationGetRelid(rel))
8757 					continue;
8758 
8759 				/*
8760 				 * If we are told not to recurse, there had better not be any
8761 				 * child tables, because we can't mark the constraint on the
8762 				 * parent valid unless it is valid for all child tables.
8763 				 */
8764 				if (!recurse)
8765 					ereport(ERROR,
8766 							(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
8767 							 errmsg("constraint must be validated on child tables too")));
8768 
8769 				/* find_all_inheritors already got lock */
8770 				childrel = heap_open(childoid, NoLock);
8771 
8772 				ATExecValidateConstraint(wqueue, childrel, constrName, false,
8773 										 true, lockmode);
8774 				heap_close(childrel, NoLock);
8775 			}
8776 
8777 			/* Queue validation for phase 3 */
8778 			newcon = (NewConstraint *) palloc0(sizeof(NewConstraint));
8779 			newcon->name = constrName;
8780 			newcon->contype = CONSTR_CHECK;
8781 			newcon->refrelid = InvalidOid;
8782 			newcon->refindid = InvalidOid;
8783 			newcon->conid = HeapTupleGetOid(tuple);
8784 
8785 			val = SysCacheGetAttr(CONSTROID, tuple,
8786 									Anum_pg_constraint_conbin, &isnull);
8787 			if (isnull)
8788 				elog(ERROR, "null conbin for constraint %u",
8789 					 HeapTupleGetOid(tuple));
8790 
8791 			conbin = TextDatumGetCString(val);
8792 			newcon->qual = (Node *) stringToNode(conbin);
8793 
8794 			/* Find or create work queue entry for this table */
8795 			tab = ATGetQueueEntry(wqueue, rel);
8796 			tab->constraints = lappend(tab->constraints, newcon);
8797 
8798 			/*
8799 			 * Invalidate relcache so that others see the new validated
8800 			 * constraint.
8801 			 */
8802 			CacheInvalidateRelcache(rel);
8803 		}
8804 
8805 		/*
8806 		 * Now update the catalog, while we have the door open.
8807 		 */
8808 		copyTuple = heap_copytuple(tuple);
8809 		copy_con = (Form_pg_constraint) GETSTRUCT(copyTuple);
8810 		copy_con->convalidated = true;
8811 		CatalogTupleUpdate(conrel, &copyTuple->t_self, copyTuple);
8812 
8813 		InvokeObjectPostAlterHook(ConstraintRelationId,
8814 								  HeapTupleGetOid(tuple), 0);
8815 
8816 		heap_freetuple(copyTuple);
8817 
8818 		ObjectAddressSet(address, ConstraintRelationId,
8819 						 HeapTupleGetOid(tuple));
8820 	}
8821 	else
8822 		address = InvalidObjectAddress; /* already validated */
8823 
8824 	systable_endscan(scan);
8825 
8826 	heap_close(conrel, RowExclusiveLock);
8827 
8828 	return address;
8829 }
8830 
8831 
8832 /*
8833  * transformColumnNameList - transform list of column names
8834  *
8835  * Lookup each name and return its attnum and type OID
8836  */
8837 static int
transformColumnNameList(Oid relId,List * colList,int16 * attnums,Oid * atttypids)8838 transformColumnNameList(Oid relId, List *colList,
8839 						int16 *attnums, Oid *atttypids)
8840 {
8841 	ListCell   *l;
8842 	int			attnum;
8843 
8844 	attnum = 0;
8845 	foreach(l, colList)
8846 	{
8847 		char	   *attname = strVal(lfirst(l));
8848 		HeapTuple	atttuple;
8849 
8850 		atttuple = SearchSysCacheAttName(relId, attname);
8851 		if (!HeapTupleIsValid(atttuple))
8852 			ereport(ERROR,
8853 					(errcode(ERRCODE_UNDEFINED_COLUMN),
8854 					 errmsg("column \"%s\" referenced in foreign key constraint does not exist",
8855 							attname)));
8856 		if (attnum >= INDEX_MAX_KEYS)
8857 			ereport(ERROR,
8858 					(errcode(ERRCODE_TOO_MANY_COLUMNS),
8859 					 errmsg("cannot have more than %d keys in a foreign key",
8860 							INDEX_MAX_KEYS)));
8861 		attnums[attnum] = ((Form_pg_attribute) GETSTRUCT(atttuple))->attnum;
8862 		atttypids[attnum] = ((Form_pg_attribute) GETSTRUCT(atttuple))->atttypid;
8863 		ReleaseSysCache(atttuple);
8864 		attnum++;
8865 	}
8866 
8867 	return attnum;
8868 }
8869 
8870 /*
8871  * transformFkeyGetPrimaryKey -
8872  *
8873  *	Look up the names, attnums, and types of the primary key attributes
8874  *	for the pkrel.  Also return the index OID and index opclasses of the
8875  *	index supporting the primary key.
8876  *
8877  *	All parameters except pkrel are output parameters.  Also, the function
8878  *	return value is the number of attributes in the primary key.
8879  *
8880  *	Used when the column list in the REFERENCES specification is omitted.
8881  */
8882 static int
transformFkeyGetPrimaryKey(Relation pkrel,Oid * indexOid,List ** attnamelist,int16 * attnums,Oid * atttypids,Oid * opclasses)8883 transformFkeyGetPrimaryKey(Relation pkrel, Oid *indexOid,
8884 						   List **attnamelist,
8885 						   int16 *attnums, Oid *atttypids,
8886 						   Oid *opclasses)
8887 {
8888 	List	   *indexoidlist;
8889 	ListCell   *indexoidscan;
8890 	HeapTuple	indexTuple = NULL;
8891 	Form_pg_index indexStruct = NULL;
8892 	Datum		indclassDatum;
8893 	bool		isnull;
8894 	oidvector  *indclass;
8895 	int			i;
8896 
8897 	/*
8898 	 * Get the list of index OIDs for the table from the relcache, and look up
8899 	 * each one in the pg_index syscache until we find one marked primary key
8900 	 * (hopefully there isn't more than one such).  Insist it's valid, too.
8901 	 */
8902 	*indexOid = InvalidOid;
8903 
8904 	indexoidlist = RelationGetIndexList(pkrel);
8905 
8906 	foreach(indexoidscan, indexoidlist)
8907 	{
8908 		Oid			indexoid = lfirst_oid(indexoidscan);
8909 
8910 		indexTuple = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(indexoid));
8911 		if (!HeapTupleIsValid(indexTuple))
8912 			elog(ERROR, "cache lookup failed for index %u", indexoid);
8913 		indexStruct = (Form_pg_index) GETSTRUCT(indexTuple);
8914 		if (indexStruct->indisprimary && IndexIsValid(indexStruct))
8915 		{
8916 			/*
8917 			 * Refuse to use a deferrable primary key.  This is per SQL spec,
8918 			 * and there would be a lot of interesting semantic problems if we
8919 			 * tried to allow it.
8920 			 */
8921 			if (!indexStruct->indimmediate)
8922 				ereport(ERROR,
8923 						(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
8924 						 errmsg("cannot use a deferrable primary key for referenced table \"%s\"",
8925 								RelationGetRelationName(pkrel))));
8926 
8927 			*indexOid = indexoid;
8928 			break;
8929 		}
8930 		ReleaseSysCache(indexTuple);
8931 	}
8932 
8933 	list_free(indexoidlist);
8934 
8935 	/*
8936 	 * Check that we found it
8937 	 */
8938 	if (!OidIsValid(*indexOid))
8939 		ereport(ERROR,
8940 				(errcode(ERRCODE_UNDEFINED_OBJECT),
8941 				 errmsg("there is no primary key for referenced table \"%s\"",
8942 						RelationGetRelationName(pkrel))));
8943 
8944 	/* Must get indclass the hard way */
8945 	indclassDatum = SysCacheGetAttr(INDEXRELID, indexTuple,
8946 									Anum_pg_index_indclass, &isnull);
8947 	Assert(!isnull);
8948 	indclass = (oidvector *) DatumGetPointer(indclassDatum);
8949 
8950 	/*
8951 	 * Now build the list of PK attributes from the indkey definition (we
8952 	 * assume a primary key cannot have expressional elements)
8953 	 */
8954 	*attnamelist = NIL;
8955 	for (i = 0; i < indexStruct->indnkeyatts; i++)
8956 	{
8957 		int			pkattno = indexStruct->indkey.values[i];
8958 
8959 		attnums[i] = pkattno;
8960 		atttypids[i] = attnumTypeId(pkrel, pkattno);
8961 		opclasses[i] = indclass->values[i];
8962 		*attnamelist = lappend(*attnamelist,
8963 							   makeString(pstrdup(NameStr(*attnumAttName(pkrel, pkattno)))));
8964 	}
8965 
8966 	ReleaseSysCache(indexTuple);
8967 
8968 	return i;
8969 }
8970 
8971 /*
8972  * transformFkeyCheckAttrs -
8973  *
8974  *	Make sure that the attributes of a referenced table belong to a unique
8975  *	(or primary key) constraint.  Return the OID of the index supporting
8976  *	the constraint, as well as the opclasses associated with the index
8977  *	columns.
8978  */
8979 static Oid
transformFkeyCheckAttrs(Relation pkrel,int numattrs,int16 * attnums,Oid * opclasses)8980 transformFkeyCheckAttrs(Relation pkrel,
8981 						int numattrs, int16 *attnums,
8982 						Oid *opclasses) /* output parameter */
8983 {
8984 	Oid			indexoid = InvalidOid;
8985 	bool		found = false;
8986 	bool		found_deferrable = false;
8987 	List	   *indexoidlist;
8988 	ListCell   *indexoidscan;
8989 	int			i,
8990 				j;
8991 
8992 	/*
8993 	 * Reject duplicate appearances of columns in the referenced-columns list.
8994 	 * Such a case is forbidden by the SQL standard, and even if we thought it
8995 	 * useful to allow it, there would be ambiguity about how to match the
8996 	 * list to unique indexes (in particular, it'd be unclear which index
8997 	 * opclass goes with which FK column).
8998 	 */
8999 	for (i = 0; i < numattrs; i++)
9000 	{
9001 		for (j = i + 1; j < numattrs; j++)
9002 		{
9003 			if (attnums[i] == attnums[j])
9004 				ereport(ERROR,
9005 						(errcode(ERRCODE_INVALID_FOREIGN_KEY),
9006 						 errmsg("foreign key referenced-columns list must not contain duplicates")));
9007 		}
9008 	}
9009 
9010 	/*
9011 	 * Get the list of index OIDs for the table from the relcache, and look up
9012 	 * each one in the pg_index syscache, and match unique indexes to the list
9013 	 * of attnums we are given.
9014 	 */
9015 	indexoidlist = RelationGetIndexList(pkrel);
9016 
9017 	foreach(indexoidscan, indexoidlist)
9018 	{
9019 		HeapTuple	indexTuple;
9020 		Form_pg_index indexStruct;
9021 
9022 		indexoid = lfirst_oid(indexoidscan);
9023 		indexTuple = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(indexoid));
9024 		if (!HeapTupleIsValid(indexTuple))
9025 			elog(ERROR, "cache lookup failed for index %u", indexoid);
9026 		indexStruct = (Form_pg_index) GETSTRUCT(indexTuple);
9027 
9028 		/*
9029 		 * Must have the right number of columns; must be unique and not a
9030 		 * partial index; forget it if there are any expressions, too. Invalid
9031 		 * indexes are out as well.
9032 		 */
9033 		if (indexStruct->indnkeyatts == numattrs &&
9034 			indexStruct->indisunique &&
9035 			IndexIsValid(indexStruct) &&
9036 			heap_attisnull(indexTuple, Anum_pg_index_indpred, NULL) &&
9037 			heap_attisnull(indexTuple, Anum_pg_index_indexprs, NULL))
9038 		{
9039 			Datum		indclassDatum;
9040 			bool		isnull;
9041 			oidvector  *indclass;
9042 
9043 			/* Must get indclass the hard way */
9044 			indclassDatum = SysCacheGetAttr(INDEXRELID, indexTuple,
9045 											Anum_pg_index_indclass, &isnull);
9046 			Assert(!isnull);
9047 			indclass = (oidvector *) DatumGetPointer(indclassDatum);
9048 
9049 			/*
9050 			 * The given attnum list may match the index columns in any order.
9051 			 * Check for a match, and extract the appropriate opclasses while
9052 			 * we're at it.
9053 			 *
9054 			 * We know that attnums[] is duplicate-free per the test at the
9055 			 * start of this function, and we checked above that the number of
9056 			 * index columns agrees, so if we find a match for each attnums[]
9057 			 * entry then we must have a one-to-one match in some order.
9058 			 */
9059 			for (i = 0; i < numattrs; i++)
9060 			{
9061 				found = false;
9062 				for (j = 0; j < numattrs; j++)
9063 				{
9064 					if (attnums[i] == indexStruct->indkey.values[j])
9065 					{
9066 						opclasses[i] = indclass->values[j];
9067 						found = true;
9068 						break;
9069 					}
9070 				}
9071 				if (!found)
9072 					break;
9073 			}
9074 
9075 			/*
9076 			 * Refuse to use a deferrable unique/primary key.  This is per SQL
9077 			 * spec, and there would be a lot of interesting semantic problems
9078 			 * if we tried to allow it.
9079 			 */
9080 			if (found && !indexStruct->indimmediate)
9081 			{
9082 				/*
9083 				 * Remember that we found an otherwise matching index, so that
9084 				 * we can generate a more appropriate error message.
9085 				 */
9086 				found_deferrable = true;
9087 				found = false;
9088 			}
9089 		}
9090 		ReleaseSysCache(indexTuple);
9091 		if (found)
9092 			break;
9093 	}
9094 
9095 	if (!found)
9096 	{
9097 		if (found_deferrable)
9098 			ereport(ERROR,
9099 					(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
9100 					 errmsg("cannot use a deferrable unique constraint for referenced table \"%s\"",
9101 							RelationGetRelationName(pkrel))));
9102 		else
9103 			ereport(ERROR,
9104 					(errcode(ERRCODE_INVALID_FOREIGN_KEY),
9105 					 errmsg("there is no unique constraint matching given keys for referenced table \"%s\"",
9106 							RelationGetRelationName(pkrel))));
9107 	}
9108 
9109 	list_free(indexoidlist);
9110 
9111 	return indexoid;
9112 }
9113 
9114 /*
9115  * findFkeyCast -
9116  *
9117  *	Wrapper around find_coercion_pathway() for ATAddForeignKeyConstraint().
9118  *	Caller has equal regard for binary coercibility and for an exact match.
9119 */
9120 static CoercionPathType
findFkeyCast(Oid targetTypeId,Oid sourceTypeId,Oid * funcid)9121 findFkeyCast(Oid targetTypeId, Oid sourceTypeId, Oid *funcid)
9122 {
9123 	CoercionPathType ret;
9124 
9125 	if (targetTypeId == sourceTypeId)
9126 	{
9127 		ret = COERCION_PATH_RELABELTYPE;
9128 		*funcid = InvalidOid;
9129 	}
9130 	else
9131 	{
9132 		ret = find_coercion_pathway(targetTypeId, sourceTypeId,
9133 									COERCION_IMPLICIT, funcid);
9134 		if (ret == COERCION_PATH_NONE)
9135 			/* A previously-relied-upon cast is now gone. */
9136 			elog(ERROR, "could not find cast from %u to %u",
9137 				 sourceTypeId, targetTypeId);
9138 	}
9139 
9140 	return ret;
9141 }
9142 
9143 /*
9144  * Permissions checks on the referenced table for ADD FOREIGN KEY
9145  *
9146  * Note: we have already checked that the user owns the referencing table,
9147  * else we'd have failed much earlier; no additional checks are needed for it.
9148  */
9149 static void
checkFkeyPermissions(Relation rel,int16 * attnums,int natts)9150 checkFkeyPermissions(Relation rel, int16 *attnums, int natts)
9151 {
9152 	Oid			roleid = GetUserId();
9153 	AclResult	aclresult;
9154 	int			i;
9155 
9156 	/* Okay if we have relation-level REFERENCES permission */
9157 	aclresult = pg_class_aclcheck(RelationGetRelid(rel), roleid,
9158 								  ACL_REFERENCES);
9159 	if (aclresult == ACLCHECK_OK)
9160 		return;
9161 	/* Else we must have REFERENCES on each column */
9162 	for (i = 0; i < natts; i++)
9163 	{
9164 		aclresult = pg_attribute_aclcheck(RelationGetRelid(rel), attnums[i],
9165 										  roleid, ACL_REFERENCES);
9166 		if (aclresult != ACLCHECK_OK)
9167 			aclcheck_error(aclresult, get_relkind_objtype(rel->rd_rel->relkind),
9168 						   RelationGetRelationName(rel));
9169 	}
9170 }
9171 
9172 /*
9173  * Scan the existing rows in a table to verify they meet a proposed FK
9174  * constraint.
9175  *
9176  * Caller must have opened and locked both relations appropriately.
9177  */
9178 static void
validateForeignKeyConstraint(char * conname,Relation rel,Relation pkrel,Oid pkindOid,Oid constraintOid)9179 validateForeignKeyConstraint(char *conname,
9180 							 Relation rel,
9181 							 Relation pkrel,
9182 							 Oid pkindOid,
9183 							 Oid constraintOid)
9184 {
9185 	HeapScanDesc scan;
9186 	HeapTuple	tuple;
9187 	Trigger		trig;
9188 	Snapshot	snapshot;
9189 
9190 	ereport(DEBUG1,
9191 			(errmsg("validating foreign key constraint \"%s\"", conname)));
9192 
9193 	/*
9194 	 * Build a trigger call structure; we'll need it either way.
9195 	 */
9196 	MemSet(&trig, 0, sizeof(trig));
9197 	trig.tgoid = InvalidOid;
9198 	trig.tgname = conname;
9199 	trig.tgenabled = TRIGGER_FIRES_ON_ORIGIN;
9200 	trig.tgisinternal = true;
9201 	trig.tgconstrrelid = RelationGetRelid(pkrel);
9202 	trig.tgconstrindid = pkindOid;
9203 	trig.tgconstraint = constraintOid;
9204 	trig.tgdeferrable = false;
9205 	trig.tginitdeferred = false;
9206 	/* we needn't fill in remaining fields */
9207 
9208 	/*
9209 	 * See if we can do it with a single LEFT JOIN query.  A false result
9210 	 * indicates we must proceed with the fire-the-trigger method.
9211 	 */
9212 	if (RI_Initial_Check(&trig, rel, pkrel))
9213 		return;
9214 
9215 	/*
9216 	 * Scan through each tuple, calling RI_FKey_check_ins (insert trigger) as
9217 	 * if that tuple had just been inserted.  If any of those fail, it should
9218 	 * ereport(ERROR) and that's that.
9219 	 */
9220 	snapshot = RegisterSnapshot(GetLatestSnapshot());
9221 	scan = heap_beginscan(rel, snapshot, 0, NULL);
9222 
9223 	while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
9224 	{
9225 		FunctionCallInfoData fcinfo;
9226 		TriggerData trigdata;
9227 
9228 		/*
9229 		 * Make a call to the trigger function
9230 		 *
9231 		 * No parameters are passed, but we do set a context
9232 		 */
9233 		MemSet(&fcinfo, 0, sizeof(fcinfo));
9234 
9235 		/*
9236 		 * We assume RI_FKey_check_ins won't look at flinfo...
9237 		 */
9238 		trigdata.type = T_TriggerData;
9239 		trigdata.tg_event = TRIGGER_EVENT_INSERT | TRIGGER_EVENT_ROW;
9240 		trigdata.tg_relation = rel;
9241 		trigdata.tg_trigtuple = tuple;
9242 		trigdata.tg_newtuple = NULL;
9243 		trigdata.tg_trigger = &trig;
9244 		trigdata.tg_trigtuplebuf = scan->rs_cbuf;
9245 		trigdata.tg_newtuplebuf = InvalidBuffer;
9246 
9247 		fcinfo.context = (Node *) &trigdata;
9248 
9249 		RI_FKey_check_ins(&fcinfo);
9250 	}
9251 
9252 	heap_endscan(scan);
9253 	UnregisterSnapshot(snapshot);
9254 }
9255 
9256 static void
CreateFKCheckTrigger(Oid myRelOid,Oid refRelOid,Constraint * fkconstraint,Oid constraintOid,Oid indexOid,bool on_insert)9257 CreateFKCheckTrigger(Oid myRelOid, Oid refRelOid, Constraint *fkconstraint,
9258 					 Oid constraintOid, Oid indexOid, bool on_insert)
9259 {
9260 	CreateTrigStmt *fk_trigger;
9261 
9262 	/*
9263 	 * Note: for a self-referential FK (referencing and referenced tables are
9264 	 * the same), it is important that the ON UPDATE action fires before the
9265 	 * CHECK action, since both triggers will fire on the same row during an
9266 	 * UPDATE event; otherwise the CHECK trigger will be checking a non-final
9267 	 * state of the row.  Triggers fire in name order, so we ensure this by
9268 	 * using names like "RI_ConstraintTrigger_a_NNNN" for the action triggers
9269 	 * and "RI_ConstraintTrigger_c_NNNN" for the check triggers.
9270 	 */
9271 	fk_trigger = makeNode(CreateTrigStmt);
9272 	fk_trigger->trigname = "RI_ConstraintTrigger_c";
9273 	fk_trigger->relation = NULL;
9274 	fk_trigger->row = true;
9275 	fk_trigger->timing = TRIGGER_TYPE_AFTER;
9276 
9277 	/* Either ON INSERT or ON UPDATE */
9278 	if (on_insert)
9279 	{
9280 		fk_trigger->funcname = SystemFuncName("RI_FKey_check_ins");
9281 		fk_trigger->events = TRIGGER_TYPE_INSERT;
9282 	}
9283 	else
9284 	{
9285 		fk_trigger->funcname = SystemFuncName("RI_FKey_check_upd");
9286 		fk_trigger->events = TRIGGER_TYPE_UPDATE;
9287 	}
9288 
9289 	fk_trigger->columns = NIL;
9290 	fk_trigger->transitionRels = NIL;
9291 	fk_trigger->whenClause = NULL;
9292 	fk_trigger->isconstraint = true;
9293 	fk_trigger->deferrable = fkconstraint->deferrable;
9294 	fk_trigger->initdeferred = fkconstraint->initdeferred;
9295 	fk_trigger->constrrel = NULL;
9296 	fk_trigger->args = NIL;
9297 
9298 	(void) CreateTrigger(fk_trigger, NULL, myRelOid, refRelOid, constraintOid,
9299 						 indexOid, InvalidOid, InvalidOid, NULL, true, false);
9300 
9301 	/* Make changes-so-far visible */
9302 	CommandCounterIncrement();
9303 }
9304 
9305 /*
9306  * createForeignKeyActionTriggers
9307  *		Create the referenced-side "action" triggers that implement a foreign
9308  *		key.
9309  */
9310 static void
createForeignKeyActionTriggers(Relation rel,Oid refRelOid,Constraint * fkconstraint,Oid constraintOid,Oid indexOid)9311 createForeignKeyActionTriggers(Relation rel, Oid refRelOid, Constraint *fkconstraint,
9312 							   Oid constraintOid, Oid indexOid)
9313 {
9314 	CreateTrigStmt *fk_trigger;
9315 
9316 	/*
9317 	 * Build and execute a CREATE CONSTRAINT TRIGGER statement for the ON
9318 	 * DELETE action on the referenced table.
9319 	 */
9320 	fk_trigger = makeNode(CreateTrigStmt);
9321 	fk_trigger->trigname = "RI_ConstraintTrigger_a";
9322 	fk_trigger->relation = NULL;
9323 	fk_trigger->row = true;
9324 	fk_trigger->timing = TRIGGER_TYPE_AFTER;
9325 	fk_trigger->events = TRIGGER_TYPE_DELETE;
9326 	fk_trigger->columns = NIL;
9327 	fk_trigger->transitionRels = NIL;
9328 	fk_trigger->whenClause = NULL;
9329 	fk_trigger->isconstraint = true;
9330 	fk_trigger->constrrel = NULL;
9331 	switch (fkconstraint->fk_del_action)
9332 	{
9333 		case FKCONSTR_ACTION_NOACTION:
9334 			fk_trigger->deferrable = fkconstraint->deferrable;
9335 			fk_trigger->initdeferred = fkconstraint->initdeferred;
9336 			fk_trigger->funcname = SystemFuncName("RI_FKey_noaction_del");
9337 			break;
9338 		case FKCONSTR_ACTION_RESTRICT:
9339 			fk_trigger->deferrable = false;
9340 			fk_trigger->initdeferred = false;
9341 			fk_trigger->funcname = SystemFuncName("RI_FKey_restrict_del");
9342 			break;
9343 		case FKCONSTR_ACTION_CASCADE:
9344 			fk_trigger->deferrable = false;
9345 			fk_trigger->initdeferred = false;
9346 			fk_trigger->funcname = SystemFuncName("RI_FKey_cascade_del");
9347 			break;
9348 		case FKCONSTR_ACTION_SETNULL:
9349 			fk_trigger->deferrable = false;
9350 			fk_trigger->initdeferred = false;
9351 			fk_trigger->funcname = SystemFuncName("RI_FKey_setnull_del");
9352 			break;
9353 		case FKCONSTR_ACTION_SETDEFAULT:
9354 			fk_trigger->deferrable = false;
9355 			fk_trigger->initdeferred = false;
9356 			fk_trigger->funcname = SystemFuncName("RI_FKey_setdefault_del");
9357 			break;
9358 		default:
9359 			elog(ERROR, "unrecognized FK action type: %d",
9360 				 (int) fkconstraint->fk_del_action);
9361 			break;
9362 	}
9363 	fk_trigger->args = NIL;
9364 
9365 	(void) CreateTrigger(fk_trigger, NULL, refRelOid, RelationGetRelid(rel),
9366 						 constraintOid,
9367 						 indexOid, InvalidOid, InvalidOid, NULL, true, false);
9368 
9369 	/* Make changes-so-far visible */
9370 	CommandCounterIncrement();
9371 
9372 	/*
9373 	 * Build and execute a CREATE CONSTRAINT TRIGGER statement for the ON
9374 	 * UPDATE action on the referenced table.
9375 	 */
9376 	fk_trigger = makeNode(CreateTrigStmt);
9377 	fk_trigger->trigname = "RI_ConstraintTrigger_a";
9378 	fk_trigger->relation = NULL;
9379 	fk_trigger->row = true;
9380 	fk_trigger->timing = TRIGGER_TYPE_AFTER;
9381 	fk_trigger->events = TRIGGER_TYPE_UPDATE;
9382 	fk_trigger->columns = NIL;
9383 	fk_trigger->transitionRels = NIL;
9384 	fk_trigger->whenClause = NULL;
9385 	fk_trigger->isconstraint = true;
9386 	fk_trigger->constrrel = NULL;
9387 	switch (fkconstraint->fk_upd_action)
9388 	{
9389 		case FKCONSTR_ACTION_NOACTION:
9390 			fk_trigger->deferrable = fkconstraint->deferrable;
9391 			fk_trigger->initdeferred = fkconstraint->initdeferred;
9392 			fk_trigger->funcname = SystemFuncName("RI_FKey_noaction_upd");
9393 			break;
9394 		case FKCONSTR_ACTION_RESTRICT:
9395 			fk_trigger->deferrable = false;
9396 			fk_trigger->initdeferred = false;
9397 			fk_trigger->funcname = SystemFuncName("RI_FKey_restrict_upd");
9398 			break;
9399 		case FKCONSTR_ACTION_CASCADE:
9400 			fk_trigger->deferrable = false;
9401 			fk_trigger->initdeferred = false;
9402 			fk_trigger->funcname = SystemFuncName("RI_FKey_cascade_upd");
9403 			break;
9404 		case FKCONSTR_ACTION_SETNULL:
9405 			fk_trigger->deferrable = false;
9406 			fk_trigger->initdeferred = false;
9407 			fk_trigger->funcname = SystemFuncName("RI_FKey_setnull_upd");
9408 			break;
9409 		case FKCONSTR_ACTION_SETDEFAULT:
9410 			fk_trigger->deferrable = false;
9411 			fk_trigger->initdeferred = false;
9412 			fk_trigger->funcname = SystemFuncName("RI_FKey_setdefault_upd");
9413 			break;
9414 		default:
9415 			elog(ERROR, "unrecognized FK action type: %d",
9416 				 (int) fkconstraint->fk_upd_action);
9417 			break;
9418 	}
9419 	fk_trigger->args = NIL;
9420 
9421 	(void) CreateTrigger(fk_trigger, NULL, refRelOid, RelationGetRelid(rel),
9422 						 constraintOid,
9423 						 indexOid, InvalidOid, InvalidOid, NULL, true, false);
9424 }
9425 
9426 /*
9427  * createForeignKeyCheckTriggers
9428  *		Create the referencing-side "check" triggers that implement a foreign
9429  *		key.
9430  */
9431 static void
createForeignKeyCheckTriggers(Oid myRelOid,Oid refRelOid,Constraint * fkconstraint,Oid constraintOid,Oid indexOid)9432 createForeignKeyCheckTriggers(Oid myRelOid, Oid refRelOid,
9433 							  Constraint *fkconstraint, Oid constraintOid,
9434 							  Oid indexOid)
9435 {
9436 	CreateFKCheckTrigger(myRelOid, refRelOid, fkconstraint, constraintOid,
9437 						 indexOid, true);
9438 	CreateFKCheckTrigger(myRelOid, refRelOid, fkconstraint, constraintOid,
9439 						 indexOid, false);
9440 }
9441 
9442 /*
9443  * Create the triggers that implement an FK constraint.
9444  *
9445  * NB: if you change any trigger properties here, see also
9446  * ATExecAlterConstraint.
9447  */
9448 void
createForeignKeyTriggers(Relation rel,Oid refRelOid,Constraint * fkconstraint,Oid constraintOid,Oid indexOid,bool create_action)9449 createForeignKeyTriggers(Relation rel, Oid refRelOid, Constraint *fkconstraint,
9450 						 Oid constraintOid, Oid indexOid, bool create_action)
9451 {
9452 	/*
9453 	 * For the referenced side, create action triggers, if requested.  (If the
9454 	 * referencing side is partitioned, there is still only one trigger, which
9455 	 * runs on the referenced side and points to the top of the referencing
9456 	 * hierarchy.)
9457 	 */
9458 	if (create_action)
9459 		createForeignKeyActionTriggers(rel, refRelOid, fkconstraint, constraintOid,
9460 									   indexOid);
9461 
9462 	/*
9463 	 * For the referencing side, create the check triggers.  We only need
9464 	 * these on the partitions.
9465 	 */
9466 	if (rel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
9467 		createForeignKeyCheckTriggers(RelationGetRelid(rel), refRelOid,
9468 									  fkconstraint, constraintOid, indexOid);
9469 
9470 	CommandCounterIncrement();
9471 }
9472 
9473 /*
9474  * ALTER TABLE DROP CONSTRAINT
9475  *
9476  * Like DROP COLUMN, we can't use the normal ALTER TABLE recursion mechanism.
9477  */
9478 static void
ATExecDropConstraint(Relation rel,const char * constrName,DropBehavior behavior,bool recurse,bool recursing,bool missing_ok,LOCKMODE lockmode)9479 ATExecDropConstraint(Relation rel, const char *constrName,
9480 					 DropBehavior behavior,
9481 					 bool recurse, bool recursing,
9482 					 bool missing_ok, LOCKMODE lockmode)
9483 {
9484 	List	   *children;
9485 	ListCell   *child;
9486 	Relation	conrel;
9487 	Form_pg_constraint con;
9488 	SysScanDesc scan;
9489 	ScanKeyData skey[3];
9490 	HeapTuple	tuple;
9491 	bool		found = false;
9492 	bool		is_no_inherit_constraint = false;
9493 	char		contype;
9494 
9495 	/* At top level, permission check was done in ATPrepCmd, else do it */
9496 	if (recursing)
9497 		ATSimplePermissions(rel, ATT_TABLE | ATT_FOREIGN_TABLE);
9498 
9499 	conrel = heap_open(ConstraintRelationId, RowExclusiveLock);
9500 
9501 	/*
9502 	 * Find and drop the target constraint
9503 	 */
9504 	ScanKeyInit(&skey[0],
9505 				Anum_pg_constraint_conrelid,
9506 				BTEqualStrategyNumber, F_OIDEQ,
9507 				ObjectIdGetDatum(RelationGetRelid(rel)));
9508 	ScanKeyInit(&skey[1],
9509 				Anum_pg_constraint_contypid,
9510 				BTEqualStrategyNumber, F_OIDEQ,
9511 				ObjectIdGetDatum(InvalidOid));
9512 	ScanKeyInit(&skey[2],
9513 				Anum_pg_constraint_conname,
9514 				BTEqualStrategyNumber, F_NAMEEQ,
9515 				CStringGetDatum(constrName));
9516 	scan = systable_beginscan(conrel, ConstraintRelidTypidNameIndexId,
9517 							  true, NULL, 3, skey);
9518 
9519 	/* There can be at most one matching row */
9520 	if (HeapTupleIsValid(tuple = systable_getnext(scan)))
9521 	{
9522 		ObjectAddress conobj;
9523 
9524 		con = (Form_pg_constraint) GETSTRUCT(tuple);
9525 
9526 		/* Don't drop inherited constraints */
9527 		if (con->coninhcount > 0 && !recursing)
9528 			ereport(ERROR,
9529 					(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
9530 					 errmsg("cannot drop inherited constraint \"%s\" of relation \"%s\"",
9531 							constrName, RelationGetRelationName(rel))));
9532 
9533 		is_no_inherit_constraint = con->connoinherit;
9534 		contype = con->contype;
9535 
9536 		/*
9537 		 * If it's a foreign-key constraint, we'd better lock the referenced
9538 		 * table and check that that's not in use, just as we've already done
9539 		 * for the constrained table (else we might, eg, be dropping a trigger
9540 		 * that has unfired events).  But we can/must skip that in the
9541 		 * self-referential case.
9542 		 */
9543 		if (contype == CONSTRAINT_FOREIGN &&
9544 			con->confrelid != RelationGetRelid(rel))
9545 		{
9546 			Relation	frel;
9547 
9548 			/* Must match lock taken by RemoveTriggerById: */
9549 			frel = heap_open(con->confrelid, AccessExclusiveLock);
9550 			CheckTableNotInUse(frel, "ALTER TABLE");
9551 			heap_close(frel, NoLock);
9552 		}
9553 
9554 		/*
9555 		 * Perform the actual constraint deletion
9556 		 */
9557 		conobj.classId = ConstraintRelationId;
9558 		conobj.objectId = HeapTupleGetOid(tuple);
9559 		conobj.objectSubId = 0;
9560 
9561 		performDeletion(&conobj, behavior, 0);
9562 
9563 		found = true;
9564 	}
9565 
9566 	systable_endscan(scan);
9567 
9568 	if (!found)
9569 	{
9570 		if (!missing_ok)
9571 		{
9572 			ereport(ERROR,
9573 					(errcode(ERRCODE_UNDEFINED_OBJECT),
9574 					 errmsg("constraint \"%s\" of relation \"%s\" does not exist",
9575 							constrName, RelationGetRelationName(rel))));
9576 		}
9577 		else
9578 		{
9579 			ereport(NOTICE,
9580 					(errmsg("constraint \"%s\" of relation \"%s\" does not exist, skipping",
9581 							constrName, RelationGetRelationName(rel))));
9582 			heap_close(conrel, RowExclusiveLock);
9583 			return;
9584 		}
9585 	}
9586 
9587 	/*
9588 	 * For partitioned tables, non-CHECK inherited constraints are dropped via
9589 	 * the dependency mechanism, so we're done here.
9590 	 */
9591 	if (contype != CONSTRAINT_CHECK &&
9592 		rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
9593 	{
9594 		heap_close(conrel, RowExclusiveLock);
9595 		return;
9596 	}
9597 
9598 	/*
9599 	 * Propagate to children as appropriate.  Unlike most other ALTER
9600 	 * routines, we have to do this one level of recursion at a time; we can't
9601 	 * use find_all_inheritors to do it in one pass.
9602 	 */
9603 	if (!is_no_inherit_constraint)
9604 		children = find_inheritance_children(RelationGetRelid(rel), lockmode);
9605 	else
9606 		children = NIL;
9607 
9608 	/*
9609 	 * For a partitioned table, if partitions exist and we are told not to
9610 	 * recurse, it's a user error.  It doesn't make sense to have a constraint
9611 	 * be defined only on the parent, especially if it's a partitioned table.
9612 	 */
9613 	if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE &&
9614 		children != NIL && !recurse)
9615 		ereport(ERROR,
9616 				(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
9617 				 errmsg("cannot remove constraint from only the partitioned table when partitions exist"),
9618 				 errhint("Do not specify the ONLY keyword.")));
9619 
9620 	foreach(child, children)
9621 	{
9622 		Oid			childrelid = lfirst_oid(child);
9623 		Relation	childrel;
9624 		HeapTuple	copy_tuple;
9625 
9626 		/* find_inheritance_children already got lock */
9627 		childrel = heap_open(childrelid, NoLock);
9628 		CheckTableNotInUse(childrel, "ALTER TABLE");
9629 
9630 		ScanKeyInit(&skey[0],
9631 					Anum_pg_constraint_conrelid,
9632 					BTEqualStrategyNumber, F_OIDEQ,
9633 					ObjectIdGetDatum(childrelid));
9634 		ScanKeyInit(&skey[1],
9635 					Anum_pg_constraint_contypid,
9636 					BTEqualStrategyNumber, F_OIDEQ,
9637 					ObjectIdGetDatum(InvalidOid));
9638 		ScanKeyInit(&skey[2],
9639 					Anum_pg_constraint_conname,
9640 					BTEqualStrategyNumber, F_NAMEEQ,
9641 					CStringGetDatum(constrName));
9642 		scan = systable_beginscan(conrel, ConstraintRelidTypidNameIndexId,
9643 								  true, NULL, 3, skey);
9644 
9645 		/* There can be at most one matching row */
9646 		if (!HeapTupleIsValid(tuple = systable_getnext(scan)))
9647 			ereport(ERROR,
9648 					(errcode(ERRCODE_UNDEFINED_OBJECT),
9649 					 errmsg("constraint \"%s\" of relation \"%s\" does not exist",
9650 							constrName,
9651 							RelationGetRelationName(childrel))));
9652 
9653 		copy_tuple = heap_copytuple(tuple);
9654 
9655 		systable_endscan(scan);
9656 
9657 		con = (Form_pg_constraint) GETSTRUCT(copy_tuple);
9658 
9659 		/* Right now only CHECK constraints can be inherited */
9660 		if (con->contype != CONSTRAINT_CHECK)
9661 			elog(ERROR, "inherited constraint is not a CHECK constraint");
9662 
9663 		if (con->coninhcount <= 0)	/* shouldn't happen */
9664 			elog(ERROR, "relation %u has non-inherited constraint \"%s\"",
9665 				 childrelid, constrName);
9666 
9667 		if (recurse)
9668 		{
9669 			/*
9670 			 * If the child constraint has other definition sources, just
9671 			 * decrement its inheritance count; if not, recurse to delete it.
9672 			 */
9673 			if (con->coninhcount == 1 && !con->conislocal)
9674 			{
9675 				/* Time to delete this child constraint, too */
9676 				ATExecDropConstraint(childrel, constrName, behavior,
9677 									 true, true,
9678 									 false, lockmode);
9679 			}
9680 			else
9681 			{
9682 				/* Child constraint must survive my deletion */
9683 				con->coninhcount--;
9684 				CatalogTupleUpdate(conrel, &copy_tuple->t_self, copy_tuple);
9685 
9686 				/* Make update visible */
9687 				CommandCounterIncrement();
9688 			}
9689 		}
9690 		else
9691 		{
9692 			/*
9693 			 * If we were told to drop ONLY in this table (no recursion), we
9694 			 * need to mark the inheritors' constraints as locally defined
9695 			 * rather than inherited.
9696 			 */
9697 			con->coninhcount--;
9698 			con->conislocal = true;
9699 
9700 			CatalogTupleUpdate(conrel, &copy_tuple->t_self, copy_tuple);
9701 
9702 			/* Make update visible */
9703 			CommandCounterIncrement();
9704 		}
9705 
9706 		heap_freetuple(copy_tuple);
9707 
9708 		heap_close(childrel, NoLock);
9709 	}
9710 
9711 	heap_close(conrel, RowExclusiveLock);
9712 }
9713 
9714 /*
9715  * ALTER COLUMN TYPE
9716  */
9717 static void
ATPrepAlterColumnType(List ** wqueue,AlteredTableInfo * tab,Relation rel,bool recurse,bool recursing,AlterTableCmd * cmd,LOCKMODE lockmode)9718 ATPrepAlterColumnType(List **wqueue,
9719 					  AlteredTableInfo *tab, Relation rel,
9720 					  bool recurse, bool recursing,
9721 					  AlterTableCmd *cmd, LOCKMODE lockmode)
9722 {
9723 	char	   *colName = cmd->name;
9724 	ColumnDef  *def = (ColumnDef *) cmd->def;
9725 	TypeName   *typeName = def->typeName;
9726 	Node	   *transform = def->cooked_default;
9727 	HeapTuple	tuple;
9728 	Form_pg_attribute attTup;
9729 	AttrNumber	attnum;
9730 	Oid			targettype;
9731 	int32		targettypmod;
9732 	Oid			targetcollid;
9733 	NewColumnValue *newval;
9734 	ParseState *pstate = make_parsestate(NULL);
9735 	AclResult	aclresult;
9736 	bool		is_expr;
9737 
9738 	if (rel->rd_rel->reloftype && !recursing)
9739 		ereport(ERROR,
9740 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
9741 				 errmsg("cannot alter column type of typed table")));
9742 
9743 	/* lookup the attribute so we can check inheritance status */
9744 	tuple = SearchSysCacheAttName(RelationGetRelid(rel), colName);
9745 	if (!HeapTupleIsValid(tuple))
9746 		ereport(ERROR,
9747 				(errcode(ERRCODE_UNDEFINED_COLUMN),
9748 				 errmsg("column \"%s\" of relation \"%s\" does not exist",
9749 						colName, RelationGetRelationName(rel))));
9750 	attTup = (Form_pg_attribute) GETSTRUCT(tuple);
9751 	attnum = attTup->attnum;
9752 
9753 	/* Can't alter a system attribute */
9754 	if (attnum <= 0)
9755 		ereport(ERROR,
9756 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
9757 				 errmsg("cannot alter system column \"%s\"",
9758 						colName)));
9759 
9760 	/*
9761 	 * Don't alter inherited columns.  At outer level, there had better not be
9762 	 * any inherited definition; when recursing, we assume this was checked at
9763 	 * the parent level (see below).
9764 	 */
9765 	if (attTup->attinhcount > 0 && !recursing)
9766 		ereport(ERROR,
9767 				(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
9768 				 errmsg("cannot alter inherited column \"%s\"",
9769 						colName)));
9770 
9771 	/* Don't alter columns used in the partition key */
9772 	if (has_partition_attrs(rel,
9773 							bms_make_singleton(attnum - FirstLowInvalidHeapAttributeNumber),
9774 							&is_expr))
9775 		ereport(ERROR,
9776 				(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
9777 				 errmsg("cannot alter column \"%s\" because it is part of the partition key of relation \"%s\"",
9778 						colName, RelationGetRelationName(rel))));
9779 
9780 	/* Look up the target type */
9781 	typenameTypeIdAndMod(NULL, typeName, &targettype, &targettypmod);
9782 
9783 	aclresult = pg_type_aclcheck(targettype, GetUserId(), ACL_USAGE);
9784 	if (aclresult != ACLCHECK_OK)
9785 		aclcheck_error_type(aclresult, targettype);
9786 
9787 	/* And the collation */
9788 	targetcollid = GetColumnDefCollation(NULL, def, targettype);
9789 
9790 	/* make sure datatype is legal for a column */
9791 	CheckAttributeType(colName, targettype, targetcollid,
9792 					   list_make1_oid(rel->rd_rel->reltype),
9793 					   false);
9794 
9795 	if (tab->relkind == RELKIND_RELATION ||
9796 		tab->relkind == RELKIND_PARTITIONED_TABLE)
9797 	{
9798 		/*
9799 		 * Set up an expression to transform the old data value to the new
9800 		 * type. If a USING option was given, use the expression as
9801 		 * transformed by transformAlterTableStmt, else just take the old
9802 		 * value and try to coerce it.  We do this first so that type
9803 		 * incompatibility can be detected before we waste effort, and because
9804 		 * we need the expression to be parsed against the original table row
9805 		 * type.
9806 		 */
9807 		if (!transform)
9808 		{
9809 			transform = (Node *) makeVar(1, attnum,
9810 										 attTup->atttypid, attTup->atttypmod,
9811 										 attTup->attcollation,
9812 										 0);
9813 		}
9814 
9815 		transform = coerce_to_target_type(pstate,
9816 										  transform, exprType(transform),
9817 										  targettype, targettypmod,
9818 										  COERCION_ASSIGNMENT,
9819 										  COERCE_IMPLICIT_CAST,
9820 										  -1);
9821 		if (transform == NULL)
9822 		{
9823 			/* error text depends on whether USING was specified or not */
9824 			if (def->cooked_default != NULL)
9825 				ereport(ERROR,
9826 						(errcode(ERRCODE_DATATYPE_MISMATCH),
9827 						 errmsg("result of USING clause for column \"%s\""
9828 								" cannot be cast automatically to type %s",
9829 								colName, format_type_be(targettype)),
9830 						 errhint("You might need to add an explicit cast.")));
9831 			else
9832 				ereport(ERROR,
9833 						(errcode(ERRCODE_DATATYPE_MISMATCH),
9834 						 errmsg("column \"%s\" cannot be cast automatically to type %s",
9835 								colName, format_type_be(targettype)),
9836 				/* translator: USING is SQL, don't translate it */
9837 						 errhint("You might need to specify \"USING %s::%s\".",
9838 								 quote_identifier(colName),
9839 								 format_type_with_typemod(targettype,
9840 														  targettypmod))));
9841 		}
9842 
9843 		/* Fix collations after all else */
9844 		assign_expr_collations(pstate, transform);
9845 
9846 		/* Plan the expr now so we can accurately assess the need to rewrite. */
9847 		transform = (Node *) expression_planner((Expr *) transform);
9848 
9849 		/*
9850 		 * Add a work queue item to make ATRewriteTable update the column
9851 		 * contents.
9852 		 */
9853 		newval = (NewColumnValue *) palloc0(sizeof(NewColumnValue));
9854 		newval->attnum = attnum;
9855 		newval->expr = (Expr *) transform;
9856 
9857 		tab->newvals = lappend(tab->newvals, newval);
9858 		if (ATColumnChangeRequiresRewrite(transform, attnum))
9859 			tab->rewrite |= AT_REWRITE_COLUMN_REWRITE;
9860 	}
9861 	else if (transform)
9862 		ereport(ERROR,
9863 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
9864 				 errmsg("\"%s\" is not a table",
9865 						RelationGetRelationName(rel))));
9866 
9867 	if (tab->relkind == RELKIND_COMPOSITE_TYPE ||
9868 		tab->relkind == RELKIND_FOREIGN_TABLE)
9869 	{
9870 		/*
9871 		 * For composite types, do this check now.  Tables will check it later
9872 		 * when the table is being rewritten.
9873 		 */
9874 		find_composite_type_dependencies(rel->rd_rel->reltype, rel, NULL);
9875 	}
9876 
9877 	ReleaseSysCache(tuple);
9878 
9879 	/*
9880 	 * Recurse manually by queueing a new command for each child, if
9881 	 * necessary. We cannot apply ATSimpleRecursion here because we need to
9882 	 * remap attribute numbers in the USING expression, if any.
9883 	 *
9884 	 * If we are told not to recurse, there had better not be any child
9885 	 * tables; else the alter would put them out of step.
9886 	 */
9887 	if (recurse)
9888 	{
9889 		Oid			relid = RelationGetRelid(rel);
9890 		List	   *child_oids,
9891 				   *child_numparents;
9892 		ListCell   *lo,
9893 				   *li;
9894 
9895 		child_oids = find_all_inheritors(relid, lockmode,
9896 										 &child_numparents);
9897 
9898 		/*
9899 		 * find_all_inheritors does the recursive search of the inheritance
9900 		 * hierarchy, so all we have to do is process all of the relids in the
9901 		 * list that it returns.
9902 		 */
9903 		forboth(lo, child_oids, li, child_numparents)
9904 		{
9905 			Oid			childrelid = lfirst_oid(lo);
9906 			int			numparents = lfirst_int(li);
9907 			Relation	childrel;
9908 			HeapTuple	childtuple;
9909 			Form_pg_attribute childattTup;
9910 
9911 			if (childrelid == relid)
9912 				continue;
9913 
9914 			/* find_all_inheritors already got lock */
9915 			childrel = relation_open(childrelid, NoLock);
9916 			CheckTableNotInUse(childrel, "ALTER TABLE");
9917 
9918 			/*
9919 			 * Verify that the child doesn't have any inherited definitions of
9920 			 * this column that came from outside this inheritance hierarchy.
9921 			 * (renameatt makes a similar test, though in a different way
9922 			 * because of its different recursion mechanism.)
9923 			 */
9924 			childtuple = SearchSysCacheAttName(RelationGetRelid(childrel),
9925 											   colName);
9926 			if (!HeapTupleIsValid(childtuple))
9927 				ereport(ERROR,
9928 						(errcode(ERRCODE_UNDEFINED_COLUMN),
9929 						 errmsg("column \"%s\" of relation \"%s\" does not exist",
9930 								colName, RelationGetRelationName(childrel))));
9931 			childattTup = (Form_pg_attribute) GETSTRUCT(childtuple);
9932 
9933 			if (childattTup->attinhcount > numparents)
9934 				ereport(ERROR,
9935 						(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
9936 						 errmsg("cannot alter inherited column \"%s\" of relation \"%s\"",
9937 								colName, RelationGetRelationName(childrel))));
9938 
9939 			ReleaseSysCache(childtuple);
9940 
9941 			/*
9942 			 * Remap the attribute numbers.  If no USING expression was
9943 			 * specified, there is no need for this step.
9944 			 */
9945 			if (def->cooked_default)
9946 			{
9947 				AttrNumber *attmap;
9948 				bool		found_whole_row;
9949 
9950 				/* create a copy to scribble on */
9951 				cmd = copyObject(cmd);
9952 
9953 				attmap = convert_tuples_by_name_map(RelationGetDescr(childrel),
9954 													RelationGetDescr(rel),
9955 													gettext_noop("could not convert row type"));
9956 				((ColumnDef *) cmd->def)->cooked_default =
9957 					map_variable_attnos(def->cooked_default,
9958 										1, 0,
9959 										attmap, RelationGetDescr(rel)->natts,
9960 										InvalidOid, &found_whole_row);
9961 				if (found_whole_row)
9962 					ereport(ERROR,
9963 							(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
9964 							 errmsg("cannot convert whole-row table reference"),
9965 							 errdetail("USING expression contains a whole-row table reference.")));
9966 				pfree(attmap);
9967 			}
9968 			ATPrepCmd(wqueue, childrel, cmd, false, true, lockmode);
9969 			relation_close(childrel, NoLock);
9970 		}
9971 	}
9972 	else if (!recursing &&
9973 			 find_inheritance_children(RelationGetRelid(rel), NoLock) != NIL)
9974 		ereport(ERROR,
9975 				(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
9976 				 errmsg("type of inherited column \"%s\" must be changed in child tables too",
9977 						colName)));
9978 
9979 	if (tab->relkind == RELKIND_COMPOSITE_TYPE)
9980 		ATTypedTableRecursion(wqueue, rel, cmd, lockmode);
9981 }
9982 
9983 /*
9984  * When the data type of a column is changed, a rewrite might not be required
9985  * if the new type is sufficiently identical to the old one, and the USING
9986  * clause isn't trying to insert some other value.  It's safe to skip the
9987  * rewrite if the old type is binary coercible to the new type, or if the
9988  * new type is an unconstrained domain over the old type.  In the case of a
9989  * constrained domain, we could get by with scanning the table and checking
9990  * the constraint rather than actually rewriting it, but we don't currently
9991  * try to do that.
9992  */
9993 static bool
ATColumnChangeRequiresRewrite(Node * expr,AttrNumber varattno)9994 ATColumnChangeRequiresRewrite(Node *expr, AttrNumber varattno)
9995 {
9996 	Assert(expr != NULL);
9997 
9998 	for (;;)
9999 	{
10000 		/* only one varno, so no need to check that */
10001 		if (IsA(expr, Var) &&((Var *) expr)->varattno == varattno)
10002 			return false;
10003 		else if (IsA(expr, RelabelType))
10004 			expr = (Node *) ((RelabelType *) expr)->arg;
10005 		else if (IsA(expr, CoerceToDomain))
10006 		{
10007 			CoerceToDomain *d = (CoerceToDomain *) expr;
10008 
10009 			if (DomainHasConstraints(d->resulttype))
10010 				return true;
10011 			expr = (Node *) d->arg;
10012 		}
10013 		else
10014 			return true;
10015 	}
10016 }
10017 
10018 /*
10019  * ALTER COLUMN .. SET DATA TYPE
10020  *
10021  * Return the address of the modified column.
10022  */
10023 static ObjectAddress
ATExecAlterColumnType(AlteredTableInfo * tab,Relation rel,AlterTableCmd * cmd,LOCKMODE lockmode)10024 ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel,
10025 					  AlterTableCmd *cmd, LOCKMODE lockmode)
10026 {
10027 	char	   *colName = cmd->name;
10028 	ColumnDef  *def = (ColumnDef *) cmd->def;
10029 	TypeName   *typeName = def->typeName;
10030 	HeapTuple	heapTup;
10031 	Form_pg_attribute attTup,
10032 				attOldTup;
10033 	AttrNumber	attnum;
10034 	HeapTuple	typeTuple;
10035 	Form_pg_type tform;
10036 	Oid			targettype;
10037 	int32		targettypmod;
10038 	Oid			targetcollid;
10039 	Node	   *defaultexpr;
10040 	Relation	attrelation;
10041 	Relation	depRel;
10042 	ScanKeyData key[3];
10043 	SysScanDesc scan;
10044 	HeapTuple	depTup;
10045 	ObjectAddress address;
10046 
10047 	/*
10048 	 * Clear all the missing values if we're rewriting the table, since this
10049 	 * renders them pointless.
10050 	 */
10051 	if (tab->rewrite)
10052 	{
10053 		Relation    newrel;
10054 
10055 		newrel = heap_open(RelationGetRelid(rel), NoLock);
10056 		RelationClearMissing(newrel);
10057 		relation_close(newrel, NoLock);
10058 		/* make sure we don't conflict with later attribute modifications */
10059 		CommandCounterIncrement();
10060 	}
10061 
10062 	attrelation = heap_open(AttributeRelationId, RowExclusiveLock);
10063 
10064 	/* Look up the target column */
10065 	heapTup = SearchSysCacheCopyAttName(RelationGetRelid(rel), colName);
10066 	if (!HeapTupleIsValid(heapTup)) /* shouldn't happen */
10067 		ereport(ERROR,
10068 				(errcode(ERRCODE_UNDEFINED_COLUMN),
10069 				 errmsg("column \"%s\" of relation \"%s\" does not exist",
10070 						colName, RelationGetRelationName(rel))));
10071 	attTup = (Form_pg_attribute) GETSTRUCT(heapTup);
10072 	attnum = attTup->attnum;
10073 	attOldTup = TupleDescAttr(tab->oldDesc, attnum - 1);
10074 
10075 	/* Check for multiple ALTER TYPE on same column --- can't cope */
10076 	if (attTup->atttypid != attOldTup->atttypid ||
10077 		attTup->atttypmod != attOldTup->atttypmod)
10078 		ereport(ERROR,
10079 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
10080 				 errmsg("cannot alter type of column \"%s\" twice",
10081 						colName)));
10082 
10083 	/* Look up the target type (should not fail, since prep found it) */
10084 	typeTuple = typenameType(NULL, typeName, &targettypmod);
10085 	tform = (Form_pg_type) GETSTRUCT(typeTuple);
10086 	targettype = HeapTupleGetOid(typeTuple);
10087 	/* And the collation */
10088 	targetcollid = GetColumnDefCollation(NULL, def, targettype);
10089 
10090 	/*
10091 	 * If there is a default expression for the column, get it and ensure we
10092 	 * can coerce it to the new datatype.  (We must do this before changing
10093 	 * the column type, because build_column_default itself will try to
10094 	 * coerce, and will not issue the error message we want if it fails.)
10095 	 *
10096 	 * We remove any implicit coercion steps at the top level of the old
10097 	 * default expression; this has been agreed to satisfy the principle of
10098 	 * least surprise.  (The conversion to the new column type should act like
10099 	 * it started from what the user sees as the stored expression, and the
10100 	 * implicit coercions aren't going to be shown.)
10101 	 */
10102 	if (attTup->atthasdef)
10103 	{
10104 		defaultexpr = build_column_default(rel, attnum);
10105 		Assert(defaultexpr);
10106 		defaultexpr = strip_implicit_coercions(defaultexpr);
10107 		defaultexpr = coerce_to_target_type(NULL,	/* no UNKNOWN params */
10108 											defaultexpr, exprType(defaultexpr),
10109 											targettype, targettypmod,
10110 											COERCION_ASSIGNMENT,
10111 											COERCE_IMPLICIT_CAST,
10112 											-1);
10113 		if (defaultexpr == NULL)
10114 			ereport(ERROR,
10115 					(errcode(ERRCODE_DATATYPE_MISMATCH),
10116 					 errmsg("default for column \"%s\" cannot be cast automatically to type %s",
10117 							colName, format_type_be(targettype))));
10118 	}
10119 	else
10120 		defaultexpr = NULL;
10121 
10122 	/*
10123 	 * Find everything that depends on the column (constraints, indexes, etc),
10124 	 * and record enough information to let us recreate the objects.
10125 	 *
10126 	 * The actual recreation does not happen here, but only after we have
10127 	 * performed all the individual ALTER TYPE operations.  We have to save
10128 	 * the info before executing ALTER TYPE, though, else the deparser will
10129 	 * get confused.
10130 	 */
10131 	depRel = heap_open(DependRelationId, RowExclusiveLock);
10132 
10133 	ScanKeyInit(&key[0],
10134 				Anum_pg_depend_refclassid,
10135 				BTEqualStrategyNumber, F_OIDEQ,
10136 				ObjectIdGetDatum(RelationRelationId));
10137 	ScanKeyInit(&key[1],
10138 				Anum_pg_depend_refobjid,
10139 				BTEqualStrategyNumber, F_OIDEQ,
10140 				ObjectIdGetDatum(RelationGetRelid(rel)));
10141 	ScanKeyInit(&key[2],
10142 				Anum_pg_depend_refobjsubid,
10143 				BTEqualStrategyNumber, F_INT4EQ,
10144 				Int32GetDatum((int32) attnum));
10145 
10146 	scan = systable_beginscan(depRel, DependReferenceIndexId, true,
10147 							  NULL, 3, key);
10148 
10149 	while (HeapTupleIsValid(depTup = systable_getnext(scan)))
10150 	{
10151 		Form_pg_depend foundDep = (Form_pg_depend) GETSTRUCT(depTup);
10152 		ObjectAddress foundObject;
10153 
10154 		/* We don't expect any PIN dependencies on columns */
10155 		if (foundDep->deptype == DEPENDENCY_PIN)
10156 			elog(ERROR, "cannot alter type of a pinned column");
10157 
10158 		foundObject.classId = foundDep->classid;
10159 		foundObject.objectId = foundDep->objid;
10160 		foundObject.objectSubId = foundDep->objsubid;
10161 
10162 		switch (getObjectClass(&foundObject))
10163 		{
10164 			case OCLASS_CLASS:
10165 				{
10166 					char		relKind = get_rel_relkind(foundObject.objectId);
10167 
10168 					if (relKind == RELKIND_INDEX ||
10169 						relKind == RELKIND_PARTITIONED_INDEX)
10170 					{
10171 						Assert(foundObject.objectSubId == 0);
10172 						RememberIndexForRebuilding(foundObject.objectId, tab);
10173 					}
10174 					else if (relKind == RELKIND_SEQUENCE)
10175 					{
10176 						/*
10177 						 * This must be a SERIAL column's sequence.  We need
10178 						 * not do anything to it.
10179 						 */
10180 						Assert(foundObject.objectSubId == 0);
10181 					}
10182 					else
10183 					{
10184 						/* Not expecting any other direct dependencies... */
10185 						elog(ERROR, "unexpected object depending on column: %s",
10186 							 getObjectDescription(&foundObject));
10187 					}
10188 					break;
10189 				}
10190 
10191 			case OCLASS_CONSTRAINT:
10192 				Assert(foundObject.objectSubId == 0);
10193 				RememberConstraintForRebuilding(foundObject.objectId, tab);
10194 				break;
10195 
10196 			case OCLASS_REWRITE:
10197 				/* XXX someday see if we can cope with revising views */
10198 				ereport(ERROR,
10199 						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
10200 						 errmsg("cannot alter type of a column used by a view or rule"),
10201 						 errdetail("%s depends on column \"%s\"",
10202 								   getObjectDescription(&foundObject),
10203 								   colName)));
10204 				break;
10205 
10206 			case OCLASS_TRIGGER:
10207 
10208 				/*
10209 				 * A trigger can depend on a column because the column is
10210 				 * specified as an update target, or because the column is
10211 				 * used in the trigger's WHEN condition.  The first case would
10212 				 * not require any extra work, but the second case would
10213 				 * require updating the WHEN expression, which will take a
10214 				 * significant amount of new code.  Since we can't easily tell
10215 				 * which case applies, we punt for both.  FIXME someday.
10216 				 */
10217 				ereport(ERROR,
10218 						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
10219 						 errmsg("cannot alter type of a column used in a trigger definition"),
10220 						 errdetail("%s depends on column \"%s\"",
10221 								   getObjectDescription(&foundObject),
10222 								   colName)));
10223 				break;
10224 
10225 			case OCLASS_POLICY:
10226 
10227 				/*
10228 				 * A policy can depend on a column because the column is
10229 				 * specified in the policy's USING or WITH CHECK qual
10230 				 * expressions.  It might be possible to rewrite and recheck
10231 				 * the policy expression, but punt for now.  It's certainly
10232 				 * easy enough to remove and recreate the policy; still, FIXME
10233 				 * someday.
10234 				 */
10235 				ereport(ERROR,
10236 						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
10237 						 errmsg("cannot alter type of a column used in a policy definition"),
10238 						 errdetail("%s depends on column \"%s\"",
10239 								   getObjectDescription(&foundObject),
10240 								   colName)));
10241 				break;
10242 
10243 			case OCLASS_DEFAULT:
10244 
10245 				/*
10246 				 * Ignore the column's default expression, since we will fix
10247 				 * it below.
10248 				 */
10249 				Assert(defaultexpr);
10250 				break;
10251 
10252 			case OCLASS_STATISTIC_EXT:
10253 
10254 				/*
10255 				 * Give the extended-stats machinery a chance to fix anything
10256 				 * that this column type change would break.
10257 				 */
10258 				UpdateStatisticsForTypeChange(foundObject.objectId,
10259 											  RelationGetRelid(rel), attnum,
10260 											  attTup->atttypid, targettype);
10261 				break;
10262 
10263 			case OCLASS_PROC:
10264 			case OCLASS_TYPE:
10265 			case OCLASS_CAST:
10266 			case OCLASS_COLLATION:
10267 			case OCLASS_CONVERSION:
10268 			case OCLASS_LANGUAGE:
10269 			case OCLASS_LARGEOBJECT:
10270 			case OCLASS_OPERATOR:
10271 			case OCLASS_OPCLASS:
10272 			case OCLASS_OPFAMILY:
10273 			case OCLASS_AM:
10274 			case OCLASS_AMOP:
10275 			case OCLASS_AMPROC:
10276 			case OCLASS_SCHEMA:
10277 			case OCLASS_TSPARSER:
10278 			case OCLASS_TSDICT:
10279 			case OCLASS_TSTEMPLATE:
10280 			case OCLASS_TSCONFIG:
10281 			case OCLASS_ROLE:
10282 			case OCLASS_DATABASE:
10283 			case OCLASS_TBLSPACE:
10284 			case OCLASS_FDW:
10285 			case OCLASS_FOREIGN_SERVER:
10286 			case OCLASS_USER_MAPPING:
10287 			case OCLASS_DEFACL:
10288 			case OCLASS_EXTENSION:
10289 			case OCLASS_EVENT_TRIGGER:
10290 			case OCLASS_PUBLICATION:
10291 			case OCLASS_PUBLICATION_REL:
10292 			case OCLASS_SUBSCRIPTION:
10293 			case OCLASS_TRANSFORM:
10294 
10295 				/*
10296 				 * We don't expect any of these sorts of objects to depend on
10297 				 * a column.
10298 				 */
10299 				elog(ERROR, "unexpected object depending on column: %s",
10300 					 getObjectDescription(&foundObject));
10301 				break;
10302 
10303 				/*
10304 				 * There's intentionally no default: case here; we want the
10305 				 * compiler to warn if a new OCLASS hasn't been handled above.
10306 				 */
10307 		}
10308 	}
10309 
10310 	systable_endscan(scan);
10311 
10312 	/*
10313 	 * Now scan for dependencies of this column on other things.  The only
10314 	 * thing we should find is the dependency on the column datatype, which we
10315 	 * want to remove, and possibly a collation dependency.
10316 	 */
10317 	ScanKeyInit(&key[0],
10318 				Anum_pg_depend_classid,
10319 				BTEqualStrategyNumber, F_OIDEQ,
10320 				ObjectIdGetDatum(RelationRelationId));
10321 	ScanKeyInit(&key[1],
10322 				Anum_pg_depend_objid,
10323 				BTEqualStrategyNumber, F_OIDEQ,
10324 				ObjectIdGetDatum(RelationGetRelid(rel)));
10325 	ScanKeyInit(&key[2],
10326 				Anum_pg_depend_objsubid,
10327 				BTEqualStrategyNumber, F_INT4EQ,
10328 				Int32GetDatum((int32) attnum));
10329 
10330 	scan = systable_beginscan(depRel, DependDependerIndexId, true,
10331 							  NULL, 3, key);
10332 
10333 	while (HeapTupleIsValid(depTup = systable_getnext(scan)))
10334 	{
10335 		Form_pg_depend foundDep = (Form_pg_depend) GETSTRUCT(depTup);
10336 
10337 		if (foundDep->deptype != DEPENDENCY_NORMAL)
10338 			elog(ERROR, "found unexpected dependency type '%c'",
10339 				 foundDep->deptype);
10340 		if (!(foundDep->refclassid == TypeRelationId &&
10341 			  foundDep->refobjid == attTup->atttypid) &&
10342 			!(foundDep->refclassid == CollationRelationId &&
10343 			  foundDep->refobjid == attTup->attcollation))
10344 			elog(ERROR, "found unexpected dependency for column");
10345 
10346 		CatalogTupleDelete(depRel, &depTup->t_self);
10347 	}
10348 
10349 	systable_endscan(scan);
10350 
10351 	heap_close(depRel, RowExclusiveLock);
10352 
10353 	/*
10354 	 * Here we go --- change the recorded column type and collation.  (Note
10355 	 * heapTup is a copy of the syscache entry, so okay to scribble on.) First
10356 	 * fix up the missing value if any. There shouldn't be any missing values
10357 	 * for anything except plain tables, but if there are, ignore them.
10358 	 */
10359 	if (rel->rd_rel->relkind == RELKIND_RELATION  && attTup->atthasmissing)
10360 	{
10361 		Datum       missingval;
10362 		bool        missingNull;
10363 
10364 		/* if rewrite is true the missing value should already be cleared */
10365 		Assert(tab->rewrite == 0);
10366 
10367 		/* Get the missing value datum */
10368 		missingval = heap_getattr(heapTup,
10369 								  Anum_pg_attribute_attmissingval,
10370 								  attrelation->rd_att,
10371 								  &missingNull);
10372 
10373 		/* if it's a null array there is nothing to do */
10374 
10375 		if (! missingNull)
10376 		{
10377 			/*
10378 			 * Get the datum out of the array and repack it in a new array
10379 			 * built with the new type data. We assume that since the table
10380 			 * doesn't need rewriting, the actual Datum doesn't need to be
10381 			 * changed, only the array metadata.
10382 			 */
10383 
10384 			int one = 1;
10385 			bool isNull;
10386 			Datum       valuesAtt[Natts_pg_attribute];
10387 			bool        nullsAtt[Natts_pg_attribute];
10388 			bool        replacesAtt[Natts_pg_attribute];
10389 			HeapTuple   newTup;
10390 
10391 			MemSet(valuesAtt, 0, sizeof(valuesAtt));
10392 			MemSet(nullsAtt, false, sizeof(nullsAtt));
10393 			MemSet(replacesAtt, false, sizeof(replacesAtt));
10394 
10395 			missingval = array_get_element(missingval,
10396 										   1,
10397 										   &one,
10398 										   0,
10399 										   attTup->attlen,
10400 										   attTup->attbyval,
10401 										   attTup->attalign,
10402 										   &isNull);
10403 			missingval = PointerGetDatum(
10404 				construct_array(&missingval,
10405 								1,
10406 								targettype,
10407 								tform->typlen,
10408 								tform->typbyval,
10409 								tform->typalign));
10410 
10411 			valuesAtt[Anum_pg_attribute_attmissingval - 1] = missingval;
10412 			replacesAtt[Anum_pg_attribute_attmissingval - 1] = true;
10413 			nullsAtt[Anum_pg_attribute_attmissingval - 1] = false;
10414 
10415 			newTup = heap_modify_tuple(heapTup, RelationGetDescr(attrelation),
10416 									   valuesAtt, nullsAtt, replacesAtt);
10417 			heap_freetuple(heapTup);
10418 			heapTup = newTup;
10419 			attTup = (Form_pg_attribute) GETSTRUCT(heapTup);
10420 		}
10421 	}
10422 
10423 	attTup->atttypid = targettype;
10424 	attTup->atttypmod = targettypmod;
10425 	attTup->attcollation = targetcollid;
10426 	attTup->attndims = list_length(typeName->arrayBounds);
10427 	attTup->attlen = tform->typlen;
10428 	attTup->attbyval = tform->typbyval;
10429 	attTup->attalign = tform->typalign;
10430 	attTup->attstorage = tform->typstorage;
10431 
10432 	ReleaseSysCache(typeTuple);
10433 
10434 	CatalogTupleUpdate(attrelation, &heapTup->t_self, heapTup);
10435 
10436 	heap_close(attrelation, RowExclusiveLock);
10437 
10438 	/* Install dependencies on new datatype and collation */
10439 	add_column_datatype_dependency(RelationGetRelid(rel), attnum, targettype);
10440 	add_column_collation_dependency(RelationGetRelid(rel), attnum, targetcollid);
10441 
10442 	/*
10443 	 * Drop any pg_statistic entry for the column, since it's now wrong type
10444 	 */
10445 	RemoveStatistics(RelationGetRelid(rel), attnum);
10446 
10447 	InvokeObjectPostAlterHook(RelationRelationId,
10448 							  RelationGetRelid(rel), attnum);
10449 
10450 	/*
10451 	 * Update the default, if present, by brute force --- remove and re-add
10452 	 * the default.  Probably unsafe to take shortcuts, since the new version
10453 	 * may well have additional dependencies.  (It's okay to do this now,
10454 	 * rather than after other ALTER TYPE commands, since the default won't
10455 	 * depend on other column types.)
10456 	 */
10457 	if (defaultexpr)
10458 	{
10459 		/* Must make new row visible since it will be updated again */
10460 		CommandCounterIncrement();
10461 
10462 		/*
10463 		 * We use RESTRICT here for safety, but at present we do not expect
10464 		 * anything to depend on the default.
10465 		 */
10466 		RemoveAttrDefault(RelationGetRelid(rel), attnum, DROP_RESTRICT, true,
10467 						  true);
10468 
10469 		StoreAttrDefault(rel, attnum, defaultexpr, true, false);
10470 	}
10471 
10472 	ObjectAddressSubSet(address, RelationRelationId,
10473 						RelationGetRelid(rel), attnum);
10474 
10475 	/* Cleanup */
10476 	heap_freetuple(heapTup);
10477 
10478 	return address;
10479 }
10480 
10481 /*
10482  * Subroutine for ATExecAlterColumnType: remember that a replica identity
10483  * needs to be reset.
10484  */
10485 static void
RememberReplicaIdentityForRebuilding(Oid indoid,AlteredTableInfo * tab)10486 RememberReplicaIdentityForRebuilding(Oid indoid, AlteredTableInfo *tab)
10487 {
10488 	if (!get_index_isreplident(indoid))
10489 		return;
10490 
10491 	if (tab->replicaIdentityIndex)
10492 		elog(ERROR, "relation %u has multiple indexes marked as replica identity", tab->relid);
10493 
10494 	tab->replicaIdentityIndex = get_rel_name(indoid);
10495 }
10496 
10497 /*
10498  * Subroutine for ATExecAlterColumnType: remember any clustered index.
10499  */
10500 static void
RememberClusterOnForRebuilding(Oid indoid,AlteredTableInfo * tab)10501 RememberClusterOnForRebuilding(Oid indoid, AlteredTableInfo *tab)
10502 {
10503 	if (!get_index_isclustered(indoid))
10504 		return;
10505 
10506 	if (tab->clusterOnIndex)
10507 		elog(ERROR, "relation %u has multiple clustered indexes", tab->relid);
10508 
10509 	tab->clusterOnIndex = get_rel_name(indoid);
10510 }
10511 
10512 /*
10513  * Subroutine for ATExecAlterColumnType: remember that a constraint needs
10514  * to be rebuilt (which we might already know).
10515  */
10516 static void
RememberConstraintForRebuilding(Oid conoid,AlteredTableInfo * tab)10517 RememberConstraintForRebuilding(Oid conoid, AlteredTableInfo *tab)
10518 {
10519 	/*
10520 	 * This de-duplication check is critical for two independent reasons: we
10521 	 * mustn't try to recreate the same constraint twice, and if a constraint
10522 	 * depends on more than one column whose type is to be altered, we must
10523 	 * capture its definition string before applying any of the column type
10524 	 * changes.  ruleutils.c will get confused if we ask again later.
10525 	 */
10526 	if (!list_member_oid(tab->changedConstraintOids, conoid))
10527 	{
10528 		/* OK, capture the constraint's existing definition string */
10529 		char	   *defstring = pg_get_constraintdef_command(conoid);
10530 		Oid			indoid;
10531 
10532 		tab->changedConstraintOids = lappend_oid(tab->changedConstraintOids,
10533 												 conoid);
10534 		tab->changedConstraintDefs = lappend(tab->changedConstraintDefs,
10535 											 defstring);
10536 
10537 		/*
10538 		 * For the index of a constraint, if any, remember if it is used for
10539 		 * the table's replica identity or if it is a clustered index, so that
10540 		 * ATPostAlterTypeCleanup() can queue up commands necessary to restore
10541 		 * those properties.
10542 		 */
10543 		indoid = get_constraint_index(conoid);
10544 		if (OidIsValid(indoid))
10545 		{
10546 			RememberReplicaIdentityForRebuilding(indoid, tab);
10547 			RememberClusterOnForRebuilding(indoid, tab);
10548 		}
10549 	}
10550 }
10551 
10552 /*
10553  * Subroutine for ATExecAlterColumnType: remember that an index needs
10554  * to be rebuilt (which we might already know).
10555  */
10556 static void
RememberIndexForRebuilding(Oid indoid,AlteredTableInfo * tab)10557 RememberIndexForRebuilding(Oid indoid, AlteredTableInfo *tab)
10558 {
10559 	/*
10560 	 * This de-duplication check is critical for two independent reasons: we
10561 	 * mustn't try to recreate the same index twice, and if an index depends
10562 	 * on more than one column whose type is to be altered, we must capture
10563 	 * its definition string before applying any of the column type changes.
10564 	 * ruleutils.c will get confused if we ask again later.
10565 	 */
10566 	if (!list_member_oid(tab->changedIndexOids, indoid))
10567 	{
10568 		/*
10569 		 * Before adding it as an index-to-rebuild, we'd better see if it
10570 		 * belongs to a constraint, and if so rebuild the constraint instead.
10571 		 * Typically this check fails, because constraint indexes normally
10572 		 * have only dependencies on their constraint.  But it's possible for
10573 		 * such an index to also have direct dependencies on table columns,
10574 		 * for example with a partial exclusion constraint.
10575 		 */
10576 		Oid			conoid = get_index_constraint(indoid);
10577 
10578 		if (OidIsValid(conoid))
10579 		{
10580 			RememberConstraintForRebuilding(conoid, tab);
10581 		}
10582 		else
10583 		{
10584 			/* OK, capture the index's existing definition string */
10585 			char	   *defstring = pg_get_indexdef_string(indoid);
10586 
10587 			tab->changedIndexOids = lappend_oid(tab->changedIndexOids,
10588 												indoid);
10589 			tab->changedIndexDefs = lappend(tab->changedIndexDefs,
10590 											defstring);
10591 
10592 			/*
10593 			 * Remember if this index is used for the table's replica identity
10594 			 * or if it is a clustered index, so that ATPostAlterTypeCleanup()
10595 			 * can queue up commands necessary to restore those properties.
10596 			 */
10597 			RememberReplicaIdentityForRebuilding(indoid, tab);
10598 			RememberClusterOnForRebuilding(indoid, tab);
10599 		}
10600 	}
10601 }
10602 
10603 /*
10604  * Returns the address of the modified column
10605  */
10606 static ObjectAddress
ATExecAlterColumnGenericOptions(Relation rel,const char * colName,List * options,LOCKMODE lockmode)10607 ATExecAlterColumnGenericOptions(Relation rel,
10608 								const char *colName,
10609 								List *options,
10610 								LOCKMODE lockmode)
10611 {
10612 	Relation	ftrel;
10613 	Relation	attrel;
10614 	ForeignServer *server;
10615 	ForeignDataWrapper *fdw;
10616 	HeapTuple	tuple;
10617 	HeapTuple	newtuple;
10618 	bool		isnull;
10619 	Datum		repl_val[Natts_pg_attribute];
10620 	bool		repl_null[Natts_pg_attribute];
10621 	bool		repl_repl[Natts_pg_attribute];
10622 	Datum		datum;
10623 	Form_pg_foreign_table fttableform;
10624 	Form_pg_attribute atttableform;
10625 	AttrNumber	attnum;
10626 	ObjectAddress address;
10627 
10628 	if (options == NIL)
10629 		return InvalidObjectAddress;
10630 
10631 	/* First, determine FDW validator associated to the foreign table. */
10632 	ftrel = heap_open(ForeignTableRelationId, AccessShareLock);
10633 	tuple = SearchSysCache1(FOREIGNTABLEREL, rel->rd_id);
10634 	if (!HeapTupleIsValid(tuple))
10635 		ereport(ERROR,
10636 				(errcode(ERRCODE_UNDEFINED_OBJECT),
10637 				 errmsg("foreign table \"%s\" does not exist",
10638 						RelationGetRelationName(rel))));
10639 	fttableform = (Form_pg_foreign_table) GETSTRUCT(tuple);
10640 	server = GetForeignServer(fttableform->ftserver);
10641 	fdw = GetForeignDataWrapper(server->fdwid);
10642 
10643 	heap_close(ftrel, AccessShareLock);
10644 	ReleaseSysCache(tuple);
10645 
10646 	attrel = heap_open(AttributeRelationId, RowExclusiveLock);
10647 	tuple = SearchSysCacheAttName(RelationGetRelid(rel), colName);
10648 	if (!HeapTupleIsValid(tuple))
10649 		ereport(ERROR,
10650 				(errcode(ERRCODE_UNDEFINED_COLUMN),
10651 				 errmsg("column \"%s\" of relation \"%s\" does not exist",
10652 						colName, RelationGetRelationName(rel))));
10653 
10654 	/* Prevent them from altering a system attribute */
10655 	atttableform = (Form_pg_attribute) GETSTRUCT(tuple);
10656 	attnum = atttableform->attnum;
10657 	if (attnum <= 0)
10658 		ereport(ERROR,
10659 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
10660 				 errmsg("cannot alter system column \"%s\"", colName)));
10661 
10662 
10663 	/* Initialize buffers for new tuple values */
10664 	memset(repl_val, 0, sizeof(repl_val));
10665 	memset(repl_null, false, sizeof(repl_null));
10666 	memset(repl_repl, false, sizeof(repl_repl));
10667 
10668 	/* Extract the current options */
10669 	datum = SysCacheGetAttr(ATTNAME,
10670 							tuple,
10671 							Anum_pg_attribute_attfdwoptions,
10672 							&isnull);
10673 	if (isnull)
10674 		datum = PointerGetDatum(NULL);
10675 
10676 	/* Transform the options */
10677 	datum = transformGenericOptions(AttributeRelationId,
10678 									datum,
10679 									options,
10680 									fdw->fdwvalidator);
10681 
10682 	if (PointerIsValid(DatumGetPointer(datum)))
10683 		repl_val[Anum_pg_attribute_attfdwoptions - 1] = datum;
10684 	else
10685 		repl_null[Anum_pg_attribute_attfdwoptions - 1] = true;
10686 
10687 	repl_repl[Anum_pg_attribute_attfdwoptions - 1] = true;
10688 
10689 	/* Everything looks good - update the tuple */
10690 
10691 	newtuple = heap_modify_tuple(tuple, RelationGetDescr(attrel),
10692 								 repl_val, repl_null, repl_repl);
10693 
10694 	CatalogTupleUpdate(attrel, &newtuple->t_self, newtuple);
10695 
10696 	InvokeObjectPostAlterHook(RelationRelationId,
10697 							  RelationGetRelid(rel),
10698 							  atttableform->attnum);
10699 	ObjectAddressSubSet(address, RelationRelationId,
10700 						RelationGetRelid(rel), attnum);
10701 
10702 	ReleaseSysCache(tuple);
10703 
10704 	heap_close(attrel, RowExclusiveLock);
10705 
10706 	heap_freetuple(newtuple);
10707 
10708 	return address;
10709 }
10710 
10711 /*
10712  * Cleanup after we've finished all the ALTER TYPE operations for a
10713  * particular relation.  We have to drop and recreate all the indexes
10714  * and constraints that depend on the altered columns.
10715  */
10716 static void
ATPostAlterTypeCleanup(List ** wqueue,AlteredTableInfo * tab,LOCKMODE lockmode)10717 ATPostAlterTypeCleanup(List **wqueue, AlteredTableInfo *tab, LOCKMODE lockmode)
10718 {
10719 	ObjectAddress obj;
10720 	ObjectAddresses *objects;
10721 	ListCell   *def_item;
10722 	ListCell   *oid_item;
10723 
10724 	/*
10725 	 * Collect all the constraints and indexes to drop so we can process them
10726 	 * in a single call.  That way we don't have to worry about dependencies
10727 	 * among them.
10728 	 */
10729 	objects = new_object_addresses();
10730 
10731 	/*
10732 	 * Re-parse the index and constraint definitions, and attach them to the
10733 	 * appropriate work queue entries.  We do this before dropping because in
10734 	 * the case of a FOREIGN KEY constraint, we might not yet have exclusive
10735 	 * lock on the table the constraint is attached to, and we need to get
10736 	 * that before reparsing/dropping.
10737 	 *
10738 	 * We can't rely on the output of deparsing to tell us which relation to
10739 	 * operate on, because concurrent activity might have made the name
10740 	 * resolve differently.  Instead, we've got to use the OID of the
10741 	 * constraint or index we're processing to figure out which relation to
10742 	 * operate on.
10743 	 */
10744 	forboth(oid_item, tab->changedConstraintOids,
10745 			def_item, tab->changedConstraintDefs)
10746 	{
10747 		Oid			oldId = lfirst_oid(oid_item);
10748 		HeapTuple	tup;
10749 		Form_pg_constraint con;
10750 		Oid			relid;
10751 		Oid			confrelid;
10752 		char		contype;
10753 		bool		conislocal;
10754 
10755 		tup = SearchSysCache1(CONSTROID, ObjectIdGetDatum(oldId));
10756 		if (!HeapTupleIsValid(tup)) /* should not happen */
10757 			elog(ERROR, "cache lookup failed for constraint %u", oldId);
10758 		con = (Form_pg_constraint) GETSTRUCT(tup);
10759 		if (OidIsValid(con->conrelid))
10760 			relid = con->conrelid;
10761 		else
10762 		{
10763 			/* must be a domain constraint */
10764 			relid = get_typ_typrelid(getBaseType(con->contypid));
10765 			if (!OidIsValid(relid))
10766 				elog(ERROR, "could not identify relation associated with constraint %u", oldId);
10767 		}
10768 		confrelid = con->confrelid;
10769 		contype = con->contype;
10770 		conislocal = con->conislocal;
10771 		ReleaseSysCache(tup);
10772 
10773 		ObjectAddressSet(obj, ConstraintRelationId, oldId);
10774 		add_exact_object_address(&obj, objects);
10775 
10776 		/*
10777 		 * If the constraint is inherited (only), we don't want to inject a
10778 		 * new definition here; it'll get recreated when ATAddCheckConstraint
10779 		 * recurses from adding the parent table's constraint.  But we had to
10780 		 * carry the info this far so that we can drop the constraint below.
10781 		 */
10782 		if (!conislocal)
10783 			continue;
10784 
10785 		/*
10786 		 * When rebuilding an FK constraint that references the table we're
10787 		 * modifying, we might not yet have any lock on the FK's table, so get
10788 		 * one now.  We'll need AccessExclusiveLock for the DROP CONSTRAINT
10789 		 * step, so there's no value in asking for anything weaker.
10790 		 */
10791 		if (relid != tab->relid && contype == CONSTRAINT_FOREIGN)
10792 			LockRelationOid(relid, AccessExclusiveLock);
10793 
10794 		ATPostAlterTypeParse(oldId, relid, confrelid,
10795 							 (char *) lfirst(def_item),
10796 							 wqueue, lockmode, tab->rewrite);
10797 	}
10798 	forboth(oid_item, tab->changedIndexOids,
10799 			def_item, tab->changedIndexDefs)
10800 	{
10801 		Oid			oldId = lfirst_oid(oid_item);
10802 		Oid			relid;
10803 
10804 		relid = IndexGetRelation(oldId, false);
10805 		ATPostAlterTypeParse(oldId, relid, InvalidOid,
10806 							 (char *) lfirst(def_item),
10807 							 wqueue, lockmode, tab->rewrite);
10808 
10809 		ObjectAddressSet(obj, RelationRelationId, oldId);
10810 		add_exact_object_address(&obj, objects);
10811 	}
10812 
10813 	/*
10814 	 * Queue up command to restore replica identity index marking
10815 	 */
10816 	if (tab->replicaIdentityIndex)
10817 	{
10818 		AlterTableCmd *cmd = makeNode(AlterTableCmd);
10819 		ReplicaIdentityStmt *subcmd = makeNode(ReplicaIdentityStmt);
10820 
10821 		subcmd->identity_type = REPLICA_IDENTITY_INDEX;
10822 		subcmd->name = tab->replicaIdentityIndex;
10823 		cmd->subtype = AT_ReplicaIdentity;
10824 		cmd->def = (Node *) subcmd;
10825 
10826 		/* do it after indexes and constraints */
10827 		tab->subcmds[AT_PASS_OLD_CONSTR] =
10828 			lappend(tab->subcmds[AT_PASS_OLD_CONSTR], cmd);
10829 	}
10830 
10831 	/*
10832 	 * Queue up command to restore marking of index used for cluster.
10833 	 */
10834 	if (tab->clusterOnIndex)
10835 	{
10836 		AlterTableCmd *cmd = makeNode(AlterTableCmd);
10837 
10838 		cmd->subtype = AT_ClusterOn;
10839 		cmd->name = tab->clusterOnIndex;
10840 
10841 		/* do it after indexes and constraints */
10842 		tab->subcmds[AT_PASS_OLD_CONSTR] =
10843 			lappend(tab->subcmds[AT_PASS_OLD_CONSTR], cmd);
10844 	}
10845 
10846 	/*
10847 	 * It should be okay to use DROP_RESTRICT here, since nothing else should
10848 	 * be depending on these objects.
10849 	 */
10850 	performMultipleDeletions(objects, DROP_RESTRICT, PERFORM_DELETION_INTERNAL);
10851 
10852 	free_object_addresses(objects);
10853 
10854 	/*
10855 	 * The objects will get recreated during subsequent passes over the work
10856 	 * queue.
10857 	 */
10858 }
10859 
10860 static void
ATPostAlterTypeParse(Oid oldId,Oid oldRelId,Oid refRelId,char * cmd,List ** wqueue,LOCKMODE lockmode,bool rewrite)10861 ATPostAlterTypeParse(Oid oldId, Oid oldRelId, Oid refRelId, char *cmd,
10862 					 List **wqueue, LOCKMODE lockmode, bool rewrite)
10863 {
10864 	List	   *raw_parsetree_list;
10865 	List	   *querytree_list;
10866 	ListCell   *list_item;
10867 	Relation	rel;
10868 
10869 	/*
10870 	 * We expect that we will get only ALTER TABLE and CREATE INDEX
10871 	 * statements. Hence, there is no need to pass them through
10872 	 * parse_analyze() or the rewriter, but instead we need to pass them
10873 	 * through parse_utilcmd.c to make them ready for execution.
10874 	 */
10875 	raw_parsetree_list = raw_parser(cmd);
10876 	querytree_list = NIL;
10877 	foreach(list_item, raw_parsetree_list)
10878 	{
10879 		RawStmt    *rs = lfirst_node(RawStmt, list_item);
10880 		Node	   *stmt = rs->stmt;
10881 
10882 		if (IsA(stmt, IndexStmt))
10883 			querytree_list = lappend(querytree_list,
10884 									 transformIndexStmt(oldRelId,
10885 														(IndexStmt *) stmt,
10886 														cmd));
10887 		else if (IsA(stmt, AlterTableStmt))
10888 			querytree_list = list_concat(querytree_list,
10889 										 transformAlterTableStmt(oldRelId,
10890 																 (AlterTableStmt *) stmt,
10891 																 cmd));
10892 		else
10893 			querytree_list = lappend(querytree_list, stmt);
10894 	}
10895 
10896 	/* Caller should already have acquired whatever lock we need. */
10897 	rel = relation_open(oldRelId, NoLock);
10898 
10899 	/*
10900 	 * Attach each generated command to the proper place in the work queue.
10901 	 * Note this could result in creation of entirely new work-queue entries.
10902 	 *
10903 	 * Also note that we have to tweak the command subtypes, because it turns
10904 	 * out that re-creation of indexes and constraints has to act a bit
10905 	 * differently from initial creation.
10906 	 */
10907 	foreach(list_item, querytree_list)
10908 	{
10909 		Node	   *stm = (Node *) lfirst(list_item);
10910 		AlteredTableInfo *tab;
10911 
10912 		tab = ATGetQueueEntry(wqueue, rel);
10913 
10914 		if (IsA(stm, IndexStmt))
10915 		{
10916 			IndexStmt  *stmt = (IndexStmt *) stm;
10917 			AlterTableCmd *newcmd;
10918 
10919 			if (!rewrite)
10920 				TryReuseIndex(oldId, stmt);
10921 			/* keep the index's comment */
10922 			stmt->idxcomment = GetComment(oldId, RelationRelationId, 0);
10923 
10924 			newcmd = makeNode(AlterTableCmd);
10925 			newcmd->subtype = AT_ReAddIndex;
10926 			newcmd->def = (Node *) stmt;
10927 			tab->subcmds[AT_PASS_OLD_INDEX] =
10928 				lappend(tab->subcmds[AT_PASS_OLD_INDEX], newcmd);
10929 		}
10930 		else if (IsA(stm, AlterTableStmt))
10931 		{
10932 			AlterTableStmt *stmt = (AlterTableStmt *) stm;
10933 			ListCell   *lcmd;
10934 
10935 			foreach(lcmd, stmt->cmds)
10936 			{
10937 				AlterTableCmd *cmd = castNode(AlterTableCmd, lfirst(lcmd));
10938 
10939 				if (cmd->subtype == AT_AddIndex)
10940 				{
10941 					IndexStmt  *indstmt;
10942 					Oid			indoid;
10943 
10944 					indstmt = castNode(IndexStmt, cmd->def);
10945 					indoid = get_constraint_index(oldId);
10946 
10947 					if (!rewrite)
10948 						TryReuseIndex(indoid, indstmt);
10949 					/* keep any comment on the index */
10950 					indstmt->idxcomment = GetComment(indoid,
10951 													 RelationRelationId, 0);
10952 
10953 					cmd->subtype = AT_ReAddIndex;
10954 					tab->subcmds[AT_PASS_OLD_INDEX] =
10955 						lappend(tab->subcmds[AT_PASS_OLD_INDEX], cmd);
10956 
10957 					/* recreate any comment on the constraint */
10958 					RebuildConstraintComment(tab,
10959 											 AT_PASS_OLD_INDEX,
10960 											 oldId,
10961 											 rel,
10962 											 NIL,
10963 											 indstmt->idxname);
10964 				}
10965 				else if (cmd->subtype == AT_AddConstraint)
10966 				{
10967 					Constraint *con = castNode(Constraint, cmd->def);
10968 
10969 					con->old_pktable_oid = refRelId;
10970 					/* rewriting neither side of a FK */
10971 					if (con->contype == CONSTR_FOREIGN &&
10972 						!rewrite && tab->rewrite == 0)
10973 						TryReuseForeignKey(oldId, con);
10974 					cmd->subtype = AT_ReAddConstraint;
10975 					tab->subcmds[AT_PASS_OLD_CONSTR] =
10976 						lappend(tab->subcmds[AT_PASS_OLD_CONSTR], cmd);
10977 
10978 					/* recreate any comment on the constraint */
10979 					RebuildConstraintComment(tab,
10980 											 AT_PASS_OLD_CONSTR,
10981 											 oldId,
10982 											 rel,
10983 											 NIL,
10984 											 con->conname);
10985 				}
10986 				else
10987 					elog(ERROR, "unexpected statement subtype: %d",
10988 						 (int) cmd->subtype);
10989 			}
10990 		}
10991 		else if (IsA(stm, AlterDomainStmt))
10992 		{
10993 			AlterDomainStmt *stmt = (AlterDomainStmt *) stm;
10994 
10995 			if (stmt->subtype == 'C')	/* ADD CONSTRAINT */
10996 			{
10997 				Constraint *con = castNode(Constraint, stmt->def);
10998 				AlterTableCmd *cmd = makeNode(AlterTableCmd);
10999 
11000 				cmd->subtype = AT_ReAddDomainConstraint;
11001 				cmd->def = (Node *) stmt;
11002 				tab->subcmds[AT_PASS_OLD_CONSTR] =
11003 					lappend(tab->subcmds[AT_PASS_OLD_CONSTR], cmd);
11004 
11005 				/* recreate any comment on the constraint */
11006 				RebuildConstraintComment(tab,
11007 										 AT_PASS_OLD_CONSTR,
11008 										 oldId,
11009 										 NULL,
11010 										 stmt->typeName,
11011 										 con->conname);
11012 			}
11013 			else
11014 				elog(ERROR, "unexpected statement subtype: %d",
11015 					 (int) stmt->subtype);
11016 		}
11017 		else
11018 			elog(ERROR, "unexpected statement type: %d",
11019 				 (int) nodeTag(stm));
11020 	}
11021 
11022 	relation_close(rel, NoLock);
11023 }
11024 
11025 /*
11026  * Subroutine for ATPostAlterTypeParse() to recreate any existing comment
11027  * for a table or domain constraint that is being rebuilt.
11028  *
11029  * objid is the OID of the constraint.
11030  * Pass "rel" for a table constraint, or "domname" (domain's qualified name
11031  * as a string list) for a domain constraint.
11032  * (We could dig that info, as well as the conname, out of the pg_constraint
11033  * entry; but callers already have them so might as well pass them.)
11034  */
11035 static void
RebuildConstraintComment(AlteredTableInfo * tab,int pass,Oid objid,Relation rel,List * domname,const char * conname)11036 RebuildConstraintComment(AlteredTableInfo *tab, int pass, Oid objid,
11037 						 Relation rel, List *domname,
11038 						 const char *conname)
11039 {
11040 	CommentStmt *cmd;
11041 	char	   *comment_str;
11042 	AlterTableCmd *newcmd;
11043 
11044 	/* Look for comment for object wanted, and leave if none */
11045 	comment_str = GetComment(objid, ConstraintRelationId, 0);
11046 	if (comment_str == NULL)
11047 		return;
11048 
11049 	/* Build CommentStmt node, copying all input data for safety */
11050 	cmd = makeNode(CommentStmt);
11051 	if (rel)
11052 	{
11053 		cmd->objtype = OBJECT_TABCONSTRAINT;
11054 		cmd->object = (Node *)
11055 			list_make3(makeString(get_namespace_name(RelationGetNamespace(rel))),
11056 					   makeString(pstrdup(RelationGetRelationName(rel))),
11057 					   makeString(pstrdup(conname)));
11058 	}
11059 	else
11060 	{
11061 		cmd->objtype = OBJECT_DOMCONSTRAINT;
11062 		cmd->object = (Node *)
11063 			list_make2(makeTypeNameFromNameList(copyObject(domname)),
11064 					   makeString(pstrdup(conname)));
11065 	}
11066 	cmd->comment = comment_str;
11067 
11068 	/* Append it to list of commands */
11069 	newcmd = makeNode(AlterTableCmd);
11070 	newcmd->subtype = AT_ReAddComment;
11071 	newcmd->def = (Node *) cmd;
11072 	tab->subcmds[pass] = lappend(tab->subcmds[pass], newcmd);
11073 }
11074 
11075 /*
11076  * Subroutine for ATPostAlterTypeParse().  Calls out to CheckIndexCompatible()
11077  * for the real analysis, then mutates the IndexStmt based on that verdict.
11078  */
11079 static void
TryReuseIndex(Oid oldId,IndexStmt * stmt)11080 TryReuseIndex(Oid oldId, IndexStmt *stmt)
11081 {
11082 	if (CheckIndexCompatible(oldId,
11083 							 stmt->accessMethod,
11084 							 stmt->indexParams,
11085 							 stmt->excludeOpNames))
11086 	{
11087 		Relation	irel = index_open(oldId, NoLock);
11088 
11089 		/* If it's a partitioned index, there is no storage to share. */
11090 		if (irel->rd_rel->relkind != RELKIND_PARTITIONED_INDEX)
11091 			stmt->oldNode = irel->rd_node.relNode;
11092 		index_close(irel, NoLock);
11093 	}
11094 }
11095 
11096 /*
11097  * Subroutine for ATPostAlterTypeParse().
11098  *
11099  * Stash the old P-F equality operator into the Constraint node, for possible
11100  * use by ATAddForeignKeyConstraint() in determining whether revalidation of
11101  * this constraint can be skipped.
11102  */
11103 static void
TryReuseForeignKey(Oid oldId,Constraint * con)11104 TryReuseForeignKey(Oid oldId, Constraint *con)
11105 {
11106 	HeapTuple	tup;
11107 	Datum		adatum;
11108 	bool		isNull;
11109 	ArrayType  *arr;
11110 	Oid		   *rawarr;
11111 	int			numkeys;
11112 	int			i;
11113 
11114 	Assert(con->contype == CONSTR_FOREIGN);
11115 	Assert(con->old_conpfeqop == NIL);	/* already prepared this node */
11116 
11117 	tup = SearchSysCache1(CONSTROID, ObjectIdGetDatum(oldId));
11118 	if (!HeapTupleIsValid(tup)) /* should not happen */
11119 		elog(ERROR, "cache lookup failed for constraint %u", oldId);
11120 
11121 	adatum = SysCacheGetAttr(CONSTROID, tup,
11122 							 Anum_pg_constraint_conpfeqop, &isNull);
11123 	if (isNull)
11124 		elog(ERROR, "null conpfeqop for constraint %u", oldId);
11125 	arr = DatumGetArrayTypeP(adatum);	/* ensure not toasted */
11126 	numkeys = ARR_DIMS(arr)[0];
11127 	/* test follows the one in ri_FetchConstraintInfo() */
11128 	if (ARR_NDIM(arr) != 1 ||
11129 		ARR_HASNULL(arr) ||
11130 		ARR_ELEMTYPE(arr) != OIDOID)
11131 		elog(ERROR, "conpfeqop is not a 1-D Oid array");
11132 	rawarr = (Oid *) ARR_DATA_PTR(arr);
11133 
11134 	/* stash a List of the operator Oids in our Constraint node */
11135 	for (i = 0; i < numkeys; i++)
11136 		con->old_conpfeqop = lappend_oid(con->old_conpfeqop, rawarr[i]);
11137 
11138 	ReleaseSysCache(tup);
11139 }
11140 
11141 /*
11142  * ALTER TABLE OWNER
11143  *
11144  * recursing is true if we are recursing from a table to its indexes,
11145  * sequences, or toast table.  We don't allow the ownership of those things to
11146  * be changed separately from the parent table.  Also, we can skip permission
11147  * checks (this is necessary not just an optimization, else we'd fail to
11148  * handle toast tables properly).
11149  *
11150  * recursing is also true if ALTER TYPE OWNER is calling us to fix up a
11151  * free-standing composite type.
11152  */
11153 void
ATExecChangeOwner(Oid relationOid,Oid newOwnerId,bool recursing,LOCKMODE lockmode)11154 ATExecChangeOwner(Oid relationOid, Oid newOwnerId, bool recursing, LOCKMODE lockmode)
11155 {
11156 	Relation	target_rel;
11157 	Relation	class_rel;
11158 	HeapTuple	tuple;
11159 	Form_pg_class tuple_class;
11160 
11161 	/*
11162 	 * Get exclusive lock till end of transaction on the target table. Use
11163 	 * relation_open so that we can work on indexes and sequences.
11164 	 */
11165 	target_rel = relation_open(relationOid, lockmode);
11166 
11167 	/* Get its pg_class tuple, too */
11168 	class_rel = heap_open(RelationRelationId, RowExclusiveLock);
11169 
11170 	tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relationOid));
11171 	if (!HeapTupleIsValid(tuple))
11172 		elog(ERROR, "cache lookup failed for relation %u", relationOid);
11173 	tuple_class = (Form_pg_class) GETSTRUCT(tuple);
11174 
11175 	/* Can we change the ownership of this tuple? */
11176 	switch (tuple_class->relkind)
11177 	{
11178 		case RELKIND_RELATION:
11179 		case RELKIND_VIEW:
11180 		case RELKIND_MATVIEW:
11181 		case RELKIND_FOREIGN_TABLE:
11182 		case RELKIND_PARTITIONED_TABLE:
11183 			/* ok to change owner */
11184 			break;
11185 		case RELKIND_INDEX:
11186 			if (!recursing)
11187 			{
11188 				/*
11189 				 * Because ALTER INDEX OWNER used to be allowed, and in fact
11190 				 * is generated by old versions of pg_dump, we give a warning
11191 				 * and do nothing rather than erroring out.  Also, to avoid
11192 				 * unnecessary chatter while restoring those old dumps, say
11193 				 * nothing at all if the command would be a no-op anyway.
11194 				 */
11195 				if (tuple_class->relowner != newOwnerId)
11196 					ereport(WARNING,
11197 							(errcode(ERRCODE_WRONG_OBJECT_TYPE),
11198 							 errmsg("cannot change owner of index \"%s\"",
11199 									NameStr(tuple_class->relname)),
11200 							 errhint("Change the ownership of the index's table, instead.")));
11201 				/* quick hack to exit via the no-op path */
11202 				newOwnerId = tuple_class->relowner;
11203 			}
11204 			break;
11205 		case RELKIND_PARTITIONED_INDEX:
11206 			if (recursing)
11207 				break;
11208 			ereport(ERROR,
11209 					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
11210 					 errmsg("cannot change owner of index \"%s\"",
11211 							NameStr(tuple_class->relname)),
11212 					 errhint("Change the ownership of the index's table, instead.")));
11213 			break;
11214 		case RELKIND_SEQUENCE:
11215 			if (!recursing &&
11216 				tuple_class->relowner != newOwnerId)
11217 			{
11218 				/* if it's an owned sequence, disallow changing it by itself */
11219 				Oid			tableId;
11220 				int32		colId;
11221 
11222 				if (sequenceIsOwned(relationOid, DEPENDENCY_AUTO, &tableId, &colId) ||
11223 					sequenceIsOwned(relationOid, DEPENDENCY_INTERNAL, &tableId, &colId))
11224 					ereport(ERROR,
11225 							(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
11226 							 errmsg("cannot change owner of sequence \"%s\"",
11227 									NameStr(tuple_class->relname)),
11228 							 errdetail("Sequence \"%s\" is linked to table \"%s\".",
11229 									   NameStr(tuple_class->relname),
11230 									   get_rel_name(tableId))));
11231 			}
11232 			break;
11233 		case RELKIND_COMPOSITE_TYPE:
11234 			if (recursing)
11235 				break;
11236 			ereport(ERROR,
11237 					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
11238 					 errmsg("\"%s\" is a composite type",
11239 							NameStr(tuple_class->relname)),
11240 					 errhint("Use ALTER TYPE instead.")));
11241 			break;
11242 		case RELKIND_TOASTVALUE:
11243 			if (recursing)
11244 				break;
11245 			/* FALL THRU */
11246 		default:
11247 			ereport(ERROR,
11248 					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
11249 					 errmsg("\"%s\" is not a table, view, sequence, or foreign table",
11250 							NameStr(tuple_class->relname))));
11251 	}
11252 
11253 	/*
11254 	 * If the new owner is the same as the existing owner, consider the
11255 	 * command to have succeeded.  This is for dump restoration purposes.
11256 	 */
11257 	if (tuple_class->relowner != newOwnerId)
11258 	{
11259 		Datum		repl_val[Natts_pg_class];
11260 		bool		repl_null[Natts_pg_class];
11261 		bool		repl_repl[Natts_pg_class];
11262 		Acl		   *newAcl;
11263 		Datum		aclDatum;
11264 		bool		isNull;
11265 		HeapTuple	newtuple;
11266 
11267 		/* skip permission checks when recursing to index or toast table */
11268 		if (!recursing)
11269 		{
11270 			/* Superusers can always do it */
11271 			if (!superuser())
11272 			{
11273 				Oid			namespaceOid = tuple_class->relnamespace;
11274 				AclResult	aclresult;
11275 
11276 				/* Otherwise, must be owner of the existing object */
11277 				if (!pg_class_ownercheck(relationOid, GetUserId()))
11278 					aclcheck_error(ACLCHECK_NOT_OWNER, get_relkind_objtype(get_rel_relkind(relationOid)),
11279 								   RelationGetRelationName(target_rel));
11280 
11281 				/* Must be able to become new owner */
11282 				check_is_member_of_role(GetUserId(), newOwnerId);
11283 
11284 				/* New owner must have CREATE privilege on namespace */
11285 				aclresult = pg_namespace_aclcheck(namespaceOid, newOwnerId,
11286 												  ACL_CREATE);
11287 				if (aclresult != ACLCHECK_OK)
11288 					aclcheck_error(aclresult, OBJECT_SCHEMA,
11289 								   get_namespace_name(namespaceOid));
11290 			}
11291 		}
11292 
11293 		memset(repl_null, false, sizeof(repl_null));
11294 		memset(repl_repl, false, sizeof(repl_repl));
11295 
11296 		repl_repl[Anum_pg_class_relowner - 1] = true;
11297 		repl_val[Anum_pg_class_relowner - 1] = ObjectIdGetDatum(newOwnerId);
11298 
11299 		/*
11300 		 * Determine the modified ACL for the new owner.  This is only
11301 		 * necessary when the ACL is non-null.
11302 		 */
11303 		aclDatum = SysCacheGetAttr(RELOID, tuple,
11304 								   Anum_pg_class_relacl,
11305 								   &isNull);
11306 		if (!isNull)
11307 		{
11308 			newAcl = aclnewowner(DatumGetAclP(aclDatum),
11309 								 tuple_class->relowner, newOwnerId);
11310 			repl_repl[Anum_pg_class_relacl - 1] = true;
11311 			repl_val[Anum_pg_class_relacl - 1] = PointerGetDatum(newAcl);
11312 		}
11313 
11314 		newtuple = heap_modify_tuple(tuple, RelationGetDescr(class_rel), repl_val, repl_null, repl_repl);
11315 
11316 		CatalogTupleUpdate(class_rel, &newtuple->t_self, newtuple);
11317 
11318 		heap_freetuple(newtuple);
11319 
11320 		/*
11321 		 * We must similarly update any per-column ACLs to reflect the new
11322 		 * owner; for neatness reasons that's split out as a subroutine.
11323 		 */
11324 		change_owner_fix_column_acls(relationOid,
11325 									 tuple_class->relowner,
11326 									 newOwnerId);
11327 
11328 		/*
11329 		 * Update owner dependency reference, if any.  A composite type has
11330 		 * none, because it's tracked for the pg_type entry instead of here;
11331 		 * indexes and TOAST tables don't have their own entries either.
11332 		 */
11333 		if (tuple_class->relkind != RELKIND_COMPOSITE_TYPE &&
11334 			tuple_class->relkind != RELKIND_INDEX &&
11335 			tuple_class->relkind != RELKIND_PARTITIONED_INDEX &&
11336 			tuple_class->relkind != RELKIND_TOASTVALUE)
11337 			changeDependencyOnOwner(RelationRelationId, relationOid,
11338 									newOwnerId);
11339 
11340 		/*
11341 		 * Also change the ownership of the table's row type, if it has one
11342 		 */
11343 		if (tuple_class->relkind != RELKIND_INDEX &&
11344 			tuple_class->relkind != RELKIND_PARTITIONED_INDEX)
11345 			AlterTypeOwnerInternal(tuple_class->reltype, newOwnerId);
11346 
11347 		/*
11348 		 * If we are operating on a table or materialized view, also change
11349 		 * the ownership of any indexes and sequences that belong to the
11350 		 * relation, as well as its toast table (if it has one).
11351 		 */
11352 		if (tuple_class->relkind == RELKIND_RELATION ||
11353 			tuple_class->relkind == RELKIND_PARTITIONED_TABLE ||
11354 			tuple_class->relkind == RELKIND_MATVIEW ||
11355 			tuple_class->relkind == RELKIND_TOASTVALUE)
11356 		{
11357 			List	   *index_oid_list;
11358 			ListCell   *i;
11359 
11360 			/* Find all the indexes belonging to this relation */
11361 			index_oid_list = RelationGetIndexList(target_rel);
11362 
11363 			/* For each index, recursively change its ownership */
11364 			foreach(i, index_oid_list)
11365 				ATExecChangeOwner(lfirst_oid(i), newOwnerId, true, lockmode);
11366 
11367 			list_free(index_oid_list);
11368 		}
11369 
11370 		/* If it has a toast table, recurse to change its ownership */
11371 		if (tuple_class->reltoastrelid != InvalidOid)
11372 			ATExecChangeOwner(tuple_class->reltoastrelid, newOwnerId,
11373 							  true, lockmode);
11374 
11375 		/* If it has dependent sequences, recurse to change them too */
11376 		change_owner_recurse_to_sequences(relationOid, newOwnerId, lockmode);
11377 	}
11378 
11379 	InvokeObjectPostAlterHook(RelationRelationId, relationOid, 0);
11380 
11381 	ReleaseSysCache(tuple);
11382 	heap_close(class_rel, RowExclusiveLock);
11383 	relation_close(target_rel, NoLock);
11384 }
11385 
11386 /*
11387  * change_owner_fix_column_acls
11388  *
11389  * Helper function for ATExecChangeOwner.  Scan the columns of the table
11390  * and fix any non-null column ACLs to reflect the new owner.
11391  */
11392 static void
change_owner_fix_column_acls(Oid relationOid,Oid oldOwnerId,Oid newOwnerId)11393 change_owner_fix_column_acls(Oid relationOid, Oid oldOwnerId, Oid newOwnerId)
11394 {
11395 	Relation	attRelation;
11396 	SysScanDesc scan;
11397 	ScanKeyData key[1];
11398 	HeapTuple	attributeTuple;
11399 
11400 	attRelation = heap_open(AttributeRelationId, RowExclusiveLock);
11401 	ScanKeyInit(&key[0],
11402 				Anum_pg_attribute_attrelid,
11403 				BTEqualStrategyNumber, F_OIDEQ,
11404 				ObjectIdGetDatum(relationOid));
11405 	scan = systable_beginscan(attRelation, AttributeRelidNumIndexId,
11406 							  true, NULL, 1, key);
11407 	while (HeapTupleIsValid(attributeTuple = systable_getnext(scan)))
11408 	{
11409 		Form_pg_attribute att = (Form_pg_attribute) GETSTRUCT(attributeTuple);
11410 		Datum		repl_val[Natts_pg_attribute];
11411 		bool		repl_null[Natts_pg_attribute];
11412 		bool		repl_repl[Natts_pg_attribute];
11413 		Acl		   *newAcl;
11414 		Datum		aclDatum;
11415 		bool		isNull;
11416 		HeapTuple	newtuple;
11417 
11418 		/* Ignore dropped columns */
11419 		if (att->attisdropped)
11420 			continue;
11421 
11422 		aclDatum = heap_getattr(attributeTuple,
11423 								Anum_pg_attribute_attacl,
11424 								RelationGetDescr(attRelation),
11425 								&isNull);
11426 		/* Null ACLs do not require changes */
11427 		if (isNull)
11428 			continue;
11429 
11430 		memset(repl_null, false, sizeof(repl_null));
11431 		memset(repl_repl, false, sizeof(repl_repl));
11432 
11433 		newAcl = aclnewowner(DatumGetAclP(aclDatum),
11434 							 oldOwnerId, newOwnerId);
11435 		repl_repl[Anum_pg_attribute_attacl - 1] = true;
11436 		repl_val[Anum_pg_attribute_attacl - 1] = PointerGetDatum(newAcl);
11437 
11438 		newtuple = heap_modify_tuple(attributeTuple,
11439 									 RelationGetDescr(attRelation),
11440 									 repl_val, repl_null, repl_repl);
11441 
11442 		CatalogTupleUpdate(attRelation, &newtuple->t_self, newtuple);
11443 
11444 		heap_freetuple(newtuple);
11445 	}
11446 	systable_endscan(scan);
11447 	heap_close(attRelation, RowExclusiveLock);
11448 }
11449 
11450 /*
11451  * change_owner_recurse_to_sequences
11452  *
11453  * Helper function for ATExecChangeOwner.  Examines pg_depend searching
11454  * for sequences that are dependent on serial columns, and changes their
11455  * ownership.
11456  */
11457 static void
change_owner_recurse_to_sequences(Oid relationOid,Oid newOwnerId,LOCKMODE lockmode)11458 change_owner_recurse_to_sequences(Oid relationOid, Oid newOwnerId, LOCKMODE lockmode)
11459 {
11460 	Relation	depRel;
11461 	SysScanDesc scan;
11462 	ScanKeyData key[2];
11463 	HeapTuple	tup;
11464 
11465 	/*
11466 	 * SERIAL sequences are those having an auto dependency on one of the
11467 	 * table's columns (we don't care *which* column, exactly).
11468 	 */
11469 	depRel = heap_open(DependRelationId, AccessShareLock);
11470 
11471 	ScanKeyInit(&key[0],
11472 				Anum_pg_depend_refclassid,
11473 				BTEqualStrategyNumber, F_OIDEQ,
11474 				ObjectIdGetDatum(RelationRelationId));
11475 	ScanKeyInit(&key[1],
11476 				Anum_pg_depend_refobjid,
11477 				BTEqualStrategyNumber, F_OIDEQ,
11478 				ObjectIdGetDatum(relationOid));
11479 	/* we leave refobjsubid unspecified */
11480 
11481 	scan = systable_beginscan(depRel, DependReferenceIndexId, true,
11482 							  NULL, 2, key);
11483 
11484 	while (HeapTupleIsValid(tup = systable_getnext(scan)))
11485 	{
11486 		Form_pg_depend depForm = (Form_pg_depend) GETSTRUCT(tup);
11487 		Relation	seqRel;
11488 
11489 		/* skip dependencies other than auto dependencies on columns */
11490 		if (depForm->refobjsubid == 0 ||
11491 			depForm->classid != RelationRelationId ||
11492 			depForm->objsubid != 0 ||
11493 			!(depForm->deptype == DEPENDENCY_AUTO || depForm->deptype == DEPENDENCY_INTERNAL))
11494 			continue;
11495 
11496 		/* Use relation_open just in case it's an index */
11497 		seqRel = relation_open(depForm->objid, lockmode);
11498 
11499 		/* skip non-sequence relations */
11500 		if (RelationGetForm(seqRel)->relkind != RELKIND_SEQUENCE)
11501 		{
11502 			/* No need to keep the lock */
11503 			relation_close(seqRel, lockmode);
11504 			continue;
11505 		}
11506 
11507 		/* We don't need to close the sequence while we alter it. */
11508 		ATExecChangeOwner(depForm->objid, newOwnerId, true, lockmode);
11509 
11510 		/* Now we can close it.  Keep the lock till end of transaction. */
11511 		relation_close(seqRel, NoLock);
11512 	}
11513 
11514 	systable_endscan(scan);
11515 
11516 	relation_close(depRel, AccessShareLock);
11517 }
11518 
11519 /*
11520  * ALTER TABLE CLUSTER ON
11521  *
11522  * The only thing we have to do is to change the indisclustered bits.
11523  *
11524  * Return the address of the new clustering index.
11525  */
11526 static ObjectAddress
ATExecClusterOn(Relation rel,const char * indexName,LOCKMODE lockmode)11527 ATExecClusterOn(Relation rel, const char *indexName, LOCKMODE lockmode)
11528 {
11529 	Oid			indexOid;
11530 	ObjectAddress address;
11531 
11532 	indexOid = get_relname_relid(indexName, rel->rd_rel->relnamespace);
11533 
11534 	if (!OidIsValid(indexOid))
11535 		ereport(ERROR,
11536 				(errcode(ERRCODE_UNDEFINED_OBJECT),
11537 				 errmsg("index \"%s\" for table \"%s\" does not exist",
11538 						indexName, RelationGetRelationName(rel))));
11539 
11540 	/* Check index is valid to cluster on */
11541 	check_index_is_clusterable(rel, indexOid, false, lockmode);
11542 
11543 	/* And do the work */
11544 	mark_index_clustered(rel, indexOid, false);
11545 
11546 	ObjectAddressSet(address,
11547 					 RelationRelationId, indexOid);
11548 
11549 	return address;
11550 }
11551 
11552 /*
11553  * ALTER TABLE SET WITHOUT CLUSTER
11554  *
11555  * We have to find any indexes on the table that have indisclustered bit
11556  * set and turn it off.
11557  */
11558 static void
ATExecDropCluster(Relation rel,LOCKMODE lockmode)11559 ATExecDropCluster(Relation rel, LOCKMODE lockmode)
11560 {
11561 	mark_index_clustered(rel, InvalidOid, false);
11562 }
11563 
11564 /*
11565  * ALTER TABLE SET TABLESPACE
11566  */
11567 static void
ATPrepSetTableSpace(AlteredTableInfo * tab,Relation rel,const char * tablespacename,LOCKMODE lockmode)11568 ATPrepSetTableSpace(AlteredTableInfo *tab, Relation rel, const char *tablespacename, LOCKMODE lockmode)
11569 {
11570 	Oid			tablespaceId;
11571 
11572 	/* Check that the tablespace exists */
11573 	tablespaceId = get_tablespace_oid(tablespacename, false);
11574 
11575 	/* Check permissions except when moving to database's default */
11576 	if (OidIsValid(tablespaceId) && tablespaceId != MyDatabaseTableSpace)
11577 	{
11578 		AclResult	aclresult;
11579 
11580 		aclresult = pg_tablespace_aclcheck(tablespaceId, GetUserId(), ACL_CREATE);
11581 		if (aclresult != ACLCHECK_OK)
11582 			aclcheck_error(aclresult, OBJECT_TABLESPACE, tablespacename);
11583 	}
11584 
11585 	/* Save info for Phase 3 to do the real work */
11586 	if (OidIsValid(tab->newTableSpace))
11587 		ereport(ERROR,
11588 				(errcode(ERRCODE_SYNTAX_ERROR),
11589 				 errmsg("cannot have multiple SET TABLESPACE subcommands")));
11590 
11591 	tab->newTableSpace = tablespaceId;
11592 }
11593 
11594 /*
11595  * Set, reset, or replace reloptions.
11596  */
11597 static void
ATExecSetRelOptions(Relation rel,List * defList,AlterTableType operation,LOCKMODE lockmode)11598 ATExecSetRelOptions(Relation rel, List *defList, AlterTableType operation,
11599 					LOCKMODE lockmode)
11600 {
11601 	Oid			relid;
11602 	Relation	pgclass;
11603 	HeapTuple	tuple;
11604 	HeapTuple	newtuple;
11605 	Datum		datum;
11606 	bool		isnull;
11607 	Datum		newOptions;
11608 	Datum		repl_val[Natts_pg_class];
11609 	bool		repl_null[Natts_pg_class];
11610 	bool		repl_repl[Natts_pg_class];
11611 	static char *validnsps[] = HEAP_RELOPT_NAMESPACES;
11612 
11613 	if (defList == NIL && operation != AT_ReplaceRelOptions)
11614 		return;					/* nothing to do */
11615 
11616 	pgclass = heap_open(RelationRelationId, RowExclusiveLock);
11617 
11618 	/* Fetch heap tuple */
11619 	relid = RelationGetRelid(rel);
11620 	tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
11621 	if (!HeapTupleIsValid(tuple))
11622 		elog(ERROR, "cache lookup failed for relation %u", relid);
11623 
11624 	if (operation == AT_ReplaceRelOptions)
11625 	{
11626 		/*
11627 		 * If we're supposed to replace the reloptions list, we just pretend
11628 		 * there were none before.
11629 		 */
11630 		datum = (Datum) 0;
11631 		isnull = true;
11632 	}
11633 	else
11634 	{
11635 		/* Get the old reloptions */
11636 		datum = SysCacheGetAttr(RELOID, tuple, Anum_pg_class_reloptions,
11637 								&isnull);
11638 	}
11639 
11640 	/* Generate new proposed reloptions (text array) */
11641 	newOptions = transformRelOptions(isnull ? (Datum) 0 : datum,
11642 									 defList, NULL, validnsps, false,
11643 									 operation == AT_ResetRelOptions);
11644 
11645 	/* Validate */
11646 	switch (rel->rd_rel->relkind)
11647 	{
11648 		case RELKIND_RELATION:
11649 		case RELKIND_TOASTVALUE:
11650 		case RELKIND_MATVIEW:
11651 		case RELKIND_PARTITIONED_TABLE:
11652 			(void) heap_reloptions(rel->rd_rel->relkind, newOptions, true);
11653 			break;
11654 		case RELKIND_VIEW:
11655 			(void) view_reloptions(newOptions, true);
11656 			break;
11657 		case RELKIND_INDEX:
11658 		case RELKIND_PARTITIONED_INDEX:
11659 			(void) index_reloptions(rel->rd_amroutine->amoptions, newOptions, true);
11660 			break;
11661 		default:
11662 			ereport(ERROR,
11663 					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
11664 					 errmsg("\"%s\" is not a table, view, materialized view, index, or TOAST table",
11665 							RelationGetRelationName(rel))));
11666 			break;
11667 	}
11668 
11669 	/* Special-case validation of view options */
11670 	if (rel->rd_rel->relkind == RELKIND_VIEW)
11671 	{
11672 		Query	   *view_query = get_view_query(rel);
11673 		List	   *view_options = untransformRelOptions(newOptions);
11674 		ListCell   *cell;
11675 		bool		check_option = false;
11676 
11677 		foreach(cell, view_options)
11678 		{
11679 			DefElem    *defel = (DefElem *) lfirst(cell);
11680 
11681 			if (strcmp(defel->defname, "check_option") == 0)
11682 				check_option = true;
11683 		}
11684 
11685 		/*
11686 		 * If the check option is specified, look to see if the view is
11687 		 * actually auto-updatable or not.
11688 		 */
11689 		if (check_option)
11690 		{
11691 			const char *view_updatable_error =
11692 			view_query_is_auto_updatable(view_query, true);
11693 
11694 			if (view_updatable_error)
11695 				ereport(ERROR,
11696 						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
11697 						 errmsg("WITH CHECK OPTION is supported only on automatically updatable views"),
11698 						 errhint("%s", _(view_updatable_error))));
11699 		}
11700 	}
11701 
11702 	/*
11703 	 * All we need do here is update the pg_class row; the new options will be
11704 	 * propagated into relcaches during post-commit cache inval.
11705 	 */
11706 	memset(repl_val, 0, sizeof(repl_val));
11707 	memset(repl_null, false, sizeof(repl_null));
11708 	memset(repl_repl, false, sizeof(repl_repl));
11709 
11710 	if (newOptions != (Datum) 0)
11711 		repl_val[Anum_pg_class_reloptions - 1] = newOptions;
11712 	else
11713 		repl_null[Anum_pg_class_reloptions - 1] = true;
11714 
11715 	repl_repl[Anum_pg_class_reloptions - 1] = true;
11716 
11717 	newtuple = heap_modify_tuple(tuple, RelationGetDescr(pgclass),
11718 								 repl_val, repl_null, repl_repl);
11719 
11720 	CatalogTupleUpdate(pgclass, &newtuple->t_self, newtuple);
11721 
11722 	InvokeObjectPostAlterHook(RelationRelationId, RelationGetRelid(rel), 0);
11723 
11724 	heap_freetuple(newtuple);
11725 
11726 	ReleaseSysCache(tuple);
11727 
11728 	/* repeat the whole exercise for the toast table, if there's one */
11729 	if (OidIsValid(rel->rd_rel->reltoastrelid))
11730 	{
11731 		Relation	toastrel;
11732 		Oid			toastid = rel->rd_rel->reltoastrelid;
11733 
11734 		toastrel = heap_open(toastid, lockmode);
11735 
11736 		/* Fetch heap tuple */
11737 		tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(toastid));
11738 		if (!HeapTupleIsValid(tuple))
11739 			elog(ERROR, "cache lookup failed for relation %u", toastid);
11740 
11741 		if (operation == AT_ReplaceRelOptions)
11742 		{
11743 			/*
11744 			 * If we're supposed to replace the reloptions list, we just
11745 			 * pretend there were none before.
11746 			 */
11747 			datum = (Datum) 0;
11748 			isnull = true;
11749 		}
11750 		else
11751 		{
11752 			/* Get the old reloptions */
11753 			datum = SysCacheGetAttr(RELOID, tuple, Anum_pg_class_reloptions,
11754 									&isnull);
11755 		}
11756 
11757 		newOptions = transformRelOptions(isnull ? (Datum) 0 : datum,
11758 										 defList, "toast", validnsps, false,
11759 										 operation == AT_ResetRelOptions);
11760 
11761 		(void) heap_reloptions(RELKIND_TOASTVALUE, newOptions, true);
11762 
11763 		memset(repl_val, 0, sizeof(repl_val));
11764 		memset(repl_null, false, sizeof(repl_null));
11765 		memset(repl_repl, false, sizeof(repl_repl));
11766 
11767 		if (newOptions != (Datum) 0)
11768 			repl_val[Anum_pg_class_reloptions - 1] = newOptions;
11769 		else
11770 			repl_null[Anum_pg_class_reloptions - 1] = true;
11771 
11772 		repl_repl[Anum_pg_class_reloptions - 1] = true;
11773 
11774 		newtuple = heap_modify_tuple(tuple, RelationGetDescr(pgclass),
11775 									 repl_val, repl_null, repl_repl);
11776 
11777 		CatalogTupleUpdate(pgclass, &newtuple->t_self, newtuple);
11778 
11779 		InvokeObjectPostAlterHookArg(RelationRelationId,
11780 									 RelationGetRelid(toastrel), 0,
11781 									 InvalidOid, true);
11782 
11783 		heap_freetuple(newtuple);
11784 
11785 		ReleaseSysCache(tuple);
11786 
11787 		heap_close(toastrel, NoLock);
11788 	}
11789 
11790 	heap_close(pgclass, RowExclusiveLock);
11791 }
11792 
11793 /*
11794  * Execute ALTER TABLE SET TABLESPACE for cases where there is no tuple
11795  * rewriting to be done, so we just want to copy the data as fast as possible.
11796  */
11797 static void
ATExecSetTableSpace(Oid tableOid,Oid newTableSpace,LOCKMODE lockmode)11798 ATExecSetTableSpace(Oid tableOid, Oid newTableSpace, LOCKMODE lockmode)
11799 {
11800 	Relation	rel;
11801 	Oid			oldTableSpace;
11802 	Oid			reltoastrelid;
11803 	Oid			newrelfilenode;
11804 	RelFileNode newrnode;
11805 	SMgrRelation dstrel;
11806 	Relation	pg_class;
11807 	HeapTuple	tuple;
11808 	Form_pg_class rd_rel;
11809 	ForkNumber	forkNum;
11810 	List	   *reltoastidxids = NIL;
11811 	ListCell   *lc;
11812 
11813 	/*
11814 	 * Need lock here in case we are recursing to toast table or index
11815 	 */
11816 	rel = relation_open(tableOid, lockmode);
11817 
11818 	/*
11819 	 * No work if no change in tablespace.
11820 	 */
11821 	oldTableSpace = rel->rd_rel->reltablespace;
11822 	if (newTableSpace == oldTableSpace ||
11823 		(newTableSpace == MyDatabaseTableSpace && oldTableSpace == 0))
11824 	{
11825 		InvokeObjectPostAlterHook(RelationRelationId,
11826 								  RelationGetRelid(rel), 0);
11827 
11828 		relation_close(rel, NoLock);
11829 		return;
11830 	}
11831 
11832 	/*
11833 	 * We cannot support moving mapped relations into different tablespaces.
11834 	 * (In particular this eliminates all shared catalogs.)
11835 	 */
11836 	if (RelationIsMapped(rel))
11837 		ereport(ERROR,
11838 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
11839 				 errmsg("cannot move system relation \"%s\"",
11840 						RelationGetRelationName(rel))));
11841 
11842 	/* Can't move a non-shared relation into pg_global */
11843 	if (newTableSpace == GLOBALTABLESPACE_OID)
11844 		ereport(ERROR,
11845 				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
11846 				 errmsg("only shared relations can be placed in pg_global tablespace")));
11847 
11848 	/*
11849 	 * Don't allow moving temp tables of other backends ... their local buffer
11850 	 * manager is not going to cope.
11851 	 */
11852 	if (RELATION_IS_OTHER_TEMP(rel))
11853 		ereport(ERROR,
11854 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
11855 				 errmsg("cannot move temporary tables of other sessions")));
11856 
11857 	reltoastrelid = rel->rd_rel->reltoastrelid;
11858 	/* Fetch the list of indexes on toast relation if necessary */
11859 	if (OidIsValid(reltoastrelid))
11860 	{
11861 		Relation	toastRel = relation_open(reltoastrelid, lockmode);
11862 
11863 		reltoastidxids = RelationGetIndexList(toastRel);
11864 		relation_close(toastRel, lockmode);
11865 	}
11866 
11867 	/* Get a modifiable copy of the relation's pg_class row */
11868 	pg_class = heap_open(RelationRelationId, RowExclusiveLock);
11869 
11870 	tuple = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(tableOid));
11871 	if (!HeapTupleIsValid(tuple))
11872 		elog(ERROR, "cache lookup failed for relation %u", tableOid);
11873 	rd_rel = (Form_pg_class) GETSTRUCT(tuple);
11874 
11875 	/*
11876 	 * Since we copy the file directly without looking at the shared buffers,
11877 	 * we'd better first flush out any pages of the source relation that are
11878 	 * in shared buffers.  We assume no new changes will be made while we are
11879 	 * holding exclusive lock on the rel.
11880 	 */
11881 	FlushRelationBuffers(rel);
11882 
11883 	/*
11884 	 * Relfilenodes are not unique in databases across tablespaces, so we need
11885 	 * to allocate a new one in the new tablespace.
11886 	 */
11887 	newrelfilenode = GetNewRelFileNode(newTableSpace, NULL,
11888 									   rel->rd_rel->relpersistence);
11889 
11890 	/* Open old and new relation */
11891 	newrnode = rel->rd_node;
11892 	newrnode.relNode = newrelfilenode;
11893 	newrnode.spcNode = newTableSpace;
11894 	dstrel = smgropen(newrnode, rel->rd_backend);
11895 
11896 	RelationOpenSmgr(rel);
11897 
11898 	/*
11899 	 * Create and copy all forks of the relation, and schedule unlinking of
11900 	 * old physical files.
11901 	 *
11902 	 * NOTE: any conflict in relfilenode value will be caught in
11903 	 * RelationCreateStorage().
11904 	 */
11905 	RelationCreateStorage(newrnode, rel->rd_rel->relpersistence);
11906 
11907 	/* copy main fork */
11908 	copy_relation_data(rel->rd_smgr, dstrel, MAIN_FORKNUM,
11909 					   rel->rd_rel->relpersistence);
11910 
11911 	/* copy those extra forks that exist */
11912 	for (forkNum = MAIN_FORKNUM + 1; forkNum <= MAX_FORKNUM; forkNum++)
11913 	{
11914 		if (smgrexists(rel->rd_smgr, forkNum))
11915 		{
11916 			smgrcreate(dstrel, forkNum, false);
11917 
11918 			/*
11919 			 * WAL log creation if the relation is persistent, or this is the
11920 			 * init fork of an unlogged relation.
11921 			 */
11922 			if (rel->rd_rel->relpersistence == RELPERSISTENCE_PERMANENT ||
11923 				(rel->rd_rel->relpersistence == RELPERSISTENCE_UNLOGGED &&
11924 				 forkNum == INIT_FORKNUM))
11925 				log_smgrcreate(&newrnode, forkNum);
11926 			copy_relation_data(rel->rd_smgr, dstrel, forkNum,
11927 							   rel->rd_rel->relpersistence);
11928 		}
11929 	}
11930 
11931 	/* drop old relation, and close new one */
11932 	RelationDropStorage(rel);
11933 	smgrclose(dstrel);
11934 
11935 	/* update the pg_class row */
11936 	rd_rel->reltablespace = (newTableSpace == MyDatabaseTableSpace) ? InvalidOid : newTableSpace;
11937 	rd_rel->relfilenode = newrelfilenode;
11938 	CatalogTupleUpdate(pg_class, &tuple->t_self, tuple);
11939 
11940 	InvokeObjectPostAlterHook(RelationRelationId, RelationGetRelid(rel), 0);
11941 
11942 	heap_freetuple(tuple);
11943 
11944 	heap_close(pg_class, RowExclusiveLock);
11945 
11946 	relation_close(rel, NoLock);
11947 
11948 	/* Make sure the reltablespace change is visible */
11949 	CommandCounterIncrement();
11950 
11951 	/* Move associated toast relation and/or indexes, too */
11952 	if (OidIsValid(reltoastrelid))
11953 		ATExecSetTableSpace(reltoastrelid, newTableSpace, lockmode);
11954 	foreach(lc, reltoastidxids)
11955 		ATExecSetTableSpace(lfirst_oid(lc), newTableSpace, lockmode);
11956 
11957 	/* Clean up */
11958 	list_free(reltoastidxids);
11959 }
11960 
11961 /*
11962  * Special handling of ALTER TABLE SET TABLESPACE for partitioned indexes,
11963  * which have no storage (so not handled in Phase 3 like other relation types)
11964  */
11965 static void
ATExecPartedIdxSetTableSpace(Relation rel,Oid newTableSpace)11966 ATExecPartedIdxSetTableSpace(Relation rel, Oid newTableSpace)
11967 {
11968 	HeapTuple	tuple;
11969 	Oid			oldTableSpace;
11970 	Relation	pg_class;
11971 	Form_pg_class rd_rel;
11972 	Oid			indexOid = RelationGetRelid(rel);
11973 
11974 	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_INDEX);
11975 
11976 	/* Can't allow a non-shared relation in pg_global */
11977 	if (newTableSpace == GLOBALTABLESPACE_OID)
11978 		ereport(ERROR,
11979 		(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
11980 			errmsg("only shared relations can be placed in pg_global tablespace")));
11981 
11982 	/*
11983 	 * No work if no change in tablespace.
11984 	 */
11985 	oldTableSpace = rel->rd_rel->reltablespace;
11986 	if (newTableSpace == oldTableSpace ||
11987 		(newTableSpace == MyDatabaseTableSpace && oldTableSpace == 0))
11988 	{
11989 		InvokeObjectPostAlterHook(RelationRelationId,
11990 								  indexOid, 0);
11991 		return;
11992 	}
11993 
11994 	/* Get a modifiable copy of the relation's pg_class row */
11995 	pg_class = heap_open(RelationRelationId, RowExclusiveLock);
11996 
11997 	tuple = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(indexOid));
11998 	if (!HeapTupleIsValid(tuple))
11999 		elog(ERROR, "cache lookup failed for relation %u", indexOid);
12000 	rd_rel = (Form_pg_class) GETSTRUCT(tuple);
12001 
12002 	/* update the pg_class row */
12003 	rd_rel->reltablespace = (newTableSpace == MyDatabaseTableSpace) ? InvalidOid : newTableSpace;
12004 	CatalogTupleUpdate(pg_class, &tuple->t_self, tuple);
12005 
12006 	/* Record dependency on tablespace */
12007 	changeDependencyOnTablespace(RelationRelationId,
12008 								 indexOid, rd_rel->reltablespace);
12009 
12010 	InvokeObjectPostAlterHook(RelationRelationId, indexOid, 0);
12011 
12012 	heap_freetuple(tuple);
12013 
12014 	heap_close(pg_class, RowExclusiveLock);
12015 
12016 	/* Make sure the reltablespace change is visible */
12017 	CommandCounterIncrement();
12018 }
12019 
12020 /*
12021  * Alter Table ALL ... SET TABLESPACE
12022  *
12023  * Allows a user to move all objects of some type in a given tablespace in the
12024  * current database to another tablespace.  Objects can be chosen based on the
12025  * owner of the object also, to allow users to move only their objects.
12026  * The user must have CREATE rights on the new tablespace, as usual.   The main
12027  * permissions handling is done by the lower-level table move function.
12028  *
12029  * All to-be-moved objects are locked first. If NOWAIT is specified and the
12030  * lock can't be acquired then we ereport(ERROR).
12031  */
12032 Oid
AlterTableMoveAll(AlterTableMoveAllStmt * stmt)12033 AlterTableMoveAll(AlterTableMoveAllStmt *stmt)
12034 {
12035 	List	   *relations = NIL;
12036 	ListCell   *l;
12037 	ScanKeyData key[1];
12038 	Relation	rel;
12039 	HeapScanDesc scan;
12040 	HeapTuple	tuple;
12041 	Oid			orig_tablespaceoid;
12042 	Oid			new_tablespaceoid;
12043 	List	   *role_oids = roleSpecsToIds(stmt->roles);
12044 
12045 	/* Ensure we were not asked to move something we can't */
12046 	if (stmt->objtype != OBJECT_TABLE && stmt->objtype != OBJECT_INDEX &&
12047 		stmt->objtype != OBJECT_MATVIEW)
12048 		ereport(ERROR,
12049 				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
12050 				 errmsg("only tables, indexes, and materialized views exist in tablespaces")));
12051 
12052 	/* Get the orig and new tablespace OIDs */
12053 	orig_tablespaceoid = get_tablespace_oid(stmt->orig_tablespacename, false);
12054 	new_tablespaceoid = get_tablespace_oid(stmt->new_tablespacename, false);
12055 
12056 	/* Can't move shared relations in to or out of pg_global */
12057 	/* This is also checked by ATExecSetTableSpace, but nice to stop earlier */
12058 	if (orig_tablespaceoid == GLOBALTABLESPACE_OID ||
12059 		new_tablespaceoid == GLOBALTABLESPACE_OID)
12060 		ereport(ERROR,
12061 				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
12062 				 errmsg("cannot move relations in to or out of pg_global tablespace")));
12063 
12064 	/*
12065 	 * Must have CREATE rights on the new tablespace, unless it is the
12066 	 * database default tablespace (which all users implicitly have CREATE
12067 	 * rights on).
12068 	 */
12069 	if (OidIsValid(new_tablespaceoid) && new_tablespaceoid != MyDatabaseTableSpace)
12070 	{
12071 		AclResult	aclresult;
12072 
12073 		aclresult = pg_tablespace_aclcheck(new_tablespaceoid, GetUserId(),
12074 										   ACL_CREATE);
12075 		if (aclresult != ACLCHECK_OK)
12076 			aclcheck_error(aclresult, OBJECT_TABLESPACE,
12077 						   get_tablespace_name(new_tablespaceoid));
12078 	}
12079 
12080 	/*
12081 	 * Now that the checks are done, check if we should set either to
12082 	 * InvalidOid because it is our database's default tablespace.
12083 	 */
12084 	if (orig_tablespaceoid == MyDatabaseTableSpace)
12085 		orig_tablespaceoid = InvalidOid;
12086 
12087 	if (new_tablespaceoid == MyDatabaseTableSpace)
12088 		new_tablespaceoid = InvalidOid;
12089 
12090 	/* no-op */
12091 	if (orig_tablespaceoid == new_tablespaceoid)
12092 		return new_tablespaceoid;
12093 
12094 	/*
12095 	 * Walk the list of objects in the tablespace and move them. This will
12096 	 * only find objects in our database, of course.
12097 	 */
12098 	ScanKeyInit(&key[0],
12099 				Anum_pg_class_reltablespace,
12100 				BTEqualStrategyNumber, F_OIDEQ,
12101 				ObjectIdGetDatum(orig_tablespaceoid));
12102 
12103 	rel = heap_open(RelationRelationId, AccessShareLock);
12104 	scan = heap_beginscan_catalog(rel, 1, key);
12105 	while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
12106 	{
12107 		Oid			relOid = HeapTupleGetOid(tuple);
12108 		Form_pg_class relForm;
12109 
12110 		relForm = (Form_pg_class) GETSTRUCT(tuple);
12111 
12112 		/*
12113 		 * Do not move objects in pg_catalog as part of this, if an admin
12114 		 * really wishes to do so, they can issue the individual ALTER
12115 		 * commands directly.
12116 		 *
12117 		 * Also, explicitly avoid any shared tables, temp tables, or TOAST
12118 		 * (TOAST will be moved with the main table).
12119 		 */
12120 		if (IsSystemNamespace(relForm->relnamespace) || relForm->relisshared ||
12121 			isAnyTempNamespace(relForm->relnamespace) ||
12122 			relForm->relnamespace == PG_TOAST_NAMESPACE)
12123 			continue;
12124 
12125 		/* Only move the object type requested */
12126 		if ((stmt->objtype == OBJECT_TABLE &&
12127 			 relForm->relkind != RELKIND_RELATION &&
12128 			 relForm->relkind != RELKIND_PARTITIONED_TABLE) ||
12129 			(stmt->objtype == OBJECT_INDEX &&
12130 			 relForm->relkind != RELKIND_INDEX &&
12131 			 relForm->relkind != RELKIND_PARTITIONED_INDEX) ||
12132 			(stmt->objtype == OBJECT_MATVIEW &&
12133 			 relForm->relkind != RELKIND_MATVIEW))
12134 			continue;
12135 
12136 		/* Check if we are only moving objects owned by certain roles */
12137 		if (role_oids != NIL && !list_member_oid(role_oids, relForm->relowner))
12138 			continue;
12139 
12140 		/*
12141 		 * Handle permissions-checking here since we are locking the tables
12142 		 * and also to avoid doing a bunch of work only to fail part-way. Note
12143 		 * that permissions will also be checked by AlterTableInternal().
12144 		 *
12145 		 * Caller must be considered an owner on the table to move it.
12146 		 */
12147 		if (!pg_class_ownercheck(relOid, GetUserId()))
12148 			aclcheck_error(ACLCHECK_NOT_OWNER, get_relkind_objtype(get_rel_relkind(relOid)),
12149 						   NameStr(relForm->relname));
12150 
12151 		if (stmt->nowait &&
12152 			!ConditionalLockRelationOid(relOid, AccessExclusiveLock))
12153 			ereport(ERROR,
12154 					(errcode(ERRCODE_OBJECT_IN_USE),
12155 					 errmsg("aborting because lock on relation \"%s.%s\" is not available",
12156 							get_namespace_name(relForm->relnamespace),
12157 							NameStr(relForm->relname))));
12158 		else
12159 			LockRelationOid(relOid, AccessExclusiveLock);
12160 
12161 		/* Add to our list of objects to move */
12162 		relations = lappend_oid(relations, relOid);
12163 	}
12164 
12165 	heap_endscan(scan);
12166 	heap_close(rel, AccessShareLock);
12167 
12168 	if (relations == NIL)
12169 		ereport(NOTICE,
12170 				(errcode(ERRCODE_NO_DATA_FOUND),
12171 				 errmsg("no matching relations in tablespace \"%s\" found",
12172 						orig_tablespaceoid == InvalidOid ? "(database default)" :
12173 						get_tablespace_name(orig_tablespaceoid))));
12174 
12175 	/* Everything is locked, loop through and move all of the relations. */
12176 	foreach(l, relations)
12177 	{
12178 		List	   *cmds = NIL;
12179 		AlterTableCmd *cmd = makeNode(AlterTableCmd);
12180 
12181 		cmd->subtype = AT_SetTableSpace;
12182 		cmd->name = stmt->new_tablespacename;
12183 
12184 		cmds = lappend(cmds, cmd);
12185 
12186 		EventTriggerAlterTableStart((Node *) stmt);
12187 		/* OID is set by AlterTableInternal */
12188 		AlterTableInternal(lfirst_oid(l), cmds, false);
12189 		EventTriggerAlterTableEnd();
12190 	}
12191 
12192 	return new_tablespaceoid;
12193 }
12194 
12195 /*
12196  * Copy data, block by block
12197  */
12198 static void
copy_relation_data(SMgrRelation src,SMgrRelation dst,ForkNumber forkNum,char relpersistence)12199 copy_relation_data(SMgrRelation src, SMgrRelation dst,
12200 				   ForkNumber forkNum, char relpersistence)
12201 {
12202 	PGAlignedBlock buf;
12203 	Page		page;
12204 	bool		use_wal;
12205 	bool		copying_initfork;
12206 	BlockNumber nblocks;
12207 	BlockNumber blkno;
12208 
12209 	page = (Page) buf.data;
12210 
12211 	/*
12212 	 * The init fork for an unlogged relation in many respects has to be
12213 	 * treated the same as normal relation, changes need to be WAL logged and
12214 	 * it needs to be synced to disk.
12215 	 */
12216 	copying_initfork = relpersistence == RELPERSISTENCE_UNLOGGED &&
12217 		forkNum == INIT_FORKNUM;
12218 
12219 	/*
12220 	 * We need to log the copied data in WAL iff WAL archiving/streaming is
12221 	 * enabled AND it's a permanent relation.
12222 	 */
12223 	use_wal = XLogIsNeeded() &&
12224 		(relpersistence == RELPERSISTENCE_PERMANENT || copying_initfork);
12225 
12226 	nblocks = smgrnblocks(src, forkNum);
12227 
12228 	for (blkno = 0; blkno < nblocks; blkno++)
12229 	{
12230 		/* If we got a cancel signal during the copy of the data, quit */
12231 		CHECK_FOR_INTERRUPTS();
12232 
12233 		smgrread(src, forkNum, blkno, buf.data);
12234 
12235 		if (!PageIsVerified(page, blkno))
12236 			ereport(ERROR,
12237 					(errcode(ERRCODE_DATA_CORRUPTED),
12238 					 errmsg("invalid page in block %u of relation %s",
12239 							blkno,
12240 							relpathbackend(src->smgr_rnode.node,
12241 										   src->smgr_rnode.backend,
12242 										   forkNum))));
12243 
12244 		/*
12245 		 * WAL-log the copied page. Unfortunately we don't know what kind of a
12246 		 * page this is, so we have to log the full page including any unused
12247 		 * space.
12248 		 */
12249 		if (use_wal)
12250 			log_newpage(&dst->smgr_rnode.node, forkNum, blkno, page, false);
12251 
12252 		PageSetChecksumInplace(page, blkno);
12253 
12254 		/*
12255 		 * Now write the page.  We say isTemp = true even if it's not a temp
12256 		 * rel, because there's no need for smgr to schedule an fsync for this
12257 		 * write; we'll do it ourselves below.
12258 		 */
12259 		smgrextend(dst, forkNum, blkno, buf.data, true);
12260 	}
12261 
12262 	/*
12263 	 * If the rel is WAL-logged, must fsync before commit.  We use heap_sync
12264 	 * to ensure that the toast table gets fsync'd too.  (For a temp or
12265 	 * unlogged rel we don't care since the data will be gone after a crash
12266 	 * anyway.)
12267 	 *
12268 	 * It's obvious that we must do this when not WAL-logging the copy. It's
12269 	 * less obvious that we have to do it even if we did WAL-log the copied
12270 	 * pages. The reason is that since we're copying outside shared buffers, a
12271 	 * CHECKPOINT occurring during the copy has no way to flush the previously
12272 	 * written data to disk (indeed it won't know the new rel even exists).  A
12273 	 * crash later on would replay WAL from the checkpoint, therefore it
12274 	 * wouldn't replay our earlier WAL entries. If we do not fsync those pages
12275 	 * here, they might still not be on disk when the crash occurs.
12276 	 */
12277 	if (relpersistence == RELPERSISTENCE_PERMANENT || copying_initfork)
12278 		smgrimmedsync(dst, forkNum);
12279 }
12280 
12281 /*
12282  * ALTER TABLE ENABLE/DISABLE TRIGGER
12283  *
12284  * We just pass this off to trigger.c.
12285  */
12286 static void
ATExecEnableDisableTrigger(Relation rel,const char * trigname,char fires_when,bool skip_system,LOCKMODE lockmode)12287 ATExecEnableDisableTrigger(Relation rel, const char *trigname,
12288 						   char fires_when, bool skip_system, LOCKMODE lockmode)
12289 {
12290 	EnableDisableTrigger(rel, trigname, fires_when, skip_system, lockmode);
12291 }
12292 
12293 /*
12294  * ALTER TABLE ENABLE/DISABLE RULE
12295  *
12296  * We just pass this off to rewriteDefine.c.
12297  */
12298 static void
ATExecEnableDisableRule(Relation rel,const char * rulename,char fires_when,LOCKMODE lockmode)12299 ATExecEnableDisableRule(Relation rel, const char *rulename,
12300 						char fires_when, LOCKMODE lockmode)
12301 {
12302 	EnableDisableRule(rel, rulename, fires_when);
12303 }
12304 
12305 /*
12306  * ALTER TABLE INHERIT
12307  *
12308  * Add a parent to the child's parents. This verifies that all the columns and
12309  * check constraints of the parent appear in the child and that they have the
12310  * same data types and expressions.
12311  */
12312 static void
ATPrepAddInherit(Relation child_rel)12313 ATPrepAddInherit(Relation child_rel)
12314 {
12315 	if (child_rel->rd_rel->reloftype)
12316 		ereport(ERROR,
12317 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
12318 				 errmsg("cannot change inheritance of typed table")));
12319 
12320 	if (child_rel->rd_rel->relispartition)
12321 		ereport(ERROR,
12322 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
12323 				 errmsg("cannot change inheritance of a partition")));
12324 
12325 	if (child_rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
12326 		ereport(ERROR,
12327 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
12328 				 errmsg("cannot change inheritance of partitioned table")));
12329 }
12330 
12331 /*
12332  * Return the address of the new parent relation.
12333  */
12334 static ObjectAddress
ATExecAddInherit(Relation child_rel,RangeVar * parent,LOCKMODE lockmode)12335 ATExecAddInherit(Relation child_rel, RangeVar *parent, LOCKMODE lockmode)
12336 {
12337 	Relation	parent_rel;
12338 	List	   *children;
12339 	ObjectAddress address;
12340 	const char *trigger_name;
12341 
12342 	/*
12343 	 * A self-exclusive lock is needed here.  See the similar case in
12344 	 * MergeAttributes() for a full explanation.
12345 	 */
12346 	parent_rel = heap_openrv(parent, ShareUpdateExclusiveLock);
12347 
12348 	/*
12349 	 * Must be owner of both parent and child -- child was checked by
12350 	 * ATSimplePermissions call in ATPrepCmd
12351 	 */
12352 	ATSimplePermissions(parent_rel, ATT_TABLE | ATT_FOREIGN_TABLE);
12353 
12354 	/* Permanent rels cannot inherit from temporary ones */
12355 	if (parent_rel->rd_rel->relpersistence == RELPERSISTENCE_TEMP &&
12356 		child_rel->rd_rel->relpersistence != RELPERSISTENCE_TEMP)
12357 		ereport(ERROR,
12358 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
12359 				 errmsg("cannot inherit from temporary relation \"%s\"",
12360 						RelationGetRelationName(parent_rel))));
12361 
12362 	/* If parent rel is temp, it must belong to this session */
12363 	if (parent_rel->rd_rel->relpersistence == RELPERSISTENCE_TEMP &&
12364 		!parent_rel->rd_islocaltemp)
12365 		ereport(ERROR,
12366 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
12367 				 errmsg("cannot inherit from temporary relation of another session")));
12368 
12369 	/* Ditto for the child */
12370 	if (child_rel->rd_rel->relpersistence == RELPERSISTENCE_TEMP &&
12371 		!child_rel->rd_islocaltemp)
12372 		ereport(ERROR,
12373 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
12374 				 errmsg("cannot inherit to temporary relation of another session")));
12375 
12376 	/* Prevent partitioned tables from becoming inheritance parents */
12377 	if (parent_rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
12378 		ereport(ERROR,
12379 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
12380 				 errmsg("cannot inherit from partitioned table \"%s\"",
12381 						parent->relname)));
12382 
12383 	/* Likewise for partitions */
12384 	if (parent_rel->rd_rel->relispartition)
12385 		ereport(ERROR,
12386 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
12387 				 errmsg("cannot inherit from a partition")));
12388 
12389 	/*
12390 	 * Prevent circularity by seeing if proposed parent inherits from child.
12391 	 * (In particular, this disallows making a rel inherit from itself.)
12392 	 *
12393 	 * This is not completely bulletproof because of race conditions: in
12394 	 * multi-level inheritance trees, someone else could concurrently be
12395 	 * making another inheritance link that closes the loop but does not join
12396 	 * either of the rels we have locked.  Preventing that seems to require
12397 	 * exclusive locks on the entire inheritance tree, which is a cure worse
12398 	 * than the disease.  find_all_inheritors() will cope with circularity
12399 	 * anyway, so don't sweat it too much.
12400 	 *
12401 	 * We use weakest lock we can on child's children, namely AccessShareLock.
12402 	 */
12403 	children = find_all_inheritors(RelationGetRelid(child_rel),
12404 								   AccessShareLock, NULL);
12405 
12406 	if (list_member_oid(children, RelationGetRelid(parent_rel)))
12407 		ereport(ERROR,
12408 				(errcode(ERRCODE_DUPLICATE_TABLE),
12409 				 errmsg("circular inheritance not allowed"),
12410 				 errdetail("\"%s\" is already a child of \"%s\".",
12411 						   parent->relname,
12412 						   RelationGetRelationName(child_rel))));
12413 
12414 	/* If parent has OIDs then child must have OIDs */
12415 	if (parent_rel->rd_rel->relhasoids && !child_rel->rd_rel->relhasoids)
12416 		ereport(ERROR,
12417 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
12418 				 errmsg("table \"%s\" without OIDs cannot inherit from table \"%s\" with OIDs",
12419 						RelationGetRelationName(child_rel),
12420 						RelationGetRelationName(parent_rel))));
12421 
12422 	/*
12423 	 * If child_rel has row-level triggers with transition tables, we
12424 	 * currently don't allow it to become an inheritance child.  See also
12425 	 * prohibitions in ATExecAttachPartition() and CreateTrigger().
12426 	 */
12427 	trigger_name = FindTriggerIncompatibleWithInheritance(child_rel->trigdesc);
12428 	if (trigger_name != NULL)
12429 		ereport(ERROR,
12430 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
12431 				 errmsg("trigger \"%s\" prevents table \"%s\" from becoming an inheritance child",
12432 						trigger_name, RelationGetRelationName(child_rel)),
12433 				 errdetail("ROW triggers with transition tables are not supported in inheritance hierarchies")));
12434 
12435 	/* OK to create inheritance */
12436 	CreateInheritance(child_rel, parent_rel);
12437 
12438 	ObjectAddressSet(address, RelationRelationId,
12439 					 RelationGetRelid(parent_rel));
12440 
12441 	/* keep our lock on the parent relation until commit */
12442 	heap_close(parent_rel, NoLock);
12443 
12444 	return address;
12445 }
12446 
12447 /*
12448  * CreateInheritance
12449  *		Catalog manipulation portion of creating inheritance between a child
12450  *		table and a parent table.
12451  *
12452  * Common to ATExecAddInherit() and ATExecAttachPartition().
12453  */
12454 static void
CreateInheritance(Relation child_rel,Relation parent_rel)12455 CreateInheritance(Relation child_rel, Relation parent_rel)
12456 {
12457 	Relation	catalogRelation;
12458 	SysScanDesc scan;
12459 	ScanKeyData key;
12460 	HeapTuple	inheritsTuple;
12461 	int32		inhseqno;
12462 
12463 	/* Note: get RowExclusiveLock because we will write pg_inherits below. */
12464 	catalogRelation = heap_open(InheritsRelationId, RowExclusiveLock);
12465 
12466 	/*
12467 	 * Check for duplicates in the list of parents, and determine the highest
12468 	 * inhseqno already present; we'll use the next one for the new parent.
12469 	 * Also, if proposed child is a partition, it cannot already be
12470 	 * inheriting.
12471 	 *
12472 	 * Note: we do not reject the case where the child already inherits from
12473 	 * the parent indirectly; CREATE TABLE doesn't reject comparable cases.
12474 	 */
12475 	ScanKeyInit(&key,
12476 				Anum_pg_inherits_inhrelid,
12477 				BTEqualStrategyNumber, F_OIDEQ,
12478 				ObjectIdGetDatum(RelationGetRelid(child_rel)));
12479 	scan = systable_beginscan(catalogRelation, InheritsRelidSeqnoIndexId,
12480 							  true, NULL, 1, &key);
12481 
12482 	/* inhseqno sequences start at 1 */
12483 	inhseqno = 0;
12484 	while (HeapTupleIsValid(inheritsTuple = systable_getnext(scan)))
12485 	{
12486 		Form_pg_inherits inh = (Form_pg_inherits) GETSTRUCT(inheritsTuple);
12487 
12488 		if (inh->inhparent == RelationGetRelid(parent_rel))
12489 			ereport(ERROR,
12490 					(errcode(ERRCODE_DUPLICATE_TABLE),
12491 					 errmsg("relation \"%s\" would be inherited from more than once",
12492 							RelationGetRelationName(parent_rel))));
12493 
12494 		if (inh->inhseqno > inhseqno)
12495 			inhseqno = inh->inhseqno;
12496 	}
12497 	systable_endscan(scan);
12498 
12499 	/* Match up the columns and bump attinhcount as needed */
12500 	MergeAttributesIntoExisting(child_rel, parent_rel);
12501 
12502 	/* Match up the constraints and bump coninhcount as needed */
12503 	MergeConstraintsIntoExisting(child_rel, parent_rel);
12504 
12505 	/*
12506 	 * OK, it looks valid.  Make the catalog entries that show inheritance.
12507 	 */
12508 	StoreCatalogInheritance1(RelationGetRelid(child_rel),
12509 							 RelationGetRelid(parent_rel),
12510 							 inhseqno + 1,
12511 							 catalogRelation,
12512 							 parent_rel->rd_rel->relkind ==
12513 							 RELKIND_PARTITIONED_TABLE);
12514 
12515 	/* Now we're done with pg_inherits */
12516 	heap_close(catalogRelation, RowExclusiveLock);
12517 }
12518 
12519 /*
12520  * Obtain the source-text form of the constraint expression for a check
12521  * constraint, given its pg_constraint tuple
12522  */
12523 static char *
decompile_conbin(HeapTuple contup,TupleDesc tupdesc)12524 decompile_conbin(HeapTuple contup, TupleDesc tupdesc)
12525 {
12526 	Form_pg_constraint con;
12527 	bool		isnull;
12528 	Datum		attr;
12529 	Datum		expr;
12530 
12531 	con = (Form_pg_constraint) GETSTRUCT(contup);
12532 	attr = heap_getattr(contup, Anum_pg_constraint_conbin, tupdesc, &isnull);
12533 	if (isnull)
12534 		elog(ERROR, "null conbin for constraint %u", HeapTupleGetOid(contup));
12535 
12536 	expr = DirectFunctionCall2(pg_get_expr, attr,
12537 							   ObjectIdGetDatum(con->conrelid));
12538 	return TextDatumGetCString(expr);
12539 }
12540 
12541 /*
12542  * Determine whether two check constraints are functionally equivalent
12543  *
12544  * The test we apply is to see whether they reverse-compile to the same
12545  * source string.  This insulates us from issues like whether attributes
12546  * have the same physical column numbers in parent and child relations.
12547  */
12548 static bool
constraints_equivalent(HeapTuple a,HeapTuple b,TupleDesc tupleDesc)12549 constraints_equivalent(HeapTuple a, HeapTuple b, TupleDesc tupleDesc)
12550 {
12551 	Form_pg_constraint acon = (Form_pg_constraint) GETSTRUCT(a);
12552 	Form_pg_constraint bcon = (Form_pg_constraint) GETSTRUCT(b);
12553 
12554 	if (acon->condeferrable != bcon->condeferrable ||
12555 		acon->condeferred != bcon->condeferred ||
12556 		strcmp(decompile_conbin(a, tupleDesc),
12557 			   decompile_conbin(b, tupleDesc)) != 0)
12558 		return false;
12559 	else
12560 		return true;
12561 }
12562 
12563 /*
12564  * Check columns in child table match up with columns in parent, and increment
12565  * their attinhcount.
12566  *
12567  * Called by CreateInheritance
12568  *
12569  * Currently all parent columns must be found in child. Missing columns are an
12570  * error.  One day we might consider creating new columns like CREATE TABLE
12571  * does.  However, that is widely unpopular --- in the common use case of
12572  * partitioned tables it's a foot-gun.
12573  *
12574  * The data type must match exactly. If the parent column is NOT NULL then
12575  * the child must be as well. Defaults are not compared, however.
12576  */
12577 static void
MergeAttributesIntoExisting(Relation child_rel,Relation parent_rel)12578 MergeAttributesIntoExisting(Relation child_rel, Relation parent_rel)
12579 {
12580 	Relation	attrrel;
12581 	AttrNumber	parent_attno;
12582 	int			parent_natts;
12583 	TupleDesc	tupleDesc;
12584 	HeapTuple	tuple;
12585 	bool		child_is_partition = false;
12586 
12587 	attrrel = heap_open(AttributeRelationId, RowExclusiveLock);
12588 
12589 	tupleDesc = RelationGetDescr(parent_rel);
12590 	parent_natts = tupleDesc->natts;
12591 
12592 	/* If parent_rel is a partitioned table, child_rel must be a partition */
12593 	if (parent_rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
12594 		child_is_partition = true;
12595 
12596 	for (parent_attno = 1; parent_attno <= parent_natts; parent_attno++)
12597 	{
12598 		Form_pg_attribute attribute = TupleDescAttr(tupleDesc,
12599 													parent_attno - 1);
12600 		char	   *attributeName = NameStr(attribute->attname);
12601 
12602 		/* Ignore dropped columns in the parent. */
12603 		if (attribute->attisdropped)
12604 			continue;
12605 
12606 		/* Find same column in child (matching on column name). */
12607 		tuple = SearchSysCacheCopyAttName(RelationGetRelid(child_rel),
12608 										  attributeName);
12609 		if (HeapTupleIsValid(tuple))
12610 		{
12611 			/* Check they are same type, typmod, and collation */
12612 			Form_pg_attribute childatt = (Form_pg_attribute) GETSTRUCT(tuple);
12613 
12614 			if (attribute->atttypid != childatt->atttypid ||
12615 				attribute->atttypmod != childatt->atttypmod)
12616 				ereport(ERROR,
12617 						(errcode(ERRCODE_DATATYPE_MISMATCH),
12618 						 errmsg("child table \"%s\" has different type for column \"%s\"",
12619 								RelationGetRelationName(child_rel),
12620 								attributeName)));
12621 
12622 			if (attribute->attcollation != childatt->attcollation)
12623 				ereport(ERROR,
12624 						(errcode(ERRCODE_COLLATION_MISMATCH),
12625 						 errmsg("child table \"%s\" has different collation for column \"%s\"",
12626 								RelationGetRelationName(child_rel),
12627 								attributeName)));
12628 
12629 			/*
12630 			 * Check child doesn't discard NOT NULL property.  (Other
12631 			 * constraints are checked elsewhere.)
12632 			 */
12633 			if (attribute->attnotnull && !childatt->attnotnull)
12634 				ereport(ERROR,
12635 						(errcode(ERRCODE_DATATYPE_MISMATCH),
12636 						 errmsg("column \"%s\" in child table must be marked NOT NULL",
12637 								attributeName)));
12638 
12639 			/*
12640 			 * OK, bump the child column's inheritance count.  (If we fail
12641 			 * later on, this change will just roll back.)
12642 			 */
12643 			childatt->attinhcount++;
12644 
12645 			/*
12646 			 * In case of partitions, we must enforce that value of attislocal
12647 			 * is same in all partitions. (Note: there are only inherited
12648 			 * attributes in partitions)
12649 			 */
12650 			if (child_is_partition)
12651 			{
12652 				Assert(childatt->attinhcount == 1);
12653 				childatt->attislocal = false;
12654 			}
12655 
12656 			CatalogTupleUpdate(attrrel, &tuple->t_self, tuple);
12657 			heap_freetuple(tuple);
12658 		}
12659 		else
12660 		{
12661 			ereport(ERROR,
12662 					(errcode(ERRCODE_DATATYPE_MISMATCH),
12663 					 errmsg("child table is missing column \"%s\"",
12664 							attributeName)));
12665 		}
12666 	}
12667 
12668 	/*
12669 	 * If the parent has an OID column, so must the child, and we'd better
12670 	 * update the child's attinhcount and attislocal the same as for normal
12671 	 * columns.  We needn't check data type or not-nullness though.
12672 	 */
12673 	if (tupleDesc->tdhasoid)
12674 	{
12675 		/*
12676 		 * Here we match by column number not name; the match *must* be the
12677 		 * system column, not some random column named "oid".
12678 		 */
12679 		tuple = SearchSysCacheCopy2(ATTNUM,
12680 									ObjectIdGetDatum(RelationGetRelid(child_rel)),
12681 									Int16GetDatum(ObjectIdAttributeNumber));
12682 		if (HeapTupleIsValid(tuple))
12683 		{
12684 			Form_pg_attribute childatt = (Form_pg_attribute) GETSTRUCT(tuple);
12685 
12686 			/* See comments above; these changes should be the same */
12687 			childatt->attinhcount++;
12688 
12689 			if (child_is_partition)
12690 			{
12691 				Assert(childatt->attinhcount == 1);
12692 				childatt->attislocal = false;
12693 			}
12694 
12695 			CatalogTupleUpdate(attrrel, &tuple->t_self, tuple);
12696 			heap_freetuple(tuple);
12697 		}
12698 		else
12699 		{
12700 			ereport(ERROR,
12701 					(errcode(ERRCODE_DATATYPE_MISMATCH),
12702 					 errmsg("child table is missing column \"%s\"",
12703 							"oid")));
12704 		}
12705 	}
12706 
12707 	heap_close(attrrel, RowExclusiveLock);
12708 }
12709 
12710 /*
12711  * Check constraints in child table match up with constraints in parent,
12712  * and increment their coninhcount.
12713  *
12714  * Constraints that are marked ONLY in the parent are ignored.
12715  *
12716  * Called by CreateInheritance
12717  *
12718  * Currently all constraints in parent must be present in the child. One day we
12719  * may consider adding new constraints like CREATE TABLE does.
12720  *
12721  * XXX This is O(N^2) which may be an issue with tables with hundreds of
12722  * constraints. As long as tables have more like 10 constraints it shouldn't be
12723  * a problem though. Even 100 constraints ought not be the end of the world.
12724  *
12725  * XXX See MergeWithExistingConstraint too if you change this code.
12726  */
12727 static void
MergeConstraintsIntoExisting(Relation child_rel,Relation parent_rel)12728 MergeConstraintsIntoExisting(Relation child_rel, Relation parent_rel)
12729 {
12730 	Relation	catalog_relation;
12731 	TupleDesc	tuple_desc;
12732 	SysScanDesc parent_scan;
12733 	ScanKeyData parent_key;
12734 	HeapTuple	parent_tuple;
12735 	bool		child_is_partition = false;
12736 
12737 	catalog_relation = heap_open(ConstraintRelationId, RowExclusiveLock);
12738 	tuple_desc = RelationGetDescr(catalog_relation);
12739 
12740 	/* If parent_rel is a partitioned table, child_rel must be a partition */
12741 	if (parent_rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
12742 		child_is_partition = true;
12743 
12744 	/* Outer loop scans through the parent's constraint definitions */
12745 	ScanKeyInit(&parent_key,
12746 				Anum_pg_constraint_conrelid,
12747 				BTEqualStrategyNumber, F_OIDEQ,
12748 				ObjectIdGetDatum(RelationGetRelid(parent_rel)));
12749 	parent_scan = systable_beginscan(catalog_relation, ConstraintRelidTypidNameIndexId,
12750 									 true, NULL, 1, &parent_key);
12751 
12752 	while (HeapTupleIsValid(parent_tuple = systable_getnext(parent_scan)))
12753 	{
12754 		Form_pg_constraint parent_con = (Form_pg_constraint) GETSTRUCT(parent_tuple);
12755 		SysScanDesc child_scan;
12756 		ScanKeyData child_key;
12757 		HeapTuple	child_tuple;
12758 		bool		found = false;
12759 
12760 		if (parent_con->contype != CONSTRAINT_CHECK)
12761 			continue;
12762 
12763 		/* if the parent's constraint is marked NO INHERIT, it's not inherited */
12764 		if (parent_con->connoinherit)
12765 			continue;
12766 
12767 		/* Search for a child constraint matching this one */
12768 		ScanKeyInit(&child_key,
12769 					Anum_pg_constraint_conrelid,
12770 					BTEqualStrategyNumber, F_OIDEQ,
12771 					ObjectIdGetDatum(RelationGetRelid(child_rel)));
12772 		child_scan = systable_beginscan(catalog_relation, ConstraintRelidTypidNameIndexId,
12773 										true, NULL, 1, &child_key);
12774 
12775 		while (HeapTupleIsValid(child_tuple = systable_getnext(child_scan)))
12776 		{
12777 			Form_pg_constraint child_con = (Form_pg_constraint) GETSTRUCT(child_tuple);
12778 			HeapTuple	child_copy;
12779 
12780 			if (child_con->contype != CONSTRAINT_CHECK)
12781 				continue;
12782 
12783 			if (strcmp(NameStr(parent_con->conname),
12784 					   NameStr(child_con->conname)) != 0)
12785 				continue;
12786 
12787 			if (!constraints_equivalent(parent_tuple, child_tuple, tuple_desc))
12788 				ereport(ERROR,
12789 						(errcode(ERRCODE_DATATYPE_MISMATCH),
12790 						 errmsg("child table \"%s\" has different definition for check constraint \"%s\"",
12791 								RelationGetRelationName(child_rel),
12792 								NameStr(parent_con->conname))));
12793 
12794 			/* If the child constraint is "no inherit" then cannot merge */
12795 			if (child_con->connoinherit)
12796 				ereport(ERROR,
12797 						(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
12798 						 errmsg("constraint \"%s\" conflicts with non-inherited constraint on child table \"%s\"",
12799 								NameStr(child_con->conname),
12800 								RelationGetRelationName(child_rel))));
12801 
12802 			/*
12803 			 * If the child constraint is "not valid" then cannot merge with a
12804 			 * valid parent constraint
12805 			 */
12806 			if (parent_con->convalidated && !child_con->convalidated)
12807 				ereport(ERROR,
12808 						(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
12809 						 errmsg("constraint \"%s\" conflicts with NOT VALID constraint on child table \"%s\"",
12810 								NameStr(child_con->conname),
12811 								RelationGetRelationName(child_rel))));
12812 
12813 			/*
12814 			 * OK, bump the child constraint's inheritance count.  (If we fail
12815 			 * later on, this change will just roll back.)
12816 			 */
12817 			child_copy = heap_copytuple(child_tuple);
12818 			child_con = (Form_pg_constraint) GETSTRUCT(child_copy);
12819 			child_con->coninhcount++;
12820 
12821 			/*
12822 			 * In case of partitions, an inherited constraint must be
12823 			 * inherited only once since it cannot have multiple parents and
12824 			 * it is never considered local.
12825 			 */
12826 			if (child_is_partition)
12827 			{
12828 				Assert(child_con->coninhcount == 1);
12829 				child_con->conislocal = false;
12830 			}
12831 
12832 			CatalogTupleUpdate(catalog_relation, &child_copy->t_self, child_copy);
12833 			heap_freetuple(child_copy);
12834 
12835 			found = true;
12836 			break;
12837 		}
12838 
12839 		systable_endscan(child_scan);
12840 
12841 		if (!found)
12842 			ereport(ERROR,
12843 					(errcode(ERRCODE_DATATYPE_MISMATCH),
12844 					 errmsg("child table is missing constraint \"%s\"",
12845 							NameStr(parent_con->conname))));
12846 	}
12847 
12848 	systable_endscan(parent_scan);
12849 	heap_close(catalog_relation, RowExclusiveLock);
12850 }
12851 
12852 /*
12853  * ALTER TABLE NO INHERIT
12854  *
12855  * Return value is the address of the relation that is no longer parent.
12856  */
12857 static ObjectAddress
ATExecDropInherit(Relation rel,RangeVar * parent,LOCKMODE lockmode)12858 ATExecDropInherit(Relation rel, RangeVar *parent, LOCKMODE lockmode)
12859 {
12860 	ObjectAddress address;
12861 	Relation	parent_rel;
12862 
12863 	if (rel->rd_rel->relispartition)
12864 		ereport(ERROR,
12865 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
12866 				 errmsg("cannot change inheritance of a partition")));
12867 
12868 	/*
12869 	 * AccessShareLock on the parent is probably enough, seeing that DROP
12870 	 * TABLE doesn't lock parent tables at all.  We need some lock since we'll
12871 	 * be inspecting the parent's schema.
12872 	 */
12873 	parent_rel = heap_openrv(parent, AccessShareLock);
12874 
12875 	/*
12876 	 * We don't bother to check ownership of the parent table --- ownership of
12877 	 * the child is presumed enough rights.
12878 	 */
12879 
12880 	/* Off to RemoveInheritance() where most of the work happens */
12881 	RemoveInheritance(rel, parent_rel);
12882 
12883 	ObjectAddressSet(address, RelationRelationId,
12884 					 RelationGetRelid(parent_rel));
12885 
12886 	/* keep our lock on the parent relation until commit */
12887 	heap_close(parent_rel, NoLock);
12888 
12889 	return address;
12890 }
12891 
12892 /*
12893  * RemoveInheritance
12894  *
12895  * Drop a parent from the child's parents. This just adjusts the attinhcount
12896  * and attislocal of the columns and removes the pg_inherit and pg_depend
12897  * entries.
12898  *
12899  * If attinhcount goes to 0 then attislocal gets set to true. If it goes back
12900  * up attislocal stays true, which means if a child is ever removed from a
12901  * parent then its columns will never be automatically dropped which may
12902  * surprise. But at least we'll never surprise by dropping columns someone
12903  * isn't expecting to be dropped which would actually mean data loss.
12904  *
12905  * coninhcount and conislocal for inherited constraints are adjusted in
12906  * exactly the same way.
12907  *
12908  * Common to ATExecDropInherit() and ATExecDetachPartition().
12909  */
12910 static void
RemoveInheritance(Relation child_rel,Relation parent_rel)12911 RemoveInheritance(Relation child_rel, Relation parent_rel)
12912 {
12913 	Relation	catalogRelation;
12914 	SysScanDesc scan;
12915 	ScanKeyData key[3];
12916 	HeapTuple	attributeTuple,
12917 				constraintTuple;
12918 	List	   *connames;
12919 	bool		found;
12920 	bool		child_is_partition = false;
12921 
12922 	/* If parent_rel is a partitioned table, child_rel must be a partition */
12923 	if (parent_rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
12924 		child_is_partition = true;
12925 
12926 	found = DeleteInheritsTuple(RelationGetRelid(child_rel),
12927 								RelationGetRelid(parent_rel));
12928 	if (!found)
12929 	{
12930 		if (child_is_partition)
12931 			ereport(ERROR,
12932 					(errcode(ERRCODE_UNDEFINED_TABLE),
12933 					 errmsg("relation \"%s\" is not a partition of relation \"%s\"",
12934 							RelationGetRelationName(child_rel),
12935 							RelationGetRelationName(parent_rel))));
12936 		else
12937 			ereport(ERROR,
12938 					(errcode(ERRCODE_UNDEFINED_TABLE),
12939 					 errmsg("relation \"%s\" is not a parent of relation \"%s\"",
12940 							RelationGetRelationName(parent_rel),
12941 							RelationGetRelationName(child_rel))));
12942 	}
12943 
12944 	/*
12945 	 * Search through child columns looking for ones matching parent rel
12946 	 */
12947 	catalogRelation = heap_open(AttributeRelationId, RowExclusiveLock);
12948 	ScanKeyInit(&key[0],
12949 				Anum_pg_attribute_attrelid,
12950 				BTEqualStrategyNumber, F_OIDEQ,
12951 				ObjectIdGetDatum(RelationGetRelid(child_rel)));
12952 	scan = systable_beginscan(catalogRelation, AttributeRelidNumIndexId,
12953 							  true, NULL, 1, key);
12954 	while (HeapTupleIsValid(attributeTuple = systable_getnext(scan)))
12955 	{
12956 		Form_pg_attribute att = (Form_pg_attribute) GETSTRUCT(attributeTuple);
12957 
12958 		/* Ignore if dropped or not inherited */
12959 		if (att->attisdropped)
12960 			continue;
12961 		if (att->attinhcount <= 0)
12962 			continue;
12963 
12964 		if (SearchSysCacheExistsAttName(RelationGetRelid(parent_rel),
12965 										NameStr(att->attname)))
12966 		{
12967 			/* Decrement inhcount and possibly set islocal to true */
12968 			HeapTuple	copyTuple = heap_copytuple(attributeTuple);
12969 			Form_pg_attribute copy_att = (Form_pg_attribute) GETSTRUCT(copyTuple);
12970 
12971 			copy_att->attinhcount--;
12972 			if (copy_att->attinhcount == 0)
12973 				copy_att->attislocal = true;
12974 
12975 			CatalogTupleUpdate(catalogRelation, &copyTuple->t_self, copyTuple);
12976 			heap_freetuple(copyTuple);
12977 		}
12978 	}
12979 	systable_endscan(scan);
12980 	heap_close(catalogRelation, RowExclusiveLock);
12981 
12982 	/*
12983 	 * Likewise, find inherited check constraints and disinherit them. To do
12984 	 * this, we first need a list of the names of the parent's check
12985 	 * constraints.  (We cheat a bit by only checking for name matches,
12986 	 * assuming that the expressions will match.)
12987 	 */
12988 	catalogRelation = heap_open(ConstraintRelationId, RowExclusiveLock);
12989 	ScanKeyInit(&key[0],
12990 				Anum_pg_constraint_conrelid,
12991 				BTEqualStrategyNumber, F_OIDEQ,
12992 				ObjectIdGetDatum(RelationGetRelid(parent_rel)));
12993 	scan = systable_beginscan(catalogRelation, ConstraintRelidTypidNameIndexId,
12994 							  true, NULL, 1, key);
12995 
12996 	connames = NIL;
12997 
12998 	while (HeapTupleIsValid(constraintTuple = systable_getnext(scan)))
12999 	{
13000 		Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(constraintTuple);
13001 
13002 		if (con->contype == CONSTRAINT_CHECK)
13003 			connames = lappend(connames, pstrdup(NameStr(con->conname)));
13004 	}
13005 
13006 	systable_endscan(scan);
13007 
13008 	/* Now scan the child's constraints */
13009 	ScanKeyInit(&key[0],
13010 				Anum_pg_constraint_conrelid,
13011 				BTEqualStrategyNumber, F_OIDEQ,
13012 				ObjectIdGetDatum(RelationGetRelid(child_rel)));
13013 	scan = systable_beginscan(catalogRelation, ConstraintRelidTypidNameIndexId,
13014 							  true, NULL, 1, key);
13015 
13016 	while (HeapTupleIsValid(constraintTuple = systable_getnext(scan)))
13017 	{
13018 		Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(constraintTuple);
13019 		bool		match;
13020 		ListCell   *lc;
13021 
13022 		if (con->contype != CONSTRAINT_CHECK)
13023 			continue;
13024 
13025 		match = false;
13026 		foreach(lc, connames)
13027 		{
13028 			if (strcmp(NameStr(con->conname), (char *) lfirst(lc)) == 0)
13029 			{
13030 				match = true;
13031 				break;
13032 			}
13033 		}
13034 
13035 		if (match)
13036 		{
13037 			/* Decrement inhcount and possibly set islocal to true */
13038 			HeapTuple	copyTuple = heap_copytuple(constraintTuple);
13039 			Form_pg_constraint copy_con = (Form_pg_constraint) GETSTRUCT(copyTuple);
13040 
13041 			if (copy_con->coninhcount <= 0) /* shouldn't happen */
13042 				elog(ERROR, "relation %u has non-inherited constraint \"%s\"",
13043 					 RelationGetRelid(child_rel), NameStr(copy_con->conname));
13044 
13045 			copy_con->coninhcount--;
13046 			if (copy_con->coninhcount == 0)
13047 				copy_con->conislocal = true;
13048 
13049 			CatalogTupleUpdate(catalogRelation, &copyTuple->t_self, copyTuple);
13050 			heap_freetuple(copyTuple);
13051 		}
13052 	}
13053 
13054 	systable_endscan(scan);
13055 	heap_close(catalogRelation, RowExclusiveLock);
13056 
13057 	drop_parent_dependency(RelationGetRelid(child_rel),
13058 						   RelationRelationId,
13059 						   RelationGetRelid(parent_rel),
13060 						   child_dependency_type(child_is_partition));
13061 
13062 	/*
13063 	 * Post alter hook of this inherits. Since object_access_hook doesn't take
13064 	 * multiple object identifiers, we relay oid of parent relation using
13065 	 * auxiliary_id argument.
13066 	 */
13067 	InvokeObjectPostAlterHookArg(InheritsRelationId,
13068 								 RelationGetRelid(child_rel), 0,
13069 								 RelationGetRelid(parent_rel), false);
13070 }
13071 
13072 /*
13073  * Drop the dependency created by StoreCatalogInheritance1 (CREATE TABLE
13074  * INHERITS/ALTER TABLE INHERIT -- refclassid will be RelationRelationId) or
13075  * heap_create_with_catalog (CREATE TABLE OF/ALTER TABLE OF -- refclassid will
13076  * be TypeRelationId).  There's no convenient way to do this, so go trawling
13077  * through pg_depend.
13078  */
13079 static void
drop_parent_dependency(Oid relid,Oid refclassid,Oid refobjid,DependencyType deptype)13080 drop_parent_dependency(Oid relid, Oid refclassid, Oid refobjid,
13081 					   DependencyType deptype)
13082 {
13083 	Relation	catalogRelation;
13084 	SysScanDesc scan;
13085 	ScanKeyData key[3];
13086 	HeapTuple	depTuple;
13087 
13088 	catalogRelation = heap_open(DependRelationId, RowExclusiveLock);
13089 
13090 	ScanKeyInit(&key[0],
13091 				Anum_pg_depend_classid,
13092 				BTEqualStrategyNumber, F_OIDEQ,
13093 				ObjectIdGetDatum(RelationRelationId));
13094 	ScanKeyInit(&key[1],
13095 				Anum_pg_depend_objid,
13096 				BTEqualStrategyNumber, F_OIDEQ,
13097 				ObjectIdGetDatum(relid));
13098 	ScanKeyInit(&key[2],
13099 				Anum_pg_depend_objsubid,
13100 				BTEqualStrategyNumber, F_INT4EQ,
13101 				Int32GetDatum(0));
13102 
13103 	scan = systable_beginscan(catalogRelation, DependDependerIndexId, true,
13104 							  NULL, 3, key);
13105 
13106 	while (HeapTupleIsValid(depTuple = systable_getnext(scan)))
13107 	{
13108 		Form_pg_depend dep = (Form_pg_depend) GETSTRUCT(depTuple);
13109 
13110 		if (dep->refclassid == refclassid &&
13111 			dep->refobjid == refobjid &&
13112 			dep->refobjsubid == 0 &&
13113 			dep->deptype == deptype)
13114 			CatalogTupleDelete(catalogRelation, &depTuple->t_self);
13115 	}
13116 
13117 	systable_endscan(scan);
13118 	heap_close(catalogRelation, RowExclusiveLock);
13119 }
13120 
13121 /*
13122  * ALTER TABLE OF
13123  *
13124  * Attach a table to a composite type, as though it had been created with CREATE
13125  * TABLE OF.  All attname, atttypid, atttypmod and attcollation must match.  The
13126  * subject table must not have inheritance parents.  These restrictions ensure
13127  * that you cannot create a configuration impossible with CREATE TABLE OF alone.
13128  *
13129  * The address of the type is returned.
13130  */
13131 static ObjectAddress
ATExecAddOf(Relation rel,const TypeName * ofTypename,LOCKMODE lockmode)13132 ATExecAddOf(Relation rel, const TypeName *ofTypename, LOCKMODE lockmode)
13133 {
13134 	Oid			relid = RelationGetRelid(rel);
13135 	Type		typetuple;
13136 	Oid			typeid;
13137 	Relation	inheritsRelation,
13138 				relationRelation;
13139 	SysScanDesc scan;
13140 	ScanKeyData key;
13141 	AttrNumber	table_attno,
13142 				type_attno;
13143 	TupleDesc	typeTupleDesc,
13144 				tableTupleDesc;
13145 	ObjectAddress tableobj,
13146 				typeobj;
13147 	HeapTuple	classtuple;
13148 
13149 	/* Validate the type. */
13150 	typetuple = typenameType(NULL, ofTypename, NULL);
13151 	check_of_type(typetuple);
13152 	typeid = HeapTupleGetOid(typetuple);
13153 
13154 	/* Fail if the table has any inheritance parents. */
13155 	inheritsRelation = heap_open(InheritsRelationId, AccessShareLock);
13156 	ScanKeyInit(&key,
13157 				Anum_pg_inherits_inhrelid,
13158 				BTEqualStrategyNumber, F_OIDEQ,
13159 				ObjectIdGetDatum(relid));
13160 	scan = systable_beginscan(inheritsRelation, InheritsRelidSeqnoIndexId,
13161 							  true, NULL, 1, &key);
13162 	if (HeapTupleIsValid(systable_getnext(scan)))
13163 		ereport(ERROR,
13164 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
13165 				 errmsg("typed tables cannot inherit")));
13166 	systable_endscan(scan);
13167 	heap_close(inheritsRelation, AccessShareLock);
13168 
13169 	/*
13170 	 * Check the tuple descriptors for compatibility.  Unlike inheritance, we
13171 	 * require that the order also match.  However, attnotnull need not match.
13172 	 * Also unlike inheritance, we do not require matching relhasoids.
13173 	 */
13174 	typeTupleDesc = lookup_rowtype_tupdesc(typeid, -1);
13175 	tableTupleDesc = RelationGetDescr(rel);
13176 	table_attno = 1;
13177 	for (type_attno = 1; type_attno <= typeTupleDesc->natts; type_attno++)
13178 	{
13179 		Form_pg_attribute type_attr,
13180 					table_attr;
13181 		const char *type_attname,
13182 				   *table_attname;
13183 
13184 		/* Get the next non-dropped type attribute. */
13185 		type_attr = TupleDescAttr(typeTupleDesc, type_attno - 1);
13186 		if (type_attr->attisdropped)
13187 			continue;
13188 		type_attname = NameStr(type_attr->attname);
13189 
13190 		/* Get the next non-dropped table attribute. */
13191 		do
13192 		{
13193 			if (table_attno > tableTupleDesc->natts)
13194 				ereport(ERROR,
13195 						(errcode(ERRCODE_DATATYPE_MISMATCH),
13196 						 errmsg("table is missing column \"%s\"",
13197 								type_attname)));
13198 			table_attr = TupleDescAttr(tableTupleDesc, table_attno - 1);
13199 			table_attno++;
13200 		} while (table_attr->attisdropped);
13201 		table_attname = NameStr(table_attr->attname);
13202 
13203 		/* Compare name. */
13204 		if (strncmp(table_attname, type_attname, NAMEDATALEN) != 0)
13205 			ereport(ERROR,
13206 					(errcode(ERRCODE_DATATYPE_MISMATCH),
13207 					 errmsg("table has column \"%s\" where type requires \"%s\"",
13208 							table_attname, type_attname)));
13209 
13210 		/* Compare type. */
13211 		if (table_attr->atttypid != type_attr->atttypid ||
13212 			table_attr->atttypmod != type_attr->atttypmod ||
13213 			table_attr->attcollation != type_attr->attcollation)
13214 			ereport(ERROR,
13215 					(errcode(ERRCODE_DATATYPE_MISMATCH),
13216 					 errmsg("table \"%s\" has different type for column \"%s\"",
13217 							RelationGetRelationName(rel), type_attname)));
13218 	}
13219 	DecrTupleDescRefCount(typeTupleDesc);
13220 
13221 	/* Any remaining columns at the end of the table had better be dropped. */
13222 	for (; table_attno <= tableTupleDesc->natts; table_attno++)
13223 	{
13224 		Form_pg_attribute table_attr = TupleDescAttr(tableTupleDesc,
13225 													 table_attno - 1);
13226 
13227 		if (!table_attr->attisdropped)
13228 			ereport(ERROR,
13229 					(errcode(ERRCODE_DATATYPE_MISMATCH),
13230 					 errmsg("table has extra column \"%s\"",
13231 							NameStr(table_attr->attname))));
13232 	}
13233 
13234 	/* If the table was already typed, drop the existing dependency. */
13235 	if (rel->rd_rel->reloftype)
13236 		drop_parent_dependency(relid, TypeRelationId, rel->rd_rel->reloftype,
13237 							   DEPENDENCY_NORMAL);
13238 
13239 	/* Record a dependency on the new type. */
13240 	tableobj.classId = RelationRelationId;
13241 	tableobj.objectId = relid;
13242 	tableobj.objectSubId = 0;
13243 	typeobj.classId = TypeRelationId;
13244 	typeobj.objectId = typeid;
13245 	typeobj.objectSubId = 0;
13246 	recordDependencyOn(&tableobj, &typeobj, DEPENDENCY_NORMAL);
13247 
13248 	/* Update pg_class.reloftype */
13249 	relationRelation = heap_open(RelationRelationId, RowExclusiveLock);
13250 	classtuple = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
13251 	if (!HeapTupleIsValid(classtuple))
13252 		elog(ERROR, "cache lookup failed for relation %u", relid);
13253 	((Form_pg_class) GETSTRUCT(classtuple))->reloftype = typeid;
13254 	CatalogTupleUpdate(relationRelation, &classtuple->t_self, classtuple);
13255 
13256 	InvokeObjectPostAlterHook(RelationRelationId, relid, 0);
13257 
13258 	heap_freetuple(classtuple);
13259 	heap_close(relationRelation, RowExclusiveLock);
13260 
13261 	ReleaseSysCache(typetuple);
13262 
13263 	return typeobj;
13264 }
13265 
13266 /*
13267  * ALTER TABLE NOT OF
13268  *
13269  * Detach a typed table from its originating type.  Just clear reloftype and
13270  * remove the dependency.
13271  */
13272 static void
ATExecDropOf(Relation rel,LOCKMODE lockmode)13273 ATExecDropOf(Relation rel, LOCKMODE lockmode)
13274 {
13275 	Oid			relid = RelationGetRelid(rel);
13276 	Relation	relationRelation;
13277 	HeapTuple	tuple;
13278 
13279 	if (!OidIsValid(rel->rd_rel->reloftype))
13280 		ereport(ERROR,
13281 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
13282 				 errmsg("\"%s\" is not a typed table",
13283 						RelationGetRelationName(rel))));
13284 
13285 	/*
13286 	 * We don't bother to check ownership of the type --- ownership of the
13287 	 * table is presumed enough rights.  No lock required on the type, either.
13288 	 */
13289 
13290 	drop_parent_dependency(relid, TypeRelationId, rel->rd_rel->reloftype,
13291 						   DEPENDENCY_NORMAL);
13292 
13293 	/* Clear pg_class.reloftype */
13294 	relationRelation = heap_open(RelationRelationId, RowExclusiveLock);
13295 	tuple = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
13296 	if (!HeapTupleIsValid(tuple))
13297 		elog(ERROR, "cache lookup failed for relation %u", relid);
13298 	((Form_pg_class) GETSTRUCT(tuple))->reloftype = InvalidOid;
13299 	CatalogTupleUpdate(relationRelation, &tuple->t_self, tuple);
13300 
13301 	InvokeObjectPostAlterHook(RelationRelationId, relid, 0);
13302 
13303 	heap_freetuple(tuple);
13304 	heap_close(relationRelation, RowExclusiveLock);
13305 }
13306 
13307 /*
13308  * relation_mark_replica_identity: Update a table's replica identity
13309  *
13310  * Iff ri_type = REPLICA_IDENTITY_INDEX, indexOid must be the Oid of a suitable
13311  * index. Otherwise, it should be InvalidOid.
13312  */
13313 static void
relation_mark_replica_identity(Relation rel,char ri_type,Oid indexOid,bool is_internal)13314 relation_mark_replica_identity(Relation rel, char ri_type, Oid indexOid,
13315 							   bool is_internal)
13316 {
13317 	Relation	pg_index;
13318 	Relation	pg_class;
13319 	HeapTuple	pg_class_tuple;
13320 	HeapTuple	pg_index_tuple;
13321 	Form_pg_class pg_class_form;
13322 	Form_pg_index pg_index_form;
13323 
13324 	ListCell   *index;
13325 
13326 	/*
13327 	 * Check whether relreplident has changed, and update it if so.
13328 	 */
13329 	pg_class = heap_open(RelationRelationId, RowExclusiveLock);
13330 	pg_class_tuple = SearchSysCacheCopy1(RELOID,
13331 										 ObjectIdGetDatum(RelationGetRelid(rel)));
13332 	if (!HeapTupleIsValid(pg_class_tuple))
13333 		elog(ERROR, "cache lookup failed for relation \"%s\"",
13334 			 RelationGetRelationName(rel));
13335 	pg_class_form = (Form_pg_class) GETSTRUCT(pg_class_tuple);
13336 	if (pg_class_form->relreplident != ri_type)
13337 	{
13338 		pg_class_form->relreplident = ri_type;
13339 		CatalogTupleUpdate(pg_class, &pg_class_tuple->t_self, pg_class_tuple);
13340 	}
13341 	heap_close(pg_class, RowExclusiveLock);
13342 	heap_freetuple(pg_class_tuple);
13343 
13344 	/*
13345 	 * Check whether the correct index is marked indisreplident; if so, we're
13346 	 * done.
13347 	 */
13348 	if (OidIsValid(indexOid))
13349 	{
13350 		Assert(ri_type == REPLICA_IDENTITY_INDEX);
13351 
13352 		pg_index_tuple = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(indexOid));
13353 		if (!HeapTupleIsValid(pg_index_tuple))
13354 			elog(ERROR, "cache lookup failed for index %u", indexOid);
13355 		pg_index_form = (Form_pg_index) GETSTRUCT(pg_index_tuple);
13356 
13357 		if (pg_index_form->indisreplident)
13358 		{
13359 			ReleaseSysCache(pg_index_tuple);
13360 			return;
13361 		}
13362 		ReleaseSysCache(pg_index_tuple);
13363 	}
13364 
13365 	/*
13366 	 * Clear the indisreplident flag from any index that had it previously,
13367 	 * and set it for any index that should have it now.
13368 	 */
13369 	pg_index = heap_open(IndexRelationId, RowExclusiveLock);
13370 	foreach(index, RelationGetIndexList(rel))
13371 	{
13372 		Oid			thisIndexOid = lfirst_oid(index);
13373 		bool		dirty = false;
13374 
13375 		pg_index_tuple = SearchSysCacheCopy1(INDEXRELID,
13376 											 ObjectIdGetDatum(thisIndexOid));
13377 		if (!HeapTupleIsValid(pg_index_tuple))
13378 			elog(ERROR, "cache lookup failed for index %u", thisIndexOid);
13379 		pg_index_form = (Form_pg_index) GETSTRUCT(pg_index_tuple);
13380 
13381 		/*
13382 		 * Unset the bit if set.  We know it's wrong because we checked this
13383 		 * earlier.
13384 		 */
13385 		if (pg_index_form->indisreplident)
13386 		{
13387 			dirty = true;
13388 			pg_index_form->indisreplident = false;
13389 		}
13390 		else if (thisIndexOid == indexOid)
13391 		{
13392 			dirty = true;
13393 			pg_index_form->indisreplident = true;
13394 		}
13395 
13396 		if (dirty)
13397 		{
13398 			CatalogTupleUpdate(pg_index, &pg_index_tuple->t_self, pg_index_tuple);
13399 			InvokeObjectPostAlterHookArg(IndexRelationId, thisIndexOid, 0,
13400 										 InvalidOid, is_internal);
13401 		}
13402 		heap_freetuple(pg_index_tuple);
13403 	}
13404 
13405 	heap_close(pg_index, RowExclusiveLock);
13406 }
13407 
13408 /*
13409  * ALTER TABLE <name> REPLICA IDENTITY ...
13410  */
13411 static void
ATExecReplicaIdentity(Relation rel,ReplicaIdentityStmt * stmt,LOCKMODE lockmode)13412 ATExecReplicaIdentity(Relation rel, ReplicaIdentityStmt *stmt, LOCKMODE lockmode)
13413 {
13414 	Oid			indexOid;
13415 	Relation	indexRel;
13416 	int			key;
13417 
13418 	if (stmt->identity_type == REPLICA_IDENTITY_DEFAULT)
13419 	{
13420 		relation_mark_replica_identity(rel, stmt->identity_type, InvalidOid, true);
13421 		return;
13422 	}
13423 	else if (stmt->identity_type == REPLICA_IDENTITY_FULL)
13424 	{
13425 		relation_mark_replica_identity(rel, stmt->identity_type, InvalidOid, true);
13426 		return;
13427 	}
13428 	else if (stmt->identity_type == REPLICA_IDENTITY_NOTHING)
13429 	{
13430 		relation_mark_replica_identity(rel, stmt->identity_type, InvalidOid, true);
13431 		return;
13432 	}
13433 	else if (stmt->identity_type == REPLICA_IDENTITY_INDEX)
13434 	{
13435 		 /* fallthrough */ ;
13436 	}
13437 	else
13438 		elog(ERROR, "unexpected identity type %u", stmt->identity_type);
13439 
13440 
13441 	/* Check that the index exists */
13442 	indexOid = get_relname_relid(stmt->name, rel->rd_rel->relnamespace);
13443 	if (!OidIsValid(indexOid))
13444 		ereport(ERROR,
13445 				(errcode(ERRCODE_UNDEFINED_OBJECT),
13446 				 errmsg("index \"%s\" for table \"%s\" does not exist",
13447 						stmt->name, RelationGetRelationName(rel))));
13448 
13449 	indexRel = index_open(indexOid, ShareLock);
13450 
13451 	/* Check that the index is on the relation we're altering. */
13452 	if (indexRel->rd_index == NULL ||
13453 		indexRel->rd_index->indrelid != RelationGetRelid(rel))
13454 		ereport(ERROR,
13455 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
13456 				 errmsg("\"%s\" is not an index for table \"%s\"",
13457 						RelationGetRelationName(indexRel),
13458 						RelationGetRelationName(rel))));
13459 	/* The AM must support uniqueness, and the index must in fact be unique. */
13460 	if (!indexRel->rd_amroutine->amcanunique ||
13461 		!indexRel->rd_index->indisunique)
13462 		ereport(ERROR,
13463 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
13464 				 errmsg("cannot use non-unique index \"%s\" as replica identity",
13465 						RelationGetRelationName(indexRel))));
13466 	/* Deferred indexes are not guaranteed to be always unique. */
13467 	if (!indexRel->rd_index->indimmediate)
13468 		ereport(ERROR,
13469 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
13470 				 errmsg("cannot use non-immediate index \"%s\" as replica identity",
13471 						RelationGetRelationName(indexRel))));
13472 	/* Expression indexes aren't supported. */
13473 	if (RelationGetIndexExpressions(indexRel) != NIL)
13474 		ereport(ERROR,
13475 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
13476 				 errmsg("cannot use expression index \"%s\" as replica identity",
13477 						RelationGetRelationName(indexRel))));
13478 	/* Predicate indexes aren't supported. */
13479 	if (RelationGetIndexPredicate(indexRel) != NIL)
13480 		ereport(ERROR,
13481 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
13482 				 errmsg("cannot use partial index \"%s\" as replica identity",
13483 						RelationGetRelationName(indexRel))));
13484 	/* And neither are invalid indexes. */
13485 	if (!IndexIsValid(indexRel->rd_index))
13486 		ereport(ERROR,
13487 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
13488 				 errmsg("cannot use invalid index \"%s\" as replica identity",
13489 						RelationGetRelationName(indexRel))));
13490 
13491 	/* Check index for nullable columns. */
13492 	for (key = 0; key < IndexRelationGetNumberOfKeyAttributes(indexRel); key++)
13493 	{
13494 		int16		attno = indexRel->rd_index->indkey.values[key];
13495 		Form_pg_attribute attr;
13496 
13497 		/* Allow OID column to be indexed; it's certainly not nullable */
13498 		if (attno == ObjectIdAttributeNumber)
13499 			continue;
13500 
13501 		/*
13502 		 * Reject any other system columns.  (Going forward, we'll disallow
13503 		 * indexes containing such columns in the first place, but they might
13504 		 * exist in older branches.)
13505 		 */
13506 		if (attno <= 0)
13507 			ereport(ERROR,
13508 					(errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
13509 					 errmsg("index \"%s\" cannot be used as replica identity because column %d is a system column",
13510 							RelationGetRelationName(indexRel), attno)));
13511 
13512 		attr = TupleDescAttr(rel->rd_att, attno - 1);
13513 		if (!attr->attnotnull)
13514 			ereport(ERROR,
13515 					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
13516 					 errmsg("index \"%s\" cannot be used as replica identity because column \"%s\" is nullable",
13517 							RelationGetRelationName(indexRel),
13518 							NameStr(attr->attname))));
13519 	}
13520 
13521 	/* This index is suitable for use as a replica identity. Mark it. */
13522 	relation_mark_replica_identity(rel, stmt->identity_type, indexOid, true);
13523 
13524 	index_close(indexRel, NoLock);
13525 }
13526 
13527 /*
13528  * ALTER TABLE ENABLE/DISABLE ROW LEVEL SECURITY
13529  */
13530 static void
ATExecEnableRowSecurity(Relation rel)13531 ATExecEnableRowSecurity(Relation rel)
13532 {
13533 	Relation	pg_class;
13534 	Oid			relid;
13535 	HeapTuple	tuple;
13536 
13537 	relid = RelationGetRelid(rel);
13538 
13539 	pg_class = heap_open(RelationRelationId, RowExclusiveLock);
13540 
13541 	tuple = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
13542 
13543 	if (!HeapTupleIsValid(tuple))
13544 		elog(ERROR, "cache lookup failed for relation %u", relid);
13545 
13546 	((Form_pg_class) GETSTRUCT(tuple))->relrowsecurity = true;
13547 	CatalogTupleUpdate(pg_class, &tuple->t_self, tuple);
13548 
13549 	heap_close(pg_class, RowExclusiveLock);
13550 	heap_freetuple(tuple);
13551 }
13552 
13553 static void
ATExecDisableRowSecurity(Relation rel)13554 ATExecDisableRowSecurity(Relation rel)
13555 {
13556 	Relation	pg_class;
13557 	Oid			relid;
13558 	HeapTuple	tuple;
13559 
13560 	relid = RelationGetRelid(rel);
13561 
13562 	/* Pull the record for this relation and update it */
13563 	pg_class = heap_open(RelationRelationId, RowExclusiveLock);
13564 
13565 	tuple = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
13566 
13567 	if (!HeapTupleIsValid(tuple))
13568 		elog(ERROR, "cache lookup failed for relation %u", relid);
13569 
13570 	((Form_pg_class) GETSTRUCT(tuple))->relrowsecurity = false;
13571 	CatalogTupleUpdate(pg_class, &tuple->t_self, tuple);
13572 
13573 	heap_close(pg_class, RowExclusiveLock);
13574 	heap_freetuple(tuple);
13575 }
13576 
13577 /*
13578  * ALTER TABLE FORCE/NO FORCE ROW LEVEL SECURITY
13579  */
13580 static void
ATExecForceNoForceRowSecurity(Relation rel,bool force_rls)13581 ATExecForceNoForceRowSecurity(Relation rel, bool force_rls)
13582 {
13583 	Relation	pg_class;
13584 	Oid			relid;
13585 	HeapTuple	tuple;
13586 
13587 	relid = RelationGetRelid(rel);
13588 
13589 	pg_class = heap_open(RelationRelationId, RowExclusiveLock);
13590 
13591 	tuple = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
13592 
13593 	if (!HeapTupleIsValid(tuple))
13594 		elog(ERROR, "cache lookup failed for relation %u", relid);
13595 
13596 	((Form_pg_class) GETSTRUCT(tuple))->relforcerowsecurity = force_rls;
13597 	CatalogTupleUpdate(pg_class, &tuple->t_self, tuple);
13598 
13599 	heap_close(pg_class, RowExclusiveLock);
13600 	heap_freetuple(tuple);
13601 }
13602 
13603 /*
13604  * ALTER FOREIGN TABLE <name> OPTIONS (...)
13605  */
13606 static void
ATExecGenericOptions(Relation rel,List * options)13607 ATExecGenericOptions(Relation rel, List *options)
13608 {
13609 	Relation	ftrel;
13610 	ForeignServer *server;
13611 	ForeignDataWrapper *fdw;
13612 	HeapTuple	tuple;
13613 	bool		isnull;
13614 	Datum		repl_val[Natts_pg_foreign_table];
13615 	bool		repl_null[Natts_pg_foreign_table];
13616 	bool		repl_repl[Natts_pg_foreign_table];
13617 	Datum		datum;
13618 	Form_pg_foreign_table tableform;
13619 
13620 	if (options == NIL)
13621 		return;
13622 
13623 	ftrel = heap_open(ForeignTableRelationId, RowExclusiveLock);
13624 
13625 	tuple = SearchSysCacheCopy1(FOREIGNTABLEREL, rel->rd_id);
13626 	if (!HeapTupleIsValid(tuple))
13627 		ereport(ERROR,
13628 				(errcode(ERRCODE_UNDEFINED_OBJECT),
13629 				 errmsg("foreign table \"%s\" does not exist",
13630 						RelationGetRelationName(rel))));
13631 	tableform = (Form_pg_foreign_table) GETSTRUCT(tuple);
13632 	server = GetForeignServer(tableform->ftserver);
13633 	fdw = GetForeignDataWrapper(server->fdwid);
13634 
13635 	memset(repl_val, 0, sizeof(repl_val));
13636 	memset(repl_null, false, sizeof(repl_null));
13637 	memset(repl_repl, false, sizeof(repl_repl));
13638 
13639 	/* Extract the current options */
13640 	datum = SysCacheGetAttr(FOREIGNTABLEREL,
13641 							tuple,
13642 							Anum_pg_foreign_table_ftoptions,
13643 							&isnull);
13644 	if (isnull)
13645 		datum = PointerGetDatum(NULL);
13646 
13647 	/* Transform the options */
13648 	datum = transformGenericOptions(ForeignTableRelationId,
13649 									datum,
13650 									options,
13651 									fdw->fdwvalidator);
13652 
13653 	if (PointerIsValid(DatumGetPointer(datum)))
13654 		repl_val[Anum_pg_foreign_table_ftoptions - 1] = datum;
13655 	else
13656 		repl_null[Anum_pg_foreign_table_ftoptions - 1] = true;
13657 
13658 	repl_repl[Anum_pg_foreign_table_ftoptions - 1] = true;
13659 
13660 	/* Everything looks good - update the tuple */
13661 
13662 	tuple = heap_modify_tuple(tuple, RelationGetDescr(ftrel),
13663 							  repl_val, repl_null, repl_repl);
13664 
13665 	CatalogTupleUpdate(ftrel, &tuple->t_self, tuple);
13666 
13667 	/*
13668 	 * Invalidate relcache so that all sessions will refresh any cached plans
13669 	 * that might depend on the old options.
13670 	 */
13671 	CacheInvalidateRelcache(rel);
13672 
13673 	InvokeObjectPostAlterHook(ForeignTableRelationId,
13674 							  RelationGetRelid(rel), 0);
13675 
13676 	heap_close(ftrel, RowExclusiveLock);
13677 
13678 	heap_freetuple(tuple);
13679 }
13680 
13681 /*
13682  * Preparation phase for SET LOGGED/UNLOGGED
13683  *
13684  * This verifies that we're not trying to change a temp table.  Also,
13685  * existing foreign key constraints are checked to avoid ending up with
13686  * permanent tables referencing unlogged tables.
13687  *
13688  * Return value is false if the operation is a no-op (in which case the
13689  * checks are skipped), otherwise true.
13690  */
13691 static bool
ATPrepChangePersistence(Relation rel,bool toLogged)13692 ATPrepChangePersistence(Relation rel, bool toLogged)
13693 {
13694 	Relation	pg_constraint;
13695 	HeapTuple	tuple;
13696 	SysScanDesc scan;
13697 	ScanKeyData skey[1];
13698 
13699 	/*
13700 	 * Disallow changing status for a temp table.  Also verify whether we can
13701 	 * get away with doing nothing; in such cases we don't need to run the
13702 	 * checks below, either.
13703 	 */
13704 	switch (rel->rd_rel->relpersistence)
13705 	{
13706 		case RELPERSISTENCE_TEMP:
13707 			ereport(ERROR,
13708 					(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
13709 					 errmsg("cannot change logged status of table \"%s\" because it is temporary",
13710 							RelationGetRelationName(rel)),
13711 					 errtable(rel)));
13712 			break;
13713 		case RELPERSISTENCE_PERMANENT:
13714 			if (toLogged)
13715 				/* nothing to do */
13716 				return false;
13717 			break;
13718 		case RELPERSISTENCE_UNLOGGED:
13719 			if (!toLogged)
13720 				/* nothing to do */
13721 				return false;
13722 			break;
13723 	}
13724 
13725 	/*
13726 	 * Check that the table is not part any publication when changing to
13727 	 * UNLOGGED as UNLOGGED tables can't be published.
13728 	 */
13729 	if (!toLogged &&
13730 		list_length(GetRelationPublications(RelationGetRelid(rel))) > 0)
13731 		ereport(ERROR,
13732 				(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
13733 				 errmsg("cannot change table \"%s\" to unlogged because it is part of a publication",
13734 						RelationGetRelationName(rel)),
13735 				 errdetail("Unlogged relations cannot be replicated.")));
13736 
13737 	/*
13738 	 * Check existing foreign key constraints to preserve the invariant that
13739 	 * permanent tables cannot reference unlogged ones.  Self-referencing
13740 	 * foreign keys can safely be ignored.
13741 	 */
13742 	pg_constraint = heap_open(ConstraintRelationId, AccessShareLock);
13743 
13744 	/*
13745 	 * Scan conrelid if changing to permanent, else confrelid.  This also
13746 	 * determines whether a useful index exists.
13747 	 */
13748 	ScanKeyInit(&skey[0],
13749 				toLogged ? Anum_pg_constraint_conrelid :
13750 				Anum_pg_constraint_confrelid,
13751 				BTEqualStrategyNumber, F_OIDEQ,
13752 				ObjectIdGetDatum(RelationGetRelid(rel)));
13753 	scan = systable_beginscan(pg_constraint,
13754 							  toLogged ? ConstraintRelidTypidNameIndexId : InvalidOid,
13755 							  true, NULL, 1, skey);
13756 
13757 	while (HeapTupleIsValid(tuple = systable_getnext(scan)))
13758 	{
13759 		Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(tuple);
13760 
13761 		if (con->contype == CONSTRAINT_FOREIGN)
13762 		{
13763 			Oid			foreignrelid;
13764 			Relation	foreignrel;
13765 
13766 			/* the opposite end of what we used as scankey */
13767 			foreignrelid = toLogged ? con->confrelid : con->conrelid;
13768 
13769 			/* ignore if self-referencing */
13770 			if (RelationGetRelid(rel) == foreignrelid)
13771 				continue;
13772 
13773 			foreignrel = relation_open(foreignrelid, AccessShareLock);
13774 
13775 			if (toLogged)
13776 			{
13777 				if (foreignrel->rd_rel->relpersistence != RELPERSISTENCE_PERMANENT)
13778 					ereport(ERROR,
13779 							(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
13780 							 errmsg("could not change table \"%s\" to logged because it references unlogged table \"%s\"",
13781 									RelationGetRelationName(rel),
13782 									RelationGetRelationName(foreignrel)),
13783 							 errtableconstraint(rel, NameStr(con->conname))));
13784 			}
13785 			else
13786 			{
13787 				if (foreignrel->rd_rel->relpersistence == RELPERSISTENCE_PERMANENT)
13788 					ereport(ERROR,
13789 							(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
13790 							 errmsg("could not change table \"%s\" to unlogged because it references logged table \"%s\"",
13791 									RelationGetRelationName(rel),
13792 									RelationGetRelationName(foreignrel)),
13793 							 errtableconstraint(rel, NameStr(con->conname))));
13794 			}
13795 
13796 			relation_close(foreignrel, AccessShareLock);
13797 		}
13798 	}
13799 
13800 	systable_endscan(scan);
13801 
13802 	heap_close(pg_constraint, AccessShareLock);
13803 
13804 	return true;
13805 }
13806 
13807 /*
13808  * Execute ALTER TABLE SET SCHEMA
13809  */
13810 ObjectAddress
AlterTableNamespace(AlterObjectSchemaStmt * stmt,Oid * oldschema)13811 AlterTableNamespace(AlterObjectSchemaStmt *stmt, Oid *oldschema)
13812 {
13813 	Relation	rel;
13814 	Oid			relid;
13815 	Oid			oldNspOid;
13816 	Oid			nspOid;
13817 	RangeVar   *newrv;
13818 	ObjectAddresses *objsMoved;
13819 	ObjectAddress myself;
13820 
13821 	relid = RangeVarGetRelidExtended(stmt->relation, AccessExclusiveLock,
13822 									 stmt->missing_ok ? RVR_MISSING_OK : 0,
13823 									 RangeVarCallbackForAlterRelation,
13824 									 (void *) stmt);
13825 
13826 	if (!OidIsValid(relid))
13827 	{
13828 		ereport(NOTICE,
13829 				(errmsg("relation \"%s\" does not exist, skipping",
13830 						stmt->relation->relname)));
13831 		return InvalidObjectAddress;
13832 	}
13833 
13834 	rel = relation_open(relid, NoLock);
13835 
13836 	oldNspOid = RelationGetNamespace(rel);
13837 
13838 	/* If it's an owned sequence, disallow moving it by itself. */
13839 	if (rel->rd_rel->relkind == RELKIND_SEQUENCE)
13840 	{
13841 		Oid			tableId;
13842 		int32		colId;
13843 
13844 		if (sequenceIsOwned(relid, DEPENDENCY_AUTO, &tableId, &colId) ||
13845 			sequenceIsOwned(relid, DEPENDENCY_INTERNAL, &tableId, &colId))
13846 			ereport(ERROR,
13847 					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
13848 					 errmsg("cannot move an owned sequence into another schema"),
13849 					 errdetail("Sequence \"%s\" is linked to table \"%s\".",
13850 							   RelationGetRelationName(rel),
13851 							   get_rel_name(tableId))));
13852 	}
13853 
13854 	/* Get and lock schema OID and check its permissions. */
13855 	newrv = makeRangeVar(stmt->newschema, RelationGetRelationName(rel), -1);
13856 	nspOid = RangeVarGetAndCheckCreationNamespace(newrv, NoLock, NULL);
13857 
13858 	/* common checks on switching namespaces */
13859 	CheckSetNamespace(oldNspOid, nspOid);
13860 
13861 	objsMoved = new_object_addresses();
13862 	AlterTableNamespaceInternal(rel, oldNspOid, nspOid, objsMoved);
13863 	free_object_addresses(objsMoved);
13864 
13865 	ObjectAddressSet(myself, RelationRelationId, relid);
13866 
13867 	if (oldschema)
13868 		*oldschema = oldNspOid;
13869 
13870 	/* close rel, but keep lock until commit */
13871 	relation_close(rel, NoLock);
13872 
13873 	return myself;
13874 }
13875 
13876 /*
13877  * The guts of relocating a table or materialized view to another namespace:
13878  * besides moving the relation itself, its dependent objects are relocated to
13879  * the new schema.
13880  */
13881 void
AlterTableNamespaceInternal(Relation rel,Oid oldNspOid,Oid nspOid,ObjectAddresses * objsMoved)13882 AlterTableNamespaceInternal(Relation rel, Oid oldNspOid, Oid nspOid,
13883 							ObjectAddresses *objsMoved)
13884 {
13885 	Relation	classRel;
13886 
13887 	Assert(objsMoved != NULL);
13888 
13889 	/* OK, modify the pg_class row and pg_depend entry */
13890 	classRel = heap_open(RelationRelationId, RowExclusiveLock);
13891 
13892 	AlterRelationNamespaceInternal(classRel, RelationGetRelid(rel), oldNspOid,
13893 								   nspOid, true, objsMoved);
13894 
13895 	/* Fix the table's row type too */
13896 	AlterTypeNamespaceInternal(rel->rd_rel->reltype,
13897 							   nspOid, false, false, objsMoved);
13898 
13899 	/* Fix other dependent stuff */
13900 	if (rel->rd_rel->relkind == RELKIND_RELATION ||
13901 		rel->rd_rel->relkind == RELKIND_MATVIEW ||
13902 		rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
13903 	{
13904 		AlterIndexNamespaces(classRel, rel, oldNspOid, nspOid, objsMoved);
13905 		AlterSeqNamespaces(classRel, rel, oldNspOid, nspOid,
13906 						   objsMoved, AccessExclusiveLock);
13907 		AlterConstraintNamespaces(RelationGetRelid(rel), oldNspOid, nspOid,
13908 								  false, objsMoved);
13909 	}
13910 
13911 	heap_close(classRel, RowExclusiveLock);
13912 }
13913 
13914 /*
13915  * The guts of relocating a relation to another namespace: fix the pg_class
13916  * entry, and the pg_depend entry if any.  Caller must already have
13917  * opened and write-locked pg_class.
13918  */
13919 void
AlterRelationNamespaceInternal(Relation classRel,Oid relOid,Oid oldNspOid,Oid newNspOid,bool hasDependEntry,ObjectAddresses * objsMoved)13920 AlterRelationNamespaceInternal(Relation classRel, Oid relOid,
13921 							   Oid oldNspOid, Oid newNspOid,
13922 							   bool hasDependEntry,
13923 							   ObjectAddresses *objsMoved)
13924 {
13925 	HeapTuple	classTup;
13926 	Form_pg_class classForm;
13927 	ObjectAddress thisobj;
13928 	bool		already_done = false;
13929 
13930 	classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relOid));
13931 	if (!HeapTupleIsValid(classTup))
13932 		elog(ERROR, "cache lookup failed for relation %u", relOid);
13933 	classForm = (Form_pg_class) GETSTRUCT(classTup);
13934 
13935 	Assert(classForm->relnamespace == oldNspOid);
13936 
13937 	thisobj.classId = RelationRelationId;
13938 	thisobj.objectId = relOid;
13939 	thisobj.objectSubId = 0;
13940 
13941 	/*
13942 	 * If the object has already been moved, don't move it again.  If it's
13943 	 * already in the right place, don't move it, but still fire the object
13944 	 * access hook.
13945 	 */
13946 	already_done = object_address_present(&thisobj, objsMoved);
13947 	if (!already_done && oldNspOid != newNspOid)
13948 	{
13949 		/* check for duplicate name (more friendly than unique-index failure) */
13950 		if (get_relname_relid(NameStr(classForm->relname),
13951 							  newNspOid) != InvalidOid)
13952 			ereport(ERROR,
13953 					(errcode(ERRCODE_DUPLICATE_TABLE),
13954 					 errmsg("relation \"%s\" already exists in schema \"%s\"",
13955 							NameStr(classForm->relname),
13956 							get_namespace_name(newNspOid))));
13957 
13958 		/* classTup is a copy, so OK to scribble on */
13959 		classForm->relnamespace = newNspOid;
13960 
13961 		CatalogTupleUpdate(classRel, &classTup->t_self, classTup);
13962 
13963 		/* Update dependency on schema if caller said so */
13964 		if (hasDependEntry &&
13965 			changeDependencyFor(RelationRelationId,
13966 								relOid,
13967 								NamespaceRelationId,
13968 								oldNspOid,
13969 								newNspOid) != 1)
13970 			elog(ERROR, "failed to change schema dependency for relation \"%s\"",
13971 				 NameStr(classForm->relname));
13972 	}
13973 	if (!already_done)
13974 	{
13975 		add_exact_object_address(&thisobj, objsMoved);
13976 
13977 		InvokeObjectPostAlterHook(RelationRelationId, relOid, 0);
13978 	}
13979 
13980 	heap_freetuple(classTup);
13981 }
13982 
13983 /*
13984  * Move all indexes for the specified relation to another namespace.
13985  *
13986  * Note: we assume adequate permission checking was done by the caller,
13987  * and that the caller has a suitable lock on the owning relation.
13988  */
13989 static void
AlterIndexNamespaces(Relation classRel,Relation rel,Oid oldNspOid,Oid newNspOid,ObjectAddresses * objsMoved)13990 AlterIndexNamespaces(Relation classRel, Relation rel,
13991 					 Oid oldNspOid, Oid newNspOid, ObjectAddresses *objsMoved)
13992 {
13993 	List	   *indexList;
13994 	ListCell   *l;
13995 
13996 	indexList = RelationGetIndexList(rel);
13997 
13998 	foreach(l, indexList)
13999 	{
14000 		Oid			indexOid = lfirst_oid(l);
14001 		ObjectAddress thisobj;
14002 
14003 		thisobj.classId = RelationRelationId;
14004 		thisobj.objectId = indexOid;
14005 		thisobj.objectSubId = 0;
14006 
14007 		/*
14008 		 * Note: currently, the index will not have its own dependency on the
14009 		 * namespace, so we don't need to do changeDependencyFor(). There's no
14010 		 * row type in pg_type, either.
14011 		 *
14012 		 * XXX this objsMoved test may be pointless -- surely we have a single
14013 		 * dependency link from a relation to each index?
14014 		 */
14015 		if (!object_address_present(&thisobj, objsMoved))
14016 		{
14017 			AlterRelationNamespaceInternal(classRel, indexOid,
14018 										   oldNspOid, newNspOid,
14019 										   false, objsMoved);
14020 			add_exact_object_address(&thisobj, objsMoved);
14021 		}
14022 	}
14023 
14024 	list_free(indexList);
14025 }
14026 
14027 /*
14028  * Move all identity and SERIAL-column sequences of the specified relation to another
14029  * namespace.
14030  *
14031  * Note: we assume adequate permission checking was done by the caller,
14032  * and that the caller has a suitable lock on the owning relation.
14033  */
14034 static void
AlterSeqNamespaces(Relation classRel,Relation rel,Oid oldNspOid,Oid newNspOid,ObjectAddresses * objsMoved,LOCKMODE lockmode)14035 AlterSeqNamespaces(Relation classRel, Relation rel,
14036 				   Oid oldNspOid, Oid newNspOid, ObjectAddresses *objsMoved,
14037 				   LOCKMODE lockmode)
14038 {
14039 	Relation	depRel;
14040 	SysScanDesc scan;
14041 	ScanKeyData key[2];
14042 	HeapTuple	tup;
14043 
14044 	/*
14045 	 * SERIAL sequences are those having an auto dependency on one of the
14046 	 * table's columns (we don't care *which* column, exactly).
14047 	 */
14048 	depRel = heap_open(DependRelationId, AccessShareLock);
14049 
14050 	ScanKeyInit(&key[0],
14051 				Anum_pg_depend_refclassid,
14052 				BTEqualStrategyNumber, F_OIDEQ,
14053 				ObjectIdGetDatum(RelationRelationId));
14054 	ScanKeyInit(&key[1],
14055 				Anum_pg_depend_refobjid,
14056 				BTEqualStrategyNumber, F_OIDEQ,
14057 				ObjectIdGetDatum(RelationGetRelid(rel)));
14058 	/* we leave refobjsubid unspecified */
14059 
14060 	scan = systable_beginscan(depRel, DependReferenceIndexId, true,
14061 							  NULL, 2, key);
14062 
14063 	while (HeapTupleIsValid(tup = systable_getnext(scan)))
14064 	{
14065 		Form_pg_depend depForm = (Form_pg_depend) GETSTRUCT(tup);
14066 		Relation	seqRel;
14067 
14068 		/* skip dependencies other than auto dependencies on columns */
14069 		if (depForm->refobjsubid == 0 ||
14070 			depForm->classid != RelationRelationId ||
14071 			depForm->objsubid != 0 ||
14072 			!(depForm->deptype == DEPENDENCY_AUTO || depForm->deptype == DEPENDENCY_INTERNAL))
14073 			continue;
14074 
14075 		/* Use relation_open just in case it's an index */
14076 		seqRel = relation_open(depForm->objid, lockmode);
14077 
14078 		/* skip non-sequence relations */
14079 		if (RelationGetForm(seqRel)->relkind != RELKIND_SEQUENCE)
14080 		{
14081 			/* No need to keep the lock */
14082 			relation_close(seqRel, lockmode);
14083 			continue;
14084 		}
14085 
14086 		/* Fix the pg_class and pg_depend entries */
14087 		AlterRelationNamespaceInternal(classRel, depForm->objid,
14088 									   oldNspOid, newNspOid,
14089 									   true, objsMoved);
14090 
14091 		/*
14092 		 * Sequences have entries in pg_type. We need to be careful to move
14093 		 * them to the new namespace, too.
14094 		 */
14095 		AlterTypeNamespaceInternal(RelationGetForm(seqRel)->reltype,
14096 								   newNspOid, false, false, objsMoved);
14097 
14098 		/* Now we can close it.  Keep the lock till end of transaction. */
14099 		relation_close(seqRel, NoLock);
14100 	}
14101 
14102 	systable_endscan(scan);
14103 
14104 	relation_close(depRel, AccessShareLock);
14105 }
14106 
14107 
14108 /*
14109  * This code supports
14110  *	CREATE TEMP TABLE ... ON COMMIT { DROP | PRESERVE ROWS | DELETE ROWS }
14111  *
14112  * Because we only support this for TEMP tables, it's sufficient to remember
14113  * the state in a backend-local data structure.
14114  */
14115 
14116 /*
14117  * Register a newly-created relation's ON COMMIT action.
14118  */
14119 void
register_on_commit_action(Oid relid,OnCommitAction action)14120 register_on_commit_action(Oid relid, OnCommitAction action)
14121 {
14122 	OnCommitItem *oc;
14123 	MemoryContext oldcxt;
14124 
14125 	/*
14126 	 * We needn't bother registering the relation unless there is an ON COMMIT
14127 	 * action we need to take.
14128 	 */
14129 	if (action == ONCOMMIT_NOOP || action == ONCOMMIT_PRESERVE_ROWS)
14130 		return;
14131 
14132 	oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
14133 
14134 	oc = (OnCommitItem *) palloc(sizeof(OnCommitItem));
14135 	oc->relid = relid;
14136 	oc->oncommit = action;
14137 	oc->creating_subid = GetCurrentSubTransactionId();
14138 	oc->deleting_subid = InvalidSubTransactionId;
14139 
14140 	on_commits = lcons(oc, on_commits);
14141 
14142 	MemoryContextSwitchTo(oldcxt);
14143 }
14144 
14145 /*
14146  * Unregister any ON COMMIT action when a relation is deleted.
14147  *
14148  * Actually, we only mark the OnCommitItem entry as to be deleted after commit.
14149  */
14150 void
remove_on_commit_action(Oid relid)14151 remove_on_commit_action(Oid relid)
14152 {
14153 	ListCell   *l;
14154 
14155 	foreach(l, on_commits)
14156 	{
14157 		OnCommitItem *oc = (OnCommitItem *) lfirst(l);
14158 
14159 		if (oc->relid == relid)
14160 		{
14161 			oc->deleting_subid = GetCurrentSubTransactionId();
14162 			break;
14163 		}
14164 	}
14165 }
14166 
14167 /*
14168  * Perform ON COMMIT actions.
14169  *
14170  * This is invoked just before actually committing, since it's possible
14171  * to encounter errors.
14172  */
14173 void
PreCommit_on_commit_actions(void)14174 PreCommit_on_commit_actions(void)
14175 {
14176 	ListCell   *l;
14177 	List	   *oids_to_truncate = NIL;
14178 	List	   *oids_to_drop = NIL;
14179 
14180 	foreach(l, on_commits)
14181 	{
14182 		OnCommitItem *oc = (OnCommitItem *) lfirst(l);
14183 
14184 		/* Ignore entry if already dropped in this xact */
14185 		if (oc->deleting_subid != InvalidSubTransactionId)
14186 			continue;
14187 
14188 		switch (oc->oncommit)
14189 		{
14190 			case ONCOMMIT_NOOP:
14191 			case ONCOMMIT_PRESERVE_ROWS:
14192 				/* Do nothing (there shouldn't be such entries, actually) */
14193 				break;
14194 			case ONCOMMIT_DELETE_ROWS:
14195 
14196 				/*
14197 				 * If this transaction hasn't accessed any temporary
14198 				 * relations, we can skip truncating ON COMMIT DELETE ROWS
14199 				 * tables, as they must still be empty.
14200 				 */
14201 				if ((MyXactFlags & XACT_FLAGS_ACCESSEDTEMPREL))
14202 					oids_to_truncate = lappend_oid(oids_to_truncate, oc->relid);
14203 				break;
14204 			case ONCOMMIT_DROP:
14205 				oids_to_drop = lappend_oid(oids_to_drop, oc->relid);
14206 				break;
14207 		}
14208 	}
14209 
14210 	/*
14211 	 * Truncate relations before dropping so that all dependencies between
14212 	 * relations are removed after they are worked on.  Doing it like this
14213 	 * might be a waste as it is possible that a relation being truncated will
14214 	 * be dropped anyway due to its parent being dropped, but this makes the
14215 	 * code more robust because of not having to re-check that the relation
14216 	 * exists at truncation time.
14217 	 */
14218 	if (oids_to_truncate != NIL)
14219 	{
14220 		heap_truncate(oids_to_truncate);
14221 		CommandCounterIncrement();	/* XXX needed? */
14222 	}
14223 	if (oids_to_drop != NIL)
14224 	{
14225 		ObjectAddresses *targetObjects = new_object_addresses();
14226 		ListCell   *l;
14227 
14228 		foreach(l, oids_to_drop)
14229 		{
14230 			ObjectAddress object;
14231 
14232 			object.classId = RelationRelationId;
14233 			object.objectId = lfirst_oid(l);
14234 			object.objectSubId = 0;
14235 
14236 			Assert(!object_address_present(&object, targetObjects));
14237 
14238 			add_exact_object_address(&object, targetObjects);
14239 		}
14240 
14241 		/*
14242 		 * Since this is an automatic drop, rather than one directly initiated
14243 		 * by the user, we pass the PERFORM_DELETION_INTERNAL flag.
14244 		 */
14245 		performMultipleDeletions(targetObjects, DROP_CASCADE,
14246 								 PERFORM_DELETION_INTERNAL | PERFORM_DELETION_QUIETLY);
14247 
14248 #ifdef USE_ASSERT_CHECKING
14249 
14250 		/*
14251 		 * Note that table deletion will call remove_on_commit_action, so the
14252 		 * entry should get marked as deleted.
14253 		 */
14254 		foreach(l, on_commits)
14255 		{
14256 			OnCommitItem *oc = (OnCommitItem *) lfirst(l);
14257 
14258 			if (oc->oncommit != ONCOMMIT_DROP)
14259 				continue;
14260 
14261 			Assert(oc->deleting_subid != InvalidSubTransactionId);
14262 		}
14263 #endif
14264 	}
14265 }
14266 
14267 /*
14268  * Post-commit or post-abort cleanup for ON COMMIT management.
14269  *
14270  * All we do here is remove no-longer-needed OnCommitItem entries.
14271  *
14272  * During commit, remove entries that were deleted during this transaction;
14273  * during abort, remove those created during this transaction.
14274  */
14275 void
AtEOXact_on_commit_actions(bool isCommit)14276 AtEOXact_on_commit_actions(bool isCommit)
14277 {
14278 	ListCell   *cur_item;
14279 	ListCell   *prev_item;
14280 
14281 	prev_item = NULL;
14282 	cur_item = list_head(on_commits);
14283 
14284 	while (cur_item != NULL)
14285 	{
14286 		OnCommitItem *oc = (OnCommitItem *) lfirst(cur_item);
14287 
14288 		if (isCommit ? oc->deleting_subid != InvalidSubTransactionId :
14289 			oc->creating_subid != InvalidSubTransactionId)
14290 		{
14291 			/* cur_item must be removed */
14292 			on_commits = list_delete_cell(on_commits, cur_item, prev_item);
14293 			pfree(oc);
14294 			if (prev_item)
14295 				cur_item = lnext(prev_item);
14296 			else
14297 				cur_item = list_head(on_commits);
14298 		}
14299 		else
14300 		{
14301 			/* cur_item must be preserved */
14302 			oc->creating_subid = InvalidSubTransactionId;
14303 			oc->deleting_subid = InvalidSubTransactionId;
14304 			prev_item = cur_item;
14305 			cur_item = lnext(prev_item);
14306 		}
14307 	}
14308 }
14309 
14310 /*
14311  * Post-subcommit or post-subabort cleanup for ON COMMIT management.
14312  *
14313  * During subabort, we can immediately remove entries created during this
14314  * subtransaction.  During subcommit, just relabel entries marked during
14315  * this subtransaction as being the parent's responsibility.
14316  */
14317 void
AtEOSubXact_on_commit_actions(bool isCommit,SubTransactionId mySubid,SubTransactionId parentSubid)14318 AtEOSubXact_on_commit_actions(bool isCommit, SubTransactionId mySubid,
14319 							  SubTransactionId parentSubid)
14320 {
14321 	ListCell   *cur_item;
14322 	ListCell   *prev_item;
14323 
14324 	prev_item = NULL;
14325 	cur_item = list_head(on_commits);
14326 
14327 	while (cur_item != NULL)
14328 	{
14329 		OnCommitItem *oc = (OnCommitItem *) lfirst(cur_item);
14330 
14331 		if (!isCommit && oc->creating_subid == mySubid)
14332 		{
14333 			/* cur_item must be removed */
14334 			on_commits = list_delete_cell(on_commits, cur_item, prev_item);
14335 			pfree(oc);
14336 			if (prev_item)
14337 				cur_item = lnext(prev_item);
14338 			else
14339 				cur_item = list_head(on_commits);
14340 		}
14341 		else
14342 		{
14343 			/* cur_item must be preserved */
14344 			if (oc->creating_subid == mySubid)
14345 				oc->creating_subid = parentSubid;
14346 			if (oc->deleting_subid == mySubid)
14347 				oc->deleting_subid = isCommit ? parentSubid : InvalidSubTransactionId;
14348 			prev_item = cur_item;
14349 			cur_item = lnext(prev_item);
14350 		}
14351 	}
14352 }
14353 
14354 /*
14355  * This is intended as a callback for RangeVarGetRelidExtended().  It allows
14356  * the relation to be locked only if (1) it's a plain table, materialized
14357  * view, or TOAST table and (2) the current user is the owner (or the
14358  * superuser).  This meets the permission-checking needs of CLUSTER, REINDEX
14359  * TABLE, and REFRESH MATERIALIZED VIEW; we expose it here so that it can be
14360  * used by all.
14361  */
14362 void
RangeVarCallbackOwnsTable(const RangeVar * relation,Oid relId,Oid oldRelId,void * arg)14363 RangeVarCallbackOwnsTable(const RangeVar *relation,
14364 						  Oid relId, Oid oldRelId, void *arg)
14365 {
14366 	char		relkind;
14367 
14368 	/* Nothing to do if the relation was not found. */
14369 	if (!OidIsValid(relId))
14370 		return;
14371 
14372 	/*
14373 	 * If the relation does exist, check whether it's an index.  But note that
14374 	 * the relation might have been dropped between the time we did the name
14375 	 * lookup and now.  In that case, there's nothing to do.
14376 	 */
14377 	relkind = get_rel_relkind(relId);
14378 	if (!relkind)
14379 		return;
14380 	if (relkind != RELKIND_RELATION && relkind != RELKIND_TOASTVALUE &&
14381 		relkind != RELKIND_MATVIEW && relkind != RELKIND_PARTITIONED_TABLE)
14382 		ereport(ERROR,
14383 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
14384 				 errmsg("\"%s\" is not a table or materialized view", relation->relname)));
14385 
14386 	/* Check permissions */
14387 	if (!pg_class_ownercheck(relId, GetUserId()))
14388 		aclcheck_error(ACLCHECK_NOT_OWNER, get_relkind_objtype(get_rel_relkind(relId)), relation->relname);
14389 }
14390 
14391 /*
14392  * Callback to RangeVarGetRelidExtended(), similar to
14393  * RangeVarCallbackOwnsTable() but without checks on the type of the relation.
14394  */
14395 void
RangeVarCallbackOwnsRelation(const RangeVar * relation,Oid relId,Oid oldRelId,void * arg)14396 RangeVarCallbackOwnsRelation(const RangeVar *relation,
14397 							 Oid relId, Oid oldRelId, void *arg)
14398 {
14399 	HeapTuple	tuple;
14400 
14401 	/* Nothing to do if the relation was not found. */
14402 	if (!OidIsValid(relId))
14403 		return;
14404 
14405 	tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relId));
14406 	if (!HeapTupleIsValid(tuple))	/* should not happen */
14407 		elog(ERROR, "cache lookup failed for relation %u", relId);
14408 
14409 	if (!pg_class_ownercheck(relId, GetUserId()))
14410 		aclcheck_error(ACLCHECK_NOT_OWNER, get_relkind_objtype(get_rel_relkind(relId)),
14411 					   relation->relname);
14412 
14413 	if (!allowSystemTableMods &&
14414 		IsSystemClass(relId, (Form_pg_class) GETSTRUCT(tuple)))
14415 		ereport(ERROR,
14416 				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
14417 				 errmsg("permission denied: \"%s\" is a system catalog",
14418 						relation->relname)));
14419 
14420 	ReleaseSysCache(tuple);
14421 }
14422 
14423 /*
14424  * Common RangeVarGetRelid callback for rename, set schema, and alter table
14425  * processing.
14426  */
14427 static void
RangeVarCallbackForAlterRelation(const RangeVar * rv,Oid relid,Oid oldrelid,void * arg)14428 RangeVarCallbackForAlterRelation(const RangeVar *rv, Oid relid, Oid oldrelid,
14429 								 void *arg)
14430 {
14431 	Node	   *stmt = (Node *) arg;
14432 	ObjectType	reltype;
14433 	HeapTuple	tuple;
14434 	Form_pg_class classform;
14435 	AclResult	aclresult;
14436 	char		relkind;
14437 
14438 	tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
14439 	if (!HeapTupleIsValid(tuple))
14440 		return;					/* concurrently dropped */
14441 	classform = (Form_pg_class) GETSTRUCT(tuple);
14442 	relkind = classform->relkind;
14443 
14444 	/* Must own relation. */
14445 	if (!pg_class_ownercheck(relid, GetUserId()))
14446 		aclcheck_error(ACLCHECK_NOT_OWNER, get_relkind_objtype(get_rel_relkind(relid)), rv->relname);
14447 
14448 	/* No system table modifications unless explicitly allowed. */
14449 	if (!allowSystemTableMods && IsSystemClass(relid, classform))
14450 		ereport(ERROR,
14451 				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
14452 				 errmsg("permission denied: \"%s\" is a system catalog",
14453 						rv->relname)));
14454 
14455 	/*
14456 	 * Extract the specified relation type from the statement parse tree.
14457 	 *
14458 	 * Also, for ALTER .. RENAME, check permissions: the user must (still)
14459 	 * have CREATE rights on the containing namespace.
14460 	 */
14461 	if (IsA(stmt, RenameStmt))
14462 	{
14463 		aclresult = pg_namespace_aclcheck(classform->relnamespace,
14464 										  GetUserId(), ACL_CREATE);
14465 		if (aclresult != ACLCHECK_OK)
14466 			aclcheck_error(aclresult, OBJECT_SCHEMA,
14467 						   get_namespace_name(classform->relnamespace));
14468 		reltype = ((RenameStmt *) stmt)->renameType;
14469 	}
14470 	else if (IsA(stmt, AlterObjectSchemaStmt))
14471 		reltype = ((AlterObjectSchemaStmt *) stmt)->objectType;
14472 
14473 	else if (IsA(stmt, AlterTableStmt))
14474 		reltype = ((AlterTableStmt *) stmt)->relkind;
14475 	else
14476 	{
14477 		elog(ERROR, "unrecognized node type: %d", (int) nodeTag(stmt));
14478 		reltype = OBJECT_TABLE; /* placate compiler */
14479 	}
14480 
14481 	/*
14482 	 * For compatibility with prior releases, we allow ALTER TABLE to be used
14483 	 * with most other types of relations (but not composite types). We allow
14484 	 * similar flexibility for ALTER INDEX in the case of RENAME, but not
14485 	 * otherwise.  Otherwise, the user must select the correct form of the
14486 	 * command for the relation at issue.
14487 	 */
14488 	if (reltype == OBJECT_SEQUENCE && relkind != RELKIND_SEQUENCE)
14489 		ereport(ERROR,
14490 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
14491 				 errmsg("\"%s\" is not a sequence", rv->relname)));
14492 
14493 	if (reltype == OBJECT_VIEW && relkind != RELKIND_VIEW)
14494 		ereport(ERROR,
14495 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
14496 				 errmsg("\"%s\" is not a view", rv->relname)));
14497 
14498 	if (reltype == OBJECT_MATVIEW && relkind != RELKIND_MATVIEW)
14499 		ereport(ERROR,
14500 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
14501 				 errmsg("\"%s\" is not a materialized view", rv->relname)));
14502 
14503 	if (reltype == OBJECT_FOREIGN_TABLE && relkind != RELKIND_FOREIGN_TABLE)
14504 		ereport(ERROR,
14505 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
14506 				 errmsg("\"%s\" is not a foreign table", rv->relname)));
14507 
14508 	if (reltype == OBJECT_TYPE && relkind != RELKIND_COMPOSITE_TYPE)
14509 		ereport(ERROR,
14510 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
14511 				 errmsg("\"%s\" is not a composite type", rv->relname)));
14512 
14513 	if (reltype == OBJECT_INDEX && relkind != RELKIND_INDEX &&
14514 		relkind != RELKIND_PARTITIONED_INDEX
14515 		&& !IsA(stmt, RenameStmt))
14516 		ereport(ERROR,
14517 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
14518 				 errmsg("\"%s\" is not an index", rv->relname)));
14519 
14520 	/*
14521 	 * Don't allow ALTER TABLE on composite types. We want people to use ALTER
14522 	 * TYPE for that.
14523 	 */
14524 	if (reltype != OBJECT_TYPE && relkind == RELKIND_COMPOSITE_TYPE)
14525 		ereport(ERROR,
14526 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
14527 				 errmsg("\"%s\" is a composite type", rv->relname),
14528 				 errhint("Use ALTER TYPE instead.")));
14529 
14530 	/*
14531 	 * Don't allow ALTER TABLE .. SET SCHEMA on relations that can't be moved
14532 	 * to a different schema, such as indexes and TOAST tables.
14533 	 */
14534 	if (IsA(stmt, AlterObjectSchemaStmt) &&
14535 		relkind != RELKIND_RELATION &&
14536 		relkind != RELKIND_VIEW &&
14537 		relkind != RELKIND_MATVIEW &&
14538 		relkind != RELKIND_SEQUENCE &&
14539 		relkind != RELKIND_FOREIGN_TABLE &&
14540 		relkind != RELKIND_PARTITIONED_TABLE)
14541 		ereport(ERROR,
14542 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
14543 				 errmsg("\"%s\" is not a table, view, materialized view, sequence, or foreign table",
14544 						rv->relname)));
14545 
14546 	ReleaseSysCache(tuple);
14547 }
14548 
14549 /*
14550  * Transform any expressions present in the partition key
14551  *
14552  * Returns a transformed PartitionSpec, as well as the strategy code
14553  */
14554 static PartitionSpec *
transformPartitionSpec(Relation rel,PartitionSpec * partspec,char * strategy)14555 transformPartitionSpec(Relation rel, PartitionSpec *partspec, char *strategy)
14556 {
14557 	PartitionSpec *newspec;
14558 	ParseState *pstate;
14559 	RangeTblEntry *rte;
14560 	ListCell   *l;
14561 
14562 	newspec = makeNode(PartitionSpec);
14563 
14564 	newspec->strategy = partspec->strategy;
14565 	newspec->partParams = NIL;
14566 	newspec->location = partspec->location;
14567 
14568 	/* Parse partitioning strategy name */
14569 	if (pg_strcasecmp(partspec->strategy, "hash") == 0)
14570 		*strategy = PARTITION_STRATEGY_HASH;
14571 	else if (pg_strcasecmp(partspec->strategy, "list") == 0)
14572 		*strategy = PARTITION_STRATEGY_LIST;
14573 	else if (pg_strcasecmp(partspec->strategy, "range") == 0)
14574 		*strategy = PARTITION_STRATEGY_RANGE;
14575 	else
14576 		ereport(ERROR,
14577 				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
14578 				 errmsg("unrecognized partitioning strategy \"%s\"",
14579 						partspec->strategy)));
14580 
14581 	/* Check valid number of columns for strategy */
14582 	if (*strategy == PARTITION_STRATEGY_LIST &&
14583 		list_length(partspec->partParams) != 1)
14584 		ereport(ERROR,
14585 				(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
14586 				 errmsg("cannot use \"list\" partition strategy with more than one column")));
14587 
14588 	/*
14589 	 * Create a dummy ParseState and insert the target relation as its sole
14590 	 * rangetable entry.  We need a ParseState for transformExpr.
14591 	 */
14592 	pstate = make_parsestate(NULL);
14593 	rte = addRangeTableEntryForRelation(pstate, rel, NULL, false, true);
14594 	addRTEtoQuery(pstate, rte, true, true, true);
14595 
14596 	/* take care of any partition expressions */
14597 	foreach(l, partspec->partParams)
14598 	{
14599 		PartitionElem *pelem = castNode(PartitionElem, lfirst(l));
14600 
14601 		if (pelem->expr)
14602 		{
14603 			/* Copy, to avoid scribbling on the input */
14604 			pelem = copyObject(pelem);
14605 
14606 			/* Now do parse transformation of the expression */
14607 			pelem->expr = transformExpr(pstate, pelem->expr,
14608 										EXPR_KIND_PARTITION_EXPRESSION);
14609 
14610 			/* we have to fix its collations too */
14611 			assign_expr_collations(pstate, pelem->expr);
14612 		}
14613 
14614 		newspec->partParams = lappend(newspec->partParams, pelem);
14615 	}
14616 
14617 	return newspec;
14618 }
14619 
14620 /*
14621  * Compute per-partition-column information from a list of PartitionElems.
14622  * Expressions in the PartitionElems must be parse-analyzed already.
14623  */
14624 static void
ComputePartitionAttrs(Relation rel,List * partParams,AttrNumber * partattrs,List ** partexprs,Oid * partopclass,Oid * partcollation,char strategy)14625 ComputePartitionAttrs(Relation rel, List *partParams, AttrNumber *partattrs,
14626 					  List **partexprs, Oid *partopclass, Oid *partcollation,
14627 					  char strategy)
14628 {
14629 	int			attn;
14630 	ListCell   *lc;
14631 	Oid			am_oid;
14632 
14633 	attn = 0;
14634 	foreach(lc, partParams)
14635 	{
14636 		PartitionElem *pelem = castNode(PartitionElem, lfirst(lc));
14637 		Oid			atttype;
14638 		Oid			attcollation;
14639 
14640 		if (pelem->name != NULL)
14641 		{
14642 			/* Simple attribute reference */
14643 			HeapTuple	atttuple;
14644 			Form_pg_attribute attform;
14645 
14646 			atttuple = SearchSysCacheAttName(RelationGetRelid(rel),
14647 											 pelem->name);
14648 			if (!HeapTupleIsValid(atttuple))
14649 				ereport(ERROR,
14650 						(errcode(ERRCODE_UNDEFINED_COLUMN),
14651 						 errmsg("column \"%s\" named in partition key does not exist",
14652 								pelem->name)));
14653 			attform = (Form_pg_attribute) GETSTRUCT(atttuple);
14654 
14655 			if (attform->attnum <= 0)
14656 				ereport(ERROR,
14657 						(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
14658 						 errmsg("cannot use system column \"%s\" in partition key",
14659 								pelem->name)));
14660 
14661 			partattrs[attn] = attform->attnum;
14662 			atttype = attform->atttypid;
14663 			attcollation = attform->attcollation;
14664 			ReleaseSysCache(atttuple);
14665 		}
14666 		else
14667 		{
14668 			/* Expression */
14669 			Node	   *expr = pelem->expr;
14670 
14671 			Assert(expr != NULL);
14672 			atttype = exprType(expr);
14673 			attcollation = exprCollation(expr);
14674 
14675 			/*
14676 			 * The expression must be of a storable type (e.g., not RECORD).
14677 			 * The test is the same as for whether a table column is of a safe
14678 			 * type (which is why we needn't check for the non-expression
14679 			 * case).
14680 			 */
14681 			CheckAttributeType("partition key",
14682 							   atttype, attcollation,
14683 							   NIL, false);
14684 
14685 			/*
14686 			 * Strip any top-level COLLATE clause.  This ensures that we treat
14687 			 * "x COLLATE y" and "(x COLLATE y)" alike.
14688 			 */
14689 			while (IsA(expr, CollateExpr))
14690 				expr = (Node *) ((CollateExpr *) expr)->arg;
14691 
14692 			if (IsA(expr, Var) &&
14693 				((Var *) expr)->varattno > 0)
14694 			{
14695 				/*
14696 				 * User wrote "(column)" or "(column COLLATE something)".
14697 				 * Treat it like simple attribute anyway.
14698 				 */
14699 				partattrs[attn] = ((Var *) expr)->varattno;
14700 			}
14701 			else
14702 			{
14703 				Bitmapset  *expr_attrs = NULL;
14704 				int			i;
14705 
14706 				partattrs[attn] = 0;	/* marks the column as expression */
14707 				*partexprs = lappend(*partexprs, expr);
14708 
14709 				/*
14710 				 * Try to simplify the expression before checking for
14711 				 * mutability.  The main practical value of doing it in this
14712 				 * order is that an inline-able SQL-language function will be
14713 				 * accepted if its expansion is immutable, whether or not the
14714 				 * function itself is marked immutable.
14715 				 *
14716 				 * Note that expression_planner does not change the passed in
14717 				 * expression destructively and we have already saved the
14718 				 * expression to be stored into the catalog above.
14719 				 */
14720 				expr = (Node *) expression_planner((Expr *) expr);
14721 
14722 				/*
14723 				 * Partition expression cannot contain mutable functions,
14724 				 * because a given row must always map to the same partition
14725 				 * as long as there is no change in the partition boundary
14726 				 * structure.
14727 				 */
14728 				if (contain_mutable_functions(expr))
14729 					ereport(ERROR,
14730 							(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
14731 							 errmsg("functions in partition key expression must be marked IMMUTABLE")));
14732 
14733 				/*
14734 				 * transformPartitionSpec() should have already rejected
14735 				 * subqueries, aggregates, window functions, and SRFs, based
14736 				 * on the EXPR_KIND_ for partition expressions.
14737 				 */
14738 
14739 				/*
14740 				 * Cannot have expressions containing whole-row references or
14741 				 * system column references.
14742 				 */
14743 				pull_varattnos(expr, 1, &expr_attrs);
14744 				if (bms_is_member(0 - FirstLowInvalidHeapAttributeNumber,
14745 								  expr_attrs))
14746 					ereport(ERROR,
14747 							(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
14748 							 errmsg("partition key expressions cannot contain whole-row references")));
14749 				for (i = FirstLowInvalidHeapAttributeNumber; i < 0; i++)
14750 				{
14751 					if (bms_is_member(i - FirstLowInvalidHeapAttributeNumber,
14752 									  expr_attrs))
14753 						ereport(ERROR,
14754 								(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
14755 								 errmsg("partition key expressions cannot contain system column references")));
14756 				}
14757 
14758 				/*
14759 				 * While it is not exactly *wrong* for a partition expression
14760 				 * to be a constant, it seems better to reject such keys.
14761 				 */
14762 				if (IsA(expr, Const))
14763 					ereport(ERROR,
14764 							(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
14765 							 errmsg("cannot use constant expression as partition key")));
14766 			}
14767 		}
14768 
14769 		/*
14770 		 * Apply collation override if any
14771 		 */
14772 		if (pelem->collation)
14773 			attcollation = get_collation_oid(pelem->collation, false);
14774 
14775 		/*
14776 		 * Check we have a collation iff it's a collatable type.  The only
14777 		 * expected failures here are (1) COLLATE applied to a noncollatable
14778 		 * type, or (2) partition expression had an unresolved collation. But
14779 		 * we might as well code this to be a complete consistency check.
14780 		 */
14781 		if (type_is_collatable(atttype))
14782 		{
14783 			if (!OidIsValid(attcollation))
14784 				ereport(ERROR,
14785 						(errcode(ERRCODE_INDETERMINATE_COLLATION),
14786 						 errmsg("could not determine which collation to use for partition expression"),
14787 						 errhint("Use the COLLATE clause to set the collation explicitly.")));
14788 		}
14789 		else
14790 		{
14791 			if (OidIsValid(attcollation))
14792 				ereport(ERROR,
14793 						(errcode(ERRCODE_DATATYPE_MISMATCH),
14794 						 errmsg("collations are not supported by type %s",
14795 								format_type_be(atttype))));
14796 		}
14797 
14798 		partcollation[attn] = attcollation;
14799 
14800 		/*
14801 		 * Identify the appropriate operator class.  For list and range
14802 		 * partitioning, we use a btree operator class; hash partitioning uses
14803 		 * a hash operator class.
14804 		 */
14805 		if (strategy == PARTITION_STRATEGY_HASH)
14806 			am_oid = HASH_AM_OID;
14807 		else
14808 			am_oid = BTREE_AM_OID;
14809 
14810 		if (!pelem->opclass)
14811 		{
14812 			partopclass[attn] = GetDefaultOpClass(atttype, am_oid);
14813 
14814 			if (!OidIsValid(partopclass[attn]))
14815 			{
14816 				if (strategy == PARTITION_STRATEGY_HASH)
14817 					ereport(ERROR,
14818 							(errcode(ERRCODE_UNDEFINED_OBJECT),
14819 							 errmsg("data type %s has no default hash operator class",
14820 									format_type_be(atttype)),
14821 							 errhint("You must specify a hash operator class or define a default hash operator class for the data type.")));
14822 				else
14823 					ereport(ERROR,
14824 							(errcode(ERRCODE_UNDEFINED_OBJECT),
14825 							 errmsg("data type %s has no default btree operator class",
14826 									format_type_be(atttype)),
14827 							 errhint("You must specify a btree operator class or define a default btree operator class for the data type.")));
14828 
14829 			}
14830 		}
14831 		else
14832 			partopclass[attn] = ResolveOpClass(pelem->opclass,
14833 											   atttype,
14834 											   am_oid == HASH_AM_OID ? "hash" : "btree",
14835 											   am_oid);
14836 
14837 		attn++;
14838 	}
14839 }
14840 
14841 /*
14842  * PartConstraintImpliedByRelConstraint
14843  *		Do scanrel's existing constraints imply the partition constraint?
14844  *
14845  * "Existing constraints" include its check constraints and column-level
14846  * NOT NULL constraints.  partConstraint describes the partition constraint,
14847  * in implicit-AND form.
14848  */
14849 bool
PartConstraintImpliedByRelConstraint(Relation scanrel,List * partConstraint)14850 PartConstraintImpliedByRelConstraint(Relation scanrel,
14851 									 List *partConstraint)
14852 {
14853 	List	   *existConstraint = NIL;
14854 	TupleConstr *constr = RelationGetDescr(scanrel)->constr;
14855 	int			num_check,
14856 				i;
14857 
14858 	if (constr && constr->has_not_null)
14859 	{
14860 		int			natts = scanrel->rd_att->natts;
14861 
14862 		for (i = 1; i <= natts; i++)
14863 		{
14864 			Form_pg_attribute att = TupleDescAttr(scanrel->rd_att, i - 1);
14865 
14866 			if (att->attnotnull && !att->attisdropped)
14867 			{
14868 				NullTest   *ntest = makeNode(NullTest);
14869 
14870 				ntest->arg = (Expr *) makeVar(1,
14871 											  i,
14872 											  att->atttypid,
14873 											  att->atttypmod,
14874 											  att->attcollation,
14875 											  0);
14876 				ntest->nulltesttype = IS_NOT_NULL;
14877 
14878 				/*
14879 				 * argisrow=false is correct even for a composite column,
14880 				 * because attnotnull does not represent a SQL-spec IS NOT
14881 				 * NULL test in such a case, just IS DISTINCT FROM NULL.
14882 				 */
14883 				ntest->argisrow = false;
14884 				ntest->location = -1;
14885 				existConstraint = lappend(existConstraint, ntest);
14886 			}
14887 		}
14888 	}
14889 
14890 	num_check = (constr != NULL) ? constr->num_check : 0;
14891 	for (i = 0; i < num_check; i++)
14892 	{
14893 		Node	   *cexpr;
14894 
14895 		/*
14896 		 * If this constraint hasn't been fully validated yet, we must ignore
14897 		 * it here.
14898 		 */
14899 		if (!constr->check[i].ccvalid)
14900 			continue;
14901 
14902 		cexpr = stringToNode(constr->check[i].ccbin);
14903 
14904 		/*
14905 		 * Run each expression through const-simplification and
14906 		 * canonicalization.  It is necessary, because we will be comparing it
14907 		 * to similarly-processed partition constraint expressions, and may
14908 		 * fail to detect valid matches without this.
14909 		 */
14910 		cexpr = eval_const_expressions(NULL, cexpr);
14911 		cexpr = (Node *) canonicalize_qual((Expr *) cexpr, true);
14912 
14913 		existConstraint = list_concat(existConstraint,
14914 									  make_ands_implicit((Expr *) cexpr));
14915 	}
14916 
14917 	/*
14918 	 * Try to make the proof.  Since we are comparing CHECK constraints, we
14919 	 * need to use weak implication, i.e., we assume existConstraint is
14920 	 * not-false and try to prove the same for partConstraint.
14921 	 *
14922 	 * Note that predicate_implied_by assumes its first argument is known
14923 	 * immutable.  That should always be true for partition constraints, so we
14924 	 * don't test it here.
14925 	 */
14926 	return predicate_implied_by(partConstraint, existConstraint, true);
14927 }
14928 
14929 /*
14930  * QueuePartitionConstraintValidation
14931  *
14932  * Add an entry to wqueue to have the given partition constraint validated by
14933  * Phase 3, for the given relation, and all its children.
14934  *
14935  * We first verify whether the given constraint is implied by pre-existing
14936  * relation constraints; if it is, there's no need to scan the table to
14937  * validate, so don't queue in that case.
14938  */
14939 static void
QueuePartitionConstraintValidation(List ** wqueue,Relation scanrel,List * partConstraint,bool validate_default)14940 QueuePartitionConstraintValidation(List **wqueue, Relation scanrel,
14941 								   List *partConstraint,
14942 								   bool validate_default)
14943 {
14944 	/*
14945 	 * Based on the table's existing constraints, determine whether or not we
14946 	 * may skip scanning the table.
14947 	 */
14948 	if (PartConstraintImpliedByRelConstraint(scanrel, partConstraint))
14949 	{
14950 		if (!validate_default)
14951 			ereport(INFO,
14952 					(errmsg("partition constraint for table \"%s\" is implied by existing constraints",
14953 							RelationGetRelationName(scanrel))));
14954 		else
14955 			ereport(INFO,
14956 					(errmsg("updated partition constraint for default partition \"%s\" is implied by existing constraints",
14957 							RelationGetRelationName(scanrel))));
14958 		return;
14959 	}
14960 
14961 	/*
14962 	 * Constraints proved insufficient. For plain relations, queue a
14963 	 * validation item now; for partitioned tables, recurse to process each
14964 	 * partition.
14965 	 */
14966 	if (scanrel->rd_rel->relkind == RELKIND_RELATION)
14967 	{
14968 		AlteredTableInfo *tab;
14969 
14970 		/* Grab a work queue entry. */
14971 		tab = ATGetQueueEntry(wqueue, scanrel);
14972 		Assert(tab->partition_constraint == NULL);
14973 		tab->partition_constraint = (Expr *) linitial(partConstraint);
14974 		tab->validate_default = validate_default;
14975 	}
14976 	else if (scanrel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
14977 	{
14978 		PartitionDesc partdesc = RelationGetPartitionDesc(scanrel);
14979 		int			i;
14980 
14981 		for (i = 0; i < partdesc->nparts; i++)
14982 		{
14983 			Relation	part_rel;
14984 			bool		found_whole_row;
14985 			List	   *thisPartConstraint;
14986 
14987 			/*
14988 			 * This is the minimum lock we need to prevent deadlocks.
14989 			 */
14990 			part_rel = heap_open(partdesc->oids[i], AccessExclusiveLock);
14991 
14992 			/*
14993 			 * Adjust the constraint for scanrel so that it matches this
14994 			 * partition's attribute numbers.
14995 			 */
14996 			thisPartConstraint =
14997 				map_partition_varattnos(partConstraint, 1,
14998 										part_rel, scanrel, &found_whole_row);
14999 			/* There can never be a whole-row reference here */
15000 			if (found_whole_row)
15001 				elog(ERROR, "unexpected whole-row reference found in partition constraint");
15002 
15003 			QueuePartitionConstraintValidation(wqueue, part_rel,
15004 											   thisPartConstraint,
15005 											   validate_default);
15006 			heap_close(part_rel, NoLock);	/* keep lock till commit */
15007 		}
15008 	}
15009 }
15010 
15011 /*
15012  * ALTER TABLE <name> ATTACH PARTITION <partition-name> FOR VALUES
15013  *
15014  * Return the address of the newly attached partition.
15015  */
15016 static ObjectAddress
ATExecAttachPartition(List ** wqueue,Relation rel,PartitionCmd * cmd)15017 ATExecAttachPartition(List **wqueue, Relation rel, PartitionCmd *cmd)
15018 {
15019 	Relation	attachrel,
15020 				catalog;
15021 	List	   *attachrel_children;
15022 	List	   *partConstraint;
15023 	SysScanDesc scan;
15024 	ScanKeyData skey;
15025 	AttrNumber	attno;
15026 	int			natts;
15027 	TupleDesc	tupleDesc;
15028 	ObjectAddress address;
15029 	const char *trigger_name;
15030 	bool		found_whole_row;
15031 	Oid			defaultPartOid;
15032 	List	   *partBoundConstraint;
15033 	List	   *cloned;
15034 	ListCell   *l;
15035 
15036 	/*
15037 	 * We must lock the default partition if one exists, because attaching a
15038 	 * new partition will change its partition constraint.
15039 	 */
15040 	defaultPartOid =
15041 		get_default_oid_from_partdesc(RelationGetPartitionDesc(rel));
15042 	if (OidIsValid(defaultPartOid))
15043 		LockRelationOid(defaultPartOid, AccessExclusiveLock);
15044 
15045 	attachrel = heap_openrv(cmd->name, AccessExclusiveLock);
15046 
15047 	/*
15048 	 * XXX I think it'd be a good idea to grab locks on all tables referenced
15049 	 * by FKs at this point also.
15050 	 */
15051 
15052 	/*
15053 	 * Must be owner of both parent and source table -- parent was checked by
15054 	 * ATSimplePermissions call in ATPrepCmd
15055 	 */
15056 	ATSimplePermissions(attachrel, ATT_TABLE | ATT_FOREIGN_TABLE);
15057 
15058 	/* A partition can only have one parent */
15059 	if (attachrel->rd_rel->relispartition)
15060 		ereport(ERROR,
15061 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
15062 				 errmsg("\"%s\" is already a partition",
15063 						RelationGetRelationName(attachrel))));
15064 
15065 	if (OidIsValid(attachrel->rd_rel->reloftype))
15066 		ereport(ERROR,
15067 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
15068 				 errmsg("cannot attach a typed table as partition")));
15069 
15070 	/*
15071 	 * Table being attached should not already be part of inheritance; either
15072 	 * as a child table...
15073 	 */
15074 	catalog = heap_open(InheritsRelationId, AccessShareLock);
15075 	ScanKeyInit(&skey,
15076 				Anum_pg_inherits_inhrelid,
15077 				BTEqualStrategyNumber, F_OIDEQ,
15078 				ObjectIdGetDatum(RelationGetRelid(attachrel)));
15079 	scan = systable_beginscan(catalog, InheritsRelidSeqnoIndexId, true,
15080 							  NULL, 1, &skey);
15081 	if (HeapTupleIsValid(systable_getnext(scan)))
15082 		ereport(ERROR,
15083 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
15084 				 errmsg("cannot attach inheritance child as partition")));
15085 	systable_endscan(scan);
15086 
15087 	/* ...or as a parent table (except the case when it is partitioned) */
15088 	ScanKeyInit(&skey,
15089 				Anum_pg_inherits_inhparent,
15090 				BTEqualStrategyNumber, F_OIDEQ,
15091 				ObjectIdGetDatum(RelationGetRelid(attachrel)));
15092 	scan = systable_beginscan(catalog, InheritsParentIndexId, true, NULL,
15093 							  1, &skey);
15094 	if (HeapTupleIsValid(systable_getnext(scan)) &&
15095 		attachrel->rd_rel->relkind == RELKIND_RELATION)
15096 		ereport(ERROR,
15097 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
15098 				 errmsg("cannot attach inheritance parent as partition")));
15099 	systable_endscan(scan);
15100 	heap_close(catalog, AccessShareLock);
15101 
15102 	/*
15103 	 * Prevent circularity by seeing if rel is a partition of attachrel. (In
15104 	 * particular, this disallows making a rel a partition of itself.)
15105 	 *
15106 	 * We do that by checking if rel is a member of the list of attachrel's
15107 	 * partitions provided the latter is partitioned at all.  We want to avoid
15108 	 * having to construct this list again, so we request the strongest lock
15109 	 * on all partitions.  We need the strongest lock, because we may decide
15110 	 * to scan them if we find out that the table being attached (or its leaf
15111 	 * partitions) may contain rows that violate the partition constraint. If
15112 	 * the table has a constraint that would prevent such rows, which by
15113 	 * definition is present in all the partitions, we need not scan the
15114 	 * table, nor its partitions.  But we cannot risk a deadlock by taking a
15115 	 * weaker lock now and the stronger one only when needed.
15116 	 */
15117 	attachrel_children = find_all_inheritors(RelationGetRelid(attachrel),
15118 											 AccessExclusiveLock, NULL);
15119 	if (list_member_oid(attachrel_children, RelationGetRelid(rel)))
15120 		ereport(ERROR,
15121 				(errcode(ERRCODE_DUPLICATE_TABLE),
15122 				 errmsg("circular inheritance not allowed"),
15123 				 errdetail("\"%s\" is already a child of \"%s\".",
15124 						   RelationGetRelationName(rel),
15125 						   RelationGetRelationName(attachrel))));
15126 
15127 	/* If the parent is permanent, so must be all of its partitions. */
15128 	if (rel->rd_rel->relpersistence != RELPERSISTENCE_TEMP &&
15129 		attachrel->rd_rel->relpersistence == RELPERSISTENCE_TEMP)
15130 		ereport(ERROR,
15131 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
15132 				 errmsg("cannot attach a temporary relation as partition of permanent relation \"%s\"",
15133 						RelationGetRelationName(rel))));
15134 
15135 	/* Temp parent cannot have a partition that is itself not a temp */
15136 	if (rel->rd_rel->relpersistence == RELPERSISTENCE_TEMP &&
15137 		attachrel->rd_rel->relpersistence != RELPERSISTENCE_TEMP)
15138 		ereport(ERROR,
15139 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
15140 				 errmsg("cannot attach a permanent relation as partition of temporary relation \"%s\"",
15141 						RelationGetRelationName(rel))));
15142 
15143 	/* If the parent is temp, it must belong to this session */
15144 	if (rel->rd_rel->relpersistence == RELPERSISTENCE_TEMP &&
15145 		!rel->rd_islocaltemp)
15146 		ereport(ERROR,
15147 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
15148 				 errmsg("cannot attach as partition of temporary relation of another session")));
15149 
15150 	/* Ditto for the partition */
15151 	if (attachrel->rd_rel->relpersistence == RELPERSISTENCE_TEMP &&
15152 		!attachrel->rd_islocaltemp)
15153 		ereport(ERROR,
15154 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
15155 				 errmsg("cannot attach temporary relation of another session as partition")));
15156 
15157 	/* If parent has OIDs then child must have OIDs */
15158 	if (rel->rd_rel->relhasoids && !attachrel->rd_rel->relhasoids)
15159 		ereport(ERROR,
15160 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
15161 				 errmsg("cannot attach table \"%s\" without OIDs as partition of"
15162 						" table \"%s\" with OIDs", RelationGetRelationName(attachrel),
15163 						RelationGetRelationName(rel))));
15164 
15165 	/* OTOH, if parent doesn't have them, do not allow in attachrel either */
15166 	if (attachrel->rd_rel->relhasoids && !rel->rd_rel->relhasoids)
15167 		ereport(ERROR,
15168 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
15169 				 errmsg("cannot attach table \"%s\" with OIDs as partition of table"
15170 						" \"%s\" without OIDs", RelationGetRelationName(attachrel),
15171 						RelationGetRelationName(rel))));
15172 
15173 	/* Check if there are any columns in attachrel that aren't in the parent */
15174 	tupleDesc = RelationGetDescr(attachrel);
15175 	natts = tupleDesc->natts;
15176 	for (attno = 1; attno <= natts; attno++)
15177 	{
15178 		Form_pg_attribute attribute = TupleDescAttr(tupleDesc, attno - 1);
15179 		char	   *attributeName = NameStr(attribute->attname);
15180 
15181 		/* Ignore dropped */
15182 		if (attribute->attisdropped)
15183 			continue;
15184 
15185 		/* Try to find the column in parent (matching on column name) */
15186 		if (!SearchSysCacheExists2(ATTNAME,
15187 								   ObjectIdGetDatum(RelationGetRelid(rel)),
15188 								   CStringGetDatum(attributeName)))
15189 			ereport(ERROR,
15190 					(errcode(ERRCODE_DATATYPE_MISMATCH),
15191 					 errmsg("table \"%s\" contains column \"%s\" not found in parent \"%s\"",
15192 							RelationGetRelationName(attachrel), attributeName,
15193 							RelationGetRelationName(rel)),
15194 					 errdetail("The new partition may contain only the columns present in parent.")));
15195 	}
15196 
15197 	/*
15198 	 * If child_rel has row-level triggers with transition tables, we
15199 	 * currently don't allow it to become a partition.  See also prohibitions
15200 	 * in ATExecAddInherit() and CreateTrigger().
15201 	 */
15202 	trigger_name = FindTriggerIncompatibleWithInheritance(attachrel->trigdesc);
15203 	if (trigger_name != NULL)
15204 		ereport(ERROR,
15205 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
15206 				 errmsg("trigger \"%s\" prevents table \"%s\" from becoming a partition",
15207 						trigger_name, RelationGetRelationName(attachrel)),
15208 				 errdetail("ROW triggers with transition tables are not supported on partitions")));
15209 
15210 	/*
15211 	 * Check that the new partition's bound is valid and does not overlap any
15212 	 * of existing partitions of the parent - note that it does not return on
15213 	 * error.
15214 	 */
15215 	check_new_partition_bound(RelationGetRelationName(attachrel), rel,
15216 							  cmd->bound);
15217 
15218 	/* OK to create inheritance.  Rest of the checks performed there */
15219 	CreateInheritance(attachrel, rel);
15220 
15221 	/* Update the pg_class entry. */
15222 	StorePartitionBound(attachrel, rel, cmd->bound);
15223 
15224 	/* Ensure there exists a correct set of indexes in the partition. */
15225 	AttachPartitionEnsureIndexes(rel, attachrel);
15226 
15227 	/* and triggers */
15228 	CloneRowTriggersToPartition(rel, attachrel);
15229 
15230 	/*
15231 	 * Clone foreign key constraints, and setup for Phase 3 to verify them.
15232 	 */
15233 	cloned = NIL;
15234 	CloneForeignKeyConstraints(RelationGetRelid(rel),
15235 							   RelationGetRelid(attachrel), &cloned);
15236 	foreach(l, cloned)
15237 	{
15238 		ClonedConstraint *clonedcon = lfirst(l);
15239 		NewConstraint *newcon;
15240 		Relation	clonedrel;
15241 		AlteredTableInfo *parttab;
15242 
15243 		clonedrel = relation_open(clonedcon->relid, NoLock);
15244 		parttab = ATGetQueueEntry(wqueue, clonedrel);
15245 
15246 		newcon = (NewConstraint *) palloc0(sizeof(NewConstraint));
15247 		newcon->name = clonedcon->constraint->conname;
15248 		newcon->contype = CONSTR_FOREIGN;
15249 		newcon->refrelid = clonedcon->refrelid;
15250 		newcon->refindid = clonedcon->conindid;
15251 		newcon->conid = clonedcon->conid;
15252 		newcon->qual = (Node *) clonedcon->constraint;
15253 
15254 		parttab->constraints = lappend(parttab->constraints, newcon);
15255 
15256 		relation_close(clonedrel, NoLock);
15257 	}
15258 
15259 	/*
15260 	 * Generate partition constraint from the partition bound specification.
15261 	 * If the parent itself is a partition, make sure to include its
15262 	 * constraint as well.
15263 	 */
15264 	partBoundConstraint = get_qual_from_partbound(attachrel, rel, cmd->bound);
15265 	partConstraint = list_concat(partBoundConstraint,
15266 								 RelationGetPartitionQual(rel));
15267 
15268 	/* Skip validation if there are no constraints to validate. */
15269 	if (partConstraint)
15270 	{
15271 		/*
15272 		 * Run the partition quals through const-simplification similar to
15273 		 * check constraints.  We skip canonicalize_qual, though, because
15274 		 * partition quals should be in canonical form already.
15275 		 */
15276 		partConstraint =
15277 			(List *) eval_const_expressions(NULL,
15278 											(Node *) partConstraint);
15279 
15280 		/* XXX this sure looks wrong */
15281 		partConstraint = list_make1(make_ands_explicit(partConstraint));
15282 
15283 		/*
15284 		 * Adjust the generated constraint to match this partition's attribute
15285 		 * numbers.
15286 		 */
15287 		partConstraint = map_partition_varattnos(partConstraint, 1, attachrel,
15288 												 rel, &found_whole_row);
15289 		/* There can never be a whole-row reference here */
15290 		if (found_whole_row)
15291 			elog(ERROR,
15292 				 "unexpected whole-row reference found in partition key");
15293 
15294 		/* Validate partition constraints against the table being attached. */
15295 		QueuePartitionConstraintValidation(wqueue, attachrel, partConstraint,
15296 										   false);
15297 	}
15298 
15299 	/*
15300 	 * If we're attaching a partition other than the default partition and a
15301 	 * default one exists, then that partition's partition constraint changes,
15302 	 * so add an entry to the work queue to validate it, too.  (We must not do
15303 	 * this when the partition being attached is the default one; we already
15304 	 * did it above!)
15305 	 */
15306 	if (OidIsValid(defaultPartOid))
15307 	{
15308 		Relation	defaultrel;
15309 		List	   *defPartConstraint;
15310 
15311 		Assert(!cmd->bound->is_default);
15312 
15313 		/* we already hold a lock on the default partition */
15314 		defaultrel = heap_open(defaultPartOid, NoLock);
15315 		defPartConstraint =
15316 			get_proposed_default_constraint(partBoundConstraint);
15317 		/*
15318 		 * Map the Vars in the constraint expression from rel's attnos to
15319 		 * defaultrel's.
15320 		 */
15321 		defPartConstraint =
15322 			map_partition_varattnos(defPartConstraint,
15323 									1, defaultrel, rel, NULL);
15324 		QueuePartitionConstraintValidation(wqueue, defaultrel,
15325 										   defPartConstraint, true);
15326 
15327 		/* keep our lock until commit. */
15328 		heap_close(defaultrel, NoLock);
15329 	}
15330 
15331 	ObjectAddressSet(address, RelationRelationId, RelationGetRelid(attachrel));
15332 
15333 	/*
15334 	 * If the partition we just attached is partitioned itself, invalidate
15335 	 * relcache for all descendent partitions too to ensure that their
15336 	 * rd_partcheck expression trees are rebuilt; partitions already locked
15337 	 * at the beginning of this function.
15338 	 */
15339 	if (attachrel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
15340 	{
15341 		ListCell *l;
15342 
15343 		foreach(l, attachrel_children)
15344 		{
15345 			CacheInvalidateRelcacheByRelid(lfirst_oid(l));
15346 		}
15347 	}
15348 
15349 	/* keep our lock until commit */
15350 	heap_close(attachrel, NoLock);
15351 
15352 	return address;
15353 }
15354 
15355 /*
15356  * AttachPartitionEnsureIndexes
15357  *		subroutine for ATExecAttachPartition to create/match indexes
15358  *
15359  * Enforce the indexing rule for partitioned tables during ALTER TABLE / ATTACH
15360  * PARTITION: every partition must have an index attached to each index on the
15361  * partitioned table.
15362  */
15363 static void
AttachPartitionEnsureIndexes(Relation rel,Relation attachrel)15364 AttachPartitionEnsureIndexes(Relation rel, Relation attachrel)
15365 {
15366 	List	   *idxes;
15367 	List	   *attachRelIdxs;
15368 	Relation   *attachrelIdxRels;
15369 	IndexInfo **attachInfos;
15370 	int			i;
15371 	ListCell   *cell;
15372 	MemoryContext cxt;
15373 	MemoryContext oldcxt;
15374 
15375 	cxt = AllocSetContextCreate(CurrentMemoryContext,
15376 								"AttachPartitionEnsureIndexes",
15377 								ALLOCSET_DEFAULT_SIZES);
15378 	oldcxt = MemoryContextSwitchTo(cxt);
15379 
15380 	idxes = RelationGetIndexList(rel);
15381 	attachRelIdxs = RelationGetIndexList(attachrel);
15382 	attachrelIdxRels = palloc(sizeof(Relation) * list_length(attachRelIdxs));
15383 	attachInfos = palloc(sizeof(IndexInfo *) * list_length(attachRelIdxs));
15384 
15385 	/* Build arrays of all existing indexes and their IndexInfos */
15386 	i = 0;
15387 	foreach(cell, attachRelIdxs)
15388 	{
15389 		Oid			cldIdxId = lfirst_oid(cell);
15390 
15391 		attachrelIdxRels[i] = index_open(cldIdxId, AccessShareLock);
15392 		attachInfos[i] = BuildIndexInfo(attachrelIdxRels[i]);
15393 		i++;
15394 	}
15395 
15396 	/*
15397 	 * If we're attaching a foreign table, we must fail if any of the indexes
15398 	 * is a constraint index; otherwise, there's nothing to do here.  Do this
15399 	 * before starting work, to avoid wasting the effort of building a few
15400 	 * non-unique indexes before coming across a unique one.
15401 	 */
15402 	if (attachrel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
15403 	{
15404 		foreach(cell, idxes)
15405 		{
15406 			Oid			idx = lfirst_oid(cell);
15407 			Relation	idxRel = index_open(idx, AccessShareLock);
15408 
15409 			if (idxRel->rd_index->indisunique ||
15410 				idxRel->rd_index->indisprimary)
15411 				ereport(ERROR,
15412 						(errcode(ERRCODE_WRONG_OBJECT_TYPE),
15413 						 errmsg("cannot attach foreign table \"%s\" as partition of partitioned table \"%s\"",
15414 								RelationGetRelationName(attachrel),
15415 								RelationGetRelationName(rel)),
15416 						 errdetail("Table \"%s\" contains unique indexes.",
15417 								   RelationGetRelationName(rel))));
15418 			index_close(idxRel, AccessShareLock);
15419 		}
15420 
15421 		goto out;
15422 	}
15423 
15424 	/*
15425 	 * For each index on the partitioned table, find a matching one in the
15426 	 * partition-to-be; if one is not found, create one.
15427 	 */
15428 	foreach(cell, idxes)
15429 	{
15430 		Oid			idx = lfirst_oid(cell);
15431 		Relation	idxRel = index_open(idx, AccessShareLock);
15432 		IndexInfo  *info;
15433 		AttrNumber *attmap;
15434 		bool		found = false;
15435 		Oid			constraintOid;
15436 
15437 		/*
15438 		 * Ignore indexes in the partitioned table other than partitioned
15439 		 * indexes.
15440 		 */
15441 		if (idxRel->rd_rel->relkind != RELKIND_PARTITIONED_INDEX)
15442 		{
15443 			index_close(idxRel, AccessShareLock);
15444 			continue;
15445 		}
15446 
15447 		/* construct an indexinfo to compare existing indexes against */
15448 		info = BuildIndexInfo(idxRel);
15449 		attmap = convert_tuples_by_name_map(RelationGetDescr(attachrel),
15450 											RelationGetDescr(rel),
15451 											gettext_noop("could not convert row type"));
15452 		constraintOid = get_relation_idx_constraint_oid(RelationGetRelid(rel), idx);
15453 
15454 		/*
15455 		 * Scan the list of existing indexes in the partition-to-be, and mark
15456 		 * the first matching, unattached one we find, if any, as partition of
15457 		 * the parent index.  If we find one, we're done.
15458 		 */
15459 		for (i = 0; i < list_length(attachRelIdxs); i++)
15460 		{
15461 			Oid			cldIdxId = RelationGetRelid(attachrelIdxRels[i]);
15462 			Oid			cldConstrOid = InvalidOid;
15463 
15464 			/* does this index have a parent?  if so, can't use it */
15465 			if (attachrelIdxRels[i]->rd_rel->relispartition)
15466 				continue;
15467 
15468 			if (CompareIndexInfo(attachInfos[i], info,
15469 								 attachrelIdxRels[i]->rd_indcollation,
15470 								 idxRel->rd_indcollation,
15471 								 attachrelIdxRels[i]->rd_opfamily,
15472 								 idxRel->rd_opfamily,
15473 								 attmap,
15474 								 RelationGetDescr(rel)->natts))
15475 			{
15476 				/*
15477 				 * If this index is being created in the parent because of a
15478 				 * constraint, then the child needs to have a constraint also,
15479 				 * so look for one.  If there is no such constraint, this
15480 				 * index is no good, so keep looking.
15481 				 */
15482 				if (OidIsValid(constraintOid))
15483 				{
15484 					cldConstrOid =
15485 						get_relation_idx_constraint_oid(RelationGetRelid(attachrel),
15486 														cldIdxId);
15487 					/* no dice */
15488 					if (!OidIsValid(cldConstrOid))
15489 						continue;
15490 				}
15491 
15492 				/* bingo. */
15493 				IndexSetParentIndex(attachrelIdxRels[i], idx);
15494 				if (OidIsValid(constraintOid))
15495 					ConstraintSetParentConstraint(cldConstrOid, constraintOid);
15496 				found = true;
15497 				break;
15498 			}
15499 		}
15500 
15501 		/*
15502 		 * If no suitable index was found in the partition-to-be, create one
15503 		 * now.
15504 		 */
15505 		if (!found)
15506 		{
15507 			IndexStmt  *stmt;
15508 			Oid			constraintOid;
15509 
15510 			stmt = generateClonedIndexStmt(NULL, RelationGetRelid(attachrel),
15511 										   idxRel, attmap,
15512 										   RelationGetDescr(rel)->natts,
15513 										   &constraintOid);
15514 			DefineIndex(RelationGetRelid(attachrel), stmt, InvalidOid,
15515 						RelationGetRelid(idxRel),
15516 						constraintOid,
15517 						true, false, false, false, false);
15518 		}
15519 
15520 		index_close(idxRel, AccessShareLock);
15521 	}
15522 
15523 out:
15524 	/* Clean up. */
15525 	for (i = 0; i < list_length(attachRelIdxs); i++)
15526 		index_close(attachrelIdxRels[i], AccessShareLock);
15527 	MemoryContextSwitchTo(oldcxt);
15528 	MemoryContextDelete(cxt);
15529 }
15530 
15531 /*
15532  * isPartitionTrigger
15533  *		Subroutine for CloneRowTriggersToPartition: determine whether
15534  *		the given trigger has been cloned from another one.
15535  *
15536  * We use pg_depend as a proxy for this, since we don't have any direct
15537  * evidence.  This is an ugly hack to cope with a catalog deficiency.
15538  * Keep away from children.  Do not stare with naked eyes.  Do not propagate.
15539  */
15540 static bool
isPartitionTrigger(Oid trigger_oid)15541 isPartitionTrigger(Oid trigger_oid)
15542 {
15543 	Relation	pg_depend;
15544 	ScanKeyData key[2];
15545 	SysScanDesc	scan;
15546 	HeapTuple	tup;
15547 	bool		found = false;
15548 
15549 	pg_depend = heap_open(DependRelationId, AccessShareLock);
15550 
15551 	ScanKeyInit(&key[0], Anum_pg_depend_classid,
15552 				BTEqualStrategyNumber,
15553 				F_OIDEQ,
15554 				ObjectIdGetDatum(TriggerRelationId));
15555 	ScanKeyInit(&key[1], Anum_pg_depend_objid,
15556 				BTEqualStrategyNumber,
15557 				F_OIDEQ,
15558 				ObjectIdGetDatum(trigger_oid));
15559 
15560 	scan = systable_beginscan(pg_depend, DependDependerIndexId,
15561 							  true, NULL, 2, key);
15562 	while ((tup = systable_getnext(scan)) != NULL)
15563 	{
15564 		Form_pg_depend	dep = (Form_pg_depend) GETSTRUCT(tup);
15565 
15566 		if (dep->refclassid == TriggerRelationId)
15567 		{
15568 			found = true;
15569 			break;
15570 		}
15571 	}
15572 
15573 	systable_endscan(scan);
15574 	heap_close(pg_depend, AccessShareLock);
15575 
15576 	return found;
15577 }
15578 
15579 /*
15580  * CloneRowTriggersToPartition
15581  *		subroutine for ATExecAttachPartition/DefineRelation to create row
15582  *		triggers on partitions
15583  */
15584 static void
CloneRowTriggersToPartition(Relation parent,Relation partition)15585 CloneRowTriggersToPartition(Relation parent, Relation partition)
15586 {
15587 	Relation	pg_trigger;
15588 	ScanKeyData key;
15589 	SysScanDesc scan;
15590 	HeapTuple	tuple;
15591 	MemoryContext perTupCxt;
15592 
15593 	ScanKeyInit(&key, Anum_pg_trigger_tgrelid, BTEqualStrategyNumber,
15594 				F_OIDEQ, ObjectIdGetDatum(RelationGetRelid(parent)));
15595 	pg_trigger = heap_open(TriggerRelationId, RowExclusiveLock);
15596 	scan = systable_beginscan(pg_trigger, TriggerRelidNameIndexId,
15597 							  true, NULL, 1, &key);
15598 
15599 	perTupCxt = AllocSetContextCreate(CurrentMemoryContext,
15600 									  "clone trig", ALLOCSET_SMALL_SIZES);
15601 
15602 	while (HeapTupleIsValid(tuple = systable_getnext(scan)))
15603 	{
15604 		Form_pg_trigger trigForm = (Form_pg_trigger) GETSTRUCT(tuple);
15605 		CreateTrigStmt *trigStmt;
15606 		Node	   *qual = NULL;
15607 		Datum		value;
15608 		bool		isnull;
15609 		List	   *cols = NIL;
15610 		List	   *trigargs = NIL;
15611 		MemoryContext oldcxt;
15612 
15613 		/*
15614 		 * Ignore statement-level triggers; those are not cloned.
15615 		 */
15616 		if (!TRIGGER_FOR_ROW(trigForm->tgtype))
15617 			continue;
15618 
15619 		/*
15620 		 * Internal triggers require careful examination.  Ideally, we don't
15621 		 * clone them.
15622 		 *
15623 		 * However, if our parent is a partitioned relation, there might be
15624 		 * internal triggers that need cloning.  In that case, we must
15625 		 * skip clone it if the trigger on parent depends on another trigger.
15626 		 *
15627 		 * Note we dare not verify that the other trigger belongs to an
15628 		 * ancestor relation of our parent, because that creates deadlock
15629 		 * opportunities.
15630 		 */
15631 		if (trigForm->tgisinternal &&
15632 			(!parent->rd_rel->relispartition ||
15633 			 !isPartitionTrigger(HeapTupleGetOid(tuple))))
15634 			continue;
15635 
15636 		/*
15637 		 * Complain if we find an unexpected trigger type.
15638 		 */
15639 		if (!TRIGGER_FOR_AFTER(trigForm->tgtype))
15640 			elog(ERROR, "unexpected trigger \"%s\" found",
15641 				 NameStr(trigForm->tgname));
15642 
15643 		/* Use short-lived context for CREATE TRIGGER */
15644 		oldcxt = MemoryContextSwitchTo(perTupCxt);
15645 
15646 		/*
15647 		 * If there is a WHEN clause, generate a 'cooked' version of it that's
15648 		 * appropriate for the partition.
15649 		 */
15650 		value = heap_getattr(tuple, Anum_pg_trigger_tgqual,
15651 							 RelationGetDescr(pg_trigger), &isnull);
15652 		if (!isnull)
15653 		{
15654 			bool		found_whole_row;
15655 
15656 			qual = stringToNode(TextDatumGetCString(value));
15657 			qual = (Node *) map_partition_varattnos((List *) qual, PRS2_OLD_VARNO,
15658 													partition, parent,
15659 													&found_whole_row);
15660 			if (found_whole_row)
15661 				elog(ERROR, "unexpected whole-row reference found in trigger WHEN clause");
15662 			qual = (Node *) map_partition_varattnos((List *) qual, PRS2_NEW_VARNO,
15663 													partition, parent,
15664 													&found_whole_row);
15665 			if (found_whole_row)
15666 				elog(ERROR, "unexpected whole-row reference found in trigger WHEN clause");
15667 		}
15668 
15669 		/*
15670 		 * If there is a column list, transform it to a list of column names.
15671 		 * Note we don't need to map this list in any way ...
15672 		 */
15673 		if (trigForm->tgattr.dim1 > 0)
15674 		{
15675 			int			i;
15676 
15677 			for (i = 0; i < trigForm->tgattr.dim1; i++)
15678 			{
15679 				Form_pg_attribute col;
15680 
15681 				col = TupleDescAttr(parent->rd_att,
15682 									trigForm->tgattr.values[i] - 1);
15683 				cols = lappend(cols,
15684 							   makeString(pstrdup(NameStr(col->attname))));
15685 			}
15686 		}
15687 
15688 		/* Reconstruct trigger arguments list. */
15689 		if (trigForm->tgnargs > 0)
15690 		{
15691 			char	   *p;
15692 			int			i;
15693 
15694 			value = heap_getattr(tuple, Anum_pg_trigger_tgargs,
15695 								 RelationGetDescr(pg_trigger), &isnull);
15696 			if (isnull)
15697 				elog(ERROR, "tgargs is null for trigger \"%s\" in partition \"%s\"",
15698 					 NameStr(trigForm->tgname), RelationGetRelationName(partition));
15699 
15700 			p = (char *) VARDATA_ANY(DatumGetByteaPP(value));
15701 
15702 			for (i = 0; i < trigForm->tgnargs; i++)
15703 			{
15704 				trigargs = lappend(trigargs, makeString(pstrdup(p)));
15705 				p += strlen(p) + 1;
15706 			}
15707 		}
15708 
15709 		trigStmt = makeNode(CreateTrigStmt);
15710 		trigStmt->trigname = NameStr(trigForm->tgname);
15711 		trigStmt->relation = NULL;
15712 		trigStmt->funcname = NULL;	/* passed separately */
15713 		trigStmt->args = trigargs;
15714 		trigStmt->row = true;
15715 		trigStmt->timing = trigForm->tgtype & TRIGGER_TYPE_TIMING_MASK;
15716 		trigStmt->events = trigForm->tgtype & TRIGGER_TYPE_EVENT_MASK;
15717 		trigStmt->columns = cols;
15718 		trigStmt->whenClause = NULL;	/* passed separately */
15719 		trigStmt->isconstraint = OidIsValid(trigForm->tgconstraint);
15720 		trigStmt->transitionRels = NIL; /* not supported at present */
15721 		trigStmt->deferrable = trigForm->tgdeferrable;
15722 		trigStmt->initdeferred = trigForm->tginitdeferred;
15723 		trigStmt->constrrel = NULL; /* passed separately */
15724 
15725 		CreateTriggerFiringOn(trigStmt, NULL, RelationGetRelid(partition),
15726 							  trigForm->tgconstrrelid, InvalidOid, InvalidOid,
15727 							  trigForm->tgfoid, HeapTupleGetOid(tuple), qual,
15728 							  false, true, trigForm->tgenabled);
15729 
15730 		MemoryContextSwitchTo(oldcxt);
15731 		MemoryContextReset(perTupCxt);
15732 	}
15733 
15734 	MemoryContextDelete(perTupCxt);
15735 
15736 	systable_endscan(scan);
15737 	heap_close(pg_trigger, RowExclusiveLock);
15738 }
15739 
15740 /*
15741  * ALTER TABLE DETACH PARTITION
15742  *
15743  * Return the address of the relation that is no longer a partition of rel.
15744  */
15745 static ObjectAddress
ATExecDetachPartition(Relation rel,RangeVar * name)15746 ATExecDetachPartition(Relation rel, RangeVar *name)
15747 {
15748 	Relation	partRel,
15749 				classRel;
15750 	HeapTuple	tuple,
15751 				newtuple;
15752 	Datum		new_val[Natts_pg_class];
15753 	bool		new_null[Natts_pg_class],
15754 				new_repl[Natts_pg_class];
15755 	ObjectAddress address;
15756 	Oid			defaultPartOid;
15757 	List	   *indexes;
15758 	List	   *fks;
15759 	ListCell   *cell;
15760 
15761 	/*
15762 	 * We must lock the default partition, because detaching this partition
15763 	 * will change its partition constraint.
15764 	 */
15765 	defaultPartOid =
15766 		get_default_oid_from_partdesc(RelationGetPartitionDesc(rel));
15767 	if (OidIsValid(defaultPartOid))
15768 		LockRelationOid(defaultPartOid, AccessExclusiveLock);
15769 
15770 	partRel = heap_openrv(name, ShareUpdateExclusiveLock);
15771 
15772 	/* All inheritance related checks are performed within the function */
15773 	RemoveInheritance(partRel, rel);
15774 
15775 	/* Update pg_class tuple */
15776 	classRel = heap_open(RelationRelationId, RowExclusiveLock);
15777 	tuple = SearchSysCacheCopy1(RELOID,
15778 								ObjectIdGetDatum(RelationGetRelid(partRel)));
15779 	if (!HeapTupleIsValid(tuple))
15780 		elog(ERROR, "cache lookup failed for relation %u",
15781 			 RelationGetRelid(partRel));
15782 	Assert(((Form_pg_class) GETSTRUCT(tuple))->relispartition);
15783 
15784 	/* Clear relpartbound and reset relispartition */
15785 	memset(new_val, 0, sizeof(new_val));
15786 	memset(new_null, false, sizeof(new_null));
15787 	memset(new_repl, false, sizeof(new_repl));
15788 	new_val[Anum_pg_class_relpartbound - 1] = (Datum) 0;
15789 	new_null[Anum_pg_class_relpartbound - 1] = true;
15790 	new_repl[Anum_pg_class_relpartbound - 1] = true;
15791 	newtuple = heap_modify_tuple(tuple, RelationGetDescr(classRel),
15792 								 new_val, new_null, new_repl);
15793 
15794 	((Form_pg_class) GETSTRUCT(newtuple))->relispartition = false;
15795 	CatalogTupleUpdate(classRel, &newtuple->t_self, newtuple);
15796 	heap_freetuple(newtuple);
15797 
15798 	if (OidIsValid(defaultPartOid))
15799 	{
15800 		/*
15801 		 * If the relation being detached is the default partition itself,
15802 		 * remove it from the parent's pg_partitioned_table entry.
15803 		 *
15804 		 * If not, we must invalidate default partition's relcache entry, as
15805 		 * in StorePartitionBound: its partition constraint depends on every
15806 		 * other partition's partition constraint.
15807 		 */
15808 		if (RelationGetRelid(partRel) == defaultPartOid)
15809 			update_default_partition_oid(RelationGetRelid(rel), InvalidOid);
15810 		else
15811 			CacheInvalidateRelcacheByRelid(defaultPartOid);
15812 	}
15813 
15814 	/* detach indexes too */
15815 	indexes = RelationGetIndexList(partRel);
15816 	foreach(cell, indexes)
15817 	{
15818 		Oid			idxid = lfirst_oid(cell);
15819 		Relation	idx;
15820 		Oid			constrOid;
15821 
15822 		if (!has_superclass(idxid))
15823 			continue;
15824 
15825 		Assert((IndexGetRelation(get_partition_parent(idxid), false) ==
15826 				RelationGetRelid(rel)));
15827 
15828 		idx = index_open(idxid, AccessExclusiveLock);
15829 		IndexSetParentIndex(idx, InvalidOid);
15830 
15831 		/* If there's a constraint associated with the index, detach it too */
15832 		constrOid = get_relation_idx_constraint_oid(RelationGetRelid(partRel),
15833 													idxid);
15834 		if (OidIsValid(constrOid))
15835 			ConstraintSetParentConstraint(constrOid, InvalidOid);
15836 
15837 		index_close(idx, NoLock);
15838 	}
15839 	heap_close(classRel, RowExclusiveLock);
15840 
15841 	/* Drop any triggers that were cloned on creation/attach. */
15842 	DropClonedTriggersFromPartition(RelationGetRelid(partRel));
15843 
15844 	/*
15845 	 * Detach any foreign keys that are inherited.  This includes creating
15846 	 * additional action triggers.
15847 	 */
15848 	fks = copyObject(RelationGetFKeyList(partRel));
15849 	foreach(cell, fks)
15850 	{
15851 		ForeignKeyCacheInfo *fk = lfirst(cell);
15852 		HeapTuple	contup;
15853 		Form_pg_constraint conform;
15854 		Constraint *fkconstraint;
15855 
15856 		contup = SearchSysCache1(CONSTROID, ObjectIdGetDatum(fk->conoid));
15857 		if (!HeapTupleIsValid(contup))
15858 			elog(ERROR, "cache lookup failed for constraint %u", fk->conoid);
15859 		conform = (Form_pg_constraint) GETSTRUCT(contup);
15860 
15861 		/* consider only the inherited foreign keys */
15862 		if (conform->contype != CONSTRAINT_FOREIGN ||
15863 			!OidIsValid(conform->conparentid))
15864 		{
15865 			ReleaseSysCache(contup);
15866 			continue;
15867 		}
15868 
15869 		/* unset conparentid and adjust conislocal, coninhcount, etc. */
15870 		ConstraintSetParentConstraint(fk->conoid, InvalidOid);
15871 
15872 		/*
15873 		 * Make the action triggers on the referenced relation.  When this was
15874 		 * a partition the action triggers pointed to the parent rel (they
15875 		 * still do), but now we need separate ones of our own.
15876 		 */
15877 		fkconstraint = makeNode(Constraint);
15878 		fkconstraint->conname = pstrdup(NameStr(conform->conname));
15879 		fkconstraint->fk_upd_action = conform->confupdtype;
15880 		fkconstraint->fk_del_action = conform->confdeltype;
15881 		fkconstraint->deferrable = conform->condeferrable;
15882 		fkconstraint->initdeferred = conform->condeferred;
15883 
15884 		createForeignKeyActionTriggers(partRel, conform->confrelid,
15885 									   fkconstraint, fk->conoid,
15886 									   conform->conindid);
15887 
15888 		ReleaseSysCache(contup);
15889 	}
15890 	list_free_deep(fks);
15891 
15892 	/*
15893 	 * Invalidate the parent's relcache so that the partition is no longer
15894 	 * included in its partition descriptor.
15895 	 */
15896 	CacheInvalidateRelcache(rel);
15897 
15898 	/*
15899 	 * If the partition we just detached is partitioned itself, invalidate
15900 	 * relcache for all descendent partitions too to ensure that their
15901 	 * rd_partcheck expression trees are rebuilt; must lock partitions
15902 	 * before doing so, using the same lockmode as what partRel has been
15903 	 * locked with by the caller.
15904 	 */
15905 	if (partRel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
15906 	{
15907 		List   *children;
15908 
15909 		children = find_all_inheritors(RelationGetRelid(partRel),
15910 									   AccessExclusiveLock, NULL);
15911 		foreach(cell, children)
15912 		{
15913 			CacheInvalidateRelcacheByRelid(lfirst_oid(cell));
15914 		}
15915 	}
15916 
15917 	ObjectAddressSet(address, RelationRelationId, RelationGetRelid(partRel));
15918 
15919 	/* keep our lock until commit */
15920 	heap_close(partRel, NoLock);
15921 
15922 	return address;
15923 }
15924 
15925 /*
15926  * DropClonedTriggersFromPartition
15927  *		subroutine for ATExecDetachPartition to remove any triggers that were
15928  *		cloned to the partition when it was created-as-partition or attached.
15929  *		This undoes what CloneRowTriggersToPartition did.
15930  */
15931 static void
DropClonedTriggersFromPartition(Oid partitionId)15932 DropClonedTriggersFromPartition(Oid partitionId)
15933 {
15934 	ScanKeyData skey;
15935 	SysScanDesc	scan;
15936 	HeapTuple	trigtup;
15937 	Relation	tgrel;
15938 	ObjectAddresses *objects;
15939 
15940 	objects = new_object_addresses();
15941 
15942 	/*
15943 	 * Scan pg_trigger to search for all triggers on this rel.
15944 	 */
15945 	ScanKeyInit(&skey, Anum_pg_trigger_tgrelid, BTEqualStrategyNumber,
15946 				F_OIDEQ, ObjectIdGetDatum(partitionId));
15947 	tgrel = heap_open(TriggerRelationId, RowExclusiveLock);
15948 	scan = systable_beginscan(tgrel, TriggerRelidNameIndexId,
15949 							  true, NULL, 1, &skey);
15950 	while (HeapTupleIsValid(trigtup = systable_getnext(scan)))
15951 	{
15952 		Oid			trigoid = HeapTupleGetOid(trigtup);
15953 		ObjectAddress trig;
15954 
15955 		/* Ignore triggers that weren't cloned */
15956 		if (!isPartitionTrigger(trigoid))
15957 			continue;
15958 
15959 		/*
15960 		 * This is ugly, but necessary: remove the dependency markings on the
15961 		 * trigger so that it can be removed.
15962 		 */
15963 		deleteDependencyRecordsForClass(TriggerRelationId, trigoid,
15964 										TriggerRelationId,
15965 										DEPENDENCY_INTERNAL_AUTO);
15966 		deleteDependencyRecordsForClass(TriggerRelationId, trigoid,
15967 										RelationRelationId,
15968 										DEPENDENCY_INTERNAL_AUTO);
15969 
15970 		/* remember this trigger to remove it below */
15971 		ObjectAddressSet(trig, TriggerRelationId, trigoid);
15972 		add_exact_object_address(&trig, objects);
15973 	}
15974 
15975 	/* make the dependency removal visible to the deletion below */
15976 	CommandCounterIncrement();
15977 	performMultipleDeletions(objects, DROP_RESTRICT, PERFORM_DELETION_INTERNAL);
15978 
15979 	/* done */
15980 	free_object_addresses(objects);
15981 	systable_endscan(scan);
15982 	heap_close(tgrel, RowExclusiveLock);
15983 }
15984 
15985 /*
15986  * Before acquiring lock on an index, acquire the same lock on the owning
15987  * table.
15988  */
15989 struct AttachIndexCallbackState
15990 {
15991 	Oid			partitionOid;
15992 	Oid			parentTblOid;
15993 	bool		lockedParentTbl;
15994 };
15995 
15996 static void
RangeVarCallbackForAttachIndex(const RangeVar * rv,Oid relOid,Oid oldRelOid,void * arg)15997 RangeVarCallbackForAttachIndex(const RangeVar *rv, Oid relOid, Oid oldRelOid,
15998 							   void *arg)
15999 {
16000 	struct AttachIndexCallbackState *state;
16001 	Form_pg_class classform;
16002 	HeapTuple	tuple;
16003 
16004 	state = (struct AttachIndexCallbackState *) arg;
16005 
16006 	if (!state->lockedParentTbl)
16007 	{
16008 		LockRelationOid(state->parentTblOid, AccessShareLock);
16009 		state->lockedParentTbl = true;
16010 	}
16011 
16012 	/*
16013 	 * If we previously locked some other heap, and the name we're looking up
16014 	 * no longer refers to an index on that relation, release the now-useless
16015 	 * lock.  XXX maybe we should do *after* we verify whether the index does
16016 	 * not actually belong to the same relation ...
16017 	 */
16018 	if (relOid != oldRelOid && OidIsValid(state->partitionOid))
16019 	{
16020 		UnlockRelationOid(state->partitionOid, AccessShareLock);
16021 		state->partitionOid = InvalidOid;
16022 	}
16023 
16024 	/* Didn't find a relation, so no need for locking or permission checks. */
16025 	if (!OidIsValid(relOid))
16026 		return;
16027 
16028 	tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relOid));
16029 	if (!HeapTupleIsValid(tuple))
16030 		return;					/* concurrently dropped, so nothing to do */
16031 	classform = (Form_pg_class) GETSTRUCT(tuple);
16032 	if (classform->relkind != RELKIND_PARTITIONED_INDEX &&
16033 		classform->relkind != RELKIND_INDEX)
16034 		ereport(ERROR,
16035 				(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
16036 				 errmsg("\"%s\" is not an index", rv->relname)));
16037 	ReleaseSysCache(tuple);
16038 
16039 	/*
16040 	 * Since we need only examine the heap's tupledesc, an access share lock
16041 	 * on it (preventing any DDL) is sufficient.
16042 	 */
16043 	state->partitionOid = IndexGetRelation(relOid, false);
16044 	LockRelationOid(state->partitionOid, AccessShareLock);
16045 }
16046 
16047 /*
16048  * ALTER INDEX i1 ATTACH PARTITION i2
16049  */
16050 static ObjectAddress
ATExecAttachPartitionIdx(List ** wqueue,Relation parentIdx,RangeVar * name)16051 ATExecAttachPartitionIdx(List **wqueue, Relation parentIdx, RangeVar *name)
16052 {
16053 	Relation	partIdx;
16054 	Relation	partTbl;
16055 	Relation	parentTbl;
16056 	ObjectAddress address;
16057 	Oid			partIdxId;
16058 	Oid			currParent;
16059 	struct AttachIndexCallbackState state;
16060 
16061 	/*
16062 	 * We need to obtain lock on the index 'name' to modify it, but we also
16063 	 * need to read its owning table's tuple descriptor -- so we need to lock
16064 	 * both.  To avoid deadlocks, obtain lock on the table before doing so on
16065 	 * the index.  Furthermore, we need to examine the parent table of the
16066 	 * partition, so lock that one too.
16067 	 */
16068 	state.partitionOid = InvalidOid;
16069 	state.parentTblOid = parentIdx->rd_index->indrelid;
16070 	state.lockedParentTbl = false;
16071 	partIdxId =
16072 		RangeVarGetRelidExtended(name, AccessExclusiveLock, 0,
16073 								 RangeVarCallbackForAttachIndex,
16074 								 (void *) &state);
16075 	/* Not there? */
16076 	if (!OidIsValid(partIdxId))
16077 		ereport(ERROR,
16078 				(errcode(ERRCODE_UNDEFINED_OBJECT),
16079 				 errmsg("index \"%s\" does not exist", name->relname)));
16080 
16081 	/* no deadlock risk: RangeVarGetRelidExtended already acquired the lock */
16082 	partIdx = relation_open(partIdxId, AccessExclusiveLock);
16083 
16084 	/* we already hold locks on both tables, so this is safe: */
16085 	parentTbl = relation_open(parentIdx->rd_index->indrelid, AccessShareLock);
16086 	partTbl = relation_open(partIdx->rd_index->indrelid, NoLock);
16087 
16088 	ObjectAddressSet(address, RelationRelationId, RelationGetRelid(partIdx));
16089 
16090 	/* Silently do nothing if already in the right state */
16091 	currParent = partIdx->rd_rel->relispartition ?
16092 		get_partition_parent(partIdxId) : InvalidOid;
16093 	if (currParent != RelationGetRelid(parentIdx))
16094 	{
16095 		IndexInfo  *childInfo;
16096 		IndexInfo  *parentInfo;
16097 		AttrNumber *attmap;
16098 		bool		found;
16099 		int			i;
16100 		PartitionDesc partDesc;
16101 		Oid			constraintOid,
16102 					cldConstrId = InvalidOid;
16103 
16104 		/*
16105 		 * If this partition already has an index attached, refuse the
16106 		 * operation.
16107 		 */
16108 		refuseDupeIndexAttach(parentIdx, partIdx, partTbl);
16109 
16110 		if (OidIsValid(currParent))
16111 			ereport(ERROR,
16112 					(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
16113 					 errmsg("cannot attach index \"%s\" as a partition of index \"%s\"",
16114 							RelationGetRelationName(partIdx),
16115 							RelationGetRelationName(parentIdx)),
16116 					 errdetail("Index \"%s\" is already attached to another index.",
16117 							   RelationGetRelationName(partIdx))));
16118 
16119 		/* Make sure it indexes a partition of the other index's table */
16120 		partDesc = RelationGetPartitionDesc(parentTbl);
16121 		found = false;
16122 		for (i = 0; i < partDesc->nparts; i++)
16123 		{
16124 			if (partDesc->oids[i] == state.partitionOid)
16125 			{
16126 				found = true;
16127 				break;
16128 			}
16129 		}
16130 		if (!found)
16131 			ereport(ERROR,
16132 					(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
16133 					 errmsg("cannot attach index \"%s\" as a partition of index \"%s\"",
16134 							RelationGetRelationName(partIdx),
16135 							RelationGetRelationName(parentIdx)),
16136 					 errdetail("Index \"%s\" is not an index on any partition of table \"%s\".",
16137 							   RelationGetRelationName(partIdx),
16138 							   RelationGetRelationName(parentTbl))));
16139 
16140 		/* Ensure the indexes are compatible */
16141 		childInfo = BuildIndexInfo(partIdx);
16142 		parentInfo = BuildIndexInfo(parentIdx);
16143 		attmap = convert_tuples_by_name_map(RelationGetDescr(partTbl),
16144 											RelationGetDescr(parentTbl),
16145 											gettext_noop("could not convert row type"));
16146 		if (!CompareIndexInfo(childInfo, parentInfo,
16147 							  partIdx->rd_indcollation,
16148 							  parentIdx->rd_indcollation,
16149 							  partIdx->rd_opfamily,
16150 							  parentIdx->rd_opfamily,
16151 							  attmap,
16152 							  RelationGetDescr(parentTbl)->natts))
16153 			ereport(ERROR,
16154 					(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
16155 					 errmsg("cannot attach index \"%s\" as a partition of index \"%s\"",
16156 							RelationGetRelationName(partIdx),
16157 							RelationGetRelationName(parentIdx)),
16158 					 errdetail("The index definitions do not match.")));
16159 
16160 		/*
16161 		 * If there is a constraint in the parent, make sure there is one in
16162 		 * the child too.
16163 		 */
16164 		constraintOid = get_relation_idx_constraint_oid(RelationGetRelid(parentTbl),
16165 														RelationGetRelid(parentIdx));
16166 
16167 		if (OidIsValid(constraintOid))
16168 		{
16169 			cldConstrId = get_relation_idx_constraint_oid(RelationGetRelid(partTbl),
16170 														  partIdxId);
16171 			if (!OidIsValid(cldConstrId))
16172 				ereport(ERROR,
16173 						(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
16174 						 errmsg("cannot attach index \"%s\" as a partition of index \"%s\"",
16175 								RelationGetRelationName(partIdx),
16176 								RelationGetRelationName(parentIdx)),
16177 						 errdetail("The index \"%s\" belongs to a constraint in table \"%s\" but no constraint exists for index \"%s\".",
16178 								   RelationGetRelationName(parentIdx),
16179 								   RelationGetRelationName(parentTbl),
16180 								   RelationGetRelationName(partIdx))));
16181 		}
16182 
16183 		/* All good -- do it */
16184 		IndexSetParentIndex(partIdx, RelationGetRelid(parentIdx));
16185 		if (OidIsValid(constraintOid))
16186 			ConstraintSetParentConstraint(cldConstrId, constraintOid);
16187 
16188 		pfree(attmap);
16189 
16190 		validatePartitionedIndex(parentIdx, parentTbl);
16191 	}
16192 
16193 	relation_close(parentTbl, AccessShareLock);
16194 	/* keep these locks till commit */
16195 	relation_close(partTbl, NoLock);
16196 	relation_close(partIdx, NoLock);
16197 
16198 	return address;
16199 }
16200 
16201 /*
16202  * Verify whether the given partition already contains an index attached
16203  * to the given partitioned index.  If so, raise an error.
16204  */
16205 static void
refuseDupeIndexAttach(Relation parentIdx,Relation partIdx,Relation partitionTbl)16206 refuseDupeIndexAttach(Relation parentIdx, Relation partIdx, Relation partitionTbl)
16207 {
16208 	Relation	pg_inherits;
16209 	ScanKeyData key;
16210 	HeapTuple	tuple;
16211 	SysScanDesc scan;
16212 
16213 	pg_inherits = heap_open(InheritsRelationId, AccessShareLock);
16214 	ScanKeyInit(&key, Anum_pg_inherits_inhparent,
16215 				BTEqualStrategyNumber, F_OIDEQ,
16216 				ObjectIdGetDatum(RelationGetRelid(parentIdx)));
16217 	scan = systable_beginscan(pg_inherits, InheritsParentIndexId, true,
16218 							  NULL, 1, &key);
16219 	while (HeapTupleIsValid(tuple = systable_getnext(scan)))
16220 	{
16221 		Form_pg_inherits inhForm;
16222 		Oid			tab;
16223 
16224 		inhForm = (Form_pg_inherits) GETSTRUCT(tuple);
16225 		tab = IndexGetRelation(inhForm->inhrelid, false);
16226 		if (tab == RelationGetRelid(partitionTbl))
16227 			ereport(ERROR,
16228 					(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
16229 					 errmsg("cannot attach index \"%s\" as a partition of index \"%s\"",
16230 							RelationGetRelationName(partIdx),
16231 							RelationGetRelationName(parentIdx)),
16232 					 errdetail("Another index is already attached for partition \"%s\".",
16233 							   RelationGetRelationName(partitionTbl))));
16234 	}
16235 
16236 	systable_endscan(scan);
16237 	heap_close(pg_inherits, AccessShareLock);
16238 }
16239 
16240 /*
16241  * Verify whether the set of attached partition indexes to a parent index on
16242  * a partitioned table is complete.  If it is, mark the parent index valid.
16243  *
16244  * This should be called each time a partition index is attached.
16245  */
16246 static void
validatePartitionedIndex(Relation partedIdx,Relation partedTbl)16247 validatePartitionedIndex(Relation partedIdx, Relation partedTbl)
16248 {
16249 	Relation	inheritsRel;
16250 	SysScanDesc scan;
16251 	ScanKeyData key;
16252 	int			tuples = 0;
16253 	HeapTuple	inhTup;
16254 	bool		updated = false;
16255 
16256 	Assert(partedIdx->rd_rel->relkind == RELKIND_PARTITIONED_INDEX);
16257 
16258 	/*
16259 	 * Scan pg_inherits for this parent index.  Count each valid index we find
16260 	 * (verifying the pg_index entry for each), and if we reach the total
16261 	 * amount we expect, we can mark this parent index as valid.
16262 	 */
16263 	inheritsRel = heap_open(InheritsRelationId, AccessShareLock);
16264 	ScanKeyInit(&key, Anum_pg_inherits_inhparent,
16265 				BTEqualStrategyNumber, F_OIDEQ,
16266 				ObjectIdGetDatum(RelationGetRelid(partedIdx)));
16267 	scan = systable_beginscan(inheritsRel, InheritsParentIndexId, true,
16268 							  NULL, 1, &key);
16269 	while ((inhTup = systable_getnext(scan)) != NULL)
16270 	{
16271 		Form_pg_inherits inhForm = (Form_pg_inherits) GETSTRUCT(inhTup);
16272 		HeapTuple	indTup;
16273 		Form_pg_index indexForm;
16274 
16275 		indTup = SearchSysCache1(INDEXRELID,
16276 								 ObjectIdGetDatum(inhForm->inhrelid));
16277 		if (!HeapTupleIsValid(indTup))
16278 			elog(ERROR, "cache lookup failed for index %u", inhForm->inhrelid);
16279 		indexForm = (Form_pg_index) GETSTRUCT(indTup);
16280 		if (IndexIsValid(indexForm))
16281 			tuples += 1;
16282 		ReleaseSysCache(indTup);
16283 	}
16284 
16285 	/* Done with pg_inherits */
16286 	systable_endscan(scan);
16287 	heap_close(inheritsRel, AccessShareLock);
16288 
16289 	/*
16290 	 * If we found as many inherited indexes as the partitioned table has
16291 	 * partitions, we're good; update pg_index to set indisvalid.
16292 	 */
16293 	if (tuples == RelationGetPartitionDesc(partedTbl)->nparts)
16294 	{
16295 		Relation	idxRel;
16296 		HeapTuple	newtup;
16297 
16298 		idxRel = heap_open(IndexRelationId, RowExclusiveLock);
16299 
16300 		newtup = heap_copytuple(partedIdx->rd_indextuple);
16301 		((Form_pg_index) GETSTRUCT(newtup))->indisvalid = true;
16302 		updated = true;
16303 
16304 		CatalogTupleUpdate(idxRel, &partedIdx->rd_indextuple->t_self, newtup);
16305 
16306 		heap_close(idxRel, RowExclusiveLock);
16307 	}
16308 
16309 	/*
16310 	 * If this index is in turn a partition of a larger index, validating it
16311 	 * might cause the parent to become valid also.  Try that.
16312 	 */
16313 	if (updated && partedIdx->rd_rel->relispartition)
16314 	{
16315 		Oid			parentIdxId,
16316 					parentTblId;
16317 		Relation	parentIdx,
16318 					parentTbl;
16319 
16320 		/* make sure we see the validation we just did */
16321 		CommandCounterIncrement();
16322 
16323 		parentIdxId = get_partition_parent(RelationGetRelid(partedIdx));
16324 		parentTblId = get_partition_parent(RelationGetRelid(partedTbl));
16325 		parentIdx = relation_open(parentIdxId, AccessExclusiveLock);
16326 		parentTbl = relation_open(parentTblId, AccessExclusiveLock);
16327 		Assert(!parentIdx->rd_index->indisvalid);
16328 
16329 		validatePartitionedIndex(parentIdx, parentTbl);
16330 
16331 		relation_close(parentIdx, AccessExclusiveLock);
16332 		relation_close(parentTbl, AccessExclusiveLock);
16333 	}
16334 }
16335