1 /*-------------------------------------------------------------------------
2  *
3  * tablecmds.c
4  *	  Commands for creating and altering table structures and settings
5  *
6  * Portions Copyright (c) 1996-2017, 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/multixact.h"
20 #include "access/reloptions.h"
21 #include "access/relscan.h"
22 #include "access/sysattr.h"
23 #include "access/tupconvert.h"
24 #include "access/xact.h"
25 #include "access/xlog.h"
26 #include "catalog/catalog.h"
27 #include "catalog/dependency.h"
28 #include "catalog/heap.h"
29 #include "catalog/index.h"
30 #include "catalog/indexing.h"
31 #include "catalog/namespace.h"
32 #include "catalog/objectaccess.h"
33 #include "catalog/partition.h"
34 #include "catalog/pg_am.h"
35 #include "catalog/pg_collation.h"
36 #include "catalog/pg_constraint.h"
37 #include "catalog/pg_constraint_fn.h"
38 #include "catalog/pg_depend.h"
39 #include "catalog/pg_foreign_table.h"
40 #include "catalog/pg_inherits.h"
41 #include "catalog/pg_inherits_fn.h"
42 #include "catalog/pg_namespace.h"
43 #include "catalog/pg_opclass.h"
44 #include "catalog/pg_tablespace.h"
45 #include "catalog/pg_trigger.h"
46 #include "catalog/pg_type.h"
47 #include "catalog/pg_type_fn.h"
48 #include "catalog/storage.h"
49 #include "catalog/storage_xlog.h"
50 #include "catalog/toasting.h"
51 #include "commands/cluster.h"
52 #include "commands/comment.h"
53 #include "commands/defrem.h"
54 #include "commands/event_trigger.h"
55 #include "commands/policy.h"
56 #include "commands/sequence.h"
57 #include "commands/tablecmds.h"
58 #include "commands/tablespace.h"
59 #include "commands/trigger.h"
60 #include "commands/typecmds.h"
61 #include "commands/user.h"
62 #include "executor/executor.h"
63 #include "foreign/foreign.h"
64 #include "miscadmin.h"
65 #include "nodes/makefuncs.h"
66 #include "nodes/nodeFuncs.h"
67 #include "nodes/parsenodes.h"
68 #include "optimizer/clauses.h"
69 #include "optimizer/planner.h"
70 #include "optimizer/predtest.h"
71 #include "optimizer/prep.h"
72 #include "optimizer/var.h"
73 #include "parser/parse_clause.h"
74 #include "parser/parse_coerce.h"
75 #include "parser/parse_collate.h"
76 #include "parser/parse_expr.h"
77 #include "parser/parse_oper.h"
78 #include "parser/parse_relation.h"
79 #include "parser/parse_type.h"
80 #include "parser/parse_utilcmd.h"
81 #include "parser/parser.h"
82 #include "pgstat.h"
83 #include "rewrite/rewriteDefine.h"
84 #include "rewrite/rewriteHandler.h"
85 #include "rewrite/rewriteManip.h"
86 #include "storage/bufmgr.h"
87 #include "storage/lmgr.h"
88 #include "storage/lock.h"
89 #include "storage/predicate.h"
90 #include "storage/smgr.h"
91 #include "utils/acl.h"
92 #include "utils/builtins.h"
93 #include "utils/fmgroids.h"
94 #include "utils/inval.h"
95 #include "utils/lsyscache.h"
96 #include "utils/memutils.h"
97 #include "utils/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 	/* Objects to rebuild after completing ALTER TYPE operations */
172 	List	   *changedConstraintOids;	/* OIDs of constraints to rebuild */
173 	List	   *changedConstraintDefs;	/* string definitions of same */
174 	List	   *changedIndexOids;	/* OIDs of indexes to rebuild */
175 	List	   *changedIndexDefs;	/* string definitions of same */
176 	char	   *replicaIdentityIndex;	/* index to reset as REPLICA IDENTITY */
177 	char	   *clusterOnIndex;	/* index to use for CLUSTER */
178 } AlteredTableInfo;
179 
180 /* Struct describing one new constraint to check in Phase 3 scan */
181 /* Note: new NOT NULL constraints are handled elsewhere */
182 typedef struct NewConstraint
183 {
184 	char	   *name;			/* Constraint name, or NULL if none */
185 	ConstrType	contype;		/* CHECK or FOREIGN */
186 	Oid			refrelid;		/* PK rel, if FOREIGN */
187 	Oid			refindid;		/* OID of PK's index, if FOREIGN */
188 	Oid			conid;			/* OID of pg_constraint entry, if FOREIGN */
189 	Node	   *qual;			/* Check expr or CONSTR_FOREIGN Constraint */
190 	ExprState  *qualstate;		/* Execution state for CHECK expr */
191 } NewConstraint;
192 
193 /*
194  * Struct describing one new column value that needs to be computed during
195  * Phase 3 copy (this could be either a new column with a non-null default, or
196  * a column that we're changing the type of).  Columns without such an entry
197  * are just copied from the old table during ATRewriteTable.  Note that the
198  * expr is an expression over *old* table values.
199  */
200 typedef struct NewColumnValue
201 {
202 	AttrNumber	attnum;			/* which column */
203 	Expr	   *expr;			/* expression to compute */
204 	ExprState  *exprstate;		/* execution state */
205 } NewColumnValue;
206 
207 /*
208  * Error-reporting support for RemoveRelations
209  */
210 struct dropmsgstrings
211 {
212 	char		kind;
213 	int			nonexistent_code;
214 	const char *nonexistent_msg;
215 	const char *skipping_msg;
216 	const char *nota_msg;
217 	const char *drophint_msg;
218 };
219 
220 static const struct dropmsgstrings dropmsgstringarray[] = {
221 	{RELKIND_RELATION,
222 		ERRCODE_UNDEFINED_TABLE,
223 		gettext_noop("table \"%s\" does not exist"),
224 		gettext_noop("table \"%s\" does not exist, skipping"),
225 		gettext_noop("\"%s\" is not a table"),
226 	gettext_noop("Use DROP TABLE to remove a table.")},
227 	{RELKIND_SEQUENCE,
228 		ERRCODE_UNDEFINED_TABLE,
229 		gettext_noop("sequence \"%s\" does not exist"),
230 		gettext_noop("sequence \"%s\" does not exist, skipping"),
231 		gettext_noop("\"%s\" is not a sequence"),
232 	gettext_noop("Use DROP SEQUENCE to remove a sequence.")},
233 	{RELKIND_VIEW,
234 		ERRCODE_UNDEFINED_TABLE,
235 		gettext_noop("view \"%s\" does not exist"),
236 		gettext_noop("view \"%s\" does not exist, skipping"),
237 		gettext_noop("\"%s\" is not a view"),
238 	gettext_noop("Use DROP VIEW to remove a view.")},
239 	{RELKIND_MATVIEW,
240 		ERRCODE_UNDEFINED_TABLE,
241 		gettext_noop("materialized view \"%s\" does not exist"),
242 		gettext_noop("materialized view \"%s\" does not exist, skipping"),
243 		gettext_noop("\"%s\" is not a materialized view"),
244 	gettext_noop("Use DROP MATERIALIZED VIEW to remove a materialized view.")},
245 	{RELKIND_INDEX,
246 		ERRCODE_UNDEFINED_OBJECT,
247 		gettext_noop("index \"%s\" does not exist"),
248 		gettext_noop("index \"%s\" does not exist, skipping"),
249 		gettext_noop("\"%s\" is not an index"),
250 	gettext_noop("Use DROP INDEX to remove an index.")},
251 	{RELKIND_COMPOSITE_TYPE,
252 		ERRCODE_UNDEFINED_OBJECT,
253 		gettext_noop("type \"%s\" does not exist"),
254 		gettext_noop("type \"%s\" does not exist, skipping"),
255 		gettext_noop("\"%s\" is not a type"),
256 	gettext_noop("Use DROP TYPE to remove a type.")},
257 	{RELKIND_FOREIGN_TABLE,
258 		ERRCODE_UNDEFINED_OBJECT,
259 		gettext_noop("foreign table \"%s\" does not exist"),
260 		gettext_noop("foreign table \"%s\" does not exist, skipping"),
261 		gettext_noop("\"%s\" is not a foreign table"),
262 	gettext_noop("Use DROP FOREIGN TABLE to remove a foreign table.")},
263 	{RELKIND_PARTITIONED_TABLE,
264 		ERRCODE_UNDEFINED_TABLE,
265 		gettext_noop("table \"%s\" does not exist"),
266 		gettext_noop("table \"%s\" does not exist, skipping"),
267 		gettext_noop("\"%s\" is not a table"),
268 	gettext_noop("Use DROP TABLE to remove a table.")},
269 	{'\0', 0, NULL, NULL, NULL, NULL}
270 };
271 
272 struct DropRelationCallbackState
273 {
274 	char		relkind;
275 	Oid			heapOid;
276 	Oid			partParentOid;
277 	bool		concurrent;
278 };
279 
280 /* Alter table target-type flags for ATSimplePermissions */
281 #define		ATT_TABLE				0x0001
282 #define		ATT_VIEW				0x0002
283 #define		ATT_MATVIEW				0x0004
284 #define		ATT_INDEX				0x0008
285 #define		ATT_COMPOSITE_TYPE		0x0010
286 #define		ATT_FOREIGN_TABLE		0x0020
287 
288 /*
289  * Partition tables are expected to be dropped when the parent partitioned
290  * table gets dropped. Hence for partitioning we use AUTO dependency.
291  * Otherwise, for regular inheritance use NORMAL dependency.
292  */
293 #define child_dependency_type(child_is_partition)	\
294 	((child_is_partition) ? DEPENDENCY_AUTO : DEPENDENCY_NORMAL)
295 
296 static void truncate_check_rel(Relation rel);
297 static List *MergeAttributes(List *schema, List *supers, char relpersistence,
298 				bool is_partition, List **supOids, List **supconstr,
299 				int *supOidCount);
300 static bool MergeCheckConstraint(List *constraints, char *name, Node *expr);
301 static void MergeAttributesIntoExisting(Relation child_rel, Relation parent_rel);
302 static void MergeConstraintsIntoExisting(Relation child_rel, Relation parent_rel);
303 static void StoreCatalogInheritance(Oid relationId, List *supers,
304 						bool child_is_partition);
305 static void StoreCatalogInheritance1(Oid relationId, Oid parentOid,
306 						 int32 seqNumber, Relation inhRelation,
307 						 bool child_is_partition);
308 static int	findAttrByName(const char *attributeName, List *schema);
309 static void AlterIndexNamespaces(Relation classRel, Relation rel,
310 					 Oid oldNspOid, Oid newNspOid, ObjectAddresses *objsMoved);
311 static void AlterSeqNamespaces(Relation classRel, Relation rel,
312 				   Oid oldNspOid, Oid newNspOid, ObjectAddresses *objsMoved,
313 				   LOCKMODE lockmode);
314 static ObjectAddress ATExecAlterConstraint(Relation rel, AlterTableCmd *cmd,
315 					  bool recurse, bool recursing, LOCKMODE lockmode);
316 static ObjectAddress ATExecValidateConstraint(List **wqueue, Relation rel,
317 						 char *constrName, bool recurse, bool recursing,
318 						 LOCKMODE lockmode);
319 static int transformColumnNameList(Oid relId, List *colList,
320 						int16 *attnums, Oid *atttypids);
321 static int transformFkeyGetPrimaryKey(Relation pkrel, Oid *indexOid,
322 						   List **attnamelist,
323 						   int16 *attnums, Oid *atttypids,
324 						   Oid *opclasses);
325 static Oid transformFkeyCheckAttrs(Relation pkrel,
326 						int numattrs, int16 *attnums,
327 						Oid *opclasses);
328 static void checkFkeyPermissions(Relation rel, int16 *attnums, int natts);
329 static CoercionPathType findFkeyCast(Oid targetTypeId, Oid sourceTypeId,
330 			 Oid *funcid);
331 static void validateForeignKeyConstraint(char *conname,
332 							 Relation rel, Relation pkrel,
333 							 Oid pkindOid, Oid constraintOid);
334 static void createForeignKeyTriggers(Relation rel, Oid refRelOid,
335 						 Constraint *fkconstraint,
336 						 Oid constraintOid, Oid indexOid);
337 static void ATController(AlterTableStmt *parsetree,
338 			 Relation rel, List *cmds, bool recurse, LOCKMODE lockmode);
339 static void ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd,
340 		  bool recurse, bool recursing, LOCKMODE lockmode);
341 static void ATRewriteCatalogs(List **wqueue, LOCKMODE lockmode);
342 static void ATExecCmd(List **wqueue, AlteredTableInfo *tab, Relation rel,
343 		  AlterTableCmd *cmd, LOCKMODE lockmode);
344 static void ATRewriteTables(AlterTableStmt *parsetree,
345 				List **wqueue, LOCKMODE lockmode);
346 static void ATRewriteTable(AlteredTableInfo *tab, Oid OIDNewHeap, LOCKMODE lockmode);
347 static AlteredTableInfo *ATGetQueueEntry(List **wqueue, Relation rel);
348 static void ATSimplePermissions(Relation rel, int allowed_targets);
349 static void ATWrongRelkindError(Relation rel, int allowed_targets);
350 static void ATSimpleRecursion(List **wqueue, Relation rel,
351 				  AlterTableCmd *cmd, bool recurse, LOCKMODE lockmode);
352 static void ATTypedTableRecursion(List **wqueue, Relation rel, AlterTableCmd *cmd,
353 					  LOCKMODE lockmode);
354 static List *find_typed_table_dependencies(Oid typeOid, const char *typeName,
355 							  DropBehavior behavior);
356 static void ATPrepAddColumn(List **wqueue, Relation rel, bool recurse, bool recursing,
357 				bool is_view, AlterTableCmd *cmd, LOCKMODE lockmode);
358 static ObjectAddress ATExecAddColumn(List **wqueue, AlteredTableInfo *tab,
359 				Relation rel, ColumnDef *colDef, bool isOid,
360 				bool recurse, bool recursing,
361 				bool if_not_exists, LOCKMODE lockmode);
362 static bool check_for_column_name_collision(Relation rel, const char *colname,
363 								bool if_not_exists);
364 static void add_column_datatype_dependency(Oid relid, int32 attnum, Oid typid);
365 static void add_column_collation_dependency(Oid relid, int32 attnum, Oid collid);
366 static void ATPrepAddOids(List **wqueue, Relation rel, bool recurse,
367 			  AlterTableCmd *cmd, LOCKMODE lockmode);
368 static void ATPrepDropNotNull(Relation rel, bool recurse, bool recursing);
369 static ObjectAddress ATExecDropNotNull(Relation rel, const char *colName, LOCKMODE lockmode);
370 static void ATPrepSetNotNull(Relation rel, bool recurse, bool recursing);
371 static ObjectAddress ATExecSetNotNull(AlteredTableInfo *tab, Relation rel,
372 				 const char *colName, LOCKMODE lockmode);
373 static ObjectAddress ATExecColumnDefault(Relation rel, const char *colName,
374 					Node *newDefault, LOCKMODE lockmode);
375 static ObjectAddress ATExecAddIdentity(Relation rel, const char *colName,
376 				  Node *def, LOCKMODE lockmode);
377 static ObjectAddress ATExecSetIdentity(Relation rel, const char *colName,
378 				  Node *def, LOCKMODE lockmode);
379 static ObjectAddress ATExecDropIdentity(Relation rel, const char *colName, bool missing_ok, LOCKMODE lockmode);
380 static void ATPrepSetStatistics(Relation rel, const char *colName,
381 					Node *newValue, LOCKMODE lockmode);
382 static ObjectAddress ATExecSetStatistics(Relation rel, const char *colName,
383 					Node *newValue, LOCKMODE lockmode);
384 static ObjectAddress ATExecSetOptions(Relation rel, const char *colName,
385 				 Node *options, bool isReset, LOCKMODE lockmode);
386 static ObjectAddress ATExecSetStorage(Relation rel, const char *colName,
387 				 Node *newValue, LOCKMODE lockmode);
388 static void ATPrepDropColumn(List **wqueue, Relation rel, bool recurse, bool recursing,
389 				 AlterTableCmd *cmd, LOCKMODE lockmode);
390 static ObjectAddress ATExecDropColumn(List **wqueue, Relation rel, const char *colName,
391 				 DropBehavior behavior,
392 				 bool recurse, bool recursing,
393 				 bool missing_ok, LOCKMODE lockmode);
394 static ObjectAddress ATExecAddIndex(AlteredTableInfo *tab, Relation rel,
395 			   IndexStmt *stmt, bool is_rebuild, LOCKMODE lockmode);
396 static ObjectAddress ATExecAddConstraint(List **wqueue,
397 					AlteredTableInfo *tab, Relation rel,
398 					Constraint *newConstraint, bool recurse, bool is_readd,
399 					LOCKMODE lockmode);
400 static ObjectAddress ATExecAddIndexConstraint(AlteredTableInfo *tab, Relation rel,
401 						 IndexStmt *stmt, LOCKMODE lockmode);
402 static ObjectAddress ATAddCheckConstraint(List **wqueue,
403 					 AlteredTableInfo *tab, Relation rel,
404 					 Constraint *constr,
405 					 bool recurse, bool recursing, bool is_readd,
406 					 LOCKMODE lockmode);
407 static ObjectAddress ATAddForeignKeyConstraint(AlteredTableInfo *tab, Relation rel,
408 						  Constraint *fkconstraint, LOCKMODE lockmode);
409 static void ATExecDropConstraint(Relation rel, const char *constrName,
410 					 DropBehavior behavior,
411 					 bool recurse, bool recursing,
412 					 bool missing_ok, LOCKMODE lockmode);
413 static void ATPrepAlterColumnType(List **wqueue,
414 					  AlteredTableInfo *tab, Relation rel,
415 					  bool recurse, bool recursing,
416 					  AlterTableCmd *cmd, LOCKMODE lockmode);
417 static bool ATColumnChangeRequiresRewrite(Node *expr, AttrNumber varattno);
418 static ObjectAddress ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel,
419 					  AlterTableCmd *cmd, LOCKMODE lockmode);
420 static void RememberConstraintForRebuilding(Oid conoid, AlteredTableInfo *tab,
421 											DependencyType deptype);
422 static void RememberIndexForRebuilding(Oid indoid, AlteredTableInfo *tab);
423 static ObjectAddress ATExecAlterColumnGenericOptions(Relation rel, const char *colName,
424 								List *options, LOCKMODE lockmode);
425 static void ATPostAlterTypeCleanup(List **wqueue, AlteredTableInfo *tab,
426 					   LOCKMODE lockmode);
427 static void ATPostAlterTypeParse(Oid oldId, Oid oldRelId, Oid refRelId,
428 					 char *cmd, List **wqueue, LOCKMODE lockmode,
429 					 bool rewrite);
430 static void RebuildConstraintComment(AlteredTableInfo *tab, int pass,
431 						 Oid objid, Relation rel, char *conname);
432 static void TryReuseIndex(Oid oldId, IndexStmt *stmt);
433 static void TryReuseForeignKey(Oid oldId, Constraint *con);
434 static void change_owner_fix_column_acls(Oid relationOid,
435 							 Oid oldOwnerId, Oid newOwnerId);
436 static void change_owner_recurse_to_sequences(Oid relationOid,
437 								  Oid newOwnerId, LOCKMODE lockmode);
438 static ObjectAddress ATExecClusterOn(Relation rel, const char *indexName,
439 				LOCKMODE lockmode);
440 static void ATExecDropCluster(Relation rel, LOCKMODE lockmode);
441 static bool ATPrepChangePersistence(Relation rel, bool toLogged);
442 static void ATPrepSetTableSpace(AlteredTableInfo *tab, Relation rel,
443 					char *tablespacename, LOCKMODE lockmode);
444 static void ATExecSetTableSpace(Oid tableOid, Oid newTableSpace, LOCKMODE lockmode);
445 static void ATExecSetRelOptions(Relation rel, List *defList,
446 					AlterTableType operation,
447 					LOCKMODE lockmode);
448 static void ATExecEnableDisableTrigger(Relation rel, char *trigname,
449 						   char fires_when, bool skip_system, LOCKMODE lockmode);
450 static void ATExecEnableDisableRule(Relation rel, char *rulename,
451 						char fires_when, LOCKMODE lockmode);
452 static void ATPrepAddInherit(Relation child_rel);
453 static ObjectAddress ATExecAddInherit(Relation child_rel, RangeVar *parent, LOCKMODE lockmode);
454 static ObjectAddress ATExecDropInherit(Relation rel, RangeVar *parent, LOCKMODE lockmode);
455 static void drop_parent_dependency(Oid relid, Oid refclassid, Oid refobjid,
456 					   DependencyType deptype);
457 static ObjectAddress ATExecAddOf(Relation rel, const TypeName *ofTypename, LOCKMODE lockmode);
458 static void ATExecDropOf(Relation rel, LOCKMODE lockmode);
459 static void ATExecReplicaIdentity(Relation rel, ReplicaIdentityStmt *stmt, LOCKMODE lockmode);
460 static void ATExecGenericOptions(Relation rel, List *options);
461 static void ATExecEnableRowSecurity(Relation rel);
462 static void ATExecDisableRowSecurity(Relation rel);
463 static void ATExecForceNoForceRowSecurity(Relation rel, bool force_rls);
464 
465 static void copy_relation_data(SMgrRelation rel, SMgrRelation dst,
466 				   ForkNumber forkNum, char relpersistence);
467 static const char *storage_name(char c);
468 
469 static void RangeVarCallbackForDropRelation(const RangeVar *rel, Oid relOid,
470 								Oid oldRelOid, void *arg);
471 static void RangeVarCallbackForAlterRelation(const RangeVar *rv, Oid relid,
472 								 Oid oldrelid, void *arg);
473 static bool is_partition_attr(Relation rel, AttrNumber attnum, bool *used_in_expr);
474 static PartitionSpec *transformPartitionSpec(Relation rel, PartitionSpec *partspec, char *strategy);
475 static void ComputePartitionAttrs(Relation rel, List *partParams, AttrNumber *partattrs,
476 					  List **partexprs, Oid *partopclass, Oid *partcollation);
477 static void CreateInheritance(Relation child_rel, Relation parent_rel);
478 static void RemoveInheritance(Relation child_rel, Relation parent_rel);
479 static ObjectAddress ATExecAttachPartition(List **wqueue, Relation rel,
480 					  PartitionCmd *cmd);
481 static ObjectAddress ATExecDetachPartition(Relation rel, RangeVar *name);
482 
483 
484 /* ----------------------------------------------------------------
485  *		DefineRelation
486  *				Creates a new relation.
487  *
488  * stmt carries parsetree information from an ordinary CREATE TABLE statement.
489  * The other arguments are used to extend the behavior for other cases:
490  * relkind: relkind to assign to the new relation
491  * ownerId: if not InvalidOid, use this as the new relation's owner.
492  * typaddress: if not null, it's set to the pg_type entry's address.
493  *
494  * Note that permissions checks are done against current user regardless of
495  * ownerId.  A nonzero ownerId is used when someone is creating a relation
496  * "on behalf of" someone else, so we still want to see that the current user
497  * has permissions to do it.
498  *
499  * If successful, returns the address of the new relation.
500  * ----------------------------------------------------------------
501  */
502 ObjectAddress
DefineRelation(CreateStmt * stmt,char relkind,Oid ownerId,ObjectAddress * typaddress,const char * queryString)503 DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId,
504 			   ObjectAddress *typaddress, const char *queryString)
505 {
506 	char		relname[NAMEDATALEN];
507 	Oid			namespaceId;
508 	Oid			relationId;
509 	Oid			tablespaceId;
510 	Relation	rel;
511 	TupleDesc	descriptor;
512 	List	   *inheritOids;
513 	List	   *old_constraints;
514 	bool		localHasOids;
515 	int			parentOidCount;
516 	List	   *rawDefaults;
517 	List	   *cookedDefaults;
518 	Datum		reloptions;
519 	ListCell   *listptr;
520 	AttrNumber	attnum;
521 	static char *validnsps[] = HEAP_RELOPT_NAMESPACES;
522 	Oid			ofTypeId;
523 	ObjectAddress address;
524 
525 	/*
526 	 * Truncate relname to appropriate length (probably a waste of time, as
527 	 * parser should have done this already).
528 	 */
529 	StrNCpy(relname, stmt->relation->relname, NAMEDATALEN);
530 
531 	/*
532 	 * Check consistency of arguments
533 	 */
534 	if (stmt->oncommit != ONCOMMIT_NOOP
535 		&& stmt->relation->relpersistence != RELPERSISTENCE_TEMP)
536 		ereport(ERROR,
537 				(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
538 				 errmsg("ON COMMIT can only be used on temporary tables")));
539 
540 	if (stmt->partspec != NULL)
541 	{
542 		if (relkind != RELKIND_RELATION)
543 			elog(ERROR, "unexpected relkind: %d", (int) relkind);
544 
545 		relkind = RELKIND_PARTITIONED_TABLE;
546 	}
547 
548 	/*
549 	 * Look up the namespace in which we are supposed to create the relation,
550 	 * check we have permission to create there, lock it against concurrent
551 	 * drop, and mark stmt->relation as RELPERSISTENCE_TEMP if a temporary
552 	 * namespace is selected.
553 	 */
554 	namespaceId =
555 		RangeVarGetAndCheckCreationNamespace(stmt->relation, NoLock, NULL);
556 
557 	/*
558 	 * Security check: disallow creating temp tables from security-restricted
559 	 * code.  This is needed because calling code might not expect untrusted
560 	 * tables to appear in pg_temp at the front of its search path.
561 	 */
562 	if (stmt->relation->relpersistence == RELPERSISTENCE_TEMP
563 		&& InSecurityRestrictedOperation())
564 		ereport(ERROR,
565 				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
566 				 errmsg("cannot create temporary table within security-restricted operation")));
567 
568 	/*
569 	 * Select tablespace to use.  If not specified, use default tablespace
570 	 * (which may in turn default to database's default).
571 	 */
572 	if (stmt->tablespacename)
573 	{
574 		tablespaceId = get_tablespace_oid(stmt->tablespacename, false);
575 	}
576 	else
577 	{
578 		tablespaceId = GetDefaultTablespace(stmt->relation->relpersistence);
579 		/* note InvalidOid is OK in this case */
580 	}
581 
582 	/* Check permissions except when using database's default */
583 	if (OidIsValid(tablespaceId) && tablespaceId != MyDatabaseTableSpace)
584 	{
585 		AclResult	aclresult;
586 
587 		aclresult = pg_tablespace_aclcheck(tablespaceId, GetUserId(),
588 										   ACL_CREATE);
589 		if (aclresult != ACLCHECK_OK)
590 			aclcheck_error(aclresult, ACL_KIND_TABLESPACE,
591 						   get_tablespace_name(tablespaceId));
592 	}
593 
594 	/* In all cases disallow placing user relations in pg_global */
595 	if (tablespaceId == GLOBALTABLESPACE_OID)
596 		ereport(ERROR,
597 				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
598 				 errmsg("only shared relations can be placed in pg_global tablespace")));
599 
600 	/* Identify user ID that will own the table */
601 	if (!OidIsValid(ownerId))
602 		ownerId = GetUserId();
603 
604 	/*
605 	 * Parse and validate reloptions, if any.
606 	 */
607 	reloptions = transformRelOptions((Datum) 0, stmt->options, NULL, validnsps,
608 									 true, false);
609 
610 	if (relkind == RELKIND_VIEW)
611 		(void) view_reloptions(reloptions, true);
612 	else
613 		(void) heap_reloptions(relkind, reloptions, true);
614 
615 	if (stmt->ofTypename)
616 	{
617 		AclResult	aclresult;
618 
619 		ofTypeId = typenameTypeId(NULL, stmt->ofTypename);
620 
621 		aclresult = pg_type_aclcheck(ofTypeId, GetUserId(), ACL_USAGE);
622 		if (aclresult != ACLCHECK_OK)
623 			aclcheck_error_type(aclresult, ofTypeId);
624 	}
625 	else
626 		ofTypeId = InvalidOid;
627 
628 	/*
629 	 * Look up inheritance ancestors and generate relation schema, including
630 	 * inherited attributes.  (Note that stmt->tableElts is destructively
631 	 * modified by MergeAttributes.)
632 	 */
633 	stmt->tableElts =
634 		MergeAttributes(stmt->tableElts, stmt->inhRelations,
635 						stmt->relation->relpersistence,
636 						stmt->partbound != NULL,
637 						&inheritOids, &old_constraints, &parentOidCount);
638 
639 	/*
640 	 * Create a tuple descriptor from the relation schema.  Note that this
641 	 * deals with column names, types, and NOT NULL constraints, but not
642 	 * default values or CHECK constraints; we handle those below.
643 	 */
644 	descriptor = BuildDescForRelation(stmt->tableElts);
645 
646 	/*
647 	 * Notice that we allow OIDs here only for plain tables and partitioned
648 	 * tables, even though some other relkinds can support them.  This is
649 	 * necessary because the default_with_oids GUC must apply only to plain
650 	 * tables and not any other relkind; doing otherwise would break existing
651 	 * pg_dump files.  We could allow explicit "WITH OIDS" while not allowing
652 	 * default_with_oids to affect other relkinds, but it would complicate
653 	 * interpretOidsOption().
654 	 */
655 	localHasOids = interpretOidsOption(stmt->options,
656 									   (relkind == RELKIND_RELATION ||
657 										relkind == RELKIND_PARTITIONED_TABLE));
658 	descriptor->tdhasoid = (localHasOids || parentOidCount > 0);
659 
660 	/*
661 	 * If a partitioned table doesn't have the system OID column, then none of
662 	 * its partitions should have it.
663 	 */
664 	if (stmt->partbound && parentOidCount == 0 && localHasOids)
665 		ereport(ERROR,
666 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
667 				 errmsg("cannot create table with OIDs as partition of table without OIDs")));
668 
669 	/*
670 	 * Find columns with default values and prepare for insertion of the
671 	 * defaults.  Pre-cooked (that is, inherited) defaults go into a list of
672 	 * CookedConstraint structs that we'll pass to heap_create_with_catalog,
673 	 * while raw defaults go into a list of RawColumnDefault structs that will
674 	 * be processed by AddRelationNewConstraints.  (We can't deal with raw
675 	 * expressions until we can do transformExpr.)
676 	 *
677 	 * We can set the atthasdef flags now in the tuple descriptor; this just
678 	 * saves StoreAttrDefault from having to do an immediate update of the
679 	 * pg_attribute rows.
680 	 */
681 	rawDefaults = NIL;
682 	cookedDefaults = NIL;
683 	attnum = 0;
684 
685 	foreach(listptr, stmt->tableElts)
686 	{
687 		ColumnDef  *colDef = lfirst(listptr);
688 
689 		attnum++;
690 
691 		if (colDef->raw_default != NULL)
692 		{
693 			RawColumnDefault *rawEnt;
694 
695 			Assert(colDef->cooked_default == NULL);
696 
697 			rawEnt = (RawColumnDefault *) palloc(sizeof(RawColumnDefault));
698 			rawEnt->attnum = attnum;
699 			rawEnt->raw_default = colDef->raw_default;
700 			rawDefaults = lappend(rawDefaults, rawEnt);
701 			descriptor->attrs[attnum - 1]->atthasdef = true;
702 		}
703 		else if (colDef->cooked_default != NULL)
704 		{
705 			CookedConstraint *cooked;
706 
707 			cooked = (CookedConstraint *) palloc(sizeof(CookedConstraint));
708 			cooked->contype = CONSTR_DEFAULT;
709 			cooked->conoid = InvalidOid;	/* until created */
710 			cooked->name = NULL;
711 			cooked->attnum = attnum;
712 			cooked->expr = colDef->cooked_default;
713 			cooked->skip_validation = false;
714 			cooked->is_local = true;	/* not used for defaults */
715 			cooked->inhcount = 0;	/* ditto */
716 			cooked->is_no_inherit = false;
717 			cookedDefaults = lappend(cookedDefaults, cooked);
718 			descriptor->attrs[attnum - 1]->atthasdef = true;
719 		}
720 
721 		if (colDef->identity)
722 			descriptor->attrs[attnum - 1]->attidentity = colDef->identity;
723 	}
724 
725 	/*
726 	 * Create the relation.  Inherited defaults and constraints are passed in
727 	 * for immediate handling --- since they don't need parsing, they can be
728 	 * stored immediately.
729 	 */
730 	relationId = heap_create_with_catalog(relname,
731 										  namespaceId,
732 										  tablespaceId,
733 										  InvalidOid,
734 										  InvalidOid,
735 										  ofTypeId,
736 										  ownerId,
737 										  descriptor,
738 										  list_concat(cookedDefaults,
739 													  old_constraints),
740 										  relkind,
741 										  stmt->relation->relpersistence,
742 										  false,
743 										  false,
744 										  localHasOids,
745 										  parentOidCount,
746 										  stmt->oncommit,
747 										  reloptions,
748 										  true,
749 										  allowSystemTableMods,
750 										  false,
751 										  typaddress);
752 
753 	/* Store inheritance information for new rel. */
754 	StoreCatalogInheritance(relationId, inheritOids, stmt->partbound != NULL);
755 
756 	/*
757 	 * We must bump the command counter to make the newly-created relation
758 	 * tuple visible for opening.
759 	 */
760 	CommandCounterIncrement();
761 
762 	/*
763 	 * Open the new relation and acquire exclusive lock on it.  This isn't
764 	 * really necessary for locking out other backends (since they can't see
765 	 * the new rel anyway until we commit), but it keeps the lock manager from
766 	 * complaining about deadlock risks.
767 	 */
768 	rel = relation_open(relationId, AccessExclusiveLock);
769 
770 	/* Process and store partition bound, if any. */
771 	if (stmt->partbound)
772 	{
773 		PartitionBoundSpec *bound;
774 		ParseState *pstate;
775 		Oid			parentId = linitial_oid(inheritOids);
776 		Relation	parent;
777 
778 		/* Already have strong enough lock on the parent */
779 		parent = heap_open(parentId, NoLock);
780 
781 		/*
782 		 * We are going to try to validate the partition bound specification
783 		 * against the partition key of parentRel, so it better have one.
784 		 */
785 		if (parent->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
786 			ereport(ERROR,
787 					(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
788 					 errmsg("\"%s\" is not partitioned",
789 							RelationGetRelationName(parent))));
790 
791 		/* Tranform the bound values */
792 		pstate = make_parsestate(NULL);
793 		pstate->p_sourcetext = queryString;
794 
795 		bound = transformPartitionBound(pstate, parent, stmt->partbound);
796 
797 		/*
798 		 * Check first that the new partition's bound is valid and does not
799 		 * overlap with any of existing partitions of the parent - note that
800 		 * it does not return on error.
801 		 */
802 		check_new_partition_bound(relname, parent, bound);
803 
804 		/* Update the pg_class entry. */
805 		StorePartitionBound(rel, parent, bound);
806 
807 		heap_close(parent, NoLock);
808 
809 		/*
810 		 * The code that follows may also update the pg_class tuple to update
811 		 * relnumchecks, so bump up the command counter to avoid the "already
812 		 * updated by self" error.
813 		 */
814 		CommandCounterIncrement();
815 	}
816 
817 	/*
818 	 * Process the partitioning specification (if any) and store the partition
819 	 * key information into the catalog.
820 	 */
821 	if (stmt->partspec)
822 	{
823 		char		strategy;
824 		int			partnatts;
825 		AttrNumber	partattrs[PARTITION_MAX_KEYS];
826 		Oid			partopclass[PARTITION_MAX_KEYS];
827 		Oid			partcollation[PARTITION_MAX_KEYS];
828 		List	   *partexprs = NIL;
829 
830 		partnatts = list_length(stmt->partspec->partParams);
831 
832 		/* Protect fixed-size arrays here and in executor */
833 		if (partnatts > PARTITION_MAX_KEYS)
834 			ereport(ERROR,
835 					(errcode(ERRCODE_TOO_MANY_COLUMNS),
836 					 errmsg("cannot partition using more than %d columns",
837 							PARTITION_MAX_KEYS)));
838 
839 		/*
840 		 * We need to transform the raw parsetrees corresponding to partition
841 		 * expressions into executable expression trees.  Like column defaults
842 		 * and CHECK constraints, we could not have done the transformation
843 		 * earlier.
844 		 */
845 		stmt->partspec = transformPartitionSpec(rel, stmt->partspec,
846 												&strategy);
847 
848 		ComputePartitionAttrs(rel, stmt->partspec->partParams,
849 							  partattrs, &partexprs, partopclass,
850 							  partcollation);
851 
852 		StorePartitionKey(rel, strategy, partnatts, partattrs, partexprs,
853 						  partopclass, partcollation);
854 	}
855 
856 	/*
857 	 * Now add any newly specified column default values and CHECK constraints
858 	 * to the new relation.  These are passed to us in the form of raw
859 	 * parsetrees; we need to transform them to executable expression trees
860 	 * before they can be added. The most convenient way to do that is to
861 	 * apply the parser's transformExpr routine, but transformExpr doesn't
862 	 * work unless we have a pre-existing relation. So, the transformation has
863 	 * to be postponed to this final step of CREATE TABLE.
864 	 */
865 	if (rawDefaults || stmt->constraints)
866 		AddRelationNewConstraints(rel, rawDefaults, stmt->constraints,
867 								  true, true, false);
868 
869 	ObjectAddressSet(address, RelationRelationId, relationId);
870 
871 	/*
872 	 * Clean up.  We keep lock on new relation (although it shouldn't be
873 	 * visible to anyone else anyway, until commit).
874 	 */
875 	relation_close(rel, NoLock);
876 
877 	return address;
878 }
879 
880 /*
881  * Emit the right error or warning message for a "DROP" command issued on a
882  * non-existent relation
883  */
884 static void
DropErrorMsgNonExistent(RangeVar * rel,char rightkind,bool missing_ok)885 DropErrorMsgNonExistent(RangeVar *rel, char rightkind, bool missing_ok)
886 {
887 	const struct dropmsgstrings *rentry;
888 
889 	if (rel->schemaname != NULL &&
890 		!OidIsValid(LookupNamespaceNoError(rel->schemaname)))
891 	{
892 		if (!missing_ok)
893 		{
894 			ereport(ERROR,
895 					(errcode(ERRCODE_UNDEFINED_SCHEMA),
896 					 errmsg("schema \"%s\" does not exist", rel->schemaname)));
897 		}
898 		else
899 		{
900 			ereport(NOTICE,
901 					(errmsg("schema \"%s\" does not exist, skipping",
902 							rel->schemaname)));
903 		}
904 		return;
905 	}
906 
907 	for (rentry = dropmsgstringarray; rentry->kind != '\0'; rentry++)
908 	{
909 		if (rentry->kind == rightkind)
910 		{
911 			if (!missing_ok)
912 			{
913 				ereport(ERROR,
914 						(errcode(rentry->nonexistent_code),
915 						 errmsg(rentry->nonexistent_msg, rel->relname)));
916 			}
917 			else
918 			{
919 				ereport(NOTICE, (errmsg(rentry->skipping_msg, rel->relname)));
920 				break;
921 			}
922 		}
923 	}
924 
925 	Assert(rentry->kind != '\0');	/* Should be impossible */
926 }
927 
928 /*
929  * Emit the right error message for a "DROP" command issued on a
930  * relation of the wrong type
931  */
932 static void
DropErrorMsgWrongType(const char * relname,char wrongkind,char rightkind)933 DropErrorMsgWrongType(const char *relname, char wrongkind, char rightkind)
934 {
935 	const struct dropmsgstrings *rentry;
936 	const struct dropmsgstrings *wentry;
937 
938 	for (rentry = dropmsgstringarray; rentry->kind != '\0'; rentry++)
939 		if (rentry->kind == rightkind)
940 			break;
941 	Assert(rentry->kind != '\0');
942 
943 	for (wentry = dropmsgstringarray; wentry->kind != '\0'; wentry++)
944 		if (wentry->kind == wrongkind)
945 			break;
946 	/* wrongkind could be something we don't have in our table... */
947 
948 	ereport(ERROR,
949 			(errcode(ERRCODE_WRONG_OBJECT_TYPE),
950 			 errmsg(rentry->nota_msg, relname),
951 			 (wentry->kind != '\0') ? errhint("%s", _(wentry->drophint_msg)) : 0));
952 }
953 
954 /*
955  * RemoveRelations
956  *		Implements DROP TABLE, DROP INDEX, DROP SEQUENCE, DROP VIEW,
957  *		DROP MATERIALIZED VIEW, DROP FOREIGN TABLE
958  */
959 void
RemoveRelations(DropStmt * drop)960 RemoveRelations(DropStmt *drop)
961 {
962 	ObjectAddresses *objects;
963 	char		relkind;
964 	ListCell   *cell;
965 	int			flags = 0;
966 	LOCKMODE	lockmode = AccessExclusiveLock;
967 
968 	/* DROP CONCURRENTLY uses a weaker lock, and has some restrictions */
969 	if (drop->concurrent)
970 	{
971 		/*
972 		 * Note that for temporary relations this lock may get upgraded
973 		 * later on, but as no other session can access a temporary
974 		 * relation, this is actually fine.
975 		 */
976 		lockmode = ShareUpdateExclusiveLock;
977 		Assert(drop->removeType == OBJECT_INDEX);
978 		if (list_length(drop->objects) != 1)
979 			ereport(ERROR,
980 					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
981 					 errmsg("DROP INDEX CONCURRENTLY does not support dropping multiple objects")));
982 		if (drop->behavior == DROP_CASCADE)
983 			ereport(ERROR,
984 					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
985 					 errmsg("DROP INDEX CONCURRENTLY does not support CASCADE")));
986 	}
987 
988 	/*
989 	 * First we identify all the relations, then we delete them in a single
990 	 * performMultipleDeletions() call.  This is to avoid unwanted DROP
991 	 * RESTRICT errors if one of the relations depends on another.
992 	 */
993 
994 	/* Determine required relkind */
995 	switch (drop->removeType)
996 	{
997 		case OBJECT_TABLE:
998 			relkind = RELKIND_RELATION;
999 			break;
1000 
1001 		case OBJECT_INDEX:
1002 			relkind = RELKIND_INDEX;
1003 			break;
1004 
1005 		case OBJECT_SEQUENCE:
1006 			relkind = RELKIND_SEQUENCE;
1007 			break;
1008 
1009 		case OBJECT_VIEW:
1010 			relkind = RELKIND_VIEW;
1011 			break;
1012 
1013 		case OBJECT_MATVIEW:
1014 			relkind = RELKIND_MATVIEW;
1015 			break;
1016 
1017 		case OBJECT_FOREIGN_TABLE:
1018 			relkind = RELKIND_FOREIGN_TABLE;
1019 			break;
1020 
1021 		default:
1022 			elog(ERROR, "unrecognized drop object type: %d",
1023 				 (int) drop->removeType);
1024 			relkind = 0;		/* keep compiler quiet */
1025 			break;
1026 	}
1027 
1028 	/* Lock and validate each relation; build a list of object addresses */
1029 	objects = new_object_addresses();
1030 
1031 	foreach(cell, drop->objects)
1032 	{
1033 		RangeVar   *rel = makeRangeVarFromNameList((List *) lfirst(cell));
1034 		Oid			relOid;
1035 		ObjectAddress obj;
1036 		struct DropRelationCallbackState state;
1037 
1038 		/*
1039 		 * These next few steps are a great deal like relation_openrv, but we
1040 		 * don't bother building a relcache entry since we don't need it.
1041 		 *
1042 		 * Check for shared-cache-inval messages before trying to access the
1043 		 * relation.  This is needed to cover the case where the name
1044 		 * identifies a rel that has been dropped and recreated since the
1045 		 * start of our transaction: if we don't flush the old syscache entry,
1046 		 * then we'll latch onto that entry and suffer an error later.
1047 		 */
1048 		AcceptInvalidationMessages();
1049 
1050 		/* Look up the appropriate relation using namespace search. */
1051 		state.relkind = relkind;
1052 		state.heapOid = InvalidOid;
1053 		state.partParentOid = InvalidOid;
1054 		state.concurrent = drop->concurrent;
1055 		relOid = RangeVarGetRelidExtended(rel, lockmode, true,
1056 										  false,
1057 										  RangeVarCallbackForDropRelation,
1058 										  (void *) &state);
1059 
1060 		/* Not there? */
1061 		if (!OidIsValid(relOid))
1062 		{
1063 			DropErrorMsgNonExistent(rel, relkind, drop->missing_ok);
1064 			continue;
1065 		}
1066 
1067 		/*
1068 		 * Decide if concurrent mode needs to be used here or not.  The
1069 		 * relation persistence cannot be known without its OID.
1070 		 */
1071 		if (drop->concurrent &&
1072 			get_rel_persistence(relOid) != RELPERSISTENCE_TEMP)
1073 		{
1074 			Assert(list_length(drop->objects) == 1 &&
1075 				   drop->removeType == OBJECT_INDEX);
1076 			flags |= PERFORM_DELETION_CONCURRENTLY;
1077 		}
1078 
1079 		/* OK, we're ready to delete this one */
1080 		obj.classId = RelationRelationId;
1081 		obj.objectId = relOid;
1082 		obj.objectSubId = 0;
1083 
1084 		add_exact_object_address(&obj, objects);
1085 	}
1086 
1087 	performMultipleDeletions(objects, drop->behavior, flags);
1088 
1089 	free_object_addresses(objects);
1090 }
1091 
1092 /*
1093  * Before acquiring a table lock, check whether we have sufficient rights.
1094  * In the case of DROP INDEX, also try to lock the table before the index.
1095  * Also, if the table to be dropped is a partition, we try to lock the parent
1096  * first.
1097  */
1098 static void
RangeVarCallbackForDropRelation(const RangeVar * rel,Oid relOid,Oid oldRelOid,void * arg)1099 RangeVarCallbackForDropRelation(const RangeVar *rel, Oid relOid, Oid oldRelOid,
1100 								void *arg)
1101 {
1102 	HeapTuple	tuple;
1103 	struct DropRelationCallbackState *state;
1104 	char		relkind;
1105 	char		expected_relkind;
1106 	bool		is_partition;
1107 	Form_pg_class classform;
1108 	LOCKMODE	heap_lockmode;
1109 
1110 	state = (struct DropRelationCallbackState *) arg;
1111 	relkind = state->relkind;
1112 	heap_lockmode = state->concurrent ?
1113 		ShareUpdateExclusiveLock : AccessExclusiveLock;
1114 
1115 	/*
1116 	 * If we previously locked some other index's heap, and the name we're
1117 	 * looking up no longer refers to that relation, release the now-useless
1118 	 * lock.
1119 	 */
1120 	if (relOid != oldRelOid && OidIsValid(state->heapOid))
1121 	{
1122 		UnlockRelationOid(state->heapOid, heap_lockmode);
1123 		state->heapOid = InvalidOid;
1124 	}
1125 
1126 	/*
1127 	 * Similarly, if we previously locked some other partition's heap, and the
1128 	 * name we're looking up no longer refers to that relation, release the
1129 	 * now-useless lock.
1130 	 */
1131 	if (relOid != oldRelOid && OidIsValid(state->partParentOid))
1132 	{
1133 		UnlockRelationOid(state->partParentOid, AccessExclusiveLock);
1134 		state->partParentOid = InvalidOid;
1135 	}
1136 
1137 	/* Didn't find a relation, so no need for locking or permission checks. */
1138 	if (!OidIsValid(relOid))
1139 		return;
1140 
1141 	tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relOid));
1142 	if (!HeapTupleIsValid(tuple))
1143 		return;					/* concurrently dropped, so nothing to do */
1144 	classform = (Form_pg_class) GETSTRUCT(tuple);
1145 	is_partition = classform->relispartition;
1146 
1147 	/*
1148 	 * Both RELKIND_RELATION and RELKIND_PARTITIONED_TABLE are OBJECT_TABLE,
1149 	 * but RemoveRelations() can only pass one relkind for a given relation.
1150 	 * It chooses RELKIND_RELATION for both regular and partitioned tables.
1151 	 * That means we must be careful before giving the wrong type error when
1152 	 * the relation is RELKIND_PARTITIONED_TABLE.
1153 	 */
1154 	if (classform->relkind == RELKIND_PARTITIONED_TABLE)
1155 		expected_relkind = RELKIND_RELATION;
1156 	else
1157 		expected_relkind = classform->relkind;
1158 
1159 	if (relkind != expected_relkind)
1160 		DropErrorMsgWrongType(rel->relname, classform->relkind, relkind);
1161 
1162 	/* Allow DROP to either table owner or schema owner */
1163 	if (!pg_class_ownercheck(relOid, GetUserId()) &&
1164 		!pg_namespace_ownercheck(classform->relnamespace, GetUserId()))
1165 		aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS,
1166 					   rel->relname);
1167 
1168 	if (!allowSystemTableMods && IsSystemClass(relOid, classform))
1169 		ereport(ERROR,
1170 				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1171 				 errmsg("permission denied: \"%s\" is a system catalog",
1172 						rel->relname)));
1173 
1174 	ReleaseSysCache(tuple);
1175 
1176 	/*
1177 	 * In DROP INDEX, attempt to acquire lock on the parent table before
1178 	 * locking the index.  index_drop() will need this anyway, and since
1179 	 * regular queries lock tables before their indexes, we risk deadlock if
1180 	 * we do it the other way around.  No error if we don't find a pg_index
1181 	 * entry, though --- the relation may have been dropped.
1182 	 */
1183 	if (relkind == RELKIND_INDEX && relOid != oldRelOid)
1184 	{
1185 		state->heapOid = IndexGetRelation(relOid, true);
1186 		if (OidIsValid(state->heapOid))
1187 			LockRelationOid(state->heapOid, heap_lockmode);
1188 	}
1189 
1190 	/*
1191 	 * Similarly, if the relation is a partition, we must acquire lock on its
1192 	 * parent before locking the partition.  That's because queries lock the
1193 	 * parent before its partitions, so we risk deadlock it we do it the other
1194 	 * way around.
1195 	 */
1196 	if (is_partition && relOid != oldRelOid)
1197 	{
1198 		state->partParentOid = get_partition_parent(relOid);
1199 		if (OidIsValid(state->partParentOid))
1200 			LockRelationOid(state->partParentOid, AccessExclusiveLock);
1201 	}
1202 }
1203 
1204 /*
1205  * ExecuteTruncate
1206  *		Executes a TRUNCATE command.
1207  *
1208  * This is a multi-relation truncate.  We first open and grab exclusive
1209  * lock on all relations involved, checking permissions and otherwise
1210  * verifying that the relation is OK for truncation.  In CASCADE mode,
1211  * relations having FK references to the targeted relations are automatically
1212  * added to the group; in RESTRICT mode, we check that all FK references are
1213  * internal to the group that's being truncated.  Finally all the relations
1214  * are truncated and reindexed.
1215  */
1216 void
ExecuteTruncate(TruncateStmt * stmt)1217 ExecuteTruncate(TruncateStmt *stmt)
1218 {
1219 	List	   *rels = NIL;
1220 	List	   *relids = NIL;
1221 	List	   *seq_relids = NIL;
1222 	EState	   *estate;
1223 	ResultRelInfo *resultRelInfos;
1224 	ResultRelInfo *resultRelInfo;
1225 	SubTransactionId mySubid;
1226 	ListCell   *cell;
1227 
1228 	/*
1229 	 * Open, exclusive-lock, and check all the explicitly-specified relations
1230 	 */
1231 	foreach(cell, stmt->relations)
1232 	{
1233 		RangeVar   *rv = lfirst(cell);
1234 		Relation	rel;
1235 		bool		recurse = rv->inh;
1236 		Oid			myrelid;
1237 		LOCKMODE	lockmode = AccessExclusiveLock;
1238 
1239 		rel = heap_openrv(rv, lockmode);
1240 		myrelid = RelationGetRelid(rel);
1241 		/* don't throw error for "TRUNCATE foo, foo" */
1242 		if (list_member_oid(relids, myrelid))
1243 		{
1244 			heap_close(rel, lockmode);
1245 			continue;
1246 		}
1247 		truncate_check_rel(rel);
1248 		rels = lappend(rels, rel);
1249 		relids = lappend_oid(relids, myrelid);
1250 
1251 		if (recurse)
1252 		{
1253 			ListCell   *child;
1254 			List	   *children;
1255 
1256 			children = find_all_inheritors(myrelid, lockmode, NULL);
1257 
1258 			foreach(child, children)
1259 			{
1260 				Oid			childrelid = lfirst_oid(child);
1261 
1262 				if (list_member_oid(relids, childrelid))
1263 					continue;
1264 
1265 				/* find_all_inheritors already got lock */
1266 				rel = heap_open(childrelid, NoLock);
1267 
1268 				/*
1269 				 * It is possible that the parent table has children that are
1270 				 * temp tables of other backends.  We cannot safely access
1271 				 * such tables (because of buffering issues), and the best
1272 				 * thing to do is to silently ignore them.  Note that this
1273 				 * check is the same as one of the checks done in
1274 				 * truncate_check_rel() called below, still it is kept
1275 				 * here for simplicity.
1276 				 */
1277 				if (RELATION_IS_OTHER_TEMP(rel))
1278 				{
1279 					heap_close(rel, lockmode);
1280 					continue;
1281 				}
1282 
1283 				truncate_check_rel(rel);
1284 				rels = lappend(rels, rel);
1285 				relids = lappend_oid(relids, childrelid);
1286 			}
1287 		}
1288 		else if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
1289 			ereport(ERROR,
1290 					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
1291 					 errmsg("cannot truncate only a partitioned table"),
1292 					 errhint("Do not specify the ONLY keyword, or use truncate only on the partitions directly.")));
1293 	}
1294 
1295 	/*
1296 	 * In CASCADE mode, suck in all referencing relations as well.  This
1297 	 * requires multiple iterations to find indirectly-dependent relations. At
1298 	 * each phase, we need to exclusive-lock new rels before looking for their
1299 	 * dependencies, else we might miss something.  Also, we check each rel as
1300 	 * soon as we open it, to avoid a faux pas such as holding lock for a long
1301 	 * time on a rel we have no permissions for.
1302 	 */
1303 	if (stmt->behavior == DROP_CASCADE)
1304 	{
1305 		for (;;)
1306 		{
1307 			List	   *newrelids;
1308 
1309 			newrelids = heap_truncate_find_FKs(relids);
1310 			if (newrelids == NIL)
1311 				break;			/* nothing else to add */
1312 
1313 			foreach(cell, newrelids)
1314 			{
1315 				Oid			relid = lfirst_oid(cell);
1316 				Relation	rel;
1317 
1318 				rel = heap_open(relid, AccessExclusiveLock);
1319 				ereport(NOTICE,
1320 						(errmsg("truncate cascades to table \"%s\"",
1321 								RelationGetRelationName(rel))));
1322 				truncate_check_rel(rel);
1323 				rels = lappend(rels, rel);
1324 				relids = lappend_oid(relids, relid);
1325 			}
1326 		}
1327 	}
1328 
1329 	/*
1330 	 * Check foreign key references.  In CASCADE mode, this should be
1331 	 * unnecessary since we just pulled in all the references; but as a
1332 	 * cross-check, do it anyway if in an Assert-enabled build.
1333 	 */
1334 #ifdef USE_ASSERT_CHECKING
1335 	heap_truncate_check_FKs(rels, false);
1336 #else
1337 	if (stmt->behavior == DROP_RESTRICT)
1338 		heap_truncate_check_FKs(rels, false);
1339 #endif
1340 
1341 	/*
1342 	 * If we are asked to restart sequences, find all the sequences, lock them
1343 	 * (we need AccessExclusiveLock for ResetSequence), and check permissions.
1344 	 * We want to do this early since it's pointless to do all the truncation
1345 	 * work only to fail on sequence permissions.
1346 	 */
1347 	if (stmt->restart_seqs)
1348 	{
1349 		foreach(cell, rels)
1350 		{
1351 			Relation	rel = (Relation) lfirst(cell);
1352 			List	   *seqlist = getOwnedSequences(RelationGetRelid(rel), 0);
1353 			ListCell   *seqcell;
1354 
1355 			foreach(seqcell, seqlist)
1356 			{
1357 				Oid			seq_relid = lfirst_oid(seqcell);
1358 				Relation	seq_rel;
1359 
1360 				seq_rel = relation_open(seq_relid, AccessExclusiveLock);
1361 
1362 				/* This check must match AlterSequence! */
1363 				if (!pg_class_ownercheck(seq_relid, GetUserId()))
1364 					aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS,
1365 								   RelationGetRelationName(seq_rel));
1366 
1367 				seq_relids = lappend_oid(seq_relids, seq_relid);
1368 
1369 				relation_close(seq_rel, NoLock);
1370 			}
1371 		}
1372 	}
1373 
1374 	/* Prepare to catch AFTER triggers. */
1375 	AfterTriggerBeginQuery();
1376 
1377 	/*
1378 	 * To fire triggers, we'll need an EState as well as a ResultRelInfo for
1379 	 * each relation.  We don't need to call ExecOpenIndices, though.
1380 	 */
1381 	estate = CreateExecutorState();
1382 	resultRelInfos = (ResultRelInfo *)
1383 		palloc(list_length(rels) * sizeof(ResultRelInfo));
1384 	resultRelInfo = resultRelInfos;
1385 	foreach(cell, rels)
1386 	{
1387 		Relation	rel = (Relation) lfirst(cell);
1388 
1389 		InitResultRelInfo(resultRelInfo,
1390 						  rel,
1391 						  0,	/* dummy rangetable index */
1392 						  NULL,
1393 						  0);
1394 		resultRelInfo++;
1395 	}
1396 	estate->es_result_relations = resultRelInfos;
1397 	estate->es_num_result_relations = list_length(rels);
1398 
1399 	/*
1400 	 * Process all BEFORE STATEMENT TRUNCATE triggers before we begin
1401 	 * truncating (this is because one of them might throw an error). Also, if
1402 	 * we were to allow them to prevent statement execution, that would need
1403 	 * to be handled here.
1404 	 */
1405 	resultRelInfo = resultRelInfos;
1406 	foreach(cell, rels)
1407 	{
1408 		estate->es_result_relation_info = resultRelInfo;
1409 		ExecBSTruncateTriggers(estate, resultRelInfo);
1410 		resultRelInfo++;
1411 	}
1412 
1413 	/*
1414 	 * OK, truncate each table.
1415 	 */
1416 	mySubid = GetCurrentSubTransactionId();
1417 
1418 	foreach(cell, rels)
1419 	{
1420 		Relation	rel = (Relation) lfirst(cell);
1421 
1422 		/* Skip partitioned tables as there is nothing to do */
1423 		if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
1424 			continue;
1425 
1426 		/*
1427 		 * Normally, we need a transaction-safe truncation here.  However, if
1428 		 * the table was either created in the current (sub)transaction or has
1429 		 * a new relfilenode in the current (sub)transaction, then we can just
1430 		 * truncate it in-place, because a rollback would cause the whole
1431 		 * table or the current physical file to be thrown away anyway.
1432 		 */
1433 		if (rel->rd_createSubid == mySubid ||
1434 			rel->rd_newRelfilenodeSubid == mySubid)
1435 		{
1436 			/* Immediate, non-rollbackable truncation is OK */
1437 			heap_truncate_one_rel(rel);
1438 		}
1439 		else
1440 		{
1441 			Oid			heap_relid;
1442 			Oid			toast_relid;
1443 			MultiXactId minmulti;
1444 
1445 			/*
1446 			 * This effectively deletes all rows in the table, and may be done
1447 			 * in a serializable transaction.  In that case we must record a
1448 			 * rw-conflict in to this transaction from each transaction
1449 			 * holding a predicate lock on the table.
1450 			 */
1451 			CheckTableForSerializableConflictIn(rel);
1452 
1453 			minmulti = GetOldestMultiXactId();
1454 
1455 			/*
1456 			 * Need the full transaction-safe pushups.
1457 			 *
1458 			 * Create a new empty storage file for the relation, and assign it
1459 			 * as the relfilenode value. The old storage file is scheduled for
1460 			 * deletion at commit.
1461 			 */
1462 			RelationSetNewRelfilenode(rel, rel->rd_rel->relpersistence,
1463 									  RecentXmin, minmulti);
1464 			if (rel->rd_rel->relpersistence == RELPERSISTENCE_UNLOGGED)
1465 				heap_create_init_fork(rel);
1466 
1467 			heap_relid = RelationGetRelid(rel);
1468 
1469 			/*
1470 			 * The same for the toast table, if any.
1471 			 */
1472 			toast_relid = rel->rd_rel->reltoastrelid;
1473 			if (OidIsValid(toast_relid))
1474 			{
1475 				Relation	toastrel = relation_open(toast_relid,
1476 													 AccessExclusiveLock);
1477 
1478 				RelationSetNewRelfilenode(toastrel,
1479 										  toastrel->rd_rel->relpersistence,
1480 										  RecentXmin, minmulti);
1481 				if (toastrel->rd_rel->relpersistence == RELPERSISTENCE_UNLOGGED)
1482 					heap_create_init_fork(toastrel);
1483 				heap_close(toastrel, NoLock);
1484 			}
1485 
1486 			/*
1487 			 * Reconstruct the indexes to match, and we're done.
1488 			 */
1489 			reindex_relation(heap_relid, REINDEX_REL_PROCESS_TOAST, 0);
1490 		}
1491 
1492 		pgstat_count_truncate(rel);
1493 	}
1494 
1495 	/*
1496 	 * Restart owned sequences if we were asked to.
1497 	 */
1498 	foreach(cell, seq_relids)
1499 	{
1500 		Oid			seq_relid = lfirst_oid(cell);
1501 
1502 		ResetSequence(seq_relid);
1503 	}
1504 
1505 	/*
1506 	 * Process all AFTER STATEMENT TRUNCATE triggers.
1507 	 */
1508 	resultRelInfo = resultRelInfos;
1509 	foreach(cell, rels)
1510 	{
1511 		estate->es_result_relation_info = resultRelInfo;
1512 		ExecASTruncateTriggers(estate, resultRelInfo);
1513 		resultRelInfo++;
1514 	}
1515 
1516 	/* Handle queued AFTER triggers */
1517 	AfterTriggerEndQuery(estate);
1518 
1519 	/* We can clean up the EState now */
1520 	FreeExecutorState(estate);
1521 
1522 	/* And close the rels (can't do this while EState still holds refs) */
1523 	foreach(cell, rels)
1524 	{
1525 		Relation	rel = (Relation) lfirst(cell);
1526 
1527 		heap_close(rel, NoLock);
1528 	}
1529 }
1530 
1531 /*
1532  * Check that a given rel is safe to truncate.  Subroutine for ExecuteTruncate
1533  */
1534 static void
truncate_check_rel(Relation rel)1535 truncate_check_rel(Relation rel)
1536 {
1537 	AclResult	aclresult;
1538 
1539 	/*
1540 	 * Only allow truncate on regular tables and partitioned tables (although,
1541 	 * the latter are only being included here for the following checks; no
1542 	 * physical truncation will occur in their case.)
1543 	 */
1544 	if (rel->rd_rel->relkind != RELKIND_RELATION &&
1545 		rel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
1546 		ereport(ERROR,
1547 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
1548 				 errmsg("\"%s\" is not a table",
1549 						RelationGetRelationName(rel))));
1550 
1551 	/* Permissions checks */
1552 	aclresult = pg_class_aclcheck(RelationGetRelid(rel), GetUserId(),
1553 								  ACL_TRUNCATE);
1554 	if (aclresult != ACLCHECK_OK)
1555 		aclcheck_error(aclresult, ACL_KIND_CLASS,
1556 					   RelationGetRelationName(rel));
1557 
1558 	if (!allowSystemTableMods && IsSystemRelation(rel))
1559 		ereport(ERROR,
1560 				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1561 				 errmsg("permission denied: \"%s\" is a system catalog",
1562 						RelationGetRelationName(rel))));
1563 
1564 	/*
1565 	 * Don't allow truncate on temp tables of other backends ... their local
1566 	 * buffer manager is not going to cope.
1567 	 */
1568 	if (RELATION_IS_OTHER_TEMP(rel))
1569 		ereport(ERROR,
1570 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1571 				 errmsg("cannot truncate temporary tables of other sessions")));
1572 
1573 	/*
1574 	 * Also check for active uses of the relation in the current transaction,
1575 	 * including open scans and pending AFTER trigger events.
1576 	 */
1577 	CheckTableNotInUse(rel, "TRUNCATE");
1578 }
1579 
1580 /*
1581  * storage_name
1582  *	  returns the name corresponding to a typstorage/attstorage enum value
1583  */
1584 static const char *
storage_name(char c)1585 storage_name(char c)
1586 {
1587 	switch (c)
1588 	{
1589 		case 'p':
1590 			return "PLAIN";
1591 		case 'm':
1592 			return "MAIN";
1593 		case 'x':
1594 			return "EXTENDED";
1595 		case 'e':
1596 			return "EXTERNAL";
1597 		default:
1598 			return "???";
1599 	}
1600 }
1601 
1602 /*----------
1603  * MergeAttributes
1604  *		Returns new schema given initial schema and superclasses.
1605  *
1606  * Input arguments:
1607  * 'schema' is the column/attribute definition for the table. (It's a list
1608  *		of ColumnDef's.) It is destructively changed.
1609  * 'supers' is a list of names (as RangeVar nodes) of parent relations.
1610  * 'relpersistence' is a persistence type of the table.
1611  * 'is_partition' tells if the table is a partition
1612  *
1613  * Output arguments:
1614  * 'supOids' receives a list of the OIDs of the parent relations.
1615  * 'supconstr' receives a list of constraints belonging to the parents,
1616  *		updated as necessary to be valid for the child.
1617  * 'supOidCount' is set to the number of parents that have OID columns.
1618  *
1619  * Return value:
1620  * Completed schema list.
1621  *
1622  * Notes:
1623  *	  The order in which the attributes are inherited is very important.
1624  *	  Intuitively, the inherited attributes should come first. If a table
1625  *	  inherits from multiple parents, the order of those attributes are
1626  *	  according to the order of the parents specified in CREATE TABLE.
1627  *
1628  *	  Here's an example:
1629  *
1630  *		create table person (name text, age int4, location point);
1631  *		create table emp (salary int4, manager text) inherits(person);
1632  *		create table student (gpa float8) inherits (person);
1633  *		create table stud_emp (percent int4) inherits (emp, student);
1634  *
1635  *	  The order of the attributes of stud_emp is:
1636  *
1637  *							person {1:name, 2:age, 3:location}
1638  *							/	 \
1639  *			   {6:gpa}	student   emp {4:salary, 5:manager}
1640  *							\	 /
1641  *						   stud_emp {7:percent}
1642  *
1643  *	   If the same attribute name appears multiple times, then it appears
1644  *	   in the result table in the proper location for its first appearance.
1645  *
1646  *	   Constraints (including NOT NULL constraints) for the child table
1647  *	   are the union of all relevant constraints, from both the child schema
1648  *	   and parent tables.
1649  *
1650  *	   The default value for a child column is defined as:
1651  *		(1) If the child schema specifies a default, that value is used.
1652  *		(2) If neither the child nor any parent specifies a default, then
1653  *			the column will not have a default.
1654  *		(3) If conflicting defaults are inherited from different parents
1655  *			(and not overridden by the child), an error is raised.
1656  *		(4) Otherwise the inherited default is used.
1657  *		Rule (3) is new in Postgres 7.1; in earlier releases you got a
1658  *		rather arbitrary choice of which parent default to use.
1659  *----------
1660  */
1661 static List *
MergeAttributes(List * schema,List * supers,char relpersistence,bool is_partition,List ** supOids,List ** supconstr,int * supOidCount)1662 MergeAttributes(List *schema, List *supers, char relpersistence,
1663 				bool is_partition, List **supOids, List **supconstr,
1664 				int *supOidCount)
1665 {
1666 	ListCell   *entry;
1667 	List	   *inhSchema = NIL;
1668 	List	   *parentOids = NIL;
1669 	List	   *constraints = NIL;
1670 	int			parentsWithOids = 0;
1671 	bool		have_bogus_defaults = false;
1672 	int			child_attno;
1673 	static Node bogus_marker = {0}; /* marks conflicting defaults */
1674 	List	   *saved_schema = NIL;
1675 
1676 	/*
1677 	 * Check for and reject tables with too many columns. We perform this
1678 	 * check relatively early for two reasons: (a) we don't run the risk of
1679 	 * overflowing an AttrNumber in subsequent code (b) an O(n^2) algorithm is
1680 	 * okay if we're processing <= 1600 columns, but could take minutes to
1681 	 * execute if the user attempts to create a table with hundreds of
1682 	 * thousands of columns.
1683 	 *
1684 	 * Note that we also need to check that we do not exceed this figure after
1685 	 * including columns from inherited relations.
1686 	 */
1687 	if (list_length(schema) > MaxHeapAttributeNumber)
1688 		ereport(ERROR,
1689 				(errcode(ERRCODE_TOO_MANY_COLUMNS),
1690 				 errmsg("tables can have at most %d columns",
1691 						MaxHeapAttributeNumber)));
1692 
1693 	/*
1694 	 * Check for duplicate names in the explicit list of attributes.
1695 	 *
1696 	 * Although we might consider merging such entries in the same way that we
1697 	 * handle name conflicts for inherited attributes, it seems to make more
1698 	 * sense to assume such conflicts are errors.
1699 	 */
1700 	foreach(entry, schema)
1701 	{
1702 		ColumnDef  *coldef = lfirst(entry);
1703 		ListCell   *rest = lnext(entry);
1704 		ListCell   *prev = entry;
1705 
1706 		if (!is_partition && coldef->typeName == NULL)
1707 		{
1708 			/*
1709 			 * Typed table column option that does not belong to a column from
1710 			 * the type.  This works because the columns from the type come
1711 			 * first in the list.  (We omit this check for partition column
1712 			 * lists; those are processed separately below.)
1713 			 */
1714 			ereport(ERROR,
1715 					(errcode(ERRCODE_UNDEFINED_COLUMN),
1716 					 errmsg("column \"%s\" does not exist",
1717 							coldef->colname)));
1718 		}
1719 
1720 		while (rest != NULL)
1721 		{
1722 			ColumnDef  *restdef = lfirst(rest);
1723 			ListCell   *next = lnext(rest); /* need to save it in case we
1724 											 * delete it */
1725 
1726 			if (strcmp(coldef->colname, restdef->colname) == 0)
1727 			{
1728 				if (coldef->is_from_type)
1729 				{
1730 					/*
1731 					 * merge the column options into the column from the type
1732 					 */
1733 					coldef->is_not_null = restdef->is_not_null;
1734 					coldef->raw_default = restdef->raw_default;
1735 					coldef->cooked_default = restdef->cooked_default;
1736 					coldef->constraints = restdef->constraints;
1737 					coldef->is_from_type = false;
1738 					list_delete_cell(schema, rest, prev);
1739 				}
1740 				else
1741 					ereport(ERROR,
1742 							(errcode(ERRCODE_DUPLICATE_COLUMN),
1743 							 errmsg("column \"%s\" specified more than once",
1744 									coldef->colname)));
1745 			}
1746 			prev = rest;
1747 			rest = next;
1748 		}
1749 	}
1750 
1751 	/*
1752 	 * In case of a partition, there are no new column definitions, only dummy
1753 	 * ColumnDefs created for column constraints.  Set them aside for now and
1754 	 * process them at the end.
1755 	 */
1756 	if (is_partition)
1757 	{
1758 		saved_schema = schema;
1759 		schema = NIL;
1760 	}
1761 
1762 	/*
1763 	 * Scan the parents left-to-right, and merge their attributes to form a
1764 	 * list of inherited attributes (inhSchema).  Also check to see if we need
1765 	 * to inherit an OID column.
1766 	 */
1767 	child_attno = 0;
1768 	foreach(entry, supers)
1769 	{
1770 		RangeVar   *parent = (RangeVar *) lfirst(entry);
1771 		Relation	relation;
1772 		TupleDesc	tupleDesc;
1773 		TupleConstr *constr;
1774 		AttrNumber *newattno;
1775 		AttrNumber	parent_attno;
1776 
1777 		/*
1778 		 * A self-exclusive lock is needed here.  If two backends attempt to
1779 		 * add children to the same parent simultaneously, and that parent has
1780 		 * no pre-existing children, then both will attempt to update the
1781 		 * parent's relhassubclass field, leading to a "tuple concurrently
1782 		 * updated" error.  Also, this interlocks against a concurrent ANALYZE
1783 		 * on the parent table, which might otherwise be attempting to clear
1784 		 * the parent's relhassubclass field, if its previous children were
1785 		 * recently dropped.
1786 		 *
1787 		 * If the child table is a partition, then we instead grab an
1788 		 * exclusive lock on the parent because its partition descriptor will
1789 		 * be changed by addition of the new partition.
1790 		 */
1791 		if (!is_partition)
1792 			relation = heap_openrv(parent, ShareUpdateExclusiveLock);
1793 		else
1794 			relation = heap_openrv(parent, AccessExclusiveLock);
1795 
1796 		/*
1797 		 * Check for active uses of the parent partitioned table in the
1798 		 * current transaction, such as being used in some manner by an
1799 		 * enclosing command.
1800 		 */
1801 		if (is_partition)
1802 			CheckTableNotInUse(relation, "CREATE TABLE .. PARTITION OF");
1803 
1804 		/*
1805 		 * We do not allow partitioned tables and partitions to participate in
1806 		 * regular inheritance.
1807 		 */
1808 		if (relation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE &&
1809 			!is_partition)
1810 			ereport(ERROR,
1811 					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
1812 					 errmsg("cannot inherit from partitioned table \"%s\"",
1813 							parent->relname)));
1814 		if (relation->rd_rel->relispartition && !is_partition)
1815 			ereport(ERROR,
1816 					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
1817 					 errmsg("cannot inherit from partition \"%s\"",
1818 							parent->relname)));
1819 
1820 		if (relation->rd_rel->relkind != RELKIND_RELATION &&
1821 			relation->rd_rel->relkind != RELKIND_FOREIGN_TABLE &&
1822 			relation->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
1823 			ereport(ERROR,
1824 					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
1825 					 errmsg("inherited relation \"%s\" is not a table or foreign table",
1826 							parent->relname)));
1827 
1828 		/*
1829 		 * If the parent is permanent, so must be all of its partitions.  Note
1830 		 * that inheritance allows that case.
1831 		 */
1832 		if (is_partition &&
1833 			relation->rd_rel->relpersistence != RELPERSISTENCE_TEMP &&
1834 			relpersistence == RELPERSISTENCE_TEMP)
1835 			ereport(ERROR,
1836 					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
1837 					 errmsg("cannot create a temporary relation as partition of permanent relation \"%s\"",
1838 							RelationGetRelationName(relation))));
1839 
1840 		/* Permanent rels cannot inherit from temporary ones */
1841 		if (relpersistence != RELPERSISTENCE_TEMP &&
1842 			relation->rd_rel->relpersistence == RELPERSISTENCE_TEMP)
1843 			ereport(ERROR,
1844 					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
1845 					 errmsg(!is_partition
1846 							? "cannot inherit from temporary relation \"%s\""
1847 							: "cannot create a permanent relation as partition of temporary relation \"%s\"",
1848 							parent->relname)));
1849 
1850 		/* If existing rel is temp, it must belong to this session */
1851 		if (relation->rd_rel->relpersistence == RELPERSISTENCE_TEMP &&
1852 			!relation->rd_islocaltemp)
1853 			ereport(ERROR,
1854 					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
1855 					 errmsg(!is_partition
1856 							? "cannot inherit from temporary relation of another session"
1857 							: "cannot create as partition of temporary relation of another session")));
1858 
1859 		/*
1860 		 * We should have an UNDER permission flag for this, but for now,
1861 		 * demand that creator of a child table own the parent.
1862 		 */
1863 		if (!pg_class_ownercheck(RelationGetRelid(relation), GetUserId()))
1864 			aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS,
1865 						   RelationGetRelationName(relation));
1866 
1867 		/*
1868 		 * Reject duplications in the list of parents.
1869 		 */
1870 		if (list_member_oid(parentOids, RelationGetRelid(relation)))
1871 			ereport(ERROR,
1872 					(errcode(ERRCODE_DUPLICATE_TABLE),
1873 					 errmsg("relation \"%s\" would be inherited from more than once",
1874 							parent->relname)));
1875 
1876 		parentOids = lappend_oid(parentOids, RelationGetRelid(relation));
1877 
1878 		if (relation->rd_rel->relhasoids)
1879 			parentsWithOids++;
1880 
1881 		tupleDesc = RelationGetDescr(relation);
1882 		constr = tupleDesc->constr;
1883 
1884 		/*
1885 		 * newattno[] will contain the child-table attribute numbers for the
1886 		 * attributes of this parent table.  (They are not the same for
1887 		 * parents after the first one, nor if we have dropped columns.)
1888 		 */
1889 		newattno = (AttrNumber *)
1890 			palloc0(tupleDesc->natts * sizeof(AttrNumber));
1891 
1892 		for (parent_attno = 1; parent_attno <= tupleDesc->natts;
1893 			 parent_attno++)
1894 		{
1895 			Form_pg_attribute attribute = tupleDesc->attrs[parent_attno - 1];
1896 			char	   *attributeName = NameStr(attribute->attname);
1897 			int			exist_attno;
1898 			ColumnDef  *def;
1899 
1900 			/*
1901 			 * Ignore dropped columns in the parent.
1902 			 */
1903 			if (attribute->attisdropped)
1904 				continue;		/* leave newattno entry as zero */
1905 
1906 			/*
1907 			 * Does it conflict with some previously inherited column?
1908 			 */
1909 			exist_attno = findAttrByName(attributeName, inhSchema);
1910 			if (exist_attno > 0)
1911 			{
1912 				Oid			defTypeId;
1913 				int32		deftypmod;
1914 				Oid			defCollId;
1915 
1916 				/*
1917 				 * Yes, try to merge the two column definitions. They must
1918 				 * have the same type, typmod, and collation.
1919 				 */
1920 				ereport(NOTICE,
1921 						(errmsg("merging multiple inherited definitions of column \"%s\"",
1922 								attributeName)));
1923 				def = (ColumnDef *) list_nth(inhSchema, exist_attno - 1);
1924 				typenameTypeIdAndMod(NULL, def->typeName, &defTypeId, &deftypmod);
1925 				if (defTypeId != attribute->atttypid ||
1926 					deftypmod != attribute->atttypmod)
1927 					ereport(ERROR,
1928 							(errcode(ERRCODE_DATATYPE_MISMATCH),
1929 							 errmsg("inherited column \"%s\" has a type conflict",
1930 									attributeName),
1931 							 errdetail("%s versus %s",
1932 									   format_type_with_typemod(defTypeId,
1933 																deftypmod),
1934 									   format_type_with_typemod(attribute->atttypid,
1935 																attribute->atttypmod))));
1936 				defCollId = GetColumnDefCollation(NULL, def, defTypeId);
1937 				if (defCollId != attribute->attcollation)
1938 					ereport(ERROR,
1939 							(errcode(ERRCODE_COLLATION_MISMATCH),
1940 							 errmsg("inherited column \"%s\" has a collation conflict",
1941 									attributeName),
1942 							 errdetail("\"%s\" versus \"%s\"",
1943 									   get_collation_name(defCollId),
1944 									   get_collation_name(attribute->attcollation))));
1945 
1946 				/* Copy storage parameter */
1947 				if (def->storage == 0)
1948 					def->storage = attribute->attstorage;
1949 				else if (def->storage != attribute->attstorage)
1950 					ereport(ERROR,
1951 							(errcode(ERRCODE_DATATYPE_MISMATCH),
1952 							 errmsg("inherited column \"%s\" has a storage parameter conflict",
1953 									attributeName),
1954 							 errdetail("%s versus %s",
1955 									   storage_name(def->storage),
1956 									   storage_name(attribute->attstorage))));
1957 
1958 				def->inhcount++;
1959 				/* Merge of NOT NULL constraints = OR 'em together */
1960 				def->is_not_null |= attribute->attnotnull;
1961 				/* Default and other constraints are handled below */
1962 				newattno[parent_attno - 1] = exist_attno;
1963 			}
1964 			else
1965 			{
1966 				/*
1967 				 * No, create a new inherited column
1968 				 */
1969 				def = makeNode(ColumnDef);
1970 				def->colname = pstrdup(attributeName);
1971 				def->typeName = makeTypeNameFromOid(attribute->atttypid,
1972 													attribute->atttypmod);
1973 				def->inhcount = 1;
1974 				def->is_local = false;
1975 				def->is_not_null = attribute->attnotnull;
1976 				def->is_from_type = false;
1977 				def->storage = attribute->attstorage;
1978 				def->raw_default = NULL;
1979 				def->cooked_default = NULL;
1980 				def->collClause = NULL;
1981 				def->collOid = attribute->attcollation;
1982 				def->constraints = NIL;
1983 				def->location = -1;
1984 				inhSchema = lappend(inhSchema, def);
1985 				newattno[parent_attno - 1] = ++child_attno;
1986 			}
1987 
1988 			/*
1989 			 * Copy default if any
1990 			 */
1991 			if (attribute->atthasdef)
1992 			{
1993 				Node	   *this_default = NULL;
1994 				AttrDefault *attrdef;
1995 				int			i;
1996 
1997 				/* Find default in constraint structure */
1998 				Assert(constr != NULL);
1999 				attrdef = constr->defval;
2000 				for (i = 0; i < constr->num_defval; i++)
2001 				{
2002 					if (attrdef[i].adnum == parent_attno)
2003 					{
2004 						this_default = stringToNode(attrdef[i].adbin);
2005 						break;
2006 					}
2007 				}
2008 				Assert(this_default != NULL);
2009 
2010 				/*
2011 				 * If default expr could contain any vars, we'd need to fix
2012 				 * 'em, but it can't; so default is ready to apply to child.
2013 				 *
2014 				 * If we already had a default from some prior parent, check
2015 				 * to see if they are the same.  If so, no problem; if not,
2016 				 * mark the column as having a bogus default. Below, we will
2017 				 * complain if the bogus default isn't overridden by the child
2018 				 * schema.
2019 				 */
2020 				Assert(def->raw_default == NULL);
2021 				if (def->cooked_default == NULL)
2022 					def->cooked_default = this_default;
2023 				else if (!equal(def->cooked_default, this_default))
2024 				{
2025 					def->cooked_default = &bogus_marker;
2026 					have_bogus_defaults = true;
2027 				}
2028 			}
2029 		}
2030 
2031 		/*
2032 		 * Now copy the CHECK constraints of this parent, adjusting attnos
2033 		 * using the completed newattno[] map.  Identically named constraints
2034 		 * are merged if possible, else we throw error.
2035 		 */
2036 		if (constr && constr->num_check > 0)
2037 		{
2038 			ConstrCheck *check = constr->check;
2039 			int			i;
2040 
2041 			for (i = 0; i < constr->num_check; i++)
2042 			{
2043 				char	   *name = check[i].ccname;
2044 				Node	   *expr;
2045 				bool		found_whole_row;
2046 
2047 				/* ignore if the constraint is non-inheritable */
2048 				if (check[i].ccnoinherit)
2049 					continue;
2050 
2051 				/* Adjust Vars to match new table's column numbering */
2052 				expr = map_variable_attnos(stringToNode(check[i].ccbin),
2053 										   1, 0,
2054 										   newattno, tupleDesc->natts,
2055 										   InvalidOid, &found_whole_row);
2056 
2057 				/*
2058 				 * For the moment we have to reject whole-row variables. We
2059 				 * could convert them, if we knew the new table's rowtype OID,
2060 				 * but that hasn't been assigned yet.
2061 				 */
2062 				if (found_whole_row)
2063 					ereport(ERROR,
2064 							(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2065 							 errmsg("cannot convert whole-row table reference"),
2066 							 errdetail("Constraint \"%s\" contains a whole-row reference to table \"%s\".",
2067 									   name,
2068 									   RelationGetRelationName(relation))));
2069 
2070 				/* check for duplicate */
2071 				if (!MergeCheckConstraint(constraints, name, expr))
2072 				{
2073 					/* nope, this is a new one */
2074 					CookedConstraint *cooked;
2075 
2076 					cooked = (CookedConstraint *) palloc(sizeof(CookedConstraint));
2077 					cooked->contype = CONSTR_CHECK;
2078 					cooked->conoid = InvalidOid;	/* until created */
2079 					cooked->name = pstrdup(name);
2080 					cooked->attnum = 0; /* not used for constraints */
2081 					cooked->expr = expr;
2082 					cooked->skip_validation = false;
2083 					cooked->is_local = false;
2084 					cooked->inhcount = 1;
2085 					cooked->is_no_inherit = false;
2086 					constraints = lappend(constraints, cooked);
2087 				}
2088 			}
2089 		}
2090 
2091 		pfree(newattno);
2092 
2093 		/*
2094 		 * Close the parent rel, but keep our lock on it until xact commit.
2095 		 * That will prevent someone else from deleting or ALTERing the parent
2096 		 * before the child is committed.
2097 		 */
2098 		heap_close(relation, NoLock);
2099 	}
2100 
2101 	/*
2102 	 * If we had no inherited attributes, the result schema is just the
2103 	 * explicitly declared columns.  Otherwise, we need to merge the declared
2104 	 * columns into the inherited schema list.  Although, we never have any
2105 	 * explicitly declared columns if the table is a partition.
2106 	 */
2107 	if (inhSchema != NIL)
2108 	{
2109 		int			schema_attno = 0;
2110 
2111 		foreach(entry, schema)
2112 		{
2113 			ColumnDef  *newdef = lfirst(entry);
2114 			char	   *attributeName = newdef->colname;
2115 			int			exist_attno;
2116 
2117 			schema_attno++;
2118 
2119 			/*
2120 			 * Does it conflict with some previously inherited column?
2121 			 */
2122 			exist_attno = findAttrByName(attributeName, inhSchema);
2123 			if (exist_attno > 0)
2124 			{
2125 				ColumnDef  *def;
2126 				Oid			defTypeId,
2127 							newTypeId;
2128 				int32		deftypmod,
2129 							newtypmod;
2130 				Oid			defcollid,
2131 							newcollid;
2132 
2133 				/*
2134 				 * Partitions have only one parent and have no column
2135 				 * definitions of their own, so conflict should never occur.
2136 				 */
2137 				Assert(!is_partition);
2138 
2139 				/*
2140 				 * Yes, try to merge the two column definitions. They must
2141 				 * have the same type, typmod, and collation.
2142 				 */
2143 				if (exist_attno == schema_attno)
2144 					ereport(NOTICE,
2145 							(errmsg("merging column \"%s\" with inherited definition",
2146 									attributeName)));
2147 				else
2148 					ereport(NOTICE,
2149 							(errmsg("moving and merging column \"%s\" with inherited definition", attributeName),
2150 							 errdetail("User-specified column moved to the position of the inherited column.")));
2151 				def = (ColumnDef *) list_nth(inhSchema, exist_attno - 1);
2152 				typenameTypeIdAndMod(NULL, def->typeName, &defTypeId, &deftypmod);
2153 				typenameTypeIdAndMod(NULL, newdef->typeName, &newTypeId, &newtypmod);
2154 				if (defTypeId != newTypeId || deftypmod != newtypmod)
2155 					ereport(ERROR,
2156 							(errcode(ERRCODE_DATATYPE_MISMATCH),
2157 							 errmsg("column \"%s\" has a type conflict",
2158 									attributeName),
2159 							 errdetail("%s versus %s",
2160 									   format_type_with_typemod(defTypeId,
2161 																deftypmod),
2162 									   format_type_with_typemod(newTypeId,
2163 																newtypmod))));
2164 				defcollid = GetColumnDefCollation(NULL, def, defTypeId);
2165 				newcollid = GetColumnDefCollation(NULL, newdef, newTypeId);
2166 				if (defcollid != newcollid)
2167 					ereport(ERROR,
2168 							(errcode(ERRCODE_COLLATION_MISMATCH),
2169 							 errmsg("column \"%s\" has a collation conflict",
2170 									attributeName),
2171 							 errdetail("\"%s\" versus \"%s\"",
2172 									   get_collation_name(defcollid),
2173 									   get_collation_name(newcollid))));
2174 
2175 				/*
2176 				 * Identity is never inherited.  The new column can have an
2177 				 * identity definition, so we always just take that one.
2178 				 */
2179 				def->identity = newdef->identity;
2180 
2181 				/* Copy storage parameter */
2182 				if (def->storage == 0)
2183 					def->storage = newdef->storage;
2184 				else if (newdef->storage != 0 && def->storage != newdef->storage)
2185 					ereport(ERROR,
2186 							(errcode(ERRCODE_DATATYPE_MISMATCH),
2187 							 errmsg("column \"%s\" has a storage parameter conflict",
2188 									attributeName),
2189 							 errdetail("%s versus %s",
2190 									   storage_name(def->storage),
2191 									   storage_name(newdef->storage))));
2192 
2193 				/* Mark the column as locally defined */
2194 				def->is_local = true;
2195 				/* Merge of NOT NULL constraints = OR 'em together */
2196 				def->is_not_null |= newdef->is_not_null;
2197 				/* If new def has a default, override previous default */
2198 				if (newdef->raw_default != NULL)
2199 				{
2200 					def->raw_default = newdef->raw_default;
2201 					def->cooked_default = newdef->cooked_default;
2202 				}
2203 			}
2204 			else
2205 			{
2206 				/*
2207 				 * No, attach new column to result schema
2208 				 */
2209 				inhSchema = lappend(inhSchema, newdef);
2210 			}
2211 		}
2212 
2213 		schema = inhSchema;
2214 
2215 		/*
2216 		 * Check that we haven't exceeded the legal # of columns after merging
2217 		 * in inherited columns.
2218 		 */
2219 		if (list_length(schema) > MaxHeapAttributeNumber)
2220 			ereport(ERROR,
2221 					(errcode(ERRCODE_TOO_MANY_COLUMNS),
2222 					 errmsg("tables can have at most %d columns",
2223 							MaxHeapAttributeNumber)));
2224 	}
2225 
2226 	/*
2227 	 * Now that we have the column definition list for a partition, we can
2228 	 * check whether the columns referenced in the column constraint specs
2229 	 * actually exist.  Also, we merge NOT NULL and defaults into each
2230 	 * corresponding column definition.
2231 	 */
2232 	if (is_partition)
2233 	{
2234 		foreach(entry, saved_schema)
2235 		{
2236 			ColumnDef  *restdef = lfirst(entry);
2237 			bool		found = false;
2238 			ListCell   *l;
2239 
2240 			foreach(l, schema)
2241 			{
2242 				ColumnDef  *coldef = lfirst(l);
2243 
2244 				if (strcmp(coldef->colname, restdef->colname) == 0)
2245 				{
2246 					found = true;
2247 					coldef->is_not_null |= restdef->is_not_null;
2248 
2249 					/*
2250 					 * Override the parent's default value for this column
2251 					 * (coldef->cooked_default) with the partition's local
2252 					 * definition (restdef->raw_default), if there's one. It
2253 					 * should be physically impossible to get a cooked default
2254 					 * in the local definition or a raw default in the
2255 					 * inherited definition, but make sure they're nulls, for
2256 					 * future-proofing.
2257 					 */
2258 					Assert(restdef->cooked_default == NULL);
2259 					Assert(coldef->raw_default == NULL);
2260 					if (restdef->raw_default)
2261 					{
2262 						coldef->raw_default = restdef->raw_default;
2263 						coldef->cooked_default = NULL;
2264 					}
2265 				}
2266 			}
2267 
2268 			/* complain for constraints on columns not in parent */
2269 			if (!found)
2270 				ereport(ERROR,
2271 						(errcode(ERRCODE_UNDEFINED_COLUMN),
2272 						 errmsg("column \"%s\" does not exist",
2273 								restdef->colname)));
2274 		}
2275 	}
2276 
2277 	/*
2278 	 * If we found any conflicting parent default values, check to make sure
2279 	 * they were overridden by the child.
2280 	 */
2281 	if (have_bogus_defaults)
2282 	{
2283 		foreach(entry, schema)
2284 		{
2285 			ColumnDef  *def = lfirst(entry);
2286 
2287 			if (def->cooked_default == &bogus_marker)
2288 				ereport(ERROR,
2289 						(errcode(ERRCODE_INVALID_COLUMN_DEFINITION),
2290 						 errmsg("column \"%s\" inherits conflicting default values",
2291 								def->colname),
2292 						 errhint("To resolve the conflict, specify a default explicitly.")));
2293 		}
2294 	}
2295 
2296 	*supOids = parentOids;
2297 	*supconstr = constraints;
2298 	*supOidCount = parentsWithOids;
2299 	return schema;
2300 }
2301 
2302 
2303 /*
2304  * MergeCheckConstraint
2305  *		Try to merge an inherited CHECK constraint with previous ones
2306  *
2307  * If we inherit identically-named constraints from multiple parents, we must
2308  * merge them, or throw an error if they don't have identical definitions.
2309  *
2310  * constraints is a list of CookedConstraint structs for previous constraints.
2311  *
2312  * Returns TRUE if merged (constraint is a duplicate), or FALSE if it's
2313  * got a so-far-unique name, or throws error if conflict.
2314  */
2315 static bool
MergeCheckConstraint(List * constraints,char * name,Node * expr)2316 MergeCheckConstraint(List *constraints, char *name, Node *expr)
2317 {
2318 	ListCell   *lc;
2319 
2320 	foreach(lc, constraints)
2321 	{
2322 		CookedConstraint *ccon = (CookedConstraint *) lfirst(lc);
2323 
2324 		Assert(ccon->contype == CONSTR_CHECK);
2325 
2326 		/* Non-matching names never conflict */
2327 		if (strcmp(ccon->name, name) != 0)
2328 			continue;
2329 
2330 		if (equal(expr, ccon->expr))
2331 		{
2332 			/* OK to merge */
2333 			ccon->inhcount++;
2334 			return true;
2335 		}
2336 
2337 		ereport(ERROR,
2338 				(errcode(ERRCODE_DUPLICATE_OBJECT),
2339 				 errmsg("check constraint name \"%s\" appears multiple times but with different expressions",
2340 						name)));
2341 	}
2342 
2343 	return false;
2344 }
2345 
2346 
2347 /*
2348  * StoreCatalogInheritance
2349  *		Updates the system catalogs with proper inheritance information.
2350  *
2351  * supers is a list of the OIDs of the new relation's direct ancestors.
2352  */
2353 static void
StoreCatalogInheritance(Oid relationId,List * supers,bool child_is_partition)2354 StoreCatalogInheritance(Oid relationId, List *supers,
2355 						bool child_is_partition)
2356 {
2357 	Relation	relation;
2358 	int32		seqNumber;
2359 	ListCell   *entry;
2360 
2361 	/*
2362 	 * sanity checks
2363 	 */
2364 	AssertArg(OidIsValid(relationId));
2365 
2366 	if (supers == NIL)
2367 		return;
2368 
2369 	/*
2370 	 * Store INHERITS information in pg_inherits using direct ancestors only.
2371 	 * Also enter dependencies on the direct ancestors, and make sure they are
2372 	 * marked with relhassubclass = true.
2373 	 *
2374 	 * (Once upon a time, both direct and indirect ancestors were found here
2375 	 * and then entered into pg_ipl.  Since that catalog doesn't exist
2376 	 * anymore, there's no need to look for indirect ancestors.)
2377 	 */
2378 	relation = heap_open(InheritsRelationId, RowExclusiveLock);
2379 
2380 	seqNumber = 1;
2381 	foreach(entry, supers)
2382 	{
2383 		Oid			parentOid = lfirst_oid(entry);
2384 
2385 		StoreCatalogInheritance1(relationId, parentOid, seqNumber, relation,
2386 								 child_is_partition);
2387 		seqNumber++;
2388 	}
2389 
2390 	heap_close(relation, RowExclusiveLock);
2391 }
2392 
2393 /*
2394  * Make catalog entries showing relationId as being an inheritance child
2395  * of parentOid.  inhRelation is the already-opened pg_inherits catalog.
2396  */
2397 static void
StoreCatalogInheritance1(Oid relationId,Oid parentOid,int32 seqNumber,Relation inhRelation,bool child_is_partition)2398 StoreCatalogInheritance1(Oid relationId, Oid parentOid,
2399 						 int32 seqNumber, Relation inhRelation,
2400 						 bool child_is_partition)
2401 {
2402 	TupleDesc	desc = RelationGetDescr(inhRelation);
2403 	Datum		values[Natts_pg_inherits];
2404 	bool		nulls[Natts_pg_inherits];
2405 	ObjectAddress childobject,
2406 				parentobject;
2407 	HeapTuple	tuple;
2408 
2409 	/*
2410 	 * Make the pg_inherits entry
2411 	 */
2412 	values[Anum_pg_inherits_inhrelid - 1] = ObjectIdGetDatum(relationId);
2413 	values[Anum_pg_inherits_inhparent - 1] = ObjectIdGetDatum(parentOid);
2414 	values[Anum_pg_inherits_inhseqno - 1] = Int32GetDatum(seqNumber);
2415 
2416 	memset(nulls, 0, sizeof(nulls));
2417 
2418 	tuple = heap_form_tuple(desc, values, nulls);
2419 
2420 	CatalogTupleInsert(inhRelation, tuple);
2421 
2422 	heap_freetuple(tuple);
2423 
2424 	/*
2425 	 * Store a dependency too
2426 	 */
2427 	parentobject.classId = RelationRelationId;
2428 	parentobject.objectId = parentOid;
2429 	parentobject.objectSubId = 0;
2430 	childobject.classId = RelationRelationId;
2431 	childobject.objectId = relationId;
2432 	childobject.objectSubId = 0;
2433 
2434 	recordDependencyOn(&childobject, &parentobject,
2435 					   child_dependency_type(child_is_partition));
2436 
2437 	/*
2438 	 * Post creation hook of this inheritance. Since object_access_hook
2439 	 * doesn't take multiple object identifiers, we relay oid of parent
2440 	 * relation using auxiliary_id argument.
2441 	 */
2442 	InvokeObjectPostAlterHookArg(InheritsRelationId,
2443 								 relationId, 0,
2444 								 parentOid, false);
2445 
2446 	/*
2447 	 * Mark the parent as having subclasses.
2448 	 */
2449 	SetRelationHasSubclass(parentOid, true);
2450 }
2451 
2452 /*
2453  * Look for an existing schema entry with the given name.
2454  *
2455  * Returns the index (starting with 1) if attribute already exists in schema,
2456  * 0 if it doesn't.
2457  */
2458 static int
findAttrByName(const char * attributeName,List * schema)2459 findAttrByName(const char *attributeName, List *schema)
2460 {
2461 	ListCell   *s;
2462 	int			i = 1;
2463 
2464 	foreach(s, schema)
2465 	{
2466 		ColumnDef  *def = lfirst(s);
2467 
2468 		if (strcmp(attributeName, def->colname) == 0)
2469 			return i;
2470 
2471 		i++;
2472 	}
2473 	return 0;
2474 }
2475 
2476 
2477 /*
2478  * SetRelationHasSubclass
2479  *		Set the value of the relation's relhassubclass field in pg_class.
2480  *
2481  * NOTE: caller must be holding an appropriate lock on the relation.
2482  * ShareUpdateExclusiveLock is sufficient.
2483  *
2484  * NOTE: an important side-effect of this operation is that an SI invalidation
2485  * message is sent out to all backends --- including me --- causing plans
2486  * referencing the relation to be rebuilt with the new list of children.
2487  * This must happen even if we find that no change is needed in the pg_class
2488  * row.
2489  */
2490 void
SetRelationHasSubclass(Oid relationId,bool relhassubclass)2491 SetRelationHasSubclass(Oid relationId, bool relhassubclass)
2492 {
2493 	Relation	relationRelation;
2494 	HeapTuple	tuple;
2495 	Form_pg_class classtuple;
2496 
2497 	/*
2498 	 * Fetch a modifiable copy of the tuple, modify it, update pg_class.
2499 	 */
2500 	relationRelation = heap_open(RelationRelationId, RowExclusiveLock);
2501 	tuple = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relationId));
2502 	if (!HeapTupleIsValid(tuple))
2503 		elog(ERROR, "cache lookup failed for relation %u", relationId);
2504 	classtuple = (Form_pg_class) GETSTRUCT(tuple);
2505 
2506 	if (classtuple->relhassubclass != relhassubclass)
2507 	{
2508 		classtuple->relhassubclass = relhassubclass;
2509 		CatalogTupleUpdate(relationRelation, &tuple->t_self, tuple);
2510 	}
2511 	else
2512 	{
2513 		/* no need to change tuple, but force relcache rebuild anyway */
2514 		CacheInvalidateRelcacheByTuple(tuple);
2515 	}
2516 
2517 	heap_freetuple(tuple);
2518 	heap_close(relationRelation, RowExclusiveLock);
2519 }
2520 
2521 /*
2522  *		renameatt_check			- basic sanity checks before attribute rename
2523  */
2524 static void
renameatt_check(Oid myrelid,Form_pg_class classform,bool recursing)2525 renameatt_check(Oid myrelid, Form_pg_class classform, bool recursing)
2526 {
2527 	char		relkind = classform->relkind;
2528 
2529 	if (classform->reloftype && !recursing)
2530 		ereport(ERROR,
2531 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
2532 				 errmsg("cannot rename column of typed table")));
2533 
2534 	/*
2535 	 * Renaming the columns of sequences or toast tables doesn't actually
2536 	 * break anything from the system's point of view, since internal
2537 	 * references are by attnum.  But it doesn't seem right to allow users to
2538 	 * change names that are hardcoded into the system, hence the following
2539 	 * restriction.
2540 	 */
2541 	if (relkind != RELKIND_RELATION &&
2542 		relkind != RELKIND_VIEW &&
2543 		relkind != RELKIND_MATVIEW &&
2544 		relkind != RELKIND_COMPOSITE_TYPE &&
2545 		relkind != RELKIND_INDEX &&
2546 		relkind != RELKIND_FOREIGN_TABLE &&
2547 		relkind != RELKIND_PARTITIONED_TABLE)
2548 		ereport(ERROR,
2549 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
2550 				 errmsg("\"%s\" is not a table, view, materialized view, composite type, index, or foreign table",
2551 						NameStr(classform->relname))));
2552 
2553 	/*
2554 	 * permissions checking.  only the owner of a class can change its schema.
2555 	 */
2556 	if (!pg_class_ownercheck(myrelid, GetUserId()))
2557 		aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS,
2558 					   NameStr(classform->relname));
2559 	if (!allowSystemTableMods && IsSystemClass(myrelid, classform))
2560 		ereport(ERROR,
2561 				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
2562 				 errmsg("permission denied: \"%s\" is a system catalog",
2563 						NameStr(classform->relname))));
2564 }
2565 
2566 /*
2567  *		renameatt_internal		- workhorse for renameatt
2568  *
2569  * Return value is the attribute number in the 'myrelid' relation.
2570  */
2571 static AttrNumber
renameatt_internal(Oid myrelid,const char * oldattname,const char * newattname,bool recurse,bool recursing,int expected_parents,DropBehavior behavior)2572 renameatt_internal(Oid myrelid,
2573 				   const char *oldattname,
2574 				   const char *newattname,
2575 				   bool recurse,
2576 				   bool recursing,
2577 				   int expected_parents,
2578 				   DropBehavior behavior)
2579 {
2580 	Relation	targetrelation;
2581 	Relation	attrelation;
2582 	HeapTuple	atttup;
2583 	Form_pg_attribute attform;
2584 	AttrNumber	attnum;
2585 
2586 	/*
2587 	 * Grab an exclusive lock on the target table, which we will NOT release
2588 	 * until end of transaction.
2589 	 */
2590 	targetrelation = relation_open(myrelid, AccessExclusiveLock);
2591 	renameatt_check(myrelid, RelationGetForm(targetrelation), recursing);
2592 
2593 	/*
2594 	 * if the 'recurse' flag is set then we are supposed to rename this
2595 	 * attribute in all classes that inherit from 'relname' (as well as in
2596 	 * 'relname').
2597 	 *
2598 	 * any permissions or problems with duplicate attributes will cause the
2599 	 * whole transaction to abort, which is what we want -- all or nothing.
2600 	 */
2601 	if (recurse)
2602 	{
2603 		List	   *child_oids,
2604 				   *child_numparents;
2605 		ListCell   *lo,
2606 				   *li;
2607 
2608 		/*
2609 		 * we need the number of parents for each child so that the recursive
2610 		 * calls to renameatt() can determine whether there are any parents
2611 		 * outside the inheritance hierarchy being processed.
2612 		 */
2613 		child_oids = find_all_inheritors(myrelid, AccessExclusiveLock,
2614 										 &child_numparents);
2615 
2616 		/*
2617 		 * find_all_inheritors does the recursive search of the inheritance
2618 		 * hierarchy, so all we have to do is process all of the relids in the
2619 		 * list that it returns.
2620 		 */
2621 		forboth(lo, child_oids, li, child_numparents)
2622 		{
2623 			Oid			childrelid = lfirst_oid(lo);
2624 			int			numparents = lfirst_int(li);
2625 
2626 			if (childrelid == myrelid)
2627 				continue;
2628 			/* note we need not recurse again */
2629 			renameatt_internal(childrelid, oldattname, newattname, false, true, numparents, behavior);
2630 		}
2631 	}
2632 	else
2633 	{
2634 		/*
2635 		 * If we are told not to recurse, there had better not be any child
2636 		 * tables; else the rename would put them out of step.
2637 		 *
2638 		 * expected_parents will only be 0 if we are not already recursing.
2639 		 */
2640 		if (expected_parents == 0 &&
2641 			find_inheritance_children(myrelid, NoLock) != NIL)
2642 			ereport(ERROR,
2643 					(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
2644 					 errmsg("inherited column \"%s\" must be renamed in child tables too",
2645 							oldattname)));
2646 	}
2647 
2648 	/* rename attributes in typed tables of composite type */
2649 	if (targetrelation->rd_rel->relkind == RELKIND_COMPOSITE_TYPE)
2650 	{
2651 		List	   *child_oids;
2652 		ListCell   *lo;
2653 
2654 		child_oids = find_typed_table_dependencies(targetrelation->rd_rel->reltype,
2655 												   RelationGetRelationName(targetrelation),
2656 												   behavior);
2657 
2658 		foreach(lo, child_oids)
2659 			renameatt_internal(lfirst_oid(lo), oldattname, newattname, true, true, 0, behavior);
2660 	}
2661 
2662 	attrelation = heap_open(AttributeRelationId, RowExclusiveLock);
2663 
2664 	atttup = SearchSysCacheCopyAttName(myrelid, oldattname);
2665 	if (!HeapTupleIsValid(atttup))
2666 		ereport(ERROR,
2667 				(errcode(ERRCODE_UNDEFINED_COLUMN),
2668 				 errmsg("column \"%s\" does not exist",
2669 						oldattname)));
2670 	attform = (Form_pg_attribute) GETSTRUCT(atttup);
2671 
2672 	attnum = attform->attnum;
2673 	if (attnum <= 0)
2674 		ereport(ERROR,
2675 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2676 				 errmsg("cannot rename system column \"%s\"",
2677 						oldattname)));
2678 
2679 	/*
2680 	 * if the attribute is inherited, forbid the renaming.  if this is a
2681 	 * top-level call to renameatt(), then expected_parents will be 0, so the
2682 	 * effect of this code will be to prohibit the renaming if the attribute
2683 	 * is inherited at all.  if this is a recursive call to renameatt(),
2684 	 * expected_parents will be the number of parents the current relation has
2685 	 * within the inheritance hierarchy being processed, so we'll prohibit the
2686 	 * renaming only if there are additional parents from elsewhere.
2687 	 */
2688 	if (attform->attinhcount > expected_parents)
2689 		ereport(ERROR,
2690 				(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
2691 				 errmsg("cannot rename inherited column \"%s\"",
2692 						oldattname)));
2693 
2694 	/* new name should not already exist */
2695 	(void) check_for_column_name_collision(targetrelation, newattname, false);
2696 
2697 	/* apply the update */
2698 	namestrcpy(&(attform->attname), newattname);
2699 
2700 	CatalogTupleUpdate(attrelation, &atttup->t_self, atttup);
2701 
2702 	InvokeObjectPostAlterHook(RelationRelationId, myrelid, attnum);
2703 
2704 	heap_freetuple(atttup);
2705 
2706 	heap_close(attrelation, RowExclusiveLock);
2707 
2708 	relation_close(targetrelation, NoLock); /* close rel but keep lock */
2709 
2710 	return attnum;
2711 }
2712 
2713 /*
2714  * Perform permissions and integrity checks before acquiring a relation lock.
2715  */
2716 static void
RangeVarCallbackForRenameAttribute(const RangeVar * rv,Oid relid,Oid oldrelid,void * arg)2717 RangeVarCallbackForRenameAttribute(const RangeVar *rv, Oid relid, Oid oldrelid,
2718 								   void *arg)
2719 {
2720 	HeapTuple	tuple;
2721 	Form_pg_class form;
2722 
2723 	tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
2724 	if (!HeapTupleIsValid(tuple))
2725 		return;					/* concurrently dropped */
2726 	form = (Form_pg_class) GETSTRUCT(tuple);
2727 	renameatt_check(relid, form, false);
2728 	ReleaseSysCache(tuple);
2729 }
2730 
2731 /*
2732  *		renameatt		- changes the name of an attribute in a relation
2733  *
2734  * The returned ObjectAddress is that of the renamed column.
2735  */
2736 ObjectAddress
renameatt(RenameStmt * stmt)2737 renameatt(RenameStmt *stmt)
2738 {
2739 	Oid			relid;
2740 	AttrNumber	attnum;
2741 	ObjectAddress address;
2742 
2743 	/* lock level taken here should match renameatt_internal */
2744 	relid = RangeVarGetRelidExtended(stmt->relation, AccessExclusiveLock,
2745 									 stmt->missing_ok, false,
2746 									 RangeVarCallbackForRenameAttribute,
2747 									 NULL);
2748 
2749 	if (!OidIsValid(relid))
2750 	{
2751 		ereport(NOTICE,
2752 				(errmsg("relation \"%s\" does not exist, skipping",
2753 						stmt->relation->relname)));
2754 		return InvalidObjectAddress;
2755 	}
2756 
2757 	attnum =
2758 		renameatt_internal(relid,
2759 						   stmt->subname,	/* old att name */
2760 						   stmt->newname,	/* new att name */
2761 						   stmt->relation->inh, /* recursive? */
2762 						   false,	/* recursing? */
2763 						   0,	/* expected inhcount */
2764 						   stmt->behavior);
2765 
2766 	ObjectAddressSubSet(address, RelationRelationId, relid, attnum);
2767 
2768 	return address;
2769 }
2770 
2771 /*
2772  * same logic as renameatt_internal
2773  */
2774 static ObjectAddress
rename_constraint_internal(Oid myrelid,Oid mytypid,const char * oldconname,const char * newconname,bool recurse,bool recursing,int expected_parents)2775 rename_constraint_internal(Oid myrelid,
2776 						   Oid mytypid,
2777 						   const char *oldconname,
2778 						   const char *newconname,
2779 						   bool recurse,
2780 						   bool recursing,
2781 						   int expected_parents)
2782 {
2783 	Relation	targetrelation = NULL;
2784 	Oid			constraintOid;
2785 	HeapTuple	tuple;
2786 	Form_pg_constraint con;
2787 	ObjectAddress address;
2788 
2789 	AssertArg(!myrelid || !mytypid);
2790 
2791 	if (mytypid)
2792 	{
2793 		constraintOid = get_domain_constraint_oid(mytypid, oldconname, false);
2794 	}
2795 	else
2796 	{
2797 		targetrelation = relation_open(myrelid, AccessExclusiveLock);
2798 
2799 		/*
2800 		 * don't tell it whether we're recursing; we allow changing typed
2801 		 * tables here
2802 		 */
2803 		renameatt_check(myrelid, RelationGetForm(targetrelation), false);
2804 
2805 		constraintOid = get_relation_constraint_oid(myrelid, oldconname, false);
2806 	}
2807 
2808 	tuple = SearchSysCache1(CONSTROID, ObjectIdGetDatum(constraintOid));
2809 	if (!HeapTupleIsValid(tuple))
2810 		elog(ERROR, "cache lookup failed for constraint %u",
2811 			 constraintOid);
2812 	con = (Form_pg_constraint) GETSTRUCT(tuple);
2813 
2814 	if (myrelid && con->contype == CONSTRAINT_CHECK && !con->connoinherit)
2815 	{
2816 		if (recurse)
2817 		{
2818 			List	   *child_oids,
2819 					   *child_numparents;
2820 			ListCell   *lo,
2821 					   *li;
2822 
2823 			child_oids = find_all_inheritors(myrelid, AccessExclusiveLock,
2824 											 &child_numparents);
2825 
2826 			forboth(lo, child_oids, li, child_numparents)
2827 			{
2828 				Oid			childrelid = lfirst_oid(lo);
2829 				int			numparents = lfirst_int(li);
2830 
2831 				if (childrelid == myrelid)
2832 					continue;
2833 
2834 				rename_constraint_internal(childrelid, InvalidOid, oldconname, newconname, false, true, numparents);
2835 			}
2836 		}
2837 		else
2838 		{
2839 			if (expected_parents == 0 &&
2840 				find_inheritance_children(myrelid, NoLock) != NIL)
2841 				ereport(ERROR,
2842 						(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
2843 						 errmsg("inherited constraint \"%s\" must be renamed in child tables too",
2844 								oldconname)));
2845 		}
2846 
2847 		if (con->coninhcount > expected_parents)
2848 			ereport(ERROR,
2849 					(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
2850 					 errmsg("cannot rename inherited constraint \"%s\"",
2851 							oldconname)));
2852 	}
2853 
2854 	if (con->conindid
2855 		&& (con->contype == CONSTRAINT_PRIMARY
2856 			|| con->contype == CONSTRAINT_UNIQUE
2857 			|| con->contype == CONSTRAINT_EXCLUSION))
2858 		/* rename the index; this renames the constraint as well */
2859 		RenameRelationInternal(con->conindid, newconname, false);
2860 	else
2861 		RenameConstraintById(constraintOid, newconname);
2862 
2863 	ObjectAddressSet(address, ConstraintRelationId, constraintOid);
2864 
2865 	ReleaseSysCache(tuple);
2866 
2867 	if (targetrelation)
2868 	{
2869 		/*
2870 		 * Invalidate relcache so as others can see the new constraint name.
2871 		 */
2872 		CacheInvalidateRelcache(targetrelation);
2873 
2874 		relation_close(targetrelation, NoLock); /* close rel but keep lock */
2875 	}
2876 
2877 	return address;
2878 }
2879 
2880 ObjectAddress
RenameConstraint(RenameStmt * stmt)2881 RenameConstraint(RenameStmt *stmt)
2882 {
2883 	Oid			relid = InvalidOid;
2884 	Oid			typid = InvalidOid;
2885 
2886 	if (stmt->renameType == OBJECT_DOMCONSTRAINT)
2887 	{
2888 		Relation	rel;
2889 		HeapTuple	tup;
2890 
2891 		typid = typenameTypeId(NULL, makeTypeNameFromNameList(castNode(List, stmt->object)));
2892 		rel = heap_open(TypeRelationId, RowExclusiveLock);
2893 		tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
2894 		if (!HeapTupleIsValid(tup))
2895 			elog(ERROR, "cache lookup failed for type %u", typid);
2896 		checkDomainOwner(tup);
2897 		ReleaseSysCache(tup);
2898 		heap_close(rel, NoLock);
2899 	}
2900 	else
2901 	{
2902 		/* lock level taken here should match rename_constraint_internal */
2903 		relid = RangeVarGetRelidExtended(stmt->relation, AccessExclusiveLock,
2904 										 stmt->missing_ok, false,
2905 										 RangeVarCallbackForRenameAttribute,
2906 										 NULL);
2907 		if (!OidIsValid(relid))
2908 		{
2909 			ereport(NOTICE,
2910 					(errmsg("relation \"%s\" does not exist, skipping",
2911 							stmt->relation->relname)));
2912 			return InvalidObjectAddress;
2913 		}
2914 	}
2915 
2916 	return
2917 		rename_constraint_internal(relid, typid,
2918 								   stmt->subname,
2919 								   stmt->newname,
2920 								   (stmt->relation &&
2921 									stmt->relation->inh),	/* recursive? */
2922 								   false,	/* recursing? */
2923 								   0 /* expected inhcount */ );
2924 
2925 }
2926 
2927 /*
2928  * Execute ALTER TABLE/INDEX/SEQUENCE/VIEW/MATERIALIZED VIEW/FOREIGN TABLE
2929  * RENAME
2930  */
2931 ObjectAddress
RenameRelation(RenameStmt * stmt)2932 RenameRelation(RenameStmt *stmt)
2933 {
2934 	Oid			relid;
2935 	ObjectAddress address;
2936 
2937 	/*
2938 	 * Grab an exclusive lock on the target table, index, sequence, view,
2939 	 * materialized view, or foreign table, which we will NOT release until
2940 	 * end of transaction.
2941 	 *
2942 	 * Lock level used here should match RenameRelationInternal, to avoid lock
2943 	 * escalation.
2944 	 */
2945 	relid = RangeVarGetRelidExtended(stmt->relation, AccessExclusiveLock,
2946 									 stmt->missing_ok, false,
2947 									 RangeVarCallbackForAlterRelation,
2948 									 (void *) stmt);
2949 
2950 	if (!OidIsValid(relid))
2951 	{
2952 		ereport(NOTICE,
2953 				(errmsg("relation \"%s\" does not exist, skipping",
2954 						stmt->relation->relname)));
2955 		return InvalidObjectAddress;
2956 	}
2957 
2958 	/* Do the work */
2959 	RenameRelationInternal(relid, stmt->newname, false);
2960 
2961 	ObjectAddressSet(address, RelationRelationId, relid);
2962 
2963 	return address;
2964 }
2965 
2966 /*
2967  *		RenameRelationInternal - change the name of a relation
2968  */
2969 void
RenameRelationInternal(Oid myrelid,const char * newrelname,bool is_internal)2970 RenameRelationInternal(Oid myrelid, const char *newrelname, bool is_internal)
2971 {
2972 	Relation	targetrelation;
2973 	Relation	relrelation;	/* for RELATION relation */
2974 	HeapTuple	reltup;
2975 	Form_pg_class relform;
2976 	Oid			namespaceId;
2977 
2978 	/*
2979 	 * Grab an exclusive lock on the target table, index, sequence, view,
2980 	 * materialized view, or foreign table, which we will NOT release until
2981 	 * end of transaction.
2982 	 */
2983 	targetrelation = relation_open(myrelid, AccessExclusiveLock);
2984 	namespaceId = RelationGetNamespace(targetrelation);
2985 
2986 	/*
2987 	 * Find relation's pg_class tuple, and make sure newrelname isn't in use.
2988 	 */
2989 	relrelation = heap_open(RelationRelationId, RowExclusiveLock);
2990 
2991 	reltup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(myrelid));
2992 	if (!HeapTupleIsValid(reltup))	/* shouldn't happen */
2993 		elog(ERROR, "cache lookup failed for relation %u", myrelid);
2994 	relform = (Form_pg_class) GETSTRUCT(reltup);
2995 
2996 	if (get_relname_relid(newrelname, namespaceId) != InvalidOid)
2997 		ereport(ERROR,
2998 				(errcode(ERRCODE_DUPLICATE_TABLE),
2999 				 errmsg("relation \"%s\" already exists",
3000 						newrelname)));
3001 
3002 	/*
3003 	 * Update pg_class tuple with new relname.  (Scribbling on reltup is OK
3004 	 * because it's a copy...)
3005 	 */
3006 	namestrcpy(&(relform->relname), newrelname);
3007 
3008 	CatalogTupleUpdate(relrelation, &reltup->t_self, reltup);
3009 
3010 	InvokeObjectPostAlterHookArg(RelationRelationId, myrelid, 0,
3011 								 InvalidOid, is_internal);
3012 
3013 	heap_freetuple(reltup);
3014 	heap_close(relrelation, RowExclusiveLock);
3015 
3016 	/*
3017 	 * Also rename the associated type, if any.
3018 	 */
3019 	if (OidIsValid(targetrelation->rd_rel->reltype))
3020 		RenameTypeInternal(targetrelation->rd_rel->reltype,
3021 						   newrelname, namespaceId);
3022 
3023 	/*
3024 	 * Also rename the associated constraint, if any.
3025 	 */
3026 	if (targetrelation->rd_rel->relkind == RELKIND_INDEX)
3027 	{
3028 		Oid			constraintId = get_index_constraint(myrelid);
3029 
3030 		if (OidIsValid(constraintId))
3031 			RenameConstraintById(constraintId, newrelname);
3032 	}
3033 
3034 	/*
3035 	 * Close rel, but keep exclusive lock!
3036 	 */
3037 	relation_close(targetrelation, NoLock);
3038 }
3039 
3040 /*
3041  * Disallow ALTER TABLE (and similar commands) when the current backend has
3042  * any open reference to the target table besides the one just acquired by
3043  * the calling command; this implies there's an open cursor or active plan.
3044  * We need this check because our lock doesn't protect us against stomping
3045  * on our own foot, only other people's feet!
3046  *
3047  * For ALTER TABLE, the only case known to cause serious trouble is ALTER
3048  * COLUMN TYPE, and some changes are obviously pretty benign, so this could
3049  * possibly be relaxed to only error out for certain types of alterations.
3050  * But the use-case for allowing any of these things is not obvious, so we
3051  * won't work hard at it for now.
3052  *
3053  * We also reject these commands if there are any pending AFTER trigger events
3054  * for the rel.  This is certainly necessary for the rewriting variants of
3055  * ALTER TABLE, because they don't preserve tuple TIDs and so the pending
3056  * events would try to fetch the wrong tuples.  It might be overly cautious
3057  * in other cases, but again it seems better to err on the side of paranoia.
3058  *
3059  * REINDEX calls this with "rel" referencing the index to be rebuilt; here
3060  * we are worried about active indexscans on the index.  The trigger-event
3061  * check can be skipped, since we are doing no damage to the parent table.
3062  *
3063  * The statement name (eg, "ALTER TABLE") is passed for use in error messages.
3064  */
3065 void
CheckTableNotInUse(Relation rel,const char * stmt)3066 CheckTableNotInUse(Relation rel, const char *stmt)
3067 {
3068 	int			expected_refcnt;
3069 
3070 	expected_refcnt = rel->rd_isnailed ? 2 : 1;
3071 	if (rel->rd_refcnt != expected_refcnt)
3072 		ereport(ERROR,
3073 				(errcode(ERRCODE_OBJECT_IN_USE),
3074 		/* translator: first %s is a SQL command, eg ALTER TABLE */
3075 				 errmsg("cannot %s \"%s\" because "
3076 						"it is being used by active queries in this session",
3077 						stmt, RelationGetRelationName(rel))));
3078 
3079 	if (rel->rd_rel->relkind != RELKIND_INDEX &&
3080 		AfterTriggerPendingOnRel(RelationGetRelid(rel)))
3081 		ereport(ERROR,
3082 				(errcode(ERRCODE_OBJECT_IN_USE),
3083 		/* translator: first %s is a SQL command, eg ALTER TABLE */
3084 				 errmsg("cannot %s \"%s\" because "
3085 						"it has pending trigger events",
3086 						stmt, RelationGetRelationName(rel))));
3087 }
3088 
3089 /*
3090  * AlterTableLookupRelation
3091  *		Look up, and lock, the OID for the relation named by an alter table
3092  *		statement.
3093  */
3094 Oid
AlterTableLookupRelation(AlterTableStmt * stmt,LOCKMODE lockmode)3095 AlterTableLookupRelation(AlterTableStmt *stmt, LOCKMODE lockmode)
3096 {
3097 	return RangeVarGetRelidExtended(stmt->relation, lockmode, stmt->missing_ok, false,
3098 									RangeVarCallbackForAlterRelation,
3099 									(void *) stmt);
3100 }
3101 
3102 /*
3103  * AlterTable
3104  *		Execute ALTER TABLE, which can be a list of subcommands
3105  *
3106  * ALTER TABLE is performed in three phases:
3107  *		1. Examine subcommands and perform pre-transformation checking.
3108  *		2. Update system catalogs.
3109  *		3. Scan table(s) to check new constraints, and optionally recopy
3110  *		   the data into new table(s).
3111  * Phase 3 is not performed unless one or more of the subcommands requires
3112  * it.  The intention of this design is to allow multiple independent
3113  * updates of the table schema to be performed with only one pass over the
3114  * data.
3115  *
3116  * ATPrepCmd performs phase 1.  A "work queue" entry is created for
3117  * each table to be affected (there may be multiple affected tables if the
3118  * commands traverse a table inheritance hierarchy).  Also we do preliminary
3119  * validation of the subcommands, including parse transformation of those
3120  * expressions that need to be evaluated with respect to the old table
3121  * schema.
3122  *
3123  * ATRewriteCatalogs performs phase 2 for each affected table.  (Note that
3124  * phases 2 and 3 normally do no explicit recursion, since phase 1 already
3125  * did it --- although some subcommands have to recurse in phase 2 instead.)
3126  * Certain subcommands need to be performed before others to avoid
3127  * unnecessary conflicts; for example, DROP COLUMN should come before
3128  * ADD COLUMN.  Therefore phase 1 divides the subcommands into multiple
3129  * lists, one for each logical "pass" of phase 2.
3130  *
3131  * ATRewriteTables performs phase 3 for those tables that need it.
3132  *
3133  * Thanks to the magic of MVCC, an error anywhere along the way rolls back
3134  * the whole operation; we don't have to do anything special to clean up.
3135  *
3136  * The caller must lock the relation, with an appropriate lock level
3137  * for the subcommands requested, using AlterTableGetLockLevel(stmt->cmds)
3138  * or higher. We pass the lock level down
3139  * so that we can apply it recursively to inherited tables. Note that the
3140  * lock level we want as we recurse might well be higher than required for
3141  * that specific subcommand. So we pass down the overall lock requirement,
3142  * rather than reassess it at lower levels.
3143  */
3144 void
AlterTable(Oid relid,LOCKMODE lockmode,AlterTableStmt * stmt)3145 AlterTable(Oid relid, LOCKMODE lockmode, AlterTableStmt *stmt)
3146 {
3147 	Relation	rel;
3148 
3149 	/* Caller is required to provide an adequate lock. */
3150 	rel = relation_open(relid, NoLock);
3151 
3152 	CheckTableNotInUse(rel, "ALTER TABLE");
3153 
3154 	ATController(stmt, rel, stmt->cmds, stmt->relation->inh, lockmode);
3155 }
3156 
3157 /*
3158  * AlterTableInternal
3159  *
3160  * ALTER TABLE with target specified by OID
3161  *
3162  * We do not reject if the relation is already open, because it's quite
3163  * likely that one or more layers of caller have it open.  That means it
3164  * is unsafe to use this entry point for alterations that could break
3165  * existing query plans.  On the assumption it's not used for such, we
3166  * don't have to reject pending AFTER triggers, either.
3167  */
3168 void
AlterTableInternal(Oid relid,List * cmds,bool recurse)3169 AlterTableInternal(Oid relid, List *cmds, bool recurse)
3170 {
3171 	Relation	rel;
3172 	LOCKMODE	lockmode = AlterTableGetLockLevel(cmds);
3173 
3174 	rel = relation_open(relid, lockmode);
3175 
3176 	EventTriggerAlterTableRelid(relid);
3177 
3178 	ATController(NULL, rel, cmds, recurse, lockmode);
3179 }
3180 
3181 /*
3182  * AlterTableGetLockLevel
3183  *
3184  * Sets the overall lock level required for the supplied list of subcommands.
3185  * Policy for doing this set according to needs of AlterTable(), see
3186  * comments there for overall explanation.
3187  *
3188  * Function is called before and after parsing, so it must give same
3189  * answer each time it is called. Some subcommands are transformed
3190  * into other subcommand types, so the transform must never be made to a
3191  * lower lock level than previously assigned. All transforms are noted below.
3192  *
3193  * Since this is called before we lock the table we cannot use table metadata
3194  * to influence the type of lock we acquire.
3195  *
3196  * There should be no lockmodes hardcoded into the subcommand functions. All
3197  * lockmode decisions for ALTER TABLE are made here only. The one exception is
3198  * ALTER TABLE RENAME which is treated as a different statement type T_RenameStmt
3199  * and does not travel through this section of code and cannot be combined with
3200  * any of the subcommands given here.
3201  *
3202  * Note that Hot Standby only knows about AccessExclusiveLocks on the master
3203  * so any changes that might affect SELECTs running on standbys need to use
3204  * AccessExclusiveLocks even if you think a lesser lock would do, unless you
3205  * have a solution for that also.
3206  *
3207  * Also note that pg_dump uses only an AccessShareLock, meaning that anything
3208  * that takes a lock less than AccessExclusiveLock can change object definitions
3209  * while pg_dump is running. Be careful to check that the appropriate data is
3210  * derived by pg_dump using an MVCC snapshot, rather than syscache lookups,
3211  * otherwise we might end up with an inconsistent dump that can't restore.
3212  */
3213 LOCKMODE
AlterTableGetLockLevel(List * cmds)3214 AlterTableGetLockLevel(List *cmds)
3215 {
3216 	/*
3217 	 * This only works if we read catalog tables using MVCC snapshots.
3218 	 */
3219 	ListCell   *lcmd;
3220 	LOCKMODE	lockmode = ShareUpdateExclusiveLock;
3221 
3222 	foreach(lcmd, cmds)
3223 	{
3224 		AlterTableCmd *cmd = (AlterTableCmd *) lfirst(lcmd);
3225 		LOCKMODE	cmd_lockmode = AccessExclusiveLock; /* default for compiler */
3226 
3227 		switch (cmd->subtype)
3228 		{
3229 				/*
3230 				 * These subcommands rewrite the heap, so require full locks.
3231 				 */
3232 			case AT_AddColumn:	/* may rewrite heap, in some cases and visible
3233 								 * to SELECT */
3234 			case AT_SetTableSpace:	/* must rewrite heap */
3235 			case AT_AlterColumnType:	/* must rewrite heap */
3236 			case AT_AddOids:	/* must rewrite heap */
3237 				cmd_lockmode = AccessExclusiveLock;
3238 				break;
3239 
3240 				/*
3241 				 * These subcommands may require addition of toast tables. If
3242 				 * we add a toast table to a table currently being scanned, we
3243 				 * might miss data added to the new toast table by concurrent
3244 				 * insert transactions.
3245 				 */
3246 			case AT_SetStorage: /* may add toast tables, see
3247 								 * ATRewriteCatalogs() */
3248 				cmd_lockmode = AccessExclusiveLock;
3249 				break;
3250 
3251 				/*
3252 				 * Removing constraints can affect SELECTs that have been
3253 				 * optimised assuming the constraint holds true.
3254 				 */
3255 			case AT_DropConstraint: /* as DROP INDEX */
3256 			case AT_DropNotNull:	/* may change some SQL plans */
3257 				cmd_lockmode = AccessExclusiveLock;
3258 				break;
3259 
3260 				/*
3261 				 * Subcommands that may be visible to concurrent SELECTs
3262 				 */
3263 			case AT_DropColumn: /* change visible to SELECT */
3264 			case AT_AddColumnToView:	/* CREATE VIEW */
3265 			case AT_DropOids:	/* calls AT_DropColumn */
3266 			case AT_EnableAlwaysRule:	/* may change SELECT rules */
3267 			case AT_EnableReplicaRule:	/* may change SELECT rules */
3268 			case AT_EnableRule: /* may change SELECT rules */
3269 			case AT_DisableRule:	/* may change SELECT rules */
3270 				cmd_lockmode = AccessExclusiveLock;
3271 				break;
3272 
3273 				/*
3274 				 * Changing owner may remove implicit SELECT privileges
3275 				 */
3276 			case AT_ChangeOwner:	/* change visible to SELECT */
3277 				cmd_lockmode = AccessExclusiveLock;
3278 				break;
3279 
3280 				/*
3281 				 * Changing foreign table options may affect optimization.
3282 				 */
3283 			case AT_GenericOptions:
3284 			case AT_AlterColumnGenericOptions:
3285 				cmd_lockmode = AccessExclusiveLock;
3286 				break;
3287 
3288 				/*
3289 				 * These subcommands affect write operations only.
3290 				 */
3291 			case AT_EnableTrig:
3292 			case AT_EnableAlwaysTrig:
3293 			case AT_EnableReplicaTrig:
3294 			case AT_EnableTrigAll:
3295 			case AT_EnableTrigUser:
3296 			case AT_DisableTrig:
3297 			case AT_DisableTrigAll:
3298 			case AT_DisableTrigUser:
3299 				cmd_lockmode = ShareRowExclusiveLock;
3300 				break;
3301 
3302 				/*
3303 				 * These subcommands affect write operations only. XXX
3304 				 * Theoretically, these could be ShareRowExclusiveLock.
3305 				 */
3306 			case AT_ColumnDefault:
3307 			case AT_AlterConstraint:
3308 			case AT_AddIndex:	/* from ADD CONSTRAINT */
3309 			case AT_AddIndexConstraint:
3310 			case AT_ReplicaIdentity:
3311 			case AT_SetNotNull:
3312 			case AT_EnableRowSecurity:
3313 			case AT_DisableRowSecurity:
3314 			case AT_ForceRowSecurity:
3315 			case AT_NoForceRowSecurity:
3316 			case AT_AddIdentity:
3317 			case AT_DropIdentity:
3318 			case AT_SetIdentity:
3319 				cmd_lockmode = AccessExclusiveLock;
3320 				break;
3321 
3322 			case AT_AddConstraint:
3323 			case AT_ProcessedConstraint:	/* becomes AT_AddConstraint */
3324 			case AT_AddConstraintRecurse:	/* becomes AT_AddConstraint */
3325 			case AT_ReAddConstraint:	/* becomes AT_AddConstraint */
3326 				if (IsA(cmd->def, Constraint))
3327 				{
3328 					Constraint *con = (Constraint *) cmd->def;
3329 
3330 					switch (con->contype)
3331 					{
3332 						case CONSTR_EXCLUSION:
3333 						case CONSTR_PRIMARY:
3334 						case CONSTR_UNIQUE:
3335 
3336 							/*
3337 							 * Cases essentially the same as CREATE INDEX. We
3338 							 * could reduce the lock strength to ShareLock if
3339 							 * we can work out how to allow concurrent catalog
3340 							 * updates. XXX Might be set down to
3341 							 * ShareRowExclusiveLock but requires further
3342 							 * analysis.
3343 							 */
3344 							cmd_lockmode = AccessExclusiveLock;
3345 							break;
3346 						case CONSTR_FOREIGN:
3347 
3348 							/*
3349 							 * We add triggers to both tables when we add a
3350 							 * Foreign Key, so the lock level must be at least
3351 							 * as strong as CREATE TRIGGER.
3352 							 */
3353 							cmd_lockmode = ShareRowExclusiveLock;
3354 							break;
3355 
3356 						default:
3357 							cmd_lockmode = AccessExclusiveLock;
3358 					}
3359 				}
3360 				break;
3361 
3362 				/*
3363 				 * These subcommands affect inheritance behaviour. Queries
3364 				 * started before us will continue to see the old inheritance
3365 				 * behaviour, while queries started after we commit will see
3366 				 * new behaviour. No need to prevent reads or writes to the
3367 				 * subtable while we hook it up though. Changing the TupDesc
3368 				 * may be a problem, so keep highest lock.
3369 				 */
3370 			case AT_AddInherit:
3371 			case AT_DropInherit:
3372 				cmd_lockmode = AccessExclusiveLock;
3373 				break;
3374 
3375 				/*
3376 				 * These subcommands affect implicit row type conversion. They
3377 				 * have affects similar to CREATE/DROP CAST on queries. don't
3378 				 * provide for invalidating parse trees as a result of such
3379 				 * changes, so we keep these at AccessExclusiveLock.
3380 				 */
3381 			case AT_AddOf:
3382 			case AT_DropOf:
3383 				cmd_lockmode = AccessExclusiveLock;
3384 				break;
3385 
3386 				/*
3387 				 * Only used by CREATE OR REPLACE VIEW which must conflict
3388 				 * with an SELECTs currently using the view.
3389 				 */
3390 			case AT_ReplaceRelOptions:
3391 				cmd_lockmode = AccessExclusiveLock;
3392 				break;
3393 
3394 				/*
3395 				 * These subcommands affect general strategies for performance
3396 				 * and maintenance, though don't change the semantic results
3397 				 * from normal data reads and writes. Delaying an ALTER TABLE
3398 				 * behind currently active writes only delays the point where
3399 				 * the new strategy begins to take effect, so there is no
3400 				 * benefit in waiting. In this case the minimum restriction
3401 				 * applies: we don't currently allow concurrent catalog
3402 				 * updates.
3403 				 */
3404 			case AT_SetStatistics:	/* Uses MVCC in getTableAttrs() */
3405 			case AT_ClusterOn:	/* Uses MVCC in getIndexes() */
3406 			case AT_DropCluster:	/* Uses MVCC in getIndexes() */
3407 			case AT_SetOptions: /* Uses MVCC in getTableAttrs() */
3408 			case AT_ResetOptions:	/* Uses MVCC in getTableAttrs() */
3409 				cmd_lockmode = ShareUpdateExclusiveLock;
3410 				break;
3411 
3412 			case AT_SetLogged:
3413 			case AT_SetUnLogged:
3414 				cmd_lockmode = AccessExclusiveLock;
3415 				break;
3416 
3417 			case AT_ValidateConstraint: /* Uses MVCC in getConstraints() */
3418 				cmd_lockmode = ShareUpdateExclusiveLock;
3419 				break;
3420 
3421 				/*
3422 				 * Rel options are more complex than first appears. Options
3423 				 * are set here for tables, views and indexes; for historical
3424 				 * reasons these can all be used with ALTER TABLE, so we can't
3425 				 * decide between them using the basic grammar.
3426 				 */
3427 			case AT_SetRelOptions:	/* Uses MVCC in getIndexes() and
3428 									 * getTables() */
3429 			case AT_ResetRelOptions:	/* Uses MVCC in getIndexes() and
3430 										 * getTables() */
3431 				cmd_lockmode = AlterTableGetRelOptionsLockLevel((List *) cmd->def);
3432 				break;
3433 
3434 			case AT_AttachPartition:
3435 			case AT_DetachPartition:
3436 				cmd_lockmode = AccessExclusiveLock;
3437 				break;
3438 
3439 			default:			/* oops */
3440 				elog(ERROR, "unrecognized alter table type: %d",
3441 					 (int) cmd->subtype);
3442 				break;
3443 		}
3444 
3445 		/*
3446 		 * Take the greatest lockmode from any subcommand
3447 		 */
3448 		if (cmd_lockmode > lockmode)
3449 			lockmode = cmd_lockmode;
3450 	}
3451 
3452 	return lockmode;
3453 }
3454 
3455 /*
3456  * ATController provides top level control over the phases.
3457  *
3458  * parsetree is passed in to allow it to be passed to event triggers
3459  * when requested.
3460  */
3461 static void
ATController(AlterTableStmt * parsetree,Relation rel,List * cmds,bool recurse,LOCKMODE lockmode)3462 ATController(AlterTableStmt *parsetree,
3463 			 Relation rel, List *cmds, bool recurse, LOCKMODE lockmode)
3464 {
3465 	List	   *wqueue = NIL;
3466 	ListCell   *lcmd;
3467 
3468 	/* Phase 1: preliminary examination of commands, create work queue */
3469 	foreach(lcmd, cmds)
3470 	{
3471 		AlterTableCmd *cmd = (AlterTableCmd *) lfirst(lcmd);
3472 
3473 		ATPrepCmd(&wqueue, rel, cmd, recurse, false, lockmode);
3474 	}
3475 
3476 	/* Close the relation, but keep lock until commit */
3477 	relation_close(rel, NoLock);
3478 
3479 	/* Phase 2: update system catalogs */
3480 	ATRewriteCatalogs(&wqueue, lockmode);
3481 
3482 	/* Phase 3: scan/rewrite tables as needed */
3483 	ATRewriteTables(parsetree, &wqueue, lockmode);
3484 }
3485 
3486 /*
3487  * ATPrepCmd
3488  *
3489  * Traffic cop for ALTER TABLE Phase 1 operations, including simple
3490  * recursion and permission checks.
3491  *
3492  * Caller must have acquired appropriate lock type on relation already.
3493  * This lock should be held until commit.
3494  */
3495 static void
ATPrepCmd(List ** wqueue,Relation rel,AlterTableCmd * cmd,bool recurse,bool recursing,LOCKMODE lockmode)3496 ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd,
3497 		  bool recurse, bool recursing, LOCKMODE lockmode)
3498 {
3499 	AlteredTableInfo *tab;
3500 	int			pass = AT_PASS_UNSET;
3501 
3502 	/* Find or create work queue entry for this table */
3503 	tab = ATGetQueueEntry(wqueue, rel);
3504 
3505 	/*
3506 	 * Copy the original subcommand for each table.  This avoids conflicts
3507 	 * when different child tables need to make different parse
3508 	 * transformations (for example, the same column may have different column
3509 	 * numbers in different children).
3510 	 */
3511 	cmd = copyObject(cmd);
3512 
3513 	/*
3514 	 * Do permissions checking, recursion to child tables if needed, and any
3515 	 * additional phase-1 processing needed.
3516 	 */
3517 	switch (cmd->subtype)
3518 	{
3519 		case AT_AddColumn:		/* ADD COLUMN */
3520 			ATSimplePermissions(rel,
3521 								ATT_TABLE | ATT_COMPOSITE_TYPE | ATT_FOREIGN_TABLE);
3522 			ATPrepAddColumn(wqueue, rel, recurse, recursing, false, cmd,
3523 							lockmode);
3524 			/* Recursion occurs during execution phase */
3525 			pass = AT_PASS_ADD_COL;
3526 			break;
3527 		case AT_AddColumnToView:	/* add column via CREATE OR REPLACE VIEW */
3528 			ATSimplePermissions(rel, ATT_VIEW);
3529 			ATPrepAddColumn(wqueue, rel, recurse, recursing, true, cmd,
3530 							lockmode);
3531 			/* Recursion occurs during execution phase */
3532 			pass = AT_PASS_ADD_COL;
3533 			break;
3534 		case AT_ColumnDefault:	/* ALTER COLUMN DEFAULT */
3535 
3536 			/*
3537 			 * We allow defaults on views so that INSERT into a view can have
3538 			 * default-ish behavior.  This works because the rewriter
3539 			 * substitutes default values into INSERTs before it expands
3540 			 * rules.
3541 			 */
3542 			ATSimplePermissions(rel, ATT_TABLE | ATT_VIEW | ATT_FOREIGN_TABLE);
3543 			ATSimpleRecursion(wqueue, rel, cmd, recurse, lockmode);
3544 			/* No command-specific prep needed */
3545 			pass = cmd->def ? AT_PASS_ADD_CONSTR : AT_PASS_DROP;
3546 			break;
3547 		case AT_AddIdentity:
3548 			ATSimplePermissions(rel, ATT_TABLE | ATT_VIEW | ATT_FOREIGN_TABLE);
3549 			pass = AT_PASS_ADD_CONSTR;
3550 			break;
3551 		case AT_DropIdentity:
3552 			ATSimplePermissions(rel, ATT_TABLE | ATT_VIEW | ATT_FOREIGN_TABLE);
3553 			pass = AT_PASS_DROP;
3554 			break;
3555 		case AT_SetIdentity:
3556 			ATSimplePermissions(rel, ATT_TABLE | ATT_VIEW | ATT_FOREIGN_TABLE);
3557 			pass = AT_PASS_COL_ATTRS;
3558 			break;
3559 		case AT_DropNotNull:	/* ALTER COLUMN DROP NOT NULL */
3560 			ATSimplePermissions(rel, ATT_TABLE | ATT_FOREIGN_TABLE);
3561 			ATPrepDropNotNull(rel, recurse, recursing);
3562 			ATSimpleRecursion(wqueue, rel, cmd, recurse, lockmode);
3563 			/* No command-specific prep needed */
3564 			pass = AT_PASS_DROP;
3565 			break;
3566 		case AT_SetNotNull:		/* ALTER COLUMN SET NOT NULL */
3567 			ATSimplePermissions(rel, ATT_TABLE | ATT_FOREIGN_TABLE);
3568 			ATPrepSetNotNull(rel, recurse, recursing);
3569 			ATSimpleRecursion(wqueue, rel, cmd, recurse, lockmode);
3570 			/* No command-specific prep needed */
3571 			pass = AT_PASS_ADD_CONSTR;
3572 			break;
3573 		case AT_SetStatistics:	/* ALTER COLUMN SET STATISTICS */
3574 			ATSimpleRecursion(wqueue, rel, cmd, recurse, lockmode);
3575 			/* Performs own permission checks */
3576 			ATPrepSetStatistics(rel, cmd->name, cmd->def, lockmode);
3577 			pass = AT_PASS_MISC;
3578 			break;
3579 		case AT_SetOptions:		/* ALTER COLUMN SET ( options ) */
3580 		case AT_ResetOptions:	/* ALTER COLUMN RESET ( options ) */
3581 			ATSimplePermissions(rel, ATT_TABLE | ATT_MATVIEW | ATT_INDEX | ATT_FOREIGN_TABLE);
3582 			/* This command never recurses */
3583 			pass = AT_PASS_MISC;
3584 			break;
3585 		case AT_SetStorage:		/* ALTER COLUMN SET STORAGE */
3586 			ATSimplePermissions(rel, ATT_TABLE | ATT_MATVIEW | ATT_FOREIGN_TABLE);
3587 			ATSimpleRecursion(wqueue, rel, cmd, recurse, lockmode);
3588 			/* No command-specific prep needed */
3589 			pass = AT_PASS_MISC;
3590 			break;
3591 		case AT_DropColumn:		/* DROP COLUMN */
3592 			ATSimplePermissions(rel,
3593 								ATT_TABLE | ATT_COMPOSITE_TYPE | ATT_FOREIGN_TABLE);
3594 			ATPrepDropColumn(wqueue, rel, recurse, recursing, cmd, lockmode);
3595 			/* Recursion occurs during execution phase */
3596 			pass = AT_PASS_DROP;
3597 			break;
3598 		case AT_AddIndex:		/* ADD INDEX */
3599 			ATSimplePermissions(rel, ATT_TABLE);
3600 			/* This command never recurses */
3601 			/* No command-specific prep needed */
3602 			pass = AT_PASS_ADD_INDEX;
3603 			break;
3604 		case AT_AddConstraint:	/* ADD CONSTRAINT */
3605 			ATSimplePermissions(rel, ATT_TABLE | ATT_FOREIGN_TABLE);
3606 			/* Recursion occurs during execution phase */
3607 			/* No command-specific prep needed except saving recurse flag */
3608 			if (recurse)
3609 				cmd->subtype = AT_AddConstraintRecurse;
3610 			pass = AT_PASS_ADD_CONSTR;
3611 			break;
3612 		case AT_AddIndexConstraint: /* ADD CONSTRAINT USING INDEX */
3613 			ATSimplePermissions(rel, ATT_TABLE);
3614 			/* This command never recurses */
3615 			/* No command-specific prep needed */
3616 			pass = AT_PASS_ADD_CONSTR;
3617 			break;
3618 		case AT_DropConstraint: /* DROP CONSTRAINT */
3619 			ATSimplePermissions(rel, ATT_TABLE | ATT_FOREIGN_TABLE);
3620 			/* Recursion occurs during execution phase */
3621 			/* No command-specific prep needed except saving recurse flag */
3622 			if (recurse)
3623 				cmd->subtype = AT_DropConstraintRecurse;
3624 			pass = AT_PASS_DROP;
3625 			break;
3626 		case AT_AlterColumnType:	/* ALTER COLUMN TYPE */
3627 			ATSimplePermissions(rel,
3628 								ATT_TABLE | ATT_COMPOSITE_TYPE | ATT_FOREIGN_TABLE);
3629 			/* Performs own recursion */
3630 			ATPrepAlterColumnType(wqueue, tab, rel, recurse, recursing, cmd, lockmode);
3631 			pass = AT_PASS_ALTER_TYPE;
3632 			break;
3633 		case AT_AlterColumnGenericOptions:
3634 			ATSimplePermissions(rel, ATT_FOREIGN_TABLE);
3635 			/* This command never recurses */
3636 			/* No command-specific prep needed */
3637 			pass = AT_PASS_MISC;
3638 			break;
3639 		case AT_ChangeOwner:	/* ALTER OWNER */
3640 			/* This command never recurses */
3641 			/* No command-specific prep needed */
3642 			pass = AT_PASS_MISC;
3643 			break;
3644 		case AT_ClusterOn:		/* CLUSTER ON */
3645 		case AT_DropCluster:	/* SET WITHOUT CLUSTER */
3646 			ATSimplePermissions(rel, ATT_TABLE | ATT_MATVIEW);
3647 			/* These commands never recurse */
3648 			/* No command-specific prep needed */
3649 			pass = AT_PASS_MISC;
3650 			break;
3651 		case AT_SetLogged:		/* SET LOGGED */
3652 			ATSimplePermissions(rel, ATT_TABLE);
3653 			tab->chgPersistence = ATPrepChangePersistence(rel, true);
3654 			/* force rewrite if necessary; see comment in ATRewriteTables */
3655 			if (tab->chgPersistence)
3656 			{
3657 				tab->rewrite |= AT_REWRITE_ALTER_PERSISTENCE;
3658 				tab->newrelpersistence = RELPERSISTENCE_PERMANENT;
3659 			}
3660 			pass = AT_PASS_MISC;
3661 			break;
3662 		case AT_SetUnLogged:	/* SET UNLOGGED */
3663 			ATSimplePermissions(rel, ATT_TABLE);
3664 			tab->chgPersistence = ATPrepChangePersistence(rel, false);
3665 			/* force rewrite if necessary; see comment in ATRewriteTables */
3666 			if (tab->chgPersistence)
3667 			{
3668 				tab->rewrite |= AT_REWRITE_ALTER_PERSISTENCE;
3669 				tab->newrelpersistence = RELPERSISTENCE_UNLOGGED;
3670 			}
3671 			pass = AT_PASS_MISC;
3672 			break;
3673 		case AT_AddOids:		/* SET WITH OIDS */
3674 			ATSimplePermissions(rel, ATT_TABLE | ATT_FOREIGN_TABLE);
3675 			if (!rel->rd_rel->relhasoids || recursing)
3676 				ATPrepAddOids(wqueue, rel, recurse, cmd, lockmode);
3677 			/* Recursion occurs during execution phase */
3678 			pass = AT_PASS_ADD_COL;
3679 			break;
3680 		case AT_DropOids:		/* SET WITHOUT OIDS */
3681 			ATSimplePermissions(rel, ATT_TABLE | ATT_FOREIGN_TABLE);
3682 			/* Performs own recursion */
3683 			if (rel->rd_rel->relhasoids)
3684 			{
3685 				AlterTableCmd *dropCmd = makeNode(AlterTableCmd);
3686 
3687 				dropCmd->subtype = AT_DropColumn;
3688 				dropCmd->name = pstrdup("oid");
3689 				dropCmd->behavior = cmd->behavior;
3690 				ATPrepCmd(wqueue, rel, dropCmd, recurse, false, lockmode);
3691 			}
3692 			pass = AT_PASS_DROP;
3693 			break;
3694 		case AT_SetTableSpace:	/* SET TABLESPACE */
3695 			ATSimplePermissions(rel, ATT_TABLE | ATT_MATVIEW | ATT_INDEX);
3696 			/* This command never recurses */
3697 			ATPrepSetTableSpace(tab, rel, cmd->name, lockmode);
3698 			pass = AT_PASS_MISC;	/* doesn't actually matter */
3699 			break;
3700 		case AT_SetRelOptions:	/* SET (...) */
3701 		case AT_ResetRelOptions:	/* RESET (...) */
3702 		case AT_ReplaceRelOptions:	/* reset them all, then set just these */
3703 			ATSimplePermissions(rel, ATT_TABLE | ATT_VIEW | ATT_MATVIEW | ATT_INDEX);
3704 			/* This command never recurses */
3705 			/* No command-specific prep needed */
3706 			pass = AT_PASS_MISC;
3707 			break;
3708 		case AT_AddInherit:		/* INHERIT */
3709 			ATSimplePermissions(rel, ATT_TABLE | ATT_FOREIGN_TABLE);
3710 			/* This command never recurses */
3711 			ATPrepAddInherit(rel);
3712 			pass = AT_PASS_MISC;
3713 			break;
3714 		case AT_DropInherit:	/* NO INHERIT */
3715 			ATSimplePermissions(rel, ATT_TABLE | ATT_FOREIGN_TABLE);
3716 			/* This command never recurses */
3717 			/* No command-specific prep needed */
3718 			pass = AT_PASS_MISC;
3719 			break;
3720 		case AT_AlterConstraint:	/* ALTER CONSTRAINT */
3721 			ATSimplePermissions(rel, ATT_TABLE);
3722 			pass = AT_PASS_MISC;
3723 			break;
3724 		case AT_ValidateConstraint: /* VALIDATE CONSTRAINT */
3725 			ATSimplePermissions(rel, ATT_TABLE | ATT_FOREIGN_TABLE);
3726 			/* Recursion occurs during execution phase */
3727 			/* No command-specific prep needed except saving recurse flag */
3728 			if (recurse)
3729 				cmd->subtype = AT_ValidateConstraintRecurse;
3730 			pass = AT_PASS_MISC;
3731 			break;
3732 		case AT_ReplicaIdentity:	/* REPLICA IDENTITY ... */
3733 			ATSimplePermissions(rel, ATT_TABLE | ATT_MATVIEW);
3734 			pass = AT_PASS_MISC;
3735 			/* This command never recurses */
3736 			/* No command-specific prep needed */
3737 			break;
3738 		case AT_EnableTrig:		/* ENABLE TRIGGER variants */
3739 		case AT_EnableAlwaysTrig:
3740 		case AT_EnableReplicaTrig:
3741 		case AT_EnableTrigAll:
3742 		case AT_EnableTrigUser:
3743 		case AT_DisableTrig:	/* DISABLE TRIGGER variants */
3744 		case AT_DisableTrigAll:
3745 		case AT_DisableTrigUser:
3746 			ATSimplePermissions(rel, ATT_TABLE | ATT_FOREIGN_TABLE);
3747 			pass = AT_PASS_MISC;
3748 			break;
3749 		case AT_EnableRule:		/* ENABLE/DISABLE RULE variants */
3750 		case AT_EnableAlwaysRule:
3751 		case AT_EnableReplicaRule:
3752 		case AT_DisableRule:
3753 		case AT_AddOf:			/* OF */
3754 		case AT_DropOf:			/* NOT OF */
3755 		case AT_EnableRowSecurity:
3756 		case AT_DisableRowSecurity:
3757 		case AT_ForceRowSecurity:
3758 		case AT_NoForceRowSecurity:
3759 			ATSimplePermissions(rel, ATT_TABLE);
3760 			/* These commands never recurse */
3761 			/* No command-specific prep needed */
3762 			pass = AT_PASS_MISC;
3763 			break;
3764 		case AT_GenericOptions:
3765 			ATSimplePermissions(rel, ATT_FOREIGN_TABLE);
3766 			/* No command-specific prep needed */
3767 			pass = AT_PASS_MISC;
3768 			break;
3769 		case AT_AttachPartition:
3770 		case AT_DetachPartition:
3771 			ATSimplePermissions(rel, ATT_TABLE);
3772 			/* No command-specific prep needed */
3773 			pass = AT_PASS_MISC;
3774 			break;
3775 		default:				/* oops */
3776 			elog(ERROR, "unrecognized alter table type: %d",
3777 				 (int) cmd->subtype);
3778 			pass = AT_PASS_UNSET;	/* keep compiler quiet */
3779 			break;
3780 	}
3781 	Assert(pass > AT_PASS_UNSET);
3782 
3783 	/* Add the subcommand to the appropriate list for phase 2 */
3784 	tab->subcmds[pass] = lappend(tab->subcmds[pass], cmd);
3785 }
3786 
3787 /*
3788  * ATRewriteCatalogs
3789  *
3790  * Traffic cop for ALTER TABLE Phase 2 operations.  Subcommands are
3791  * dispatched in a "safe" execution order (designed to avoid unnecessary
3792  * conflicts).
3793  */
3794 static void
ATRewriteCatalogs(List ** wqueue,LOCKMODE lockmode)3795 ATRewriteCatalogs(List **wqueue, LOCKMODE lockmode)
3796 {
3797 	int			pass;
3798 	ListCell   *ltab;
3799 
3800 	/*
3801 	 * We process all the tables "in parallel", one pass at a time.  This is
3802 	 * needed because we may have to propagate work from one table to another
3803 	 * (specifically, ALTER TYPE on a foreign key's PK has to dispatch the
3804 	 * re-adding of the foreign key constraint to the other table).  Work can
3805 	 * only be propagated into later passes, however.
3806 	 */
3807 	for (pass = 0; pass < AT_NUM_PASSES; pass++)
3808 	{
3809 		/* Go through each table that needs to be processed */
3810 		foreach(ltab, *wqueue)
3811 		{
3812 			AlteredTableInfo *tab = (AlteredTableInfo *) lfirst(ltab);
3813 			List	   *subcmds = tab->subcmds[pass];
3814 			Relation	rel;
3815 			ListCell   *lcmd;
3816 
3817 			if (subcmds == NIL)
3818 				continue;
3819 
3820 			/*
3821 			 * Appropriate lock was obtained by phase 1, needn't get it again
3822 			 */
3823 			rel = relation_open(tab->relid, NoLock);
3824 
3825 			foreach(lcmd, subcmds)
3826 				ATExecCmd(wqueue, tab, rel, (AlterTableCmd *) lfirst(lcmd), lockmode);
3827 
3828 			/*
3829 			 * After the ALTER TYPE pass, do cleanup work (this is not done in
3830 			 * ATExecAlterColumnType since it should be done only once if
3831 			 * multiple columns of a table are altered).
3832 			 */
3833 			if (pass == AT_PASS_ALTER_TYPE)
3834 				ATPostAlterTypeCleanup(wqueue, tab, lockmode);
3835 
3836 			relation_close(rel, NoLock);
3837 		}
3838 	}
3839 
3840 	/* Check to see if a toast table must be added. */
3841 	foreach(ltab, *wqueue)
3842 	{
3843 		AlteredTableInfo *tab = (AlteredTableInfo *) lfirst(ltab);
3844 
3845 		/*
3846 		 * If the table is source table of ATTACH PARTITION command, we did
3847 		 * not modify anything about it that will change its toasting
3848 		 * requirement, so no need to check.
3849 		 */
3850 		if (((tab->relkind == RELKIND_RELATION ||
3851 			  tab->relkind == RELKIND_PARTITIONED_TABLE) &&
3852 			 tab->partition_constraint == NULL) ||
3853 			tab->relkind == RELKIND_MATVIEW)
3854 			AlterTableCreateToastTable(tab->relid, (Datum) 0, lockmode);
3855 	}
3856 }
3857 
3858 /*
3859  * ATExecCmd: dispatch a subcommand to appropriate execution routine
3860  */
3861 static void
ATExecCmd(List ** wqueue,AlteredTableInfo * tab,Relation rel,AlterTableCmd * cmd,LOCKMODE lockmode)3862 ATExecCmd(List **wqueue, AlteredTableInfo *tab, Relation rel,
3863 		  AlterTableCmd *cmd, LOCKMODE lockmode)
3864 {
3865 	ObjectAddress address = InvalidObjectAddress;
3866 
3867 	switch (cmd->subtype)
3868 	{
3869 		case AT_AddColumn:		/* ADD COLUMN */
3870 		case AT_AddColumnToView:	/* add column via CREATE OR REPLACE VIEW */
3871 			address = ATExecAddColumn(wqueue, tab, rel, (ColumnDef *) cmd->def,
3872 									  false, false, false,
3873 									  cmd->missing_ok, lockmode);
3874 			break;
3875 		case AT_AddColumnRecurse:
3876 			address = ATExecAddColumn(wqueue, tab, rel, (ColumnDef *) cmd->def,
3877 									  false, true, false,
3878 									  cmd->missing_ok, lockmode);
3879 			break;
3880 		case AT_ColumnDefault:	/* ALTER COLUMN DEFAULT */
3881 			address = ATExecColumnDefault(rel, cmd->name, cmd->def, lockmode);
3882 			break;
3883 		case AT_AddIdentity:
3884 			address = ATExecAddIdentity(rel, cmd->name, cmd->def, lockmode);
3885 			break;
3886 		case AT_SetIdentity:
3887 			address = ATExecSetIdentity(rel, cmd->name, cmd->def, lockmode);
3888 			break;
3889 		case AT_DropIdentity:
3890 			address = ATExecDropIdentity(rel, cmd->name, cmd->missing_ok, lockmode);
3891 			break;
3892 		case AT_DropNotNull:	/* ALTER COLUMN DROP NOT NULL */
3893 			address = ATExecDropNotNull(rel, cmd->name, lockmode);
3894 			break;
3895 		case AT_SetNotNull:		/* ALTER COLUMN SET NOT NULL */
3896 			address = ATExecSetNotNull(tab, rel, cmd->name, lockmode);
3897 			break;
3898 		case AT_SetStatistics:	/* ALTER COLUMN SET STATISTICS */
3899 			address = ATExecSetStatistics(rel, cmd->name, cmd->def, lockmode);
3900 			break;
3901 		case AT_SetOptions:		/* ALTER COLUMN SET ( options ) */
3902 			address = ATExecSetOptions(rel, cmd->name, cmd->def, false, lockmode);
3903 			break;
3904 		case AT_ResetOptions:	/* ALTER COLUMN RESET ( options ) */
3905 			address = ATExecSetOptions(rel, cmd->name, cmd->def, true, lockmode);
3906 			break;
3907 		case AT_SetStorage:		/* ALTER COLUMN SET STORAGE */
3908 			address = ATExecSetStorage(rel, cmd->name, cmd->def, lockmode);
3909 			break;
3910 		case AT_DropColumn:		/* DROP COLUMN */
3911 			address = ATExecDropColumn(wqueue, rel, cmd->name,
3912 									   cmd->behavior, false, false,
3913 									   cmd->missing_ok, lockmode);
3914 			break;
3915 		case AT_DropColumnRecurse:	/* DROP COLUMN with recursion */
3916 			address = ATExecDropColumn(wqueue, rel, cmd->name,
3917 									   cmd->behavior, true, false,
3918 									   cmd->missing_ok, lockmode);
3919 			break;
3920 		case AT_AddIndex:		/* ADD INDEX */
3921 			address = ATExecAddIndex(tab, rel, (IndexStmt *) cmd->def, false,
3922 									 lockmode);
3923 			break;
3924 		case AT_ReAddIndex:		/* ADD INDEX */
3925 			address = ATExecAddIndex(tab, rel, (IndexStmt *) cmd->def, true,
3926 									 lockmode);
3927 			break;
3928 		case AT_AddConstraint:	/* ADD CONSTRAINT */
3929 			address =
3930 				ATExecAddConstraint(wqueue, tab, rel, (Constraint *) cmd->def,
3931 									false, false, lockmode);
3932 			break;
3933 		case AT_AddConstraintRecurse:	/* ADD CONSTRAINT with recursion */
3934 			address =
3935 				ATExecAddConstraint(wqueue, tab, rel, (Constraint *) cmd->def,
3936 									true, false, lockmode);
3937 			break;
3938 		case AT_ReAddConstraint:	/* Re-add pre-existing check constraint */
3939 			address =
3940 				ATExecAddConstraint(wqueue, tab, rel, (Constraint *) cmd->def,
3941 									true, true, lockmode);
3942 			break;
3943 		case AT_ReAddComment:	/* Re-add existing comment */
3944 			address = CommentObject((CommentStmt *) cmd->def);
3945 			break;
3946 		case AT_AddIndexConstraint: /* ADD CONSTRAINT USING INDEX */
3947 			address = ATExecAddIndexConstraint(tab, rel, (IndexStmt *) cmd->def,
3948 											   lockmode);
3949 			break;
3950 		case AT_AlterConstraint:	/* ALTER CONSTRAINT */
3951 			address = ATExecAlterConstraint(rel, cmd, false, false, lockmode);
3952 			break;
3953 		case AT_ValidateConstraint: /* VALIDATE CONSTRAINT */
3954 			address = ATExecValidateConstraint(wqueue, rel, cmd->name, false,
3955 											   false, lockmode);
3956 			break;
3957 		case AT_ValidateConstraintRecurse:	/* VALIDATE CONSTRAINT with
3958 											 * recursion */
3959 			address = ATExecValidateConstraint(wqueue, rel, cmd->name, true,
3960 											   false, lockmode);
3961 			break;
3962 		case AT_DropConstraint: /* DROP CONSTRAINT */
3963 			ATExecDropConstraint(rel, cmd->name, cmd->behavior,
3964 								 false, false,
3965 								 cmd->missing_ok, lockmode);
3966 			break;
3967 		case AT_DropConstraintRecurse:	/* DROP CONSTRAINT with recursion */
3968 			ATExecDropConstraint(rel, cmd->name, cmd->behavior,
3969 								 true, false,
3970 								 cmd->missing_ok, lockmode);
3971 			break;
3972 		case AT_AlterColumnType:	/* ALTER COLUMN TYPE */
3973 			address = ATExecAlterColumnType(tab, rel, cmd, lockmode);
3974 			break;
3975 		case AT_AlterColumnGenericOptions:	/* ALTER COLUMN OPTIONS */
3976 			address =
3977 				ATExecAlterColumnGenericOptions(rel, cmd->name,
3978 												(List *) cmd->def, lockmode);
3979 			break;
3980 		case AT_ChangeOwner:	/* ALTER OWNER */
3981 			ATExecChangeOwner(RelationGetRelid(rel),
3982 							  get_rolespec_oid(cmd->newowner, false),
3983 							  false, lockmode);
3984 			break;
3985 		case AT_ClusterOn:		/* CLUSTER ON */
3986 			address = ATExecClusterOn(rel, cmd->name, lockmode);
3987 			break;
3988 		case AT_DropCluster:	/* SET WITHOUT CLUSTER */
3989 			ATExecDropCluster(rel, lockmode);
3990 			break;
3991 		case AT_SetLogged:		/* SET LOGGED */
3992 		case AT_SetUnLogged:	/* SET UNLOGGED */
3993 			break;
3994 		case AT_AddOids:		/* SET WITH OIDS */
3995 			/* Use the ADD COLUMN code, unless prep decided to do nothing */
3996 			if (cmd->def != NULL)
3997 				address =
3998 					ATExecAddColumn(wqueue, tab, rel, (ColumnDef *) cmd->def,
3999 									true, false, false,
4000 									cmd->missing_ok, lockmode);
4001 			break;
4002 		case AT_AddOidsRecurse: /* SET WITH OIDS */
4003 			/* Use the ADD COLUMN code, unless prep decided to do nothing */
4004 			if (cmd->def != NULL)
4005 				address =
4006 					ATExecAddColumn(wqueue, tab, rel, (ColumnDef *) cmd->def,
4007 									true, true, false,
4008 									cmd->missing_ok, lockmode);
4009 			break;
4010 		case AT_DropOids:		/* SET WITHOUT OIDS */
4011 
4012 			/*
4013 			 * Nothing to do here; we'll have generated a DropColumn
4014 			 * subcommand to do the real work
4015 			 */
4016 			break;
4017 		case AT_SetTableSpace:	/* SET TABLESPACE */
4018 
4019 			/*
4020 			 * Nothing to do here; Phase 3 does the work
4021 			 */
4022 			break;
4023 		case AT_SetRelOptions:	/* SET (...) */
4024 		case AT_ResetRelOptions:	/* RESET (...) */
4025 		case AT_ReplaceRelOptions:	/* replace entire option list */
4026 			ATExecSetRelOptions(rel, (List *) cmd->def, cmd->subtype, lockmode);
4027 			break;
4028 		case AT_EnableTrig:		/* ENABLE TRIGGER name */
4029 			ATExecEnableDisableTrigger(rel, cmd->name,
4030 									   TRIGGER_FIRES_ON_ORIGIN, false, lockmode);
4031 			break;
4032 		case AT_EnableAlwaysTrig:	/* ENABLE ALWAYS TRIGGER name */
4033 			ATExecEnableDisableTrigger(rel, cmd->name,
4034 									   TRIGGER_FIRES_ALWAYS, false, lockmode);
4035 			break;
4036 		case AT_EnableReplicaTrig:	/* ENABLE REPLICA TRIGGER name */
4037 			ATExecEnableDisableTrigger(rel, cmd->name,
4038 									   TRIGGER_FIRES_ON_REPLICA, false, lockmode);
4039 			break;
4040 		case AT_DisableTrig:	/* DISABLE TRIGGER name */
4041 			ATExecEnableDisableTrigger(rel, cmd->name,
4042 									   TRIGGER_DISABLED, false, lockmode);
4043 			break;
4044 		case AT_EnableTrigAll:	/* ENABLE TRIGGER ALL */
4045 			ATExecEnableDisableTrigger(rel, NULL,
4046 									   TRIGGER_FIRES_ON_ORIGIN, false, lockmode);
4047 			break;
4048 		case AT_DisableTrigAll: /* DISABLE TRIGGER ALL */
4049 			ATExecEnableDisableTrigger(rel, NULL,
4050 									   TRIGGER_DISABLED, false, lockmode);
4051 			break;
4052 		case AT_EnableTrigUser: /* ENABLE TRIGGER USER */
4053 			ATExecEnableDisableTrigger(rel, NULL,
4054 									   TRIGGER_FIRES_ON_ORIGIN, true, lockmode);
4055 			break;
4056 		case AT_DisableTrigUser:	/* DISABLE TRIGGER USER */
4057 			ATExecEnableDisableTrigger(rel, NULL,
4058 									   TRIGGER_DISABLED, true, lockmode);
4059 			break;
4060 
4061 		case AT_EnableRule:		/* ENABLE RULE name */
4062 			ATExecEnableDisableRule(rel, cmd->name,
4063 									RULE_FIRES_ON_ORIGIN, lockmode);
4064 			break;
4065 		case AT_EnableAlwaysRule:	/* ENABLE ALWAYS RULE name */
4066 			ATExecEnableDisableRule(rel, cmd->name,
4067 									RULE_FIRES_ALWAYS, lockmode);
4068 			break;
4069 		case AT_EnableReplicaRule:	/* ENABLE REPLICA RULE name */
4070 			ATExecEnableDisableRule(rel, cmd->name,
4071 									RULE_FIRES_ON_REPLICA, lockmode);
4072 			break;
4073 		case AT_DisableRule:	/* DISABLE RULE name */
4074 			ATExecEnableDisableRule(rel, cmd->name,
4075 									RULE_DISABLED, lockmode);
4076 			break;
4077 
4078 		case AT_AddInherit:
4079 			address = ATExecAddInherit(rel, (RangeVar *) cmd->def, lockmode);
4080 			break;
4081 		case AT_DropInherit:
4082 			address = ATExecDropInherit(rel, (RangeVar *) cmd->def, lockmode);
4083 			break;
4084 		case AT_AddOf:
4085 			address = ATExecAddOf(rel, (TypeName *) cmd->def, lockmode);
4086 			break;
4087 		case AT_DropOf:
4088 			ATExecDropOf(rel, lockmode);
4089 			break;
4090 		case AT_ReplicaIdentity:
4091 			ATExecReplicaIdentity(rel, (ReplicaIdentityStmt *) cmd->def, lockmode);
4092 			break;
4093 		case AT_EnableRowSecurity:
4094 			ATExecEnableRowSecurity(rel);
4095 			break;
4096 		case AT_DisableRowSecurity:
4097 			ATExecDisableRowSecurity(rel);
4098 			break;
4099 		case AT_ForceRowSecurity:
4100 			ATExecForceNoForceRowSecurity(rel, true);
4101 			break;
4102 		case AT_NoForceRowSecurity:
4103 			ATExecForceNoForceRowSecurity(rel, false);
4104 			break;
4105 		case AT_GenericOptions:
4106 			ATExecGenericOptions(rel, (List *) cmd->def);
4107 			break;
4108 		case AT_AttachPartition:
4109 			ATExecAttachPartition(wqueue, rel, (PartitionCmd *) cmd->def);
4110 			break;
4111 		case AT_DetachPartition:
4112 			ATExecDetachPartition(rel, ((PartitionCmd *) cmd->def)->name);
4113 			break;
4114 		default:				/* oops */
4115 			elog(ERROR, "unrecognized alter table type: %d",
4116 				 (int) cmd->subtype);
4117 			break;
4118 	}
4119 
4120 	/*
4121 	 * Report the subcommand to interested event triggers.
4122 	 */
4123 	EventTriggerCollectAlterTableSubcmd((Node *) cmd, address);
4124 
4125 	/*
4126 	 * Bump the command counter to ensure the next subcommand in the sequence
4127 	 * can see the changes so far
4128 	 */
4129 	CommandCounterIncrement();
4130 }
4131 
4132 /*
4133  * ATRewriteTables: ALTER TABLE phase 3
4134  */
4135 static void
ATRewriteTables(AlterTableStmt * parsetree,List ** wqueue,LOCKMODE lockmode)4136 ATRewriteTables(AlterTableStmt *parsetree, List **wqueue, LOCKMODE lockmode)
4137 {
4138 	ListCell   *ltab;
4139 
4140 	/* Go through each table that needs to be checked or rewritten */
4141 	foreach(ltab, *wqueue)
4142 	{
4143 		AlteredTableInfo *tab = (AlteredTableInfo *) lfirst(ltab);
4144 
4145 		/* Foreign tables have no storage, nor do partitioned tables. */
4146 		if (tab->relkind == RELKIND_FOREIGN_TABLE ||
4147 			tab->relkind == RELKIND_PARTITIONED_TABLE)
4148 			continue;
4149 
4150 		/*
4151 		 * If we change column data types or add/remove OIDs, the operation
4152 		 * has to be propagated to tables that use this table's rowtype as a
4153 		 * column type.  tab->newvals will also be non-NULL in the case where
4154 		 * we're adding a column with a default.  We choose to forbid that
4155 		 * case as well, since composite types might eventually support
4156 		 * defaults.
4157 		 *
4158 		 * (Eventually we'll probably need to check for composite type
4159 		 * dependencies even when we're just scanning the table without a
4160 		 * rewrite, but at the moment a composite type does not enforce any
4161 		 * constraints, so it's not necessary/appropriate to enforce them just
4162 		 * during ALTER.)
4163 		 */
4164 		if (tab->newvals != NIL || tab->rewrite > 0)
4165 		{
4166 			Relation	rel;
4167 
4168 			rel = heap_open(tab->relid, NoLock);
4169 			find_composite_type_dependencies(rel->rd_rel->reltype, rel, NULL);
4170 			heap_close(rel, NoLock);
4171 		}
4172 
4173 		/*
4174 		 * We only need to rewrite the table if at least one column needs to
4175 		 * be recomputed, we are adding/removing the OID column, or we are
4176 		 * changing its persistence.
4177 		 *
4178 		 * There are two reasons for requiring a rewrite when changing
4179 		 * persistence: on one hand, we need to ensure that the buffers
4180 		 * belonging to each of the two relations are marked with or without
4181 		 * BM_PERMANENT properly.  On the other hand, since rewriting creates
4182 		 * and assigns a new relfilenode, we automatically create or drop an
4183 		 * init fork for the relation as appropriate.
4184 		 */
4185 		if (tab->rewrite > 0)
4186 		{
4187 			/* Build a temporary relation and copy data */
4188 			Relation	OldHeap;
4189 			Oid			OIDNewHeap;
4190 			Oid			NewTableSpace;
4191 			char		persistence;
4192 
4193 			OldHeap = heap_open(tab->relid, NoLock);
4194 
4195 			/*
4196 			 * We don't support rewriting of system catalogs; there are too
4197 			 * many corner cases and too little benefit.  In particular this
4198 			 * is certainly not going to work for mapped catalogs.
4199 			 */
4200 			if (IsSystemRelation(OldHeap))
4201 				ereport(ERROR,
4202 						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
4203 						 errmsg("cannot rewrite system relation \"%s\"",
4204 								RelationGetRelationName(OldHeap))));
4205 
4206 			if (RelationIsUsedAsCatalogTable(OldHeap))
4207 				ereport(ERROR,
4208 						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
4209 						 errmsg("cannot rewrite table \"%s\" used as a catalog table",
4210 								RelationGetRelationName(OldHeap))));
4211 
4212 			/*
4213 			 * Don't allow rewrite on temp tables of other backends ... their
4214 			 * local buffer manager is not going to cope.
4215 			 */
4216 			if (RELATION_IS_OTHER_TEMP(OldHeap))
4217 				ereport(ERROR,
4218 						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
4219 						 errmsg("cannot rewrite temporary tables of other sessions")));
4220 
4221 			/*
4222 			 * Select destination tablespace (same as original unless user
4223 			 * requested a change)
4224 			 */
4225 			if (tab->newTableSpace)
4226 				NewTableSpace = tab->newTableSpace;
4227 			else
4228 				NewTableSpace = OldHeap->rd_rel->reltablespace;
4229 
4230 			/*
4231 			 * Select persistence of transient table (same as original unless
4232 			 * user requested a change)
4233 			 */
4234 			persistence = tab->chgPersistence ?
4235 				tab->newrelpersistence : OldHeap->rd_rel->relpersistence;
4236 
4237 			heap_close(OldHeap, NoLock);
4238 
4239 			/*
4240 			 * Fire off an Event Trigger now, before actually rewriting the
4241 			 * table.
4242 			 *
4243 			 * We don't support Event Trigger for nested commands anywhere,
4244 			 * here included, and parsetree is given NULL when coming from
4245 			 * AlterTableInternal.
4246 			 *
4247 			 * And fire it only once.
4248 			 */
4249 			if (parsetree)
4250 				EventTriggerTableRewrite((Node *) parsetree,
4251 										 tab->relid,
4252 										 tab->rewrite);
4253 
4254 			/*
4255 			 * Create transient table that will receive the modified data.
4256 			 *
4257 			 * Ensure it is marked correctly as logged or unlogged.  We have
4258 			 * to do this here so that buffers for the new relfilenode will
4259 			 * have the right persistence set, and at the same time ensure
4260 			 * that the original filenode's buffers will get read in with the
4261 			 * correct setting (i.e. the original one).  Otherwise a rollback
4262 			 * after the rewrite would possibly result with buffers for the
4263 			 * original filenode having the wrong persistence setting.
4264 			 *
4265 			 * NB: This relies on swap_relation_files() also swapping the
4266 			 * persistence. That wouldn't work for pg_class, but that can't be
4267 			 * unlogged anyway.
4268 			 */
4269 			OIDNewHeap = make_new_heap(tab->relid, NewTableSpace, persistence,
4270 									   lockmode);
4271 
4272 			/*
4273 			 * Copy the heap data into the new table with the desired
4274 			 * modifications, and test the current data within the table
4275 			 * against new constraints generated by ALTER TABLE commands.
4276 			 */
4277 			ATRewriteTable(tab, OIDNewHeap, lockmode);
4278 
4279 			/*
4280 			 * Swap the physical files of the old and new heaps, then rebuild
4281 			 * indexes and discard the old heap.  We can use RecentXmin for
4282 			 * the table's new relfrozenxid because we rewrote all the tuples
4283 			 * in ATRewriteTable, so no older Xid remains in the table.  Also,
4284 			 * we never try to swap toast tables by content, since we have no
4285 			 * interest in letting this code work on system catalogs.
4286 			 */
4287 			finish_heap_swap(tab->relid, OIDNewHeap,
4288 							 false, false, true,
4289 							 !OidIsValid(tab->newTableSpace),
4290 							 RecentXmin,
4291 							 ReadNextMultiXactId(),
4292 							 persistence);
4293 		}
4294 		else
4295 		{
4296 			/*
4297 			 * Test the current data within the table against new constraints
4298 			 * generated by ALTER TABLE commands, but don't rebuild data.
4299 			 */
4300 			if (tab->constraints != NIL || tab->new_notnull ||
4301 				tab->partition_constraint != NULL)
4302 				ATRewriteTable(tab, InvalidOid, lockmode);
4303 
4304 			/*
4305 			 * If we had SET TABLESPACE but no reason to reconstruct tuples,
4306 			 * just do a block-by-block copy.
4307 			 */
4308 			if (tab->newTableSpace)
4309 				ATExecSetTableSpace(tab->relid, tab->newTableSpace, lockmode);
4310 		}
4311 	}
4312 
4313 	/*
4314 	 * Foreign key constraints are checked in a final pass, since (a) it's
4315 	 * generally best to examine each one separately, and (b) it's at least
4316 	 * theoretically possible that we have changed both relations of the
4317 	 * foreign key, and we'd better have finished both rewrites before we try
4318 	 * to read the tables.
4319 	 */
4320 	foreach(ltab, *wqueue)
4321 	{
4322 		AlteredTableInfo *tab = (AlteredTableInfo *) lfirst(ltab);
4323 		Relation	rel = NULL;
4324 		ListCell   *lcon;
4325 
4326 		foreach(lcon, tab->constraints)
4327 		{
4328 			NewConstraint *con = lfirst(lcon);
4329 
4330 			if (con->contype == CONSTR_FOREIGN)
4331 			{
4332 				Constraint *fkconstraint = (Constraint *) con->qual;
4333 				Relation	refrel;
4334 
4335 				if (rel == NULL)
4336 				{
4337 					/* Long since locked, no need for another */
4338 					rel = heap_open(tab->relid, NoLock);
4339 				}
4340 
4341 				refrel = heap_open(con->refrelid, RowShareLock);
4342 
4343 				validateForeignKeyConstraint(fkconstraint->conname, rel, refrel,
4344 											 con->refindid,
4345 											 con->conid);
4346 
4347 				/*
4348 				 * No need to mark the constraint row as validated, we did
4349 				 * that when we inserted the row earlier.
4350 				 */
4351 
4352 				heap_close(refrel, NoLock);
4353 			}
4354 		}
4355 
4356 		if (rel)
4357 			heap_close(rel, NoLock);
4358 	}
4359 }
4360 
4361 /*
4362  * ATRewriteTable: scan or rewrite one table
4363  *
4364  * OIDNewHeap is InvalidOid if we don't need to rewrite
4365  */
4366 static void
ATRewriteTable(AlteredTableInfo * tab,Oid OIDNewHeap,LOCKMODE lockmode)4367 ATRewriteTable(AlteredTableInfo *tab, Oid OIDNewHeap, LOCKMODE lockmode)
4368 {
4369 	Relation	oldrel;
4370 	Relation	newrel;
4371 	TupleDesc	oldTupDesc;
4372 	TupleDesc	newTupDesc;
4373 	bool		needscan = false;
4374 	List	   *notnull_attrs;
4375 	int			i;
4376 	ListCell   *l;
4377 	EState	   *estate;
4378 	CommandId	mycid;
4379 	BulkInsertState bistate;
4380 	int			hi_options;
4381 	ExprState  *partqualstate = NULL;
4382 
4383 	/*
4384 	 * Open the relation(s).  We have surely already locked the existing
4385 	 * table.
4386 	 */
4387 	oldrel = heap_open(tab->relid, NoLock);
4388 	oldTupDesc = tab->oldDesc;
4389 	newTupDesc = RelationGetDescr(oldrel);	/* includes all mods */
4390 
4391 	if (OidIsValid(OIDNewHeap))
4392 		newrel = heap_open(OIDNewHeap, lockmode);
4393 	else
4394 		newrel = NULL;
4395 
4396 	/*
4397 	 * Prepare a BulkInsertState and options for heap_insert. Because we're
4398 	 * building a new heap, we can skip WAL-logging and fsync it to disk at
4399 	 * the end instead (unless WAL-logging is required for archiving or
4400 	 * streaming replication). The FSM is empty too, so don't bother using it.
4401 	 */
4402 	if (newrel)
4403 	{
4404 		mycid = GetCurrentCommandId(true);
4405 		bistate = GetBulkInsertState();
4406 
4407 		hi_options = HEAP_INSERT_SKIP_FSM;
4408 		if (!XLogIsNeeded())
4409 			hi_options |= HEAP_INSERT_SKIP_WAL;
4410 	}
4411 	else
4412 	{
4413 		/* keep compiler quiet about using these uninitialized */
4414 		mycid = 0;
4415 		bistate = NULL;
4416 		hi_options = 0;
4417 	}
4418 
4419 	/*
4420 	 * Generate the constraint and default execution states
4421 	 */
4422 
4423 	estate = CreateExecutorState();
4424 
4425 	/* Build the needed expression execution states */
4426 	foreach(l, tab->constraints)
4427 	{
4428 		NewConstraint *con = lfirst(l);
4429 
4430 		switch (con->contype)
4431 		{
4432 			case CONSTR_CHECK:
4433 				needscan = true;
4434 				con->qualstate = ExecPrepareExpr((Expr *) con->qual, estate);
4435 				break;
4436 			case CONSTR_FOREIGN:
4437 				/* Nothing to do here */
4438 				break;
4439 			default:
4440 				elog(ERROR, "unrecognized constraint type: %d",
4441 					 (int) con->contype);
4442 		}
4443 	}
4444 
4445 	/* Build expression execution states for partition check quals */
4446 	if (tab->partition_constraint)
4447 	{
4448 		needscan = true;
4449 		partqualstate = ExecPrepareExpr(tab->partition_constraint, estate);
4450 	}
4451 
4452 	foreach(l, tab->newvals)
4453 	{
4454 		NewColumnValue *ex = lfirst(l);
4455 
4456 		/* expr already planned */
4457 		ex->exprstate = ExecInitExpr((Expr *) ex->expr, NULL);
4458 	}
4459 
4460 	notnull_attrs = NIL;
4461 	if (newrel || tab->new_notnull)
4462 	{
4463 		/*
4464 		 * If we are rebuilding the tuples OR if we added any new NOT NULL
4465 		 * constraints, check all not-null constraints.  This is a bit of
4466 		 * overkill but it minimizes risk of bugs, and heap_attisnull is a
4467 		 * pretty cheap test anyway.
4468 		 */
4469 		for (i = 0; i < newTupDesc->natts; i++)
4470 		{
4471 			if (newTupDesc->attrs[i]->attnotnull &&
4472 				!newTupDesc->attrs[i]->attisdropped)
4473 				notnull_attrs = lappend_int(notnull_attrs, i);
4474 		}
4475 		if (notnull_attrs)
4476 			needscan = true;
4477 	}
4478 
4479 	if (newrel || needscan)
4480 	{
4481 		ExprContext *econtext;
4482 		Datum	   *values;
4483 		bool	   *isnull;
4484 		TupleTableSlot *oldslot;
4485 		TupleTableSlot *newslot;
4486 		HeapScanDesc scan;
4487 		HeapTuple	tuple;
4488 		MemoryContext oldCxt;
4489 		List	   *dropped_attrs = NIL;
4490 		ListCell   *lc;
4491 		Snapshot	snapshot;
4492 
4493 		if (newrel)
4494 			ereport(DEBUG1,
4495 					(errmsg("rewriting table \"%s\"",
4496 							RelationGetRelationName(oldrel))));
4497 		else
4498 			ereport(DEBUG1,
4499 					(errmsg("verifying table \"%s\"",
4500 							RelationGetRelationName(oldrel))));
4501 
4502 		if (newrel)
4503 		{
4504 			/*
4505 			 * All predicate locks on the tuples or pages are about to be made
4506 			 * invalid, because we move tuples around.  Promote them to
4507 			 * relation locks.
4508 			 */
4509 			TransferPredicateLocksToHeapRelation(oldrel);
4510 		}
4511 
4512 		econtext = GetPerTupleExprContext(estate);
4513 
4514 		/*
4515 		 * Make tuple slots for old and new tuples.  Note that even when the
4516 		 * tuples are the same, the tupDescs might not be (consider ADD COLUMN
4517 		 * without a default).
4518 		 */
4519 		oldslot = MakeSingleTupleTableSlot(oldTupDesc);
4520 		newslot = MakeSingleTupleTableSlot(newTupDesc);
4521 
4522 		/* Preallocate values/isnull arrays */
4523 		i = Max(newTupDesc->natts, oldTupDesc->natts);
4524 		values = (Datum *) palloc(i * sizeof(Datum));
4525 		isnull = (bool *) palloc(i * sizeof(bool));
4526 		memset(values, 0, i * sizeof(Datum));
4527 		memset(isnull, true, i * sizeof(bool));
4528 
4529 		/*
4530 		 * Any attributes that are dropped according to the new tuple
4531 		 * descriptor can be set to NULL. We precompute the list of dropped
4532 		 * attributes to avoid needing to do so in the per-tuple loop.
4533 		 */
4534 		for (i = 0; i < newTupDesc->natts; i++)
4535 		{
4536 			if (newTupDesc->attrs[i]->attisdropped)
4537 				dropped_attrs = lappend_int(dropped_attrs, i);
4538 		}
4539 
4540 		/*
4541 		 * Scan through the rows, generating a new row if needed and then
4542 		 * checking all the constraints.
4543 		 */
4544 		snapshot = RegisterSnapshot(GetLatestSnapshot());
4545 		scan = heap_beginscan(oldrel, snapshot, 0, NULL);
4546 
4547 		/*
4548 		 * Switch to per-tuple memory context and reset it for each tuple
4549 		 * produced, so we don't leak memory.
4550 		 */
4551 		oldCxt = MemoryContextSwitchTo(GetPerTupleMemoryContext(estate));
4552 
4553 		while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
4554 		{
4555 			if (tab->rewrite > 0)
4556 			{
4557 				Oid			tupOid = InvalidOid;
4558 
4559 				/* Extract data from old tuple */
4560 				heap_deform_tuple(tuple, oldTupDesc, values, isnull);
4561 				if (oldTupDesc->tdhasoid)
4562 					tupOid = HeapTupleGetOid(tuple);
4563 
4564 				/* Set dropped attributes to null in new tuple */
4565 				foreach(lc, dropped_attrs)
4566 					isnull[lfirst_int(lc)] = true;
4567 
4568 				/*
4569 				 * Process supplied expressions to replace selected columns.
4570 				 * Expression inputs come from the old tuple.
4571 				 */
4572 				ExecStoreTuple(tuple, oldslot, InvalidBuffer, false);
4573 				econtext->ecxt_scantuple = oldslot;
4574 
4575 				foreach(l, tab->newvals)
4576 				{
4577 					NewColumnValue *ex = lfirst(l);
4578 
4579 					values[ex->attnum - 1] = ExecEvalExpr(ex->exprstate,
4580 														  econtext,
4581 														  &isnull[ex->attnum - 1]);
4582 				}
4583 
4584 				/*
4585 				 * Form the new tuple. Note that we don't explicitly pfree it,
4586 				 * since the per-tuple memory context will be reset shortly.
4587 				 */
4588 				tuple = heap_form_tuple(newTupDesc, values, isnull);
4589 
4590 				/* Preserve OID, if any */
4591 				if (newTupDesc->tdhasoid)
4592 					HeapTupleSetOid(tuple, tupOid);
4593 
4594 				/*
4595 				 * Constraints might reference the tableoid column, so
4596 				 * initialize t_tableOid before evaluating them.
4597 				 */
4598 				tuple->t_tableOid = RelationGetRelid(oldrel);
4599 			}
4600 
4601 			/* Now check any constraints on the possibly-changed tuple */
4602 			ExecStoreTuple(tuple, newslot, InvalidBuffer, false);
4603 			econtext->ecxt_scantuple = newslot;
4604 
4605 			foreach(l, notnull_attrs)
4606 			{
4607 				int			attn = lfirst_int(l);
4608 
4609 				if (heap_attisnull(tuple, attn + 1))
4610 					ereport(ERROR,
4611 							(errcode(ERRCODE_NOT_NULL_VIOLATION),
4612 							 errmsg("column \"%s\" contains null values",
4613 									NameStr(newTupDesc->attrs[attn]->attname)),
4614 							 errtablecol(oldrel, attn + 1)));
4615 			}
4616 
4617 			foreach(l, tab->constraints)
4618 			{
4619 				NewConstraint *con = lfirst(l);
4620 
4621 				switch (con->contype)
4622 				{
4623 					case CONSTR_CHECK:
4624 						if (!ExecCheck(con->qualstate, econtext))
4625 							ereport(ERROR,
4626 									(errcode(ERRCODE_CHECK_VIOLATION),
4627 									 errmsg("check constraint \"%s\" is violated by some row",
4628 											con->name),
4629 									 errtableconstraint(oldrel, con->name)));
4630 						break;
4631 					case CONSTR_FOREIGN:
4632 						/* Nothing to do here */
4633 						break;
4634 					default:
4635 						elog(ERROR, "unrecognized constraint type: %d",
4636 							 (int) con->contype);
4637 				}
4638 			}
4639 
4640 			if (partqualstate && !ExecCheck(partqualstate, econtext))
4641 				ereport(ERROR,
4642 						(errcode(ERRCODE_CHECK_VIOLATION),
4643 						 errmsg("partition constraint is violated by some row")));
4644 
4645 			/* Write the tuple out to the new relation */
4646 			if (newrel)
4647 				heap_insert(newrel, tuple, mycid, hi_options, bistate);
4648 
4649 			ResetExprContext(econtext);
4650 
4651 			CHECK_FOR_INTERRUPTS();
4652 		}
4653 
4654 		MemoryContextSwitchTo(oldCxt);
4655 		heap_endscan(scan);
4656 		UnregisterSnapshot(snapshot);
4657 
4658 		ExecDropSingleTupleTableSlot(oldslot);
4659 		ExecDropSingleTupleTableSlot(newslot);
4660 	}
4661 
4662 	FreeExecutorState(estate);
4663 
4664 	heap_close(oldrel, NoLock);
4665 	if (newrel)
4666 	{
4667 		FreeBulkInsertState(bistate);
4668 
4669 		/* If we skipped writing WAL, then we need to sync the heap. */
4670 		if (hi_options & HEAP_INSERT_SKIP_WAL)
4671 			heap_sync(newrel);
4672 
4673 		heap_close(newrel, NoLock);
4674 	}
4675 }
4676 
4677 /*
4678  * ATGetQueueEntry: find or create an entry in the ALTER TABLE work queue
4679  */
4680 static AlteredTableInfo *
ATGetQueueEntry(List ** wqueue,Relation rel)4681 ATGetQueueEntry(List **wqueue, Relation rel)
4682 {
4683 	Oid			relid = RelationGetRelid(rel);
4684 	AlteredTableInfo *tab;
4685 	ListCell   *ltab;
4686 
4687 	foreach(ltab, *wqueue)
4688 	{
4689 		tab = (AlteredTableInfo *) lfirst(ltab);
4690 		if (tab->relid == relid)
4691 			return tab;
4692 	}
4693 
4694 	/*
4695 	 * Not there, so add it.  Note that we make a copy of the relation's
4696 	 * existing descriptor before anything interesting can happen to it.
4697 	 */
4698 	tab = (AlteredTableInfo *) palloc0(sizeof(AlteredTableInfo));
4699 	tab->relid = relid;
4700 	tab->relkind = rel->rd_rel->relkind;
4701 	tab->oldDesc = CreateTupleDescCopy(RelationGetDescr(rel));
4702 	tab->newrelpersistence = RELPERSISTENCE_PERMANENT;
4703 	tab->chgPersistence = false;
4704 
4705 	*wqueue = lappend(*wqueue, tab);
4706 
4707 	return tab;
4708 }
4709 
4710 /*
4711  * ATSimplePermissions
4712  *
4713  * - Ensure that it is a relation (or possibly a view)
4714  * - Ensure this user is the owner
4715  * - Ensure that it is not a system table
4716  */
4717 static void
ATSimplePermissions(Relation rel,int allowed_targets)4718 ATSimplePermissions(Relation rel, int allowed_targets)
4719 {
4720 	int			actual_target;
4721 
4722 	switch (rel->rd_rel->relkind)
4723 	{
4724 		case RELKIND_RELATION:
4725 		case RELKIND_PARTITIONED_TABLE:
4726 			actual_target = ATT_TABLE;
4727 			break;
4728 		case RELKIND_VIEW:
4729 			actual_target = ATT_VIEW;
4730 			break;
4731 		case RELKIND_MATVIEW:
4732 			actual_target = ATT_MATVIEW;
4733 			break;
4734 		case RELKIND_INDEX:
4735 			actual_target = ATT_INDEX;
4736 			break;
4737 		case RELKIND_COMPOSITE_TYPE:
4738 			actual_target = ATT_COMPOSITE_TYPE;
4739 			break;
4740 		case RELKIND_FOREIGN_TABLE:
4741 			actual_target = ATT_FOREIGN_TABLE;
4742 			break;
4743 		default:
4744 			actual_target = 0;
4745 			break;
4746 	}
4747 
4748 	/* Wrong target type? */
4749 	if ((actual_target & allowed_targets) == 0)
4750 		ATWrongRelkindError(rel, allowed_targets);
4751 
4752 	/* Permissions checks */
4753 	if (!pg_class_ownercheck(RelationGetRelid(rel), GetUserId()))
4754 		aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS,
4755 					   RelationGetRelationName(rel));
4756 
4757 	if (!allowSystemTableMods && IsSystemRelation(rel))
4758 		ereport(ERROR,
4759 				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
4760 				 errmsg("permission denied: \"%s\" is a system catalog",
4761 						RelationGetRelationName(rel))));
4762 }
4763 
4764 /*
4765  * ATWrongRelkindError
4766  *
4767  * Throw an error when a relation has been determined to be of the wrong
4768  * type.
4769  */
4770 static void
ATWrongRelkindError(Relation rel,int allowed_targets)4771 ATWrongRelkindError(Relation rel, int allowed_targets)
4772 {
4773 	char	   *msg;
4774 
4775 	switch (allowed_targets)
4776 	{
4777 		case ATT_TABLE:
4778 			msg = _("\"%s\" is not a table");
4779 			break;
4780 		case ATT_TABLE | ATT_VIEW:
4781 			msg = _("\"%s\" is not a table or view");
4782 			break;
4783 		case ATT_TABLE | ATT_VIEW | ATT_FOREIGN_TABLE:
4784 			msg = _("\"%s\" is not a table, view, or foreign table");
4785 			break;
4786 		case ATT_TABLE | ATT_VIEW | ATT_MATVIEW | ATT_INDEX:
4787 			msg = _("\"%s\" is not a table, view, materialized view, or index");
4788 			break;
4789 		case ATT_TABLE | ATT_MATVIEW:
4790 			msg = _("\"%s\" is not a table or materialized view");
4791 			break;
4792 		case ATT_TABLE | ATT_MATVIEW | ATT_INDEX:
4793 			msg = _("\"%s\" is not a table, materialized view, or index");
4794 			break;
4795 		case ATT_TABLE | ATT_MATVIEW | ATT_FOREIGN_TABLE:
4796 			msg = _("\"%s\" is not a table, materialized view, or foreign table");
4797 			break;
4798 		case ATT_TABLE | ATT_FOREIGN_TABLE:
4799 			msg = _("\"%s\" is not a table or foreign table");
4800 			break;
4801 		case ATT_TABLE | ATT_COMPOSITE_TYPE | ATT_FOREIGN_TABLE:
4802 			msg = _("\"%s\" is not a table, composite type, or foreign table");
4803 			break;
4804 		case ATT_TABLE | ATT_MATVIEW | ATT_INDEX | ATT_FOREIGN_TABLE:
4805 			msg = _("\"%s\" is not a table, materialized view, index, or foreign table");
4806 			break;
4807 		case ATT_VIEW:
4808 			msg = _("\"%s\" is not a view");
4809 			break;
4810 		case ATT_FOREIGN_TABLE:
4811 			msg = _("\"%s\" is not a foreign table");
4812 			break;
4813 		default:
4814 			/* shouldn't get here, add all necessary cases above */
4815 			msg = _("\"%s\" is of the wrong type");
4816 			break;
4817 	}
4818 
4819 	ereport(ERROR,
4820 			(errcode(ERRCODE_WRONG_OBJECT_TYPE),
4821 			 errmsg(msg, RelationGetRelationName(rel))));
4822 }
4823 
4824 /*
4825  * ATSimpleRecursion
4826  *
4827  * Simple table recursion sufficient for most ALTER TABLE operations.
4828  * All direct and indirect children are processed in an unspecified order.
4829  * Note that if a child inherits from the original table via multiple
4830  * inheritance paths, it will be visited just once.
4831  */
4832 static void
ATSimpleRecursion(List ** wqueue,Relation rel,AlterTableCmd * cmd,bool recurse,LOCKMODE lockmode)4833 ATSimpleRecursion(List **wqueue, Relation rel,
4834 				  AlterTableCmd *cmd, bool recurse, LOCKMODE lockmode)
4835 {
4836 	/*
4837 	 * Propagate to children if desired.  Only plain tables and foreign tables
4838 	 * have children, so no need to search for other relkinds.
4839 	 */
4840 	if (recurse &&
4841 		(rel->rd_rel->relkind == RELKIND_RELATION ||
4842 		 rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE ||
4843 		 rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE))
4844 	{
4845 		Oid			relid = RelationGetRelid(rel);
4846 		ListCell   *child;
4847 		List	   *children;
4848 
4849 		children = find_all_inheritors(relid, lockmode, NULL);
4850 
4851 		/*
4852 		 * find_all_inheritors does the recursive search of the inheritance
4853 		 * hierarchy, so all we have to do is process all of the relids in the
4854 		 * list that it returns.
4855 		 */
4856 		foreach(child, children)
4857 		{
4858 			Oid			childrelid = lfirst_oid(child);
4859 			Relation	childrel;
4860 
4861 			if (childrelid == relid)
4862 				continue;
4863 			/* find_all_inheritors already got lock */
4864 			childrel = relation_open(childrelid, NoLock);
4865 			CheckTableNotInUse(childrel, "ALTER TABLE");
4866 			ATPrepCmd(wqueue, childrel, cmd, false, true, lockmode);
4867 			relation_close(childrel, NoLock);
4868 		}
4869 	}
4870 }
4871 
4872 /*
4873  * ATTypedTableRecursion
4874  *
4875  * Propagate ALTER TYPE operations to the typed tables of that type.
4876  * Also check the RESTRICT/CASCADE behavior.  Given CASCADE, also permit
4877  * recursion to inheritance children of the typed tables.
4878  */
4879 static void
ATTypedTableRecursion(List ** wqueue,Relation rel,AlterTableCmd * cmd,LOCKMODE lockmode)4880 ATTypedTableRecursion(List **wqueue, Relation rel, AlterTableCmd *cmd,
4881 					  LOCKMODE lockmode)
4882 {
4883 	ListCell   *child;
4884 	List	   *children;
4885 
4886 	Assert(rel->rd_rel->relkind == RELKIND_COMPOSITE_TYPE);
4887 
4888 	children = find_typed_table_dependencies(rel->rd_rel->reltype,
4889 											 RelationGetRelationName(rel),
4890 											 cmd->behavior);
4891 
4892 	foreach(child, children)
4893 	{
4894 		Oid			childrelid = lfirst_oid(child);
4895 		Relation	childrel;
4896 
4897 		childrel = relation_open(childrelid, lockmode);
4898 		CheckTableNotInUse(childrel, "ALTER TABLE");
4899 		ATPrepCmd(wqueue, childrel, cmd, true, true, lockmode);
4900 		relation_close(childrel, NoLock);
4901 	}
4902 }
4903 
4904 
4905 /*
4906  * find_composite_type_dependencies
4907  *
4908  * Check to see if the type "typeOid" is being used as a column in some table
4909  * (possibly nested several levels deep in composite types, arrays, etc!).
4910  * Eventually, we'd like to propagate the check or rewrite operation
4911  * into such tables, but for now, just error out if we find any.
4912  *
4913  * Caller should provide either the associated relation of a rowtype,
4914  * or a type name (not both) for use in the error message, if any.
4915  *
4916  * Note that "typeOid" is not necessarily a composite type; it could also be
4917  * another container type such as an array or range, or a domain over one of
4918  * these things.  The name of this function is therefore somewhat historical,
4919  * but it's not worth changing.
4920  *
4921  * We assume that functions and views depending on the type are not reasons
4922  * to reject the ALTER.  (How safe is this really?)
4923  */
4924 void
find_composite_type_dependencies(Oid typeOid,Relation origRelation,const char * origTypeName)4925 find_composite_type_dependencies(Oid typeOid, Relation origRelation,
4926 								 const char *origTypeName)
4927 {
4928 	Relation	depRel;
4929 	ScanKeyData key[2];
4930 	SysScanDesc depScan;
4931 	HeapTuple	depTup;
4932 
4933 	/* since this function recurses, it could be driven to stack overflow */
4934 	check_stack_depth();
4935 
4936 	/*
4937 	 * We scan pg_depend to find those things that depend on the given type.
4938 	 * (We assume we can ignore refobjsubid for a type.)
4939 	 */
4940 	depRel = heap_open(DependRelationId, AccessShareLock);
4941 
4942 	ScanKeyInit(&key[0],
4943 				Anum_pg_depend_refclassid,
4944 				BTEqualStrategyNumber, F_OIDEQ,
4945 				ObjectIdGetDatum(TypeRelationId));
4946 	ScanKeyInit(&key[1],
4947 				Anum_pg_depend_refobjid,
4948 				BTEqualStrategyNumber, F_OIDEQ,
4949 				ObjectIdGetDatum(typeOid));
4950 
4951 	depScan = systable_beginscan(depRel, DependReferenceIndexId, true,
4952 								 NULL, 2, key);
4953 
4954 	while (HeapTupleIsValid(depTup = systable_getnext(depScan)))
4955 	{
4956 		Form_pg_depend pg_depend = (Form_pg_depend) GETSTRUCT(depTup);
4957 		Relation	rel;
4958 		Form_pg_attribute att;
4959 
4960 		/* Check for directly dependent types */
4961 		if (pg_depend->classid == TypeRelationId)
4962 		{
4963 			/*
4964 			 * This must be an array, domain, or range containing the given
4965 			 * type, so recursively check for uses of this type.  Note that
4966 			 * any error message will mention the original type not the
4967 			 * container; this is intentional.
4968 			 */
4969 			find_composite_type_dependencies(pg_depend->objid,
4970 											 origRelation, origTypeName);
4971 			continue;
4972 		}
4973 
4974 		/* Else, ignore dependees that aren't user columns of relations */
4975 		/* (we assume system columns are never of interesting types) */
4976 		if (pg_depend->classid != RelationRelationId ||
4977 			pg_depend->objsubid <= 0)
4978 			continue;
4979 
4980 		rel = relation_open(pg_depend->objid, AccessShareLock);
4981 		att = rel->rd_att->attrs[pg_depend->objsubid - 1];
4982 
4983 		if (rel->rd_rel->relkind == RELKIND_RELATION ||
4984 			rel->rd_rel->relkind == RELKIND_MATVIEW ||
4985 			rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
4986 		{
4987 			if (origTypeName)
4988 				ereport(ERROR,
4989 						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
4990 						 errmsg("cannot alter type \"%s\" because column \"%s.%s\" uses it",
4991 								origTypeName,
4992 								RelationGetRelationName(rel),
4993 								NameStr(att->attname))));
4994 			else if (origRelation->rd_rel->relkind == RELKIND_COMPOSITE_TYPE)
4995 				ereport(ERROR,
4996 						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
4997 						 errmsg("cannot alter type \"%s\" because column \"%s.%s\" uses it",
4998 								RelationGetRelationName(origRelation),
4999 								RelationGetRelationName(rel),
5000 								NameStr(att->attname))));
5001 			else if (origRelation->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
5002 				ereport(ERROR,
5003 						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
5004 						 errmsg("cannot alter foreign table \"%s\" because column \"%s.%s\" uses its row type",
5005 								RelationGetRelationName(origRelation),
5006 								RelationGetRelationName(rel),
5007 								NameStr(att->attname))));
5008 			else
5009 				ereport(ERROR,
5010 						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
5011 						 errmsg("cannot alter table \"%s\" because column \"%s.%s\" uses its row type",
5012 								RelationGetRelationName(origRelation),
5013 								RelationGetRelationName(rel),
5014 								NameStr(att->attname))));
5015 		}
5016 		else if (OidIsValid(rel->rd_rel->reltype))
5017 		{
5018 			/*
5019 			 * A view or composite type itself isn't a problem, but we must
5020 			 * recursively check for indirect dependencies via its rowtype.
5021 			 */
5022 			find_composite_type_dependencies(rel->rd_rel->reltype,
5023 											 origRelation, origTypeName);
5024 		}
5025 
5026 		relation_close(rel, AccessShareLock);
5027 	}
5028 
5029 	systable_endscan(depScan);
5030 
5031 	relation_close(depRel, AccessShareLock);
5032 }
5033 
5034 
5035 /*
5036  * find_typed_table_dependencies
5037  *
5038  * Check to see if a composite type is being used as the type of a
5039  * typed table.  Abort if any are found and behavior is RESTRICT.
5040  * Else return the list of tables.
5041  */
5042 static List *
find_typed_table_dependencies(Oid typeOid,const char * typeName,DropBehavior behavior)5043 find_typed_table_dependencies(Oid typeOid, const char *typeName, DropBehavior behavior)
5044 {
5045 	Relation	classRel;
5046 	ScanKeyData key[1];
5047 	HeapScanDesc scan;
5048 	HeapTuple	tuple;
5049 	List	   *result = NIL;
5050 
5051 	classRel = heap_open(RelationRelationId, AccessShareLock);
5052 
5053 	ScanKeyInit(&key[0],
5054 				Anum_pg_class_reloftype,
5055 				BTEqualStrategyNumber, F_OIDEQ,
5056 				ObjectIdGetDatum(typeOid));
5057 
5058 	scan = heap_beginscan_catalog(classRel, 1, key);
5059 
5060 	while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
5061 	{
5062 		if (behavior == DROP_RESTRICT)
5063 			ereport(ERROR,
5064 					(errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
5065 					 errmsg("cannot alter type \"%s\" because it is the type of a typed table",
5066 							typeName),
5067 					 errhint("Use ALTER ... CASCADE to alter the typed tables too.")));
5068 		else
5069 			result = lappend_oid(result, HeapTupleGetOid(tuple));
5070 	}
5071 
5072 	heap_endscan(scan);
5073 	heap_close(classRel, AccessShareLock);
5074 
5075 	return result;
5076 }
5077 
5078 
5079 /*
5080  * check_of_type
5081  *
5082  * Check whether a type is suitable for CREATE TABLE OF/ALTER TABLE OF.  If it
5083  * isn't suitable, throw an error.  Currently, we require that the type
5084  * originated with CREATE TYPE AS.  We could support any row type, but doing so
5085  * would require handling a number of extra corner cases in the DDL commands.
5086  */
5087 void
check_of_type(HeapTuple typetuple)5088 check_of_type(HeapTuple typetuple)
5089 {
5090 	Form_pg_type typ = (Form_pg_type) GETSTRUCT(typetuple);
5091 	bool		typeOk = false;
5092 
5093 	if (typ->typtype == TYPTYPE_COMPOSITE)
5094 	{
5095 		Relation	typeRelation;
5096 
5097 		Assert(OidIsValid(typ->typrelid));
5098 		typeRelation = relation_open(typ->typrelid, AccessShareLock);
5099 		typeOk = (typeRelation->rd_rel->relkind == RELKIND_COMPOSITE_TYPE);
5100 
5101 		/*
5102 		 * Close the parent rel, but keep our AccessShareLock on it until xact
5103 		 * commit.  That will prevent someone else from deleting or ALTERing
5104 		 * the type before the typed table creation/conversion commits.
5105 		 */
5106 		relation_close(typeRelation, NoLock);
5107 	}
5108 	if (!typeOk)
5109 		ereport(ERROR,
5110 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
5111 				 errmsg("type %s is not a composite type",
5112 						format_type_be(HeapTupleGetOid(typetuple)))));
5113 }
5114 
5115 
5116 /*
5117  * ALTER TABLE ADD COLUMN
5118  *
5119  * Adds an additional attribute to a relation making the assumption that
5120  * CHECK, NOT NULL, and FOREIGN KEY constraints will be removed from the
5121  * AT_AddColumn AlterTableCmd by parse_utilcmd.c and added as independent
5122  * AlterTableCmd's.
5123  *
5124  * ADD COLUMN cannot use the normal ALTER TABLE recursion mechanism, because we
5125  * have to decide at runtime whether to recurse or not depending on whether we
5126  * actually add a column or merely merge with an existing column.  (We can't
5127  * check this in a static pre-pass because it won't handle multiple inheritance
5128  * situations correctly.)
5129  */
5130 static void
ATPrepAddColumn(List ** wqueue,Relation rel,bool recurse,bool recursing,bool is_view,AlterTableCmd * cmd,LOCKMODE lockmode)5131 ATPrepAddColumn(List **wqueue, Relation rel, bool recurse, bool recursing,
5132 				bool is_view, AlterTableCmd *cmd, LOCKMODE lockmode)
5133 {
5134 	if (rel->rd_rel->reloftype && !recursing)
5135 		ereport(ERROR,
5136 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
5137 				 errmsg("cannot add column to typed table")));
5138 
5139 	if (rel->rd_rel->relkind == RELKIND_COMPOSITE_TYPE)
5140 		ATTypedTableRecursion(wqueue, rel, cmd, lockmode);
5141 
5142 	if (recurse && !is_view)
5143 		cmd->subtype = AT_AddColumnRecurse;
5144 }
5145 
5146 /*
5147  * Add a column to a table; this handles the AT_AddOids cases as well.  The
5148  * return value is the address of the new column in the parent relation.
5149  */
5150 static ObjectAddress
ATExecAddColumn(List ** wqueue,AlteredTableInfo * tab,Relation rel,ColumnDef * colDef,bool isOid,bool recurse,bool recursing,bool if_not_exists,LOCKMODE lockmode)5151 ATExecAddColumn(List **wqueue, AlteredTableInfo *tab, Relation rel,
5152 				ColumnDef *colDef, bool isOid,
5153 				bool recurse, bool recursing,
5154 				bool if_not_exists, LOCKMODE lockmode)
5155 {
5156 	Oid			myrelid = RelationGetRelid(rel);
5157 	Relation	pgclass,
5158 				attrdesc;
5159 	HeapTuple	reltup;
5160 	FormData_pg_attribute attribute;
5161 	int			newattnum;
5162 	char		relkind;
5163 	HeapTuple	typeTuple;
5164 	Oid			typeOid;
5165 	int32		typmod;
5166 	Oid			collOid;
5167 	Form_pg_type tform;
5168 	Expr	   *defval;
5169 	List	   *children;
5170 	ListCell   *child;
5171 	AclResult	aclresult;
5172 	ObjectAddress address;
5173 
5174 	/* At top level, permission check was done in ATPrepCmd, else do it */
5175 	if (recursing)
5176 		ATSimplePermissions(rel, ATT_TABLE | ATT_FOREIGN_TABLE);
5177 
5178 	if (rel->rd_rel->relispartition && !recursing)
5179 		ereport(ERROR,
5180 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
5181 				 errmsg("cannot add column to a partition")));
5182 
5183 	attrdesc = heap_open(AttributeRelationId, RowExclusiveLock);
5184 
5185 	/*
5186 	 * Are we adding the column to a recursion child?  If so, check whether to
5187 	 * merge with an existing definition for the column.  If we do merge, we
5188 	 * must not recurse.  Children will already have the column, and recursing
5189 	 * into them would mess up attinhcount.
5190 	 */
5191 	if (colDef->inhcount > 0)
5192 	{
5193 		HeapTuple	tuple;
5194 
5195 		/* Does child already have a column by this name? */
5196 		tuple = SearchSysCacheCopyAttName(myrelid, colDef->colname);
5197 		if (HeapTupleIsValid(tuple))
5198 		{
5199 			Form_pg_attribute childatt = (Form_pg_attribute) GETSTRUCT(tuple);
5200 			Oid			ctypeId;
5201 			int32		ctypmod;
5202 			Oid			ccollid;
5203 
5204 			/* Child column must match on type, typmod, and collation */
5205 			typenameTypeIdAndMod(NULL, colDef->typeName, &ctypeId, &ctypmod);
5206 			if (ctypeId != childatt->atttypid ||
5207 				ctypmod != childatt->atttypmod)
5208 				ereport(ERROR,
5209 						(errcode(ERRCODE_DATATYPE_MISMATCH),
5210 						 errmsg("child table \"%s\" has different type for column \"%s\"",
5211 								RelationGetRelationName(rel), colDef->colname)));
5212 			ccollid = GetColumnDefCollation(NULL, colDef, ctypeId);
5213 			if (ccollid != childatt->attcollation)
5214 				ereport(ERROR,
5215 						(errcode(ERRCODE_COLLATION_MISMATCH),
5216 						 errmsg("child table \"%s\" has different collation for column \"%s\"",
5217 								RelationGetRelationName(rel), colDef->colname),
5218 						 errdetail("\"%s\" versus \"%s\"",
5219 								   get_collation_name(ccollid),
5220 								   get_collation_name(childatt->attcollation))));
5221 
5222 			/* If it's OID, child column must actually be OID */
5223 			if (isOid && childatt->attnum != ObjectIdAttributeNumber)
5224 				ereport(ERROR,
5225 						(errcode(ERRCODE_DATATYPE_MISMATCH),
5226 						 errmsg("child table \"%s\" has a conflicting \"%s\" column",
5227 								RelationGetRelationName(rel), colDef->colname)));
5228 
5229 			/* Bump the existing child att's inhcount */
5230 			childatt->attinhcount++;
5231 			CatalogTupleUpdate(attrdesc, &tuple->t_self, tuple);
5232 
5233 			heap_freetuple(tuple);
5234 
5235 			/* Inform the user about the merge */
5236 			ereport(NOTICE,
5237 					(errmsg("merging definition of column \"%s\" for child \"%s\"",
5238 							colDef->colname, RelationGetRelationName(rel))));
5239 
5240 			heap_close(attrdesc, RowExclusiveLock);
5241 			return InvalidObjectAddress;
5242 		}
5243 	}
5244 
5245 	pgclass = heap_open(RelationRelationId, RowExclusiveLock);
5246 
5247 	reltup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(myrelid));
5248 	if (!HeapTupleIsValid(reltup))
5249 		elog(ERROR, "cache lookup failed for relation %u", myrelid);
5250 	relkind = ((Form_pg_class) GETSTRUCT(reltup))->relkind;
5251 
5252 	/*
5253 	 * Cannot add identity column if table has children, because identity does
5254 	 * not inherit.  (Adding column and identity separately will work.)
5255 	 */
5256 	if (colDef->identity &&
5257 		recurse &&
5258 		find_inheritance_children(myrelid, NoLock) != NIL)
5259 		ereport(ERROR,
5260 				(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
5261 				 errmsg("cannot recursively add identity column to table that has child tables")));
5262 
5263 	/* skip if the name already exists and if_not_exists is true */
5264 	if (!check_for_column_name_collision(rel, colDef->colname, if_not_exists))
5265 	{
5266 		heap_close(attrdesc, RowExclusiveLock);
5267 		heap_freetuple(reltup);
5268 		heap_close(pgclass, RowExclusiveLock);
5269 		return InvalidObjectAddress;
5270 	}
5271 
5272 	/* Determine the new attribute's number */
5273 	if (isOid)
5274 		newattnum = ObjectIdAttributeNumber;
5275 	else
5276 	{
5277 		newattnum = ((Form_pg_class) GETSTRUCT(reltup))->relnatts + 1;
5278 		if (newattnum > MaxHeapAttributeNumber)
5279 			ereport(ERROR,
5280 					(errcode(ERRCODE_TOO_MANY_COLUMNS),
5281 					 errmsg("tables can have at most %d columns",
5282 							MaxHeapAttributeNumber)));
5283 	}
5284 
5285 	typeTuple = typenameType(NULL, colDef->typeName, &typmod);
5286 	tform = (Form_pg_type) GETSTRUCT(typeTuple);
5287 	typeOid = HeapTupleGetOid(typeTuple);
5288 
5289 	aclresult = pg_type_aclcheck(typeOid, GetUserId(), ACL_USAGE);
5290 	if (aclresult != ACLCHECK_OK)
5291 		aclcheck_error_type(aclresult, typeOid);
5292 
5293 	collOid = GetColumnDefCollation(NULL, colDef, typeOid);
5294 
5295 	/* make sure datatype is legal for a column */
5296 	CheckAttributeType(colDef->colname, typeOid, collOid,
5297 					   list_make1_oid(rel->rd_rel->reltype),
5298 					   false);
5299 
5300 	/* construct new attribute's pg_attribute entry */
5301 	attribute.attrelid = myrelid;
5302 	namestrcpy(&(attribute.attname), colDef->colname);
5303 	attribute.atttypid = typeOid;
5304 	attribute.attstattarget = (newattnum > 0) ? -1 : 0;
5305 	attribute.attlen = tform->typlen;
5306 	attribute.attcacheoff = -1;
5307 	attribute.atttypmod = typmod;
5308 	attribute.attnum = newattnum;
5309 	attribute.attbyval = tform->typbyval;
5310 	attribute.attndims = list_length(colDef->typeName->arrayBounds);
5311 	attribute.attstorage = tform->typstorage;
5312 	attribute.attalign = tform->typalign;
5313 	attribute.attnotnull = colDef->is_not_null;
5314 	attribute.atthasdef = false;
5315 	attribute.attidentity = colDef->identity;
5316 	attribute.attisdropped = false;
5317 	attribute.attislocal = colDef->is_local;
5318 	attribute.attinhcount = colDef->inhcount;
5319 	attribute.attcollation = collOid;
5320 	/* attribute.attacl is handled by InsertPgAttributeTuple */
5321 
5322 	ReleaseSysCache(typeTuple);
5323 
5324 	InsertPgAttributeTuple(attrdesc, &attribute, NULL);
5325 
5326 	heap_close(attrdesc, RowExclusiveLock);
5327 
5328 	/*
5329 	 * Update pg_class tuple as appropriate
5330 	 */
5331 	if (isOid)
5332 		((Form_pg_class) GETSTRUCT(reltup))->relhasoids = true;
5333 	else
5334 		((Form_pg_class) GETSTRUCT(reltup))->relnatts = newattnum;
5335 
5336 	CatalogTupleUpdate(pgclass, &reltup->t_self, reltup);
5337 
5338 	heap_freetuple(reltup);
5339 
5340 	/* Post creation hook for new attribute */
5341 	InvokeObjectPostCreateHook(RelationRelationId, myrelid, newattnum);
5342 
5343 	heap_close(pgclass, RowExclusiveLock);
5344 
5345 	/* Make the attribute's catalog entry visible */
5346 	CommandCounterIncrement();
5347 
5348 	/*
5349 	 * Store the DEFAULT, if any, in the catalogs
5350 	 */
5351 	if (colDef->raw_default)
5352 	{
5353 		RawColumnDefault *rawEnt;
5354 
5355 		rawEnt = (RawColumnDefault *) palloc(sizeof(RawColumnDefault));
5356 		rawEnt->attnum = attribute.attnum;
5357 		rawEnt->raw_default = copyObject(colDef->raw_default);
5358 
5359 		/*
5360 		 * This function is intended for CREATE TABLE, so it processes a
5361 		 * _list_ of defaults, but we just do one.
5362 		 */
5363 		AddRelationNewConstraints(rel, list_make1(rawEnt), NIL,
5364 								  false, true, false);
5365 
5366 		/* Make the additional catalog changes visible */
5367 		CommandCounterIncrement();
5368 	}
5369 
5370 	/*
5371 	 * Tell Phase 3 to fill in the default expression, if there is one.
5372 	 *
5373 	 * If there is no default, Phase 3 doesn't have to do anything, because
5374 	 * that effectively means that the default is NULL.  The heap tuple access
5375 	 * routines always check for attnum > # of attributes in tuple, and return
5376 	 * NULL if so, so without any modification of the tuple data we will get
5377 	 * the effect of NULL values in the new column.
5378 	 *
5379 	 * An exception occurs when the new column is of a domain type: the domain
5380 	 * might have a NOT NULL constraint, or a check constraint that indirectly
5381 	 * rejects nulls.  If there are any domain constraints then we construct
5382 	 * an explicit NULL default value that will be passed through
5383 	 * CoerceToDomain processing.  (This is a tad inefficient, since it causes
5384 	 * rewriting the table which we really don't have to do, but the present
5385 	 * design of domain processing doesn't offer any simple way of checking
5386 	 * the constraints more directly.)
5387 	 *
5388 	 * Note: we use build_column_default, and not just the cooked default
5389 	 * returned by AddRelationNewConstraints, so that the right thing happens
5390 	 * when a datatype's default applies.
5391 	 *
5392 	 * We skip this step completely for views and foreign tables.  For a view,
5393 	 * we can only get here from CREATE OR REPLACE VIEW, which historically
5394 	 * doesn't set up defaults, not even for domain-typed columns.  And in any
5395 	 * case we mustn't invoke Phase 3 on a view or foreign table, since they
5396 	 * have no storage.
5397 	 */
5398 	if (relkind != RELKIND_VIEW && relkind != RELKIND_COMPOSITE_TYPE
5399 		&& relkind != RELKIND_FOREIGN_TABLE && attribute.attnum > 0)
5400 	{
5401 		/*
5402 		 * For an identity column, we can't use build_column_default(),
5403 		 * because the sequence ownership isn't set yet.  So do it manually.
5404 		 */
5405 		if (colDef->identity)
5406 		{
5407 			NextValueExpr *nve = makeNode(NextValueExpr);
5408 
5409 			nve->seqid = RangeVarGetRelid(colDef->identitySequence, NoLock, false);
5410 			nve->typeId = typeOid;
5411 
5412 			defval = (Expr *) nve;
5413 		}
5414 		else
5415 			defval = (Expr *) build_column_default(rel, attribute.attnum);
5416 
5417 		if (!defval && DomainHasConstraints(typeOid))
5418 		{
5419 			Oid			baseTypeId;
5420 			int32		baseTypeMod;
5421 			Oid			baseTypeColl;
5422 
5423 			baseTypeMod = typmod;
5424 			baseTypeId = getBaseTypeAndTypmod(typeOid, &baseTypeMod);
5425 			baseTypeColl = get_typcollation(baseTypeId);
5426 			defval = (Expr *) makeNullConst(baseTypeId, baseTypeMod, baseTypeColl);
5427 			defval = (Expr *) coerce_to_target_type(NULL,
5428 													(Node *) defval,
5429 													baseTypeId,
5430 													typeOid,
5431 													typmod,
5432 													COERCION_ASSIGNMENT,
5433 													COERCE_IMPLICIT_CAST,
5434 													-1);
5435 			if (defval == NULL) /* should not happen */
5436 				elog(ERROR, "failed to coerce base type to domain");
5437 		}
5438 
5439 		if (defval)
5440 		{
5441 			NewColumnValue *newval;
5442 
5443 			newval = (NewColumnValue *) palloc0(sizeof(NewColumnValue));
5444 			newval->attnum = attribute.attnum;
5445 			newval->expr = expression_planner(defval);
5446 
5447 			tab->newvals = lappend(tab->newvals, newval);
5448 			tab->rewrite |= AT_REWRITE_DEFAULT_VAL;
5449 		}
5450 
5451 		/*
5452 		 * If the new column is NOT NULL, tell Phase 3 it needs to test that.
5453 		 * (Note we don't do this for an OID column.  OID will be marked not
5454 		 * null, but since it's filled specially, there's no need to test
5455 		 * anything.)
5456 		 */
5457 		tab->new_notnull |= colDef->is_not_null;
5458 	}
5459 
5460 	/*
5461 	 * If we are adding an OID column, we have to tell Phase 3 to rewrite the
5462 	 * table to fix that.
5463 	 */
5464 	if (isOid)
5465 		tab->rewrite |= AT_REWRITE_ALTER_OID;
5466 
5467 	/*
5468 	 * Add needed dependency entries for the new column.
5469 	 */
5470 	add_column_datatype_dependency(myrelid, newattnum, attribute.atttypid);
5471 	add_column_collation_dependency(myrelid, newattnum, attribute.attcollation);
5472 
5473 	/*
5474 	 * Propagate to children as appropriate.  Unlike most other ALTER
5475 	 * routines, we have to do this one level of recursion at a time; we can't
5476 	 * use find_all_inheritors to do it in one pass.
5477 	 */
5478 	children = find_inheritance_children(RelationGetRelid(rel), lockmode);
5479 
5480 	/*
5481 	 * If we are told not to recurse, there had better not be any child
5482 	 * tables; else the addition would put them out of step.
5483 	 */
5484 	if (children && !recurse)
5485 		ereport(ERROR,
5486 				(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
5487 				 errmsg("column must be added to child tables too")));
5488 
5489 	/* Children should see column as singly inherited */
5490 	if (!recursing)
5491 	{
5492 		colDef = copyObject(colDef);
5493 		colDef->inhcount = 1;
5494 		colDef->is_local = false;
5495 	}
5496 
5497 	foreach(child, children)
5498 	{
5499 		Oid			childrelid = lfirst_oid(child);
5500 		Relation	childrel;
5501 		AlteredTableInfo *childtab;
5502 
5503 		/* find_inheritance_children already got lock */
5504 		childrel = heap_open(childrelid, NoLock);
5505 		CheckTableNotInUse(childrel, "ALTER TABLE");
5506 
5507 		/* Find or create work queue entry for this table */
5508 		childtab = ATGetQueueEntry(wqueue, childrel);
5509 
5510 		/* Recurse to child; return value is ignored */
5511 		ATExecAddColumn(wqueue, childtab, childrel,
5512 						colDef, isOid, recurse, true,
5513 						if_not_exists, lockmode);
5514 
5515 		heap_close(childrel, NoLock);
5516 	}
5517 
5518 	ObjectAddressSubSet(address, RelationRelationId, myrelid, newattnum);
5519 	return address;
5520 }
5521 
5522 /*
5523  * If a new or renamed column will collide with the name of an existing
5524  * column and if_not_exists is false then error out, else do nothing.
5525  */
5526 static bool
check_for_column_name_collision(Relation rel,const char * colname,bool if_not_exists)5527 check_for_column_name_collision(Relation rel, const char *colname,
5528 								bool if_not_exists)
5529 {
5530 	HeapTuple	attTuple;
5531 	int			attnum;
5532 
5533 	/*
5534 	 * this test is deliberately not attisdropped-aware, since if one tries to
5535 	 * add a column matching a dropped column name, it's gonna fail anyway.
5536 	 */
5537 	attTuple = SearchSysCache2(ATTNAME,
5538 							   ObjectIdGetDatum(RelationGetRelid(rel)),
5539 							   PointerGetDatum(colname));
5540 	if (!HeapTupleIsValid(attTuple))
5541 		return true;
5542 
5543 	attnum = ((Form_pg_attribute) GETSTRUCT(attTuple))->attnum;
5544 	ReleaseSysCache(attTuple);
5545 
5546 	/*
5547 	 * We throw a different error message for conflicts with system column
5548 	 * names, since they are normally not shown and the user might otherwise
5549 	 * be confused about the reason for the conflict.
5550 	 */
5551 	if (attnum <= 0)
5552 		ereport(ERROR,
5553 				(errcode(ERRCODE_DUPLICATE_COLUMN),
5554 				 errmsg("column name \"%s\" conflicts with a system column name",
5555 						colname)));
5556 	else
5557 	{
5558 		if (if_not_exists)
5559 		{
5560 			ereport(NOTICE,
5561 					(errcode(ERRCODE_DUPLICATE_COLUMN),
5562 					 errmsg("column \"%s\" of relation \"%s\" already exists, skipping",
5563 							colname, RelationGetRelationName(rel))));
5564 			return false;
5565 		}
5566 
5567 		ereport(ERROR,
5568 				(errcode(ERRCODE_DUPLICATE_COLUMN),
5569 				 errmsg("column \"%s\" of relation \"%s\" already exists",
5570 						colname, RelationGetRelationName(rel))));
5571 	}
5572 
5573 	return true;
5574 }
5575 
5576 /*
5577  * Install a column's dependency on its datatype.
5578  */
5579 static void
add_column_datatype_dependency(Oid relid,int32 attnum,Oid typid)5580 add_column_datatype_dependency(Oid relid, int32 attnum, Oid typid)
5581 {
5582 	ObjectAddress myself,
5583 				referenced;
5584 
5585 	myself.classId = RelationRelationId;
5586 	myself.objectId = relid;
5587 	myself.objectSubId = attnum;
5588 	referenced.classId = TypeRelationId;
5589 	referenced.objectId = typid;
5590 	referenced.objectSubId = 0;
5591 	recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
5592 }
5593 
5594 /*
5595  * Install a column's dependency on its collation.
5596  */
5597 static void
add_column_collation_dependency(Oid relid,int32 attnum,Oid collid)5598 add_column_collation_dependency(Oid relid, int32 attnum, Oid collid)
5599 {
5600 	ObjectAddress myself,
5601 				referenced;
5602 
5603 	/* We know the default collation is pinned, so don't bother recording it */
5604 	if (OidIsValid(collid) && collid != DEFAULT_COLLATION_OID)
5605 	{
5606 		myself.classId = RelationRelationId;
5607 		myself.objectId = relid;
5608 		myself.objectSubId = attnum;
5609 		referenced.classId = CollationRelationId;
5610 		referenced.objectId = collid;
5611 		referenced.objectSubId = 0;
5612 		recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
5613 	}
5614 }
5615 
5616 /*
5617  * ALTER TABLE SET WITH OIDS
5618  *
5619  * Basically this is an ADD COLUMN for the special OID column.  We have
5620  * to cons up a ColumnDef node because the ADD COLUMN code needs one.
5621  */
5622 static void
ATPrepAddOids(List ** wqueue,Relation rel,bool recurse,AlterTableCmd * cmd,LOCKMODE lockmode)5623 ATPrepAddOids(List **wqueue, Relation rel, bool recurse, AlterTableCmd *cmd, LOCKMODE lockmode)
5624 {
5625 	/* If we're recursing to a child table, the ColumnDef is already set up */
5626 	if (cmd->def == NULL)
5627 	{
5628 		ColumnDef  *cdef = makeNode(ColumnDef);
5629 
5630 		cdef->colname = pstrdup("oid");
5631 		cdef->typeName = makeTypeNameFromOid(OIDOID, -1);
5632 		cdef->inhcount = 0;
5633 		cdef->is_local = true;
5634 		cdef->is_not_null = true;
5635 		cdef->storage = 0;
5636 		cdef->location = -1;
5637 		cmd->def = (Node *) cdef;
5638 	}
5639 	ATPrepAddColumn(wqueue, rel, recurse, false, false, cmd, lockmode);
5640 
5641 	if (recurse)
5642 		cmd->subtype = AT_AddOidsRecurse;
5643 }
5644 
5645 /*
5646  * ALTER TABLE ALTER COLUMN DROP NOT NULL
5647  *
5648  * Return the address of the modified column.  If the column was already
5649  * nullable, InvalidObjectAddress is returned.
5650  */
5651 
5652 static void
ATPrepDropNotNull(Relation rel,bool recurse,bool recursing)5653 ATPrepDropNotNull(Relation rel, bool recurse, bool recursing)
5654 {
5655 	/*
5656 	 * If the parent is a partitioned table, like check constraints, we do not
5657 	 * support removing the NOT NULL while partitions exist.
5658 	 */
5659 	if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
5660 	{
5661 		PartitionDesc partdesc = RelationGetPartitionDesc(rel);
5662 
5663 		Assert(partdesc != NULL);
5664 		if (partdesc->nparts > 0 && !recurse && !recursing)
5665 			ereport(ERROR,
5666 					(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
5667 					 errmsg("cannot remove constraint from only the partitioned table when partitions exist"),
5668 					 errhint("Do not specify the ONLY keyword.")));
5669 	}
5670 }
5671 static ObjectAddress
ATExecDropNotNull(Relation rel,const char * colName,LOCKMODE lockmode)5672 ATExecDropNotNull(Relation rel, const char *colName, LOCKMODE lockmode)
5673 {
5674 	HeapTuple	tuple;
5675 	AttrNumber	attnum;
5676 	Relation	attr_rel;
5677 	List	   *indexoidlist;
5678 	ListCell   *indexoidscan;
5679 	ObjectAddress address;
5680 
5681 	/*
5682 	 * lookup the attribute
5683 	 */
5684 	attr_rel = heap_open(AttributeRelationId, RowExclusiveLock);
5685 
5686 	tuple = SearchSysCacheCopyAttName(RelationGetRelid(rel), colName);
5687 
5688 	if (!HeapTupleIsValid(tuple))
5689 		ereport(ERROR,
5690 				(errcode(ERRCODE_UNDEFINED_COLUMN),
5691 				 errmsg("column \"%s\" of relation \"%s\" does not exist",
5692 						colName, RelationGetRelationName(rel))));
5693 
5694 	attnum = ((Form_pg_attribute) GETSTRUCT(tuple))->attnum;
5695 
5696 	/* Prevent them from altering a system attribute */
5697 	if (attnum <= 0)
5698 		ereport(ERROR,
5699 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
5700 				 errmsg("cannot alter system column \"%s\"",
5701 						colName)));
5702 
5703 	if (get_attidentity(RelationGetRelid(rel), attnum))
5704 		ereport(ERROR,
5705 				(errcode(ERRCODE_SYNTAX_ERROR),
5706 				 errmsg("column \"%s\" of relation \"%s\" is an identity column",
5707 						colName, RelationGetRelationName(rel))));
5708 
5709 	/*
5710 	 * Check that the attribute is not in a primary key
5711 	 *
5712 	 * Note: we'll throw error even if the pkey index is not valid.
5713 	 */
5714 
5715 	/* Loop over all indexes on the relation */
5716 	indexoidlist = RelationGetIndexList(rel);
5717 
5718 	foreach(indexoidscan, indexoidlist)
5719 	{
5720 		Oid			indexoid = lfirst_oid(indexoidscan);
5721 		HeapTuple	indexTuple;
5722 		Form_pg_index indexStruct;
5723 		int			i;
5724 
5725 		indexTuple = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(indexoid));
5726 		if (!HeapTupleIsValid(indexTuple))
5727 			elog(ERROR, "cache lookup failed for index %u", indexoid);
5728 		indexStruct = (Form_pg_index) GETSTRUCT(indexTuple);
5729 
5730 		/* If the index is not a primary key, skip the check */
5731 		if (indexStruct->indisprimary)
5732 		{
5733 			/*
5734 			 * Loop over each attribute in the primary key and see if it
5735 			 * matches the to-be-altered attribute
5736 			 */
5737 			for (i = 0; i < indexStruct->indnatts; i++)
5738 			{
5739 				if (indexStruct->indkey.values[i] == attnum)
5740 					ereport(ERROR,
5741 							(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
5742 							 errmsg("column \"%s\" is in a primary key",
5743 									colName)));
5744 			}
5745 		}
5746 
5747 		ReleaseSysCache(indexTuple);
5748 	}
5749 
5750 	list_free(indexoidlist);
5751 
5752 	/* If rel is partition, shouldn't drop NOT NULL if parent has the same */
5753 	if (rel->rd_rel->relispartition)
5754 	{
5755 		Oid			parentId = get_partition_parent(RelationGetRelid(rel));
5756 		Relation	parent = heap_open(parentId, AccessShareLock);
5757 		TupleDesc	tupDesc = RelationGetDescr(parent);
5758 		AttrNumber	parent_attnum;
5759 
5760 		parent_attnum = get_attnum(parentId, colName);
5761 		if (tupDesc->attrs[parent_attnum - 1]->attnotnull)
5762 			ereport(ERROR,
5763 					(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
5764 					 errmsg("column \"%s\" is marked NOT NULL in parent table",
5765 							colName)));
5766 		heap_close(parent, AccessShareLock);
5767 	}
5768 
5769 	/*
5770 	 * Okay, actually perform the catalog change ... if needed
5771 	 */
5772 	if (((Form_pg_attribute) GETSTRUCT(tuple))->attnotnull)
5773 	{
5774 		((Form_pg_attribute) GETSTRUCT(tuple))->attnotnull = FALSE;
5775 
5776 		CatalogTupleUpdate(attr_rel, &tuple->t_self, tuple);
5777 
5778 		ObjectAddressSubSet(address, RelationRelationId,
5779 							RelationGetRelid(rel), attnum);
5780 	}
5781 	else
5782 		address = InvalidObjectAddress;
5783 
5784 	InvokeObjectPostAlterHook(RelationRelationId,
5785 							  RelationGetRelid(rel), attnum);
5786 
5787 	heap_close(attr_rel, RowExclusiveLock);
5788 
5789 	return address;
5790 }
5791 
5792 /*
5793  * ALTER TABLE ALTER COLUMN SET NOT NULL
5794  *
5795  * Return the address of the modified column.  If the column was already NOT
5796  * NULL, InvalidObjectAddress is returned.
5797  */
5798 
5799 static void
ATPrepSetNotNull(Relation rel,bool recurse,bool recursing)5800 ATPrepSetNotNull(Relation rel, bool recurse, bool recursing)
5801 {
5802 	/*
5803 	 * If the parent is a partitioned table, like check constraints, NOT NULL
5804 	 * constraints must be added to the child tables.  Complain if requested
5805 	 * otherwise and partitions exist.
5806 	 */
5807 	if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
5808 	{
5809 		PartitionDesc partdesc = RelationGetPartitionDesc(rel);
5810 
5811 		if (partdesc && partdesc->nparts > 0 && !recurse && !recursing)
5812 			ereport(ERROR,
5813 					(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
5814 					 errmsg("cannot add constraint to only the partitioned table when partitions exist"),
5815 					 errhint("Do not specify the ONLY keyword.")));
5816 	}
5817 }
5818 
5819 static ObjectAddress
ATExecSetNotNull(AlteredTableInfo * tab,Relation rel,const char * colName,LOCKMODE lockmode)5820 ATExecSetNotNull(AlteredTableInfo *tab, Relation rel,
5821 				 const char *colName, LOCKMODE lockmode)
5822 {
5823 	HeapTuple	tuple;
5824 	AttrNumber	attnum;
5825 	Relation	attr_rel;
5826 	ObjectAddress address;
5827 
5828 	/*
5829 	 * lookup the attribute
5830 	 */
5831 	attr_rel = heap_open(AttributeRelationId, RowExclusiveLock);
5832 
5833 	tuple = SearchSysCacheCopyAttName(RelationGetRelid(rel), colName);
5834 
5835 	if (!HeapTupleIsValid(tuple))
5836 		ereport(ERROR,
5837 				(errcode(ERRCODE_UNDEFINED_COLUMN),
5838 				 errmsg("column \"%s\" of relation \"%s\" does not exist",
5839 						colName, RelationGetRelationName(rel))));
5840 
5841 	attnum = ((Form_pg_attribute) GETSTRUCT(tuple))->attnum;
5842 
5843 	/* Prevent them from altering a system attribute */
5844 	if (attnum <= 0)
5845 		ereport(ERROR,
5846 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
5847 				 errmsg("cannot alter system column \"%s\"",
5848 						colName)));
5849 
5850 	/*
5851 	 * Okay, actually perform the catalog change ... if needed
5852 	 */
5853 	if (!((Form_pg_attribute) GETSTRUCT(tuple))->attnotnull)
5854 	{
5855 		((Form_pg_attribute) GETSTRUCT(tuple))->attnotnull = TRUE;
5856 
5857 		CatalogTupleUpdate(attr_rel, &tuple->t_self, tuple);
5858 
5859 		/* Tell Phase 3 it needs to test the constraint */
5860 		tab->new_notnull = true;
5861 
5862 		ObjectAddressSubSet(address, RelationRelationId,
5863 							RelationGetRelid(rel), attnum);
5864 	}
5865 	else
5866 		address = InvalidObjectAddress;
5867 
5868 	InvokeObjectPostAlterHook(RelationRelationId,
5869 							  RelationGetRelid(rel), attnum);
5870 
5871 	heap_close(attr_rel, RowExclusiveLock);
5872 
5873 	return address;
5874 }
5875 
5876 /*
5877  * ALTER TABLE ALTER COLUMN SET/DROP DEFAULT
5878  *
5879  * Return the address of the affected column.
5880  */
5881 static ObjectAddress
ATExecColumnDefault(Relation rel,const char * colName,Node * newDefault,LOCKMODE lockmode)5882 ATExecColumnDefault(Relation rel, const char *colName,
5883 					Node *newDefault, LOCKMODE lockmode)
5884 {
5885 	AttrNumber	attnum;
5886 	ObjectAddress address;
5887 
5888 	/*
5889 	 * get the number of the attribute
5890 	 */
5891 	attnum = get_attnum(RelationGetRelid(rel), colName);
5892 	if (attnum == InvalidAttrNumber)
5893 		ereport(ERROR,
5894 				(errcode(ERRCODE_UNDEFINED_COLUMN),
5895 				 errmsg("column \"%s\" of relation \"%s\" does not exist",
5896 						colName, RelationGetRelationName(rel))));
5897 
5898 	/* Prevent them from altering a system attribute */
5899 	if (attnum <= 0)
5900 		ereport(ERROR,
5901 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
5902 				 errmsg("cannot alter system column \"%s\"",
5903 						colName)));
5904 
5905 	if (get_attidentity(RelationGetRelid(rel), attnum))
5906 		ereport(ERROR,
5907 				(errcode(ERRCODE_SYNTAX_ERROR),
5908 				 errmsg("column \"%s\" of relation \"%s\" is an identity column",
5909 						colName, RelationGetRelationName(rel)),
5910 				 newDefault ? 0 : errhint("Use ALTER TABLE ... ALTER COLUMN ... DROP IDENTITY instead.")));
5911 
5912 	/*
5913 	 * Remove any old default for the column.  We use RESTRICT here for
5914 	 * safety, but at present we do not expect anything to depend on the
5915 	 * default.
5916 	 *
5917 	 * We treat removing the existing default as an internal operation when it
5918 	 * is preparatory to adding a new default, but as a user-initiated
5919 	 * operation when the user asked for a drop.
5920 	 */
5921 	RemoveAttrDefault(RelationGetRelid(rel), attnum, DROP_RESTRICT, false,
5922 					  newDefault == NULL ? false : true);
5923 
5924 	if (newDefault)
5925 	{
5926 		/* SET DEFAULT */
5927 		RawColumnDefault *rawEnt;
5928 
5929 		rawEnt = (RawColumnDefault *) palloc(sizeof(RawColumnDefault));
5930 		rawEnt->attnum = attnum;
5931 		rawEnt->raw_default = newDefault;
5932 
5933 		/*
5934 		 * This function is intended for CREATE TABLE, so it processes a
5935 		 * _list_ of defaults, but we just do one.
5936 		 */
5937 		AddRelationNewConstraints(rel, list_make1(rawEnt), NIL,
5938 								  false, true, false);
5939 	}
5940 
5941 	ObjectAddressSubSet(address, RelationRelationId,
5942 						RelationGetRelid(rel), attnum);
5943 	return address;
5944 }
5945 
5946 /*
5947  * ALTER TABLE ALTER COLUMN ADD IDENTITY
5948  *
5949  * Return the address of the affected column.
5950  */
5951 static ObjectAddress
ATExecAddIdentity(Relation rel,const char * colName,Node * def,LOCKMODE lockmode)5952 ATExecAddIdentity(Relation rel, const char *colName,
5953 				  Node *def, LOCKMODE lockmode)
5954 {
5955 	Relation	attrelation;
5956 	HeapTuple	tuple;
5957 	Form_pg_attribute attTup;
5958 	AttrNumber	attnum;
5959 	ObjectAddress address;
5960 	ColumnDef  *cdef = castNode(ColumnDef, def);
5961 
5962 	attrelation = heap_open(AttributeRelationId, RowExclusiveLock);
5963 
5964 	tuple = SearchSysCacheCopyAttName(RelationGetRelid(rel), colName);
5965 	if (!HeapTupleIsValid(tuple))
5966 		ereport(ERROR,
5967 				(errcode(ERRCODE_UNDEFINED_COLUMN),
5968 				 errmsg("column \"%s\" of relation \"%s\" does not exist",
5969 						colName, RelationGetRelationName(rel))));
5970 	attTup = (Form_pg_attribute) GETSTRUCT(tuple);
5971 	attnum = attTup->attnum;
5972 
5973 	/* Can't alter a system attribute */
5974 	if (attnum <= 0)
5975 		ereport(ERROR,
5976 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
5977 				 errmsg("cannot alter system column \"%s\"",
5978 						colName)));
5979 
5980 	/*
5981 	 * Creating a column as identity implies NOT NULL, so adding the identity
5982 	 * to an existing column that is not NOT NULL would create a state that
5983 	 * cannot be reproduced without contortions.
5984 	 */
5985 	if (!attTup->attnotnull)
5986 		ereport(ERROR,
5987 				(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
5988 				 errmsg("column \"%s\" of relation \"%s\" must be declared NOT NULL before identity can be added",
5989 						colName, RelationGetRelationName(rel))));
5990 
5991 	if (attTup->attidentity)
5992 		ereport(ERROR,
5993 				(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
5994 				 errmsg("column \"%s\" of relation \"%s\" is already an identity column",
5995 						colName, RelationGetRelationName(rel))));
5996 
5997 	if (attTup->atthasdef)
5998 		ereport(ERROR,
5999 				(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
6000 				 errmsg("column \"%s\" of relation \"%s\" already has a default value",
6001 						colName, RelationGetRelationName(rel))));
6002 
6003 	attTup->attidentity = cdef->identity;
6004 	CatalogTupleUpdate(attrelation, &tuple->t_self, tuple);
6005 
6006 	InvokeObjectPostAlterHook(RelationRelationId,
6007 							  RelationGetRelid(rel),
6008 							  attTup->attnum);
6009 	ObjectAddressSubSet(address, RelationRelationId,
6010 						RelationGetRelid(rel), attnum);
6011 	heap_freetuple(tuple);
6012 
6013 	heap_close(attrelation, RowExclusiveLock);
6014 
6015 	return address;
6016 }
6017 
6018 /*
6019  * ALTER TABLE ALTER COLUMN SET { GENERATED or sequence options }
6020  *
6021  * Return the address of the affected column.
6022  */
6023 static ObjectAddress
ATExecSetIdentity(Relation rel,const char * colName,Node * def,LOCKMODE lockmode)6024 ATExecSetIdentity(Relation rel, const char *colName, Node *def, LOCKMODE lockmode)
6025 {
6026 	ListCell   *option;
6027 	DefElem    *generatedEl = NULL;
6028 	HeapTuple	tuple;
6029 	Form_pg_attribute attTup;
6030 	AttrNumber	attnum;
6031 	Relation	attrelation;
6032 	ObjectAddress address;
6033 
6034 	foreach(option, castNode(List, def))
6035 	{
6036 		DefElem    *defel = lfirst_node(DefElem, option);
6037 
6038 		if (strcmp(defel->defname, "generated") == 0)
6039 		{
6040 			if (generatedEl)
6041 				ereport(ERROR,
6042 						(errcode(ERRCODE_SYNTAX_ERROR),
6043 						 errmsg("conflicting or redundant options")));
6044 			generatedEl = defel;
6045 		}
6046 		else
6047 			elog(ERROR, "option \"%s\" not recognized",
6048 				 defel->defname);
6049 	}
6050 
6051 	/*
6052 	 * Even if there is nothing to change here, we run all the checks.  There
6053 	 * will be a subsequent ALTER SEQUENCE that relies on everything being
6054 	 * there.
6055 	 */
6056 
6057 	attrelation = heap_open(AttributeRelationId, RowExclusiveLock);
6058 	tuple = SearchSysCacheCopyAttName(RelationGetRelid(rel), colName);
6059 	if (!HeapTupleIsValid(tuple))
6060 		ereport(ERROR,
6061 				(errcode(ERRCODE_UNDEFINED_COLUMN),
6062 				 errmsg("column \"%s\" of relation \"%s\" does not exist",
6063 						colName, RelationGetRelationName(rel))));
6064 
6065 	attTup = (Form_pg_attribute) GETSTRUCT(tuple);
6066 	attnum = attTup->attnum;
6067 
6068 	if (attnum <= 0)
6069 		ereport(ERROR,
6070 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
6071 				 errmsg("cannot alter system column \"%s\"",
6072 						colName)));
6073 
6074 	if (!attTup->attidentity)
6075 		ereport(ERROR,
6076 				(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
6077 				 errmsg("column \"%s\" of relation \"%s\" is not an identity column",
6078 						colName, RelationGetRelationName(rel))));
6079 
6080 	if (generatedEl)
6081 	{
6082 		attTup->attidentity = defGetInt32(generatedEl);
6083 		CatalogTupleUpdate(attrelation, &tuple->t_self, tuple);
6084 
6085 		InvokeObjectPostAlterHook(RelationRelationId,
6086 								  RelationGetRelid(rel),
6087 								  attTup->attnum);
6088 		ObjectAddressSubSet(address, RelationRelationId,
6089 							RelationGetRelid(rel), attnum);
6090 	}
6091 	else
6092 		address = InvalidObjectAddress;
6093 
6094 	heap_freetuple(tuple);
6095 	heap_close(attrelation, RowExclusiveLock);
6096 
6097 	return address;
6098 }
6099 
6100 /*
6101  * ALTER TABLE ALTER COLUMN DROP IDENTITY
6102  *
6103  * Return the address of the affected column.
6104  */
6105 static ObjectAddress
ATExecDropIdentity(Relation rel,const char * colName,bool missing_ok,LOCKMODE lockmode)6106 ATExecDropIdentity(Relation rel, const char *colName, bool missing_ok, LOCKMODE lockmode)
6107 {
6108 	HeapTuple	tuple;
6109 	Form_pg_attribute attTup;
6110 	AttrNumber	attnum;
6111 	Relation	attrelation;
6112 	ObjectAddress address;
6113 	Oid			seqid;
6114 	ObjectAddress seqaddress;
6115 
6116 	attrelation = heap_open(AttributeRelationId, RowExclusiveLock);
6117 	tuple = SearchSysCacheCopyAttName(RelationGetRelid(rel), colName);
6118 	if (!HeapTupleIsValid(tuple))
6119 		ereport(ERROR,
6120 				(errcode(ERRCODE_UNDEFINED_COLUMN),
6121 				 errmsg("column \"%s\" of relation \"%s\" does not exist",
6122 						colName, RelationGetRelationName(rel))));
6123 
6124 	attTup = (Form_pg_attribute) GETSTRUCT(tuple);
6125 	attnum = attTup->attnum;
6126 
6127 	if (attnum <= 0)
6128 		ereport(ERROR,
6129 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
6130 				 errmsg("cannot alter system column \"%s\"",
6131 						colName)));
6132 
6133 	if (!attTup->attidentity)
6134 	{
6135 		if (!missing_ok)
6136 			ereport(ERROR,
6137 					(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
6138 					 errmsg("column \"%s\" of relation \"%s\" is not an identity column",
6139 							colName, RelationGetRelationName(rel))));
6140 		else
6141 		{
6142 			ereport(NOTICE,
6143 					(errmsg("column \"%s\" of relation \"%s\" is not an identity column, skipping",
6144 							colName, RelationGetRelationName(rel))));
6145 			heap_freetuple(tuple);
6146 			heap_close(attrelation, RowExclusiveLock);
6147 			return InvalidObjectAddress;
6148 		}
6149 	}
6150 
6151 	attTup->attidentity = '\0';
6152 	CatalogTupleUpdate(attrelation, &tuple->t_self, tuple);
6153 
6154 	InvokeObjectPostAlterHook(RelationRelationId,
6155 							  RelationGetRelid(rel),
6156 							  attTup->attnum);
6157 	ObjectAddressSubSet(address, RelationRelationId,
6158 						RelationGetRelid(rel), attnum);
6159 	heap_freetuple(tuple);
6160 
6161 	heap_close(attrelation, RowExclusiveLock);
6162 
6163 	/* drop the internal sequence */
6164 	seqid = getOwnedSequence(RelationGetRelid(rel), attnum);
6165 	deleteDependencyRecordsForClass(RelationRelationId, seqid,
6166 									RelationRelationId, DEPENDENCY_INTERNAL);
6167 	CommandCounterIncrement();
6168 	seqaddress.classId = RelationRelationId;
6169 	seqaddress.objectId = seqid;
6170 	seqaddress.objectSubId = 0;
6171 	performDeletion(&seqaddress, DROP_RESTRICT, PERFORM_DELETION_INTERNAL);
6172 
6173 	return address;
6174 }
6175 
6176 /*
6177  * ALTER TABLE ALTER COLUMN SET STATISTICS
6178  */
6179 static void
ATPrepSetStatistics(Relation rel,const char * colName,Node * newValue,LOCKMODE lockmode)6180 ATPrepSetStatistics(Relation rel, const char *colName, Node *newValue, LOCKMODE lockmode)
6181 {
6182 	/*
6183 	 * We do our own permission checking because (a) we want to allow SET
6184 	 * STATISTICS on indexes (for expressional index columns), and (b) we want
6185 	 * to allow SET STATISTICS on system catalogs without requiring
6186 	 * allowSystemTableMods to be turned on.
6187 	 */
6188 	if (rel->rd_rel->relkind != RELKIND_RELATION &&
6189 		rel->rd_rel->relkind != RELKIND_MATVIEW &&
6190 		rel->rd_rel->relkind != RELKIND_INDEX &&
6191 		rel->rd_rel->relkind != RELKIND_FOREIGN_TABLE &&
6192 		rel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
6193 		ereport(ERROR,
6194 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
6195 				 errmsg("\"%s\" is not a table, materialized view, index, or foreign table",
6196 						RelationGetRelationName(rel))));
6197 
6198 	/* Permissions checks */
6199 	if (!pg_class_ownercheck(RelationGetRelid(rel), GetUserId()))
6200 		aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS,
6201 					   RelationGetRelationName(rel));
6202 }
6203 
6204 /*
6205  * Return value is the address of the modified column
6206  */
6207 static ObjectAddress
ATExecSetStatistics(Relation rel,const char * colName,Node * newValue,LOCKMODE lockmode)6208 ATExecSetStatistics(Relation rel, const char *colName, Node *newValue, LOCKMODE lockmode)
6209 {
6210 	int			newtarget;
6211 	Relation	attrelation;
6212 	HeapTuple	tuple;
6213 	Form_pg_attribute attrtuple;
6214 	AttrNumber	attnum;
6215 	ObjectAddress address;
6216 
6217 	Assert(IsA(newValue, Integer));
6218 	newtarget = intVal(newValue);
6219 
6220 	/*
6221 	 * Limit target to a sane range
6222 	 */
6223 	if (newtarget < -1)
6224 	{
6225 		ereport(ERROR,
6226 				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
6227 				 errmsg("statistics target %d is too low",
6228 						newtarget)));
6229 	}
6230 	else if (newtarget > 10000)
6231 	{
6232 		newtarget = 10000;
6233 		ereport(WARNING,
6234 				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
6235 				 errmsg("lowering statistics target to %d",
6236 						newtarget)));
6237 	}
6238 
6239 	attrelation = heap_open(AttributeRelationId, RowExclusiveLock);
6240 
6241 	tuple = SearchSysCacheCopyAttName(RelationGetRelid(rel), colName);
6242 
6243 	if (!HeapTupleIsValid(tuple))
6244 		ereport(ERROR,
6245 				(errcode(ERRCODE_UNDEFINED_COLUMN),
6246 				 errmsg("column \"%s\" of relation \"%s\" does not exist",
6247 						colName, RelationGetRelationName(rel))));
6248 	attrtuple = (Form_pg_attribute) GETSTRUCT(tuple);
6249 
6250 	attnum = attrtuple->attnum;
6251 	if (attnum <= 0)
6252 		ereport(ERROR,
6253 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
6254 				 errmsg("cannot alter system column \"%s\"",
6255 						colName)));
6256 
6257 	attrtuple->attstattarget = newtarget;
6258 
6259 	CatalogTupleUpdate(attrelation, &tuple->t_self, tuple);
6260 
6261 	InvokeObjectPostAlterHook(RelationRelationId,
6262 							  RelationGetRelid(rel),
6263 							  attrtuple->attnum);
6264 	ObjectAddressSubSet(address, RelationRelationId,
6265 						RelationGetRelid(rel), attnum);
6266 	heap_freetuple(tuple);
6267 
6268 	heap_close(attrelation, RowExclusiveLock);
6269 
6270 	return address;
6271 }
6272 
6273 /*
6274  * Return value is the address of the modified column
6275  */
6276 static ObjectAddress
ATExecSetOptions(Relation rel,const char * colName,Node * options,bool isReset,LOCKMODE lockmode)6277 ATExecSetOptions(Relation rel, const char *colName, Node *options,
6278 				 bool isReset, LOCKMODE lockmode)
6279 {
6280 	Relation	attrelation;
6281 	HeapTuple	tuple,
6282 				newtuple;
6283 	Form_pg_attribute attrtuple;
6284 	AttrNumber	attnum;
6285 	Datum		datum,
6286 				newOptions;
6287 	bool		isnull;
6288 	ObjectAddress address;
6289 	Datum		repl_val[Natts_pg_attribute];
6290 	bool		repl_null[Natts_pg_attribute];
6291 	bool		repl_repl[Natts_pg_attribute];
6292 
6293 	attrelation = heap_open(AttributeRelationId, RowExclusiveLock);
6294 
6295 	tuple = SearchSysCacheAttName(RelationGetRelid(rel), colName);
6296 
6297 	if (!HeapTupleIsValid(tuple))
6298 		ereport(ERROR,
6299 				(errcode(ERRCODE_UNDEFINED_COLUMN),
6300 				 errmsg("column \"%s\" of relation \"%s\" does not exist",
6301 						colName, RelationGetRelationName(rel))));
6302 	attrtuple = (Form_pg_attribute) GETSTRUCT(tuple);
6303 
6304 	attnum = attrtuple->attnum;
6305 	if (attnum <= 0)
6306 		ereport(ERROR,
6307 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
6308 				 errmsg("cannot alter system column \"%s\"",
6309 						colName)));
6310 
6311 	/* Generate new proposed attoptions (text array) */
6312 	datum = SysCacheGetAttr(ATTNAME, tuple, Anum_pg_attribute_attoptions,
6313 							&isnull);
6314 	newOptions = transformRelOptions(isnull ? (Datum) 0 : datum,
6315 									 castNode(List, options), NULL, NULL,
6316 									 false, isReset);
6317 	/* Validate new options */
6318 	(void) attribute_reloptions(newOptions, true);
6319 
6320 	/* Build new tuple. */
6321 	memset(repl_null, false, sizeof(repl_null));
6322 	memset(repl_repl, false, sizeof(repl_repl));
6323 	if (newOptions != (Datum) 0)
6324 		repl_val[Anum_pg_attribute_attoptions - 1] = newOptions;
6325 	else
6326 		repl_null[Anum_pg_attribute_attoptions - 1] = true;
6327 	repl_repl[Anum_pg_attribute_attoptions - 1] = true;
6328 	newtuple = heap_modify_tuple(tuple, RelationGetDescr(attrelation),
6329 								 repl_val, repl_null, repl_repl);
6330 
6331 	/* Update system catalog. */
6332 	CatalogTupleUpdate(attrelation, &newtuple->t_self, newtuple);
6333 
6334 	InvokeObjectPostAlterHook(RelationRelationId,
6335 							  RelationGetRelid(rel),
6336 							  attrtuple->attnum);
6337 	ObjectAddressSubSet(address, RelationRelationId,
6338 						RelationGetRelid(rel), attnum);
6339 
6340 	heap_freetuple(newtuple);
6341 
6342 	ReleaseSysCache(tuple);
6343 
6344 	heap_close(attrelation, RowExclusiveLock);
6345 
6346 	return address;
6347 }
6348 
6349 /*
6350  * ALTER TABLE ALTER COLUMN SET STORAGE
6351  *
6352  * Return value is the address of the modified column
6353  */
6354 static ObjectAddress
ATExecSetStorage(Relation rel,const char * colName,Node * newValue,LOCKMODE lockmode)6355 ATExecSetStorage(Relation rel, const char *colName, Node *newValue, LOCKMODE lockmode)
6356 {
6357 	char	   *storagemode;
6358 	char		newstorage;
6359 	Relation	attrelation;
6360 	HeapTuple	tuple;
6361 	Form_pg_attribute attrtuple;
6362 	AttrNumber	attnum;
6363 	ObjectAddress address;
6364 
6365 	Assert(IsA(newValue, String));
6366 	storagemode = strVal(newValue);
6367 
6368 	if (pg_strcasecmp(storagemode, "plain") == 0)
6369 		newstorage = 'p';
6370 	else if (pg_strcasecmp(storagemode, "external") == 0)
6371 		newstorage = 'e';
6372 	else if (pg_strcasecmp(storagemode, "extended") == 0)
6373 		newstorage = 'x';
6374 	else if (pg_strcasecmp(storagemode, "main") == 0)
6375 		newstorage = 'm';
6376 	else
6377 	{
6378 		ereport(ERROR,
6379 				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
6380 				 errmsg("invalid storage type \"%s\"",
6381 						storagemode)));
6382 		newstorage = 0;			/* keep compiler quiet */
6383 	}
6384 
6385 	attrelation = heap_open(AttributeRelationId, RowExclusiveLock);
6386 
6387 	tuple = SearchSysCacheCopyAttName(RelationGetRelid(rel), colName);
6388 
6389 	if (!HeapTupleIsValid(tuple))
6390 		ereport(ERROR,
6391 				(errcode(ERRCODE_UNDEFINED_COLUMN),
6392 				 errmsg("column \"%s\" of relation \"%s\" does not exist",
6393 						colName, RelationGetRelationName(rel))));
6394 	attrtuple = (Form_pg_attribute) GETSTRUCT(tuple);
6395 
6396 	attnum = attrtuple->attnum;
6397 	if (attnum <= 0)
6398 		ereport(ERROR,
6399 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
6400 				 errmsg("cannot alter system column \"%s\"",
6401 						colName)));
6402 
6403 	/*
6404 	 * safety check: do not allow toasted storage modes unless column datatype
6405 	 * is TOAST-aware.
6406 	 */
6407 	if (newstorage == 'p' || TypeIsToastable(attrtuple->atttypid))
6408 		attrtuple->attstorage = newstorage;
6409 	else
6410 		ereport(ERROR,
6411 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
6412 				 errmsg("column data type %s can only have storage PLAIN",
6413 						format_type_be(attrtuple->atttypid))));
6414 
6415 	CatalogTupleUpdate(attrelation, &tuple->t_self, tuple);
6416 
6417 	InvokeObjectPostAlterHook(RelationRelationId,
6418 							  RelationGetRelid(rel),
6419 							  attrtuple->attnum);
6420 
6421 	heap_freetuple(tuple);
6422 
6423 	heap_close(attrelation, RowExclusiveLock);
6424 
6425 	ObjectAddressSubSet(address, RelationRelationId,
6426 						RelationGetRelid(rel), attnum);
6427 	return address;
6428 }
6429 
6430 
6431 /*
6432  * ALTER TABLE DROP COLUMN
6433  *
6434  * DROP COLUMN cannot use the normal ALTER TABLE recursion mechanism,
6435  * because we have to decide at runtime whether to recurse or not depending
6436  * on whether attinhcount goes to zero or not.  (We can't check this in a
6437  * static pre-pass because it won't handle multiple inheritance situations
6438  * correctly.)
6439  */
6440 static void
ATPrepDropColumn(List ** wqueue,Relation rel,bool recurse,bool recursing,AlterTableCmd * cmd,LOCKMODE lockmode)6441 ATPrepDropColumn(List **wqueue, Relation rel, bool recurse, bool recursing,
6442 				 AlterTableCmd *cmd, LOCKMODE lockmode)
6443 {
6444 	if (rel->rd_rel->reloftype && !recursing)
6445 		ereport(ERROR,
6446 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
6447 				 errmsg("cannot drop column from typed table")));
6448 
6449 	if (rel->rd_rel->relkind == RELKIND_COMPOSITE_TYPE)
6450 		ATTypedTableRecursion(wqueue, rel, cmd, lockmode);
6451 
6452 	if (recurse)
6453 		cmd->subtype = AT_DropColumnRecurse;
6454 }
6455 
6456 /*
6457  * Checks if attnum is a partition attribute for rel
6458  *
6459  * Sets *used_in_expr if attnum is found to be referenced in some partition
6460  * key expression.  It's possible for a column to be both used directly and
6461  * as part of an expression; if that happens, *used_in_expr may end up as
6462  * either true or false.  That's OK for current uses of this function, because
6463  * *used_in_expr is only used to tailor the error message text.
6464  */
6465 static bool
is_partition_attr(Relation rel,AttrNumber attnum,bool * used_in_expr)6466 is_partition_attr(Relation rel, AttrNumber attnum, bool *used_in_expr)
6467 {
6468 	PartitionKey key;
6469 	int			partnatts;
6470 	List	   *partexprs;
6471 	ListCell   *partexprs_item;
6472 	int			i;
6473 
6474 	if (rel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
6475 		return false;
6476 
6477 	key = RelationGetPartitionKey(rel);
6478 	partnatts = get_partition_natts(key);
6479 	partexprs = get_partition_exprs(key);
6480 
6481 	partexprs_item = list_head(partexprs);
6482 	for (i = 0; i < partnatts; i++)
6483 	{
6484 		AttrNumber	partattno = get_partition_col_attnum(key, i);
6485 
6486 		if (partattno != 0)
6487 		{
6488 			if (attnum == partattno)
6489 			{
6490 				if (used_in_expr)
6491 					*used_in_expr = false;
6492 				return true;
6493 			}
6494 		}
6495 		else
6496 		{
6497 			/* Arbitrary expression */
6498 			Node	   *expr = (Node *) lfirst(partexprs_item);
6499 			Bitmapset  *expr_attrs = NULL;
6500 
6501 			/* Find all attributes referenced */
6502 			pull_varattnos(expr, 1, &expr_attrs);
6503 			partexprs_item = lnext(partexprs_item);
6504 
6505 			if (bms_is_member(attnum - FirstLowInvalidHeapAttributeNumber,
6506 							  expr_attrs))
6507 			{
6508 				if (used_in_expr)
6509 					*used_in_expr = true;
6510 				return true;
6511 			}
6512 		}
6513 	}
6514 
6515 	return false;
6516 }
6517 
6518 /*
6519  * Return value is the address of the dropped column.
6520  */
6521 static ObjectAddress
ATExecDropColumn(List ** wqueue,Relation rel,const char * colName,DropBehavior behavior,bool recurse,bool recursing,bool missing_ok,LOCKMODE lockmode)6522 ATExecDropColumn(List **wqueue, Relation rel, const char *colName,
6523 				 DropBehavior behavior,
6524 				 bool recurse, bool recursing,
6525 				 bool missing_ok, LOCKMODE lockmode)
6526 {
6527 	HeapTuple	tuple;
6528 	Form_pg_attribute targetatt;
6529 	AttrNumber	attnum;
6530 	List	   *children;
6531 	ObjectAddress object;
6532 	bool		is_expr;
6533 
6534 	/* At top level, permission check was done in ATPrepCmd, else do it */
6535 	if (recursing)
6536 		ATSimplePermissions(rel, ATT_TABLE | ATT_FOREIGN_TABLE);
6537 
6538 	/*
6539 	 * get the number of the attribute
6540 	 */
6541 	tuple = SearchSysCacheAttName(RelationGetRelid(rel), colName);
6542 	if (!HeapTupleIsValid(tuple))
6543 	{
6544 		if (!missing_ok)
6545 		{
6546 			ereport(ERROR,
6547 					(errcode(ERRCODE_UNDEFINED_COLUMN),
6548 					 errmsg("column \"%s\" of relation \"%s\" does not exist",
6549 							colName, RelationGetRelationName(rel))));
6550 		}
6551 		else
6552 		{
6553 			ereport(NOTICE,
6554 					(errmsg("column \"%s\" of relation \"%s\" does not exist, skipping",
6555 							colName, RelationGetRelationName(rel))));
6556 			return InvalidObjectAddress;
6557 		}
6558 	}
6559 	targetatt = (Form_pg_attribute) GETSTRUCT(tuple);
6560 
6561 	attnum = targetatt->attnum;
6562 
6563 	/* Can't drop a system attribute, except OID */
6564 	if (attnum <= 0 && attnum != ObjectIdAttributeNumber)
6565 		ereport(ERROR,
6566 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
6567 				 errmsg("cannot drop system column \"%s\"",
6568 						colName)));
6569 
6570 	/*
6571 	 * Don't drop inherited columns, unless recursing (presumably from a drop
6572 	 * of the parent column)
6573 	 */
6574 	if (targetatt->attinhcount > 0 && !recursing)
6575 		ereport(ERROR,
6576 				(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
6577 				 errmsg("cannot drop inherited column \"%s\"",
6578 						colName)));
6579 
6580 	/*
6581 	 * Don't drop columns used in the partition key, either.  (If we let this
6582 	 * go through, the key column's dependencies would cause a cascaded drop
6583 	 * of the whole table, which is surely not what the user expected.)
6584 	 */
6585 	if (is_partition_attr(rel, attnum, &is_expr))
6586 		ereport(ERROR,
6587 				(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
6588 				 errmsg("cannot drop column \"%s\" because it is part of the partition key of relation \"%s\"",
6589 						colName, RelationGetRelationName(rel))));
6590 
6591 	ReleaseSysCache(tuple);
6592 
6593 	/*
6594 	 * Propagate to children as appropriate.  Unlike most other ALTER
6595 	 * routines, we have to do this one level of recursion at a time; we can't
6596 	 * use find_all_inheritors to do it in one pass.
6597 	 */
6598 	children = find_inheritance_children(RelationGetRelid(rel), lockmode);
6599 
6600 	if (children)
6601 	{
6602 		Relation	attr_rel;
6603 		ListCell   *child;
6604 
6605 		/*
6606 		 * In case of a partitioned table, the column must be dropped from the
6607 		 * partitions as well.
6608 		 */
6609 		if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE && !recurse)
6610 			ereport(ERROR,
6611 					(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
6612 					 errmsg("cannot drop column from only the partitioned table when partitions exist"),
6613 					 errhint("Do not specify the ONLY keyword.")));
6614 
6615 		attr_rel = heap_open(AttributeRelationId, RowExclusiveLock);
6616 		foreach(child, children)
6617 		{
6618 			Oid			childrelid = lfirst_oid(child);
6619 			Relation	childrel;
6620 			Form_pg_attribute childatt;
6621 
6622 			/* find_inheritance_children already got lock */
6623 			childrel = heap_open(childrelid, NoLock);
6624 			CheckTableNotInUse(childrel, "ALTER TABLE");
6625 
6626 			tuple = SearchSysCacheCopyAttName(childrelid, colName);
6627 			if (!HeapTupleIsValid(tuple))	/* shouldn't happen */
6628 				elog(ERROR, "cache lookup failed for attribute \"%s\" of relation %u",
6629 					 colName, childrelid);
6630 			childatt = (Form_pg_attribute) GETSTRUCT(tuple);
6631 
6632 			if (childatt->attinhcount <= 0) /* shouldn't happen */
6633 				elog(ERROR, "relation %u has non-inherited attribute \"%s\"",
6634 					 childrelid, colName);
6635 
6636 			if (recurse)
6637 			{
6638 				/*
6639 				 * If the child column has other definition sources, just
6640 				 * decrement its inheritance count; if not, recurse to delete
6641 				 * it.
6642 				 */
6643 				if (childatt->attinhcount == 1 && !childatt->attislocal)
6644 				{
6645 					/* Time to delete this child column, too */
6646 					ATExecDropColumn(wqueue, childrel, colName,
6647 									 behavior, true, true,
6648 									 false, lockmode);
6649 				}
6650 				else
6651 				{
6652 					/* Child column must survive my deletion */
6653 					childatt->attinhcount--;
6654 
6655 					CatalogTupleUpdate(attr_rel, &tuple->t_self, tuple);
6656 
6657 					/* Make update visible */
6658 					CommandCounterIncrement();
6659 				}
6660 			}
6661 			else
6662 			{
6663 				/*
6664 				 * If we were told to drop ONLY in this table (no recursion),
6665 				 * we need to mark the inheritors' attributes as locally
6666 				 * defined rather than inherited.
6667 				 */
6668 				childatt->attinhcount--;
6669 				childatt->attislocal = true;
6670 
6671 				CatalogTupleUpdate(attr_rel, &tuple->t_self, tuple);
6672 
6673 				/* Make update visible */
6674 				CommandCounterIncrement();
6675 			}
6676 
6677 			heap_freetuple(tuple);
6678 
6679 			heap_close(childrel, NoLock);
6680 		}
6681 		heap_close(attr_rel, RowExclusiveLock);
6682 	}
6683 
6684 	/*
6685 	 * Perform the actual column deletion
6686 	 */
6687 	object.classId = RelationRelationId;
6688 	object.objectId = RelationGetRelid(rel);
6689 	object.objectSubId = attnum;
6690 
6691 	performDeletion(&object, behavior, 0);
6692 
6693 	/*
6694 	 * If we dropped the OID column, must adjust pg_class.relhasoids and tell
6695 	 * Phase 3 to physically get rid of the column.  We formerly left the
6696 	 * column in place physically, but this caused subtle problems.  See
6697 	 * http://archives.postgresql.org/pgsql-hackers/2009-02/msg00363.php
6698 	 */
6699 	if (attnum == ObjectIdAttributeNumber)
6700 	{
6701 		Relation	class_rel;
6702 		Form_pg_class tuple_class;
6703 		AlteredTableInfo *tab;
6704 
6705 		class_rel = heap_open(RelationRelationId, RowExclusiveLock);
6706 
6707 		tuple = SearchSysCacheCopy1(RELOID,
6708 									ObjectIdGetDatum(RelationGetRelid(rel)));
6709 		if (!HeapTupleIsValid(tuple))
6710 			elog(ERROR, "cache lookup failed for relation %u",
6711 				 RelationGetRelid(rel));
6712 		tuple_class = (Form_pg_class) GETSTRUCT(tuple);
6713 
6714 		tuple_class->relhasoids = false;
6715 		CatalogTupleUpdate(class_rel, &tuple->t_self, tuple);
6716 
6717 		heap_close(class_rel, RowExclusiveLock);
6718 
6719 		/* Find or create work queue entry for this table */
6720 		tab = ATGetQueueEntry(wqueue, rel);
6721 
6722 		/* Tell Phase 3 to physically remove the OID column */
6723 		tab->rewrite |= AT_REWRITE_ALTER_OID;
6724 	}
6725 
6726 	return object;
6727 }
6728 
6729 /*
6730  * ALTER TABLE ADD INDEX
6731  *
6732  * There is no such command in the grammar, but parse_utilcmd.c converts
6733  * UNIQUE and PRIMARY KEY constraints into AT_AddIndex subcommands.  This lets
6734  * us schedule creation of the index at the appropriate time during ALTER.
6735  *
6736  * Return value is the address of the new index.
6737  */
6738 static ObjectAddress
ATExecAddIndex(AlteredTableInfo * tab,Relation rel,IndexStmt * stmt,bool is_rebuild,LOCKMODE lockmode)6739 ATExecAddIndex(AlteredTableInfo *tab, Relation rel,
6740 			   IndexStmt *stmt, bool is_rebuild, LOCKMODE lockmode)
6741 {
6742 	bool		check_rights;
6743 	bool		skip_build;
6744 	bool		quiet;
6745 	ObjectAddress address;
6746 
6747 	Assert(IsA(stmt, IndexStmt));
6748 	Assert(!stmt->concurrent);
6749 
6750 	/* The IndexStmt has already been through transformIndexStmt */
6751 	Assert(stmt->transformed);
6752 
6753 	/* suppress schema rights check when rebuilding existing index */
6754 	check_rights = !is_rebuild;
6755 	/* skip index build if phase 3 will do it or we're reusing an old one */
6756 	skip_build = tab->rewrite > 0 || OidIsValid(stmt->oldNode);
6757 	/* suppress notices when rebuilding existing index */
6758 	quiet = is_rebuild;
6759 
6760 	address = DefineIndex(RelationGetRelid(rel),
6761 						  stmt,
6762 						  InvalidOid,	/* no predefined OID */
6763 						  true, /* is_alter_table */
6764 						  check_rights,
6765 						  false,	/* check_not_in_use - we did it already */
6766 						  skip_build,
6767 						  quiet);
6768 
6769 	/*
6770 	 * If TryReuseIndex() stashed a relfilenode for us, we used it for the new
6771 	 * index instead of building from scratch.  The DROP of the old edition of
6772 	 * this index will have scheduled the storage for deletion at commit, so
6773 	 * cancel that pending deletion.
6774 	 */
6775 	if (OidIsValid(stmt->oldNode))
6776 	{
6777 		Relation	irel = index_open(address.objectId, NoLock);
6778 
6779 		RelationPreserveStorage(irel->rd_node, true);
6780 		index_close(irel, NoLock);
6781 	}
6782 
6783 	return address;
6784 }
6785 
6786 /*
6787  * ALTER TABLE ADD CONSTRAINT USING INDEX
6788  *
6789  * Returns the address of the new constraint.
6790  */
6791 static ObjectAddress
ATExecAddIndexConstraint(AlteredTableInfo * tab,Relation rel,IndexStmt * stmt,LOCKMODE lockmode)6792 ATExecAddIndexConstraint(AlteredTableInfo *tab, Relation rel,
6793 						 IndexStmt *stmt, LOCKMODE lockmode)
6794 {
6795 	Oid			index_oid = stmt->indexOid;
6796 	Relation	indexRel;
6797 	char	   *indexName;
6798 	IndexInfo  *indexInfo;
6799 	char	   *constraintName;
6800 	char		constraintType;
6801 	ObjectAddress address;
6802 
6803 	Assert(IsA(stmt, IndexStmt));
6804 	Assert(OidIsValid(index_oid));
6805 	Assert(stmt->isconstraint);
6806 
6807 	indexRel = index_open(index_oid, AccessShareLock);
6808 
6809 	indexName = pstrdup(RelationGetRelationName(indexRel));
6810 
6811 	indexInfo = BuildIndexInfo(indexRel);
6812 
6813 	/* this should have been checked at parse time */
6814 	if (!indexInfo->ii_Unique)
6815 		elog(ERROR, "index \"%s\" is not unique", indexName);
6816 
6817 	/*
6818 	 * Determine name to assign to constraint.  We require a constraint to
6819 	 * have the same name as the underlying index; therefore, use the index's
6820 	 * existing name as the default constraint name, and if the user
6821 	 * explicitly gives some other name for the constraint, rename the index
6822 	 * to match.
6823 	 */
6824 	constraintName = stmt->idxname;
6825 	if (constraintName == NULL)
6826 		constraintName = indexName;
6827 	else if (strcmp(constraintName, indexName) != 0)
6828 	{
6829 		ereport(NOTICE,
6830 				(errmsg("ALTER TABLE / ADD CONSTRAINT USING INDEX will rename index \"%s\" to \"%s\"",
6831 						indexName, constraintName)));
6832 		RenameRelationInternal(index_oid, constraintName, false);
6833 	}
6834 
6835 	/* Extra checks needed if making primary key */
6836 	if (stmt->primary)
6837 		index_check_primary_key(rel, indexInfo, true, stmt);
6838 
6839 	/* Note we currently don't support EXCLUSION constraints here */
6840 	if (stmt->primary)
6841 		constraintType = CONSTRAINT_PRIMARY;
6842 	else
6843 		constraintType = CONSTRAINT_UNIQUE;
6844 
6845 	/* Create the catalog entries for the constraint */
6846 	address = index_constraint_create(rel,
6847 									  index_oid,
6848 									  indexInfo,
6849 									  constraintName,
6850 									  constraintType,
6851 									  stmt->deferrable,
6852 									  stmt->initdeferred,
6853 									  stmt->primary,
6854 									  true, /* update pg_index */
6855 									  true, /* remove old dependencies */
6856 									  allowSystemTableMods,
6857 									  false);	/* is_internal */
6858 
6859 	index_close(indexRel, NoLock);
6860 
6861 	return address;
6862 }
6863 
6864 /*
6865  * ALTER TABLE ADD CONSTRAINT
6866  *
6867  * Return value is the address of the new constraint; if no constraint was
6868  * added, InvalidObjectAddress is returned.
6869  */
6870 static ObjectAddress
ATExecAddConstraint(List ** wqueue,AlteredTableInfo * tab,Relation rel,Constraint * newConstraint,bool recurse,bool is_readd,LOCKMODE lockmode)6871 ATExecAddConstraint(List **wqueue, AlteredTableInfo *tab, Relation rel,
6872 					Constraint *newConstraint, bool recurse, bool is_readd,
6873 					LOCKMODE lockmode)
6874 {
6875 	ObjectAddress address = InvalidObjectAddress;
6876 
6877 	Assert(IsA(newConstraint, Constraint));
6878 
6879 	/*
6880 	 * Currently, we only expect to see CONSTR_CHECK and CONSTR_FOREIGN nodes
6881 	 * arriving here (see the preprocessing done in parse_utilcmd.c).  Use a
6882 	 * switch anyway to make it easier to add more code later.
6883 	 */
6884 	switch (newConstraint->contype)
6885 	{
6886 		case CONSTR_CHECK:
6887 			address =
6888 				ATAddCheckConstraint(wqueue, tab, rel,
6889 									 newConstraint, recurse, false, is_readd,
6890 									 lockmode);
6891 			break;
6892 
6893 		case CONSTR_FOREIGN:
6894 
6895 			/*
6896 			 * Note that we currently never recurse for FK constraints, so the
6897 			 * "recurse" flag is silently ignored.
6898 			 *
6899 			 * Assign or validate constraint name
6900 			 */
6901 			if (newConstraint->conname)
6902 			{
6903 				if (ConstraintNameIsUsed(CONSTRAINT_RELATION,
6904 										 RelationGetRelid(rel),
6905 										 RelationGetNamespace(rel),
6906 										 newConstraint->conname))
6907 					ereport(ERROR,
6908 							(errcode(ERRCODE_DUPLICATE_OBJECT),
6909 							 errmsg("constraint \"%s\" for relation \"%s\" already exists",
6910 									newConstraint->conname,
6911 									RelationGetRelationName(rel))));
6912 			}
6913 			else
6914 				newConstraint->conname =
6915 					ChooseConstraintName(RelationGetRelationName(rel),
6916 										 strVal(linitial(newConstraint->fk_attrs)),
6917 										 "fkey",
6918 										 RelationGetNamespace(rel),
6919 										 NIL);
6920 
6921 			address = ATAddForeignKeyConstraint(tab, rel, newConstraint,
6922 												lockmode);
6923 			break;
6924 
6925 		default:
6926 			elog(ERROR, "unrecognized constraint type: %d",
6927 				 (int) newConstraint->contype);
6928 	}
6929 
6930 	return address;
6931 }
6932 
6933 /*
6934  * Add a check constraint to a single table and its children.  Returns the
6935  * address of the constraint added to the parent relation, if one gets added,
6936  * or InvalidObjectAddress otherwise.
6937  *
6938  * Subroutine for ATExecAddConstraint.
6939  *
6940  * We must recurse to child tables during execution, rather than using
6941  * ALTER TABLE's normal prep-time recursion.  The reason is that all the
6942  * constraints *must* be given the same name, else they won't be seen as
6943  * related later.  If the user didn't explicitly specify a name, then
6944  * AddRelationNewConstraints would normally assign different names to the
6945  * child constraints.  To fix that, we must capture the name assigned at
6946  * the parent table and pass that down.
6947  */
6948 static ObjectAddress
ATAddCheckConstraint(List ** wqueue,AlteredTableInfo * tab,Relation rel,Constraint * constr,bool recurse,bool recursing,bool is_readd,LOCKMODE lockmode)6949 ATAddCheckConstraint(List **wqueue, AlteredTableInfo *tab, Relation rel,
6950 					 Constraint *constr, bool recurse, bool recursing,
6951 					 bool is_readd, LOCKMODE lockmode)
6952 {
6953 	List	   *newcons;
6954 	ListCell   *lcon;
6955 	List	   *children;
6956 	ListCell   *child;
6957 	ObjectAddress address = InvalidObjectAddress;
6958 
6959 	/* At top level, permission check was done in ATPrepCmd, else do it */
6960 	if (recursing)
6961 		ATSimplePermissions(rel, ATT_TABLE | ATT_FOREIGN_TABLE);
6962 
6963 	/*
6964 	 * Call AddRelationNewConstraints to do the work, making sure it works on
6965 	 * a copy of the Constraint so transformExpr can't modify the original. It
6966 	 * returns a list of cooked constraints.
6967 	 *
6968 	 * If the constraint ends up getting merged with a pre-existing one, it's
6969 	 * omitted from the returned list, which is what we want: we do not need
6970 	 * to do any validation work.  That can only happen at child tables,
6971 	 * though, since we disallow merging at the top level.
6972 	 */
6973 	newcons = AddRelationNewConstraints(rel, NIL,
6974 										list_make1(copyObject(constr)),
6975 										recursing | is_readd,	/* allow_merge */
6976 										!recursing, /* is_local */
6977 										is_readd);	/* is_internal */
6978 
6979 	/* we don't expect more than one constraint here */
6980 	Assert(list_length(newcons) <= 1);
6981 
6982 	/* Add each to-be-validated constraint to Phase 3's queue */
6983 	foreach(lcon, newcons)
6984 	{
6985 		CookedConstraint *ccon = (CookedConstraint *) lfirst(lcon);
6986 
6987 		if (!ccon->skip_validation)
6988 		{
6989 			NewConstraint *newcon;
6990 
6991 			newcon = (NewConstraint *) palloc0(sizeof(NewConstraint));
6992 			newcon->name = ccon->name;
6993 			newcon->contype = ccon->contype;
6994 			newcon->qual = ccon->expr;
6995 
6996 			tab->constraints = lappend(tab->constraints, newcon);
6997 		}
6998 
6999 		/* Save the actually assigned name if it was defaulted */
7000 		if (constr->conname == NULL)
7001 			constr->conname = ccon->name;
7002 
7003 		ObjectAddressSet(address, ConstraintRelationId, ccon->conoid);
7004 	}
7005 
7006 	/* At this point we must have a locked-down name to use */
7007 	Assert(constr->conname != NULL);
7008 
7009 	/* Advance command counter in case same table is visited multiple times */
7010 	CommandCounterIncrement();
7011 
7012 	/*
7013 	 * If the constraint got merged with an existing constraint, we're done.
7014 	 * We mustn't recurse to child tables in this case, because they've
7015 	 * already got the constraint, and visiting them again would lead to an
7016 	 * incorrect value for coninhcount.
7017 	 */
7018 	if (newcons == NIL)
7019 		return address;
7020 
7021 	/*
7022 	 * If adding a NO INHERIT constraint, no need to find our children.
7023 	 */
7024 	if (constr->is_no_inherit)
7025 		return address;
7026 
7027 	/*
7028 	 * Propagate to children as appropriate.  Unlike most other ALTER
7029 	 * routines, we have to do this one level of recursion at a time; we can't
7030 	 * use find_all_inheritors to do it in one pass.
7031 	 */
7032 	children = find_inheritance_children(RelationGetRelid(rel), lockmode);
7033 
7034 	/*
7035 	 * Check if ONLY was specified with ALTER TABLE.  If so, allow the
7036 	 * constraint creation only if there are no children currently.  Error out
7037 	 * otherwise.
7038 	 */
7039 	if (!recurse && children != NIL)
7040 		ereport(ERROR,
7041 				(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
7042 				 errmsg("constraint must be added to child tables too")));
7043 
7044 	foreach(child, children)
7045 	{
7046 		Oid			childrelid = lfirst_oid(child);
7047 		Relation	childrel;
7048 		AlteredTableInfo *childtab;
7049 
7050 		/* find_inheritance_children already got lock */
7051 		childrel = heap_open(childrelid, NoLock);
7052 		CheckTableNotInUse(childrel, "ALTER TABLE");
7053 
7054 		/* Find or create work queue entry for this table */
7055 		childtab = ATGetQueueEntry(wqueue, childrel);
7056 
7057 		/* Recurse to child */
7058 		ATAddCheckConstraint(wqueue, childtab, childrel,
7059 							 constr, recurse, true, is_readd, lockmode);
7060 
7061 		heap_close(childrel, NoLock);
7062 	}
7063 
7064 	return address;
7065 }
7066 
7067 /*
7068  * Add a foreign-key constraint to a single table; return the new constraint's
7069  * address.
7070  *
7071  * Subroutine for ATExecAddConstraint.  Must already hold exclusive
7072  * lock on the rel, and have done appropriate validity checks for it.
7073  * We do permissions checks here, however.
7074  */
7075 static ObjectAddress
ATAddForeignKeyConstraint(AlteredTableInfo * tab,Relation rel,Constraint * fkconstraint,LOCKMODE lockmode)7076 ATAddForeignKeyConstraint(AlteredTableInfo *tab, Relation rel,
7077 						  Constraint *fkconstraint, LOCKMODE lockmode)
7078 {
7079 	Relation	pkrel;
7080 	int16		pkattnum[INDEX_MAX_KEYS];
7081 	int16		fkattnum[INDEX_MAX_KEYS];
7082 	Oid			pktypoid[INDEX_MAX_KEYS];
7083 	Oid			fktypoid[INDEX_MAX_KEYS];
7084 	Oid			opclasses[INDEX_MAX_KEYS];
7085 	Oid			pfeqoperators[INDEX_MAX_KEYS];
7086 	Oid			ppeqoperators[INDEX_MAX_KEYS];
7087 	Oid			ffeqoperators[INDEX_MAX_KEYS];
7088 	int			i;
7089 	int			numfks,
7090 				numpks;
7091 	Oid			indexOid;
7092 	Oid			constrOid;
7093 	bool		old_check_ok;
7094 	ObjectAddress address;
7095 	ListCell   *old_pfeqop_item = list_head(fkconstraint->old_conpfeqop);
7096 
7097 	/*
7098 	 * Grab ShareRowExclusiveLock on the pk table, so that someone doesn't
7099 	 * delete rows out from under us.
7100 	 */
7101 	if (OidIsValid(fkconstraint->old_pktable_oid))
7102 		pkrel = heap_open(fkconstraint->old_pktable_oid, ShareRowExclusiveLock);
7103 	else
7104 		pkrel = heap_openrv(fkconstraint->pktable, ShareRowExclusiveLock);
7105 
7106 	/*
7107 	 * Validity checks (permission checks wait till we have the column
7108 	 * numbers)
7109 	 */
7110 	if (pkrel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
7111 		ereport(ERROR,
7112 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
7113 				 errmsg("cannot reference partitioned table \"%s\"",
7114 						RelationGetRelationName(pkrel))));
7115 
7116 	if (pkrel->rd_rel->relkind != RELKIND_RELATION)
7117 		ereport(ERROR,
7118 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
7119 				 errmsg("referenced relation \"%s\" is not a table",
7120 						RelationGetRelationName(pkrel))));
7121 
7122 	if (!allowSystemTableMods && IsSystemRelation(pkrel))
7123 		ereport(ERROR,
7124 				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
7125 				 errmsg("permission denied: \"%s\" is a system catalog",
7126 						RelationGetRelationName(pkrel))));
7127 
7128 	/*
7129 	 * References from permanent or unlogged tables to temp tables, and from
7130 	 * permanent tables to unlogged tables, are disallowed because the
7131 	 * referenced data can vanish out from under us.  References from temp
7132 	 * tables to any other table type are also disallowed, because other
7133 	 * backends might need to run the RI triggers on the perm table, but they
7134 	 * can't reliably see tuples in the local buffers of other backends.
7135 	 */
7136 	switch (rel->rd_rel->relpersistence)
7137 	{
7138 		case RELPERSISTENCE_PERMANENT:
7139 			if (pkrel->rd_rel->relpersistence != RELPERSISTENCE_PERMANENT)
7140 				ereport(ERROR,
7141 						(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
7142 						 errmsg("constraints on permanent tables may reference only permanent tables")));
7143 			break;
7144 		case RELPERSISTENCE_UNLOGGED:
7145 			if (pkrel->rd_rel->relpersistence != RELPERSISTENCE_PERMANENT
7146 				&& pkrel->rd_rel->relpersistence != RELPERSISTENCE_UNLOGGED)
7147 				ereport(ERROR,
7148 						(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
7149 						 errmsg("constraints on unlogged tables may reference only permanent or unlogged tables")));
7150 			break;
7151 		case RELPERSISTENCE_TEMP:
7152 			if (pkrel->rd_rel->relpersistence != RELPERSISTENCE_TEMP)
7153 				ereport(ERROR,
7154 						(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
7155 						 errmsg("constraints on temporary tables may reference only temporary tables")));
7156 			if (!pkrel->rd_islocaltemp || !rel->rd_islocaltemp)
7157 				ereport(ERROR,
7158 						(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
7159 						 errmsg("constraints on temporary tables must involve temporary tables of this session")));
7160 			break;
7161 	}
7162 
7163 	/*
7164 	 * Look up the referencing attributes to make sure they exist, and record
7165 	 * their attnums and type OIDs.
7166 	 */
7167 	MemSet(pkattnum, 0, sizeof(pkattnum));
7168 	MemSet(fkattnum, 0, sizeof(fkattnum));
7169 	MemSet(pktypoid, 0, sizeof(pktypoid));
7170 	MemSet(fktypoid, 0, sizeof(fktypoid));
7171 	MemSet(opclasses, 0, sizeof(opclasses));
7172 	MemSet(pfeqoperators, 0, sizeof(pfeqoperators));
7173 	MemSet(ppeqoperators, 0, sizeof(ppeqoperators));
7174 	MemSet(ffeqoperators, 0, sizeof(ffeqoperators));
7175 
7176 	numfks = transformColumnNameList(RelationGetRelid(rel),
7177 									 fkconstraint->fk_attrs,
7178 									 fkattnum, fktypoid);
7179 
7180 	/*
7181 	 * If the attribute list for the referenced table was omitted, lookup the
7182 	 * definition of the primary key and use it.  Otherwise, validate the
7183 	 * supplied attribute list.  In either case, discover the index OID and
7184 	 * index opclasses, and the attnums and type OIDs of the attributes.
7185 	 */
7186 	if (fkconstraint->pk_attrs == NIL)
7187 	{
7188 		numpks = transformFkeyGetPrimaryKey(pkrel, &indexOid,
7189 											&fkconstraint->pk_attrs,
7190 											pkattnum, pktypoid,
7191 											opclasses);
7192 	}
7193 	else
7194 	{
7195 		numpks = transformColumnNameList(RelationGetRelid(pkrel),
7196 										 fkconstraint->pk_attrs,
7197 										 pkattnum, pktypoid);
7198 		/* Look for an index matching the column list */
7199 		indexOid = transformFkeyCheckAttrs(pkrel, numpks, pkattnum,
7200 										   opclasses);
7201 	}
7202 
7203 	/*
7204 	 * Now we can check permissions.
7205 	 */
7206 	checkFkeyPermissions(pkrel, pkattnum, numpks);
7207 
7208 	/*
7209 	 * Look up the equality operators to use in the constraint.
7210 	 *
7211 	 * Note that we have to be careful about the difference between the actual
7212 	 * PK column type and the opclass' declared input type, which might be
7213 	 * only binary-compatible with it.  The declared opcintype is the right
7214 	 * thing to probe pg_amop with.
7215 	 */
7216 	if (numfks != numpks)
7217 		ereport(ERROR,
7218 				(errcode(ERRCODE_INVALID_FOREIGN_KEY),
7219 				 errmsg("number of referencing and referenced columns for foreign key disagree")));
7220 
7221 	/*
7222 	 * On the strength of a previous constraint, we might avoid scanning
7223 	 * tables to validate this one.  See below.
7224 	 */
7225 	old_check_ok = (fkconstraint->old_conpfeqop != NIL);
7226 	Assert(!old_check_ok || numfks == list_length(fkconstraint->old_conpfeqop));
7227 
7228 	for (i = 0; i < numpks; i++)
7229 	{
7230 		Oid			pktype = pktypoid[i];
7231 		Oid			fktype = fktypoid[i];
7232 		Oid			fktyped;
7233 		HeapTuple	cla_ht;
7234 		Form_pg_opclass cla_tup;
7235 		Oid			amid;
7236 		Oid			opfamily;
7237 		Oid			opcintype;
7238 		Oid			pfeqop;
7239 		Oid			ppeqop;
7240 		Oid			ffeqop;
7241 		int16		eqstrategy;
7242 		Oid			pfeqop_right;
7243 
7244 		/* We need several fields out of the pg_opclass entry */
7245 		cla_ht = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclasses[i]));
7246 		if (!HeapTupleIsValid(cla_ht))
7247 			elog(ERROR, "cache lookup failed for opclass %u", opclasses[i]);
7248 		cla_tup = (Form_pg_opclass) GETSTRUCT(cla_ht);
7249 		amid = cla_tup->opcmethod;
7250 		opfamily = cla_tup->opcfamily;
7251 		opcintype = cla_tup->opcintype;
7252 		ReleaseSysCache(cla_ht);
7253 
7254 		/*
7255 		 * Check it's a btree; currently this can never fail since no other
7256 		 * index AMs support unique indexes.  If we ever did have other types
7257 		 * of unique indexes, we'd need a way to determine which operator
7258 		 * strategy number is equality.  (Is it reasonable to insist that
7259 		 * every such index AM use btree's number for equality?)
7260 		 */
7261 		if (amid != BTREE_AM_OID)
7262 			elog(ERROR, "only b-tree indexes are supported for foreign keys");
7263 		eqstrategy = BTEqualStrategyNumber;
7264 
7265 		/*
7266 		 * There had better be a primary equality operator for the index.
7267 		 * We'll use it for PK = PK comparisons.
7268 		 */
7269 		ppeqop = get_opfamily_member(opfamily, opcintype, opcintype,
7270 									 eqstrategy);
7271 
7272 		if (!OidIsValid(ppeqop))
7273 			elog(ERROR, "missing operator %d(%u,%u) in opfamily %u",
7274 				 eqstrategy, opcintype, opcintype, opfamily);
7275 
7276 		/*
7277 		 * Are there equality operators that take exactly the FK type? Assume
7278 		 * we should look through any domain here.
7279 		 */
7280 		fktyped = getBaseType(fktype);
7281 
7282 		pfeqop = get_opfamily_member(opfamily, opcintype, fktyped,
7283 									 eqstrategy);
7284 		if (OidIsValid(pfeqop))
7285 		{
7286 			pfeqop_right = fktyped;
7287 			ffeqop = get_opfamily_member(opfamily, fktyped, fktyped,
7288 										 eqstrategy);
7289 		}
7290 		else
7291 		{
7292 			/* keep compiler quiet */
7293 			pfeqop_right = InvalidOid;
7294 			ffeqop = InvalidOid;
7295 		}
7296 
7297 		if (!(OidIsValid(pfeqop) && OidIsValid(ffeqop)))
7298 		{
7299 			/*
7300 			 * Otherwise, look for an implicit cast from the FK type to the
7301 			 * opcintype, and if found, use the primary equality operator.
7302 			 * This is a bit tricky because opcintype might be a polymorphic
7303 			 * type such as ANYARRAY or ANYENUM; so what we have to test is
7304 			 * whether the two actual column types can be concurrently cast to
7305 			 * that type.  (Otherwise, we'd fail to reject combinations such
7306 			 * as int[] and point[].)
7307 			 */
7308 			Oid			input_typeids[2];
7309 			Oid			target_typeids[2];
7310 
7311 			input_typeids[0] = pktype;
7312 			input_typeids[1] = fktype;
7313 			target_typeids[0] = opcintype;
7314 			target_typeids[1] = opcintype;
7315 			if (can_coerce_type(2, input_typeids, target_typeids,
7316 								COERCION_IMPLICIT))
7317 			{
7318 				pfeqop = ffeqop = ppeqop;
7319 				pfeqop_right = opcintype;
7320 			}
7321 		}
7322 
7323 		if (!(OidIsValid(pfeqop) && OidIsValid(ffeqop)))
7324 			ereport(ERROR,
7325 					(errcode(ERRCODE_DATATYPE_MISMATCH),
7326 					 errmsg("foreign key constraint \"%s\" "
7327 							"cannot be implemented",
7328 							fkconstraint->conname),
7329 					 errdetail("Key columns \"%s\" and \"%s\" "
7330 							   "are of incompatible types: %s and %s.",
7331 							   strVal(list_nth(fkconstraint->fk_attrs, i)),
7332 							   strVal(list_nth(fkconstraint->pk_attrs, i)),
7333 							   format_type_be(fktype),
7334 							   format_type_be(pktype))));
7335 
7336 		if (old_check_ok)
7337 		{
7338 			/*
7339 			 * When a pfeqop changes, revalidate the constraint.  We could
7340 			 * permit intra-opfamily changes, but that adds subtle complexity
7341 			 * without any concrete benefit for core types.  We need not
7342 			 * assess ppeqop or ffeqop, which RI_Initial_Check() does not use.
7343 			 */
7344 			old_check_ok = (pfeqop == lfirst_oid(old_pfeqop_item));
7345 			old_pfeqop_item = lnext(old_pfeqop_item);
7346 		}
7347 		if (old_check_ok)
7348 		{
7349 			Oid			old_fktype;
7350 			Oid			new_fktype;
7351 			CoercionPathType old_pathtype;
7352 			CoercionPathType new_pathtype;
7353 			Oid			old_castfunc;
7354 			Oid			new_castfunc;
7355 
7356 			/*
7357 			 * Identify coercion pathways from each of the old and new FK-side
7358 			 * column types to the right (foreign) operand type of the pfeqop.
7359 			 * We may assume that pg_constraint.conkey is not changing.
7360 			 */
7361 			old_fktype = tab->oldDesc->attrs[fkattnum[i] - 1]->atttypid;
7362 			new_fktype = fktype;
7363 			old_pathtype = findFkeyCast(pfeqop_right, old_fktype,
7364 										&old_castfunc);
7365 			new_pathtype = findFkeyCast(pfeqop_right, new_fktype,
7366 										&new_castfunc);
7367 
7368 			/*
7369 			 * Upon a change to the cast from the FK column to its pfeqop
7370 			 * operand, revalidate the constraint.  For this evaluation, a
7371 			 * binary coercion cast is equivalent to no cast at all.  While
7372 			 * type implementors should design implicit casts with an eye
7373 			 * toward consistency of operations like equality, we cannot
7374 			 * assume here that they have done so.
7375 			 *
7376 			 * A function with a polymorphic argument could change behavior
7377 			 * arbitrarily in response to get_fn_expr_argtype().  Therefore,
7378 			 * when the cast destination is polymorphic, we only avoid
7379 			 * revalidation if the input type has not changed at all.  Given
7380 			 * just the core data types and operator classes, this requirement
7381 			 * prevents no would-be optimizations.
7382 			 *
7383 			 * If the cast converts from a base type to a domain thereon, then
7384 			 * that domain type must be the opcintype of the unique index.
7385 			 * Necessarily, the primary key column must then be of the domain
7386 			 * type.  Since the constraint was previously valid, all values on
7387 			 * the foreign side necessarily exist on the primary side and in
7388 			 * turn conform to the domain.  Consequently, we need not treat
7389 			 * domains specially here.
7390 			 *
7391 			 * Since we require that all collations share the same notion of
7392 			 * equality (which they do, because texteq reduces to bitwise
7393 			 * equality), we don't compare collation here.
7394 			 *
7395 			 * We need not directly consider the PK type.  It's necessarily
7396 			 * binary coercible to the opcintype of the unique index column,
7397 			 * and ri_triggers.c will only deal with PK datums in terms of
7398 			 * that opcintype.  Changing the opcintype also changes pfeqop.
7399 			 */
7400 			old_check_ok = (new_pathtype == old_pathtype &&
7401 							new_castfunc == old_castfunc &&
7402 							(!IsPolymorphicType(pfeqop_right) ||
7403 							 new_fktype == old_fktype));
7404 		}
7405 
7406 		pfeqoperators[i] = pfeqop;
7407 		ppeqoperators[i] = ppeqop;
7408 		ffeqoperators[i] = ffeqop;
7409 	}
7410 
7411 	/*
7412 	 * Record the FK constraint in pg_constraint.
7413 	 */
7414 	constrOid = CreateConstraintEntry(fkconstraint->conname,
7415 									  RelationGetNamespace(rel),
7416 									  CONSTRAINT_FOREIGN,
7417 									  fkconstraint->deferrable,
7418 									  fkconstraint->initdeferred,
7419 									  fkconstraint->initially_valid,
7420 									  RelationGetRelid(rel),
7421 									  fkattnum,
7422 									  numfks,
7423 									  InvalidOid,	/* not a domain constraint */
7424 									  indexOid,
7425 									  RelationGetRelid(pkrel),
7426 									  pkattnum,
7427 									  pfeqoperators,
7428 									  ppeqoperators,
7429 									  ffeqoperators,
7430 									  numpks,
7431 									  fkconstraint->fk_upd_action,
7432 									  fkconstraint->fk_del_action,
7433 									  fkconstraint->fk_matchtype,
7434 									  NULL, /* no exclusion constraint */
7435 									  NULL, /* no check constraint */
7436 									  NULL,
7437 									  NULL,
7438 									  true, /* islocal */
7439 									  0,	/* inhcount */
7440 									  true, /* isnoinherit */
7441 									  false);	/* is_internal */
7442 	ObjectAddressSet(address, ConstraintRelationId, constrOid);
7443 
7444 	/*
7445 	 * Create the triggers that will enforce the constraint.
7446 	 */
7447 	createForeignKeyTriggers(rel, RelationGetRelid(pkrel), fkconstraint,
7448 							 constrOid, indexOid);
7449 
7450 	/*
7451 	 * Tell Phase 3 to check that the constraint is satisfied by existing
7452 	 * rows. We can skip this during table creation, when requested explicitly
7453 	 * by specifying NOT VALID in an ADD FOREIGN KEY command, and when we're
7454 	 * recreating a constraint following a SET DATA TYPE operation that did
7455 	 * not impugn its validity.
7456 	 */
7457 	if (!old_check_ok && !fkconstraint->skip_validation)
7458 	{
7459 		NewConstraint *newcon;
7460 
7461 		newcon = (NewConstraint *) palloc0(sizeof(NewConstraint));
7462 		newcon->name = fkconstraint->conname;
7463 		newcon->contype = CONSTR_FOREIGN;
7464 		newcon->refrelid = RelationGetRelid(pkrel);
7465 		newcon->refindid = indexOid;
7466 		newcon->conid = constrOid;
7467 		newcon->qual = (Node *) fkconstraint;
7468 
7469 		tab->constraints = lappend(tab->constraints, newcon);
7470 	}
7471 
7472 	/*
7473 	 * Close pk table, but keep lock until we've committed.
7474 	 */
7475 	heap_close(pkrel, NoLock);
7476 
7477 	return address;
7478 }
7479 
7480 /*
7481  * ALTER TABLE ALTER CONSTRAINT
7482  *
7483  * Update the attributes of a constraint.
7484  *
7485  * Currently only works for Foreign Key constraints.
7486  * Foreign keys do not inherit, so we purposely ignore the
7487  * recursion bit here, but we keep the API the same for when
7488  * other constraint types are supported.
7489  *
7490  * If the constraint is modified, returns its address; otherwise, return
7491  * InvalidObjectAddress.
7492  */
7493 static ObjectAddress
ATExecAlterConstraint(Relation rel,AlterTableCmd * cmd,bool recurse,bool recursing,LOCKMODE lockmode)7494 ATExecAlterConstraint(Relation rel, AlterTableCmd *cmd,
7495 					  bool recurse, bool recursing, LOCKMODE lockmode)
7496 {
7497 	Constraint *cmdcon;
7498 	Relation	conrel;
7499 	SysScanDesc scan;
7500 	ScanKeyData key;
7501 	HeapTuple	contuple;
7502 	Form_pg_constraint currcon = NULL;
7503 	bool		found = false;
7504 	ObjectAddress address;
7505 
7506 	cmdcon = castNode(Constraint, cmd->def);
7507 
7508 	conrel = heap_open(ConstraintRelationId, RowExclusiveLock);
7509 
7510 	/*
7511 	 * Find and check the target constraint
7512 	 */
7513 	ScanKeyInit(&key,
7514 				Anum_pg_constraint_conrelid,
7515 				BTEqualStrategyNumber, F_OIDEQ,
7516 				ObjectIdGetDatum(RelationGetRelid(rel)));
7517 	scan = systable_beginscan(conrel, ConstraintRelidIndexId,
7518 							  true, NULL, 1, &key);
7519 
7520 	while (HeapTupleIsValid(contuple = systable_getnext(scan)))
7521 	{
7522 		currcon = (Form_pg_constraint) GETSTRUCT(contuple);
7523 		if (strcmp(NameStr(currcon->conname), cmdcon->conname) == 0)
7524 		{
7525 			found = true;
7526 			break;
7527 		}
7528 	}
7529 
7530 	if (!found)
7531 		ereport(ERROR,
7532 				(errcode(ERRCODE_UNDEFINED_OBJECT),
7533 				 errmsg("constraint \"%s\" of relation \"%s\" does not exist",
7534 						cmdcon->conname, RelationGetRelationName(rel))));
7535 
7536 	if (currcon->contype != CONSTRAINT_FOREIGN)
7537 		ereport(ERROR,
7538 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
7539 				 errmsg("constraint \"%s\" of relation \"%s\" is not a foreign key constraint",
7540 						cmdcon->conname, RelationGetRelationName(rel))));
7541 
7542 	if (currcon->condeferrable != cmdcon->deferrable ||
7543 		currcon->condeferred != cmdcon->initdeferred)
7544 	{
7545 		HeapTuple	copyTuple;
7546 		HeapTuple	tgtuple;
7547 		Form_pg_constraint copy_con;
7548 		List	   *otherrelids = NIL;
7549 		ScanKeyData tgkey;
7550 		SysScanDesc tgscan;
7551 		Relation	tgrel;
7552 		ListCell   *lc;
7553 
7554 		/*
7555 		 * Now update the catalog, while we have the door open.
7556 		 */
7557 		copyTuple = heap_copytuple(contuple);
7558 		copy_con = (Form_pg_constraint) GETSTRUCT(copyTuple);
7559 		copy_con->condeferrable = cmdcon->deferrable;
7560 		copy_con->condeferred = cmdcon->initdeferred;
7561 		CatalogTupleUpdate(conrel, &copyTuple->t_self, copyTuple);
7562 
7563 		InvokeObjectPostAlterHook(ConstraintRelationId,
7564 								  HeapTupleGetOid(contuple), 0);
7565 
7566 		heap_freetuple(copyTuple);
7567 
7568 		/*
7569 		 * Now we need to update the multiple entries in pg_trigger that
7570 		 * implement the constraint.
7571 		 */
7572 		tgrel = heap_open(TriggerRelationId, RowExclusiveLock);
7573 
7574 		ScanKeyInit(&tgkey,
7575 					Anum_pg_trigger_tgconstraint,
7576 					BTEqualStrategyNumber, F_OIDEQ,
7577 					ObjectIdGetDatum(HeapTupleGetOid(contuple)));
7578 
7579 		tgscan = systable_beginscan(tgrel, TriggerConstraintIndexId, true,
7580 									NULL, 1, &tgkey);
7581 
7582 		while (HeapTupleIsValid(tgtuple = systable_getnext(tgscan)))
7583 		{
7584 			Form_pg_trigger tgform = (Form_pg_trigger) GETSTRUCT(tgtuple);
7585 			Form_pg_trigger copy_tg;
7586 
7587 			/*
7588 			 * Remember OIDs of other relation(s) involved in FK constraint.
7589 			 * (Note: it's likely that we could skip forcing a relcache inval
7590 			 * for other rels that don't have a trigger whose properties
7591 			 * change, but let's be conservative.)
7592 			 */
7593 			if (tgform->tgrelid != RelationGetRelid(rel))
7594 				otherrelids = list_append_unique_oid(otherrelids,
7595 													 tgform->tgrelid);
7596 
7597 			/*
7598 			 * Update deferrability of RI_FKey_noaction_del,
7599 			 * RI_FKey_noaction_upd, RI_FKey_check_ins and RI_FKey_check_upd
7600 			 * triggers, but not others; see createForeignKeyTriggers and
7601 			 * CreateFKCheckTrigger.
7602 			 */
7603 			if (tgform->tgfoid != F_RI_FKEY_NOACTION_DEL &&
7604 				tgform->tgfoid != F_RI_FKEY_NOACTION_UPD &&
7605 				tgform->tgfoid != F_RI_FKEY_CHECK_INS &&
7606 				tgform->tgfoid != F_RI_FKEY_CHECK_UPD)
7607 				continue;
7608 
7609 			copyTuple = heap_copytuple(tgtuple);
7610 			copy_tg = (Form_pg_trigger) GETSTRUCT(copyTuple);
7611 
7612 			copy_tg->tgdeferrable = cmdcon->deferrable;
7613 			copy_tg->tginitdeferred = cmdcon->initdeferred;
7614 			CatalogTupleUpdate(tgrel, &copyTuple->t_self, copyTuple);
7615 
7616 			InvokeObjectPostAlterHook(TriggerRelationId,
7617 									  HeapTupleGetOid(tgtuple), 0);
7618 
7619 			heap_freetuple(copyTuple);
7620 		}
7621 
7622 		systable_endscan(tgscan);
7623 
7624 		heap_close(tgrel, RowExclusiveLock);
7625 
7626 		/*
7627 		 * Invalidate relcache so that others see the new attributes.  We must
7628 		 * inval both the named rel and any others having relevant triggers.
7629 		 * (At present there should always be exactly one other rel, but
7630 		 * there's no need to hard-wire such an assumption here.)
7631 		 */
7632 		CacheInvalidateRelcache(rel);
7633 		foreach(lc, otherrelids)
7634 		{
7635 			CacheInvalidateRelcacheByRelid(lfirst_oid(lc));
7636 		}
7637 
7638 		ObjectAddressSet(address, ConstraintRelationId,
7639 						 HeapTupleGetOid(contuple));
7640 	}
7641 	else
7642 		address = InvalidObjectAddress;
7643 
7644 	systable_endscan(scan);
7645 
7646 	heap_close(conrel, RowExclusiveLock);
7647 
7648 	return address;
7649 }
7650 
7651 /*
7652  * ALTER TABLE VALIDATE CONSTRAINT
7653  *
7654  * XXX The reason we handle recursion here rather than at Phase 1 is because
7655  * there's no good way to skip recursing when handling foreign keys: there is
7656  * no need to lock children in that case, yet we wouldn't be able to avoid
7657  * doing so at that level.
7658  *
7659  * Return value is the address of the validated constraint.  If the constraint
7660  * was already validated, InvalidObjectAddress is returned.
7661  */
7662 static ObjectAddress
ATExecValidateConstraint(List ** wqueue,Relation rel,char * constrName,bool recurse,bool recursing,LOCKMODE lockmode)7663 ATExecValidateConstraint(List **wqueue, Relation rel, char *constrName,
7664 						 bool recurse, bool recursing, LOCKMODE lockmode)
7665 {
7666 	Relation	conrel;
7667 	SysScanDesc scan;
7668 	ScanKeyData key;
7669 	HeapTuple	tuple;
7670 	Form_pg_constraint con = NULL;
7671 	bool		found = false;
7672 	ObjectAddress address;
7673 
7674 	conrel = heap_open(ConstraintRelationId, RowExclusiveLock);
7675 
7676 	/*
7677 	 * Find and check the target constraint
7678 	 */
7679 	ScanKeyInit(&key,
7680 				Anum_pg_constraint_conrelid,
7681 				BTEqualStrategyNumber, F_OIDEQ,
7682 				ObjectIdGetDatum(RelationGetRelid(rel)));
7683 	scan = systable_beginscan(conrel, ConstraintRelidIndexId,
7684 							  true, NULL, 1, &key);
7685 
7686 	while (HeapTupleIsValid(tuple = systable_getnext(scan)))
7687 	{
7688 		con = (Form_pg_constraint) GETSTRUCT(tuple);
7689 		if (strcmp(NameStr(con->conname), constrName) == 0)
7690 		{
7691 			found = true;
7692 			break;
7693 		}
7694 	}
7695 
7696 	if (!found)
7697 		ereport(ERROR,
7698 				(errcode(ERRCODE_UNDEFINED_OBJECT),
7699 				 errmsg("constraint \"%s\" of relation \"%s\" does not exist",
7700 						constrName, RelationGetRelationName(rel))));
7701 
7702 	if (con->contype != CONSTRAINT_FOREIGN &&
7703 		con->contype != CONSTRAINT_CHECK)
7704 		ereport(ERROR,
7705 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
7706 				 errmsg("constraint \"%s\" of relation \"%s\" is not a foreign key or check constraint",
7707 						constrName, RelationGetRelationName(rel))));
7708 
7709 	if (!con->convalidated)
7710 	{
7711 		AlteredTableInfo *tab;
7712 		HeapTuple	copyTuple;
7713 		Form_pg_constraint copy_con;
7714 
7715 		if (con->contype == CONSTRAINT_FOREIGN)
7716 		{
7717 			NewConstraint *newcon;
7718 			Constraint *fkconstraint;
7719 
7720 			/* Queue validation for phase 3 */
7721 			fkconstraint = makeNode(Constraint);
7722 			/* for now this is all we need */
7723 			fkconstraint->conname = constrName;
7724 
7725 			newcon = (NewConstraint *) palloc0(sizeof(NewConstraint));
7726 			newcon->name = constrName;
7727 			newcon->contype = CONSTR_FOREIGN;
7728 			newcon->refrelid = con->confrelid;
7729 			newcon->refindid = con->conindid;
7730 			newcon->conid = HeapTupleGetOid(tuple);
7731 			newcon->qual = (Node *) fkconstraint;
7732 
7733 			/* Find or create work queue entry for this table */
7734 			tab = ATGetQueueEntry(wqueue, rel);
7735 			tab->constraints = lappend(tab->constraints, newcon);
7736 
7737 			/*
7738 			 * Foreign keys do not inherit, so we purposely ignore the
7739 			 * recursion bit here
7740 			 */
7741 		}
7742 		else if (con->contype == CONSTRAINT_CHECK)
7743 		{
7744 			List	   *children = NIL;
7745 			ListCell   *child;
7746 			NewConstraint *newcon;
7747 			bool		isnull;
7748 			Datum		val;
7749 			char	   *conbin;
7750 
7751 			/*
7752 			 * If we're recursing, the parent has already done this, so skip
7753 			 * it.  Also, if the constraint is a NO INHERIT constraint, we
7754 			 * shouldn't try to look for it in the children.
7755 			 */
7756 			if (!recursing && !con->connoinherit)
7757 				children = find_all_inheritors(RelationGetRelid(rel),
7758 											   lockmode, NULL);
7759 
7760 			/*
7761 			 * For CHECK constraints, we must ensure that we only mark the
7762 			 * constraint as validated on the parent if it's already validated
7763 			 * on the children.
7764 			 *
7765 			 * We recurse before validating on the parent, to reduce risk of
7766 			 * deadlocks.
7767 			 */
7768 			foreach(child, children)
7769 			{
7770 				Oid			childoid = lfirst_oid(child);
7771 				Relation	childrel;
7772 
7773 				if (childoid == RelationGetRelid(rel))
7774 					continue;
7775 
7776 				/*
7777 				 * If we are told not to recurse, there had better not be any
7778 				 * child tables, because we can't mark the constraint on the
7779 				 * parent valid unless it is valid for all child tables.
7780 				 */
7781 				if (!recurse)
7782 					ereport(ERROR,
7783 							(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
7784 							 errmsg("constraint must be validated on child tables too")));
7785 
7786 				/* find_all_inheritors already got lock */
7787 				childrel = heap_open(childoid, NoLock);
7788 
7789 				ATExecValidateConstraint(wqueue, childrel, constrName, false,
7790 										 true, lockmode);
7791 				heap_close(childrel, NoLock);
7792 			}
7793 
7794 			/* Queue validation for phase 3 */
7795 			newcon = (NewConstraint *) palloc0(sizeof(NewConstraint));
7796 			newcon->name = constrName;
7797 			newcon->contype = CONSTR_CHECK;
7798 			newcon->refrelid = InvalidOid;
7799 			newcon->refindid = InvalidOid;
7800 			newcon->conid = HeapTupleGetOid(tuple);
7801 
7802 			val = SysCacheGetAttr(CONSTROID, tuple,
7803 									Anum_pg_constraint_conbin, &isnull);
7804 			if (isnull)
7805 				elog(ERROR, "null conbin for constraint %u",
7806 					 HeapTupleGetOid(tuple));
7807 
7808 			conbin = TextDatumGetCString(val);
7809 			newcon->qual = (Node *) stringToNode(conbin);
7810 
7811 			/* Find or create work queue entry for this table */
7812 			tab = ATGetQueueEntry(wqueue, rel);
7813 			tab->constraints = lappend(tab->constraints, newcon);
7814 
7815 			/*
7816 			 * Invalidate relcache so that others see the new validated
7817 			 * constraint.
7818 			 */
7819 			CacheInvalidateRelcache(rel);
7820 		}
7821 
7822 		/*
7823 		 * Now update the catalog, while we have the door open.
7824 		 */
7825 		copyTuple = heap_copytuple(tuple);
7826 		copy_con = (Form_pg_constraint) GETSTRUCT(copyTuple);
7827 		copy_con->convalidated = true;
7828 		CatalogTupleUpdate(conrel, &copyTuple->t_self, copyTuple);
7829 
7830 		InvokeObjectPostAlterHook(ConstraintRelationId,
7831 								  HeapTupleGetOid(tuple), 0);
7832 
7833 		heap_freetuple(copyTuple);
7834 
7835 		ObjectAddressSet(address, ConstraintRelationId,
7836 						 HeapTupleGetOid(tuple));
7837 	}
7838 	else
7839 		address = InvalidObjectAddress; /* already validated */
7840 
7841 	systable_endscan(scan);
7842 
7843 	heap_close(conrel, RowExclusiveLock);
7844 
7845 	return address;
7846 }
7847 
7848 
7849 /*
7850  * transformColumnNameList - transform list of column names
7851  *
7852  * Lookup each name and return its attnum and type OID
7853  */
7854 static int
transformColumnNameList(Oid relId,List * colList,int16 * attnums,Oid * atttypids)7855 transformColumnNameList(Oid relId, List *colList,
7856 						int16 *attnums, Oid *atttypids)
7857 {
7858 	ListCell   *l;
7859 	int			attnum;
7860 
7861 	attnum = 0;
7862 	foreach(l, colList)
7863 	{
7864 		char	   *attname = strVal(lfirst(l));
7865 		HeapTuple	atttuple;
7866 
7867 		atttuple = SearchSysCacheAttName(relId, attname);
7868 		if (!HeapTupleIsValid(atttuple))
7869 			ereport(ERROR,
7870 					(errcode(ERRCODE_UNDEFINED_COLUMN),
7871 					 errmsg("column \"%s\" referenced in foreign key constraint does not exist",
7872 							attname)));
7873 		if (attnum >= INDEX_MAX_KEYS)
7874 			ereport(ERROR,
7875 					(errcode(ERRCODE_TOO_MANY_COLUMNS),
7876 					 errmsg("cannot have more than %d keys in a foreign key",
7877 							INDEX_MAX_KEYS)));
7878 		attnums[attnum] = ((Form_pg_attribute) GETSTRUCT(atttuple))->attnum;
7879 		atttypids[attnum] = ((Form_pg_attribute) GETSTRUCT(atttuple))->atttypid;
7880 		ReleaseSysCache(atttuple);
7881 		attnum++;
7882 	}
7883 
7884 	return attnum;
7885 }
7886 
7887 /*
7888  * transformFkeyGetPrimaryKey -
7889  *
7890  *	Look up the names, attnums, and types of the primary key attributes
7891  *	for the pkrel.  Also return the index OID and index opclasses of the
7892  *	index supporting the primary key.
7893  *
7894  *	All parameters except pkrel are output parameters.  Also, the function
7895  *	return value is the number of attributes in the primary key.
7896  *
7897  *	Used when the column list in the REFERENCES specification is omitted.
7898  */
7899 static int
transformFkeyGetPrimaryKey(Relation pkrel,Oid * indexOid,List ** attnamelist,int16 * attnums,Oid * atttypids,Oid * opclasses)7900 transformFkeyGetPrimaryKey(Relation pkrel, Oid *indexOid,
7901 						   List **attnamelist,
7902 						   int16 *attnums, Oid *atttypids,
7903 						   Oid *opclasses)
7904 {
7905 	List	   *indexoidlist;
7906 	ListCell   *indexoidscan;
7907 	HeapTuple	indexTuple = NULL;
7908 	Form_pg_index indexStruct = NULL;
7909 	Datum		indclassDatum;
7910 	bool		isnull;
7911 	oidvector  *indclass;
7912 	int			i;
7913 
7914 	/*
7915 	 * Get the list of index OIDs for the table from the relcache, and look up
7916 	 * each one in the pg_index syscache until we find one marked primary key
7917 	 * (hopefully there isn't more than one such).  Insist it's valid, too.
7918 	 */
7919 	*indexOid = InvalidOid;
7920 
7921 	indexoidlist = RelationGetIndexList(pkrel);
7922 
7923 	foreach(indexoidscan, indexoidlist)
7924 	{
7925 		Oid			indexoid = lfirst_oid(indexoidscan);
7926 
7927 		indexTuple = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(indexoid));
7928 		if (!HeapTupleIsValid(indexTuple))
7929 			elog(ERROR, "cache lookup failed for index %u", indexoid);
7930 		indexStruct = (Form_pg_index) GETSTRUCT(indexTuple);
7931 		if (indexStruct->indisprimary && IndexIsValid(indexStruct))
7932 		{
7933 			/*
7934 			 * Refuse to use a deferrable primary key.  This is per SQL spec,
7935 			 * and there would be a lot of interesting semantic problems if we
7936 			 * tried to allow it.
7937 			 */
7938 			if (!indexStruct->indimmediate)
7939 				ereport(ERROR,
7940 						(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
7941 						 errmsg("cannot use a deferrable primary key for referenced table \"%s\"",
7942 								RelationGetRelationName(pkrel))));
7943 
7944 			*indexOid = indexoid;
7945 			break;
7946 		}
7947 		ReleaseSysCache(indexTuple);
7948 	}
7949 
7950 	list_free(indexoidlist);
7951 
7952 	/*
7953 	 * Check that we found it
7954 	 */
7955 	if (!OidIsValid(*indexOid))
7956 		ereport(ERROR,
7957 				(errcode(ERRCODE_UNDEFINED_OBJECT),
7958 				 errmsg("there is no primary key for referenced table \"%s\"",
7959 						RelationGetRelationName(pkrel))));
7960 
7961 	/* Must get indclass the hard way */
7962 	indclassDatum = SysCacheGetAttr(INDEXRELID, indexTuple,
7963 									Anum_pg_index_indclass, &isnull);
7964 	Assert(!isnull);
7965 	indclass = (oidvector *) DatumGetPointer(indclassDatum);
7966 
7967 	/*
7968 	 * Now build the list of PK attributes from the indkey definition (we
7969 	 * assume a primary key cannot have expressional elements)
7970 	 */
7971 	*attnamelist = NIL;
7972 	for (i = 0; i < indexStruct->indnatts; i++)
7973 	{
7974 		int			pkattno = indexStruct->indkey.values[i];
7975 
7976 		attnums[i] = pkattno;
7977 		atttypids[i] = attnumTypeId(pkrel, pkattno);
7978 		opclasses[i] = indclass->values[i];
7979 		*attnamelist = lappend(*attnamelist,
7980 							   makeString(pstrdup(NameStr(*attnumAttName(pkrel, pkattno)))));
7981 	}
7982 
7983 	ReleaseSysCache(indexTuple);
7984 
7985 	return i;
7986 }
7987 
7988 /*
7989  * transformFkeyCheckAttrs -
7990  *
7991  *	Make sure that the attributes of a referenced table belong to a unique
7992  *	(or primary key) constraint.  Return the OID of the index supporting
7993  *	the constraint, as well as the opclasses associated with the index
7994  *	columns.
7995  */
7996 static Oid
transformFkeyCheckAttrs(Relation pkrel,int numattrs,int16 * attnums,Oid * opclasses)7997 transformFkeyCheckAttrs(Relation pkrel,
7998 						int numattrs, int16 *attnums,
7999 						Oid *opclasses) /* output parameter */
8000 {
8001 	Oid			indexoid = InvalidOid;
8002 	bool		found = false;
8003 	bool		found_deferrable = false;
8004 	List	   *indexoidlist;
8005 	ListCell   *indexoidscan;
8006 	int			i,
8007 				j;
8008 
8009 	/*
8010 	 * Reject duplicate appearances of columns in the referenced-columns list.
8011 	 * Such a case is forbidden by the SQL standard, and even if we thought it
8012 	 * useful to allow it, there would be ambiguity about how to match the
8013 	 * list to unique indexes (in particular, it'd be unclear which index
8014 	 * opclass goes with which FK column).
8015 	 */
8016 	for (i = 0; i < numattrs; i++)
8017 	{
8018 		for (j = i + 1; j < numattrs; j++)
8019 		{
8020 			if (attnums[i] == attnums[j])
8021 				ereport(ERROR,
8022 						(errcode(ERRCODE_INVALID_FOREIGN_KEY),
8023 						 errmsg("foreign key referenced-columns list must not contain duplicates")));
8024 		}
8025 	}
8026 
8027 	/*
8028 	 * Get the list of index OIDs for the table from the relcache, and look up
8029 	 * each one in the pg_index syscache, and match unique indexes to the list
8030 	 * of attnums we are given.
8031 	 */
8032 	indexoidlist = RelationGetIndexList(pkrel);
8033 
8034 	foreach(indexoidscan, indexoidlist)
8035 	{
8036 		HeapTuple	indexTuple;
8037 		Form_pg_index indexStruct;
8038 
8039 		indexoid = lfirst_oid(indexoidscan);
8040 		indexTuple = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(indexoid));
8041 		if (!HeapTupleIsValid(indexTuple))
8042 			elog(ERROR, "cache lookup failed for index %u", indexoid);
8043 		indexStruct = (Form_pg_index) GETSTRUCT(indexTuple);
8044 
8045 		/*
8046 		 * Must have the right number of columns; must be unique and not a
8047 		 * partial index; forget it if there are any expressions, too. Invalid
8048 		 * indexes are out as well.
8049 		 */
8050 		if (indexStruct->indnatts == numattrs &&
8051 			indexStruct->indisunique &&
8052 			IndexIsValid(indexStruct) &&
8053 			heap_attisnull(indexTuple, Anum_pg_index_indpred) &&
8054 			heap_attisnull(indexTuple, Anum_pg_index_indexprs))
8055 		{
8056 			Datum		indclassDatum;
8057 			bool		isnull;
8058 			oidvector  *indclass;
8059 
8060 			/* Must get indclass the hard way */
8061 			indclassDatum = SysCacheGetAttr(INDEXRELID, indexTuple,
8062 											Anum_pg_index_indclass, &isnull);
8063 			Assert(!isnull);
8064 			indclass = (oidvector *) DatumGetPointer(indclassDatum);
8065 
8066 			/*
8067 			 * The given attnum list may match the index columns in any order.
8068 			 * Check for a match, and extract the appropriate opclasses while
8069 			 * we're at it.
8070 			 *
8071 			 * We know that attnums[] is duplicate-free per the test at the
8072 			 * start of this function, and we checked above that the number of
8073 			 * index columns agrees, so if we find a match for each attnums[]
8074 			 * entry then we must have a one-to-one match in some order.
8075 			 */
8076 			for (i = 0; i < numattrs; i++)
8077 			{
8078 				found = false;
8079 				for (j = 0; j < numattrs; j++)
8080 				{
8081 					if (attnums[i] == indexStruct->indkey.values[j])
8082 					{
8083 						opclasses[i] = indclass->values[j];
8084 						found = true;
8085 						break;
8086 					}
8087 				}
8088 				if (!found)
8089 					break;
8090 			}
8091 
8092 			/*
8093 			 * Refuse to use a deferrable unique/primary key.  This is per SQL
8094 			 * spec, and there would be a lot of interesting semantic problems
8095 			 * if we tried to allow it.
8096 			 */
8097 			if (found && !indexStruct->indimmediate)
8098 			{
8099 				/*
8100 				 * Remember that we found an otherwise matching index, so that
8101 				 * we can generate a more appropriate error message.
8102 				 */
8103 				found_deferrable = true;
8104 				found = false;
8105 			}
8106 		}
8107 		ReleaseSysCache(indexTuple);
8108 		if (found)
8109 			break;
8110 	}
8111 
8112 	if (!found)
8113 	{
8114 		if (found_deferrable)
8115 			ereport(ERROR,
8116 					(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
8117 					 errmsg("cannot use a deferrable unique constraint for referenced table \"%s\"",
8118 							RelationGetRelationName(pkrel))));
8119 		else
8120 			ereport(ERROR,
8121 					(errcode(ERRCODE_INVALID_FOREIGN_KEY),
8122 					 errmsg("there is no unique constraint matching given keys for referenced table \"%s\"",
8123 							RelationGetRelationName(pkrel))));
8124 	}
8125 
8126 	list_free(indexoidlist);
8127 
8128 	return indexoid;
8129 }
8130 
8131 /*
8132  * findFkeyCast -
8133  *
8134  *	Wrapper around find_coercion_pathway() for ATAddForeignKeyConstraint().
8135  *	Caller has equal regard for binary coercibility and for an exact match.
8136 */
8137 static CoercionPathType
findFkeyCast(Oid targetTypeId,Oid sourceTypeId,Oid * funcid)8138 findFkeyCast(Oid targetTypeId, Oid sourceTypeId, Oid *funcid)
8139 {
8140 	CoercionPathType ret;
8141 
8142 	if (targetTypeId == sourceTypeId)
8143 	{
8144 		ret = COERCION_PATH_RELABELTYPE;
8145 		*funcid = InvalidOid;
8146 	}
8147 	else
8148 	{
8149 		ret = find_coercion_pathway(targetTypeId, sourceTypeId,
8150 									COERCION_IMPLICIT, funcid);
8151 		if (ret == COERCION_PATH_NONE)
8152 			/* A previously-relied-upon cast is now gone. */
8153 			elog(ERROR, "could not find cast from %u to %u",
8154 				 sourceTypeId, targetTypeId);
8155 	}
8156 
8157 	return ret;
8158 }
8159 
8160 /*
8161  * Permissions checks on the referenced table for ADD FOREIGN KEY
8162  *
8163  * Note: we have already checked that the user owns the referencing table,
8164  * else we'd have failed much earlier; no additional checks are needed for it.
8165  */
8166 static void
checkFkeyPermissions(Relation rel,int16 * attnums,int natts)8167 checkFkeyPermissions(Relation rel, int16 *attnums, int natts)
8168 {
8169 	Oid			roleid = GetUserId();
8170 	AclResult	aclresult;
8171 	int			i;
8172 
8173 	/* Okay if we have relation-level REFERENCES permission */
8174 	aclresult = pg_class_aclcheck(RelationGetRelid(rel), roleid,
8175 								  ACL_REFERENCES);
8176 	if (aclresult == ACLCHECK_OK)
8177 		return;
8178 	/* Else we must have REFERENCES on each column */
8179 	for (i = 0; i < natts; i++)
8180 	{
8181 		aclresult = pg_attribute_aclcheck(RelationGetRelid(rel), attnums[i],
8182 										  roleid, ACL_REFERENCES);
8183 		if (aclresult != ACLCHECK_OK)
8184 			aclcheck_error(aclresult, ACL_KIND_CLASS,
8185 						   RelationGetRelationName(rel));
8186 	}
8187 }
8188 
8189 /*
8190  * Scan the existing rows in a table to verify they meet a proposed FK
8191  * constraint.
8192  *
8193  * Caller must have opened and locked both relations appropriately.
8194  */
8195 static void
validateForeignKeyConstraint(char * conname,Relation rel,Relation pkrel,Oid pkindOid,Oid constraintOid)8196 validateForeignKeyConstraint(char *conname,
8197 							 Relation rel,
8198 							 Relation pkrel,
8199 							 Oid pkindOid,
8200 							 Oid constraintOid)
8201 {
8202 	HeapScanDesc scan;
8203 	HeapTuple	tuple;
8204 	Trigger		trig;
8205 	Snapshot	snapshot;
8206 
8207 	ereport(DEBUG1,
8208 			(errmsg("validating foreign key constraint \"%s\"", conname)));
8209 
8210 	/*
8211 	 * Build a trigger call structure; we'll need it either way.
8212 	 */
8213 	MemSet(&trig, 0, sizeof(trig));
8214 	trig.tgoid = InvalidOid;
8215 	trig.tgname = conname;
8216 	trig.tgenabled = TRIGGER_FIRES_ON_ORIGIN;
8217 	trig.tgisinternal = TRUE;
8218 	trig.tgconstrrelid = RelationGetRelid(pkrel);
8219 	trig.tgconstrindid = pkindOid;
8220 	trig.tgconstraint = constraintOid;
8221 	trig.tgdeferrable = FALSE;
8222 	trig.tginitdeferred = FALSE;
8223 	/* we needn't fill in remaining fields */
8224 
8225 	/*
8226 	 * See if we can do it with a single LEFT JOIN query.  A FALSE result
8227 	 * indicates we must proceed with the fire-the-trigger method.
8228 	 */
8229 	if (RI_Initial_Check(&trig, rel, pkrel))
8230 		return;
8231 
8232 	/*
8233 	 * Scan through each tuple, calling RI_FKey_check_ins (insert trigger) as
8234 	 * if that tuple had just been inserted.  If any of those fail, it should
8235 	 * ereport(ERROR) and that's that.
8236 	 */
8237 	snapshot = RegisterSnapshot(GetLatestSnapshot());
8238 	scan = heap_beginscan(rel, snapshot, 0, NULL);
8239 
8240 	while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
8241 	{
8242 		FunctionCallInfoData fcinfo;
8243 		TriggerData trigdata;
8244 
8245 		/*
8246 		 * Make a call to the trigger function
8247 		 *
8248 		 * No parameters are passed, but we do set a context
8249 		 */
8250 		MemSet(&fcinfo, 0, sizeof(fcinfo));
8251 
8252 		/*
8253 		 * We assume RI_FKey_check_ins won't look at flinfo...
8254 		 */
8255 		trigdata.type = T_TriggerData;
8256 		trigdata.tg_event = TRIGGER_EVENT_INSERT | TRIGGER_EVENT_ROW;
8257 		trigdata.tg_relation = rel;
8258 		trigdata.tg_trigtuple = tuple;
8259 		trigdata.tg_newtuple = NULL;
8260 		trigdata.tg_trigger = &trig;
8261 		trigdata.tg_trigtuplebuf = scan->rs_cbuf;
8262 		trigdata.tg_newtuplebuf = InvalidBuffer;
8263 
8264 		fcinfo.context = (Node *) &trigdata;
8265 
8266 		RI_FKey_check_ins(&fcinfo);
8267 	}
8268 
8269 	heap_endscan(scan);
8270 	UnregisterSnapshot(snapshot);
8271 }
8272 
8273 static void
CreateFKCheckTrigger(Oid myRelOid,Oid refRelOid,Constraint * fkconstraint,Oid constraintOid,Oid indexOid,bool on_insert)8274 CreateFKCheckTrigger(Oid myRelOid, Oid refRelOid, Constraint *fkconstraint,
8275 					 Oid constraintOid, Oid indexOid, bool on_insert)
8276 {
8277 	CreateTrigStmt *fk_trigger;
8278 
8279 	/*
8280 	 * Note: for a self-referential FK (referencing and referenced tables are
8281 	 * the same), it is important that the ON UPDATE action fires before the
8282 	 * CHECK action, since both triggers will fire on the same row during an
8283 	 * UPDATE event; otherwise the CHECK trigger will be checking a non-final
8284 	 * state of the row.  Triggers fire in name order, so we ensure this by
8285 	 * using names like "RI_ConstraintTrigger_a_NNNN" for the action triggers
8286 	 * and "RI_ConstraintTrigger_c_NNNN" for the check triggers.
8287 	 */
8288 	fk_trigger = makeNode(CreateTrigStmt);
8289 	fk_trigger->trigname = "RI_ConstraintTrigger_c";
8290 	fk_trigger->relation = NULL;
8291 	fk_trigger->row = true;
8292 	fk_trigger->timing = TRIGGER_TYPE_AFTER;
8293 
8294 	/* Either ON INSERT or ON UPDATE */
8295 	if (on_insert)
8296 	{
8297 		fk_trigger->funcname = SystemFuncName("RI_FKey_check_ins");
8298 		fk_trigger->events = TRIGGER_TYPE_INSERT;
8299 	}
8300 	else
8301 	{
8302 		fk_trigger->funcname = SystemFuncName("RI_FKey_check_upd");
8303 		fk_trigger->events = TRIGGER_TYPE_UPDATE;
8304 	}
8305 
8306 	fk_trigger->columns = NIL;
8307 	fk_trigger->transitionRels = NIL;
8308 	fk_trigger->whenClause = NULL;
8309 	fk_trigger->isconstraint = true;
8310 	fk_trigger->deferrable = fkconstraint->deferrable;
8311 	fk_trigger->initdeferred = fkconstraint->initdeferred;
8312 	fk_trigger->constrrel = NULL;
8313 	fk_trigger->args = NIL;
8314 
8315 	(void) CreateTrigger(fk_trigger, NULL, myRelOid, refRelOid, constraintOid,
8316 						 indexOid, true);
8317 
8318 	/* Make changes-so-far visible */
8319 	CommandCounterIncrement();
8320 }
8321 
8322 /*
8323  * Create the triggers that implement an FK constraint.
8324  *
8325  * NB: if you change any trigger properties here, see also
8326  * ATExecAlterConstraint.
8327  */
8328 static void
createForeignKeyTriggers(Relation rel,Oid refRelOid,Constraint * fkconstraint,Oid constraintOid,Oid indexOid)8329 createForeignKeyTriggers(Relation rel, Oid refRelOid, Constraint *fkconstraint,
8330 						 Oid constraintOid, Oid indexOid)
8331 {
8332 	Oid			myRelOid;
8333 	CreateTrigStmt *fk_trigger;
8334 
8335 	myRelOid = RelationGetRelid(rel);
8336 
8337 	/* Make changes-so-far visible */
8338 	CommandCounterIncrement();
8339 
8340 	/*
8341 	 * Build and execute a CREATE CONSTRAINT TRIGGER statement for the ON
8342 	 * DELETE action on the referenced table.
8343 	 */
8344 	fk_trigger = makeNode(CreateTrigStmt);
8345 	fk_trigger->trigname = "RI_ConstraintTrigger_a";
8346 	fk_trigger->relation = NULL;
8347 	fk_trigger->row = true;
8348 	fk_trigger->timing = TRIGGER_TYPE_AFTER;
8349 	fk_trigger->events = TRIGGER_TYPE_DELETE;
8350 	fk_trigger->columns = NIL;
8351 	fk_trigger->transitionRels = NIL;
8352 	fk_trigger->whenClause = NULL;
8353 	fk_trigger->isconstraint = true;
8354 	fk_trigger->constrrel = NULL;
8355 	switch (fkconstraint->fk_del_action)
8356 	{
8357 		case FKCONSTR_ACTION_NOACTION:
8358 			fk_trigger->deferrable = fkconstraint->deferrable;
8359 			fk_trigger->initdeferred = fkconstraint->initdeferred;
8360 			fk_trigger->funcname = SystemFuncName("RI_FKey_noaction_del");
8361 			break;
8362 		case FKCONSTR_ACTION_RESTRICT:
8363 			fk_trigger->deferrable = false;
8364 			fk_trigger->initdeferred = false;
8365 			fk_trigger->funcname = SystemFuncName("RI_FKey_restrict_del");
8366 			break;
8367 		case FKCONSTR_ACTION_CASCADE:
8368 			fk_trigger->deferrable = false;
8369 			fk_trigger->initdeferred = false;
8370 			fk_trigger->funcname = SystemFuncName("RI_FKey_cascade_del");
8371 			break;
8372 		case FKCONSTR_ACTION_SETNULL:
8373 			fk_trigger->deferrable = false;
8374 			fk_trigger->initdeferred = false;
8375 			fk_trigger->funcname = SystemFuncName("RI_FKey_setnull_del");
8376 			break;
8377 		case FKCONSTR_ACTION_SETDEFAULT:
8378 			fk_trigger->deferrable = false;
8379 			fk_trigger->initdeferred = false;
8380 			fk_trigger->funcname = SystemFuncName("RI_FKey_setdefault_del");
8381 			break;
8382 		default:
8383 			elog(ERROR, "unrecognized FK action type: %d",
8384 				 (int) fkconstraint->fk_del_action);
8385 			break;
8386 	}
8387 	fk_trigger->args = NIL;
8388 
8389 	(void) CreateTrigger(fk_trigger, NULL, refRelOid, myRelOid, constraintOid,
8390 						 indexOid, true);
8391 
8392 	/* Make changes-so-far visible */
8393 	CommandCounterIncrement();
8394 
8395 	/*
8396 	 * Build and execute a CREATE CONSTRAINT TRIGGER statement for the ON
8397 	 * UPDATE action on the referenced table.
8398 	 */
8399 	fk_trigger = makeNode(CreateTrigStmt);
8400 	fk_trigger->trigname = "RI_ConstraintTrigger_a";
8401 	fk_trigger->relation = NULL;
8402 	fk_trigger->row = true;
8403 	fk_trigger->timing = TRIGGER_TYPE_AFTER;
8404 	fk_trigger->events = TRIGGER_TYPE_UPDATE;
8405 	fk_trigger->columns = NIL;
8406 	fk_trigger->transitionRels = NIL;
8407 	fk_trigger->whenClause = NULL;
8408 	fk_trigger->isconstraint = true;
8409 	fk_trigger->constrrel = NULL;
8410 	switch (fkconstraint->fk_upd_action)
8411 	{
8412 		case FKCONSTR_ACTION_NOACTION:
8413 			fk_trigger->deferrable = fkconstraint->deferrable;
8414 			fk_trigger->initdeferred = fkconstraint->initdeferred;
8415 			fk_trigger->funcname = SystemFuncName("RI_FKey_noaction_upd");
8416 			break;
8417 		case FKCONSTR_ACTION_RESTRICT:
8418 			fk_trigger->deferrable = false;
8419 			fk_trigger->initdeferred = false;
8420 			fk_trigger->funcname = SystemFuncName("RI_FKey_restrict_upd");
8421 			break;
8422 		case FKCONSTR_ACTION_CASCADE:
8423 			fk_trigger->deferrable = false;
8424 			fk_trigger->initdeferred = false;
8425 			fk_trigger->funcname = SystemFuncName("RI_FKey_cascade_upd");
8426 			break;
8427 		case FKCONSTR_ACTION_SETNULL:
8428 			fk_trigger->deferrable = false;
8429 			fk_trigger->initdeferred = false;
8430 			fk_trigger->funcname = SystemFuncName("RI_FKey_setnull_upd");
8431 			break;
8432 		case FKCONSTR_ACTION_SETDEFAULT:
8433 			fk_trigger->deferrable = false;
8434 			fk_trigger->initdeferred = false;
8435 			fk_trigger->funcname = SystemFuncName("RI_FKey_setdefault_upd");
8436 			break;
8437 		default:
8438 			elog(ERROR, "unrecognized FK action type: %d",
8439 				 (int) fkconstraint->fk_upd_action);
8440 			break;
8441 	}
8442 	fk_trigger->args = NIL;
8443 
8444 	(void) CreateTrigger(fk_trigger, NULL, refRelOid, myRelOid, constraintOid,
8445 						 indexOid, true);
8446 
8447 	/* Make changes-so-far visible */
8448 	CommandCounterIncrement();
8449 
8450 	/*
8451 	 * Build and execute CREATE CONSTRAINT TRIGGER statements for the CHECK
8452 	 * action for both INSERTs and UPDATEs on the referencing table.
8453 	 */
8454 	CreateFKCheckTrigger(myRelOid, refRelOid, fkconstraint, constraintOid,
8455 						 indexOid, true);
8456 	CreateFKCheckTrigger(myRelOid, refRelOid, fkconstraint, constraintOid,
8457 						 indexOid, false);
8458 }
8459 
8460 /*
8461  * ALTER TABLE DROP CONSTRAINT
8462  *
8463  * Like DROP COLUMN, we can't use the normal ALTER TABLE recursion mechanism.
8464  */
8465 static void
ATExecDropConstraint(Relation rel,const char * constrName,DropBehavior behavior,bool recurse,bool recursing,bool missing_ok,LOCKMODE lockmode)8466 ATExecDropConstraint(Relation rel, const char *constrName,
8467 					 DropBehavior behavior,
8468 					 bool recurse, bool recursing,
8469 					 bool missing_ok, LOCKMODE lockmode)
8470 {
8471 	List	   *children;
8472 	ListCell   *child;
8473 	Relation	conrel;
8474 	Form_pg_constraint con;
8475 	SysScanDesc scan;
8476 	ScanKeyData key;
8477 	HeapTuple	tuple;
8478 	bool		found = false;
8479 	bool		is_no_inherit_constraint = false;
8480 
8481 	/* At top level, permission check was done in ATPrepCmd, else do it */
8482 	if (recursing)
8483 		ATSimplePermissions(rel, ATT_TABLE | ATT_FOREIGN_TABLE);
8484 
8485 	conrel = heap_open(ConstraintRelationId, RowExclusiveLock);
8486 
8487 	/*
8488 	 * Find and drop the target constraint
8489 	 */
8490 	ScanKeyInit(&key,
8491 				Anum_pg_constraint_conrelid,
8492 				BTEqualStrategyNumber, F_OIDEQ,
8493 				ObjectIdGetDatum(RelationGetRelid(rel)));
8494 	scan = systable_beginscan(conrel, ConstraintRelidIndexId,
8495 							  true, NULL, 1, &key);
8496 
8497 	while (HeapTupleIsValid(tuple = systable_getnext(scan)))
8498 	{
8499 		ObjectAddress conobj;
8500 
8501 		con = (Form_pg_constraint) GETSTRUCT(tuple);
8502 
8503 		if (strcmp(NameStr(con->conname), constrName) != 0)
8504 			continue;
8505 
8506 		/* Don't drop inherited constraints */
8507 		if (con->coninhcount > 0 && !recursing)
8508 			ereport(ERROR,
8509 					(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
8510 					 errmsg("cannot drop inherited constraint \"%s\" of relation \"%s\"",
8511 							constrName, RelationGetRelationName(rel))));
8512 
8513 		is_no_inherit_constraint = con->connoinherit;
8514 
8515 		/*
8516 		 * If it's a foreign-key constraint, we'd better lock the referenced
8517 		 * table and check that that's not in use, just as we've already done
8518 		 * for the constrained table (else we might, eg, be dropping a trigger
8519 		 * that has unfired events).  But we can/must skip that in the
8520 		 * self-referential case.
8521 		 */
8522 		if (con->contype == CONSTRAINT_FOREIGN &&
8523 			con->confrelid != RelationGetRelid(rel))
8524 		{
8525 			Relation	frel;
8526 
8527 			/* Must match lock taken by RemoveTriggerById: */
8528 			frel = heap_open(con->confrelid, AccessExclusiveLock);
8529 			CheckTableNotInUse(frel, "ALTER TABLE");
8530 			heap_close(frel, NoLock);
8531 		}
8532 
8533 		/*
8534 		 * Perform the actual constraint deletion
8535 		 */
8536 		conobj.classId = ConstraintRelationId;
8537 		conobj.objectId = HeapTupleGetOid(tuple);
8538 		conobj.objectSubId = 0;
8539 
8540 		performDeletion(&conobj, behavior, 0);
8541 
8542 		found = true;
8543 
8544 		/* constraint found and dropped -- no need to keep looping */
8545 		break;
8546 	}
8547 
8548 	systable_endscan(scan);
8549 
8550 	if (!found)
8551 	{
8552 		if (!missing_ok)
8553 		{
8554 			ereport(ERROR,
8555 					(errcode(ERRCODE_UNDEFINED_OBJECT),
8556 					 errmsg("constraint \"%s\" of relation \"%s\" does not exist",
8557 							constrName, RelationGetRelationName(rel))));
8558 		}
8559 		else
8560 		{
8561 			ereport(NOTICE,
8562 					(errmsg("constraint \"%s\" of relation \"%s\" does not exist, skipping",
8563 							constrName, RelationGetRelationName(rel))));
8564 			heap_close(conrel, RowExclusiveLock);
8565 			return;
8566 		}
8567 	}
8568 
8569 	/*
8570 	 * Propagate to children as appropriate.  Unlike most other ALTER
8571 	 * routines, we have to do this one level of recursion at a time; we can't
8572 	 * use find_all_inheritors to do it in one pass.
8573 	 */
8574 	if (!is_no_inherit_constraint)
8575 		children = find_inheritance_children(RelationGetRelid(rel), lockmode);
8576 	else
8577 		children = NIL;
8578 
8579 	/*
8580 	 * For a partitioned table, if partitions exist and we are told not to
8581 	 * recurse, it's a user error.  It doesn't make sense to have a constraint
8582 	 * be defined only on the parent, especially if it's a partitioned table.
8583 	 */
8584 	if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE &&
8585 		children != NIL && !recurse)
8586 		ereport(ERROR,
8587 				(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
8588 				 errmsg("cannot remove constraint from only the partitioned table when partitions exist"),
8589 				 errhint("Do not specify the ONLY keyword.")));
8590 
8591 	foreach(child, children)
8592 	{
8593 		Oid			childrelid = lfirst_oid(child);
8594 		Relation	childrel;
8595 		HeapTuple	copy_tuple;
8596 
8597 		/* find_inheritance_children already got lock */
8598 		childrel = heap_open(childrelid, NoLock);
8599 		CheckTableNotInUse(childrel, "ALTER TABLE");
8600 
8601 		ScanKeyInit(&key,
8602 					Anum_pg_constraint_conrelid,
8603 					BTEqualStrategyNumber, F_OIDEQ,
8604 					ObjectIdGetDatum(childrelid));
8605 		scan = systable_beginscan(conrel, ConstraintRelidIndexId,
8606 								  true, NULL, 1, &key);
8607 
8608 		/* scan for matching tuple - there should only be one */
8609 		while (HeapTupleIsValid(tuple = systable_getnext(scan)))
8610 		{
8611 			con = (Form_pg_constraint) GETSTRUCT(tuple);
8612 
8613 			/* Right now only CHECK constraints can be inherited */
8614 			if (con->contype != CONSTRAINT_CHECK)
8615 				continue;
8616 
8617 			if (strcmp(NameStr(con->conname), constrName) == 0)
8618 				break;
8619 		}
8620 
8621 		if (!HeapTupleIsValid(tuple))
8622 			ereport(ERROR,
8623 					(errcode(ERRCODE_UNDEFINED_OBJECT),
8624 					 errmsg("constraint \"%s\" of relation \"%s\" does not exist",
8625 							constrName,
8626 							RelationGetRelationName(childrel))));
8627 
8628 		copy_tuple = heap_copytuple(tuple);
8629 
8630 		systable_endscan(scan);
8631 
8632 		con = (Form_pg_constraint) GETSTRUCT(copy_tuple);
8633 
8634 		if (con->coninhcount <= 0)	/* shouldn't happen */
8635 			elog(ERROR, "relation %u has non-inherited constraint \"%s\"",
8636 				 childrelid, constrName);
8637 
8638 		if (recurse)
8639 		{
8640 			/*
8641 			 * If the child constraint has other definition sources, just
8642 			 * decrement its inheritance count; if not, recurse to delete it.
8643 			 */
8644 			if (con->coninhcount == 1 && !con->conislocal)
8645 			{
8646 				/* Time to delete this child constraint, too */
8647 				ATExecDropConstraint(childrel, constrName, behavior,
8648 									 true, true,
8649 									 false, lockmode);
8650 			}
8651 			else
8652 			{
8653 				/* Child constraint must survive my deletion */
8654 				con->coninhcount--;
8655 				CatalogTupleUpdate(conrel, &copy_tuple->t_self, copy_tuple);
8656 
8657 				/* Make update visible */
8658 				CommandCounterIncrement();
8659 			}
8660 		}
8661 		else
8662 		{
8663 			/*
8664 			 * If we were told to drop ONLY in this table (no recursion), we
8665 			 * need to mark the inheritors' constraints as locally defined
8666 			 * rather than inherited.
8667 			 */
8668 			con->coninhcount--;
8669 			con->conislocal = true;
8670 
8671 			CatalogTupleUpdate(conrel, &copy_tuple->t_self, copy_tuple);
8672 
8673 			/* Make update visible */
8674 			CommandCounterIncrement();
8675 		}
8676 
8677 		heap_freetuple(copy_tuple);
8678 
8679 		heap_close(childrel, NoLock);
8680 	}
8681 
8682 	heap_close(conrel, RowExclusiveLock);
8683 }
8684 
8685 /*
8686  * ALTER COLUMN TYPE
8687  */
8688 static void
ATPrepAlterColumnType(List ** wqueue,AlteredTableInfo * tab,Relation rel,bool recurse,bool recursing,AlterTableCmd * cmd,LOCKMODE lockmode)8689 ATPrepAlterColumnType(List **wqueue,
8690 					  AlteredTableInfo *tab, Relation rel,
8691 					  bool recurse, bool recursing,
8692 					  AlterTableCmd *cmd, LOCKMODE lockmode)
8693 {
8694 	char	   *colName = cmd->name;
8695 	ColumnDef  *def = (ColumnDef *) cmd->def;
8696 	TypeName   *typeName = def->typeName;
8697 	Node	   *transform = def->cooked_default;
8698 	HeapTuple	tuple;
8699 	Form_pg_attribute attTup;
8700 	AttrNumber	attnum;
8701 	Oid			targettype;
8702 	int32		targettypmod;
8703 	Oid			targetcollid;
8704 	NewColumnValue *newval;
8705 	ParseState *pstate = make_parsestate(NULL);
8706 	AclResult	aclresult;
8707 	bool		is_expr;
8708 
8709 	if (rel->rd_rel->reloftype && !recursing)
8710 		ereport(ERROR,
8711 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
8712 				 errmsg("cannot alter column type of typed table")));
8713 
8714 	/* lookup the attribute so we can check inheritance status */
8715 	tuple = SearchSysCacheAttName(RelationGetRelid(rel), colName);
8716 	if (!HeapTupleIsValid(tuple))
8717 		ereport(ERROR,
8718 				(errcode(ERRCODE_UNDEFINED_COLUMN),
8719 				 errmsg("column \"%s\" of relation \"%s\" does not exist",
8720 						colName, RelationGetRelationName(rel))));
8721 	attTup = (Form_pg_attribute) GETSTRUCT(tuple);
8722 	attnum = attTup->attnum;
8723 
8724 	/* Can't alter a system attribute */
8725 	if (attnum <= 0)
8726 		ereport(ERROR,
8727 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
8728 				 errmsg("cannot alter system column \"%s\"",
8729 						colName)));
8730 
8731 	/*
8732 	 * Don't alter inherited columns.  At outer level, there had better not be
8733 	 * any inherited definition; when recursing, we assume this was checked at
8734 	 * the parent level (see below).
8735 	 */
8736 	if (attTup->attinhcount > 0 && !recursing)
8737 		ereport(ERROR,
8738 				(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
8739 				 errmsg("cannot alter inherited column \"%s\"",
8740 						colName)));
8741 
8742 	/* Don't alter columns used in the partition key */
8743 	if (is_partition_attr(rel, attnum, &is_expr))
8744 		ereport(ERROR,
8745 				(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
8746 				 errmsg("cannot alter column \"%s\" because it is part of the partition key of relation \"%s\"",
8747 						colName, RelationGetRelationName(rel))));
8748 
8749 	/* Look up the target type */
8750 	typenameTypeIdAndMod(NULL, typeName, &targettype, &targettypmod);
8751 
8752 	aclresult = pg_type_aclcheck(targettype, GetUserId(), ACL_USAGE);
8753 	if (aclresult != ACLCHECK_OK)
8754 		aclcheck_error_type(aclresult, targettype);
8755 
8756 	/* And the collation */
8757 	targetcollid = GetColumnDefCollation(NULL, def, targettype);
8758 
8759 	/* make sure datatype is legal for a column */
8760 	CheckAttributeType(colName, targettype, targetcollid,
8761 					   list_make1_oid(rel->rd_rel->reltype),
8762 					   false);
8763 
8764 	if (tab->relkind == RELKIND_RELATION ||
8765 		tab->relkind == RELKIND_PARTITIONED_TABLE)
8766 	{
8767 		/*
8768 		 * Set up an expression to transform the old data value to the new
8769 		 * type. If a USING option was given, use the expression as
8770 		 * transformed by transformAlterTableStmt, else just take the old
8771 		 * value and try to coerce it.  We do this first so that type
8772 		 * incompatibility can be detected before we waste effort, and because
8773 		 * we need the expression to be parsed against the original table row
8774 		 * type.
8775 		 */
8776 		if (!transform)
8777 		{
8778 			transform = (Node *) makeVar(1, attnum,
8779 										 attTup->atttypid, attTup->atttypmod,
8780 										 attTup->attcollation,
8781 										 0);
8782 		}
8783 
8784 		transform = coerce_to_target_type(pstate,
8785 										  transform, exprType(transform),
8786 										  targettype, targettypmod,
8787 										  COERCION_ASSIGNMENT,
8788 										  COERCE_IMPLICIT_CAST,
8789 										  -1);
8790 		if (transform == NULL)
8791 		{
8792 			/* error text depends on whether USING was specified or not */
8793 			if (def->cooked_default != NULL)
8794 				ereport(ERROR,
8795 						(errcode(ERRCODE_DATATYPE_MISMATCH),
8796 						 errmsg("result of USING clause for column \"%s\""
8797 								" cannot be cast automatically to type %s",
8798 								colName, format_type_be(targettype)),
8799 						 errhint("You might need to add an explicit cast.")));
8800 			else
8801 				ereport(ERROR,
8802 						(errcode(ERRCODE_DATATYPE_MISMATCH),
8803 						 errmsg("column \"%s\" cannot be cast automatically to type %s",
8804 								colName, format_type_be(targettype)),
8805 				/* translator: USING is SQL, don't translate it */
8806 						 errhint("You might need to specify \"USING %s::%s\".",
8807 								 quote_identifier(colName),
8808 								 format_type_with_typemod(targettype,
8809 														  targettypmod))));
8810 		}
8811 
8812 		/* Fix collations after all else */
8813 		assign_expr_collations(pstate, transform);
8814 
8815 		/* Plan the expr now so we can accurately assess the need to rewrite. */
8816 		transform = (Node *) expression_planner((Expr *) transform);
8817 
8818 		/*
8819 		 * Add a work queue item to make ATRewriteTable update the column
8820 		 * contents.
8821 		 */
8822 		newval = (NewColumnValue *) palloc0(sizeof(NewColumnValue));
8823 		newval->attnum = attnum;
8824 		newval->expr = (Expr *) transform;
8825 
8826 		tab->newvals = lappend(tab->newvals, newval);
8827 		if (ATColumnChangeRequiresRewrite(transform, attnum))
8828 			tab->rewrite |= AT_REWRITE_COLUMN_REWRITE;
8829 	}
8830 	else if (transform)
8831 		ereport(ERROR,
8832 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
8833 				 errmsg("\"%s\" is not a table",
8834 						RelationGetRelationName(rel))));
8835 
8836 	if (tab->relkind == RELKIND_COMPOSITE_TYPE ||
8837 		tab->relkind == RELKIND_FOREIGN_TABLE)
8838 	{
8839 		/*
8840 		 * For composite types, do this check now.  Tables will check it later
8841 		 * when the table is being rewritten.
8842 		 */
8843 		find_composite_type_dependencies(rel->rd_rel->reltype, rel, NULL);
8844 	}
8845 
8846 	ReleaseSysCache(tuple);
8847 
8848 	/*
8849 	 * Recurse manually by queueing a new command for each child, if
8850 	 * necessary. We cannot apply ATSimpleRecursion here because we need to
8851 	 * remap attribute numbers in the USING expression, if any.
8852 	 *
8853 	 * If we are told not to recurse, there had better not be any child
8854 	 * tables; else the alter would put them out of step.
8855 	 */
8856 	if (recurse)
8857 	{
8858 		Oid			relid = RelationGetRelid(rel);
8859 		List	   *child_oids,
8860 				   *child_numparents;
8861 		ListCell   *lo,
8862 				   *li;
8863 
8864 		child_oids = find_all_inheritors(relid, lockmode,
8865 										 &child_numparents);
8866 
8867 		/*
8868 		 * find_all_inheritors does the recursive search of the inheritance
8869 		 * hierarchy, so all we have to do is process all of the relids in the
8870 		 * list that it returns.
8871 		 */
8872 		forboth(lo, child_oids, li, child_numparents)
8873 		{
8874 			Oid			childrelid = lfirst_oid(lo);
8875 			int			numparents = lfirst_int(li);
8876 			Relation	childrel;
8877 			HeapTuple	childtuple;
8878 			Form_pg_attribute childattTup;
8879 
8880 			if (childrelid == relid)
8881 				continue;
8882 
8883 			/* find_all_inheritors already got lock */
8884 			childrel = relation_open(childrelid, NoLock);
8885 			CheckTableNotInUse(childrel, "ALTER TABLE");
8886 
8887 			/*
8888 			 * Verify that the child doesn't have any inherited definitions of
8889 			 * this column that came from outside this inheritance hierarchy.
8890 			 * (renameatt makes a similar test, though in a different way
8891 			 * because of its different recursion mechanism.)
8892 			 */
8893 			childtuple = SearchSysCacheAttName(RelationGetRelid(childrel),
8894 											   colName);
8895 			if (!HeapTupleIsValid(childtuple))
8896 				ereport(ERROR,
8897 						(errcode(ERRCODE_UNDEFINED_COLUMN),
8898 						 errmsg("column \"%s\" of relation \"%s\" does not exist",
8899 								colName, RelationGetRelationName(childrel))));
8900 			childattTup = (Form_pg_attribute) GETSTRUCT(childtuple);
8901 
8902 			if (childattTup->attinhcount > numparents)
8903 				ereport(ERROR,
8904 						(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
8905 						 errmsg("cannot alter inherited column \"%s\" of relation \"%s\"",
8906 								colName, RelationGetRelationName(childrel))));
8907 
8908 			ReleaseSysCache(childtuple);
8909 
8910 			/*
8911 			 * Remap the attribute numbers.  If no USING expression was
8912 			 * specified, there is no need for this step.
8913 			 */
8914 			if (def->cooked_default)
8915 			{
8916 				AttrNumber *attmap;
8917 				bool		found_whole_row;
8918 
8919 				/* create a copy to scribble on */
8920 				cmd = copyObject(cmd);
8921 
8922 				attmap = convert_tuples_by_name_map(RelationGetDescr(childrel),
8923 													RelationGetDescr(rel),
8924 													gettext_noop("could not convert row type"));
8925 				((ColumnDef *) cmd->def)->cooked_default =
8926 					map_variable_attnos(def->cooked_default,
8927 										1, 0,
8928 										attmap, RelationGetDescr(rel)->natts,
8929 										InvalidOid, &found_whole_row);
8930 				if (found_whole_row)
8931 					ereport(ERROR,
8932 							(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
8933 							 errmsg("cannot convert whole-row table reference"),
8934 							 errdetail("USING expression contains a whole-row table reference.")));
8935 				pfree(attmap);
8936 			}
8937 			ATPrepCmd(wqueue, childrel, cmd, false, true, lockmode);
8938 			relation_close(childrel, NoLock);
8939 		}
8940 	}
8941 	else if (!recursing &&
8942 			 find_inheritance_children(RelationGetRelid(rel), NoLock) != NIL)
8943 		ereport(ERROR,
8944 				(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
8945 				 errmsg("type of inherited column \"%s\" must be changed in child tables too",
8946 						colName)));
8947 
8948 	if (tab->relkind == RELKIND_COMPOSITE_TYPE)
8949 		ATTypedTableRecursion(wqueue, rel, cmd, lockmode);
8950 }
8951 
8952 /*
8953  * When the data type of a column is changed, a rewrite might not be required
8954  * if the new type is sufficiently identical to the old one, and the USING
8955  * clause isn't trying to insert some other value.  It's safe to skip the
8956  * rewrite if the old type is binary coercible to the new type, or if the
8957  * new type is an unconstrained domain over the old type.  In the case of a
8958  * constrained domain, we could get by with scanning the table and checking
8959  * the constraint rather than actually rewriting it, but we don't currently
8960  * try to do that.
8961  */
8962 static bool
ATColumnChangeRequiresRewrite(Node * expr,AttrNumber varattno)8963 ATColumnChangeRequiresRewrite(Node *expr, AttrNumber varattno)
8964 {
8965 	Assert(expr != NULL);
8966 
8967 	for (;;)
8968 	{
8969 		/* only one varno, so no need to check that */
8970 		if (IsA(expr, Var) &&((Var *) expr)->varattno == varattno)
8971 			return false;
8972 		else if (IsA(expr, RelabelType))
8973 			expr = (Node *) ((RelabelType *) expr)->arg;
8974 		else if (IsA(expr, CoerceToDomain))
8975 		{
8976 			CoerceToDomain *d = (CoerceToDomain *) expr;
8977 
8978 			if (DomainHasConstraints(d->resulttype))
8979 				return true;
8980 			expr = (Node *) d->arg;
8981 		}
8982 		else
8983 			return true;
8984 	}
8985 }
8986 
8987 /*
8988  * ALTER COLUMN .. SET DATA TYPE
8989  *
8990  * Return the address of the modified column.
8991  */
8992 static ObjectAddress
ATExecAlterColumnType(AlteredTableInfo * tab,Relation rel,AlterTableCmd * cmd,LOCKMODE lockmode)8993 ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel,
8994 					  AlterTableCmd *cmd, LOCKMODE lockmode)
8995 {
8996 	char	   *colName = cmd->name;
8997 	ColumnDef  *def = (ColumnDef *) cmd->def;
8998 	TypeName   *typeName = def->typeName;
8999 	HeapTuple	heapTup;
9000 	Form_pg_attribute attTup;
9001 	AttrNumber	attnum;
9002 	HeapTuple	typeTuple;
9003 	Form_pg_type tform;
9004 	Oid			targettype;
9005 	int32		targettypmod;
9006 	Oid			targetcollid;
9007 	Node	   *defaultexpr;
9008 	Relation	attrelation;
9009 	Relation	depRel;
9010 	ScanKeyData key[3];
9011 	SysScanDesc scan;
9012 	HeapTuple	depTup;
9013 	ObjectAddress address;
9014 
9015 	attrelation = heap_open(AttributeRelationId, RowExclusiveLock);
9016 
9017 	/* Look up the target column */
9018 	heapTup = SearchSysCacheCopyAttName(RelationGetRelid(rel), colName);
9019 	if (!HeapTupleIsValid(heapTup)) /* shouldn't happen */
9020 		ereport(ERROR,
9021 				(errcode(ERRCODE_UNDEFINED_COLUMN),
9022 				 errmsg("column \"%s\" of relation \"%s\" does not exist",
9023 						colName, RelationGetRelationName(rel))));
9024 	attTup = (Form_pg_attribute) GETSTRUCT(heapTup);
9025 	attnum = attTup->attnum;
9026 
9027 	/* Check for multiple ALTER TYPE on same column --- can't cope */
9028 	if (attTup->atttypid != tab->oldDesc->attrs[attnum - 1]->atttypid ||
9029 		attTup->atttypmod != tab->oldDesc->attrs[attnum - 1]->atttypmod)
9030 		ereport(ERROR,
9031 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
9032 				 errmsg("cannot alter type of column \"%s\" twice",
9033 						colName)));
9034 
9035 	/* Look up the target type (should not fail, since prep found it) */
9036 	typeTuple = typenameType(NULL, typeName, &targettypmod);
9037 	tform = (Form_pg_type) GETSTRUCT(typeTuple);
9038 	targettype = HeapTupleGetOid(typeTuple);
9039 	/* And the collation */
9040 	targetcollid = GetColumnDefCollation(NULL, def, targettype);
9041 
9042 	/*
9043 	 * If there is a default expression for the column, get it and ensure we
9044 	 * can coerce it to the new datatype.  (We must do this before changing
9045 	 * the column type, because build_column_default itself will try to
9046 	 * coerce, and will not issue the error message we want if it fails.)
9047 	 *
9048 	 * We remove any implicit coercion steps at the top level of the old
9049 	 * default expression; this has been agreed to satisfy the principle of
9050 	 * least surprise.  (The conversion to the new column type should act like
9051 	 * it started from what the user sees as the stored expression, and the
9052 	 * implicit coercions aren't going to be shown.)
9053 	 */
9054 	if (attTup->atthasdef)
9055 	{
9056 		defaultexpr = build_column_default(rel, attnum);
9057 		Assert(defaultexpr);
9058 		defaultexpr = strip_implicit_coercions(defaultexpr);
9059 		defaultexpr = coerce_to_target_type(NULL,	/* no UNKNOWN params */
9060 											defaultexpr, exprType(defaultexpr),
9061 											targettype, targettypmod,
9062 											COERCION_ASSIGNMENT,
9063 											COERCE_IMPLICIT_CAST,
9064 											-1);
9065 		if (defaultexpr == NULL)
9066 			ereport(ERROR,
9067 					(errcode(ERRCODE_DATATYPE_MISMATCH),
9068 					 errmsg("default for column \"%s\" cannot be cast automatically to type %s",
9069 							colName, format_type_be(targettype))));
9070 	}
9071 	else
9072 		defaultexpr = NULL;
9073 
9074 	/*
9075 	 * Find everything that depends on the column (constraints, indexes, etc),
9076 	 * and record enough information to let us recreate the objects.
9077 	 *
9078 	 * The actual recreation does not happen here, but only after we have
9079 	 * performed all the individual ALTER TYPE operations.  We have to save
9080 	 * the info before executing ALTER TYPE, though, else the deparser will
9081 	 * get confused.
9082 	 */
9083 	depRel = heap_open(DependRelationId, RowExclusiveLock);
9084 
9085 	ScanKeyInit(&key[0],
9086 				Anum_pg_depend_refclassid,
9087 				BTEqualStrategyNumber, F_OIDEQ,
9088 				ObjectIdGetDatum(RelationRelationId));
9089 	ScanKeyInit(&key[1],
9090 				Anum_pg_depend_refobjid,
9091 				BTEqualStrategyNumber, F_OIDEQ,
9092 				ObjectIdGetDatum(RelationGetRelid(rel)));
9093 	ScanKeyInit(&key[2],
9094 				Anum_pg_depend_refobjsubid,
9095 				BTEqualStrategyNumber, F_INT4EQ,
9096 				Int32GetDatum((int32) attnum));
9097 
9098 	scan = systable_beginscan(depRel, DependReferenceIndexId, true,
9099 							  NULL, 3, key);
9100 
9101 	while (HeapTupleIsValid(depTup = systable_getnext(scan)))
9102 	{
9103 		Form_pg_depend foundDep = (Form_pg_depend) GETSTRUCT(depTup);
9104 		ObjectAddress foundObject;
9105 
9106 		/* We don't expect any PIN dependencies on columns */
9107 		if (foundDep->deptype == DEPENDENCY_PIN)
9108 			elog(ERROR, "cannot alter type of a pinned column");
9109 
9110 		foundObject.classId = foundDep->classid;
9111 		foundObject.objectId = foundDep->objid;
9112 		foundObject.objectSubId = foundDep->objsubid;
9113 
9114 		switch (getObjectClass(&foundObject))
9115 		{
9116 			case OCLASS_CLASS:
9117 				{
9118 					char		relKind = get_rel_relkind(foundObject.objectId);
9119 
9120 					if (relKind == RELKIND_INDEX)
9121 					{
9122 						Assert(foundObject.objectSubId == 0);
9123 						RememberIndexForRebuilding(foundObject.objectId, tab);
9124 					}
9125 					else if (relKind == RELKIND_SEQUENCE)
9126 					{
9127 						/*
9128 						 * This must be a SERIAL column's sequence.  We need
9129 						 * not do anything to it.
9130 						 */
9131 						Assert(foundObject.objectSubId == 0);
9132 					}
9133 					else
9134 					{
9135 						/* Not expecting any other direct dependencies... */
9136 						elog(ERROR, "unexpected object depending on column: %s",
9137 							 getObjectDescription(&foundObject));
9138 					}
9139 					break;
9140 				}
9141 
9142 			case OCLASS_CONSTRAINT:
9143 				Assert(foundObject.objectSubId == 0);
9144 				RememberConstraintForRebuilding(foundObject.objectId, tab,
9145 												foundDep->deptype);
9146 				break;
9147 
9148 			case OCLASS_REWRITE:
9149 				/* XXX someday see if we can cope with revising views */
9150 				ereport(ERROR,
9151 						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
9152 						 errmsg("cannot alter type of a column used by a view or rule"),
9153 						 errdetail("%s depends on column \"%s\"",
9154 								   getObjectDescription(&foundObject),
9155 								   colName)));
9156 				break;
9157 
9158 			case OCLASS_TRIGGER:
9159 
9160 				/*
9161 				 * A trigger can depend on a column because the column is
9162 				 * specified as an update target, or because the column is
9163 				 * used in the trigger's WHEN condition.  The first case would
9164 				 * not require any extra work, but the second case would
9165 				 * require updating the WHEN expression, which will take a
9166 				 * significant amount of new code.  Since we can't easily tell
9167 				 * which case applies, we punt for both.  FIXME someday.
9168 				 */
9169 				ereport(ERROR,
9170 						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
9171 						 errmsg("cannot alter type of a column used in a trigger definition"),
9172 						 errdetail("%s depends on column \"%s\"",
9173 								   getObjectDescription(&foundObject),
9174 								   colName)));
9175 				break;
9176 
9177 			case OCLASS_POLICY:
9178 
9179 				/*
9180 				 * A policy can depend on a column because the column is
9181 				 * specified in the policy's USING or WITH CHECK qual
9182 				 * expressions.  It might be possible to rewrite and recheck
9183 				 * the policy expression, but punt for now.  It's certainly
9184 				 * easy enough to remove and recreate the policy; still, FIXME
9185 				 * someday.
9186 				 */
9187 				ereport(ERROR,
9188 						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
9189 						 errmsg("cannot alter type of a column used in a policy definition"),
9190 						 errdetail("%s depends on column \"%s\"",
9191 								   getObjectDescription(&foundObject),
9192 								   colName)));
9193 				break;
9194 
9195 			case OCLASS_DEFAULT:
9196 
9197 				/*
9198 				 * Ignore the column's default expression, since we will fix
9199 				 * it below.
9200 				 */
9201 				Assert(defaultexpr);
9202 				break;
9203 
9204 			case OCLASS_STATISTIC_EXT:
9205 
9206 				/*
9207 				 * Give the extended-stats machinery a chance to fix anything
9208 				 * that this column type change would break.
9209 				 */
9210 				UpdateStatisticsForTypeChange(foundObject.objectId,
9211 											  RelationGetRelid(rel), attnum,
9212 											  attTup->atttypid, targettype);
9213 				break;
9214 
9215 			case OCLASS_PROC:
9216 			case OCLASS_TYPE:
9217 			case OCLASS_CAST:
9218 			case OCLASS_COLLATION:
9219 			case OCLASS_CONVERSION:
9220 			case OCLASS_LANGUAGE:
9221 			case OCLASS_LARGEOBJECT:
9222 			case OCLASS_OPERATOR:
9223 			case OCLASS_OPCLASS:
9224 			case OCLASS_OPFAMILY:
9225 			case OCLASS_AM:
9226 			case OCLASS_AMOP:
9227 			case OCLASS_AMPROC:
9228 			case OCLASS_SCHEMA:
9229 			case OCLASS_TSPARSER:
9230 			case OCLASS_TSDICT:
9231 			case OCLASS_TSTEMPLATE:
9232 			case OCLASS_TSCONFIG:
9233 			case OCLASS_ROLE:
9234 			case OCLASS_DATABASE:
9235 			case OCLASS_TBLSPACE:
9236 			case OCLASS_FDW:
9237 			case OCLASS_FOREIGN_SERVER:
9238 			case OCLASS_USER_MAPPING:
9239 			case OCLASS_DEFACL:
9240 			case OCLASS_EXTENSION:
9241 			case OCLASS_EVENT_TRIGGER:
9242 			case OCLASS_PUBLICATION:
9243 			case OCLASS_PUBLICATION_REL:
9244 			case OCLASS_SUBSCRIPTION:
9245 			case OCLASS_TRANSFORM:
9246 
9247 				/*
9248 				 * We don't expect any of these sorts of objects to depend on
9249 				 * a column.
9250 				 */
9251 				elog(ERROR, "unexpected object depending on column: %s",
9252 					 getObjectDescription(&foundObject));
9253 				break;
9254 
9255 				/*
9256 				 * There's intentionally no default: case here; we want the
9257 				 * compiler to warn if a new OCLASS hasn't been handled above.
9258 				 */
9259 		}
9260 	}
9261 
9262 	systable_endscan(scan);
9263 
9264 	/*
9265 	 * Now scan for dependencies of this column on other things.  The only
9266 	 * thing we should find is the dependency on the column datatype, which we
9267 	 * want to remove, and possibly a collation dependency.
9268 	 */
9269 	ScanKeyInit(&key[0],
9270 				Anum_pg_depend_classid,
9271 				BTEqualStrategyNumber, F_OIDEQ,
9272 				ObjectIdGetDatum(RelationRelationId));
9273 	ScanKeyInit(&key[1],
9274 				Anum_pg_depend_objid,
9275 				BTEqualStrategyNumber, F_OIDEQ,
9276 				ObjectIdGetDatum(RelationGetRelid(rel)));
9277 	ScanKeyInit(&key[2],
9278 				Anum_pg_depend_objsubid,
9279 				BTEqualStrategyNumber, F_INT4EQ,
9280 				Int32GetDatum((int32) attnum));
9281 
9282 	scan = systable_beginscan(depRel, DependDependerIndexId, true,
9283 							  NULL, 3, key);
9284 
9285 	while (HeapTupleIsValid(depTup = systable_getnext(scan)))
9286 	{
9287 		Form_pg_depend foundDep = (Form_pg_depend) GETSTRUCT(depTup);
9288 
9289 		if (foundDep->deptype != DEPENDENCY_NORMAL)
9290 			elog(ERROR, "found unexpected dependency type '%c'",
9291 				 foundDep->deptype);
9292 		if (!(foundDep->refclassid == TypeRelationId &&
9293 			  foundDep->refobjid == attTup->atttypid) &&
9294 			!(foundDep->refclassid == CollationRelationId &&
9295 			  foundDep->refobjid == attTup->attcollation))
9296 			elog(ERROR, "found unexpected dependency for column");
9297 
9298 		CatalogTupleDelete(depRel, &depTup->t_self);
9299 	}
9300 
9301 	systable_endscan(scan);
9302 
9303 	heap_close(depRel, RowExclusiveLock);
9304 
9305 	/*
9306 	 * Here we go --- change the recorded column type and collation.  (Note
9307 	 * heapTup is a copy of the syscache entry, so okay to scribble on.)
9308 	 */
9309 	attTup->atttypid = targettype;
9310 	attTup->atttypmod = targettypmod;
9311 	attTup->attcollation = targetcollid;
9312 	attTup->attndims = list_length(typeName->arrayBounds);
9313 	attTup->attlen = tform->typlen;
9314 	attTup->attbyval = tform->typbyval;
9315 	attTup->attalign = tform->typalign;
9316 	attTup->attstorage = tform->typstorage;
9317 
9318 	ReleaseSysCache(typeTuple);
9319 
9320 	CatalogTupleUpdate(attrelation, &heapTup->t_self, heapTup);
9321 
9322 	heap_close(attrelation, RowExclusiveLock);
9323 
9324 	/* Install dependencies on new datatype and collation */
9325 	add_column_datatype_dependency(RelationGetRelid(rel), attnum, targettype);
9326 	add_column_collation_dependency(RelationGetRelid(rel), attnum, targetcollid);
9327 
9328 	/*
9329 	 * Drop any pg_statistic entry for the column, since it's now wrong type
9330 	 */
9331 	RemoveStatistics(RelationGetRelid(rel), attnum);
9332 
9333 	InvokeObjectPostAlterHook(RelationRelationId,
9334 							  RelationGetRelid(rel), attnum);
9335 
9336 	/*
9337 	 * Update the default, if present, by brute force --- remove and re-add
9338 	 * the default.  Probably unsafe to take shortcuts, since the new version
9339 	 * may well have additional dependencies.  (It's okay to do this now,
9340 	 * rather than after other ALTER TYPE commands, since the default won't
9341 	 * depend on other column types.)
9342 	 */
9343 	if (defaultexpr)
9344 	{
9345 		/* Must make new row visible since it will be updated again */
9346 		CommandCounterIncrement();
9347 
9348 		/*
9349 		 * We use RESTRICT here for safety, but at present we do not expect
9350 		 * anything to depend on the default.
9351 		 */
9352 		RemoveAttrDefault(RelationGetRelid(rel), attnum, DROP_RESTRICT, true,
9353 						  true);
9354 
9355 		StoreAttrDefault(rel, attnum, defaultexpr, true);
9356 	}
9357 
9358 	ObjectAddressSubSet(address, RelationRelationId,
9359 						RelationGetRelid(rel), attnum);
9360 
9361 	/* Cleanup */
9362 	heap_freetuple(heapTup);
9363 
9364 	return address;
9365 }
9366 
9367 /*
9368  * Subroutine for ATExecAlterColumnType: remember that a replica identity
9369  * needs to be reset.
9370  */
9371 static void
RememberReplicaIdentityForRebuilding(Oid indoid,AlteredTableInfo * tab)9372 RememberReplicaIdentityForRebuilding(Oid indoid, AlteredTableInfo *tab)
9373 {
9374 	if (!get_index_isreplident(indoid))
9375 		return;
9376 
9377 	if (tab->replicaIdentityIndex)
9378 		elog(ERROR, "relation %u has multiple indexes marked as replica identity", tab->relid);
9379 
9380 	tab->replicaIdentityIndex = get_rel_name(indoid);
9381 }
9382 
9383 /*
9384  * Subroutine for ATExecAlterColumnType: remember any clustered index.
9385  */
9386 static void
RememberClusterOnForRebuilding(Oid indoid,AlteredTableInfo * tab)9387 RememberClusterOnForRebuilding(Oid indoid, AlteredTableInfo *tab)
9388 {
9389 	if (!get_index_isclustered(indoid))
9390 		return;
9391 
9392 	if (tab->clusterOnIndex)
9393 		elog(ERROR, "relation %u has multiple clustered indexes", tab->relid);
9394 
9395 	tab->clusterOnIndex = get_rel_name(indoid);
9396 }
9397 
9398 /*
9399  * Subroutine for ATExecAlterColumnType: remember that a constraint needs
9400  * to be rebuilt (which we might already know).
9401  */
9402 static void
RememberConstraintForRebuilding(Oid conoid,AlteredTableInfo * tab,DependencyType deptype)9403 RememberConstraintForRebuilding(Oid conoid, AlteredTableInfo *tab,
9404 								DependencyType deptype)
9405 {
9406 	/*
9407 	 * This de-duplication check is critical for two independent reasons: we
9408 	 * mustn't try to recreate the same constraint twice, and if a constraint
9409 	 * depends on more than one column whose type is to be altered, we must
9410 	 * capture its definition string before applying any of the column type
9411 	 * changes.  ruleutils.c will get confused if we ask again later.
9412 	 */
9413 	if (!list_member_oid(tab->changedConstraintOids, conoid))
9414 	{
9415 		/* OK, capture the constraint's existing definition string */
9416 		char	   *defstring = pg_get_constraintdef_command(conoid);
9417 		Oid			indoid;
9418 
9419 		/*
9420 		 * Put NORMAL dependencies at the front of the list and AUTO
9421 		 * dependencies at the back.  This makes sure that foreign-key
9422 		 * constraints depending on this column will be dropped before unique
9423 		 * or primary-key constraints of the column; which we must have
9424 		 * because the FK constraints depend on the indexes belonging to the
9425 		 * unique constraints.
9426 		 */
9427 		if (deptype == DEPENDENCY_NORMAL)
9428 		{
9429 			tab->changedConstraintOids = lcons_oid(conoid,
9430 												   tab->changedConstraintOids);
9431 			tab->changedConstraintDefs = lcons(defstring,
9432 											   tab->changedConstraintDefs);
9433 		}
9434 		else
9435 		{
9436 			tab->changedConstraintOids = lappend_oid(tab->changedConstraintOids,
9437 													 conoid);
9438 			tab->changedConstraintDefs = lappend(tab->changedConstraintDefs,
9439 												 defstring);
9440 		}
9441 
9442 		/*
9443 		 * For the index of a constraint, if any, remember if it is used for
9444 		 * the table's replica identity or if it is a clustered index, so that
9445 		 * ATPostAlterTypeCleanup() can queue up commands necessary to restore
9446 		 * those properties.
9447 		 */
9448 		indoid = get_constraint_index(conoid);
9449 		if (OidIsValid(indoid))
9450 		{
9451 			RememberReplicaIdentityForRebuilding(indoid, tab);
9452 			RememberClusterOnForRebuilding(indoid, tab);
9453 		}
9454 	}
9455 }
9456 
9457 /*
9458  * Subroutine for ATExecAlterColumnType: remember that an index needs
9459  * to be rebuilt (which we might already know).
9460  */
9461 static void
RememberIndexForRebuilding(Oid indoid,AlteredTableInfo * tab)9462 RememberIndexForRebuilding(Oid indoid, AlteredTableInfo *tab)
9463 {
9464 	/*
9465 	 * This de-duplication check is critical for two independent reasons: we
9466 	 * mustn't try to recreate the same index twice, and if an index depends
9467 	 * on more than one column whose type is to be altered, we must capture
9468 	 * its definition string before applying any of the column type changes.
9469 	 * ruleutils.c will get confused if we ask again later.
9470 	 */
9471 	if (!list_member_oid(tab->changedIndexOids, indoid))
9472 	{
9473 		/*
9474 		 * Before adding it as an index-to-rebuild, we'd better see if it
9475 		 * belongs to a constraint, and if so rebuild the constraint instead.
9476 		 * Typically this check fails, because constraint indexes normally
9477 		 * have only dependencies on their constraint.  But it's possible for
9478 		 * such an index to also have direct dependencies on table columns,
9479 		 * for example with a partial exclusion constraint.
9480 		 */
9481 		Oid			conoid = get_index_constraint(indoid);
9482 
9483 		if (OidIsValid(conoid))
9484 		{
9485 			/* index dependencies on columns should generally be AUTO */
9486 			RememberConstraintForRebuilding(conoid, tab, DEPENDENCY_AUTO);
9487 		}
9488 		else
9489 		{
9490 			/* OK, capture the index's existing definition string */
9491 			char	   *defstring = pg_get_indexdef_string(indoid);
9492 
9493 			tab->changedIndexOids = lappend_oid(tab->changedIndexOids,
9494 												indoid);
9495 			tab->changedIndexDefs = lappend(tab->changedIndexDefs,
9496 											defstring);
9497 
9498 			/*
9499 			 * Remember if this index is used for the table's replica identity
9500 			 * or if it is a clustered index, so that ATPostAlterTypeCleanup()
9501 			 * can queue up commands necessary to restore those properties.
9502 			 */
9503 			RememberReplicaIdentityForRebuilding(indoid, tab);
9504 			RememberClusterOnForRebuilding(indoid, tab);
9505 		}
9506 	}
9507 }
9508 
9509 /*
9510  * Returns the address of the modified column
9511  */
9512 static ObjectAddress
ATExecAlterColumnGenericOptions(Relation rel,const char * colName,List * options,LOCKMODE lockmode)9513 ATExecAlterColumnGenericOptions(Relation rel,
9514 								const char *colName,
9515 								List *options,
9516 								LOCKMODE lockmode)
9517 {
9518 	Relation	ftrel;
9519 	Relation	attrel;
9520 	ForeignServer *server;
9521 	ForeignDataWrapper *fdw;
9522 	HeapTuple	tuple;
9523 	HeapTuple	newtuple;
9524 	bool		isnull;
9525 	Datum		repl_val[Natts_pg_attribute];
9526 	bool		repl_null[Natts_pg_attribute];
9527 	bool		repl_repl[Natts_pg_attribute];
9528 	Datum		datum;
9529 	Form_pg_foreign_table fttableform;
9530 	Form_pg_attribute atttableform;
9531 	AttrNumber	attnum;
9532 	ObjectAddress address;
9533 
9534 	if (options == NIL)
9535 		return InvalidObjectAddress;
9536 
9537 	/* First, determine FDW validator associated to the foreign table. */
9538 	ftrel = heap_open(ForeignTableRelationId, AccessShareLock);
9539 	tuple = SearchSysCache1(FOREIGNTABLEREL, rel->rd_id);
9540 	if (!HeapTupleIsValid(tuple))
9541 		ereport(ERROR,
9542 				(errcode(ERRCODE_UNDEFINED_OBJECT),
9543 				 errmsg("foreign table \"%s\" does not exist",
9544 						RelationGetRelationName(rel))));
9545 	fttableform = (Form_pg_foreign_table) GETSTRUCT(tuple);
9546 	server = GetForeignServer(fttableform->ftserver);
9547 	fdw = GetForeignDataWrapper(server->fdwid);
9548 
9549 	heap_close(ftrel, AccessShareLock);
9550 	ReleaseSysCache(tuple);
9551 
9552 	attrel = heap_open(AttributeRelationId, RowExclusiveLock);
9553 	tuple = SearchSysCacheAttName(RelationGetRelid(rel), colName);
9554 	if (!HeapTupleIsValid(tuple))
9555 		ereport(ERROR,
9556 				(errcode(ERRCODE_UNDEFINED_COLUMN),
9557 				 errmsg("column \"%s\" of relation \"%s\" does not exist",
9558 						colName, RelationGetRelationName(rel))));
9559 
9560 	/* Prevent them from altering a system attribute */
9561 	atttableform = (Form_pg_attribute) GETSTRUCT(tuple);
9562 	attnum = atttableform->attnum;
9563 	if (attnum <= 0)
9564 		ereport(ERROR,
9565 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
9566 				 errmsg("cannot alter system column \"%s\"", colName)));
9567 
9568 
9569 	/* Initialize buffers for new tuple values */
9570 	memset(repl_val, 0, sizeof(repl_val));
9571 	memset(repl_null, false, sizeof(repl_null));
9572 	memset(repl_repl, false, sizeof(repl_repl));
9573 
9574 	/* Extract the current options */
9575 	datum = SysCacheGetAttr(ATTNAME,
9576 							tuple,
9577 							Anum_pg_attribute_attfdwoptions,
9578 							&isnull);
9579 	if (isnull)
9580 		datum = PointerGetDatum(NULL);
9581 
9582 	/* Transform the options */
9583 	datum = transformGenericOptions(AttributeRelationId,
9584 									datum,
9585 									options,
9586 									fdw->fdwvalidator);
9587 
9588 	if (PointerIsValid(DatumGetPointer(datum)))
9589 		repl_val[Anum_pg_attribute_attfdwoptions - 1] = datum;
9590 	else
9591 		repl_null[Anum_pg_attribute_attfdwoptions - 1] = true;
9592 
9593 	repl_repl[Anum_pg_attribute_attfdwoptions - 1] = true;
9594 
9595 	/* Everything looks good - update the tuple */
9596 
9597 	newtuple = heap_modify_tuple(tuple, RelationGetDescr(attrel),
9598 								 repl_val, repl_null, repl_repl);
9599 
9600 	CatalogTupleUpdate(attrel, &newtuple->t_self, newtuple);
9601 
9602 	InvokeObjectPostAlterHook(RelationRelationId,
9603 							  RelationGetRelid(rel),
9604 							  atttableform->attnum);
9605 	ObjectAddressSubSet(address, RelationRelationId,
9606 						RelationGetRelid(rel), attnum);
9607 
9608 	ReleaseSysCache(tuple);
9609 
9610 	heap_close(attrel, RowExclusiveLock);
9611 
9612 	heap_freetuple(newtuple);
9613 
9614 	return address;
9615 }
9616 
9617 /*
9618  * Cleanup after we've finished all the ALTER TYPE operations for a
9619  * particular relation.  We have to drop and recreate all the indexes
9620  * and constraints that depend on the altered columns.
9621  */
9622 static void
ATPostAlterTypeCleanup(List ** wqueue,AlteredTableInfo * tab,LOCKMODE lockmode)9623 ATPostAlterTypeCleanup(List **wqueue, AlteredTableInfo *tab, LOCKMODE lockmode)
9624 {
9625 	ObjectAddress obj;
9626 	ListCell   *def_item;
9627 	ListCell   *oid_item;
9628 
9629 	/*
9630 	 * Re-parse the index and constraint definitions, and attach them to the
9631 	 * appropriate work queue entries.  We do this before dropping because in
9632 	 * the case of a FOREIGN KEY constraint, we might not yet have exclusive
9633 	 * lock on the table the constraint is attached to, and we need to get
9634 	 * that before reparsing/dropping.
9635 	 *
9636 	 * We can't rely on the output of deparsing to tell us which relation to
9637 	 * operate on, because concurrent activity might have made the name
9638 	 * resolve differently.  Instead, we've got to use the OID of the
9639 	 * constraint or index we're processing to figure out which relation to
9640 	 * operate on.
9641 	 */
9642 	forboth(oid_item, tab->changedConstraintOids,
9643 			def_item, tab->changedConstraintDefs)
9644 	{
9645 		Oid			oldId = lfirst_oid(oid_item);
9646 		HeapTuple	tup;
9647 		Form_pg_constraint con;
9648 		Oid			relid;
9649 		Oid			confrelid;
9650 		char		contype;
9651 		bool		conislocal;
9652 
9653 		tup = SearchSysCache1(CONSTROID, ObjectIdGetDatum(oldId));
9654 		if (!HeapTupleIsValid(tup)) /* should not happen */
9655 			elog(ERROR, "cache lookup failed for constraint %u", oldId);
9656 		con = (Form_pg_constraint) GETSTRUCT(tup);
9657 		relid = con->conrelid;
9658 		confrelid = con->confrelid;
9659 		contype = con->contype;
9660 		conislocal = con->conislocal;
9661 		ReleaseSysCache(tup);
9662 
9663 		/*
9664 		 * If the constraint is inherited (only), we don't want to inject a
9665 		 * new definition here; it'll get recreated when ATAddCheckConstraint
9666 		 * recurses from adding the parent table's constraint.  But we had to
9667 		 * carry the info this far so that we can drop the constraint below.
9668 		 */
9669 		if (!conislocal)
9670 			continue;
9671 
9672 		/*
9673 		 * When rebuilding an FK constraint that references the table we're
9674 		 * modifying, we might not yet have any lock on the FK's table, so get
9675 		 * one now.  We'll need AccessExclusiveLock for the DROP CONSTRAINT
9676 		 * step, so there's no value in asking for anything weaker.
9677 		 */
9678 		if (relid != tab->relid && contype == CONSTRAINT_FOREIGN)
9679 			LockRelationOid(relid, AccessExclusiveLock);
9680 
9681 		ATPostAlterTypeParse(oldId, relid, confrelid,
9682 							 (char *) lfirst(def_item),
9683 							 wqueue, lockmode, tab->rewrite);
9684 	}
9685 	forboth(oid_item, tab->changedIndexOids,
9686 			def_item, tab->changedIndexDefs)
9687 	{
9688 		Oid			oldId = lfirst_oid(oid_item);
9689 		Oid			relid;
9690 
9691 		relid = IndexGetRelation(oldId, false);
9692 		ATPostAlterTypeParse(oldId, relid, InvalidOid,
9693 							 (char *) lfirst(def_item),
9694 							 wqueue, lockmode, tab->rewrite);
9695 	}
9696 
9697 	/*
9698 	 * Queue up command to restore replica identity index marking
9699 	 */
9700 	if (tab->replicaIdentityIndex)
9701 	{
9702 		AlterTableCmd *cmd = makeNode(AlterTableCmd);
9703 		ReplicaIdentityStmt *subcmd = makeNode(ReplicaIdentityStmt);
9704 
9705 		subcmd->identity_type = REPLICA_IDENTITY_INDEX;
9706 		subcmd->name = tab->replicaIdentityIndex;
9707 		cmd->subtype = AT_ReplicaIdentity;
9708 		cmd->def = (Node *) subcmd;
9709 
9710 		/* do it after indexes and constraints */
9711 		tab->subcmds[AT_PASS_OLD_CONSTR] =
9712 			lappend(tab->subcmds[AT_PASS_OLD_CONSTR], cmd);
9713 	}
9714 
9715 	/*
9716 	 * Queue up command to restore marking of index used for cluster.
9717 	 */
9718 	if (tab->clusterOnIndex)
9719 	{
9720 		AlterTableCmd *cmd = makeNode(AlterTableCmd);
9721 
9722 		cmd->subtype = AT_ClusterOn;
9723 		cmd->name = tab->clusterOnIndex;
9724 
9725 		/* do it after indexes and constraints */
9726 		tab->subcmds[AT_PASS_OLD_CONSTR] =
9727 			lappend(tab->subcmds[AT_PASS_OLD_CONSTR], cmd);
9728 	}
9729 
9730 	/*
9731 	 * Now we can drop the existing constraints and indexes --- constraints
9732 	 * first, since some of them might depend on the indexes.  In fact, we
9733 	 * have to delete FOREIGN KEY constraints before UNIQUE constraints, but
9734 	 * we already ordered the constraint list to ensure that would happen. It
9735 	 * should be okay to use DROP_RESTRICT here, since nothing else should be
9736 	 * depending on these objects.
9737 	 */
9738 	foreach(oid_item, tab->changedConstraintOids)
9739 	{
9740 		obj.classId = ConstraintRelationId;
9741 		obj.objectId = lfirst_oid(oid_item);
9742 		obj.objectSubId = 0;
9743 		performDeletion(&obj, DROP_RESTRICT, PERFORM_DELETION_INTERNAL);
9744 	}
9745 
9746 	foreach(oid_item, tab->changedIndexOids)
9747 	{
9748 		obj.classId = RelationRelationId;
9749 		obj.objectId = lfirst_oid(oid_item);
9750 		obj.objectSubId = 0;
9751 		performDeletion(&obj, DROP_RESTRICT, PERFORM_DELETION_INTERNAL);
9752 	}
9753 
9754 	/*
9755 	 * The objects will get recreated during subsequent passes over the work
9756 	 * queue.
9757 	 */
9758 }
9759 
9760 static void
ATPostAlterTypeParse(Oid oldId,Oid oldRelId,Oid refRelId,char * cmd,List ** wqueue,LOCKMODE lockmode,bool rewrite)9761 ATPostAlterTypeParse(Oid oldId, Oid oldRelId, Oid refRelId, char *cmd,
9762 					 List **wqueue, LOCKMODE lockmode, bool rewrite)
9763 {
9764 	List	   *raw_parsetree_list;
9765 	List	   *querytree_list;
9766 	ListCell   *list_item;
9767 	Relation	rel;
9768 
9769 	/*
9770 	 * We expect that we will get only ALTER TABLE and CREATE INDEX
9771 	 * statements. Hence, there is no need to pass them through
9772 	 * parse_analyze() or the rewriter, but instead we need to pass them
9773 	 * through parse_utilcmd.c to make them ready for execution.
9774 	 */
9775 	raw_parsetree_list = raw_parser(cmd);
9776 	querytree_list = NIL;
9777 	foreach(list_item, raw_parsetree_list)
9778 	{
9779 		RawStmt    *rs = lfirst_node(RawStmt, list_item);
9780 		Node	   *stmt = rs->stmt;
9781 
9782 		if (IsA(stmt, IndexStmt))
9783 			querytree_list = lappend(querytree_list,
9784 									 transformIndexStmt(oldRelId,
9785 														(IndexStmt *) stmt,
9786 														cmd));
9787 		else if (IsA(stmt, AlterTableStmt))
9788 			querytree_list = list_concat(querytree_list,
9789 										 transformAlterTableStmt(oldRelId,
9790 																 (AlterTableStmt *) stmt,
9791 																 cmd));
9792 		else
9793 			querytree_list = lappend(querytree_list, stmt);
9794 	}
9795 
9796 	/* Caller should already have acquired whatever lock we need. */
9797 	rel = relation_open(oldRelId, NoLock);
9798 
9799 	/*
9800 	 * Attach each generated command to the proper place in the work queue.
9801 	 * Note this could result in creation of entirely new work-queue entries.
9802 	 *
9803 	 * Also note that we have to tweak the command subtypes, because it turns
9804 	 * out that re-creation of indexes and constraints has to act a bit
9805 	 * differently from initial creation.
9806 	 */
9807 	foreach(list_item, querytree_list)
9808 	{
9809 		Node	   *stm = (Node *) lfirst(list_item);
9810 		AlteredTableInfo *tab;
9811 
9812 		tab = ATGetQueueEntry(wqueue, rel);
9813 
9814 		if (IsA(stm, IndexStmt))
9815 		{
9816 			IndexStmt  *stmt = (IndexStmt *) stm;
9817 			AlterTableCmd *newcmd;
9818 
9819 			if (!rewrite)
9820 				TryReuseIndex(oldId, stmt);
9821 			/* keep the index's comment */
9822 			stmt->idxcomment = GetComment(oldId, RelationRelationId, 0);
9823 
9824 			newcmd = makeNode(AlterTableCmd);
9825 			newcmd->subtype = AT_ReAddIndex;
9826 			newcmd->def = (Node *) stmt;
9827 			tab->subcmds[AT_PASS_OLD_INDEX] =
9828 				lappend(tab->subcmds[AT_PASS_OLD_INDEX], newcmd);
9829 		}
9830 		else if (IsA(stm, AlterTableStmt))
9831 		{
9832 			AlterTableStmt *stmt = (AlterTableStmt *) stm;
9833 			ListCell   *lcmd;
9834 
9835 			foreach(lcmd, stmt->cmds)
9836 			{
9837 				AlterTableCmd *cmd = (AlterTableCmd *) lfirst(lcmd);
9838 
9839 				if (cmd->subtype == AT_AddIndex)
9840 				{
9841 					IndexStmt  *indstmt;
9842 					Oid			indoid;
9843 
9844 					indstmt = castNode(IndexStmt, cmd->def);
9845 					indoid = get_constraint_index(oldId);
9846 
9847 					if (!rewrite)
9848 						TryReuseIndex(indoid, indstmt);
9849 					/* keep any comment on the index */
9850 					indstmt->idxcomment = GetComment(indoid,
9851 													 RelationRelationId, 0);
9852 
9853 					cmd->subtype = AT_ReAddIndex;
9854 					tab->subcmds[AT_PASS_OLD_INDEX] =
9855 						lappend(tab->subcmds[AT_PASS_OLD_INDEX], cmd);
9856 
9857 					/* recreate any comment on the constraint */
9858 					RebuildConstraintComment(tab,
9859 											 AT_PASS_OLD_INDEX,
9860 											 oldId,
9861 											 rel, indstmt->idxname);
9862 				}
9863 				else if (cmd->subtype == AT_AddConstraint)
9864 				{
9865 					Constraint *con;
9866 
9867 					con = castNode(Constraint, cmd->def);
9868 					con->old_pktable_oid = refRelId;
9869 					/* rewriting neither side of a FK */
9870 					if (con->contype == CONSTR_FOREIGN &&
9871 						!rewrite && tab->rewrite == 0)
9872 						TryReuseForeignKey(oldId, con);
9873 					cmd->subtype = AT_ReAddConstraint;
9874 					tab->subcmds[AT_PASS_OLD_CONSTR] =
9875 						lappend(tab->subcmds[AT_PASS_OLD_CONSTR], cmd);
9876 
9877 					/* recreate any comment on the constraint */
9878 					RebuildConstraintComment(tab,
9879 											 AT_PASS_OLD_CONSTR,
9880 											 oldId,
9881 											 rel, con->conname);
9882 				}
9883 				else
9884 					elog(ERROR, "unexpected statement subtype: %d",
9885 						 (int) cmd->subtype);
9886 			}
9887 		}
9888 		else
9889 			elog(ERROR, "unexpected statement type: %d",
9890 				 (int) nodeTag(stm));
9891 	}
9892 
9893 	relation_close(rel, NoLock);
9894 }
9895 
9896 /*
9897  * Subroutine for ATPostAlterTypeParse() to recreate a comment entry for
9898  * a constraint that is being re-added.
9899  */
9900 static void
RebuildConstraintComment(AlteredTableInfo * tab,int pass,Oid objid,Relation rel,char * conname)9901 RebuildConstraintComment(AlteredTableInfo *tab, int pass, Oid objid,
9902 						 Relation rel, char *conname)
9903 {
9904 	CommentStmt *cmd;
9905 	char	   *comment_str;
9906 	AlterTableCmd *newcmd;
9907 
9908 	/* Look for comment for object wanted, and leave if none */
9909 	comment_str = GetComment(objid, ConstraintRelationId, 0);
9910 	if (comment_str == NULL)
9911 		return;
9912 
9913 	/* Build node CommentStmt */
9914 	cmd = makeNode(CommentStmt);
9915 	cmd->objtype = OBJECT_TABCONSTRAINT;
9916 	cmd->object = (Node *) list_make3(makeString(get_namespace_name(RelationGetNamespace(rel))),
9917 									  makeString(pstrdup(RelationGetRelationName(rel))),
9918 									  makeString(pstrdup(conname)));
9919 	cmd->comment = comment_str;
9920 
9921 	/* Append it to list of commands */
9922 	newcmd = makeNode(AlterTableCmd);
9923 	newcmd->subtype = AT_ReAddComment;
9924 	newcmd->def = (Node *) cmd;
9925 	tab->subcmds[pass] = lappend(tab->subcmds[pass], newcmd);
9926 }
9927 
9928 /*
9929  * Subroutine for ATPostAlterTypeParse().  Calls out to CheckIndexCompatible()
9930  * for the real analysis, then mutates the IndexStmt based on that verdict.
9931  */
9932 static void
TryReuseIndex(Oid oldId,IndexStmt * stmt)9933 TryReuseIndex(Oid oldId, IndexStmt *stmt)
9934 {
9935 	if (CheckIndexCompatible(oldId,
9936 							 stmt->accessMethod,
9937 							 stmt->indexParams,
9938 							 stmt->excludeOpNames))
9939 	{
9940 		Relation	irel = index_open(oldId, NoLock);
9941 
9942 		stmt->oldNode = irel->rd_node.relNode;
9943 		index_close(irel, NoLock);
9944 	}
9945 }
9946 
9947 /*
9948  * Subroutine for ATPostAlterTypeParse().
9949  *
9950  * Stash the old P-F equality operator into the Constraint node, for possible
9951  * use by ATAddForeignKeyConstraint() in determining whether revalidation of
9952  * this constraint can be skipped.
9953  */
9954 static void
TryReuseForeignKey(Oid oldId,Constraint * con)9955 TryReuseForeignKey(Oid oldId, Constraint *con)
9956 {
9957 	HeapTuple	tup;
9958 	Datum		adatum;
9959 	bool		isNull;
9960 	ArrayType  *arr;
9961 	Oid		   *rawarr;
9962 	int			numkeys;
9963 	int			i;
9964 
9965 	Assert(con->contype == CONSTR_FOREIGN);
9966 	Assert(con->old_conpfeqop == NIL);	/* already prepared this node */
9967 
9968 	tup = SearchSysCache1(CONSTROID, ObjectIdGetDatum(oldId));
9969 	if (!HeapTupleIsValid(tup)) /* should not happen */
9970 		elog(ERROR, "cache lookup failed for constraint %u", oldId);
9971 
9972 	adatum = SysCacheGetAttr(CONSTROID, tup,
9973 							 Anum_pg_constraint_conpfeqop, &isNull);
9974 	if (isNull)
9975 		elog(ERROR, "null conpfeqop for constraint %u", oldId);
9976 	arr = DatumGetArrayTypeP(adatum);	/* ensure not toasted */
9977 	numkeys = ARR_DIMS(arr)[0];
9978 	/* test follows the one in ri_FetchConstraintInfo() */
9979 	if (ARR_NDIM(arr) != 1 ||
9980 		ARR_HASNULL(arr) ||
9981 		ARR_ELEMTYPE(arr) != OIDOID)
9982 		elog(ERROR, "conpfeqop is not a 1-D Oid array");
9983 	rawarr = (Oid *) ARR_DATA_PTR(arr);
9984 
9985 	/* stash a List of the operator Oids in our Constraint node */
9986 	for (i = 0; i < numkeys; i++)
9987 		con->old_conpfeqop = lappend_oid(con->old_conpfeqop, rawarr[i]);
9988 
9989 	ReleaseSysCache(tup);
9990 }
9991 
9992 /*
9993  * ALTER TABLE OWNER
9994  *
9995  * recursing is true if we are recursing from a table to its indexes,
9996  * sequences, or toast table.  We don't allow the ownership of those things to
9997  * be changed separately from the parent table.  Also, we can skip permission
9998  * checks (this is necessary not just an optimization, else we'd fail to
9999  * handle toast tables properly).
10000  *
10001  * recursing is also true if ALTER TYPE OWNER is calling us to fix up a
10002  * free-standing composite type.
10003  */
10004 void
ATExecChangeOwner(Oid relationOid,Oid newOwnerId,bool recursing,LOCKMODE lockmode)10005 ATExecChangeOwner(Oid relationOid, Oid newOwnerId, bool recursing, LOCKMODE lockmode)
10006 {
10007 	Relation	target_rel;
10008 	Relation	class_rel;
10009 	HeapTuple	tuple;
10010 	Form_pg_class tuple_class;
10011 
10012 	/*
10013 	 * Get exclusive lock till end of transaction on the target table. Use
10014 	 * relation_open so that we can work on indexes and sequences.
10015 	 */
10016 	target_rel = relation_open(relationOid, lockmode);
10017 
10018 	/* Get its pg_class tuple, too */
10019 	class_rel = heap_open(RelationRelationId, RowExclusiveLock);
10020 
10021 	tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relationOid));
10022 	if (!HeapTupleIsValid(tuple))
10023 		elog(ERROR, "cache lookup failed for relation %u", relationOid);
10024 	tuple_class = (Form_pg_class) GETSTRUCT(tuple);
10025 
10026 	/* Can we change the ownership of this tuple? */
10027 	switch (tuple_class->relkind)
10028 	{
10029 		case RELKIND_RELATION:
10030 		case RELKIND_VIEW:
10031 		case RELKIND_MATVIEW:
10032 		case RELKIND_FOREIGN_TABLE:
10033 		case RELKIND_PARTITIONED_TABLE:
10034 			/* ok to change owner */
10035 			break;
10036 		case RELKIND_INDEX:
10037 			if (!recursing)
10038 			{
10039 				/*
10040 				 * Because ALTER INDEX OWNER used to be allowed, and in fact
10041 				 * is generated by old versions of pg_dump, we give a warning
10042 				 * and do nothing rather than erroring out.  Also, to avoid
10043 				 * unnecessary chatter while restoring those old dumps, say
10044 				 * nothing at all if the command would be a no-op anyway.
10045 				 */
10046 				if (tuple_class->relowner != newOwnerId)
10047 					ereport(WARNING,
10048 							(errcode(ERRCODE_WRONG_OBJECT_TYPE),
10049 							 errmsg("cannot change owner of index \"%s\"",
10050 									NameStr(tuple_class->relname)),
10051 							 errhint("Change the ownership of the index's table, instead.")));
10052 				/* quick hack to exit via the no-op path */
10053 				newOwnerId = tuple_class->relowner;
10054 			}
10055 			break;
10056 		case RELKIND_SEQUENCE:
10057 			if (!recursing &&
10058 				tuple_class->relowner != newOwnerId)
10059 			{
10060 				/* if it's an owned sequence, disallow changing it by itself */
10061 				Oid			tableId;
10062 				int32		colId;
10063 
10064 				if (sequenceIsOwned(relationOid, DEPENDENCY_AUTO, &tableId, &colId) ||
10065 					sequenceIsOwned(relationOid, DEPENDENCY_INTERNAL, &tableId, &colId))
10066 					ereport(ERROR,
10067 							(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
10068 							 errmsg("cannot change owner of sequence \"%s\"",
10069 									NameStr(tuple_class->relname)),
10070 							 errdetail("Sequence \"%s\" is linked to table \"%s\".",
10071 									   NameStr(tuple_class->relname),
10072 									   get_rel_name(tableId))));
10073 			}
10074 			break;
10075 		case RELKIND_COMPOSITE_TYPE:
10076 			if (recursing)
10077 				break;
10078 			ereport(ERROR,
10079 					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
10080 					 errmsg("\"%s\" is a composite type",
10081 							NameStr(tuple_class->relname)),
10082 					 errhint("Use ALTER TYPE instead.")));
10083 			break;
10084 		case RELKIND_TOASTVALUE:
10085 			if (recursing)
10086 				break;
10087 			/* FALL THRU */
10088 		default:
10089 			ereport(ERROR,
10090 					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
10091 					 errmsg("\"%s\" is not a table, view, sequence, or foreign table",
10092 							NameStr(tuple_class->relname))));
10093 	}
10094 
10095 	/*
10096 	 * If the new owner is the same as the existing owner, consider the
10097 	 * command to have succeeded.  This is for dump restoration purposes.
10098 	 */
10099 	if (tuple_class->relowner != newOwnerId)
10100 	{
10101 		Datum		repl_val[Natts_pg_class];
10102 		bool		repl_null[Natts_pg_class];
10103 		bool		repl_repl[Natts_pg_class];
10104 		Acl		   *newAcl;
10105 		Datum		aclDatum;
10106 		bool		isNull;
10107 		HeapTuple	newtuple;
10108 
10109 		/* skip permission checks when recursing to index or toast table */
10110 		if (!recursing)
10111 		{
10112 			/* Superusers can always do it */
10113 			if (!superuser())
10114 			{
10115 				Oid			namespaceOid = tuple_class->relnamespace;
10116 				AclResult	aclresult;
10117 
10118 				/* Otherwise, must be owner of the existing object */
10119 				if (!pg_class_ownercheck(relationOid, GetUserId()))
10120 					aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS,
10121 								   RelationGetRelationName(target_rel));
10122 
10123 				/* Must be able to become new owner */
10124 				check_is_member_of_role(GetUserId(), newOwnerId);
10125 
10126 				/* New owner must have CREATE privilege on namespace */
10127 				aclresult = pg_namespace_aclcheck(namespaceOid, newOwnerId,
10128 												  ACL_CREATE);
10129 				if (aclresult != ACLCHECK_OK)
10130 					aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
10131 								   get_namespace_name(namespaceOid));
10132 			}
10133 		}
10134 
10135 		memset(repl_null, false, sizeof(repl_null));
10136 		memset(repl_repl, false, sizeof(repl_repl));
10137 
10138 		repl_repl[Anum_pg_class_relowner - 1] = true;
10139 		repl_val[Anum_pg_class_relowner - 1] = ObjectIdGetDatum(newOwnerId);
10140 
10141 		/*
10142 		 * Determine the modified ACL for the new owner.  This is only
10143 		 * necessary when the ACL is non-null.
10144 		 */
10145 		aclDatum = SysCacheGetAttr(RELOID, tuple,
10146 								   Anum_pg_class_relacl,
10147 								   &isNull);
10148 		if (!isNull)
10149 		{
10150 			newAcl = aclnewowner(DatumGetAclP(aclDatum),
10151 								 tuple_class->relowner, newOwnerId);
10152 			repl_repl[Anum_pg_class_relacl - 1] = true;
10153 			repl_val[Anum_pg_class_relacl - 1] = PointerGetDatum(newAcl);
10154 		}
10155 
10156 		newtuple = heap_modify_tuple(tuple, RelationGetDescr(class_rel), repl_val, repl_null, repl_repl);
10157 
10158 		CatalogTupleUpdate(class_rel, &newtuple->t_self, newtuple);
10159 
10160 		heap_freetuple(newtuple);
10161 
10162 		/*
10163 		 * We must similarly update any per-column ACLs to reflect the new
10164 		 * owner; for neatness reasons that's split out as a subroutine.
10165 		 */
10166 		change_owner_fix_column_acls(relationOid,
10167 									 tuple_class->relowner,
10168 									 newOwnerId);
10169 
10170 		/*
10171 		 * Update owner dependency reference, if any.  A composite type has
10172 		 * none, because it's tracked for the pg_type entry instead of here;
10173 		 * indexes and TOAST tables don't have their own entries either.
10174 		 */
10175 		if (tuple_class->relkind != RELKIND_COMPOSITE_TYPE &&
10176 			tuple_class->relkind != RELKIND_INDEX &&
10177 			tuple_class->relkind != RELKIND_TOASTVALUE)
10178 			changeDependencyOnOwner(RelationRelationId, relationOid,
10179 									newOwnerId);
10180 
10181 		/*
10182 		 * Also change the ownership of the table's row type, if it has one
10183 		 */
10184 		if (tuple_class->relkind != RELKIND_INDEX)
10185 			AlterTypeOwnerInternal(tuple_class->reltype, newOwnerId);
10186 
10187 		/*
10188 		 * If we are operating on a table or materialized view, also change
10189 		 * the ownership of any indexes and sequences that belong to the
10190 		 * relation, as well as its toast table (if it has one).
10191 		 */
10192 		if (tuple_class->relkind == RELKIND_RELATION ||
10193 			tuple_class->relkind == RELKIND_MATVIEW ||
10194 			tuple_class->relkind == RELKIND_TOASTVALUE)
10195 		{
10196 			List	   *index_oid_list;
10197 			ListCell   *i;
10198 
10199 			/* Find all the indexes belonging to this relation */
10200 			index_oid_list = RelationGetIndexList(target_rel);
10201 
10202 			/* For each index, recursively change its ownership */
10203 			foreach(i, index_oid_list)
10204 				ATExecChangeOwner(lfirst_oid(i), newOwnerId, true, lockmode);
10205 
10206 			list_free(index_oid_list);
10207 		}
10208 
10209 		/* If it has a toast table, recurse to change its ownership */
10210 		if (tuple_class->reltoastrelid != InvalidOid)
10211 			ATExecChangeOwner(tuple_class->reltoastrelid, newOwnerId,
10212 							  true, lockmode);
10213 
10214 		/* If it has dependent sequences, recurse to change them too */
10215 		change_owner_recurse_to_sequences(relationOid, newOwnerId, lockmode);
10216 	}
10217 
10218 	InvokeObjectPostAlterHook(RelationRelationId, relationOid, 0);
10219 
10220 	ReleaseSysCache(tuple);
10221 	heap_close(class_rel, RowExclusiveLock);
10222 	relation_close(target_rel, NoLock);
10223 }
10224 
10225 /*
10226  * change_owner_fix_column_acls
10227  *
10228  * Helper function for ATExecChangeOwner.  Scan the columns of the table
10229  * and fix any non-null column ACLs to reflect the new owner.
10230  */
10231 static void
change_owner_fix_column_acls(Oid relationOid,Oid oldOwnerId,Oid newOwnerId)10232 change_owner_fix_column_acls(Oid relationOid, Oid oldOwnerId, Oid newOwnerId)
10233 {
10234 	Relation	attRelation;
10235 	SysScanDesc scan;
10236 	ScanKeyData key[1];
10237 	HeapTuple	attributeTuple;
10238 
10239 	attRelation = heap_open(AttributeRelationId, RowExclusiveLock);
10240 	ScanKeyInit(&key[0],
10241 				Anum_pg_attribute_attrelid,
10242 				BTEqualStrategyNumber, F_OIDEQ,
10243 				ObjectIdGetDatum(relationOid));
10244 	scan = systable_beginscan(attRelation, AttributeRelidNumIndexId,
10245 							  true, NULL, 1, key);
10246 	while (HeapTupleIsValid(attributeTuple = systable_getnext(scan)))
10247 	{
10248 		Form_pg_attribute att = (Form_pg_attribute) GETSTRUCT(attributeTuple);
10249 		Datum		repl_val[Natts_pg_attribute];
10250 		bool		repl_null[Natts_pg_attribute];
10251 		bool		repl_repl[Natts_pg_attribute];
10252 		Acl		   *newAcl;
10253 		Datum		aclDatum;
10254 		bool		isNull;
10255 		HeapTuple	newtuple;
10256 
10257 		/* Ignore dropped columns */
10258 		if (att->attisdropped)
10259 			continue;
10260 
10261 		aclDatum = heap_getattr(attributeTuple,
10262 								Anum_pg_attribute_attacl,
10263 								RelationGetDescr(attRelation),
10264 								&isNull);
10265 		/* Null ACLs do not require changes */
10266 		if (isNull)
10267 			continue;
10268 
10269 		memset(repl_null, false, sizeof(repl_null));
10270 		memset(repl_repl, false, sizeof(repl_repl));
10271 
10272 		newAcl = aclnewowner(DatumGetAclP(aclDatum),
10273 							 oldOwnerId, newOwnerId);
10274 		repl_repl[Anum_pg_attribute_attacl - 1] = true;
10275 		repl_val[Anum_pg_attribute_attacl - 1] = PointerGetDatum(newAcl);
10276 
10277 		newtuple = heap_modify_tuple(attributeTuple,
10278 									 RelationGetDescr(attRelation),
10279 									 repl_val, repl_null, repl_repl);
10280 
10281 		CatalogTupleUpdate(attRelation, &newtuple->t_self, newtuple);
10282 
10283 		heap_freetuple(newtuple);
10284 	}
10285 	systable_endscan(scan);
10286 	heap_close(attRelation, RowExclusiveLock);
10287 }
10288 
10289 /*
10290  * change_owner_recurse_to_sequences
10291  *
10292  * Helper function for ATExecChangeOwner.  Examines pg_depend searching
10293  * for sequences that are dependent on serial columns, and changes their
10294  * ownership.
10295  */
10296 static void
change_owner_recurse_to_sequences(Oid relationOid,Oid newOwnerId,LOCKMODE lockmode)10297 change_owner_recurse_to_sequences(Oid relationOid, Oid newOwnerId, LOCKMODE lockmode)
10298 {
10299 	Relation	depRel;
10300 	SysScanDesc scan;
10301 	ScanKeyData key[2];
10302 	HeapTuple	tup;
10303 
10304 	/*
10305 	 * SERIAL sequences are those having an auto dependency on one of the
10306 	 * table's columns (we don't care *which* column, exactly).
10307 	 */
10308 	depRel = heap_open(DependRelationId, AccessShareLock);
10309 
10310 	ScanKeyInit(&key[0],
10311 				Anum_pg_depend_refclassid,
10312 				BTEqualStrategyNumber, F_OIDEQ,
10313 				ObjectIdGetDatum(RelationRelationId));
10314 	ScanKeyInit(&key[1],
10315 				Anum_pg_depend_refobjid,
10316 				BTEqualStrategyNumber, F_OIDEQ,
10317 				ObjectIdGetDatum(relationOid));
10318 	/* we leave refobjsubid unspecified */
10319 
10320 	scan = systable_beginscan(depRel, DependReferenceIndexId, true,
10321 							  NULL, 2, key);
10322 
10323 	while (HeapTupleIsValid(tup = systable_getnext(scan)))
10324 	{
10325 		Form_pg_depend depForm = (Form_pg_depend) GETSTRUCT(tup);
10326 		Relation	seqRel;
10327 
10328 		/* skip dependencies other than auto dependencies on columns */
10329 		if (depForm->refobjsubid == 0 ||
10330 			depForm->classid != RelationRelationId ||
10331 			depForm->objsubid != 0 ||
10332 			!(depForm->deptype == DEPENDENCY_AUTO || depForm->deptype == DEPENDENCY_INTERNAL))
10333 			continue;
10334 
10335 		/* Use relation_open just in case it's an index */
10336 		seqRel = relation_open(depForm->objid, lockmode);
10337 
10338 		/* skip non-sequence relations */
10339 		if (RelationGetForm(seqRel)->relkind != RELKIND_SEQUENCE)
10340 		{
10341 			/* No need to keep the lock */
10342 			relation_close(seqRel, lockmode);
10343 			continue;
10344 		}
10345 
10346 		/* We don't need to close the sequence while we alter it. */
10347 		ATExecChangeOwner(depForm->objid, newOwnerId, true, lockmode);
10348 
10349 		/* Now we can close it.  Keep the lock till end of transaction. */
10350 		relation_close(seqRel, NoLock);
10351 	}
10352 
10353 	systable_endscan(scan);
10354 
10355 	relation_close(depRel, AccessShareLock);
10356 }
10357 
10358 /*
10359  * ALTER TABLE CLUSTER ON
10360  *
10361  * The only thing we have to do is to change the indisclustered bits.
10362  *
10363  * Return the address of the new clustering index.
10364  */
10365 static ObjectAddress
ATExecClusterOn(Relation rel,const char * indexName,LOCKMODE lockmode)10366 ATExecClusterOn(Relation rel, const char *indexName, LOCKMODE lockmode)
10367 {
10368 	Oid			indexOid;
10369 	ObjectAddress address;
10370 
10371 	indexOid = get_relname_relid(indexName, rel->rd_rel->relnamespace);
10372 
10373 	if (!OidIsValid(indexOid))
10374 		ereport(ERROR,
10375 				(errcode(ERRCODE_UNDEFINED_OBJECT),
10376 				 errmsg("index \"%s\" for table \"%s\" does not exist",
10377 						indexName, RelationGetRelationName(rel))));
10378 
10379 	/* Check index is valid to cluster on */
10380 	check_index_is_clusterable(rel, indexOid, false, lockmode);
10381 
10382 	/* And do the work */
10383 	mark_index_clustered(rel, indexOid, false);
10384 
10385 	ObjectAddressSet(address,
10386 					 RelationRelationId, indexOid);
10387 
10388 	return address;
10389 }
10390 
10391 /*
10392  * ALTER TABLE SET WITHOUT CLUSTER
10393  *
10394  * We have to find any indexes on the table that have indisclustered bit
10395  * set and turn it off.
10396  */
10397 static void
ATExecDropCluster(Relation rel,LOCKMODE lockmode)10398 ATExecDropCluster(Relation rel, LOCKMODE lockmode)
10399 {
10400 	mark_index_clustered(rel, InvalidOid, false);
10401 }
10402 
10403 /*
10404  * ALTER TABLE SET TABLESPACE
10405  */
10406 static void
ATPrepSetTableSpace(AlteredTableInfo * tab,Relation rel,char * tablespacename,LOCKMODE lockmode)10407 ATPrepSetTableSpace(AlteredTableInfo *tab, Relation rel, char *tablespacename, LOCKMODE lockmode)
10408 {
10409 	Oid			tablespaceId;
10410 
10411 	/* Check that the tablespace exists */
10412 	tablespaceId = get_tablespace_oid(tablespacename, false);
10413 
10414 	/* Check permissions except when moving to database's default */
10415 	if (OidIsValid(tablespaceId) && tablespaceId != MyDatabaseTableSpace)
10416 	{
10417 		AclResult	aclresult;
10418 
10419 		aclresult = pg_tablespace_aclcheck(tablespaceId, GetUserId(), ACL_CREATE);
10420 		if (aclresult != ACLCHECK_OK)
10421 			aclcheck_error(aclresult, ACL_KIND_TABLESPACE, tablespacename);
10422 	}
10423 
10424 	/* Save info for Phase 3 to do the real work */
10425 	if (OidIsValid(tab->newTableSpace))
10426 		ereport(ERROR,
10427 				(errcode(ERRCODE_SYNTAX_ERROR),
10428 				 errmsg("cannot have multiple SET TABLESPACE subcommands")));
10429 
10430 	tab->newTableSpace = tablespaceId;
10431 }
10432 
10433 /*
10434  * Set, reset, or replace reloptions.
10435  */
10436 static void
ATExecSetRelOptions(Relation rel,List * defList,AlterTableType operation,LOCKMODE lockmode)10437 ATExecSetRelOptions(Relation rel, List *defList, AlterTableType operation,
10438 					LOCKMODE lockmode)
10439 {
10440 	Oid			relid;
10441 	Relation	pgclass;
10442 	HeapTuple	tuple;
10443 	HeapTuple	newtuple;
10444 	Datum		datum;
10445 	bool		isnull;
10446 	Datum		newOptions;
10447 	Datum		repl_val[Natts_pg_class];
10448 	bool		repl_null[Natts_pg_class];
10449 	bool		repl_repl[Natts_pg_class];
10450 	static char *validnsps[] = HEAP_RELOPT_NAMESPACES;
10451 
10452 	if (defList == NIL && operation != AT_ReplaceRelOptions)
10453 		return;					/* nothing to do */
10454 
10455 	pgclass = heap_open(RelationRelationId, RowExclusiveLock);
10456 
10457 	/* Fetch heap tuple */
10458 	relid = RelationGetRelid(rel);
10459 	tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
10460 	if (!HeapTupleIsValid(tuple))
10461 		elog(ERROR, "cache lookup failed for relation %u", relid);
10462 
10463 	if (operation == AT_ReplaceRelOptions)
10464 	{
10465 		/*
10466 		 * If we're supposed to replace the reloptions list, we just pretend
10467 		 * there were none before.
10468 		 */
10469 		datum = (Datum) 0;
10470 		isnull = true;
10471 	}
10472 	else
10473 	{
10474 		/* Get the old reloptions */
10475 		datum = SysCacheGetAttr(RELOID, tuple, Anum_pg_class_reloptions,
10476 								&isnull);
10477 	}
10478 
10479 	/* Generate new proposed reloptions (text array) */
10480 	newOptions = transformRelOptions(isnull ? (Datum) 0 : datum,
10481 									 defList, NULL, validnsps, false,
10482 									 operation == AT_ResetRelOptions);
10483 
10484 	/* Validate */
10485 	switch (rel->rd_rel->relkind)
10486 	{
10487 		case RELKIND_RELATION:
10488 		case RELKIND_TOASTVALUE:
10489 		case RELKIND_MATVIEW:
10490 		case RELKIND_PARTITIONED_TABLE:
10491 			(void) heap_reloptions(rel->rd_rel->relkind, newOptions, true);
10492 			break;
10493 		case RELKIND_VIEW:
10494 			(void) view_reloptions(newOptions, true);
10495 			break;
10496 		case RELKIND_INDEX:
10497 			(void) index_reloptions(rel->rd_amroutine->amoptions, newOptions, true);
10498 			break;
10499 		default:
10500 			ereport(ERROR,
10501 					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
10502 					 errmsg("\"%s\" is not a table, view, materialized view, index, or TOAST table",
10503 							RelationGetRelationName(rel))));
10504 			break;
10505 	}
10506 
10507 	/* Special-case validation of view options */
10508 	if (rel->rd_rel->relkind == RELKIND_VIEW)
10509 	{
10510 		Query	   *view_query = get_view_query(rel);
10511 		List	   *view_options = untransformRelOptions(newOptions);
10512 		ListCell   *cell;
10513 		bool		check_option = false;
10514 
10515 		foreach(cell, view_options)
10516 		{
10517 			DefElem    *defel = (DefElem *) lfirst(cell);
10518 
10519 			if (pg_strcasecmp(defel->defname, "check_option") == 0)
10520 				check_option = true;
10521 		}
10522 
10523 		/*
10524 		 * If the check option is specified, look to see if the view is
10525 		 * actually auto-updatable or not.
10526 		 */
10527 		if (check_option)
10528 		{
10529 			const char *view_updatable_error =
10530 			view_query_is_auto_updatable(view_query, true);
10531 
10532 			if (view_updatable_error)
10533 				ereport(ERROR,
10534 						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
10535 						 errmsg("WITH CHECK OPTION is supported only on automatically updatable views"),
10536 						 errhint("%s", _(view_updatable_error))));
10537 		}
10538 	}
10539 
10540 	/*
10541 	 * All we need do here is update the pg_class row; the new options will be
10542 	 * propagated into relcaches during post-commit cache inval.
10543 	 */
10544 	memset(repl_val, 0, sizeof(repl_val));
10545 	memset(repl_null, false, sizeof(repl_null));
10546 	memset(repl_repl, false, sizeof(repl_repl));
10547 
10548 	if (newOptions != (Datum) 0)
10549 		repl_val[Anum_pg_class_reloptions - 1] = newOptions;
10550 	else
10551 		repl_null[Anum_pg_class_reloptions - 1] = true;
10552 
10553 	repl_repl[Anum_pg_class_reloptions - 1] = true;
10554 
10555 	newtuple = heap_modify_tuple(tuple, RelationGetDescr(pgclass),
10556 								 repl_val, repl_null, repl_repl);
10557 
10558 	CatalogTupleUpdate(pgclass, &newtuple->t_self, newtuple);
10559 
10560 	InvokeObjectPostAlterHook(RelationRelationId, RelationGetRelid(rel), 0);
10561 
10562 	heap_freetuple(newtuple);
10563 
10564 	ReleaseSysCache(tuple);
10565 
10566 	/* repeat the whole exercise for the toast table, if there's one */
10567 	if (OidIsValid(rel->rd_rel->reltoastrelid))
10568 	{
10569 		Relation	toastrel;
10570 		Oid			toastid = rel->rd_rel->reltoastrelid;
10571 
10572 		toastrel = heap_open(toastid, lockmode);
10573 
10574 		/* Fetch heap tuple */
10575 		tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(toastid));
10576 		if (!HeapTupleIsValid(tuple))
10577 			elog(ERROR, "cache lookup failed for relation %u", toastid);
10578 
10579 		if (operation == AT_ReplaceRelOptions)
10580 		{
10581 			/*
10582 			 * If we're supposed to replace the reloptions list, we just
10583 			 * pretend there were none before.
10584 			 */
10585 			datum = (Datum) 0;
10586 			isnull = true;
10587 		}
10588 		else
10589 		{
10590 			/* Get the old reloptions */
10591 			datum = SysCacheGetAttr(RELOID, tuple, Anum_pg_class_reloptions,
10592 									&isnull);
10593 		}
10594 
10595 		newOptions = transformRelOptions(isnull ? (Datum) 0 : datum,
10596 										 defList, "toast", validnsps, false,
10597 										 operation == AT_ResetRelOptions);
10598 
10599 		(void) heap_reloptions(RELKIND_TOASTVALUE, newOptions, true);
10600 
10601 		memset(repl_val, 0, sizeof(repl_val));
10602 		memset(repl_null, false, sizeof(repl_null));
10603 		memset(repl_repl, false, sizeof(repl_repl));
10604 
10605 		if (newOptions != (Datum) 0)
10606 			repl_val[Anum_pg_class_reloptions - 1] = newOptions;
10607 		else
10608 			repl_null[Anum_pg_class_reloptions - 1] = true;
10609 
10610 		repl_repl[Anum_pg_class_reloptions - 1] = true;
10611 
10612 		newtuple = heap_modify_tuple(tuple, RelationGetDescr(pgclass),
10613 									 repl_val, repl_null, repl_repl);
10614 
10615 		CatalogTupleUpdate(pgclass, &newtuple->t_self, newtuple);
10616 
10617 		InvokeObjectPostAlterHookArg(RelationRelationId,
10618 									 RelationGetRelid(toastrel), 0,
10619 									 InvalidOid, true);
10620 
10621 		heap_freetuple(newtuple);
10622 
10623 		ReleaseSysCache(tuple);
10624 
10625 		heap_close(toastrel, NoLock);
10626 	}
10627 
10628 	heap_close(pgclass, RowExclusiveLock);
10629 }
10630 
10631 /*
10632  * Execute ALTER TABLE SET TABLESPACE for cases where there is no tuple
10633  * rewriting to be done, so we just want to copy the data as fast as possible.
10634  */
10635 static void
ATExecSetTableSpace(Oid tableOid,Oid newTableSpace,LOCKMODE lockmode)10636 ATExecSetTableSpace(Oid tableOid, Oid newTableSpace, LOCKMODE lockmode)
10637 {
10638 	Relation	rel;
10639 	Oid			oldTableSpace;
10640 	Oid			reltoastrelid;
10641 	Oid			newrelfilenode;
10642 	RelFileNode newrnode;
10643 	SMgrRelation dstrel;
10644 	Relation	pg_class;
10645 	HeapTuple	tuple;
10646 	Form_pg_class rd_rel;
10647 	ForkNumber	forkNum;
10648 	List	   *reltoastidxids = NIL;
10649 	ListCell   *lc;
10650 
10651 	/*
10652 	 * Need lock here in case we are recursing to toast table or index
10653 	 */
10654 	rel = relation_open(tableOid, lockmode);
10655 
10656 	/*
10657 	 * No work if no change in tablespace.
10658 	 */
10659 	oldTableSpace = rel->rd_rel->reltablespace;
10660 	if (newTableSpace == oldTableSpace ||
10661 		(newTableSpace == MyDatabaseTableSpace && oldTableSpace == 0))
10662 	{
10663 		InvokeObjectPostAlterHook(RelationRelationId,
10664 								  RelationGetRelid(rel), 0);
10665 
10666 		relation_close(rel, NoLock);
10667 		return;
10668 	}
10669 
10670 	/*
10671 	 * We cannot support moving mapped relations into different tablespaces.
10672 	 * (In particular this eliminates all shared catalogs.)
10673 	 */
10674 	if (RelationIsMapped(rel))
10675 		ereport(ERROR,
10676 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
10677 				 errmsg("cannot move system relation \"%s\"",
10678 						RelationGetRelationName(rel))));
10679 
10680 	/* Can't move a non-shared relation into pg_global */
10681 	if (newTableSpace == GLOBALTABLESPACE_OID)
10682 		ereport(ERROR,
10683 				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
10684 				 errmsg("only shared relations can be placed in pg_global tablespace")));
10685 
10686 	/*
10687 	 * Don't allow moving temp tables of other backends ... their local buffer
10688 	 * manager is not going to cope.
10689 	 */
10690 	if (RELATION_IS_OTHER_TEMP(rel))
10691 		ereport(ERROR,
10692 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
10693 				 errmsg("cannot move temporary tables of other sessions")));
10694 
10695 	reltoastrelid = rel->rd_rel->reltoastrelid;
10696 	/* Fetch the list of indexes on toast relation if necessary */
10697 	if (OidIsValid(reltoastrelid))
10698 	{
10699 		Relation	toastRel = relation_open(reltoastrelid, lockmode);
10700 
10701 		reltoastidxids = RelationGetIndexList(toastRel);
10702 		relation_close(toastRel, lockmode);
10703 	}
10704 
10705 	/* Get a modifiable copy of the relation's pg_class row */
10706 	pg_class = heap_open(RelationRelationId, RowExclusiveLock);
10707 
10708 	tuple = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(tableOid));
10709 	if (!HeapTupleIsValid(tuple))
10710 		elog(ERROR, "cache lookup failed for relation %u", tableOid);
10711 	rd_rel = (Form_pg_class) GETSTRUCT(tuple);
10712 
10713 	/*
10714 	 * Since we copy the file directly without looking at the shared buffers,
10715 	 * we'd better first flush out any pages of the source relation that are
10716 	 * in shared buffers.  We assume no new changes will be made while we are
10717 	 * holding exclusive lock on the rel.
10718 	 */
10719 	FlushRelationBuffers(rel);
10720 
10721 	/*
10722 	 * Relfilenodes are not unique in databases across tablespaces, so we need
10723 	 * to allocate a new one in the new tablespace.
10724 	 */
10725 	newrelfilenode = GetNewRelFileNode(newTableSpace, NULL,
10726 									   rel->rd_rel->relpersistence);
10727 
10728 	/* Open old and new relation */
10729 	newrnode = rel->rd_node;
10730 	newrnode.relNode = newrelfilenode;
10731 	newrnode.spcNode = newTableSpace;
10732 	dstrel = smgropen(newrnode, rel->rd_backend);
10733 
10734 	RelationOpenSmgr(rel);
10735 
10736 	/*
10737 	 * Create and copy all forks of the relation, and schedule unlinking of
10738 	 * old physical files.
10739 	 *
10740 	 * NOTE: any conflict in relfilenode value will be caught in
10741 	 * RelationCreateStorage().
10742 	 */
10743 	RelationCreateStorage(newrnode, rel->rd_rel->relpersistence);
10744 
10745 	/* copy main fork */
10746 	copy_relation_data(rel->rd_smgr, dstrel, MAIN_FORKNUM,
10747 					   rel->rd_rel->relpersistence);
10748 
10749 	/* copy those extra forks that exist */
10750 	for (forkNum = MAIN_FORKNUM + 1; forkNum <= MAX_FORKNUM; forkNum++)
10751 	{
10752 		if (smgrexists(rel->rd_smgr, forkNum))
10753 		{
10754 			smgrcreate(dstrel, forkNum, false);
10755 
10756 			/*
10757 			 * WAL log creation if the relation is persistent, or this is the
10758 			 * init fork of an unlogged relation.
10759 			 */
10760 			if (rel->rd_rel->relpersistence == RELPERSISTENCE_PERMANENT ||
10761 				(rel->rd_rel->relpersistence == RELPERSISTENCE_UNLOGGED &&
10762 				 forkNum == INIT_FORKNUM))
10763 				log_smgrcreate(&newrnode, forkNum);
10764 			copy_relation_data(rel->rd_smgr, dstrel, forkNum,
10765 							   rel->rd_rel->relpersistence);
10766 		}
10767 	}
10768 
10769 	/* drop old relation, and close new one */
10770 	RelationDropStorage(rel);
10771 	smgrclose(dstrel);
10772 
10773 	/* update the pg_class row */
10774 	rd_rel->reltablespace = (newTableSpace == MyDatabaseTableSpace) ? InvalidOid : newTableSpace;
10775 	rd_rel->relfilenode = newrelfilenode;
10776 	CatalogTupleUpdate(pg_class, &tuple->t_self, tuple);
10777 
10778 	InvokeObjectPostAlterHook(RelationRelationId, RelationGetRelid(rel), 0);
10779 
10780 	heap_freetuple(tuple);
10781 
10782 	heap_close(pg_class, RowExclusiveLock);
10783 
10784 	relation_close(rel, NoLock);
10785 
10786 	/* Make sure the reltablespace change is visible */
10787 	CommandCounterIncrement();
10788 
10789 	/* Move associated toast relation and/or indexes, too */
10790 	if (OidIsValid(reltoastrelid))
10791 		ATExecSetTableSpace(reltoastrelid, newTableSpace, lockmode);
10792 	foreach(lc, reltoastidxids)
10793 		ATExecSetTableSpace(lfirst_oid(lc), newTableSpace, lockmode);
10794 
10795 	/* Clean up */
10796 	list_free(reltoastidxids);
10797 }
10798 
10799 /*
10800  * Alter Table ALL ... SET TABLESPACE
10801  *
10802  * Allows a user to move all objects of some type in a given tablespace in the
10803  * current database to another tablespace.  Objects can be chosen based on the
10804  * owner of the object also, to allow users to move only their objects.
10805  * The user must have CREATE rights on the new tablespace, as usual.   The main
10806  * permissions handling is done by the lower-level table move function.
10807  *
10808  * All to-be-moved objects are locked first. If NOWAIT is specified and the
10809  * lock can't be acquired then we ereport(ERROR).
10810  */
10811 Oid
AlterTableMoveAll(AlterTableMoveAllStmt * stmt)10812 AlterTableMoveAll(AlterTableMoveAllStmt *stmt)
10813 {
10814 	List	   *relations = NIL;
10815 	ListCell   *l;
10816 	ScanKeyData key[1];
10817 	Relation	rel;
10818 	HeapScanDesc scan;
10819 	HeapTuple	tuple;
10820 	Oid			orig_tablespaceoid;
10821 	Oid			new_tablespaceoid;
10822 	List	   *role_oids = roleSpecsToIds(stmt->roles);
10823 
10824 	/* Ensure we were not asked to move something we can't */
10825 	if (stmt->objtype != OBJECT_TABLE && stmt->objtype != OBJECT_INDEX &&
10826 		stmt->objtype != OBJECT_MATVIEW)
10827 		ereport(ERROR,
10828 				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
10829 				 errmsg("only tables, indexes, and materialized views exist in tablespaces")));
10830 
10831 	/* Get the orig and new tablespace OIDs */
10832 	orig_tablespaceoid = get_tablespace_oid(stmt->orig_tablespacename, false);
10833 	new_tablespaceoid = get_tablespace_oid(stmt->new_tablespacename, false);
10834 
10835 	/* Can't move shared relations in to or out of pg_global */
10836 	/* This is also checked by ATExecSetTableSpace, but nice to stop earlier */
10837 	if (orig_tablespaceoid == GLOBALTABLESPACE_OID ||
10838 		new_tablespaceoid == GLOBALTABLESPACE_OID)
10839 		ereport(ERROR,
10840 				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
10841 				 errmsg("cannot move relations in to or out of pg_global tablespace")));
10842 
10843 	/*
10844 	 * Must have CREATE rights on the new tablespace, unless it is the
10845 	 * database default tablespace (which all users implicitly have CREATE
10846 	 * rights on).
10847 	 */
10848 	if (OidIsValid(new_tablespaceoid) && new_tablespaceoid != MyDatabaseTableSpace)
10849 	{
10850 		AclResult	aclresult;
10851 
10852 		aclresult = pg_tablespace_aclcheck(new_tablespaceoid, GetUserId(),
10853 										   ACL_CREATE);
10854 		if (aclresult != ACLCHECK_OK)
10855 			aclcheck_error(aclresult, ACL_KIND_TABLESPACE,
10856 						   get_tablespace_name(new_tablespaceoid));
10857 	}
10858 
10859 	/*
10860 	 * Now that the checks are done, check if we should set either to
10861 	 * InvalidOid because it is our database's default tablespace.
10862 	 */
10863 	if (orig_tablespaceoid == MyDatabaseTableSpace)
10864 		orig_tablespaceoid = InvalidOid;
10865 
10866 	if (new_tablespaceoid == MyDatabaseTableSpace)
10867 		new_tablespaceoid = InvalidOid;
10868 
10869 	/* no-op */
10870 	if (orig_tablespaceoid == new_tablespaceoid)
10871 		return new_tablespaceoid;
10872 
10873 	/*
10874 	 * Walk the list of objects in the tablespace and move them. This will
10875 	 * only find objects in our database, of course.
10876 	 */
10877 	ScanKeyInit(&key[0],
10878 				Anum_pg_class_reltablespace,
10879 				BTEqualStrategyNumber, F_OIDEQ,
10880 				ObjectIdGetDatum(orig_tablespaceoid));
10881 
10882 	rel = heap_open(RelationRelationId, AccessShareLock);
10883 	scan = heap_beginscan_catalog(rel, 1, key);
10884 	while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
10885 	{
10886 		Oid			relOid = HeapTupleGetOid(tuple);
10887 		Form_pg_class relForm;
10888 
10889 		relForm = (Form_pg_class) GETSTRUCT(tuple);
10890 
10891 		/*
10892 		 * Do not move objects in pg_catalog as part of this, if an admin
10893 		 * really wishes to do so, they can issue the individual ALTER
10894 		 * commands directly.
10895 		 *
10896 		 * Also, explicitly avoid any shared tables, temp tables, or TOAST
10897 		 * (TOAST will be moved with the main table).
10898 		 */
10899 		if (IsSystemNamespace(relForm->relnamespace) || relForm->relisshared ||
10900 			isAnyTempNamespace(relForm->relnamespace) ||
10901 			relForm->relnamespace == PG_TOAST_NAMESPACE)
10902 			continue;
10903 
10904 		/* Only move the object type requested */
10905 		if ((stmt->objtype == OBJECT_TABLE &&
10906 			 relForm->relkind != RELKIND_RELATION &&
10907 			 relForm->relkind != RELKIND_PARTITIONED_TABLE) ||
10908 			(stmt->objtype == OBJECT_INDEX &&
10909 			 relForm->relkind != RELKIND_INDEX) ||
10910 			(stmt->objtype == OBJECT_MATVIEW &&
10911 			 relForm->relkind != RELKIND_MATVIEW))
10912 			continue;
10913 
10914 		/* Check if we are only moving objects owned by certain roles */
10915 		if (role_oids != NIL && !list_member_oid(role_oids, relForm->relowner))
10916 			continue;
10917 
10918 		/*
10919 		 * Handle permissions-checking here since we are locking the tables
10920 		 * and also to avoid doing a bunch of work only to fail part-way. Note
10921 		 * that permissions will also be checked by AlterTableInternal().
10922 		 *
10923 		 * Caller must be considered an owner on the table to move it.
10924 		 */
10925 		if (!pg_class_ownercheck(relOid, GetUserId()))
10926 			aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS,
10927 						   NameStr(relForm->relname));
10928 
10929 		if (stmt->nowait &&
10930 			!ConditionalLockRelationOid(relOid, AccessExclusiveLock))
10931 			ereport(ERROR,
10932 					(errcode(ERRCODE_OBJECT_IN_USE),
10933 					 errmsg("aborting because lock on relation \"%s.%s\" is not available",
10934 							get_namespace_name(relForm->relnamespace),
10935 							NameStr(relForm->relname))));
10936 		else
10937 			LockRelationOid(relOid, AccessExclusiveLock);
10938 
10939 		/* Add to our list of objects to move */
10940 		relations = lappend_oid(relations, relOid);
10941 	}
10942 
10943 	heap_endscan(scan);
10944 	heap_close(rel, AccessShareLock);
10945 
10946 	if (relations == NIL)
10947 		ereport(NOTICE,
10948 				(errcode(ERRCODE_NO_DATA_FOUND),
10949 				 errmsg("no matching relations in tablespace \"%s\" found",
10950 						orig_tablespaceoid == InvalidOid ? "(database default)" :
10951 						get_tablespace_name(orig_tablespaceoid))));
10952 
10953 	/* Everything is locked, loop through and move all of the relations. */
10954 	foreach(l, relations)
10955 	{
10956 		List	   *cmds = NIL;
10957 		AlterTableCmd *cmd = makeNode(AlterTableCmd);
10958 
10959 		cmd->subtype = AT_SetTableSpace;
10960 		cmd->name = stmt->new_tablespacename;
10961 
10962 		cmds = lappend(cmds, cmd);
10963 
10964 		EventTriggerAlterTableStart((Node *) stmt);
10965 		/* OID is set by AlterTableInternal */
10966 		AlterTableInternal(lfirst_oid(l), cmds, false);
10967 		EventTriggerAlterTableEnd();
10968 	}
10969 
10970 	return new_tablespaceoid;
10971 }
10972 
10973 /*
10974  * Copy data, block by block
10975  */
10976 static void
copy_relation_data(SMgrRelation src,SMgrRelation dst,ForkNumber forkNum,char relpersistence)10977 copy_relation_data(SMgrRelation src, SMgrRelation dst,
10978 				   ForkNumber forkNum, char relpersistence)
10979 {
10980 	PGAlignedBlock buf;
10981 	Page		page;
10982 	bool		use_wal;
10983 	bool		copying_initfork;
10984 	BlockNumber nblocks;
10985 	BlockNumber blkno;
10986 
10987 	page = (Page) buf.data;
10988 
10989 	/*
10990 	 * The init fork for an unlogged relation in many respects has to be
10991 	 * treated the same as normal relation, changes need to be WAL logged and
10992 	 * it needs to be synced to disk.
10993 	 */
10994 	copying_initfork = relpersistence == RELPERSISTENCE_UNLOGGED &&
10995 		forkNum == INIT_FORKNUM;
10996 
10997 	/*
10998 	 * We need to log the copied data in WAL iff WAL archiving/streaming is
10999 	 * enabled AND it's a permanent relation.
11000 	 */
11001 	use_wal = XLogIsNeeded() &&
11002 		(relpersistence == RELPERSISTENCE_PERMANENT || copying_initfork);
11003 
11004 	nblocks = smgrnblocks(src, forkNum);
11005 
11006 	for (blkno = 0; blkno < nblocks; blkno++)
11007 	{
11008 		/* If we got a cancel signal during the copy of the data, quit */
11009 		CHECK_FOR_INTERRUPTS();
11010 
11011 		smgrread(src, forkNum, blkno, buf.data);
11012 
11013 		if (!PageIsVerified(page, blkno))
11014 			ereport(ERROR,
11015 					(errcode(ERRCODE_DATA_CORRUPTED),
11016 					 errmsg("invalid page in block %u of relation %s",
11017 							blkno,
11018 							relpathbackend(src->smgr_rnode.node,
11019 										   src->smgr_rnode.backend,
11020 										   forkNum))));
11021 
11022 		/*
11023 		 * WAL-log the copied page. Unfortunately we don't know what kind of a
11024 		 * page this is, so we have to log the full page including any unused
11025 		 * space.
11026 		 */
11027 		if (use_wal)
11028 			log_newpage(&dst->smgr_rnode.node, forkNum, blkno, page, false);
11029 
11030 		PageSetChecksumInplace(page, blkno);
11031 
11032 		/*
11033 		 * Now write the page.  We say isTemp = true even if it's not a temp
11034 		 * rel, because there's no need for smgr to schedule an fsync for this
11035 		 * write; we'll do it ourselves below.
11036 		 */
11037 		smgrextend(dst, forkNum, blkno, buf.data, true);
11038 	}
11039 
11040 	/*
11041 	 * If the rel is WAL-logged, must fsync before commit.  We use heap_sync
11042 	 * to ensure that the toast table gets fsync'd too.  (For a temp or
11043 	 * unlogged rel we don't care since the data will be gone after a crash
11044 	 * anyway.)
11045 	 *
11046 	 * It's obvious that we must do this when not WAL-logging the copy. It's
11047 	 * less obvious that we have to do it even if we did WAL-log the copied
11048 	 * pages. The reason is that since we're copying outside shared buffers, a
11049 	 * CHECKPOINT occurring during the copy has no way to flush the previously
11050 	 * written data to disk (indeed it won't know the new rel even exists).  A
11051 	 * crash later on would replay WAL from the checkpoint, therefore it
11052 	 * wouldn't replay our earlier WAL entries. If we do not fsync those pages
11053 	 * here, they might still not be on disk when the crash occurs.
11054 	 */
11055 	if (relpersistence == RELPERSISTENCE_PERMANENT || copying_initfork)
11056 		smgrimmedsync(dst, forkNum);
11057 }
11058 
11059 /*
11060  * ALTER TABLE ENABLE/DISABLE TRIGGER
11061  *
11062  * We just pass this off to trigger.c.
11063  */
11064 static void
ATExecEnableDisableTrigger(Relation rel,char * trigname,char fires_when,bool skip_system,LOCKMODE lockmode)11065 ATExecEnableDisableTrigger(Relation rel, char *trigname,
11066 						   char fires_when, bool skip_system, LOCKMODE lockmode)
11067 {
11068 	EnableDisableTrigger(rel, trigname, fires_when, skip_system);
11069 }
11070 
11071 /*
11072  * ALTER TABLE ENABLE/DISABLE RULE
11073  *
11074  * We just pass this off to rewriteDefine.c.
11075  */
11076 static void
ATExecEnableDisableRule(Relation rel,char * rulename,char fires_when,LOCKMODE lockmode)11077 ATExecEnableDisableRule(Relation rel, char *rulename,
11078 						char fires_when, LOCKMODE lockmode)
11079 {
11080 	EnableDisableRule(rel, rulename, fires_when);
11081 }
11082 
11083 /*
11084  * ALTER TABLE INHERIT
11085  *
11086  * Add a parent to the child's parents. This verifies that all the columns and
11087  * check constraints of the parent appear in the child and that they have the
11088  * same data types and expressions.
11089  */
11090 static void
ATPrepAddInherit(Relation child_rel)11091 ATPrepAddInherit(Relation child_rel)
11092 {
11093 	if (child_rel->rd_rel->reloftype)
11094 		ereport(ERROR,
11095 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
11096 				 errmsg("cannot change inheritance of typed table")));
11097 
11098 	if (child_rel->rd_rel->relispartition)
11099 		ereport(ERROR,
11100 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
11101 				 errmsg("cannot change inheritance of a partition")));
11102 
11103 	if (child_rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
11104 		ereport(ERROR,
11105 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
11106 				 errmsg("cannot change inheritance of partitioned table")));
11107 }
11108 
11109 /*
11110  * Return the address of the new parent relation.
11111  */
11112 static ObjectAddress
ATExecAddInherit(Relation child_rel,RangeVar * parent,LOCKMODE lockmode)11113 ATExecAddInherit(Relation child_rel, RangeVar *parent, LOCKMODE lockmode)
11114 {
11115 	Relation	parent_rel;
11116 	List	   *children;
11117 	ObjectAddress address;
11118 	const char *trigger_name;
11119 
11120 	/*
11121 	 * A self-exclusive lock is needed here.  See the similar case in
11122 	 * MergeAttributes() for a full explanation.
11123 	 */
11124 	parent_rel = heap_openrv(parent, ShareUpdateExclusiveLock);
11125 
11126 	/*
11127 	 * Must be owner of both parent and child -- child was checked by
11128 	 * ATSimplePermissions call in ATPrepCmd
11129 	 */
11130 	ATSimplePermissions(parent_rel, ATT_TABLE | ATT_FOREIGN_TABLE);
11131 
11132 	/* Permanent rels cannot inherit from temporary ones */
11133 	if (parent_rel->rd_rel->relpersistence == RELPERSISTENCE_TEMP &&
11134 		child_rel->rd_rel->relpersistence != RELPERSISTENCE_TEMP)
11135 		ereport(ERROR,
11136 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
11137 				 errmsg("cannot inherit from temporary relation \"%s\"",
11138 						RelationGetRelationName(parent_rel))));
11139 
11140 	/* If parent rel is temp, it must belong to this session */
11141 	if (parent_rel->rd_rel->relpersistence == RELPERSISTENCE_TEMP &&
11142 		!parent_rel->rd_islocaltemp)
11143 		ereport(ERROR,
11144 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
11145 				 errmsg("cannot inherit from temporary relation of another session")));
11146 
11147 	/* Ditto for the child */
11148 	if (child_rel->rd_rel->relpersistence == RELPERSISTENCE_TEMP &&
11149 		!child_rel->rd_islocaltemp)
11150 		ereport(ERROR,
11151 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
11152 				 errmsg("cannot inherit to temporary relation of another session")));
11153 
11154 	/* Prevent partitioned tables from becoming inheritance parents */
11155 	if (parent_rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
11156 		ereport(ERROR,
11157 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
11158 				 errmsg("cannot inherit from partitioned table \"%s\"",
11159 						parent->relname)));
11160 
11161 	/* Likewise for partitions */
11162 	if (parent_rel->rd_rel->relispartition)
11163 		ereport(ERROR,
11164 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
11165 				 errmsg("cannot inherit from a partition")));
11166 
11167 	/*
11168 	 * Prevent circularity by seeing if proposed parent inherits from child.
11169 	 * (In particular, this disallows making a rel inherit from itself.)
11170 	 *
11171 	 * This is not completely bulletproof because of race conditions: in
11172 	 * multi-level inheritance trees, someone else could concurrently be
11173 	 * making another inheritance link that closes the loop but does not join
11174 	 * either of the rels we have locked.  Preventing that seems to require
11175 	 * exclusive locks on the entire inheritance tree, which is a cure worse
11176 	 * than the disease.  find_all_inheritors() will cope with circularity
11177 	 * anyway, so don't sweat it too much.
11178 	 *
11179 	 * We use weakest lock we can on child's children, namely AccessShareLock.
11180 	 */
11181 	children = find_all_inheritors(RelationGetRelid(child_rel),
11182 								   AccessShareLock, NULL);
11183 
11184 	if (list_member_oid(children, RelationGetRelid(parent_rel)))
11185 		ereport(ERROR,
11186 				(errcode(ERRCODE_DUPLICATE_TABLE),
11187 				 errmsg("circular inheritance not allowed"),
11188 				 errdetail("\"%s\" is already a child of \"%s\".",
11189 						   parent->relname,
11190 						   RelationGetRelationName(child_rel))));
11191 
11192 	/* If parent has OIDs then child must have OIDs */
11193 	if (parent_rel->rd_rel->relhasoids && !child_rel->rd_rel->relhasoids)
11194 		ereport(ERROR,
11195 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
11196 				 errmsg("table \"%s\" without OIDs cannot inherit from table \"%s\" with OIDs",
11197 						RelationGetRelationName(child_rel),
11198 						RelationGetRelationName(parent_rel))));
11199 
11200 	/*
11201 	 * If child_rel has row-level triggers with transition tables, we
11202 	 * currently don't allow it to become an inheritance child.  See also
11203 	 * prohibitions in ATExecAttachPartition() and CreateTrigger().
11204 	 */
11205 	trigger_name = FindTriggerIncompatibleWithInheritance(child_rel->trigdesc);
11206 	if (trigger_name != NULL)
11207 		ereport(ERROR,
11208 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
11209 				 errmsg("trigger \"%s\" prevents table \"%s\" from becoming an inheritance child",
11210 						trigger_name, RelationGetRelationName(child_rel)),
11211 				 errdetail("ROW triggers with transition tables are not supported in inheritance hierarchies")));
11212 
11213 	/* OK to create inheritance */
11214 	CreateInheritance(child_rel, parent_rel);
11215 
11216 	ObjectAddressSet(address, RelationRelationId,
11217 					 RelationGetRelid(parent_rel));
11218 
11219 	/* keep our lock on the parent relation until commit */
11220 	heap_close(parent_rel, NoLock);
11221 
11222 	return address;
11223 }
11224 
11225 /*
11226  * CreateInheritance
11227  *		Catalog manipulation portion of creating inheritance between a child
11228  *		table and a parent table.
11229  *
11230  * Common to ATExecAddInherit() and ATExecAttachPartition().
11231  */
11232 static void
CreateInheritance(Relation child_rel,Relation parent_rel)11233 CreateInheritance(Relation child_rel, Relation parent_rel)
11234 {
11235 	Relation	catalogRelation;
11236 	SysScanDesc scan;
11237 	ScanKeyData key;
11238 	HeapTuple	inheritsTuple;
11239 	int32		inhseqno;
11240 
11241 	/* Note: get RowExclusiveLock because we will write pg_inherits below. */
11242 	catalogRelation = heap_open(InheritsRelationId, RowExclusiveLock);
11243 
11244 	/*
11245 	 * Check for duplicates in the list of parents, and determine the highest
11246 	 * inhseqno already present; we'll use the next one for the new parent.
11247 	 * Also, if proposed child is a partition, it cannot already be
11248 	 * inheriting.
11249 	 *
11250 	 * Note: we do not reject the case where the child already inherits from
11251 	 * the parent indirectly; CREATE TABLE doesn't reject comparable cases.
11252 	 */
11253 	ScanKeyInit(&key,
11254 				Anum_pg_inherits_inhrelid,
11255 				BTEqualStrategyNumber, F_OIDEQ,
11256 				ObjectIdGetDatum(RelationGetRelid(child_rel)));
11257 	scan = systable_beginscan(catalogRelation, InheritsRelidSeqnoIndexId,
11258 							  true, NULL, 1, &key);
11259 
11260 	/* inhseqno sequences start at 1 */
11261 	inhseqno = 0;
11262 	while (HeapTupleIsValid(inheritsTuple = systable_getnext(scan)))
11263 	{
11264 		Form_pg_inherits inh = (Form_pg_inherits) GETSTRUCT(inheritsTuple);
11265 
11266 		if (inh->inhparent == RelationGetRelid(parent_rel))
11267 			ereport(ERROR,
11268 					(errcode(ERRCODE_DUPLICATE_TABLE),
11269 					 errmsg("relation \"%s\" would be inherited from more than once",
11270 							RelationGetRelationName(parent_rel))));
11271 
11272 		if (inh->inhseqno > inhseqno)
11273 			inhseqno = inh->inhseqno;
11274 	}
11275 	systable_endscan(scan);
11276 
11277 	/* Match up the columns and bump attinhcount as needed */
11278 	MergeAttributesIntoExisting(child_rel, parent_rel);
11279 
11280 	/* Match up the constraints and bump coninhcount as needed */
11281 	MergeConstraintsIntoExisting(child_rel, parent_rel);
11282 
11283 	/*
11284 	 * OK, it looks valid.  Make the catalog entries that show inheritance.
11285 	 */
11286 	StoreCatalogInheritance1(RelationGetRelid(child_rel),
11287 							 RelationGetRelid(parent_rel),
11288 							 inhseqno + 1,
11289 							 catalogRelation,
11290 							 parent_rel->rd_rel->relkind ==
11291 							 RELKIND_PARTITIONED_TABLE);
11292 
11293 	/* Now we're done with pg_inherits */
11294 	heap_close(catalogRelation, RowExclusiveLock);
11295 }
11296 
11297 /*
11298  * Obtain the source-text form of the constraint expression for a check
11299  * constraint, given its pg_constraint tuple
11300  */
11301 static char *
decompile_conbin(HeapTuple contup,TupleDesc tupdesc)11302 decompile_conbin(HeapTuple contup, TupleDesc tupdesc)
11303 {
11304 	Form_pg_constraint con;
11305 	bool		isnull;
11306 	Datum		attr;
11307 	Datum		expr;
11308 
11309 	con = (Form_pg_constraint) GETSTRUCT(contup);
11310 	attr = heap_getattr(contup, Anum_pg_constraint_conbin, tupdesc, &isnull);
11311 	if (isnull)
11312 		elog(ERROR, "null conbin for constraint %u", HeapTupleGetOid(contup));
11313 
11314 	expr = DirectFunctionCall2(pg_get_expr, attr,
11315 							   ObjectIdGetDatum(con->conrelid));
11316 	return TextDatumGetCString(expr);
11317 }
11318 
11319 /*
11320  * Determine whether two check constraints are functionally equivalent
11321  *
11322  * The test we apply is to see whether they reverse-compile to the same
11323  * source string.  This insulates us from issues like whether attributes
11324  * have the same physical column numbers in parent and child relations.
11325  */
11326 static bool
constraints_equivalent(HeapTuple a,HeapTuple b,TupleDesc tupleDesc)11327 constraints_equivalent(HeapTuple a, HeapTuple b, TupleDesc tupleDesc)
11328 {
11329 	Form_pg_constraint acon = (Form_pg_constraint) GETSTRUCT(a);
11330 	Form_pg_constraint bcon = (Form_pg_constraint) GETSTRUCT(b);
11331 
11332 	if (acon->condeferrable != bcon->condeferrable ||
11333 		acon->condeferred != bcon->condeferred ||
11334 		strcmp(decompile_conbin(a, tupleDesc),
11335 			   decompile_conbin(b, tupleDesc)) != 0)
11336 		return false;
11337 	else
11338 		return true;
11339 }
11340 
11341 /*
11342  * Check columns in child table match up with columns in parent, and increment
11343  * their attinhcount.
11344  *
11345  * Called by CreateInheritance
11346  *
11347  * Currently all parent columns must be found in child. Missing columns are an
11348  * error.  One day we might consider creating new columns like CREATE TABLE
11349  * does.  However, that is widely unpopular --- in the common use case of
11350  * partitioned tables it's a foot-gun.
11351  *
11352  * The data type must match exactly. If the parent column is NOT NULL then
11353  * the child must be as well. Defaults are not compared, however.
11354  */
11355 static void
MergeAttributesIntoExisting(Relation child_rel,Relation parent_rel)11356 MergeAttributesIntoExisting(Relation child_rel, Relation parent_rel)
11357 {
11358 	Relation	attrrel;
11359 	AttrNumber	parent_attno;
11360 	int			parent_natts;
11361 	TupleDesc	tupleDesc;
11362 	HeapTuple	tuple;
11363 	bool		child_is_partition = false;
11364 
11365 	attrrel = heap_open(AttributeRelationId, RowExclusiveLock);
11366 
11367 	tupleDesc = RelationGetDescr(parent_rel);
11368 	parent_natts = tupleDesc->natts;
11369 
11370 	/* If parent_rel is a partitioned table, child_rel must be a partition */
11371 	if (parent_rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
11372 		child_is_partition = true;
11373 
11374 	for (parent_attno = 1; parent_attno <= parent_natts; parent_attno++)
11375 	{
11376 		Form_pg_attribute attribute = tupleDesc->attrs[parent_attno - 1];
11377 		char	   *attributeName = NameStr(attribute->attname);
11378 
11379 		/* Ignore dropped columns in the parent. */
11380 		if (attribute->attisdropped)
11381 			continue;
11382 
11383 		/* Find same column in child (matching on column name). */
11384 		tuple = SearchSysCacheCopyAttName(RelationGetRelid(child_rel),
11385 										  attributeName);
11386 		if (HeapTupleIsValid(tuple))
11387 		{
11388 			/* Check they are same type, typmod, and collation */
11389 			Form_pg_attribute childatt = (Form_pg_attribute) GETSTRUCT(tuple);
11390 
11391 			if (attribute->atttypid != childatt->atttypid ||
11392 				attribute->atttypmod != childatt->atttypmod)
11393 				ereport(ERROR,
11394 						(errcode(ERRCODE_DATATYPE_MISMATCH),
11395 						 errmsg("child table \"%s\" has different type for column \"%s\"",
11396 								RelationGetRelationName(child_rel),
11397 								attributeName)));
11398 
11399 			if (attribute->attcollation != childatt->attcollation)
11400 				ereport(ERROR,
11401 						(errcode(ERRCODE_COLLATION_MISMATCH),
11402 						 errmsg("child table \"%s\" has different collation for column \"%s\"",
11403 								RelationGetRelationName(child_rel),
11404 								attributeName)));
11405 
11406 			/*
11407 			 * Check child doesn't discard NOT NULL property.  (Other
11408 			 * constraints are checked elsewhere.)
11409 			 */
11410 			if (attribute->attnotnull && !childatt->attnotnull)
11411 				ereport(ERROR,
11412 						(errcode(ERRCODE_DATATYPE_MISMATCH),
11413 						 errmsg("column \"%s\" in child table must be marked NOT NULL",
11414 								attributeName)));
11415 
11416 			/*
11417 			 * OK, bump the child column's inheritance count.  (If we fail
11418 			 * later on, this change will just roll back.)
11419 			 */
11420 			childatt->attinhcount++;
11421 
11422 			/*
11423 			 * In case of partitions, we must enforce that value of attislocal
11424 			 * is same in all partitions. (Note: there are only inherited
11425 			 * attributes in partitions)
11426 			 */
11427 			if (child_is_partition)
11428 			{
11429 				Assert(childatt->attinhcount == 1);
11430 				childatt->attislocal = false;
11431 			}
11432 
11433 			CatalogTupleUpdate(attrrel, &tuple->t_self, tuple);
11434 			heap_freetuple(tuple);
11435 		}
11436 		else
11437 		{
11438 			ereport(ERROR,
11439 					(errcode(ERRCODE_DATATYPE_MISMATCH),
11440 					 errmsg("child table is missing column \"%s\"",
11441 							attributeName)));
11442 		}
11443 	}
11444 
11445 	/*
11446 	 * If the parent has an OID column, so must the child, and we'd better
11447 	 * update the child's attinhcount and attislocal the same as for normal
11448 	 * columns.  We needn't check data type or not-nullness though.
11449 	 */
11450 	if (tupleDesc->tdhasoid)
11451 	{
11452 		/*
11453 		 * Here we match by column number not name; the match *must* be the
11454 		 * system column, not some random column named "oid".
11455 		 */
11456 		tuple = SearchSysCacheCopy2(ATTNUM,
11457 									ObjectIdGetDatum(RelationGetRelid(child_rel)),
11458 									Int16GetDatum(ObjectIdAttributeNumber));
11459 		if (HeapTupleIsValid(tuple))
11460 		{
11461 			Form_pg_attribute childatt = (Form_pg_attribute) GETSTRUCT(tuple);
11462 
11463 			/* See comments above; these changes should be the same */
11464 			childatt->attinhcount++;
11465 
11466 			if (child_is_partition)
11467 			{
11468 				Assert(childatt->attinhcount == 1);
11469 				childatt->attislocal = false;
11470 			}
11471 
11472 			CatalogTupleUpdate(attrrel, &tuple->t_self, tuple);
11473 			heap_freetuple(tuple);
11474 		}
11475 		else
11476 		{
11477 			ereport(ERROR,
11478 					(errcode(ERRCODE_DATATYPE_MISMATCH),
11479 					 errmsg("child table is missing column \"%s\"",
11480 							"oid")));
11481 		}
11482 	}
11483 
11484 	heap_close(attrrel, RowExclusiveLock);
11485 }
11486 
11487 /*
11488  * Check constraints in child table match up with constraints in parent,
11489  * and increment their coninhcount.
11490  *
11491  * Constraints that are marked ONLY in the parent are ignored.
11492  *
11493  * Called by CreateInheritance
11494  *
11495  * Currently all constraints in parent must be present in the child. One day we
11496  * may consider adding new constraints like CREATE TABLE does.
11497  *
11498  * XXX This is O(N^2) which may be an issue with tables with hundreds of
11499  * constraints. As long as tables have more like 10 constraints it shouldn't be
11500  * a problem though. Even 100 constraints ought not be the end of the world.
11501  *
11502  * XXX See MergeWithExistingConstraint too if you change this code.
11503  */
11504 static void
MergeConstraintsIntoExisting(Relation child_rel,Relation parent_rel)11505 MergeConstraintsIntoExisting(Relation child_rel, Relation parent_rel)
11506 {
11507 	Relation	catalog_relation;
11508 	TupleDesc	tuple_desc;
11509 	SysScanDesc parent_scan;
11510 	ScanKeyData parent_key;
11511 	HeapTuple	parent_tuple;
11512 	bool		child_is_partition = false;
11513 
11514 	catalog_relation = heap_open(ConstraintRelationId, RowExclusiveLock);
11515 	tuple_desc = RelationGetDescr(catalog_relation);
11516 
11517 	/* If parent_rel is a partitioned table, child_rel must be a partition */
11518 	if (parent_rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
11519 		child_is_partition = true;
11520 
11521 	/* Outer loop scans through the parent's constraint definitions */
11522 	ScanKeyInit(&parent_key,
11523 				Anum_pg_constraint_conrelid,
11524 				BTEqualStrategyNumber, F_OIDEQ,
11525 				ObjectIdGetDatum(RelationGetRelid(parent_rel)));
11526 	parent_scan = systable_beginscan(catalog_relation, ConstraintRelidIndexId,
11527 									 true, NULL, 1, &parent_key);
11528 
11529 	while (HeapTupleIsValid(parent_tuple = systable_getnext(parent_scan)))
11530 	{
11531 		Form_pg_constraint parent_con = (Form_pg_constraint) GETSTRUCT(parent_tuple);
11532 		SysScanDesc child_scan;
11533 		ScanKeyData child_key;
11534 		HeapTuple	child_tuple;
11535 		bool		found = false;
11536 
11537 		if (parent_con->contype != CONSTRAINT_CHECK)
11538 			continue;
11539 
11540 		/* if the parent's constraint is marked NO INHERIT, it's not inherited */
11541 		if (parent_con->connoinherit)
11542 			continue;
11543 
11544 		/* Search for a child constraint matching this one */
11545 		ScanKeyInit(&child_key,
11546 					Anum_pg_constraint_conrelid,
11547 					BTEqualStrategyNumber, F_OIDEQ,
11548 					ObjectIdGetDatum(RelationGetRelid(child_rel)));
11549 		child_scan = systable_beginscan(catalog_relation, ConstraintRelidIndexId,
11550 										true, NULL, 1, &child_key);
11551 
11552 		while (HeapTupleIsValid(child_tuple = systable_getnext(child_scan)))
11553 		{
11554 			Form_pg_constraint child_con = (Form_pg_constraint) GETSTRUCT(child_tuple);
11555 			HeapTuple	child_copy;
11556 
11557 			if (child_con->contype != CONSTRAINT_CHECK)
11558 				continue;
11559 
11560 			if (strcmp(NameStr(parent_con->conname),
11561 					   NameStr(child_con->conname)) != 0)
11562 				continue;
11563 
11564 			if (!constraints_equivalent(parent_tuple, child_tuple, tuple_desc))
11565 				ereport(ERROR,
11566 						(errcode(ERRCODE_DATATYPE_MISMATCH),
11567 						 errmsg("child table \"%s\" has different definition for check constraint \"%s\"",
11568 								RelationGetRelationName(child_rel),
11569 								NameStr(parent_con->conname))));
11570 
11571 			/* If the child constraint is "no inherit" then cannot merge */
11572 			if (child_con->connoinherit)
11573 				ereport(ERROR,
11574 						(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
11575 						 errmsg("constraint \"%s\" conflicts with non-inherited constraint on child table \"%s\"",
11576 								NameStr(child_con->conname),
11577 								RelationGetRelationName(child_rel))));
11578 
11579 			/*
11580 			 * If the child constraint is "not valid" then cannot merge with a
11581 			 * valid parent constraint
11582 			 */
11583 			if (parent_con->convalidated && !child_con->convalidated)
11584 				ereport(ERROR,
11585 						(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
11586 						 errmsg("constraint \"%s\" conflicts with NOT VALID constraint on child table \"%s\"",
11587 								NameStr(child_con->conname),
11588 								RelationGetRelationName(child_rel))));
11589 
11590 			/*
11591 			 * OK, bump the child constraint's inheritance count.  (If we fail
11592 			 * later on, this change will just roll back.)
11593 			 */
11594 			child_copy = heap_copytuple(child_tuple);
11595 			child_con = (Form_pg_constraint) GETSTRUCT(child_copy);
11596 			child_con->coninhcount++;
11597 
11598 			/*
11599 			 * In case of partitions, an inherited constraint must be
11600 			 * inherited only once since it cannot have multiple parents and
11601 			 * it is never considered local.
11602 			 */
11603 			if (child_is_partition)
11604 			{
11605 				Assert(child_con->coninhcount == 1);
11606 				child_con->conislocal = false;
11607 			}
11608 
11609 			CatalogTupleUpdate(catalog_relation, &child_copy->t_self, child_copy);
11610 			heap_freetuple(child_copy);
11611 
11612 			found = true;
11613 			break;
11614 		}
11615 
11616 		systable_endscan(child_scan);
11617 
11618 		if (!found)
11619 			ereport(ERROR,
11620 					(errcode(ERRCODE_DATATYPE_MISMATCH),
11621 					 errmsg("child table is missing constraint \"%s\"",
11622 							NameStr(parent_con->conname))));
11623 	}
11624 
11625 	systable_endscan(parent_scan);
11626 	heap_close(catalog_relation, RowExclusiveLock);
11627 }
11628 
11629 /*
11630  * ALTER TABLE NO INHERIT
11631  *
11632  * Return value is the address of the relation that is no longer parent.
11633  */
11634 static ObjectAddress
ATExecDropInherit(Relation rel,RangeVar * parent,LOCKMODE lockmode)11635 ATExecDropInherit(Relation rel, RangeVar *parent, LOCKMODE lockmode)
11636 {
11637 	ObjectAddress address;
11638 	Relation	parent_rel;
11639 
11640 	if (rel->rd_rel->relispartition)
11641 		ereport(ERROR,
11642 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
11643 				 errmsg("cannot change inheritance of a partition")));
11644 
11645 	/*
11646 	 * AccessShareLock on the parent is probably enough, seeing that DROP
11647 	 * TABLE doesn't lock parent tables at all.  We need some lock since we'll
11648 	 * be inspecting the parent's schema.
11649 	 */
11650 	parent_rel = heap_openrv(parent, AccessShareLock);
11651 
11652 	/*
11653 	 * We don't bother to check ownership of the parent table --- ownership of
11654 	 * the child is presumed enough rights.
11655 	 */
11656 
11657 	/* Off to RemoveInheritance() where most of the work happens */
11658 	RemoveInheritance(rel, parent_rel);
11659 
11660 	ObjectAddressSet(address, RelationRelationId,
11661 					 RelationGetRelid(parent_rel));
11662 
11663 	/* keep our lock on the parent relation until commit */
11664 	heap_close(parent_rel, NoLock);
11665 
11666 	return address;
11667 }
11668 
11669 /*
11670  * RemoveInheritance
11671  *
11672  * Drop a parent from the child's parents. This just adjusts the attinhcount
11673  * and attislocal of the columns and removes the pg_inherit and pg_depend
11674  * entries.
11675  *
11676  * If attinhcount goes to 0 then attislocal gets set to true. If it goes back
11677  * up attislocal stays true, which means if a child is ever removed from a
11678  * parent then its columns will never be automatically dropped which may
11679  * surprise. But at least we'll never surprise by dropping columns someone
11680  * isn't expecting to be dropped which would actually mean data loss.
11681  *
11682  * coninhcount and conislocal for inherited constraints are adjusted in
11683  * exactly the same way.
11684  *
11685  * Common to ATExecDropInherit() and ATExecDetachPartition().
11686  */
11687 static void
RemoveInheritance(Relation child_rel,Relation parent_rel)11688 RemoveInheritance(Relation child_rel, Relation parent_rel)
11689 {
11690 	Relation	catalogRelation;
11691 	SysScanDesc scan;
11692 	ScanKeyData key[3];
11693 	HeapTuple	inheritsTuple,
11694 				attributeTuple,
11695 				constraintTuple;
11696 	List	   *connames;
11697 	bool		found = false;
11698 	bool		child_is_partition = false;
11699 
11700 	/* If parent_rel is a partitioned table, child_rel must be a partition */
11701 	if (parent_rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
11702 		child_is_partition = true;
11703 
11704 	/*
11705 	 * Find and destroy the pg_inherits entry linking the two, or error out if
11706 	 * there is none.
11707 	 */
11708 	catalogRelation = heap_open(InheritsRelationId, RowExclusiveLock);
11709 	ScanKeyInit(&key[0],
11710 				Anum_pg_inherits_inhrelid,
11711 				BTEqualStrategyNumber, F_OIDEQ,
11712 				ObjectIdGetDatum(RelationGetRelid(child_rel)));
11713 	scan = systable_beginscan(catalogRelation, InheritsRelidSeqnoIndexId,
11714 							  true, NULL, 1, key);
11715 
11716 	while (HeapTupleIsValid(inheritsTuple = systable_getnext(scan)))
11717 	{
11718 		Oid			inhparent;
11719 
11720 		inhparent = ((Form_pg_inherits) GETSTRUCT(inheritsTuple))->inhparent;
11721 		if (inhparent == RelationGetRelid(parent_rel))
11722 		{
11723 			CatalogTupleDelete(catalogRelation, &inheritsTuple->t_self);
11724 			found = true;
11725 			break;
11726 		}
11727 	}
11728 
11729 	systable_endscan(scan);
11730 	heap_close(catalogRelation, RowExclusiveLock);
11731 
11732 	if (!found)
11733 	{
11734 		if (child_is_partition)
11735 			ereport(ERROR,
11736 					(errcode(ERRCODE_UNDEFINED_TABLE),
11737 					 errmsg("relation \"%s\" is not a partition of relation \"%s\"",
11738 							RelationGetRelationName(child_rel),
11739 							RelationGetRelationName(parent_rel))));
11740 		else
11741 			ereport(ERROR,
11742 					(errcode(ERRCODE_UNDEFINED_TABLE),
11743 					 errmsg("relation \"%s\" is not a parent of relation \"%s\"",
11744 							RelationGetRelationName(parent_rel),
11745 							RelationGetRelationName(child_rel))));
11746 	}
11747 
11748 	/*
11749 	 * Search through child columns looking for ones matching parent rel
11750 	 */
11751 	catalogRelation = heap_open(AttributeRelationId, RowExclusiveLock);
11752 	ScanKeyInit(&key[0],
11753 				Anum_pg_attribute_attrelid,
11754 				BTEqualStrategyNumber, F_OIDEQ,
11755 				ObjectIdGetDatum(RelationGetRelid(child_rel)));
11756 	scan = systable_beginscan(catalogRelation, AttributeRelidNumIndexId,
11757 							  true, NULL, 1, key);
11758 	while (HeapTupleIsValid(attributeTuple = systable_getnext(scan)))
11759 	{
11760 		Form_pg_attribute att = (Form_pg_attribute) GETSTRUCT(attributeTuple);
11761 
11762 		/* Ignore if dropped or not inherited */
11763 		if (att->attisdropped)
11764 			continue;
11765 		if (att->attinhcount <= 0)
11766 			continue;
11767 
11768 		if (SearchSysCacheExistsAttName(RelationGetRelid(parent_rel),
11769 										NameStr(att->attname)))
11770 		{
11771 			/* Decrement inhcount and possibly set islocal to true */
11772 			HeapTuple	copyTuple = heap_copytuple(attributeTuple);
11773 			Form_pg_attribute copy_att = (Form_pg_attribute) GETSTRUCT(copyTuple);
11774 
11775 			copy_att->attinhcount--;
11776 			if (copy_att->attinhcount == 0)
11777 				copy_att->attislocal = true;
11778 
11779 			CatalogTupleUpdate(catalogRelation, &copyTuple->t_self, copyTuple);
11780 			heap_freetuple(copyTuple);
11781 		}
11782 	}
11783 	systable_endscan(scan);
11784 	heap_close(catalogRelation, RowExclusiveLock);
11785 
11786 	/*
11787 	 * Likewise, find inherited check constraints and disinherit them. To do
11788 	 * this, we first need a list of the names of the parent's check
11789 	 * constraints.  (We cheat a bit by only checking for name matches,
11790 	 * assuming that the expressions will match.)
11791 	 */
11792 	catalogRelation = heap_open(ConstraintRelationId, RowExclusiveLock);
11793 	ScanKeyInit(&key[0],
11794 				Anum_pg_constraint_conrelid,
11795 				BTEqualStrategyNumber, F_OIDEQ,
11796 				ObjectIdGetDatum(RelationGetRelid(parent_rel)));
11797 	scan = systable_beginscan(catalogRelation, ConstraintRelidIndexId,
11798 							  true, NULL, 1, key);
11799 
11800 	connames = NIL;
11801 
11802 	while (HeapTupleIsValid(constraintTuple = systable_getnext(scan)))
11803 	{
11804 		Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(constraintTuple);
11805 
11806 		if (con->contype == CONSTRAINT_CHECK)
11807 			connames = lappend(connames, pstrdup(NameStr(con->conname)));
11808 	}
11809 
11810 	systable_endscan(scan);
11811 
11812 	/* Now scan the child's constraints */
11813 	ScanKeyInit(&key[0],
11814 				Anum_pg_constraint_conrelid,
11815 				BTEqualStrategyNumber, F_OIDEQ,
11816 				ObjectIdGetDatum(RelationGetRelid(child_rel)));
11817 	scan = systable_beginscan(catalogRelation, ConstraintRelidIndexId,
11818 							  true, NULL, 1, key);
11819 
11820 	while (HeapTupleIsValid(constraintTuple = systable_getnext(scan)))
11821 	{
11822 		Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(constraintTuple);
11823 		bool		match;
11824 		ListCell   *lc;
11825 
11826 		if (con->contype != CONSTRAINT_CHECK)
11827 			continue;
11828 
11829 		match = false;
11830 		foreach(lc, connames)
11831 		{
11832 			if (strcmp(NameStr(con->conname), (char *) lfirst(lc)) == 0)
11833 			{
11834 				match = true;
11835 				break;
11836 			}
11837 		}
11838 
11839 		if (match)
11840 		{
11841 			/* Decrement inhcount and possibly set islocal to true */
11842 			HeapTuple	copyTuple = heap_copytuple(constraintTuple);
11843 			Form_pg_constraint copy_con = (Form_pg_constraint) GETSTRUCT(copyTuple);
11844 
11845 			if (copy_con->coninhcount <= 0) /* shouldn't happen */
11846 				elog(ERROR, "relation %u has non-inherited constraint \"%s\"",
11847 					 RelationGetRelid(child_rel), NameStr(copy_con->conname));
11848 
11849 			copy_con->coninhcount--;
11850 			if (copy_con->coninhcount == 0)
11851 				copy_con->conislocal = true;
11852 
11853 			CatalogTupleUpdate(catalogRelation, &copyTuple->t_self, copyTuple);
11854 			heap_freetuple(copyTuple);
11855 		}
11856 	}
11857 
11858 	systable_endscan(scan);
11859 	heap_close(catalogRelation, RowExclusiveLock);
11860 
11861 	drop_parent_dependency(RelationGetRelid(child_rel),
11862 						   RelationRelationId,
11863 						   RelationGetRelid(parent_rel),
11864 						   child_dependency_type(child_is_partition));
11865 
11866 	/*
11867 	 * Post alter hook of this inherits. Since object_access_hook doesn't take
11868 	 * multiple object identifiers, we relay oid of parent relation using
11869 	 * auxiliary_id argument.
11870 	 */
11871 	InvokeObjectPostAlterHookArg(InheritsRelationId,
11872 								 RelationGetRelid(child_rel), 0,
11873 								 RelationGetRelid(parent_rel), false);
11874 }
11875 
11876 /*
11877  * Drop the dependency created by StoreCatalogInheritance1 (CREATE TABLE
11878  * INHERITS/ALTER TABLE INHERIT -- refclassid will be RelationRelationId) or
11879  * heap_create_with_catalog (CREATE TABLE OF/ALTER TABLE OF -- refclassid will
11880  * be TypeRelationId).  There's no convenient way to do this, so go trawling
11881  * through pg_depend.
11882  */
11883 static void
drop_parent_dependency(Oid relid,Oid refclassid,Oid refobjid,DependencyType deptype)11884 drop_parent_dependency(Oid relid, Oid refclassid, Oid refobjid,
11885 					   DependencyType deptype)
11886 {
11887 	Relation	catalogRelation;
11888 	SysScanDesc scan;
11889 	ScanKeyData key[3];
11890 	HeapTuple	depTuple;
11891 
11892 	catalogRelation = heap_open(DependRelationId, RowExclusiveLock);
11893 
11894 	ScanKeyInit(&key[0],
11895 				Anum_pg_depend_classid,
11896 				BTEqualStrategyNumber, F_OIDEQ,
11897 				ObjectIdGetDatum(RelationRelationId));
11898 	ScanKeyInit(&key[1],
11899 				Anum_pg_depend_objid,
11900 				BTEqualStrategyNumber, F_OIDEQ,
11901 				ObjectIdGetDatum(relid));
11902 	ScanKeyInit(&key[2],
11903 				Anum_pg_depend_objsubid,
11904 				BTEqualStrategyNumber, F_INT4EQ,
11905 				Int32GetDatum(0));
11906 
11907 	scan = systable_beginscan(catalogRelation, DependDependerIndexId, true,
11908 							  NULL, 3, key);
11909 
11910 	while (HeapTupleIsValid(depTuple = systable_getnext(scan)))
11911 	{
11912 		Form_pg_depend dep = (Form_pg_depend) GETSTRUCT(depTuple);
11913 
11914 		if (dep->refclassid == refclassid &&
11915 			dep->refobjid == refobjid &&
11916 			dep->refobjsubid == 0 &&
11917 			dep->deptype == deptype)
11918 			CatalogTupleDelete(catalogRelation, &depTuple->t_self);
11919 	}
11920 
11921 	systable_endscan(scan);
11922 	heap_close(catalogRelation, RowExclusiveLock);
11923 }
11924 
11925 /*
11926  * ALTER TABLE OF
11927  *
11928  * Attach a table to a composite type, as though it had been created with CREATE
11929  * TABLE OF.  All attname, atttypid, atttypmod and attcollation must match.  The
11930  * subject table must not have inheritance parents.  These restrictions ensure
11931  * that you cannot create a configuration impossible with CREATE TABLE OF alone.
11932  *
11933  * The address of the type is returned.
11934  */
11935 static ObjectAddress
ATExecAddOf(Relation rel,const TypeName * ofTypename,LOCKMODE lockmode)11936 ATExecAddOf(Relation rel, const TypeName *ofTypename, LOCKMODE lockmode)
11937 {
11938 	Oid			relid = RelationGetRelid(rel);
11939 	Type		typetuple;
11940 	Oid			typeid;
11941 	Relation	inheritsRelation,
11942 				relationRelation;
11943 	SysScanDesc scan;
11944 	ScanKeyData key;
11945 	AttrNumber	table_attno,
11946 				type_attno;
11947 	TupleDesc	typeTupleDesc,
11948 				tableTupleDesc;
11949 	ObjectAddress tableobj,
11950 				typeobj;
11951 	HeapTuple	classtuple;
11952 
11953 	/* Validate the type. */
11954 	typetuple = typenameType(NULL, ofTypename, NULL);
11955 	check_of_type(typetuple);
11956 	typeid = HeapTupleGetOid(typetuple);
11957 
11958 	/* Fail if the table has any inheritance parents. */
11959 	inheritsRelation = heap_open(InheritsRelationId, AccessShareLock);
11960 	ScanKeyInit(&key,
11961 				Anum_pg_inherits_inhrelid,
11962 				BTEqualStrategyNumber, F_OIDEQ,
11963 				ObjectIdGetDatum(relid));
11964 	scan = systable_beginscan(inheritsRelation, InheritsRelidSeqnoIndexId,
11965 							  true, NULL, 1, &key);
11966 	if (HeapTupleIsValid(systable_getnext(scan)))
11967 		ereport(ERROR,
11968 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
11969 				 errmsg("typed tables cannot inherit")));
11970 	systable_endscan(scan);
11971 	heap_close(inheritsRelation, AccessShareLock);
11972 
11973 	/*
11974 	 * Check the tuple descriptors for compatibility.  Unlike inheritance, we
11975 	 * require that the order also match.  However, attnotnull need not match.
11976 	 * Also unlike inheritance, we do not require matching relhasoids.
11977 	 */
11978 	typeTupleDesc = lookup_rowtype_tupdesc(typeid, -1);
11979 	tableTupleDesc = RelationGetDescr(rel);
11980 	table_attno = 1;
11981 	for (type_attno = 1; type_attno <= typeTupleDesc->natts; type_attno++)
11982 	{
11983 		Form_pg_attribute type_attr,
11984 					table_attr;
11985 		const char *type_attname,
11986 				   *table_attname;
11987 
11988 		/* Get the next non-dropped type attribute. */
11989 		type_attr = typeTupleDesc->attrs[type_attno - 1];
11990 		if (type_attr->attisdropped)
11991 			continue;
11992 		type_attname = NameStr(type_attr->attname);
11993 
11994 		/* Get the next non-dropped table attribute. */
11995 		do
11996 		{
11997 			if (table_attno > tableTupleDesc->natts)
11998 				ereport(ERROR,
11999 						(errcode(ERRCODE_DATATYPE_MISMATCH),
12000 						 errmsg("table is missing column \"%s\"",
12001 								type_attname)));
12002 			table_attr = tableTupleDesc->attrs[table_attno++ - 1];
12003 		} while (table_attr->attisdropped);
12004 		table_attname = NameStr(table_attr->attname);
12005 
12006 		/* Compare name. */
12007 		if (strncmp(table_attname, type_attname, NAMEDATALEN) != 0)
12008 			ereport(ERROR,
12009 					(errcode(ERRCODE_DATATYPE_MISMATCH),
12010 					 errmsg("table has column \"%s\" where type requires \"%s\"",
12011 							table_attname, type_attname)));
12012 
12013 		/* Compare type. */
12014 		if (table_attr->atttypid != type_attr->atttypid ||
12015 			table_attr->atttypmod != type_attr->atttypmod ||
12016 			table_attr->attcollation != type_attr->attcollation)
12017 			ereport(ERROR,
12018 					(errcode(ERRCODE_DATATYPE_MISMATCH),
12019 					 errmsg("table \"%s\" has different type for column \"%s\"",
12020 							RelationGetRelationName(rel), type_attname)));
12021 	}
12022 	DecrTupleDescRefCount(typeTupleDesc);
12023 
12024 	/* Any remaining columns at the end of the table had better be dropped. */
12025 	for (; table_attno <= tableTupleDesc->natts; table_attno++)
12026 	{
12027 		Form_pg_attribute table_attr = tableTupleDesc->attrs[table_attno - 1];
12028 
12029 		if (!table_attr->attisdropped)
12030 			ereport(ERROR,
12031 					(errcode(ERRCODE_DATATYPE_MISMATCH),
12032 					 errmsg("table has extra column \"%s\"",
12033 							NameStr(table_attr->attname))));
12034 	}
12035 
12036 	/* If the table was already typed, drop the existing dependency. */
12037 	if (rel->rd_rel->reloftype)
12038 		drop_parent_dependency(relid, TypeRelationId, rel->rd_rel->reloftype,
12039 							   DEPENDENCY_NORMAL);
12040 
12041 	/* Record a dependency on the new type. */
12042 	tableobj.classId = RelationRelationId;
12043 	tableobj.objectId = relid;
12044 	tableobj.objectSubId = 0;
12045 	typeobj.classId = TypeRelationId;
12046 	typeobj.objectId = typeid;
12047 	typeobj.objectSubId = 0;
12048 	recordDependencyOn(&tableobj, &typeobj, DEPENDENCY_NORMAL);
12049 
12050 	/* Update pg_class.reloftype */
12051 	relationRelation = heap_open(RelationRelationId, RowExclusiveLock);
12052 	classtuple = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
12053 	if (!HeapTupleIsValid(classtuple))
12054 		elog(ERROR, "cache lookup failed for relation %u", relid);
12055 	((Form_pg_class) GETSTRUCT(classtuple))->reloftype = typeid;
12056 	CatalogTupleUpdate(relationRelation, &classtuple->t_self, classtuple);
12057 
12058 	InvokeObjectPostAlterHook(RelationRelationId, relid, 0);
12059 
12060 	heap_freetuple(classtuple);
12061 	heap_close(relationRelation, RowExclusiveLock);
12062 
12063 	ReleaseSysCache(typetuple);
12064 
12065 	return typeobj;
12066 }
12067 
12068 /*
12069  * ALTER TABLE NOT OF
12070  *
12071  * Detach a typed table from its originating type.  Just clear reloftype and
12072  * remove the dependency.
12073  */
12074 static void
ATExecDropOf(Relation rel,LOCKMODE lockmode)12075 ATExecDropOf(Relation rel, LOCKMODE lockmode)
12076 {
12077 	Oid			relid = RelationGetRelid(rel);
12078 	Relation	relationRelation;
12079 	HeapTuple	tuple;
12080 
12081 	if (!OidIsValid(rel->rd_rel->reloftype))
12082 		ereport(ERROR,
12083 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
12084 				 errmsg("\"%s\" is not a typed table",
12085 						RelationGetRelationName(rel))));
12086 
12087 	/*
12088 	 * We don't bother to check ownership of the type --- ownership of the
12089 	 * table is presumed enough rights.  No lock required on the type, either.
12090 	 */
12091 
12092 	drop_parent_dependency(relid, TypeRelationId, rel->rd_rel->reloftype,
12093 						   DEPENDENCY_NORMAL);
12094 
12095 	/* Clear pg_class.reloftype */
12096 	relationRelation = heap_open(RelationRelationId, RowExclusiveLock);
12097 	tuple = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
12098 	if (!HeapTupleIsValid(tuple))
12099 		elog(ERROR, "cache lookup failed for relation %u", relid);
12100 	((Form_pg_class) GETSTRUCT(tuple))->reloftype = InvalidOid;
12101 	CatalogTupleUpdate(relationRelation, &tuple->t_self, tuple);
12102 
12103 	InvokeObjectPostAlterHook(RelationRelationId, relid, 0);
12104 
12105 	heap_freetuple(tuple);
12106 	heap_close(relationRelation, RowExclusiveLock);
12107 }
12108 
12109 /*
12110  * relation_mark_replica_identity: Update a table's replica identity
12111  *
12112  * Iff ri_type = REPLICA_IDENTITY_INDEX, indexOid must be the Oid of a suitable
12113  * index. Otherwise, it should be InvalidOid.
12114  */
12115 static void
relation_mark_replica_identity(Relation rel,char ri_type,Oid indexOid,bool is_internal)12116 relation_mark_replica_identity(Relation rel, char ri_type, Oid indexOid,
12117 							   bool is_internal)
12118 {
12119 	Relation	pg_index;
12120 	Relation	pg_class;
12121 	HeapTuple	pg_class_tuple;
12122 	HeapTuple	pg_index_tuple;
12123 	Form_pg_class pg_class_form;
12124 	Form_pg_index pg_index_form;
12125 
12126 	ListCell   *index;
12127 
12128 	/*
12129 	 * Check whether relreplident has changed, and update it if so.
12130 	 */
12131 	pg_class = heap_open(RelationRelationId, RowExclusiveLock);
12132 	pg_class_tuple = SearchSysCacheCopy1(RELOID,
12133 										 ObjectIdGetDatum(RelationGetRelid(rel)));
12134 	if (!HeapTupleIsValid(pg_class_tuple))
12135 		elog(ERROR, "cache lookup failed for relation \"%s\"",
12136 			 RelationGetRelationName(rel));
12137 	pg_class_form = (Form_pg_class) GETSTRUCT(pg_class_tuple);
12138 	if (pg_class_form->relreplident != ri_type)
12139 	{
12140 		pg_class_form->relreplident = ri_type;
12141 		CatalogTupleUpdate(pg_class, &pg_class_tuple->t_self, pg_class_tuple);
12142 	}
12143 	heap_close(pg_class, RowExclusiveLock);
12144 	heap_freetuple(pg_class_tuple);
12145 
12146 	/*
12147 	 * Check whether the correct index is marked indisreplident; if so, we're
12148 	 * done.
12149 	 */
12150 	if (OidIsValid(indexOid))
12151 	{
12152 		Assert(ri_type == REPLICA_IDENTITY_INDEX);
12153 
12154 		pg_index_tuple = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(indexOid));
12155 		if (!HeapTupleIsValid(pg_index_tuple))
12156 			elog(ERROR, "cache lookup failed for index %u", indexOid);
12157 		pg_index_form = (Form_pg_index) GETSTRUCT(pg_index_tuple);
12158 
12159 		if (pg_index_form->indisreplident)
12160 		{
12161 			ReleaseSysCache(pg_index_tuple);
12162 			return;
12163 		}
12164 		ReleaseSysCache(pg_index_tuple);
12165 	}
12166 
12167 	/*
12168 	 * Clear the indisreplident flag from any index that had it previously,
12169 	 * and set it for any index that should have it now.
12170 	 */
12171 	pg_index = heap_open(IndexRelationId, RowExclusiveLock);
12172 	foreach(index, RelationGetIndexList(rel))
12173 	{
12174 		Oid			thisIndexOid = lfirst_oid(index);
12175 		bool		dirty = false;
12176 
12177 		pg_index_tuple = SearchSysCacheCopy1(INDEXRELID,
12178 											 ObjectIdGetDatum(thisIndexOid));
12179 		if (!HeapTupleIsValid(pg_index_tuple))
12180 			elog(ERROR, "cache lookup failed for index %u", thisIndexOid);
12181 		pg_index_form = (Form_pg_index) GETSTRUCT(pg_index_tuple);
12182 
12183 		/*
12184 		 * Unset the bit if set.  We know it's wrong because we checked this
12185 		 * earlier.
12186 		 */
12187 		if (pg_index_form->indisreplident)
12188 		{
12189 			dirty = true;
12190 			pg_index_form->indisreplident = false;
12191 		}
12192 		else if (thisIndexOid == indexOid)
12193 		{
12194 			dirty = true;
12195 			pg_index_form->indisreplident = true;
12196 		}
12197 
12198 		if (dirty)
12199 		{
12200 			CatalogTupleUpdate(pg_index, &pg_index_tuple->t_self, pg_index_tuple);
12201 			InvokeObjectPostAlterHookArg(IndexRelationId, thisIndexOid, 0,
12202 										 InvalidOid, is_internal);
12203 		}
12204 		heap_freetuple(pg_index_tuple);
12205 	}
12206 
12207 	heap_close(pg_index, RowExclusiveLock);
12208 }
12209 
12210 /*
12211  * ALTER TABLE <name> REPLICA IDENTITY ...
12212  */
12213 static void
ATExecReplicaIdentity(Relation rel,ReplicaIdentityStmt * stmt,LOCKMODE lockmode)12214 ATExecReplicaIdentity(Relation rel, ReplicaIdentityStmt *stmt, LOCKMODE lockmode)
12215 {
12216 	Oid			indexOid;
12217 	Relation	indexRel;
12218 	int			key;
12219 
12220 	if (stmt->identity_type == REPLICA_IDENTITY_DEFAULT)
12221 	{
12222 		relation_mark_replica_identity(rel, stmt->identity_type, InvalidOid, true);
12223 		return;
12224 	}
12225 	else if (stmt->identity_type == REPLICA_IDENTITY_FULL)
12226 	{
12227 		relation_mark_replica_identity(rel, stmt->identity_type, InvalidOid, true);
12228 		return;
12229 	}
12230 	else if (stmt->identity_type == REPLICA_IDENTITY_NOTHING)
12231 	{
12232 		relation_mark_replica_identity(rel, stmt->identity_type, InvalidOid, true);
12233 		return;
12234 	}
12235 	else if (stmt->identity_type == REPLICA_IDENTITY_INDEX)
12236 	{
12237 		 /* fallthrough */ ;
12238 	}
12239 	else
12240 		elog(ERROR, "unexpected identity type %u", stmt->identity_type);
12241 
12242 
12243 	/* Check that the index exists */
12244 	indexOid = get_relname_relid(stmt->name, rel->rd_rel->relnamespace);
12245 	if (!OidIsValid(indexOid))
12246 		ereport(ERROR,
12247 				(errcode(ERRCODE_UNDEFINED_OBJECT),
12248 				 errmsg("index \"%s\" for table \"%s\" does not exist",
12249 						stmt->name, RelationGetRelationName(rel))));
12250 
12251 	indexRel = index_open(indexOid, ShareLock);
12252 
12253 	/* Check that the index is on the relation we're altering. */
12254 	if (indexRel->rd_index == NULL ||
12255 		indexRel->rd_index->indrelid != RelationGetRelid(rel))
12256 		ereport(ERROR,
12257 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
12258 				 errmsg("\"%s\" is not an index for table \"%s\"",
12259 						RelationGetRelationName(indexRel),
12260 						RelationGetRelationName(rel))));
12261 	/* The AM must support uniqueness, and the index must in fact be unique. */
12262 	if (!indexRel->rd_amroutine->amcanunique ||
12263 		!indexRel->rd_index->indisunique)
12264 		ereport(ERROR,
12265 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
12266 				 errmsg("cannot use non-unique index \"%s\" as replica identity",
12267 						RelationGetRelationName(indexRel))));
12268 	/* Deferred indexes are not guaranteed to be always unique. */
12269 	if (!indexRel->rd_index->indimmediate)
12270 		ereport(ERROR,
12271 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
12272 				 errmsg("cannot use non-immediate index \"%s\" as replica identity",
12273 						RelationGetRelationName(indexRel))));
12274 	/* Expression indexes aren't supported. */
12275 	if (RelationGetIndexExpressions(indexRel) != NIL)
12276 		ereport(ERROR,
12277 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
12278 				 errmsg("cannot use expression index \"%s\" as replica identity",
12279 						RelationGetRelationName(indexRel))));
12280 	/* Predicate indexes aren't supported. */
12281 	if (RelationGetIndexPredicate(indexRel) != NIL)
12282 		ereport(ERROR,
12283 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
12284 				 errmsg("cannot use partial index \"%s\" as replica identity",
12285 						RelationGetRelationName(indexRel))));
12286 	/* And neither are invalid indexes. */
12287 	if (!IndexIsValid(indexRel->rd_index))
12288 		ereport(ERROR,
12289 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
12290 				 errmsg("cannot use invalid index \"%s\" as replica identity",
12291 						RelationGetRelationName(indexRel))));
12292 
12293 	/* Check index for nullable columns. */
12294 	for (key = 0; key < indexRel->rd_index->indnatts; key++)
12295 	{
12296 		int16		attno = indexRel->rd_index->indkey.values[key];
12297 		Form_pg_attribute attr;
12298 
12299 		/* Allow OID column to be indexed; it's certainly not nullable */
12300 		if (attno == ObjectIdAttributeNumber)
12301 			continue;
12302 
12303 		/*
12304 		 * Reject any other system columns.  (Going forward, we'll disallow
12305 		 * indexes containing such columns in the first place, but they might
12306 		 * exist in older branches.)
12307 		 */
12308 		if (attno <= 0)
12309 			ereport(ERROR,
12310 					(errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
12311 					 errmsg("index \"%s\" cannot be used as replica identity because column %d is a system column",
12312 							RelationGetRelationName(indexRel), attno)));
12313 
12314 		attr = rel->rd_att->attrs[attno - 1];
12315 		if (!attr->attnotnull)
12316 			ereport(ERROR,
12317 					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
12318 					 errmsg("index \"%s\" cannot be used as replica identity because column \"%s\" is nullable",
12319 							RelationGetRelationName(indexRel),
12320 							NameStr(attr->attname))));
12321 	}
12322 
12323 	/* This index is suitable for use as a replica identity. Mark it. */
12324 	relation_mark_replica_identity(rel, stmt->identity_type, indexOid, true);
12325 
12326 	index_close(indexRel, NoLock);
12327 }
12328 
12329 /*
12330  * ALTER TABLE ENABLE/DISABLE ROW LEVEL SECURITY
12331  */
12332 static void
ATExecEnableRowSecurity(Relation rel)12333 ATExecEnableRowSecurity(Relation rel)
12334 {
12335 	Relation	pg_class;
12336 	Oid			relid;
12337 	HeapTuple	tuple;
12338 
12339 	relid = RelationGetRelid(rel);
12340 
12341 	pg_class = heap_open(RelationRelationId, RowExclusiveLock);
12342 
12343 	tuple = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
12344 
12345 	if (!HeapTupleIsValid(tuple))
12346 		elog(ERROR, "cache lookup failed for relation %u", relid);
12347 
12348 	((Form_pg_class) GETSTRUCT(tuple))->relrowsecurity = true;
12349 	CatalogTupleUpdate(pg_class, &tuple->t_self, tuple);
12350 
12351 	heap_close(pg_class, RowExclusiveLock);
12352 	heap_freetuple(tuple);
12353 }
12354 
12355 static void
ATExecDisableRowSecurity(Relation rel)12356 ATExecDisableRowSecurity(Relation rel)
12357 {
12358 	Relation	pg_class;
12359 	Oid			relid;
12360 	HeapTuple	tuple;
12361 
12362 	relid = RelationGetRelid(rel);
12363 
12364 	/* Pull the record for this relation and update it */
12365 	pg_class = heap_open(RelationRelationId, RowExclusiveLock);
12366 
12367 	tuple = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
12368 
12369 	if (!HeapTupleIsValid(tuple))
12370 		elog(ERROR, "cache lookup failed for relation %u", relid);
12371 
12372 	((Form_pg_class) GETSTRUCT(tuple))->relrowsecurity = false;
12373 	CatalogTupleUpdate(pg_class, &tuple->t_self, tuple);
12374 
12375 	heap_close(pg_class, RowExclusiveLock);
12376 	heap_freetuple(tuple);
12377 }
12378 
12379 /*
12380  * ALTER TABLE FORCE/NO FORCE ROW LEVEL SECURITY
12381  */
12382 static void
ATExecForceNoForceRowSecurity(Relation rel,bool force_rls)12383 ATExecForceNoForceRowSecurity(Relation rel, bool force_rls)
12384 {
12385 	Relation	pg_class;
12386 	Oid			relid;
12387 	HeapTuple	tuple;
12388 
12389 	relid = RelationGetRelid(rel);
12390 
12391 	pg_class = heap_open(RelationRelationId, RowExclusiveLock);
12392 
12393 	tuple = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
12394 
12395 	if (!HeapTupleIsValid(tuple))
12396 		elog(ERROR, "cache lookup failed for relation %u", relid);
12397 
12398 	((Form_pg_class) GETSTRUCT(tuple))->relforcerowsecurity = force_rls;
12399 	CatalogTupleUpdate(pg_class, &tuple->t_self, tuple);
12400 
12401 	heap_close(pg_class, RowExclusiveLock);
12402 	heap_freetuple(tuple);
12403 }
12404 
12405 /*
12406  * ALTER FOREIGN TABLE <name> OPTIONS (...)
12407  */
12408 static void
ATExecGenericOptions(Relation rel,List * options)12409 ATExecGenericOptions(Relation rel, List *options)
12410 {
12411 	Relation	ftrel;
12412 	ForeignServer *server;
12413 	ForeignDataWrapper *fdw;
12414 	HeapTuple	tuple;
12415 	bool		isnull;
12416 	Datum		repl_val[Natts_pg_foreign_table];
12417 	bool		repl_null[Natts_pg_foreign_table];
12418 	bool		repl_repl[Natts_pg_foreign_table];
12419 	Datum		datum;
12420 	Form_pg_foreign_table tableform;
12421 
12422 	if (options == NIL)
12423 		return;
12424 
12425 	ftrel = heap_open(ForeignTableRelationId, RowExclusiveLock);
12426 
12427 	tuple = SearchSysCacheCopy1(FOREIGNTABLEREL, rel->rd_id);
12428 	if (!HeapTupleIsValid(tuple))
12429 		ereport(ERROR,
12430 				(errcode(ERRCODE_UNDEFINED_OBJECT),
12431 				 errmsg("foreign table \"%s\" does not exist",
12432 						RelationGetRelationName(rel))));
12433 	tableform = (Form_pg_foreign_table) GETSTRUCT(tuple);
12434 	server = GetForeignServer(tableform->ftserver);
12435 	fdw = GetForeignDataWrapper(server->fdwid);
12436 
12437 	memset(repl_val, 0, sizeof(repl_val));
12438 	memset(repl_null, false, sizeof(repl_null));
12439 	memset(repl_repl, false, sizeof(repl_repl));
12440 
12441 	/* Extract the current options */
12442 	datum = SysCacheGetAttr(FOREIGNTABLEREL,
12443 							tuple,
12444 							Anum_pg_foreign_table_ftoptions,
12445 							&isnull);
12446 	if (isnull)
12447 		datum = PointerGetDatum(NULL);
12448 
12449 	/* Transform the options */
12450 	datum = transformGenericOptions(ForeignTableRelationId,
12451 									datum,
12452 									options,
12453 									fdw->fdwvalidator);
12454 
12455 	if (PointerIsValid(DatumGetPointer(datum)))
12456 		repl_val[Anum_pg_foreign_table_ftoptions - 1] = datum;
12457 	else
12458 		repl_null[Anum_pg_foreign_table_ftoptions - 1] = true;
12459 
12460 	repl_repl[Anum_pg_foreign_table_ftoptions - 1] = true;
12461 
12462 	/* Everything looks good - update the tuple */
12463 
12464 	tuple = heap_modify_tuple(tuple, RelationGetDescr(ftrel),
12465 							  repl_val, repl_null, repl_repl);
12466 
12467 	CatalogTupleUpdate(ftrel, &tuple->t_self, tuple);
12468 
12469 	/*
12470 	 * Invalidate relcache so that all sessions will refresh any cached plans
12471 	 * that might depend on the old options.
12472 	 */
12473 	CacheInvalidateRelcache(rel);
12474 
12475 	InvokeObjectPostAlterHook(ForeignTableRelationId,
12476 							  RelationGetRelid(rel), 0);
12477 
12478 	heap_close(ftrel, RowExclusiveLock);
12479 
12480 	heap_freetuple(tuple);
12481 }
12482 
12483 /*
12484  * Preparation phase for SET LOGGED/UNLOGGED
12485  *
12486  * This verifies that we're not trying to change a temp table.  Also,
12487  * existing foreign key constraints are checked to avoid ending up with
12488  * permanent tables referencing unlogged tables.
12489  *
12490  * Return value is false if the operation is a no-op (in which case the
12491  * checks are skipped), otherwise true.
12492  */
12493 static bool
ATPrepChangePersistence(Relation rel,bool toLogged)12494 ATPrepChangePersistence(Relation rel, bool toLogged)
12495 {
12496 	Relation	pg_constraint;
12497 	HeapTuple	tuple;
12498 	SysScanDesc scan;
12499 	ScanKeyData skey[1];
12500 
12501 	/*
12502 	 * Disallow changing status for a temp table.  Also verify whether we can
12503 	 * get away with doing nothing; in such cases we don't need to run the
12504 	 * checks below, either.
12505 	 */
12506 	switch (rel->rd_rel->relpersistence)
12507 	{
12508 		case RELPERSISTENCE_TEMP:
12509 			ereport(ERROR,
12510 					(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
12511 					 errmsg("cannot change logged status of table \"%s\" because it is temporary",
12512 							RelationGetRelationName(rel)),
12513 					 errtable(rel)));
12514 			break;
12515 		case RELPERSISTENCE_PERMANENT:
12516 			if (toLogged)
12517 				/* nothing to do */
12518 				return false;
12519 			break;
12520 		case RELPERSISTENCE_UNLOGGED:
12521 			if (!toLogged)
12522 				/* nothing to do */
12523 				return false;
12524 			break;
12525 	}
12526 
12527 	/*
12528 	 * Check that the table is not part any publication when changing to
12529 	 * UNLOGGED as UNLOGGED tables can't be published.
12530 	 */
12531 	if (!toLogged &&
12532 		list_length(GetRelationPublications(RelationGetRelid(rel))) > 0)
12533 		ereport(ERROR,
12534 				(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
12535 				 errmsg("cannot change table \"%s\" to unlogged because it is part of a publication",
12536 						RelationGetRelationName(rel)),
12537 				 errdetail("Unlogged relations cannot be replicated.")));
12538 
12539 	/*
12540 	 * Check existing foreign key constraints to preserve the invariant that
12541 	 * permanent tables cannot reference unlogged ones.  Self-referencing
12542 	 * foreign keys can safely be ignored.
12543 	 */
12544 	pg_constraint = heap_open(ConstraintRelationId, AccessShareLock);
12545 
12546 	/*
12547 	 * Scan conrelid if changing to permanent, else confrelid.  This also
12548 	 * determines whether a useful index exists.
12549 	 */
12550 	ScanKeyInit(&skey[0],
12551 				toLogged ? Anum_pg_constraint_conrelid :
12552 				Anum_pg_constraint_confrelid,
12553 				BTEqualStrategyNumber, F_OIDEQ,
12554 				ObjectIdGetDatum(RelationGetRelid(rel)));
12555 	scan = systable_beginscan(pg_constraint,
12556 							  toLogged ? ConstraintRelidIndexId : InvalidOid,
12557 							  true, NULL, 1, skey);
12558 
12559 	while (HeapTupleIsValid(tuple = systable_getnext(scan)))
12560 	{
12561 		Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(tuple);
12562 
12563 		if (con->contype == CONSTRAINT_FOREIGN)
12564 		{
12565 			Oid			foreignrelid;
12566 			Relation	foreignrel;
12567 
12568 			/* the opposite end of what we used as scankey */
12569 			foreignrelid = toLogged ? con->confrelid : con->conrelid;
12570 
12571 			/* ignore if self-referencing */
12572 			if (RelationGetRelid(rel) == foreignrelid)
12573 				continue;
12574 
12575 			foreignrel = relation_open(foreignrelid, AccessShareLock);
12576 
12577 			if (toLogged)
12578 			{
12579 				if (foreignrel->rd_rel->relpersistence != RELPERSISTENCE_PERMANENT)
12580 					ereport(ERROR,
12581 							(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
12582 							 errmsg("could not change table \"%s\" to logged because it references unlogged table \"%s\"",
12583 									RelationGetRelationName(rel),
12584 									RelationGetRelationName(foreignrel)),
12585 							 errtableconstraint(rel, NameStr(con->conname))));
12586 			}
12587 			else
12588 			{
12589 				if (foreignrel->rd_rel->relpersistence == RELPERSISTENCE_PERMANENT)
12590 					ereport(ERROR,
12591 							(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
12592 							 errmsg("could not change table \"%s\" to unlogged because it references logged table \"%s\"",
12593 									RelationGetRelationName(rel),
12594 									RelationGetRelationName(foreignrel)),
12595 							 errtableconstraint(rel, NameStr(con->conname))));
12596 			}
12597 
12598 			relation_close(foreignrel, AccessShareLock);
12599 		}
12600 	}
12601 
12602 	systable_endscan(scan);
12603 
12604 	heap_close(pg_constraint, AccessShareLock);
12605 
12606 	return true;
12607 }
12608 
12609 /*
12610  * Execute ALTER TABLE SET SCHEMA
12611  */
12612 ObjectAddress
AlterTableNamespace(AlterObjectSchemaStmt * stmt,Oid * oldschema)12613 AlterTableNamespace(AlterObjectSchemaStmt *stmt, Oid *oldschema)
12614 {
12615 	Relation	rel;
12616 	Oid			relid;
12617 	Oid			oldNspOid;
12618 	Oid			nspOid;
12619 	RangeVar   *newrv;
12620 	ObjectAddresses *objsMoved;
12621 	ObjectAddress myself;
12622 
12623 	relid = RangeVarGetRelidExtended(stmt->relation, AccessExclusiveLock,
12624 									 stmt->missing_ok, false,
12625 									 RangeVarCallbackForAlterRelation,
12626 									 (void *) stmt);
12627 
12628 	if (!OidIsValid(relid))
12629 	{
12630 		ereport(NOTICE,
12631 				(errmsg("relation \"%s\" does not exist, skipping",
12632 						stmt->relation->relname)));
12633 		return InvalidObjectAddress;
12634 	}
12635 
12636 	rel = relation_open(relid, NoLock);
12637 
12638 	oldNspOid = RelationGetNamespace(rel);
12639 
12640 	/* If it's an owned sequence, disallow moving it by itself. */
12641 	if (rel->rd_rel->relkind == RELKIND_SEQUENCE)
12642 	{
12643 		Oid			tableId;
12644 		int32		colId;
12645 
12646 		if (sequenceIsOwned(relid, DEPENDENCY_AUTO, &tableId, &colId) ||
12647 			sequenceIsOwned(relid, DEPENDENCY_INTERNAL, &tableId, &colId))
12648 			ereport(ERROR,
12649 					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
12650 					 errmsg("cannot move an owned sequence into another schema"),
12651 					 errdetail("Sequence \"%s\" is linked to table \"%s\".",
12652 							   RelationGetRelationName(rel),
12653 							   get_rel_name(tableId))));
12654 	}
12655 
12656 	/* Get and lock schema OID and check its permissions. */
12657 	newrv = makeRangeVar(stmt->newschema, RelationGetRelationName(rel), -1);
12658 	nspOid = RangeVarGetAndCheckCreationNamespace(newrv, NoLock, NULL);
12659 
12660 	/* common checks on switching namespaces */
12661 	CheckSetNamespace(oldNspOid, nspOid);
12662 
12663 	objsMoved = new_object_addresses();
12664 	AlterTableNamespaceInternal(rel, oldNspOid, nspOid, objsMoved);
12665 	free_object_addresses(objsMoved);
12666 
12667 	ObjectAddressSet(myself, RelationRelationId, relid);
12668 
12669 	if (oldschema)
12670 		*oldschema = oldNspOid;
12671 
12672 	/* close rel, but keep lock until commit */
12673 	relation_close(rel, NoLock);
12674 
12675 	return myself;
12676 }
12677 
12678 /*
12679  * The guts of relocating a table or materialized view to another namespace:
12680  * besides moving the relation itself, its dependent objects are relocated to
12681  * the new schema.
12682  */
12683 void
AlterTableNamespaceInternal(Relation rel,Oid oldNspOid,Oid nspOid,ObjectAddresses * objsMoved)12684 AlterTableNamespaceInternal(Relation rel, Oid oldNspOid, Oid nspOid,
12685 							ObjectAddresses *objsMoved)
12686 {
12687 	Relation	classRel;
12688 
12689 	Assert(objsMoved != NULL);
12690 
12691 	/* OK, modify the pg_class row and pg_depend entry */
12692 	classRel = heap_open(RelationRelationId, RowExclusiveLock);
12693 
12694 	AlterRelationNamespaceInternal(classRel, RelationGetRelid(rel), oldNspOid,
12695 								   nspOid, true, objsMoved);
12696 
12697 	/* Fix the table's row type too */
12698 	AlterTypeNamespaceInternal(rel->rd_rel->reltype,
12699 							   nspOid, false, false, objsMoved);
12700 
12701 	/* Fix other dependent stuff */
12702 	if (rel->rd_rel->relkind == RELKIND_RELATION ||
12703 		rel->rd_rel->relkind == RELKIND_MATVIEW ||
12704 		rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
12705 	{
12706 		AlterIndexNamespaces(classRel, rel, oldNspOid, nspOid, objsMoved);
12707 		AlterSeqNamespaces(classRel, rel, oldNspOid, nspOid,
12708 						   objsMoved, AccessExclusiveLock);
12709 		AlterConstraintNamespaces(RelationGetRelid(rel), oldNspOid, nspOid,
12710 								  false, objsMoved);
12711 	}
12712 
12713 	heap_close(classRel, RowExclusiveLock);
12714 }
12715 
12716 /*
12717  * The guts of relocating a relation to another namespace: fix the pg_class
12718  * entry, and the pg_depend entry if any.  Caller must already have
12719  * opened and write-locked pg_class.
12720  */
12721 void
AlterRelationNamespaceInternal(Relation classRel,Oid relOid,Oid oldNspOid,Oid newNspOid,bool hasDependEntry,ObjectAddresses * objsMoved)12722 AlterRelationNamespaceInternal(Relation classRel, Oid relOid,
12723 							   Oid oldNspOid, Oid newNspOid,
12724 							   bool hasDependEntry,
12725 							   ObjectAddresses *objsMoved)
12726 {
12727 	HeapTuple	classTup;
12728 	Form_pg_class classForm;
12729 	ObjectAddress thisobj;
12730 	bool		already_done = false;
12731 
12732 	classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relOid));
12733 	if (!HeapTupleIsValid(classTup))
12734 		elog(ERROR, "cache lookup failed for relation %u", relOid);
12735 	classForm = (Form_pg_class) GETSTRUCT(classTup);
12736 
12737 	Assert(classForm->relnamespace == oldNspOid);
12738 
12739 	thisobj.classId = RelationRelationId;
12740 	thisobj.objectId = relOid;
12741 	thisobj.objectSubId = 0;
12742 
12743 	/*
12744 	 * If the object has already been moved, don't move it again.  If it's
12745 	 * already in the right place, don't move it, but still fire the object
12746 	 * access hook.
12747 	 */
12748 	already_done = object_address_present(&thisobj, objsMoved);
12749 	if (!already_done && oldNspOid != newNspOid)
12750 	{
12751 		/* check for duplicate name (more friendly than unique-index failure) */
12752 		if (get_relname_relid(NameStr(classForm->relname),
12753 							  newNspOid) != InvalidOid)
12754 			ereport(ERROR,
12755 					(errcode(ERRCODE_DUPLICATE_TABLE),
12756 					 errmsg("relation \"%s\" already exists in schema \"%s\"",
12757 							NameStr(classForm->relname),
12758 							get_namespace_name(newNspOid))));
12759 
12760 		/* classTup is a copy, so OK to scribble on */
12761 		classForm->relnamespace = newNspOid;
12762 
12763 		CatalogTupleUpdate(classRel, &classTup->t_self, classTup);
12764 
12765 		/* Update dependency on schema if caller said so */
12766 		if (hasDependEntry &&
12767 			changeDependencyFor(RelationRelationId,
12768 								relOid,
12769 								NamespaceRelationId,
12770 								oldNspOid,
12771 								newNspOid) != 1)
12772 			elog(ERROR, "failed to change schema dependency for relation \"%s\"",
12773 				 NameStr(classForm->relname));
12774 	}
12775 	if (!already_done)
12776 	{
12777 		add_exact_object_address(&thisobj, objsMoved);
12778 
12779 		InvokeObjectPostAlterHook(RelationRelationId, relOid, 0);
12780 	}
12781 
12782 	heap_freetuple(classTup);
12783 }
12784 
12785 /*
12786  * Move all indexes for the specified relation to another namespace.
12787  *
12788  * Note: we assume adequate permission checking was done by the caller,
12789  * and that the caller has a suitable lock on the owning relation.
12790  */
12791 static void
AlterIndexNamespaces(Relation classRel,Relation rel,Oid oldNspOid,Oid newNspOid,ObjectAddresses * objsMoved)12792 AlterIndexNamespaces(Relation classRel, Relation rel,
12793 					 Oid oldNspOid, Oid newNspOid, ObjectAddresses *objsMoved)
12794 {
12795 	List	   *indexList;
12796 	ListCell   *l;
12797 
12798 	indexList = RelationGetIndexList(rel);
12799 
12800 	foreach(l, indexList)
12801 	{
12802 		Oid			indexOid = lfirst_oid(l);
12803 		ObjectAddress thisobj;
12804 
12805 		thisobj.classId = RelationRelationId;
12806 		thisobj.objectId = indexOid;
12807 		thisobj.objectSubId = 0;
12808 
12809 		/*
12810 		 * Note: currently, the index will not have its own dependency on the
12811 		 * namespace, so we don't need to do changeDependencyFor(). There's no
12812 		 * row type in pg_type, either.
12813 		 *
12814 		 * XXX this objsMoved test may be pointless -- surely we have a single
12815 		 * dependency link from a relation to each index?
12816 		 */
12817 		if (!object_address_present(&thisobj, objsMoved))
12818 		{
12819 			AlterRelationNamespaceInternal(classRel, indexOid,
12820 										   oldNspOid, newNspOid,
12821 										   false, objsMoved);
12822 			add_exact_object_address(&thisobj, objsMoved);
12823 		}
12824 	}
12825 
12826 	list_free(indexList);
12827 }
12828 
12829 /*
12830  * Move all identity and SERIAL-column sequences of the specified relation to another
12831  * namespace.
12832  *
12833  * Note: we assume adequate permission checking was done by the caller,
12834  * and that the caller has a suitable lock on the owning relation.
12835  */
12836 static void
AlterSeqNamespaces(Relation classRel,Relation rel,Oid oldNspOid,Oid newNspOid,ObjectAddresses * objsMoved,LOCKMODE lockmode)12837 AlterSeqNamespaces(Relation classRel, Relation rel,
12838 				   Oid oldNspOid, Oid newNspOid, ObjectAddresses *objsMoved,
12839 				   LOCKMODE lockmode)
12840 {
12841 	Relation	depRel;
12842 	SysScanDesc scan;
12843 	ScanKeyData key[2];
12844 	HeapTuple	tup;
12845 
12846 	/*
12847 	 * SERIAL sequences are those having an auto dependency on one of the
12848 	 * table's columns (we don't care *which* column, exactly).
12849 	 */
12850 	depRel = heap_open(DependRelationId, AccessShareLock);
12851 
12852 	ScanKeyInit(&key[0],
12853 				Anum_pg_depend_refclassid,
12854 				BTEqualStrategyNumber, F_OIDEQ,
12855 				ObjectIdGetDatum(RelationRelationId));
12856 	ScanKeyInit(&key[1],
12857 				Anum_pg_depend_refobjid,
12858 				BTEqualStrategyNumber, F_OIDEQ,
12859 				ObjectIdGetDatum(RelationGetRelid(rel)));
12860 	/* we leave refobjsubid unspecified */
12861 
12862 	scan = systable_beginscan(depRel, DependReferenceIndexId, true,
12863 							  NULL, 2, key);
12864 
12865 	while (HeapTupleIsValid(tup = systable_getnext(scan)))
12866 	{
12867 		Form_pg_depend depForm = (Form_pg_depend) GETSTRUCT(tup);
12868 		Relation	seqRel;
12869 
12870 		/* skip dependencies other than auto dependencies on columns */
12871 		if (depForm->refobjsubid == 0 ||
12872 			depForm->classid != RelationRelationId ||
12873 			depForm->objsubid != 0 ||
12874 			!(depForm->deptype == DEPENDENCY_AUTO || depForm->deptype == DEPENDENCY_INTERNAL))
12875 			continue;
12876 
12877 		/* Use relation_open just in case it's an index */
12878 		seqRel = relation_open(depForm->objid, lockmode);
12879 
12880 		/* skip non-sequence relations */
12881 		if (RelationGetForm(seqRel)->relkind != RELKIND_SEQUENCE)
12882 		{
12883 			/* No need to keep the lock */
12884 			relation_close(seqRel, lockmode);
12885 			continue;
12886 		}
12887 
12888 		/* Fix the pg_class and pg_depend entries */
12889 		AlterRelationNamespaceInternal(classRel, depForm->objid,
12890 									   oldNspOid, newNspOid,
12891 									   true, objsMoved);
12892 
12893 		/*
12894 		 * Sequences have entries in pg_type. We need to be careful to move
12895 		 * them to the new namespace, too.
12896 		 */
12897 		AlterTypeNamespaceInternal(RelationGetForm(seqRel)->reltype,
12898 								   newNspOid, false, false, objsMoved);
12899 
12900 		/* Now we can close it.  Keep the lock till end of transaction. */
12901 		relation_close(seqRel, NoLock);
12902 	}
12903 
12904 	systable_endscan(scan);
12905 
12906 	relation_close(depRel, AccessShareLock);
12907 }
12908 
12909 
12910 /*
12911  * This code supports
12912  *	CREATE TEMP TABLE ... ON COMMIT { DROP | PRESERVE ROWS | DELETE ROWS }
12913  *
12914  * Because we only support this for TEMP tables, it's sufficient to remember
12915  * the state in a backend-local data structure.
12916  */
12917 
12918 /*
12919  * Register a newly-created relation's ON COMMIT action.
12920  */
12921 void
register_on_commit_action(Oid relid,OnCommitAction action)12922 register_on_commit_action(Oid relid, OnCommitAction action)
12923 {
12924 	OnCommitItem *oc;
12925 	MemoryContext oldcxt;
12926 
12927 	/*
12928 	 * We needn't bother registering the relation unless there is an ON COMMIT
12929 	 * action we need to take.
12930 	 */
12931 	if (action == ONCOMMIT_NOOP || action == ONCOMMIT_PRESERVE_ROWS)
12932 		return;
12933 
12934 	oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
12935 
12936 	oc = (OnCommitItem *) palloc(sizeof(OnCommitItem));
12937 	oc->relid = relid;
12938 	oc->oncommit = action;
12939 	oc->creating_subid = GetCurrentSubTransactionId();
12940 	oc->deleting_subid = InvalidSubTransactionId;
12941 
12942 	on_commits = lcons(oc, on_commits);
12943 
12944 	MemoryContextSwitchTo(oldcxt);
12945 }
12946 
12947 /*
12948  * Unregister any ON COMMIT action when a relation is deleted.
12949  *
12950  * Actually, we only mark the OnCommitItem entry as to be deleted after commit.
12951  */
12952 void
remove_on_commit_action(Oid relid)12953 remove_on_commit_action(Oid relid)
12954 {
12955 	ListCell   *l;
12956 
12957 	foreach(l, on_commits)
12958 	{
12959 		OnCommitItem *oc = (OnCommitItem *) lfirst(l);
12960 
12961 		if (oc->relid == relid)
12962 		{
12963 			oc->deleting_subid = GetCurrentSubTransactionId();
12964 			break;
12965 		}
12966 	}
12967 }
12968 
12969 /*
12970  * Perform ON COMMIT actions.
12971  *
12972  * This is invoked just before actually committing, since it's possible
12973  * to encounter errors.
12974  */
12975 void
PreCommit_on_commit_actions(void)12976 PreCommit_on_commit_actions(void)
12977 {
12978 	ListCell   *l;
12979 	List	   *oids_to_truncate = NIL;
12980 	List	   *oids_to_drop = NIL;
12981 
12982 	foreach(l, on_commits)
12983 	{
12984 		OnCommitItem *oc = (OnCommitItem *) lfirst(l);
12985 
12986 		/* Ignore entry if already dropped in this xact */
12987 		if (oc->deleting_subid != InvalidSubTransactionId)
12988 			continue;
12989 
12990 		switch (oc->oncommit)
12991 		{
12992 			case ONCOMMIT_NOOP:
12993 			case ONCOMMIT_PRESERVE_ROWS:
12994 				/* Do nothing (there shouldn't be such entries, actually) */
12995 				break;
12996 			case ONCOMMIT_DELETE_ROWS:
12997 
12998 				/*
12999 				 * If this transaction hasn't accessed any temporary
13000 				 * relations, we can skip truncating ON COMMIT DELETE ROWS
13001 				 * tables, as they must still be empty.
13002 				 */
13003 				if ((MyXactFlags & XACT_FLAGS_ACCESSEDTEMPREL))
13004 					oids_to_truncate = lappend_oid(oids_to_truncate, oc->relid);
13005 				break;
13006 			case ONCOMMIT_DROP:
13007 				oids_to_drop = lappend_oid(oids_to_drop, oc->relid);
13008 				break;
13009 		}
13010 	}
13011 
13012 	/*
13013 	 * Truncate relations before dropping so that all dependencies between
13014 	 * relations are removed after they are worked on.  Doing it like this
13015 	 * might be a waste as it is possible that a relation being truncated will
13016 	 * be dropped anyway due to its parent being dropped, but this makes the
13017 	 * code more robust because of not having to re-check that the relation
13018 	 * exists at truncation time.
13019 	 */
13020 	if (oids_to_truncate != NIL)
13021 	{
13022 		heap_truncate(oids_to_truncate);
13023 		CommandCounterIncrement();	/* XXX needed? */
13024 	}
13025 	if (oids_to_drop != NIL)
13026 	{
13027 		ObjectAddresses *targetObjects = new_object_addresses();
13028 		ListCell   *l;
13029 
13030 		foreach(l, oids_to_drop)
13031 		{
13032 			ObjectAddress object;
13033 
13034 			object.classId = RelationRelationId;
13035 			object.objectId = lfirst_oid(l);
13036 			object.objectSubId = 0;
13037 
13038 			Assert(!object_address_present(&object, targetObjects));
13039 
13040 			add_exact_object_address(&object, targetObjects);
13041 		}
13042 
13043 		/*
13044 		 * Since this is an automatic drop, rather than one directly initiated
13045 		 * by the user, we pass the PERFORM_DELETION_INTERNAL flag.
13046 		 */
13047 		performMultipleDeletions(targetObjects, DROP_CASCADE,
13048 								 PERFORM_DELETION_INTERNAL | PERFORM_DELETION_QUIETLY);
13049 
13050 #ifdef USE_ASSERT_CHECKING
13051 
13052 		/*
13053 		 * Note that table deletion will call remove_on_commit_action, so the
13054 		 * entry should get marked as deleted.
13055 		 */
13056 		foreach(l, on_commits)
13057 		{
13058 			OnCommitItem *oc = (OnCommitItem *) lfirst(l);
13059 
13060 			if (oc->oncommit != ONCOMMIT_DROP)
13061 				continue;
13062 
13063 			Assert(oc->deleting_subid != InvalidSubTransactionId);
13064 		}
13065 #endif
13066 	}
13067 }
13068 
13069 /*
13070  * Post-commit or post-abort cleanup for ON COMMIT management.
13071  *
13072  * All we do here is remove no-longer-needed OnCommitItem entries.
13073  *
13074  * During commit, remove entries that were deleted during this transaction;
13075  * during abort, remove those created during this transaction.
13076  */
13077 void
AtEOXact_on_commit_actions(bool isCommit)13078 AtEOXact_on_commit_actions(bool isCommit)
13079 {
13080 	ListCell   *cur_item;
13081 	ListCell   *prev_item;
13082 
13083 	prev_item = NULL;
13084 	cur_item = list_head(on_commits);
13085 
13086 	while (cur_item != NULL)
13087 	{
13088 		OnCommitItem *oc = (OnCommitItem *) lfirst(cur_item);
13089 
13090 		if (isCommit ? oc->deleting_subid != InvalidSubTransactionId :
13091 			oc->creating_subid != InvalidSubTransactionId)
13092 		{
13093 			/* cur_item must be removed */
13094 			on_commits = list_delete_cell(on_commits, cur_item, prev_item);
13095 			pfree(oc);
13096 			if (prev_item)
13097 				cur_item = lnext(prev_item);
13098 			else
13099 				cur_item = list_head(on_commits);
13100 		}
13101 		else
13102 		{
13103 			/* cur_item must be preserved */
13104 			oc->creating_subid = InvalidSubTransactionId;
13105 			oc->deleting_subid = InvalidSubTransactionId;
13106 			prev_item = cur_item;
13107 			cur_item = lnext(prev_item);
13108 		}
13109 	}
13110 }
13111 
13112 /*
13113  * Post-subcommit or post-subabort cleanup for ON COMMIT management.
13114  *
13115  * During subabort, we can immediately remove entries created during this
13116  * subtransaction.  During subcommit, just relabel entries marked during
13117  * this subtransaction as being the parent's responsibility.
13118  */
13119 void
AtEOSubXact_on_commit_actions(bool isCommit,SubTransactionId mySubid,SubTransactionId parentSubid)13120 AtEOSubXact_on_commit_actions(bool isCommit, SubTransactionId mySubid,
13121 							  SubTransactionId parentSubid)
13122 {
13123 	ListCell   *cur_item;
13124 	ListCell   *prev_item;
13125 
13126 	prev_item = NULL;
13127 	cur_item = list_head(on_commits);
13128 
13129 	while (cur_item != NULL)
13130 	{
13131 		OnCommitItem *oc = (OnCommitItem *) lfirst(cur_item);
13132 
13133 		if (!isCommit && oc->creating_subid == mySubid)
13134 		{
13135 			/* cur_item must be removed */
13136 			on_commits = list_delete_cell(on_commits, cur_item, prev_item);
13137 			pfree(oc);
13138 			if (prev_item)
13139 				cur_item = lnext(prev_item);
13140 			else
13141 				cur_item = list_head(on_commits);
13142 		}
13143 		else
13144 		{
13145 			/* cur_item must be preserved */
13146 			if (oc->creating_subid == mySubid)
13147 				oc->creating_subid = parentSubid;
13148 			if (oc->deleting_subid == mySubid)
13149 				oc->deleting_subid = isCommit ? parentSubid : InvalidSubTransactionId;
13150 			prev_item = cur_item;
13151 			cur_item = lnext(prev_item);
13152 		}
13153 	}
13154 }
13155 
13156 /*
13157  * This is intended as a callback for RangeVarGetRelidExtended().  It allows
13158  * the relation to be locked only if (1) it's a plain table, materialized
13159  * view, or TOAST table and (2) the current user is the owner (or the
13160  * superuser).  This meets the permission-checking needs of CLUSTER, REINDEX
13161  * TABLE, and REFRESH MATERIALIZED VIEW; we expose it here so that it can be
13162  * used by all.
13163  */
13164 void
RangeVarCallbackOwnsTable(const RangeVar * relation,Oid relId,Oid oldRelId,void * arg)13165 RangeVarCallbackOwnsTable(const RangeVar *relation,
13166 						  Oid relId, Oid oldRelId, void *arg)
13167 {
13168 	char		relkind;
13169 
13170 	/* Nothing to do if the relation was not found. */
13171 	if (!OidIsValid(relId))
13172 		return;
13173 
13174 	/*
13175 	 * If the relation does exist, check whether it's an index.  But note that
13176 	 * the relation might have been dropped between the time we did the name
13177 	 * lookup and now.  In that case, there's nothing to do.
13178 	 */
13179 	relkind = get_rel_relkind(relId);
13180 	if (!relkind)
13181 		return;
13182 	if (relkind != RELKIND_RELATION && relkind != RELKIND_TOASTVALUE &&
13183 		relkind != RELKIND_MATVIEW && relkind != RELKIND_PARTITIONED_TABLE)
13184 		ereport(ERROR,
13185 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
13186 				 errmsg("\"%s\" is not a table or materialized view", relation->relname)));
13187 
13188 	/* Check permissions */
13189 	if (!pg_class_ownercheck(relId, GetUserId()))
13190 		aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS, relation->relname);
13191 }
13192 
13193 /*
13194  * Callback to RangeVarGetRelidExtended(), similar to
13195  * RangeVarCallbackOwnsTable() but without checks on the type of the relation.
13196  */
13197 void
RangeVarCallbackOwnsRelation(const RangeVar * relation,Oid relId,Oid oldRelId,void * arg)13198 RangeVarCallbackOwnsRelation(const RangeVar *relation,
13199 							 Oid relId, Oid oldRelId, void *arg)
13200 {
13201 	HeapTuple	tuple;
13202 
13203 	/* Nothing to do if the relation was not found. */
13204 	if (!OidIsValid(relId))
13205 		return;
13206 
13207 	tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relId));
13208 	if (!HeapTupleIsValid(tuple))	/* should not happen */
13209 		elog(ERROR, "cache lookup failed for relation %u", relId);
13210 
13211 	if (!pg_class_ownercheck(relId, GetUserId()))
13212 		aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS,
13213 					   relation->relname);
13214 
13215 	if (!allowSystemTableMods &&
13216 		IsSystemClass(relId, (Form_pg_class) GETSTRUCT(tuple)))
13217 		ereport(ERROR,
13218 				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
13219 				 errmsg("permission denied: \"%s\" is a system catalog",
13220 						relation->relname)));
13221 
13222 	ReleaseSysCache(tuple);
13223 }
13224 
13225 /*
13226  * Common RangeVarGetRelid callback for rename, set schema, and alter table
13227  * processing.
13228  */
13229 static void
RangeVarCallbackForAlterRelation(const RangeVar * rv,Oid relid,Oid oldrelid,void * arg)13230 RangeVarCallbackForAlterRelation(const RangeVar *rv, Oid relid, Oid oldrelid,
13231 								 void *arg)
13232 {
13233 	Node	   *stmt = (Node *) arg;
13234 	ObjectType	reltype;
13235 	HeapTuple	tuple;
13236 	Form_pg_class classform;
13237 	AclResult	aclresult;
13238 	char		relkind;
13239 
13240 	tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
13241 	if (!HeapTupleIsValid(tuple))
13242 		return;					/* concurrently dropped */
13243 	classform = (Form_pg_class) GETSTRUCT(tuple);
13244 	relkind = classform->relkind;
13245 
13246 	/* Must own relation. */
13247 	if (!pg_class_ownercheck(relid, GetUserId()))
13248 		aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS, rv->relname);
13249 
13250 	/* No system table modifications unless explicitly allowed. */
13251 	if (!allowSystemTableMods && IsSystemClass(relid, classform))
13252 		ereport(ERROR,
13253 				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
13254 				 errmsg("permission denied: \"%s\" is a system catalog",
13255 						rv->relname)));
13256 
13257 	/*
13258 	 * Extract the specified relation type from the statement parse tree.
13259 	 *
13260 	 * Also, for ALTER .. RENAME, check permissions: the user must (still)
13261 	 * have CREATE rights on the containing namespace.
13262 	 */
13263 	if (IsA(stmt, RenameStmt))
13264 	{
13265 		aclresult = pg_namespace_aclcheck(classform->relnamespace,
13266 										  GetUserId(), ACL_CREATE);
13267 		if (aclresult != ACLCHECK_OK)
13268 			aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
13269 						   get_namespace_name(classform->relnamespace));
13270 		reltype = ((RenameStmt *) stmt)->renameType;
13271 	}
13272 	else if (IsA(stmt, AlterObjectSchemaStmt))
13273 		reltype = ((AlterObjectSchemaStmt *) stmt)->objectType;
13274 
13275 	else if (IsA(stmt, AlterTableStmt))
13276 		reltype = ((AlterTableStmt *) stmt)->relkind;
13277 	else
13278 	{
13279 		reltype = OBJECT_TABLE; /* placate compiler */
13280 		elog(ERROR, "unrecognized node type: %d", (int) nodeTag(stmt));
13281 	}
13282 
13283 	/*
13284 	 * For compatibility with prior releases, we allow ALTER TABLE to be used
13285 	 * with most other types of relations (but not composite types). We allow
13286 	 * similar flexibility for ALTER INDEX in the case of RENAME, but not
13287 	 * otherwise.  Otherwise, the user must select the correct form of the
13288 	 * command for the relation at issue.
13289 	 */
13290 	if (reltype == OBJECT_SEQUENCE && relkind != RELKIND_SEQUENCE)
13291 		ereport(ERROR,
13292 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
13293 				 errmsg("\"%s\" is not a sequence", rv->relname)));
13294 
13295 	if (reltype == OBJECT_VIEW && relkind != RELKIND_VIEW)
13296 		ereport(ERROR,
13297 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
13298 				 errmsg("\"%s\" is not a view", rv->relname)));
13299 
13300 	if (reltype == OBJECT_MATVIEW && relkind != RELKIND_MATVIEW)
13301 		ereport(ERROR,
13302 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
13303 				 errmsg("\"%s\" is not a materialized view", rv->relname)));
13304 
13305 	if (reltype == OBJECT_FOREIGN_TABLE && relkind != RELKIND_FOREIGN_TABLE)
13306 		ereport(ERROR,
13307 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
13308 				 errmsg("\"%s\" is not a foreign table", rv->relname)));
13309 
13310 	if (reltype == OBJECT_TYPE && relkind != RELKIND_COMPOSITE_TYPE)
13311 		ereport(ERROR,
13312 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
13313 				 errmsg("\"%s\" is not a composite type", rv->relname)));
13314 
13315 	if (reltype == OBJECT_INDEX && relkind != RELKIND_INDEX
13316 		&& !IsA(stmt, RenameStmt))
13317 		ereport(ERROR,
13318 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
13319 				 errmsg("\"%s\" is not an index", rv->relname)));
13320 
13321 	/*
13322 	 * Don't allow ALTER TABLE on composite types. We want people to use ALTER
13323 	 * TYPE for that.
13324 	 */
13325 	if (reltype != OBJECT_TYPE && relkind == RELKIND_COMPOSITE_TYPE)
13326 		ereport(ERROR,
13327 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
13328 				 errmsg("\"%s\" is a composite type", rv->relname),
13329 				 errhint("Use ALTER TYPE instead.")));
13330 
13331 	/*
13332 	 * Don't allow ALTER TABLE .. SET SCHEMA on relations that can't be moved
13333 	 * to a different schema, such as indexes and TOAST tables.
13334 	 */
13335 	if (IsA(stmt, AlterObjectSchemaStmt) &&
13336 		relkind != RELKIND_RELATION &&
13337 		relkind != RELKIND_VIEW &&
13338 		relkind != RELKIND_MATVIEW &&
13339 		relkind != RELKIND_SEQUENCE &&
13340 		relkind != RELKIND_FOREIGN_TABLE &&
13341 		relkind != RELKIND_PARTITIONED_TABLE)
13342 		ereport(ERROR,
13343 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
13344 				 errmsg("\"%s\" is not a table, view, materialized view, sequence, or foreign table",
13345 						rv->relname)));
13346 
13347 	ReleaseSysCache(tuple);
13348 }
13349 
13350 /*
13351  * Transform any expressions present in the partition key
13352  *
13353  * Returns a transformed PartitionSpec, as well as the strategy code
13354  */
13355 static PartitionSpec *
transformPartitionSpec(Relation rel,PartitionSpec * partspec,char * strategy)13356 transformPartitionSpec(Relation rel, PartitionSpec *partspec, char *strategy)
13357 {
13358 	PartitionSpec *newspec;
13359 	ParseState *pstate;
13360 	RangeTblEntry *rte;
13361 	ListCell   *l;
13362 
13363 	newspec = makeNode(PartitionSpec);
13364 
13365 	newspec->strategy = partspec->strategy;
13366 	newspec->partParams = NIL;
13367 	newspec->location = partspec->location;
13368 
13369 	/* Parse partitioning strategy name */
13370 	if (pg_strcasecmp(partspec->strategy, "list") == 0)
13371 		*strategy = PARTITION_STRATEGY_LIST;
13372 	else if (pg_strcasecmp(partspec->strategy, "range") == 0)
13373 		*strategy = PARTITION_STRATEGY_RANGE;
13374 	else
13375 		ereport(ERROR,
13376 				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
13377 				 errmsg("unrecognized partitioning strategy \"%s\"",
13378 						partspec->strategy)));
13379 
13380 	/* Check valid number of columns for strategy */
13381 	if (*strategy == PARTITION_STRATEGY_LIST &&
13382 		list_length(partspec->partParams) != 1)
13383 		ereport(ERROR,
13384 				(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
13385 				 errmsg("cannot use \"list\" partition strategy with more than one column")));
13386 
13387 	/*
13388 	 * Create a dummy ParseState and insert the target relation as its sole
13389 	 * rangetable entry.  We need a ParseState for transformExpr.
13390 	 */
13391 	pstate = make_parsestate(NULL);
13392 	rte = addRangeTableEntryForRelation(pstate, rel, NULL, false, true);
13393 	addRTEtoQuery(pstate, rte, true, true, true);
13394 
13395 	/* take care of any partition expressions */
13396 	foreach(l, partspec->partParams)
13397 	{
13398 		PartitionElem *pelem = castNode(PartitionElem, lfirst(l));
13399 
13400 		if (pelem->expr)
13401 		{
13402 			/* Copy, to avoid scribbling on the input */
13403 			pelem = copyObject(pelem);
13404 
13405 			/* Now do parse transformation of the expression */
13406 			pelem->expr = transformExpr(pstate, pelem->expr,
13407 										EXPR_KIND_PARTITION_EXPRESSION);
13408 
13409 			/* we have to fix its collations too */
13410 			assign_expr_collations(pstate, pelem->expr);
13411 		}
13412 
13413 		newspec->partParams = lappend(newspec->partParams, pelem);
13414 	}
13415 
13416 	return newspec;
13417 }
13418 
13419 /*
13420  * Compute per-partition-column information from a list of PartitionElems.
13421  * Expressions in the PartitionElems must be parse-analyzed already.
13422  */
13423 static void
ComputePartitionAttrs(Relation rel,List * partParams,AttrNumber * partattrs,List ** partexprs,Oid * partopclass,Oid * partcollation)13424 ComputePartitionAttrs(Relation rel, List *partParams, AttrNumber *partattrs,
13425 					  List **partexprs, Oid *partopclass, Oid *partcollation)
13426 {
13427 	int			attn;
13428 	ListCell   *lc;
13429 
13430 	attn = 0;
13431 	foreach(lc, partParams)
13432 	{
13433 		PartitionElem *pelem = castNode(PartitionElem, lfirst(lc));
13434 		Oid			atttype;
13435 		Oid			attcollation;
13436 
13437 		if (pelem->name != NULL)
13438 		{
13439 			/* Simple attribute reference */
13440 			HeapTuple	atttuple;
13441 			Form_pg_attribute attform;
13442 
13443 			atttuple = SearchSysCacheAttName(RelationGetRelid(rel),
13444 											 pelem->name);
13445 			if (!HeapTupleIsValid(atttuple))
13446 				ereport(ERROR,
13447 						(errcode(ERRCODE_UNDEFINED_COLUMN),
13448 						 errmsg("column \"%s\" named in partition key does not exist",
13449 								pelem->name)));
13450 			attform = (Form_pg_attribute) GETSTRUCT(atttuple);
13451 
13452 			if (attform->attnum <= 0)
13453 				ereport(ERROR,
13454 						(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
13455 						 errmsg("cannot use system column \"%s\" in partition key",
13456 								pelem->name)));
13457 
13458 			partattrs[attn] = attform->attnum;
13459 			atttype = attform->atttypid;
13460 			attcollation = attform->attcollation;
13461 			ReleaseSysCache(atttuple);
13462 		}
13463 		else
13464 		{
13465 			/* Expression */
13466 			Node	   *expr = pelem->expr;
13467 
13468 			Assert(expr != NULL);
13469 			atttype = exprType(expr);
13470 			attcollation = exprCollation(expr);
13471 
13472 			/*
13473 			 * The expression must be of a storable type (e.g., not RECORD).
13474 			 * The test is the same as for whether a table column is of a safe
13475 			 * type (which is why we needn't check for the non-expression
13476 			 * case).
13477 			 */
13478 			CheckAttributeType("partition key",
13479 							   atttype, attcollation,
13480 							   NIL, false);
13481 
13482 			/*
13483 			 * Strip any top-level COLLATE clause.  This ensures that we treat
13484 			 * "x COLLATE y" and "(x COLLATE y)" alike.
13485 			 */
13486 			while (IsA(expr, CollateExpr))
13487 				expr = (Node *) ((CollateExpr *) expr)->arg;
13488 
13489 			if (IsA(expr, Var) &&
13490 				((Var *) expr)->varattno > 0)
13491 			{
13492 				/*
13493 				 * User wrote "(column)" or "(column COLLATE something)".
13494 				 * Treat it like simple attribute anyway.
13495 				 */
13496 				partattrs[attn] = ((Var *) expr)->varattno;
13497 			}
13498 			else
13499 			{
13500 				Bitmapset  *expr_attrs = NULL;
13501 				int			i;
13502 
13503 				partattrs[attn] = 0;	/* marks the column as expression */
13504 				*partexprs = lappend(*partexprs, expr);
13505 
13506 				/*
13507 				 * Try to simplify the expression before checking for
13508 				 * mutability.  The main practical value of doing it in this
13509 				 * order is that an inline-able SQL-language function will be
13510 				 * accepted if its expansion is immutable, whether or not the
13511 				 * function itself is marked immutable.
13512 				 *
13513 				 * Note that expression_planner does not change the passed in
13514 				 * expression destructively and we have already saved the
13515 				 * expression to be stored into the catalog above.
13516 				 */
13517 				expr = (Node *) expression_planner((Expr *) expr);
13518 
13519 				/*
13520 				 * Partition expression cannot contain mutable functions,
13521 				 * because a given row must always map to the same partition
13522 				 * as long as there is no change in the partition boundary
13523 				 * structure.
13524 				 */
13525 				if (contain_mutable_functions(expr))
13526 					ereport(ERROR,
13527 							(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
13528 							 errmsg("functions in partition key expression must be marked IMMUTABLE")));
13529 
13530 				/*
13531 				 * transformPartitionSpec() should have already rejected
13532 				 * subqueries, aggregates, window functions, and SRFs, based
13533 				 * on the EXPR_KIND_ for partition expressions.
13534 				 */
13535 
13536 				/*
13537 				 * Cannot have expressions containing whole-row references or
13538 				 * system column references.
13539 				 */
13540 				pull_varattnos(expr, 1, &expr_attrs);
13541 				if (bms_is_member(0 - FirstLowInvalidHeapAttributeNumber,
13542 								  expr_attrs))
13543 					ereport(ERROR,
13544 							(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
13545 							 errmsg("partition key expressions cannot contain whole-row references")));
13546 				for (i = FirstLowInvalidHeapAttributeNumber; i < 0; i++)
13547 				{
13548 					if (bms_is_member(i - FirstLowInvalidHeapAttributeNumber,
13549 									  expr_attrs))
13550 						ereport(ERROR,
13551 								(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
13552 								 errmsg("partition key expressions cannot contain system column references")));
13553 				}
13554 
13555 				/*
13556 				 * While it is not exactly *wrong* for a partition expression
13557 				 * to be a constant, it seems better to reject such keys.
13558 				 */
13559 				if (IsA(expr, Const))
13560 					ereport(ERROR,
13561 							(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
13562 							 errmsg("cannot use constant expression as partition key")));
13563 			}
13564 		}
13565 
13566 		/*
13567 		 * Apply collation override if any
13568 		 */
13569 		if (pelem->collation)
13570 			attcollation = get_collation_oid(pelem->collation, false);
13571 
13572 		/*
13573 		 * Check we have a collation iff it's a collatable type.  The only
13574 		 * expected failures here are (1) COLLATE applied to a noncollatable
13575 		 * type, or (2) partition expression had an unresolved collation. But
13576 		 * we might as well code this to be a complete consistency check.
13577 		 */
13578 		if (type_is_collatable(atttype))
13579 		{
13580 			if (!OidIsValid(attcollation))
13581 				ereport(ERROR,
13582 						(errcode(ERRCODE_INDETERMINATE_COLLATION),
13583 						 errmsg("could not determine which collation to use for partition expression"),
13584 						 errhint("Use the COLLATE clause to set the collation explicitly.")));
13585 		}
13586 		else
13587 		{
13588 			if (OidIsValid(attcollation))
13589 				ereport(ERROR,
13590 						(errcode(ERRCODE_DATATYPE_MISMATCH),
13591 						 errmsg("collations are not supported by type %s",
13592 								format_type_be(atttype))));
13593 		}
13594 
13595 		partcollation[attn] = attcollation;
13596 
13597 		/*
13598 		 * Identify a btree opclass to use. Currently, we use only btree
13599 		 * operators, which seems enough for list and range partitioning.
13600 		 */
13601 		if (!pelem->opclass)
13602 		{
13603 			partopclass[attn] = GetDefaultOpClass(atttype, BTREE_AM_OID);
13604 
13605 			if (!OidIsValid(partopclass[attn]))
13606 				ereport(ERROR,
13607 						(errcode(ERRCODE_UNDEFINED_OBJECT),
13608 						 errmsg("data type %s has no default btree operator class",
13609 								format_type_be(atttype)),
13610 						 errhint("You must specify a btree operator class or define a default btree operator class for the data type.")));
13611 		}
13612 		else
13613 			partopclass[attn] = ResolveOpClass(pelem->opclass,
13614 											   atttype,
13615 											   "btree",
13616 											   BTREE_AM_OID);
13617 
13618 		attn++;
13619 	}
13620 }
13621 
13622 /*
13623  * ALTER TABLE <name> ATTACH PARTITION <partition-name> FOR VALUES
13624  *
13625  * Return the address of the newly attached partition.
13626  */
13627 static ObjectAddress
ATExecAttachPartition(List ** wqueue,Relation rel,PartitionCmd * cmd)13628 ATExecAttachPartition(List **wqueue, Relation rel, PartitionCmd *cmd)
13629 {
13630 	Relation	attachrel,
13631 				catalog;
13632 	List	   *attachrel_children;
13633 	TupleConstr *attachrel_constr;
13634 	List	   *partConstraint,
13635 			   *existConstraint;
13636 	SysScanDesc scan;
13637 	ScanKeyData skey;
13638 	AttrNumber	attno;
13639 	int			natts;
13640 	TupleDesc	tupleDesc;
13641 	bool		skip_validate = false;
13642 	ObjectAddress address;
13643 	const char *trigger_name;
13644 	bool		found_whole_row;
13645 
13646 	attachrel = heap_openrv(cmd->name, AccessExclusiveLock);
13647 
13648 	/*
13649 	 * Must be owner of both parent and source table -- parent was checked by
13650 	 * ATSimplePermissions call in ATPrepCmd
13651 	 */
13652 	ATSimplePermissions(attachrel, ATT_TABLE | ATT_FOREIGN_TABLE);
13653 
13654 	/* A partition can only have one parent */
13655 	if (attachrel->rd_rel->relispartition)
13656 		ereport(ERROR,
13657 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
13658 				 errmsg("\"%s\" is already a partition",
13659 						RelationGetRelationName(attachrel))));
13660 
13661 	if (OidIsValid(attachrel->rd_rel->reloftype))
13662 		ereport(ERROR,
13663 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
13664 				 errmsg("cannot attach a typed table as partition")));
13665 
13666 	/*
13667 	 * Table being attached should not already be part of inheritance; either
13668 	 * as a child table...
13669 	 */
13670 	catalog = heap_open(InheritsRelationId, AccessShareLock);
13671 	ScanKeyInit(&skey,
13672 				Anum_pg_inherits_inhrelid,
13673 				BTEqualStrategyNumber, F_OIDEQ,
13674 				ObjectIdGetDatum(RelationGetRelid(attachrel)));
13675 	scan = systable_beginscan(catalog, InheritsRelidSeqnoIndexId, true,
13676 							  NULL, 1, &skey);
13677 	if (HeapTupleIsValid(systable_getnext(scan)))
13678 		ereport(ERROR,
13679 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
13680 				 errmsg("cannot attach inheritance child as partition")));
13681 	systable_endscan(scan);
13682 
13683 	/* ...or as a parent table (except the case when it is partitioned) */
13684 	ScanKeyInit(&skey,
13685 				Anum_pg_inherits_inhparent,
13686 				BTEqualStrategyNumber, F_OIDEQ,
13687 				ObjectIdGetDatum(RelationGetRelid(attachrel)));
13688 	scan = systable_beginscan(catalog, InheritsParentIndexId, true, NULL,
13689 							  1, &skey);
13690 	if (HeapTupleIsValid(systable_getnext(scan)) &&
13691 		attachrel->rd_rel->relkind == RELKIND_RELATION)
13692 		ereport(ERROR,
13693 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
13694 				 errmsg("cannot attach inheritance parent as partition")));
13695 	systable_endscan(scan);
13696 	heap_close(catalog, AccessShareLock);
13697 
13698 	/*
13699 	 * Prevent circularity by seeing if rel is a partition of attachrel. (In
13700 	 * particular, this disallows making a rel a partition of itself.)
13701 	 *
13702 	 * We do that by checking if rel is a member of the list of attachrel's
13703 	 * partitions provided the latter is partitioned at all.  We want to avoid
13704 	 * having to construct this list again, so we request the strongest lock
13705 	 * on all partitions.  We need the strongest lock, because we may decide
13706 	 * to scan them if we find out that the table being attached (or its leaf
13707 	 * partitions) may contain rows that violate the partition constraint. If
13708 	 * the table has a constraint that would prevent such rows, which by
13709 	 * definition is present in all the partitions, we need not scan the
13710 	 * table, nor its partitions.  But we cannot risk a deadlock by taking a
13711 	 * weaker lock now and the stronger one only when needed.
13712 	 */
13713 	attachrel_children = find_all_inheritors(RelationGetRelid(attachrel),
13714 											 AccessExclusiveLock, NULL);
13715 	if (list_member_oid(attachrel_children, RelationGetRelid(rel)))
13716 		ereport(ERROR,
13717 				(errcode(ERRCODE_DUPLICATE_TABLE),
13718 				 errmsg("circular inheritance not allowed"),
13719 				 errdetail("\"%s\" is already a child of \"%s\".",
13720 						   RelationGetRelationName(rel),
13721 						   RelationGetRelationName(attachrel))));
13722 
13723 	/* If the parent is permanent, so must be all of its partitions. */
13724 	if (rel->rd_rel->relpersistence != RELPERSISTENCE_TEMP &&
13725 		attachrel->rd_rel->relpersistence == RELPERSISTENCE_TEMP)
13726 		ereport(ERROR,
13727 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
13728 				 errmsg("cannot attach a temporary relation as partition of permanent relation \"%s\"",
13729 						RelationGetRelationName(rel))));
13730 
13731 	/* Temp parent cannot have a partition that is itself not a temp */
13732 	if (rel->rd_rel->relpersistence == RELPERSISTENCE_TEMP &&
13733 		attachrel->rd_rel->relpersistence != RELPERSISTENCE_TEMP)
13734 		ereport(ERROR,
13735 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
13736 				 errmsg("cannot attach a permanent relation as partition of temporary relation \"%s\"",
13737 						RelationGetRelationName(rel))));
13738 
13739 	/* If the parent is temp, it must belong to this session */
13740 	if (rel->rd_rel->relpersistence == RELPERSISTENCE_TEMP &&
13741 		!rel->rd_islocaltemp)
13742 		ereport(ERROR,
13743 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
13744 				 errmsg("cannot attach as partition of temporary relation of another session")));
13745 
13746 	/* Ditto for the partition */
13747 	if (attachrel->rd_rel->relpersistence == RELPERSISTENCE_TEMP &&
13748 		!attachrel->rd_islocaltemp)
13749 		ereport(ERROR,
13750 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
13751 				 errmsg("cannot attach temporary relation of another session as partition")));
13752 
13753 	/* If parent has OIDs then child must have OIDs */
13754 	if (rel->rd_rel->relhasoids && !attachrel->rd_rel->relhasoids)
13755 		ereport(ERROR,
13756 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
13757 				 errmsg("cannot attach table \"%s\" without OIDs as partition of"
13758 						" table \"%s\" with OIDs", RelationGetRelationName(attachrel),
13759 						RelationGetRelationName(rel))));
13760 
13761 	/* OTOH, if parent doesn't have them, do not allow in attachrel either */
13762 	if (attachrel->rd_rel->relhasoids && !rel->rd_rel->relhasoids)
13763 		ereport(ERROR,
13764 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
13765 				 errmsg("cannot attach table \"%s\" with OIDs as partition of table"
13766 						" \"%s\" without OIDs", RelationGetRelationName(attachrel),
13767 						RelationGetRelationName(rel))));
13768 
13769 	/* Check if there are any columns in attachrel that aren't in the parent */
13770 	tupleDesc = RelationGetDescr(attachrel);
13771 	natts = tupleDesc->natts;
13772 	for (attno = 1; attno <= natts; attno++)
13773 	{
13774 		Form_pg_attribute attribute = tupleDesc->attrs[attno - 1];
13775 		char	   *attributeName = NameStr(attribute->attname);
13776 
13777 		/* Ignore dropped */
13778 		if (attribute->attisdropped)
13779 			continue;
13780 
13781 		/* Try to find the column in parent (matching on column name) */
13782 		if (!SearchSysCacheExists2(ATTNAME,
13783 								   ObjectIdGetDatum(RelationGetRelid(rel)),
13784 								   CStringGetDatum(attributeName)))
13785 			ereport(ERROR,
13786 					(errcode(ERRCODE_DATATYPE_MISMATCH),
13787 					 errmsg("table \"%s\" contains column \"%s\" not found in parent \"%s\"",
13788 							RelationGetRelationName(attachrel), attributeName,
13789 							RelationGetRelationName(rel)),
13790 					 errdetail("The new partition may contain only the columns present in parent.")));
13791 	}
13792 
13793 	/*
13794 	 * If child_rel has row-level triggers with transition tables, we
13795 	 * currently don't allow it to become a partition.  See also prohibitions
13796 	 * in ATExecAddInherit() and CreateTrigger().
13797 	 */
13798 	trigger_name = FindTriggerIncompatibleWithInheritance(attachrel->trigdesc);
13799 	if (trigger_name != NULL)
13800 		ereport(ERROR,
13801 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
13802 				 errmsg("trigger \"%s\" prevents table \"%s\" from becoming a partition",
13803 						trigger_name, RelationGetRelationName(attachrel)),
13804 				 errdetail("ROW triggers with transition tables are not supported on partitions")));
13805 
13806 	/* OK to create inheritance.  Rest of the checks performed there */
13807 	CreateInheritance(attachrel, rel);
13808 
13809 	/*
13810 	 * Check that the new partition's bound is valid and does not overlap any
13811 	 * of existing partitions of the parent - note that it does not return on
13812 	 * error.
13813 	 */
13814 	check_new_partition_bound(RelationGetRelationName(attachrel), rel,
13815 							  cmd->bound);
13816 
13817 	/* Update the pg_class entry. */
13818 	StorePartitionBound(attachrel, rel, cmd->bound);
13819 
13820 	/*
13821 	 * Generate partition constraint from the partition bound specification.
13822 	 * If the parent itself is a partition, make sure to include its
13823 	 * constraint as well.
13824 	 */
13825 	partConstraint = list_concat(get_qual_from_partbound(attachrel, rel,
13826 														 cmd->bound),
13827 								 RelationGetPartitionQual(rel));
13828 
13829 	/*
13830 	 * Run the partition quals through const-simplification similar to check
13831 	 * constraints.  We skip canonicalize_qual, though, because partition
13832 	 * quals should be in canonical form already; also, since the qual is in
13833 	 * implicit-AND format, we'd have to explicitly convert it to explicit-AND
13834 	 * format and back again.
13835 	 */
13836 	partConstraint = (List *) eval_const_expressions(NULL,
13837 													 (Node *) partConstraint);
13838 
13839 	partConstraint = list_make1(make_ands_explicit(partConstraint));
13840 
13841 	/*
13842 	 * Adjust the generated constraint to match this partition's attribute
13843 	 * numbers.
13844 	 */
13845 	partConstraint = map_partition_varattnos(partConstraint, 1, attachrel,
13846 											 rel, &found_whole_row);
13847 	/* There can never be a whole-row reference here */
13848 	if (found_whole_row)
13849 		elog(ERROR, "unexpected whole-row reference found in partition key");
13850 
13851 	/*
13852 	 * Check if we can do away with having to scan the table being attached to
13853 	 * validate the partition constraint, by *proving* that the existing
13854 	 * constraints of the table *imply* the partition predicate.  We include
13855 	 * the table's check constraints and NOT NULL constraints in the list of
13856 	 * clauses passed to predicate_implied_by().
13857 	 *
13858 	 * There is a case in which we cannot rely on just the result of the
13859 	 * proof.
13860 	 */
13861 	attachrel_constr = tupleDesc->constr;
13862 	existConstraint = NIL;
13863 	if (attachrel_constr != NULL)
13864 	{
13865 		int			num_check = attachrel_constr->num_check;
13866 		int			i;
13867 
13868 		if (attachrel_constr->has_not_null)
13869 		{
13870 			int			natts = attachrel->rd_att->natts;
13871 
13872 			for (i = 1; i <= natts; i++)
13873 			{
13874 				Form_pg_attribute att = attachrel->rd_att->attrs[i - 1];
13875 
13876 				if (att->attnotnull && !att->attisdropped)
13877 				{
13878 					NullTest   *ntest = makeNode(NullTest);
13879 
13880 					ntest->arg = (Expr *) makeVar(1,
13881 												  i,
13882 												  att->atttypid,
13883 												  att->atttypmod,
13884 												  att->attcollation,
13885 												  0);
13886 					ntest->nulltesttype = IS_NOT_NULL;
13887 
13888 					/*
13889 					 * argisrow=false is correct even for a composite column,
13890 					 * because attnotnull does not represent a SQL-spec IS NOT
13891 					 * NULL test in such a case, just IS DISTINCT FROM NULL.
13892 					 */
13893 					ntest->argisrow = false;
13894 					ntest->location = -1;
13895 					existConstraint = lappend(existConstraint, ntest);
13896 				}
13897 			}
13898 		}
13899 
13900 		for (i = 0; i < num_check; i++)
13901 		{
13902 			Node	   *cexpr;
13903 
13904 			/*
13905 			 * If this constraint hasn't been fully validated yet, we must
13906 			 * ignore it here.
13907 			 */
13908 			if (!attachrel_constr->check[i].ccvalid)
13909 				continue;
13910 
13911 			cexpr = stringToNode(attachrel_constr->check[i].ccbin);
13912 
13913 			/*
13914 			 * Run each expression through const-simplification and
13915 			 * canonicalization.  It is necessary, because we will be
13916 			 * comparing it to similarly-processed qual clauses, and may fail
13917 			 * to detect valid matches without this.
13918 			 */
13919 			cexpr = eval_const_expressions(NULL, cexpr);
13920 			cexpr = (Node *) canonicalize_qual_ext((Expr *) cexpr, true);
13921 
13922 			existConstraint = list_concat(existConstraint,
13923 										  make_ands_implicit((Expr *) cexpr));
13924 		}
13925 
13926 		/* And away we go ... */
13927 		if (predicate_implied_by(partConstraint, existConstraint, true))
13928 			skip_validate = true;
13929 	}
13930 
13931 	if (skip_validate)
13932 	{
13933 		/* No need to scan the table after all. */
13934 		ereport(INFO,
13935 				(errmsg("partition constraint for table \"%s\" is implied by existing constraints",
13936 						RelationGetRelationName(attachrel))));
13937 	}
13938 	else
13939 	{
13940 		/* Constraints proved insufficient, so we need to scan the table. */
13941 		ListCell   *lc;
13942 
13943 		foreach(lc, attachrel_children)
13944 		{
13945 			AlteredTableInfo *tab;
13946 			Oid			part_relid = lfirst_oid(lc);
13947 			Relation	part_rel;
13948 			List	   *my_partconstr = partConstraint;
13949 
13950 			/* Lock already taken */
13951 			if (part_relid != RelationGetRelid(attachrel))
13952 				part_rel = heap_open(part_relid, NoLock);
13953 			else
13954 				part_rel = attachrel;
13955 
13956 			/*
13957 			 * Skip if the partition is itself a partitioned table.  We can
13958 			 * only ever scan RELKIND_RELATION relations.
13959 			 */
13960 			if (part_rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
13961 			{
13962 				if (part_rel != attachrel)
13963 					heap_close(part_rel, NoLock);
13964 				continue;
13965 			}
13966 
13967 			if (part_rel != attachrel)
13968 			{
13969 				/*
13970 				 * Adjust the constraint that we constructed above for
13971 				 * attachRel so that it matches this partition's attribute
13972 				 * numbers.
13973 				 */
13974 				my_partconstr = map_partition_varattnos(my_partconstr, 1,
13975 														part_rel, attachrel,
13976 														&found_whole_row);
13977 				/* There can never be a whole-row reference here */
13978 				if (found_whole_row)
13979 					elog(ERROR, "unexpected whole-row reference found in partition key");
13980 			}
13981 
13982 			/* Grab a work queue entry. */
13983 			tab = ATGetQueueEntry(wqueue, part_rel);
13984 			tab->partition_constraint = (Expr *) linitial(my_partconstr);
13985 
13986 			/* keep our lock until commit */
13987 			if (part_rel != attachrel)
13988 				heap_close(part_rel, NoLock);
13989 		}
13990 	}
13991 
13992 	ObjectAddressSet(address, RelationRelationId, RelationGetRelid(attachrel));
13993 
13994 	/*
13995 	 * If the partition we just attached is partitioned itself, invalidate
13996 	 * relcache for all descendent partitions too to ensure that their
13997 	 * rd_partcheck expression trees are rebuilt; partitions already locked
13998 	 * at the beginning of this function.
13999 	 */
14000 	if (attachrel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
14001 	{
14002 		ListCell *l;
14003 
14004 		foreach(l, attachrel_children)
14005 		{
14006 			CacheInvalidateRelcacheByRelid(lfirst_oid(l));
14007 		}
14008 	}
14009 
14010 	/* keep our lock until commit */
14011 	heap_close(attachrel, NoLock);
14012 
14013 	return address;
14014 }
14015 
14016 /*
14017  * ALTER TABLE DETACH PARTITION
14018  *
14019  * Return the address of the relation that is no longer a partition of rel.
14020  */
14021 static ObjectAddress
ATExecDetachPartition(Relation rel,RangeVar * name)14022 ATExecDetachPartition(Relation rel, RangeVar *name)
14023 {
14024 	Relation	partRel,
14025 				classRel;
14026 	HeapTuple	tuple,
14027 				newtuple;
14028 	Datum		new_val[Natts_pg_class];
14029 	bool		isnull,
14030 				new_null[Natts_pg_class],
14031 				new_repl[Natts_pg_class];
14032 	ObjectAddress address;
14033 
14034 	partRel = heap_openrv(name, ShareUpdateExclusiveLock);
14035 
14036 	/* All inheritance related checks are performed within the function */
14037 	RemoveInheritance(partRel, rel);
14038 
14039 	/* Update pg_class tuple */
14040 	classRel = heap_open(RelationRelationId, RowExclusiveLock);
14041 	tuple = SearchSysCacheCopy1(RELOID,
14042 								ObjectIdGetDatum(RelationGetRelid(partRel)));
14043 	if (!HeapTupleIsValid(tuple))
14044 		elog(ERROR, "cache lookup failed for relation %u",
14045 			 RelationGetRelid(partRel));
14046 	Assert(((Form_pg_class) GETSTRUCT(tuple))->relispartition);
14047 
14048 	(void) SysCacheGetAttr(RELOID, tuple, Anum_pg_class_relpartbound,
14049 						   &isnull);
14050 	Assert(!isnull);
14051 
14052 	/* Clear relpartbound and reset relispartition */
14053 	memset(new_val, 0, sizeof(new_val));
14054 	memset(new_null, false, sizeof(new_null));
14055 	memset(new_repl, false, sizeof(new_repl));
14056 	new_val[Anum_pg_class_relpartbound - 1] = (Datum) 0;
14057 	new_null[Anum_pg_class_relpartbound - 1] = true;
14058 	new_repl[Anum_pg_class_relpartbound - 1] = true;
14059 	newtuple = heap_modify_tuple(tuple, RelationGetDescr(classRel),
14060 								 new_val, new_null, new_repl);
14061 
14062 	((Form_pg_class) GETSTRUCT(newtuple))->relispartition = false;
14063 	CatalogTupleUpdate(classRel, &newtuple->t_self, newtuple);
14064 	heap_freetuple(newtuple);
14065 	heap_close(classRel, RowExclusiveLock);
14066 
14067 	/*
14068 	 * Invalidate the parent's relcache so that the partition is no longer
14069 	 * included in its partition descriptor.
14070 	 */
14071 	CacheInvalidateRelcache(rel);
14072 
14073 	/*
14074 	 * If the partition we just detached is partitioned itself, invalidate
14075 	 * relcache for all descendent partitions too to ensure that their
14076 	 * rd_partcheck expression trees are rebuilt; must lock partitions
14077 	 * before doing so, using the same lockmode as what partRel has been
14078 	 * locked with by the caller.
14079 	 */
14080 	if (partRel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
14081 	{
14082 		List   *children;
14083 		ListCell *cell;
14084 
14085 		children = find_all_inheritors(RelationGetRelid(partRel),
14086 									   AccessExclusiveLock, NULL);
14087 		foreach(cell, children)
14088 		{
14089 			CacheInvalidateRelcacheByRelid(lfirst_oid(cell));
14090 		}
14091 	}
14092 
14093 	ObjectAddressSet(address, RelationRelationId, RelationGetRelid(partRel));
14094 
14095 	/* keep our lock until commit */
14096 	heap_close(partRel, NoLock);
14097 
14098 	return address;
14099 }
14100