1 /*-------------------------------------------------------------------------
2  *
3  * tablecmds.c
4  *	  Commands for creating and altering table structures and settings
5  *
6  * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  *
10  * IDENTIFICATION
11  *	  src/backend/commands/tablecmds.c
12  *
13  *-------------------------------------------------------------------------
14  */
15 #include "postgres.h"
16 
17 #include "access/attmap.h"
18 #include "access/genam.h"
19 #include "access/heapam.h"
20 #include "access/heapam_xlog.h"
21 #include "access/multixact.h"
22 #include "access/reloptions.h"
23 #include "access/relscan.h"
24 #include "access/sysattr.h"
25 #include "access/tableam.h"
26 #include "access/xact.h"
27 #include "access/xlog.h"
28 #include "catalog/catalog.h"
29 #include "catalog/dependency.h"
30 #include "catalog/heap.h"
31 #include "catalog/index.h"
32 #include "catalog/indexing.h"
33 #include "catalog/namespace.h"
34 #include "catalog/objectaccess.h"
35 #include "catalog/partition.h"
36 #include "catalog/pg_am.h"
37 #include "catalog/pg_collation.h"
38 #include "catalog/pg_constraint.h"
39 #include "catalog/pg_depend.h"
40 #include "catalog/pg_foreign_table.h"
41 #include "catalog/pg_inherits.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/storage.h"
48 #include "catalog/storage_xlog.h"
49 #include "catalog/toasting.h"
50 #include "commands/cluster.h"
51 #include "commands/comment.h"
52 #include "commands/defrem.h"
53 #include "commands/event_trigger.h"
54 #include "commands/policy.h"
55 #include "commands/sequence.h"
56 #include "commands/tablecmds.h"
57 #include "commands/tablespace.h"
58 #include "commands/trigger.h"
59 #include "commands/typecmds.h"
60 #include "commands/user.h"
61 #include "executor/executor.h"
62 #include "foreign/foreign.h"
63 #include "miscadmin.h"
64 #include "nodes/makefuncs.h"
65 #include "nodes/nodeFuncs.h"
66 #include "nodes/parsenodes.h"
67 #include "optimizer/optimizer.h"
68 #include "parser/parse_clause.h"
69 #include "parser/parse_coerce.h"
70 #include "parser/parse_collate.h"
71 #include "parser/parse_expr.h"
72 #include "parser/parse_oper.h"
73 #include "parser/parse_relation.h"
74 #include "parser/parse_type.h"
75 #include "parser/parse_utilcmd.h"
76 #include "parser/parser.h"
77 #include "partitioning/partbounds.h"
78 #include "partitioning/partdesc.h"
79 #include "pgstat.h"
80 #include "rewrite/rewriteDefine.h"
81 #include "rewrite/rewriteHandler.h"
82 #include "rewrite/rewriteManip.h"
83 #include "storage/bufmgr.h"
84 #include "storage/lmgr.h"
85 #include "storage/lock.h"
86 #include "storage/predicate.h"
87 #include "storage/smgr.h"
88 #include "tcop/utility.h"
89 #include "utils/acl.h"
90 #include "utils/builtins.h"
91 #include "utils/fmgroids.h"
92 #include "utils/inval.h"
93 #include "utils/lsyscache.h"
94 #include "utils/memutils.h"
95 #include "utils/partcache.h"
96 #include "utils/relcache.h"
97 #include "utils/ruleutils.h"
98 #include "utils/snapmgr.h"
99 #include "utils/syscache.h"
100 #include "utils/timestamp.h"
101 #include "utils/typcache.h"
102 
103 /*
104  * ON COMMIT action list
105  */
106 typedef struct OnCommitItem
107 {
108 	Oid			relid;			/* relid of relation */
109 	OnCommitAction oncommit;	/* what to do at end of xact */
110 
111 	/*
112 	 * If this entry was created during the current transaction,
113 	 * creating_subid is the ID of the creating subxact; if created in a prior
114 	 * transaction, creating_subid is zero.  If deleted during the current
115 	 * transaction, deleting_subid is the ID of the deleting subxact; if no
116 	 * deletion request is pending, deleting_subid is zero.
117 	 */
118 	SubTransactionId creating_subid;
119 	SubTransactionId deleting_subid;
120 } OnCommitItem;
121 
122 static List *on_commits = NIL;
123 
124 
125 /*
126  * State information for ALTER TABLE
127  *
128  * The pending-work queue for an ALTER TABLE is a List of AlteredTableInfo
129  * structs, one for each table modified by the operation (the named table
130  * plus any child tables that are affected).  We save lists of subcommands
131  * to apply to this table (possibly modified by parse transformation steps);
132  * these lists will be executed in Phase 2.  If a Phase 3 step is needed,
133  * necessary information is stored in the constraints and newvals lists.
134  *
135  * Phase 2 is divided into multiple passes; subcommands are executed in
136  * a pass determined by subcommand type.
137  */
138 
139 #define AT_PASS_UNSET			-1	/* UNSET will cause ERROR */
140 #define AT_PASS_DROP			0	/* DROP (all flavors) */
141 #define AT_PASS_ALTER_TYPE		1	/* ALTER COLUMN TYPE */
142 #define AT_PASS_OLD_INDEX		2	/* re-add existing indexes */
143 #define AT_PASS_OLD_CONSTR		3	/* re-add existing constraints */
144 /* We could support a RENAME COLUMN pass here, but not currently used */
145 #define AT_PASS_ADD_COL			4	/* ADD COLUMN */
146 #define AT_PASS_ADD_CONSTR		5	/* ADD constraints (initial examination) */
147 #define AT_PASS_COL_ATTRS		6	/* set column attributes, eg NOT NULL */
148 #define AT_PASS_ADD_INDEXCONSTR	7	/* ADD index-based constraints */
149 #define AT_PASS_ADD_INDEX		8	/* ADD indexes */
150 #define AT_PASS_ADD_OTHERCONSTR	9	/* ADD other constraints, defaults */
151 #define AT_PASS_MISC			10	/* other stuff */
152 #define AT_NUM_PASSES			11
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 	List	   *afterStmts;		/* List of utility command parsetrees */
166 	bool		verify_new_notnull; /* T if we should recheck NOT NULL */
167 	int			rewrite;		/* Reason for forced rewrite, if any */
168 	Oid			newTableSpace;	/* new tablespace; 0 means no change */
169 	bool		chgPersistence; /* T if SET LOGGED/UNLOGGED is used */
170 	char		newrelpersistence;	/* if above is true */
171 	Expr	   *partition_constraint;	/* for attach partition validation */
172 	/* true, if validating default due to some other attach/detach */
173 	bool		validate_default;
174 	/* Objects to rebuild after completing ALTER TYPE operations */
175 	List	   *changedConstraintOids;	/* OIDs of constraints to rebuild */
176 	List	   *changedConstraintDefs;	/* string definitions of same */
177 	List	   *changedIndexOids;	/* OIDs of indexes to rebuild */
178 	List	   *changedIndexDefs;	/* string definitions of same */
179 	char	   *replicaIdentityIndex;	/* index to reset as REPLICA IDENTITY */
180 	char	   *clusterOnIndex; /* index to use for CLUSTER */
181 } AlteredTableInfo;
182 
183 /* Struct describing one new constraint to check in Phase 3 scan */
184 /* Note: new NOT NULL constraints are handled elsewhere */
185 typedef struct NewConstraint
186 {
187 	char	   *name;			/* Constraint name, or NULL if none */
188 	ConstrType	contype;		/* CHECK or FOREIGN */
189 	Oid			refrelid;		/* PK rel, if FOREIGN */
190 	Oid			refindid;		/* OID of PK's index, if FOREIGN */
191 	Oid			conid;			/* OID of pg_constraint entry, if FOREIGN */
192 	Node	   *qual;			/* Check expr or CONSTR_FOREIGN Constraint */
193 	ExprState  *qualstate;		/* Execution state for CHECK expr */
194 } NewConstraint;
195 
196 /*
197  * Struct describing one new column value that needs to be computed during
198  * Phase 3 copy (this could be either a new column with a non-null default, or
199  * a column that we're changing the type of).  Columns without such an entry
200  * are just copied from the old table during ATRewriteTable.  Note that the
201  * expr is an expression over *old* table values, except when is_generated
202  * is true; then it is an expression over columns of the *new* tuple.
203  */
204 typedef struct NewColumnValue
205 {
206 	AttrNumber	attnum;			/* which column */
207 	Expr	   *expr;			/* expression to compute */
208 	ExprState  *exprstate;		/* execution state */
209 	bool		is_generated;	/* is it a GENERATED expression? */
210 } NewColumnValue;
211 
212 /*
213  * Error-reporting support for RemoveRelations
214  */
215 struct dropmsgstrings
216 {
217 	char		kind;
218 	int			nonexistent_code;
219 	const char *nonexistent_msg;
220 	const char *skipping_msg;
221 	const char *nota_msg;
222 	const char *drophint_msg;
223 };
224 
225 static const struct dropmsgstrings dropmsgstringarray[] = {
226 	{RELKIND_RELATION,
227 		ERRCODE_UNDEFINED_TABLE,
228 		gettext_noop("table \"%s\" does not exist"),
229 		gettext_noop("table \"%s\" does not exist, skipping"),
230 		gettext_noop("\"%s\" is not a table"),
231 	gettext_noop("Use DROP TABLE to remove a table.")},
232 	{RELKIND_SEQUENCE,
233 		ERRCODE_UNDEFINED_TABLE,
234 		gettext_noop("sequence \"%s\" does not exist"),
235 		gettext_noop("sequence \"%s\" does not exist, skipping"),
236 		gettext_noop("\"%s\" is not a sequence"),
237 	gettext_noop("Use DROP SEQUENCE to remove a sequence.")},
238 	{RELKIND_VIEW,
239 		ERRCODE_UNDEFINED_TABLE,
240 		gettext_noop("view \"%s\" does not exist"),
241 		gettext_noop("view \"%s\" does not exist, skipping"),
242 		gettext_noop("\"%s\" is not a view"),
243 	gettext_noop("Use DROP VIEW to remove a view.")},
244 	{RELKIND_MATVIEW,
245 		ERRCODE_UNDEFINED_TABLE,
246 		gettext_noop("materialized view \"%s\" does not exist"),
247 		gettext_noop("materialized view \"%s\" does not exist, skipping"),
248 		gettext_noop("\"%s\" is not a materialized view"),
249 	gettext_noop("Use DROP MATERIALIZED VIEW to remove a materialized view.")},
250 	{RELKIND_INDEX,
251 		ERRCODE_UNDEFINED_OBJECT,
252 		gettext_noop("index \"%s\" does not exist"),
253 		gettext_noop("index \"%s\" does not exist, skipping"),
254 		gettext_noop("\"%s\" is not an index"),
255 	gettext_noop("Use DROP INDEX to remove an index.")},
256 	{RELKIND_COMPOSITE_TYPE,
257 		ERRCODE_UNDEFINED_OBJECT,
258 		gettext_noop("type \"%s\" does not exist"),
259 		gettext_noop("type \"%s\" does not exist, skipping"),
260 		gettext_noop("\"%s\" is not a type"),
261 	gettext_noop("Use DROP TYPE to remove a type.")},
262 	{RELKIND_FOREIGN_TABLE,
263 		ERRCODE_UNDEFINED_OBJECT,
264 		gettext_noop("foreign table \"%s\" does not exist"),
265 		gettext_noop("foreign table \"%s\" does not exist, skipping"),
266 		gettext_noop("\"%s\" is not a foreign table"),
267 	gettext_noop("Use DROP FOREIGN TABLE to remove a foreign table.")},
268 	{RELKIND_PARTITIONED_TABLE,
269 		ERRCODE_UNDEFINED_TABLE,
270 		gettext_noop("table \"%s\" does not exist"),
271 		gettext_noop("table \"%s\" does not exist, skipping"),
272 		gettext_noop("\"%s\" is not a table"),
273 	gettext_noop("Use DROP TABLE to remove a table.")},
274 	{RELKIND_PARTITIONED_INDEX,
275 		ERRCODE_UNDEFINED_OBJECT,
276 		gettext_noop("index \"%s\" does not exist"),
277 		gettext_noop("index \"%s\" does not exist, skipping"),
278 		gettext_noop("\"%s\" is not an index"),
279 	gettext_noop("Use DROP INDEX to remove an index.")},
280 	{'\0', 0, NULL, NULL, NULL, NULL}
281 };
282 
283 struct DropRelationCallbackState
284 {
285 	char		relkind;
286 	Oid			heapOid;
287 	Oid			partParentOid;
288 	bool		concurrent;
289 };
290 
291 /* Alter table target-type flags for ATSimplePermissions */
292 #define		ATT_TABLE				0x0001
293 #define		ATT_VIEW				0x0002
294 #define		ATT_MATVIEW				0x0004
295 #define		ATT_INDEX				0x0008
296 #define		ATT_COMPOSITE_TYPE		0x0010
297 #define		ATT_FOREIGN_TABLE		0x0020
298 #define		ATT_PARTITIONED_INDEX	0x0040
299 
300 /*
301  * Partition tables are expected to be dropped when the parent partitioned
302  * table gets dropped. Hence for partitioning we use AUTO dependency.
303  * Otherwise, for regular inheritance use NORMAL dependency.
304  */
305 #define child_dependency_type(child_is_partition)	\
306 	((child_is_partition) ? DEPENDENCY_AUTO : DEPENDENCY_NORMAL)
307 
308 static void truncate_check_rel(Oid relid, Form_pg_class reltuple);
309 static void truncate_check_perms(Oid relid, Form_pg_class reltuple);
310 static void truncate_check_activity(Relation rel);
311 static void RangeVarCallbackForTruncate(const RangeVar *relation,
312 										Oid relId, Oid oldRelId, void *arg);
313 static List *MergeAttributes(List *schema, List *supers, char relpersistence,
314 							 bool is_partition, List **supconstr);
315 static bool MergeCheckConstraint(List *constraints, char *name, Node *expr);
316 static void MergeAttributesIntoExisting(Relation child_rel, Relation parent_rel);
317 static void MergeConstraintsIntoExisting(Relation child_rel, Relation parent_rel);
318 static void StoreCatalogInheritance(Oid relationId, List *supers,
319 									bool child_is_partition);
320 static void StoreCatalogInheritance1(Oid relationId, Oid parentOid,
321 									 int32 seqNumber, Relation inhRelation,
322 									 bool child_is_partition);
323 static int	findAttrByName(const char *attributeName, List *schema);
324 static void AlterIndexNamespaces(Relation classRel, Relation rel,
325 								 Oid oldNspOid, Oid newNspOid, ObjectAddresses *objsMoved);
326 static void AlterSeqNamespaces(Relation classRel, Relation rel,
327 							   Oid oldNspOid, Oid newNspOid, ObjectAddresses *objsMoved,
328 							   LOCKMODE lockmode);
329 static ObjectAddress ATExecAlterConstraint(Relation rel, AlterTableCmd *cmd,
330 										   bool recurse, bool recursing, LOCKMODE lockmode);
331 static bool ATExecAlterConstrRecurse(Constraint *cmdcon, Relation conrel, Relation tgrel,
332 									 Relation rel, HeapTuple contuple, List **otherrelids,
333 									 LOCKMODE lockmode);
334 static ObjectAddress ATExecValidateConstraint(List **wqueue,
335 											  Relation rel, char *constrName,
336 											  bool recurse, bool recursing, LOCKMODE lockmode);
337 static int	transformColumnNameList(Oid relId, List *colList,
338 									int16 *attnums, Oid *atttypids);
339 static int	transformFkeyGetPrimaryKey(Relation pkrel, Oid *indexOid,
340 									   List **attnamelist,
341 									   int16 *attnums, Oid *atttypids,
342 									   Oid *opclasses);
343 static Oid	transformFkeyCheckAttrs(Relation pkrel,
344 									int numattrs, int16 *attnums,
345 									Oid *opclasses);
346 static void checkFkeyPermissions(Relation rel, int16 *attnums, int natts);
347 static CoercionPathType findFkeyCast(Oid targetTypeId, Oid sourceTypeId,
348 									 Oid *funcid);
349 static void validateForeignKeyConstraint(char *conname,
350 										 Relation rel, Relation pkrel,
351 										 Oid pkindOid, Oid constraintOid);
352 static void ATController(AlterTableStmt *parsetree,
353 						 Relation rel, List *cmds, bool recurse, LOCKMODE lockmode,
354 						 AlterTableUtilityContext *context);
355 static void ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd,
356 					  bool recurse, bool recursing, LOCKMODE lockmode,
357 					  AlterTableUtilityContext *context);
358 static void ATRewriteCatalogs(List **wqueue, LOCKMODE lockmode,
359 							  AlterTableUtilityContext *context);
360 static void ATExecCmd(List **wqueue, AlteredTableInfo *tab, Relation rel,
361 					  AlterTableCmd *cmd, LOCKMODE lockmode, int cur_pass,
362 					  AlterTableUtilityContext *context);
363 static AlterTableCmd *ATParseTransformCmd(List **wqueue, AlteredTableInfo *tab,
364 										  Relation rel, AlterTableCmd *cmd,
365 										  bool recurse, LOCKMODE lockmode,
366 										  int cur_pass,
367 										  AlterTableUtilityContext *context);
368 static void ATRewriteTables(AlterTableStmt *parsetree,
369 							List **wqueue, LOCKMODE lockmode,
370 							AlterTableUtilityContext *context);
371 static void ATRewriteTable(AlteredTableInfo *tab, Oid OIDNewHeap, LOCKMODE lockmode);
372 static AlteredTableInfo *ATGetQueueEntry(List **wqueue, Relation rel);
373 static void ATSimplePermissions(Relation rel, int allowed_targets);
374 static void ATWrongRelkindError(Relation rel, int allowed_targets);
375 static void ATSimpleRecursion(List **wqueue, Relation rel,
376 							  AlterTableCmd *cmd, bool recurse, LOCKMODE lockmode,
377 							  AlterTableUtilityContext *context);
378 static void ATCheckPartitionsNotInUse(Relation rel, LOCKMODE lockmode);
379 static void ATTypedTableRecursion(List **wqueue, Relation rel, AlterTableCmd *cmd,
380 								  LOCKMODE lockmode,
381 								  AlterTableUtilityContext *context);
382 static List *find_typed_table_dependencies(Oid typeOid, const char *typeName,
383 										   DropBehavior behavior);
384 static void ATPrepAddColumn(List **wqueue, Relation rel, bool recurse, bool recursing,
385 							bool is_view, AlterTableCmd *cmd, LOCKMODE lockmode,
386 							AlterTableUtilityContext *context);
387 static ObjectAddress ATExecAddColumn(List **wqueue, AlteredTableInfo *tab,
388 									 Relation rel, AlterTableCmd **cmd,
389 									 bool recurse, bool recursing,
390 									 LOCKMODE lockmode, int cur_pass,
391 									 AlterTableUtilityContext *context);
392 static bool check_for_column_name_collision(Relation rel, const char *colname,
393 											bool if_not_exists);
394 static void add_column_datatype_dependency(Oid relid, int32 attnum, Oid typid);
395 static void add_column_collation_dependency(Oid relid, int32 attnum, Oid collid);
396 static void ATPrepDropNotNull(Relation rel, bool recurse, bool recursing);
397 static ObjectAddress ATExecDropNotNull(Relation rel, const char *colName, LOCKMODE lockmode);
398 static void ATPrepSetNotNull(List **wqueue, Relation rel,
399 							 AlterTableCmd *cmd, bool recurse, bool recursing,
400 							 LOCKMODE lockmode,
401 							 AlterTableUtilityContext *context);
402 static ObjectAddress ATExecSetNotNull(AlteredTableInfo *tab, Relation rel,
403 									  const char *colName, LOCKMODE lockmode);
404 static void ATExecCheckNotNull(AlteredTableInfo *tab, Relation rel,
405 							   const char *colName, LOCKMODE lockmode);
406 static bool NotNullImpliedByRelConstraints(Relation rel, Form_pg_attribute attr);
407 static bool ConstraintImpliedByRelConstraint(Relation scanrel,
408 											 List *testConstraint, List *provenConstraint);
409 static ObjectAddress ATExecColumnDefault(Relation rel, const char *colName,
410 										 Node *newDefault, LOCKMODE lockmode);
411 static ObjectAddress ATExecCookedColumnDefault(Relation rel, AttrNumber attnum,
412 											   Node *newDefault);
413 static ObjectAddress ATExecAddIdentity(Relation rel, const char *colName,
414 									   Node *def, LOCKMODE lockmode);
415 static ObjectAddress ATExecSetIdentity(Relation rel, const char *colName,
416 									   Node *def, LOCKMODE lockmode);
417 static ObjectAddress ATExecDropIdentity(Relation rel, const char *colName, bool missing_ok, LOCKMODE lockmode);
418 static void ATPrepDropExpression(Relation rel, AlterTableCmd *cmd, bool recurse, bool recursing, LOCKMODE lockmode);
419 static ObjectAddress ATExecDropExpression(Relation rel, const char *colName, bool missing_ok, LOCKMODE lockmode);
420 static ObjectAddress ATExecSetStatistics(Relation rel, const char *colName, int16 colNum,
421 										 Node *newValue, LOCKMODE lockmode);
422 static ObjectAddress ATExecSetOptions(Relation rel, const char *colName,
423 									  Node *options, bool isReset, LOCKMODE lockmode);
424 static ObjectAddress ATExecSetStorage(Relation rel, const char *colName,
425 									  Node *newValue, LOCKMODE lockmode);
426 static void ATPrepDropColumn(List **wqueue, Relation rel, bool recurse, bool recursing,
427 							 AlterTableCmd *cmd, LOCKMODE lockmode,
428 							 AlterTableUtilityContext *context);
429 static ObjectAddress ATExecDropColumn(List **wqueue, Relation rel, const char *colName,
430 									  DropBehavior behavior,
431 									  bool recurse, bool recursing,
432 									  bool missing_ok, LOCKMODE lockmode,
433 									  ObjectAddresses *addrs);
434 static ObjectAddress ATExecAddIndex(AlteredTableInfo *tab, Relation rel,
435 									IndexStmt *stmt, bool is_rebuild, LOCKMODE lockmode);
436 static ObjectAddress ATExecAddConstraint(List **wqueue,
437 										 AlteredTableInfo *tab, Relation rel,
438 										 Constraint *newConstraint, bool recurse, bool is_readd,
439 										 LOCKMODE lockmode);
440 static char *ChooseForeignKeyConstraintNameAddition(List *colnames);
441 static ObjectAddress ATExecAddIndexConstraint(AlteredTableInfo *tab, Relation rel,
442 											  IndexStmt *stmt, LOCKMODE lockmode);
443 static ObjectAddress ATAddCheckConstraint(List **wqueue,
444 										  AlteredTableInfo *tab, Relation rel,
445 										  Constraint *constr,
446 										  bool recurse, bool recursing, bool is_readd,
447 										  LOCKMODE lockmode);
448 static ObjectAddress ATAddForeignKeyConstraint(List **wqueue, AlteredTableInfo *tab,
449 											   Relation rel, Constraint *fkconstraint, Oid parentConstr,
450 											   bool recurse, bool recursing,
451 											   LOCKMODE lockmode);
452 static ObjectAddress addFkRecurseReferenced(List **wqueue, Constraint *fkconstraint,
453 											Relation rel, Relation pkrel, Oid indexOid, Oid parentConstr,
454 											int numfks, int16 *pkattnum, int16 *fkattnum,
455 											Oid *pfeqoperators, Oid *ppeqoperators, Oid *ffeqoperators,
456 											bool old_check_ok);
457 static void addFkRecurseReferencing(List **wqueue, Constraint *fkconstraint,
458 									Relation rel, Relation pkrel, Oid indexOid, Oid parentConstr,
459 									int numfks, int16 *pkattnum, int16 *fkattnum,
460 									Oid *pfeqoperators, Oid *ppeqoperators, Oid *ffeqoperators,
461 									bool old_check_ok, LOCKMODE lockmode);
462 static void CloneForeignKeyConstraints(List **wqueue, Relation parentRel,
463 									   Relation partitionRel);
464 static void CloneFkReferenced(Relation parentRel, Relation partitionRel);
465 static void CloneFkReferencing(List **wqueue, Relation parentRel,
466 							   Relation partRel);
467 static void createForeignKeyCheckTriggers(Oid myRelOid, Oid refRelOid,
468 										  Constraint *fkconstraint, Oid constraintOid,
469 										  Oid indexOid);
470 static void createForeignKeyActionTriggers(Relation rel, Oid refRelOid,
471 										   Constraint *fkconstraint, Oid constraintOid,
472 										   Oid indexOid);
473 static bool tryAttachPartitionForeignKey(ForeignKeyCacheInfo *fk,
474 										 Oid partRelid,
475 										 Oid parentConstrOid, int numfks,
476 										 AttrNumber *mapped_conkey, AttrNumber *confkey,
477 										 Oid *conpfeqop);
478 static void ATExecDropConstraint(Relation rel, const char *constrName,
479 								 DropBehavior behavior,
480 								 bool recurse, bool recursing,
481 								 bool missing_ok, LOCKMODE lockmode);
482 static void ATPrepAlterColumnType(List **wqueue,
483 								  AlteredTableInfo *tab, Relation rel,
484 								  bool recurse, bool recursing,
485 								  AlterTableCmd *cmd, LOCKMODE lockmode,
486 								  AlterTableUtilityContext *context);
487 static bool ATColumnChangeRequiresRewrite(Node *expr, AttrNumber varattno);
488 static ObjectAddress ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel,
489 										   AlterTableCmd *cmd, LOCKMODE lockmode);
490 static void RememberConstraintForRebuilding(Oid conoid, AlteredTableInfo *tab);
491 static void RememberIndexForRebuilding(Oid indoid, AlteredTableInfo *tab);
492 static void ATPostAlterTypeCleanup(List **wqueue, AlteredTableInfo *tab,
493 								   LOCKMODE lockmode);
494 static void ATPostAlterTypeParse(Oid oldId, Oid oldRelId, Oid refRelId,
495 								 char *cmd, List **wqueue, LOCKMODE lockmode,
496 								 bool rewrite);
497 static void RebuildConstraintComment(AlteredTableInfo *tab, int pass,
498 									 Oid objid, Relation rel, List *domname,
499 									 const char *conname);
500 static void TryReuseIndex(Oid oldId, IndexStmt *stmt);
501 static void TryReuseForeignKey(Oid oldId, Constraint *con);
502 static ObjectAddress ATExecAlterColumnGenericOptions(Relation rel, const char *colName,
503 													 List *options, LOCKMODE lockmode);
504 static void change_owner_fix_column_acls(Oid relationOid,
505 										 Oid oldOwnerId, Oid newOwnerId);
506 static void change_owner_recurse_to_sequences(Oid relationOid,
507 											  Oid newOwnerId, LOCKMODE lockmode);
508 static ObjectAddress ATExecClusterOn(Relation rel, const char *indexName,
509 									 LOCKMODE lockmode);
510 static void ATExecDropCluster(Relation rel, LOCKMODE lockmode);
511 static bool ATPrepChangePersistence(Relation rel, bool toLogged);
512 static void ATPrepSetTableSpace(AlteredTableInfo *tab, Relation rel,
513 								const char *tablespacename, LOCKMODE lockmode);
514 static void ATExecSetTableSpace(Oid tableOid, Oid newTableSpace, LOCKMODE lockmode);
515 static void ATExecSetTableSpaceNoStorage(Relation rel, Oid newTableSpace);
516 static void ATExecSetRelOptions(Relation rel, List *defList,
517 								AlterTableType operation,
518 								LOCKMODE lockmode);
519 static void ATExecEnableDisableTrigger(Relation rel, const char *trigname,
520 									   char fires_when, bool skip_system, LOCKMODE lockmode);
521 static void ATExecEnableDisableRule(Relation rel, const char *rulename,
522 									char fires_when, LOCKMODE lockmode);
523 static void ATPrepAddInherit(Relation child_rel);
524 static ObjectAddress ATExecAddInherit(Relation child_rel, RangeVar *parent, LOCKMODE lockmode);
525 static ObjectAddress ATExecDropInherit(Relation rel, RangeVar *parent, LOCKMODE lockmode);
526 static void drop_parent_dependency(Oid relid, Oid refclassid, Oid refobjid,
527 								   DependencyType deptype);
528 static ObjectAddress ATExecAddOf(Relation rel, const TypeName *ofTypename, LOCKMODE lockmode);
529 static void ATExecDropOf(Relation rel, LOCKMODE lockmode);
530 static void ATExecReplicaIdentity(Relation rel, ReplicaIdentityStmt *stmt, LOCKMODE lockmode);
531 static void ATExecGenericOptions(Relation rel, List *options);
532 static void ATExecEnableRowSecurity(Relation rel);
533 static void ATExecDisableRowSecurity(Relation rel);
534 static void ATExecForceNoForceRowSecurity(Relation rel, bool force_rls);
535 
536 static void index_copy_data(Relation rel, RelFileNode newrnode);
537 static const char *storage_name(char c);
538 
539 static void RangeVarCallbackForDropRelation(const RangeVar *rel, Oid relOid,
540 											Oid oldRelOid, void *arg);
541 static void RangeVarCallbackForAlterRelation(const RangeVar *rv, Oid relid,
542 											 Oid oldrelid, void *arg);
543 static PartitionSpec *transformPartitionSpec(Relation rel, PartitionSpec *partspec, char *strategy);
544 static void ComputePartitionAttrs(ParseState *pstate, Relation rel, List *partParams, AttrNumber *partattrs,
545 								  List **partexprs, Oid *partopclass, Oid *partcollation, char strategy);
546 static void CreateInheritance(Relation child_rel, Relation parent_rel);
547 static void RemoveInheritance(Relation child_rel, Relation parent_rel);
548 static ObjectAddress ATExecAttachPartition(List **wqueue, Relation rel,
549 										   PartitionCmd *cmd);
550 static void AttachPartitionEnsureIndexes(Relation rel, Relation attachrel);
551 static void QueuePartitionConstraintValidation(List **wqueue, Relation scanrel,
552 											   List *partConstraint,
553 											   bool validate_default);
554 static void CloneRowTriggersToPartition(Relation parent, Relation partition);
555 static void DropClonedTriggersFromPartition(Oid partitionId);
556 static ObjectAddress ATExecDetachPartition(Relation rel, RangeVar *name);
557 static ObjectAddress ATExecAttachPartitionIdx(List **wqueue, Relation rel,
558 											  RangeVar *name);
559 static void validatePartitionedIndex(Relation partedIdx, Relation partedTbl);
560 static void refuseDupeIndexAttach(Relation parentIdx, Relation partIdx,
561 								  Relation partitionTbl);
562 static List *GetParentedForeignKeyRefs(Relation partition);
563 static void ATDetachCheckNoForeignKeyRefs(Relation partition);
564 
565 
566 /* ----------------------------------------------------------------
567  *		DefineRelation
568  *				Creates a new relation.
569  *
570  * stmt carries parsetree information from an ordinary CREATE TABLE statement.
571  * The other arguments are used to extend the behavior for other cases:
572  * relkind: relkind to assign to the new relation
573  * ownerId: if not InvalidOid, use this as the new relation's owner.
574  * typaddress: if not null, it's set to the pg_type entry's address.
575  * queryString: for error reporting
576  *
577  * Note that permissions checks are done against current user regardless of
578  * ownerId.  A nonzero ownerId is used when someone is creating a relation
579  * "on behalf of" someone else, so we still want to see that the current user
580  * has permissions to do it.
581  *
582  * If successful, returns the address of the new relation.
583  * ----------------------------------------------------------------
584  */
585 ObjectAddress
DefineRelation(CreateStmt * stmt,char relkind,Oid ownerId,ObjectAddress * typaddress,const char * queryString)586 DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId,
587 			   ObjectAddress *typaddress, const char *queryString)
588 {
589 	char		relname[NAMEDATALEN];
590 	Oid			namespaceId;
591 	Oid			relationId;
592 	Oid			tablespaceId;
593 	Relation	rel;
594 	TupleDesc	descriptor;
595 	List	   *inheritOids;
596 	List	   *old_constraints;
597 	List	   *rawDefaults;
598 	List	   *cookedDefaults;
599 	Datum		reloptions;
600 	ListCell   *listptr;
601 	AttrNumber	attnum;
602 	bool		partitioned;
603 	static char *validnsps[] = HEAP_RELOPT_NAMESPACES;
604 	Oid			ofTypeId;
605 	ObjectAddress address;
606 	LOCKMODE	parentLockmode;
607 	const char *accessMethod = NULL;
608 	Oid			accessMethodId = InvalidOid;
609 
610 	/*
611 	 * Truncate relname to appropriate length (probably a waste of time, as
612 	 * parser should have done this already).
613 	 */
614 	StrNCpy(relname, stmt->relation->relname, NAMEDATALEN);
615 
616 	/*
617 	 * Check consistency of arguments
618 	 */
619 	if (stmt->oncommit != ONCOMMIT_NOOP
620 		&& stmt->relation->relpersistence != RELPERSISTENCE_TEMP)
621 		ereport(ERROR,
622 				(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
623 				 errmsg("ON COMMIT can only be used on temporary tables")));
624 
625 	if (stmt->partspec != NULL)
626 	{
627 		if (relkind != RELKIND_RELATION)
628 			elog(ERROR, "unexpected relkind: %d", (int) relkind);
629 
630 		relkind = RELKIND_PARTITIONED_TABLE;
631 		partitioned = true;
632 	}
633 	else
634 		partitioned = false;
635 
636 	/*
637 	 * Look up the namespace in which we are supposed to create the relation,
638 	 * check we have permission to create there, lock it against concurrent
639 	 * drop, and mark stmt->relation as RELPERSISTENCE_TEMP if a temporary
640 	 * namespace is selected.
641 	 */
642 	namespaceId =
643 		RangeVarGetAndCheckCreationNamespace(stmt->relation, NoLock, NULL);
644 
645 	/*
646 	 * Security check: disallow creating temp tables from security-restricted
647 	 * code.  This is needed because calling code might not expect untrusted
648 	 * tables to appear in pg_temp at the front of its search path.
649 	 */
650 	if (stmt->relation->relpersistence == RELPERSISTENCE_TEMP
651 		&& InSecurityRestrictedOperation())
652 		ereport(ERROR,
653 				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
654 				 errmsg("cannot create temporary table within security-restricted operation")));
655 
656 	/*
657 	 * Determine the lockmode to use when scanning parents.  A self-exclusive
658 	 * lock is needed here.
659 	 *
660 	 * For regular inheritance, if two backends attempt to add children to the
661 	 * same parent simultaneously, and that parent has no pre-existing
662 	 * children, then both will attempt to update the parent's relhassubclass
663 	 * field, leading to a "tuple concurrently updated" error.  Also, this
664 	 * interlocks against a concurrent ANALYZE on the parent table, which
665 	 * might otherwise be attempting to clear the parent's relhassubclass
666 	 * field, if its previous children were recently dropped.
667 	 *
668 	 * If the child table is a partition, then we instead grab an exclusive
669 	 * lock on the parent because its partition descriptor will be changed by
670 	 * addition of the new partition.
671 	 */
672 	parentLockmode = (stmt->partbound != NULL ? AccessExclusiveLock :
673 					  ShareUpdateExclusiveLock);
674 
675 	/* Determine the list of OIDs of the parents. */
676 	inheritOids = NIL;
677 	foreach(listptr, stmt->inhRelations)
678 	{
679 		RangeVar   *rv = (RangeVar *) lfirst(listptr);
680 		Oid			parentOid;
681 
682 		parentOid = RangeVarGetRelid(rv, parentLockmode, false);
683 
684 		/*
685 		 * Reject duplications in the list of parents.
686 		 */
687 		if (list_member_oid(inheritOids, parentOid))
688 			ereport(ERROR,
689 					(errcode(ERRCODE_DUPLICATE_TABLE),
690 					 errmsg("relation \"%s\" would be inherited from more than once",
691 							get_rel_name(parentOid))));
692 
693 		inheritOids = lappend_oid(inheritOids, parentOid);
694 	}
695 
696 	/*
697 	 * Select tablespace to use: an explicitly indicated one, or (in the case
698 	 * of a partitioned table) the parent's, if it has one.
699 	 */
700 	if (stmt->tablespacename)
701 	{
702 		tablespaceId = get_tablespace_oid(stmt->tablespacename, false);
703 
704 		if (partitioned && tablespaceId == MyDatabaseTableSpace)
705 			ereport(ERROR,
706 					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
707 					 errmsg("cannot specify default tablespace for partitioned relations")));
708 	}
709 	else if (stmt->partbound)
710 	{
711 		/*
712 		 * For partitions, when no other tablespace is specified, we default
713 		 * the tablespace to the parent partitioned table's.
714 		 */
715 		Assert(list_length(inheritOids) == 1);
716 		tablespaceId = get_rel_tablespace(linitial_oid(inheritOids));
717 	}
718 	else
719 		tablespaceId = InvalidOid;
720 
721 	/* still nothing? use the default */
722 	if (!OidIsValid(tablespaceId))
723 		tablespaceId = GetDefaultTablespace(stmt->relation->relpersistence,
724 											partitioned);
725 
726 	/* Check permissions except when using database's default */
727 	if (OidIsValid(tablespaceId) && tablespaceId != MyDatabaseTableSpace)
728 	{
729 		AclResult	aclresult;
730 
731 		aclresult = pg_tablespace_aclcheck(tablespaceId, GetUserId(),
732 										   ACL_CREATE);
733 		if (aclresult != ACLCHECK_OK)
734 			aclcheck_error(aclresult, OBJECT_TABLESPACE,
735 						   get_tablespace_name(tablespaceId));
736 	}
737 
738 	/* In all cases disallow placing user relations in pg_global */
739 	if (tablespaceId == GLOBALTABLESPACE_OID)
740 		ereport(ERROR,
741 				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
742 				 errmsg("only shared relations can be placed in pg_global tablespace")));
743 
744 	/* Identify user ID that will own the table */
745 	if (!OidIsValid(ownerId))
746 		ownerId = GetUserId();
747 
748 	/*
749 	 * Parse and validate reloptions, if any.
750 	 */
751 	reloptions = transformRelOptions((Datum) 0, stmt->options, NULL, validnsps,
752 									 true, false);
753 
754 	switch (relkind)
755 	{
756 		case RELKIND_VIEW:
757 			(void) view_reloptions(reloptions, true);
758 			break;
759 		case RELKIND_PARTITIONED_TABLE:
760 			(void) partitioned_table_reloptions(reloptions, true);
761 			break;
762 		default:
763 			(void) heap_reloptions(relkind, reloptions, true);
764 	}
765 
766 	if (stmt->ofTypename)
767 	{
768 		AclResult	aclresult;
769 
770 		ofTypeId = typenameTypeId(NULL, stmt->ofTypename);
771 
772 		aclresult = pg_type_aclcheck(ofTypeId, GetUserId(), ACL_USAGE);
773 		if (aclresult != ACLCHECK_OK)
774 			aclcheck_error_type(aclresult, ofTypeId);
775 	}
776 	else
777 		ofTypeId = InvalidOid;
778 
779 	/*
780 	 * Look up inheritance ancestors and generate relation schema, including
781 	 * inherited attributes.  (Note that stmt->tableElts is destructively
782 	 * modified by MergeAttributes.)
783 	 */
784 	stmt->tableElts =
785 		MergeAttributes(stmt->tableElts, inheritOids,
786 						stmt->relation->relpersistence,
787 						stmt->partbound != NULL,
788 						&old_constraints);
789 
790 	/*
791 	 * Create a tuple descriptor from the relation schema.  Note that this
792 	 * deals with column names, types, and NOT NULL constraints, but not
793 	 * default values or CHECK constraints; we handle those below.
794 	 */
795 	descriptor = BuildDescForRelation(stmt->tableElts);
796 
797 	/*
798 	 * Find columns with default values and prepare for insertion of the
799 	 * defaults.  Pre-cooked (that is, inherited) defaults go into a list of
800 	 * CookedConstraint structs that we'll pass to heap_create_with_catalog,
801 	 * while raw defaults go into a list of RawColumnDefault structs that will
802 	 * be processed by AddRelationNewConstraints.  (We can't deal with raw
803 	 * expressions until we can do transformExpr.)
804 	 *
805 	 * We can set the atthasdef flags now in the tuple descriptor; this just
806 	 * saves StoreAttrDefault from having to do an immediate update of the
807 	 * pg_attribute rows.
808 	 */
809 	rawDefaults = NIL;
810 	cookedDefaults = NIL;
811 	attnum = 0;
812 
813 	foreach(listptr, stmt->tableElts)
814 	{
815 		ColumnDef  *colDef = lfirst(listptr);
816 		Form_pg_attribute attr;
817 
818 		attnum++;
819 		attr = TupleDescAttr(descriptor, attnum - 1);
820 
821 		if (colDef->raw_default != NULL)
822 		{
823 			RawColumnDefault *rawEnt;
824 
825 			Assert(colDef->cooked_default == NULL);
826 
827 			rawEnt = (RawColumnDefault *) palloc(sizeof(RawColumnDefault));
828 			rawEnt->attnum = attnum;
829 			rawEnt->raw_default = colDef->raw_default;
830 			rawEnt->missingMode = false;
831 			rawEnt->generated = colDef->generated;
832 			rawDefaults = lappend(rawDefaults, rawEnt);
833 			attr->atthasdef = true;
834 		}
835 		else if (colDef->cooked_default != NULL)
836 		{
837 			CookedConstraint *cooked;
838 
839 			cooked = (CookedConstraint *) palloc(sizeof(CookedConstraint));
840 			cooked->contype = CONSTR_DEFAULT;
841 			cooked->conoid = InvalidOid;	/* until created */
842 			cooked->name = NULL;
843 			cooked->attnum = attnum;
844 			cooked->expr = colDef->cooked_default;
845 			cooked->skip_validation = false;
846 			cooked->is_local = true;	/* not used for defaults */
847 			cooked->inhcount = 0;	/* ditto */
848 			cooked->is_no_inherit = false;
849 			cookedDefaults = lappend(cookedDefaults, cooked);
850 			attr->atthasdef = true;
851 		}
852 
853 		if (colDef->identity)
854 			attr->attidentity = colDef->identity;
855 
856 		if (colDef->generated)
857 			attr->attgenerated = colDef->generated;
858 	}
859 
860 	/*
861 	 * If the statement hasn't specified an access method, but we're defining
862 	 * a type of relation that needs one, use the default.
863 	 */
864 	if (stmt->accessMethod != NULL)
865 	{
866 		accessMethod = stmt->accessMethod;
867 
868 		if (partitioned)
869 			ereport(ERROR,
870 					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
871 					 errmsg("specifying a table access method is not supported on a partitioned table")));
872 
873 	}
874 	else if (relkind == RELKIND_RELATION ||
875 			 relkind == RELKIND_TOASTVALUE ||
876 			 relkind == RELKIND_MATVIEW)
877 		accessMethod = default_table_access_method;
878 
879 	/* look up the access method, verify it is for a table */
880 	if (accessMethod != NULL)
881 		accessMethodId = get_table_am_oid(accessMethod, false);
882 
883 	/*
884 	 * Create the relation.  Inherited defaults and constraints are passed in
885 	 * for immediate handling --- since they don't need parsing, they can be
886 	 * stored immediately.
887 	 */
888 	relationId = heap_create_with_catalog(relname,
889 										  namespaceId,
890 										  tablespaceId,
891 										  InvalidOid,
892 										  InvalidOid,
893 										  ofTypeId,
894 										  ownerId,
895 										  accessMethodId,
896 										  descriptor,
897 										  list_concat(cookedDefaults,
898 													  old_constraints),
899 										  relkind,
900 										  stmt->relation->relpersistence,
901 										  false,
902 										  false,
903 										  stmt->oncommit,
904 										  reloptions,
905 										  true,
906 										  allowSystemTableMods,
907 										  false,
908 										  InvalidOid,
909 										  typaddress);
910 
911 	/*
912 	 * We must bump the command counter to make the newly-created relation
913 	 * tuple visible for opening.
914 	 */
915 	CommandCounterIncrement();
916 
917 	/*
918 	 * Open the new relation and acquire exclusive lock on it.  This isn't
919 	 * really necessary for locking out other backends (since they can't see
920 	 * the new rel anyway until we commit), but it keeps the lock manager from
921 	 * complaining about deadlock risks.
922 	 */
923 	rel = relation_open(relationId, AccessExclusiveLock);
924 
925 	/*
926 	 * Now add any newly specified column default and generation expressions
927 	 * to the new relation.  These are passed to us in the form of raw
928 	 * parsetrees; we need to transform them to executable expression trees
929 	 * before they can be added. The most convenient way to do that is to
930 	 * apply the parser's transformExpr routine, but transformExpr doesn't
931 	 * work unless we have a pre-existing relation. So, the transformation has
932 	 * to be postponed to this final step of CREATE TABLE.
933 	 *
934 	 * This needs to be before processing the partitioning clauses because
935 	 * those could refer to generated columns.
936 	 */
937 	if (rawDefaults)
938 		AddRelationNewConstraints(rel, rawDefaults, NIL,
939 								  true, true, false, queryString);
940 
941 	/*
942 	 * Make column generation expressions visible for use by partitioning.
943 	 */
944 	CommandCounterIncrement();
945 
946 	/* Process and store partition bound, if any. */
947 	if (stmt->partbound)
948 	{
949 		PartitionBoundSpec *bound;
950 		ParseState *pstate;
951 		Oid			parentId = linitial_oid(inheritOids),
952 					defaultPartOid;
953 		Relation	parent,
954 					defaultRel = NULL;
955 		ParseNamespaceItem *nsitem;
956 
957 		/* Already have strong enough lock on the parent */
958 		parent = table_open(parentId, NoLock);
959 
960 		/*
961 		 * We are going to try to validate the partition bound specification
962 		 * against the partition key of parentRel, so it better have one.
963 		 */
964 		if (parent->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
965 			ereport(ERROR,
966 					(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
967 					 errmsg("\"%s\" is not partitioned",
968 							RelationGetRelationName(parent))));
969 
970 		/*
971 		 * The partition constraint of the default partition depends on the
972 		 * partition bounds of every other partition. It is possible that
973 		 * another backend might be about to execute a query on the default
974 		 * partition table, and that the query relies on previously cached
975 		 * default partition constraints. We must therefore take a table lock
976 		 * strong enough to prevent all queries on the default partition from
977 		 * proceeding until we commit and send out a shared-cache-inval notice
978 		 * that will make them update their index lists.
979 		 *
980 		 * Order of locking: The relation being added won't be visible to
981 		 * other backends until it is committed, hence here in
982 		 * DefineRelation() the order of locking the default partition and the
983 		 * relation being added does not matter. But at all other places we
984 		 * need to lock the default relation before we lock the relation being
985 		 * added or removed i.e. we should take the lock in same order at all
986 		 * the places such that lock parent, lock default partition and then
987 		 * lock the partition so as to avoid a deadlock.
988 		 */
989 		defaultPartOid =
990 			get_default_oid_from_partdesc(RelationGetPartitionDesc(parent));
991 		if (OidIsValid(defaultPartOid))
992 			defaultRel = table_open(defaultPartOid, AccessExclusiveLock);
993 
994 		/* Transform the bound values */
995 		pstate = make_parsestate(NULL);
996 		pstate->p_sourcetext = queryString;
997 
998 		/*
999 		 * Add an nsitem containing this relation, so that transformExpr
1000 		 * called on partition bound expressions is able to report errors
1001 		 * using a proper context.
1002 		 */
1003 		nsitem = addRangeTableEntryForRelation(pstate, rel, AccessShareLock,
1004 											   NULL, false, false);
1005 		addNSItemToQuery(pstate, nsitem, false, true, true);
1006 
1007 		bound = transformPartitionBound(pstate, parent, stmt->partbound);
1008 
1009 		/*
1010 		 * Check first that the new partition's bound is valid and does not
1011 		 * overlap with any of existing partitions of the parent.
1012 		 */
1013 		check_new_partition_bound(relname, parent, bound);
1014 
1015 		/*
1016 		 * If the default partition exists, its partition constraints will
1017 		 * change after the addition of this new partition such that it won't
1018 		 * allow any row that qualifies for this new partition. So, check that
1019 		 * the existing data in the default partition satisfies the constraint
1020 		 * as it will exist after adding this partition.
1021 		 */
1022 		if (OidIsValid(defaultPartOid))
1023 		{
1024 			check_default_partition_contents(parent, defaultRel, bound);
1025 			/* Keep the lock until commit. */
1026 			table_close(defaultRel, NoLock);
1027 		}
1028 
1029 		/* Update the pg_class entry. */
1030 		StorePartitionBound(rel, parent, bound);
1031 
1032 		table_close(parent, NoLock);
1033 	}
1034 
1035 	/* Store inheritance information for new rel. */
1036 	StoreCatalogInheritance(relationId, inheritOids, stmt->partbound != NULL);
1037 
1038 	/*
1039 	 * Process the partitioning specification (if any) and store the partition
1040 	 * key information into the catalog.
1041 	 */
1042 	if (partitioned)
1043 	{
1044 		ParseState *pstate;
1045 		char		strategy;
1046 		int			partnatts;
1047 		AttrNumber	partattrs[PARTITION_MAX_KEYS];
1048 		Oid			partopclass[PARTITION_MAX_KEYS];
1049 		Oid			partcollation[PARTITION_MAX_KEYS];
1050 		List	   *partexprs = NIL;
1051 
1052 		pstate = make_parsestate(NULL);
1053 		pstate->p_sourcetext = queryString;
1054 
1055 		partnatts = list_length(stmt->partspec->partParams);
1056 
1057 		/* Protect fixed-size arrays here and in executor */
1058 		if (partnatts > PARTITION_MAX_KEYS)
1059 			ereport(ERROR,
1060 					(errcode(ERRCODE_TOO_MANY_COLUMNS),
1061 					 errmsg("cannot partition using more than %d columns",
1062 							PARTITION_MAX_KEYS)));
1063 
1064 		/*
1065 		 * We need to transform the raw parsetrees corresponding to partition
1066 		 * expressions into executable expression trees.  Like column defaults
1067 		 * and CHECK constraints, we could not have done the transformation
1068 		 * earlier.
1069 		 */
1070 		stmt->partspec = transformPartitionSpec(rel, stmt->partspec,
1071 												&strategy);
1072 
1073 		ComputePartitionAttrs(pstate, rel, stmt->partspec->partParams,
1074 							  partattrs, &partexprs, partopclass,
1075 							  partcollation, strategy);
1076 
1077 		StorePartitionKey(rel, strategy, partnatts, partattrs, partexprs,
1078 						  partopclass, partcollation);
1079 
1080 		/* make it all visible */
1081 		CommandCounterIncrement();
1082 	}
1083 
1084 	/*
1085 	 * If we're creating a partition, create now all the indexes, triggers,
1086 	 * FKs defined in the parent.
1087 	 *
1088 	 * We can't do it earlier, because DefineIndex wants to know the partition
1089 	 * key which we just stored.
1090 	 */
1091 	if (stmt->partbound)
1092 	{
1093 		Oid			parentId = linitial_oid(inheritOids);
1094 		Relation	parent;
1095 		List	   *idxlist;
1096 		ListCell   *cell;
1097 
1098 		/* Already have strong enough lock on the parent */
1099 		parent = table_open(parentId, NoLock);
1100 		idxlist = RelationGetIndexList(parent);
1101 
1102 		/*
1103 		 * For each index in the parent table, create one in the partition
1104 		 */
1105 		foreach(cell, idxlist)
1106 		{
1107 			Relation	idxRel = index_open(lfirst_oid(cell), AccessShareLock);
1108 			AttrMap    *attmap;
1109 			IndexStmt  *idxstmt;
1110 			Oid			constraintOid;
1111 
1112 			if (rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
1113 			{
1114 				if (idxRel->rd_index->indisunique)
1115 					ereport(ERROR,
1116 							(errcode(ERRCODE_WRONG_OBJECT_TYPE),
1117 							 errmsg("cannot create foreign partition of partitioned table \"%s\"",
1118 									RelationGetRelationName(parent)),
1119 							 errdetail("Table \"%s\" contains indexes that are unique.",
1120 									   RelationGetRelationName(parent))));
1121 				else
1122 				{
1123 					index_close(idxRel, AccessShareLock);
1124 					continue;
1125 				}
1126 			}
1127 
1128 			attmap = build_attrmap_by_name(RelationGetDescr(rel),
1129 										   RelationGetDescr(parent));
1130 			idxstmt =
1131 				generateClonedIndexStmt(NULL, idxRel,
1132 										attmap, &constraintOid);
1133 			DefineIndex(RelationGetRelid(rel),
1134 						idxstmt,
1135 						InvalidOid,
1136 						RelationGetRelid(idxRel),
1137 						constraintOid,
1138 						false, false, false, false, false);
1139 
1140 			index_close(idxRel, AccessShareLock);
1141 		}
1142 
1143 		list_free(idxlist);
1144 
1145 		/*
1146 		 * If there are any row-level triggers, clone them to the new
1147 		 * partition.
1148 		 */
1149 		if (parent->trigdesc != NULL)
1150 			CloneRowTriggersToPartition(parent, rel);
1151 
1152 		/*
1153 		 * And foreign keys too.  Note that because we're freshly creating the
1154 		 * table, there is no need to verify these new constraints.
1155 		 */
1156 		CloneForeignKeyConstraints(NULL, parent, rel);
1157 
1158 		table_close(parent, NoLock);
1159 	}
1160 
1161 	/*
1162 	 * Now add any newly specified CHECK constraints to the new relation. Same
1163 	 * as for defaults above, but these need to come after partitioning is set
1164 	 * up.
1165 	 */
1166 	if (stmt->constraints)
1167 		AddRelationNewConstraints(rel, NIL, stmt->constraints,
1168 								  true, true, false, queryString);
1169 
1170 	ObjectAddressSet(address, RelationRelationId, relationId);
1171 
1172 	/*
1173 	 * Clean up.  We keep lock on new relation (although it shouldn't be
1174 	 * visible to anyone else anyway, until commit).
1175 	 */
1176 	relation_close(rel, NoLock);
1177 
1178 	return address;
1179 }
1180 
1181 /*
1182  * Emit the right error or warning message for a "DROP" command issued on a
1183  * non-existent relation
1184  */
1185 static void
DropErrorMsgNonExistent(RangeVar * rel,char rightkind,bool missing_ok)1186 DropErrorMsgNonExistent(RangeVar *rel, char rightkind, bool missing_ok)
1187 {
1188 	const struct dropmsgstrings *rentry;
1189 
1190 	if (rel->schemaname != NULL &&
1191 		!OidIsValid(LookupNamespaceNoError(rel->schemaname)))
1192 	{
1193 		if (!missing_ok)
1194 		{
1195 			ereport(ERROR,
1196 					(errcode(ERRCODE_UNDEFINED_SCHEMA),
1197 					 errmsg("schema \"%s\" does not exist", rel->schemaname)));
1198 		}
1199 		else
1200 		{
1201 			ereport(NOTICE,
1202 					(errmsg("schema \"%s\" does not exist, skipping",
1203 							rel->schemaname)));
1204 		}
1205 		return;
1206 	}
1207 
1208 	for (rentry = dropmsgstringarray; rentry->kind != '\0'; rentry++)
1209 	{
1210 		if (rentry->kind == rightkind)
1211 		{
1212 			if (!missing_ok)
1213 			{
1214 				ereport(ERROR,
1215 						(errcode(rentry->nonexistent_code),
1216 						 errmsg(rentry->nonexistent_msg, rel->relname)));
1217 			}
1218 			else
1219 			{
1220 				ereport(NOTICE, (errmsg(rentry->skipping_msg, rel->relname)));
1221 				break;
1222 			}
1223 		}
1224 	}
1225 
1226 	Assert(rentry->kind != '\0');	/* Should be impossible */
1227 }
1228 
1229 /*
1230  * Emit the right error message for a "DROP" command issued on a
1231  * relation of the wrong type
1232  */
1233 static void
DropErrorMsgWrongType(const char * relname,char wrongkind,char rightkind)1234 DropErrorMsgWrongType(const char *relname, char wrongkind, char rightkind)
1235 {
1236 	const struct dropmsgstrings *rentry;
1237 	const struct dropmsgstrings *wentry;
1238 
1239 	for (rentry = dropmsgstringarray; rentry->kind != '\0'; rentry++)
1240 		if (rentry->kind == rightkind)
1241 			break;
1242 	Assert(rentry->kind != '\0');
1243 
1244 	for (wentry = dropmsgstringarray; wentry->kind != '\0'; wentry++)
1245 		if (wentry->kind == wrongkind)
1246 			break;
1247 	/* wrongkind could be something we don't have in our table... */
1248 
1249 	ereport(ERROR,
1250 			(errcode(ERRCODE_WRONG_OBJECT_TYPE),
1251 			 errmsg(rentry->nota_msg, relname),
1252 			 (wentry->kind != '\0') ? errhint("%s", _(wentry->drophint_msg)) : 0));
1253 }
1254 
1255 /*
1256  * RemoveRelations
1257  *		Implements DROP TABLE, DROP INDEX, DROP SEQUENCE, DROP VIEW,
1258  *		DROP MATERIALIZED VIEW, DROP FOREIGN TABLE
1259  */
1260 void
RemoveRelations(DropStmt * drop)1261 RemoveRelations(DropStmt *drop)
1262 {
1263 	ObjectAddresses *objects;
1264 	char		relkind;
1265 	ListCell   *cell;
1266 	int			flags = 0;
1267 	LOCKMODE	lockmode = AccessExclusiveLock;
1268 
1269 	/* DROP CONCURRENTLY uses a weaker lock, and has some restrictions */
1270 	if (drop->concurrent)
1271 	{
1272 		/*
1273 		 * Note that for temporary relations this lock may get upgraded later
1274 		 * on, but as no other session can access a temporary relation, this
1275 		 * is actually fine.
1276 		 */
1277 		lockmode = ShareUpdateExclusiveLock;
1278 		Assert(drop->removeType == OBJECT_INDEX);
1279 		if (list_length(drop->objects) != 1)
1280 			ereport(ERROR,
1281 					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1282 					 errmsg("DROP INDEX CONCURRENTLY does not support dropping multiple objects")));
1283 		if (drop->behavior == DROP_CASCADE)
1284 			ereport(ERROR,
1285 					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1286 					 errmsg("DROP INDEX CONCURRENTLY does not support CASCADE")));
1287 	}
1288 
1289 	/*
1290 	 * First we identify all the relations, then we delete them in a single
1291 	 * performMultipleDeletions() call.  This is to avoid unwanted DROP
1292 	 * RESTRICT errors if one of the relations depends on another.
1293 	 */
1294 
1295 	/* Determine required relkind */
1296 	switch (drop->removeType)
1297 	{
1298 		case OBJECT_TABLE:
1299 			relkind = RELKIND_RELATION;
1300 			break;
1301 
1302 		case OBJECT_INDEX:
1303 			relkind = RELKIND_INDEX;
1304 			break;
1305 
1306 		case OBJECT_SEQUENCE:
1307 			relkind = RELKIND_SEQUENCE;
1308 			break;
1309 
1310 		case OBJECT_VIEW:
1311 			relkind = RELKIND_VIEW;
1312 			break;
1313 
1314 		case OBJECT_MATVIEW:
1315 			relkind = RELKIND_MATVIEW;
1316 			break;
1317 
1318 		case OBJECT_FOREIGN_TABLE:
1319 			relkind = RELKIND_FOREIGN_TABLE;
1320 			break;
1321 
1322 		default:
1323 			elog(ERROR, "unrecognized drop object type: %d",
1324 				 (int) drop->removeType);
1325 			relkind = 0;		/* keep compiler quiet */
1326 			break;
1327 	}
1328 
1329 	/* Lock and validate each relation; build a list of object addresses */
1330 	objects = new_object_addresses();
1331 
1332 	foreach(cell, drop->objects)
1333 	{
1334 		RangeVar   *rel = makeRangeVarFromNameList((List *) lfirst(cell));
1335 		Oid			relOid;
1336 		ObjectAddress obj;
1337 		struct DropRelationCallbackState state;
1338 
1339 		/*
1340 		 * These next few steps are a great deal like relation_openrv, but we
1341 		 * don't bother building a relcache entry since we don't need it.
1342 		 *
1343 		 * Check for shared-cache-inval messages before trying to access the
1344 		 * relation.  This is needed to cover the case where the name
1345 		 * identifies a rel that has been dropped and recreated since the
1346 		 * start of our transaction: if we don't flush the old syscache entry,
1347 		 * then we'll latch onto that entry and suffer an error later.
1348 		 */
1349 		AcceptInvalidationMessages();
1350 
1351 		/* Look up the appropriate relation using namespace search. */
1352 		state.relkind = relkind;
1353 		state.heapOid = InvalidOid;
1354 		state.partParentOid = InvalidOid;
1355 		state.concurrent = drop->concurrent;
1356 		relOid = RangeVarGetRelidExtended(rel, lockmode, RVR_MISSING_OK,
1357 										  RangeVarCallbackForDropRelation,
1358 										  (void *) &state);
1359 
1360 		/* Not there? */
1361 		if (!OidIsValid(relOid))
1362 		{
1363 			DropErrorMsgNonExistent(rel, relkind, drop->missing_ok);
1364 			continue;
1365 		}
1366 
1367 		/*
1368 		 * Decide if concurrent mode needs to be used here or not.  The
1369 		 * relation persistence cannot be known without its OID.
1370 		 */
1371 		if (drop->concurrent &&
1372 			get_rel_persistence(relOid) != RELPERSISTENCE_TEMP)
1373 		{
1374 			Assert(list_length(drop->objects) == 1 &&
1375 				   drop->removeType == OBJECT_INDEX);
1376 			flags |= PERFORM_DELETION_CONCURRENTLY;
1377 		}
1378 
1379 		/*
1380 		 * Concurrent index drop cannot be used with partitioned indexes,
1381 		 * either.
1382 		 */
1383 		if ((flags & PERFORM_DELETION_CONCURRENTLY) != 0 &&
1384 			get_rel_relkind(relOid) == RELKIND_PARTITIONED_INDEX)
1385 			ereport(ERROR,
1386 					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1387 					 errmsg("cannot drop partitioned index \"%s\" concurrently",
1388 							rel->relname)));
1389 
1390 		/* OK, we're ready to delete this one */
1391 		obj.classId = RelationRelationId;
1392 		obj.objectId = relOid;
1393 		obj.objectSubId = 0;
1394 
1395 		add_exact_object_address(&obj, objects);
1396 	}
1397 
1398 	performMultipleDeletions(objects, drop->behavior, flags);
1399 
1400 	free_object_addresses(objects);
1401 }
1402 
1403 /*
1404  * Before acquiring a table lock, check whether we have sufficient rights.
1405  * In the case of DROP INDEX, also try to lock the table before the index.
1406  * Also, if the table to be dropped is a partition, we try to lock the parent
1407  * first.
1408  */
1409 static void
RangeVarCallbackForDropRelation(const RangeVar * rel,Oid relOid,Oid oldRelOid,void * arg)1410 RangeVarCallbackForDropRelation(const RangeVar *rel, Oid relOid, Oid oldRelOid,
1411 								void *arg)
1412 {
1413 	HeapTuple	tuple;
1414 	struct DropRelationCallbackState *state;
1415 	char		relkind;
1416 	char		expected_relkind;
1417 	bool		is_partition;
1418 	Form_pg_class classform;
1419 	LOCKMODE	heap_lockmode;
1420 	bool		invalid_system_index = false;
1421 
1422 	state = (struct DropRelationCallbackState *) arg;
1423 	relkind = state->relkind;
1424 	heap_lockmode = state->concurrent ?
1425 		ShareUpdateExclusiveLock : AccessExclusiveLock;
1426 
1427 	/*
1428 	 * If we previously locked some other index's heap, and the name we're
1429 	 * looking up no longer refers to that relation, release the now-useless
1430 	 * lock.
1431 	 */
1432 	if (relOid != oldRelOid && OidIsValid(state->heapOid))
1433 	{
1434 		UnlockRelationOid(state->heapOid, heap_lockmode);
1435 		state->heapOid = InvalidOid;
1436 	}
1437 
1438 	/*
1439 	 * Similarly, if we previously locked some other partition's heap, and the
1440 	 * name we're looking up no longer refers to that relation, release the
1441 	 * now-useless lock.
1442 	 */
1443 	if (relOid != oldRelOid && OidIsValid(state->partParentOid))
1444 	{
1445 		UnlockRelationOid(state->partParentOid, AccessExclusiveLock);
1446 		state->partParentOid = InvalidOid;
1447 	}
1448 
1449 	/* Didn't find a relation, so no need for locking or permission checks. */
1450 	if (!OidIsValid(relOid))
1451 		return;
1452 
1453 	tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relOid));
1454 	if (!HeapTupleIsValid(tuple))
1455 		return;					/* concurrently dropped, so nothing to do */
1456 	classform = (Form_pg_class) GETSTRUCT(tuple);
1457 	is_partition = classform->relispartition;
1458 
1459 	/*
1460 	 * Both RELKIND_RELATION and RELKIND_PARTITIONED_TABLE are OBJECT_TABLE,
1461 	 * but RemoveRelations() can only pass one relkind for a given relation.
1462 	 * It chooses RELKIND_RELATION for both regular and partitioned tables.
1463 	 * That means we must be careful before giving the wrong type error when
1464 	 * the relation is RELKIND_PARTITIONED_TABLE.  An equivalent problem
1465 	 * exists with indexes.
1466 	 */
1467 	if (classform->relkind == RELKIND_PARTITIONED_TABLE)
1468 		expected_relkind = RELKIND_RELATION;
1469 	else if (classform->relkind == RELKIND_PARTITIONED_INDEX)
1470 		expected_relkind = RELKIND_INDEX;
1471 	else
1472 		expected_relkind = classform->relkind;
1473 
1474 	if (relkind != expected_relkind)
1475 		DropErrorMsgWrongType(rel->relname, classform->relkind, relkind);
1476 
1477 	/* Allow DROP to either table owner or schema owner */
1478 	if (!pg_class_ownercheck(relOid, GetUserId()) &&
1479 		!pg_namespace_ownercheck(classform->relnamespace, GetUserId()))
1480 		aclcheck_error(ACLCHECK_NOT_OWNER, get_relkind_objtype(get_rel_relkind(relOid)),
1481 					   rel->relname);
1482 
1483 	/*
1484 	 * Check the case of a system index that might have been invalidated by a
1485 	 * failed concurrent process and allow its drop. For the time being, this
1486 	 * only concerns indexes of toast relations that became invalid during a
1487 	 * REINDEX CONCURRENTLY process.
1488 	 */
1489 	if (IsSystemClass(relOid, classform) && relkind == RELKIND_INDEX)
1490 	{
1491 		HeapTuple	locTuple;
1492 		Form_pg_index indexform;
1493 		bool		indisvalid;
1494 
1495 		locTuple = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(relOid));
1496 		if (!HeapTupleIsValid(locTuple))
1497 		{
1498 			ReleaseSysCache(tuple);
1499 			return;
1500 		}
1501 
1502 		indexform = (Form_pg_index) GETSTRUCT(locTuple);
1503 		indisvalid = indexform->indisvalid;
1504 		ReleaseSysCache(locTuple);
1505 
1506 		/* Mark object as being an invalid index of system catalogs */
1507 		if (!indisvalid)
1508 			invalid_system_index = true;
1509 	}
1510 
1511 	/* In the case of an invalid index, it is fine to bypass this check */
1512 	if (!invalid_system_index && !allowSystemTableMods && IsSystemClass(relOid, classform))
1513 		ereport(ERROR,
1514 				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1515 				 errmsg("permission denied: \"%s\" is a system catalog",
1516 						rel->relname)));
1517 
1518 	ReleaseSysCache(tuple);
1519 
1520 	/*
1521 	 * In DROP INDEX, attempt to acquire lock on the parent table before
1522 	 * locking the index.  index_drop() will need this anyway, and since
1523 	 * regular queries lock tables before their indexes, we risk deadlock if
1524 	 * we do it the other way around.  No error if we don't find a pg_index
1525 	 * entry, though --- the relation may have been dropped.
1526 	 */
1527 	if ((relkind == RELKIND_INDEX || relkind == RELKIND_PARTITIONED_INDEX) &&
1528 		relOid != oldRelOid)
1529 	{
1530 		state->heapOid = IndexGetRelation(relOid, true);
1531 		if (OidIsValid(state->heapOid))
1532 			LockRelationOid(state->heapOid, heap_lockmode);
1533 	}
1534 
1535 	/*
1536 	 * Similarly, if the relation is a partition, we must acquire lock on its
1537 	 * parent before locking the partition.  That's because queries lock the
1538 	 * parent before its partitions, so we risk deadlock it we do it the other
1539 	 * way around.
1540 	 */
1541 	if (is_partition && relOid != oldRelOid)
1542 	{
1543 		state->partParentOid = get_partition_parent(relOid);
1544 		if (OidIsValid(state->partParentOid))
1545 			LockRelationOid(state->partParentOid, AccessExclusiveLock);
1546 	}
1547 }
1548 
1549 /*
1550  * ExecuteTruncate
1551  *		Executes a TRUNCATE command.
1552  *
1553  * This is a multi-relation truncate.  We first open and grab exclusive
1554  * lock on all relations involved, checking permissions and otherwise
1555  * verifying that the relation is OK for truncation.  In CASCADE mode,
1556  * relations having FK references to the targeted relations are automatically
1557  * added to the group; in RESTRICT mode, we check that all FK references are
1558  * internal to the group that's being truncated.  Finally all the relations
1559  * are truncated and reindexed.
1560  */
1561 void
ExecuteTruncate(TruncateStmt * stmt)1562 ExecuteTruncate(TruncateStmt *stmt)
1563 {
1564 	List	   *rels = NIL;
1565 	List	   *relids = NIL;
1566 	List	   *relids_logged = NIL;
1567 	ListCell   *cell;
1568 
1569 	/*
1570 	 * Open, exclusive-lock, and check all the explicitly-specified relations
1571 	 */
1572 	foreach(cell, stmt->relations)
1573 	{
1574 		RangeVar   *rv = lfirst(cell);
1575 		Relation	rel;
1576 		bool		recurse = rv->inh;
1577 		Oid			myrelid;
1578 		LOCKMODE	lockmode = AccessExclusiveLock;
1579 
1580 		myrelid = RangeVarGetRelidExtended(rv, lockmode,
1581 										   0, RangeVarCallbackForTruncate,
1582 										   NULL);
1583 
1584 		/* open the relation, we already hold a lock on it */
1585 		rel = table_open(myrelid, NoLock);
1586 
1587 		/* don't throw error for "TRUNCATE foo, foo" */
1588 		if (list_member_oid(relids, myrelid))
1589 		{
1590 			table_close(rel, lockmode);
1591 			continue;
1592 		}
1593 
1594 		/*
1595 		 * RangeVarGetRelidExtended() has done most checks with its callback,
1596 		 * but other checks with the now-opened Relation remain.
1597 		 */
1598 		truncate_check_activity(rel);
1599 
1600 		rels = lappend(rels, rel);
1601 		relids = lappend_oid(relids, myrelid);
1602 		/* Log this relation only if needed for logical decoding */
1603 		if (RelationIsLogicallyLogged(rel))
1604 			relids_logged = lappend_oid(relids_logged, myrelid);
1605 
1606 		if (recurse)
1607 		{
1608 			ListCell   *child;
1609 			List	   *children;
1610 
1611 			children = find_all_inheritors(myrelid, lockmode, NULL);
1612 
1613 			foreach(child, children)
1614 			{
1615 				Oid			childrelid = lfirst_oid(child);
1616 
1617 				if (list_member_oid(relids, childrelid))
1618 					continue;
1619 
1620 				/* find_all_inheritors already got lock */
1621 				rel = table_open(childrelid, NoLock);
1622 
1623 				/*
1624 				 * It is possible that the parent table has children that are
1625 				 * temp tables of other backends.  We cannot safely access
1626 				 * such tables (because of buffering issues), and the best
1627 				 * thing to do is to silently ignore them.  Note that this
1628 				 * check is the same as one of the checks done in
1629 				 * truncate_check_activity() called below, still it is kept
1630 				 * here for simplicity.
1631 				 */
1632 				if (RELATION_IS_OTHER_TEMP(rel))
1633 				{
1634 					table_close(rel, lockmode);
1635 					continue;
1636 				}
1637 
1638 				/*
1639 				 * Inherited TRUNCATE commands perform access permission
1640 				 * checks on the parent table only. So we skip checking the
1641 				 * children's permissions and don't call
1642 				 * truncate_check_perms() here.
1643 				 */
1644 				truncate_check_rel(RelationGetRelid(rel), rel->rd_rel);
1645 				truncate_check_activity(rel);
1646 
1647 				rels = lappend(rels, rel);
1648 				relids = lappend_oid(relids, childrelid);
1649 				/* Log this relation only if needed for logical decoding */
1650 				if (RelationIsLogicallyLogged(rel))
1651 					relids_logged = lappend_oid(relids_logged, childrelid);
1652 			}
1653 		}
1654 		else if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
1655 			ereport(ERROR,
1656 					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
1657 					 errmsg("cannot truncate only a partitioned table"),
1658 					 errhint("Do not specify the ONLY keyword, or use TRUNCATE ONLY on the partitions directly.")));
1659 	}
1660 
1661 	ExecuteTruncateGuts(rels, relids, relids_logged,
1662 						stmt->behavior, stmt->restart_seqs);
1663 
1664 	/* And close the rels */
1665 	foreach(cell, rels)
1666 	{
1667 		Relation	rel = (Relation) lfirst(cell);
1668 
1669 		table_close(rel, NoLock);
1670 	}
1671 }
1672 
1673 /*
1674  * ExecuteTruncateGuts
1675  *
1676  * Internal implementation of TRUNCATE.  This is called by the actual TRUNCATE
1677  * command (see above) as well as replication subscribers that execute a
1678  * replicated TRUNCATE action.
1679  *
1680  * explicit_rels is the list of Relations to truncate that the command
1681  * specified.  relids is the list of Oids corresponding to explicit_rels.
1682  * relids_logged is the list of Oids (a subset of relids) that require
1683  * WAL-logging.  This is all a bit redundant, but the existing callers have
1684  * this information handy in this form.
1685  */
1686 void
ExecuteTruncateGuts(List * explicit_rels,List * relids,List * relids_logged,DropBehavior behavior,bool restart_seqs)1687 ExecuteTruncateGuts(List *explicit_rels, List *relids, List *relids_logged,
1688 					DropBehavior behavior, bool restart_seqs)
1689 {
1690 	List	   *rels;
1691 	List	   *seq_relids = NIL;
1692 	EState	   *estate;
1693 	ResultRelInfo *resultRelInfos;
1694 	ResultRelInfo *resultRelInfo;
1695 	SubTransactionId mySubid;
1696 	ListCell   *cell;
1697 	Oid		   *logrelids;
1698 
1699 	/*
1700 	 * Check the explicitly-specified relations.
1701 	 *
1702 	 * In CASCADE mode, suck in all referencing relations as well.  This
1703 	 * requires multiple iterations to find indirectly-dependent relations. At
1704 	 * each phase, we need to exclusive-lock new rels before looking for their
1705 	 * dependencies, else we might miss something.  Also, we check each rel as
1706 	 * soon as we open it, to avoid a faux pas such as holding lock for a long
1707 	 * time on a rel we have no permissions for.
1708 	 */
1709 	rels = list_copy(explicit_rels);
1710 	if (behavior == DROP_CASCADE)
1711 	{
1712 		for (;;)
1713 		{
1714 			List	   *newrelids;
1715 
1716 			newrelids = heap_truncate_find_FKs(relids);
1717 			if (newrelids == NIL)
1718 				break;			/* nothing else to add */
1719 
1720 			foreach(cell, newrelids)
1721 			{
1722 				Oid			relid = lfirst_oid(cell);
1723 				Relation	rel;
1724 
1725 				rel = table_open(relid, AccessExclusiveLock);
1726 				ereport(NOTICE,
1727 						(errmsg("truncate cascades to table \"%s\"",
1728 								RelationGetRelationName(rel))));
1729 				truncate_check_rel(relid, rel->rd_rel);
1730 				truncate_check_perms(relid, rel->rd_rel);
1731 				truncate_check_activity(rel);
1732 				rels = lappend(rels, rel);
1733 				relids = lappend_oid(relids, relid);
1734 				/* Log this relation only if needed for logical decoding */
1735 				if (RelationIsLogicallyLogged(rel))
1736 					relids_logged = lappend_oid(relids_logged, relid);
1737 			}
1738 		}
1739 	}
1740 
1741 	/*
1742 	 * Check foreign key references.  In CASCADE mode, this should be
1743 	 * unnecessary since we just pulled in all the references; but as a
1744 	 * cross-check, do it anyway if in an Assert-enabled build.
1745 	 */
1746 #ifdef USE_ASSERT_CHECKING
1747 	heap_truncate_check_FKs(rels, false);
1748 #else
1749 	if (behavior == DROP_RESTRICT)
1750 		heap_truncate_check_FKs(rels, false);
1751 #endif
1752 
1753 	/*
1754 	 * If we are asked to restart sequences, find all the sequences, lock them
1755 	 * (we need AccessExclusiveLock for ResetSequence), and check permissions.
1756 	 * We want to do this early since it's pointless to do all the truncation
1757 	 * work only to fail on sequence permissions.
1758 	 */
1759 	if (restart_seqs)
1760 	{
1761 		foreach(cell, rels)
1762 		{
1763 			Relation	rel = (Relation) lfirst(cell);
1764 			List	   *seqlist = getOwnedSequences(RelationGetRelid(rel));
1765 			ListCell   *seqcell;
1766 
1767 			foreach(seqcell, seqlist)
1768 			{
1769 				Oid			seq_relid = lfirst_oid(seqcell);
1770 				Relation	seq_rel;
1771 
1772 				seq_rel = relation_open(seq_relid, AccessExclusiveLock);
1773 
1774 				/* This check must match AlterSequence! */
1775 				if (!pg_class_ownercheck(seq_relid, GetUserId()))
1776 					aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_SEQUENCE,
1777 								   RelationGetRelationName(seq_rel));
1778 
1779 				seq_relids = lappend_oid(seq_relids, seq_relid);
1780 
1781 				relation_close(seq_rel, NoLock);
1782 			}
1783 		}
1784 	}
1785 
1786 	/* Prepare to catch AFTER triggers. */
1787 	AfterTriggerBeginQuery();
1788 
1789 	/*
1790 	 * To fire triggers, we'll need an EState as well as a ResultRelInfo for
1791 	 * each relation.  We don't need to call ExecOpenIndices, though.
1792 	 */
1793 	estate = CreateExecutorState();
1794 	resultRelInfos = (ResultRelInfo *)
1795 		palloc(list_length(rels) * sizeof(ResultRelInfo));
1796 	resultRelInfo = resultRelInfos;
1797 	foreach(cell, rels)
1798 	{
1799 		Relation	rel = (Relation) lfirst(cell);
1800 
1801 		InitResultRelInfo(resultRelInfo,
1802 						  rel,
1803 						  0,	/* dummy rangetable index */
1804 						  NULL,
1805 						  0);
1806 		resultRelInfo++;
1807 	}
1808 	estate->es_result_relations = resultRelInfos;
1809 	estate->es_num_result_relations = list_length(rels);
1810 
1811 	/*
1812 	 * Process all BEFORE STATEMENT TRUNCATE triggers before we begin
1813 	 * truncating (this is because one of them might throw an error). Also, if
1814 	 * we were to allow them to prevent statement execution, that would need
1815 	 * to be handled here.
1816 	 */
1817 	resultRelInfo = resultRelInfos;
1818 	foreach(cell, rels)
1819 	{
1820 		estate->es_result_relation_info = resultRelInfo;
1821 		ExecBSTruncateTriggers(estate, resultRelInfo);
1822 		resultRelInfo++;
1823 	}
1824 
1825 	/*
1826 	 * OK, truncate each table.
1827 	 */
1828 	mySubid = GetCurrentSubTransactionId();
1829 
1830 	foreach(cell, rels)
1831 	{
1832 		Relation	rel = (Relation) lfirst(cell);
1833 
1834 		/* Skip partitioned tables as there is nothing to do */
1835 		if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
1836 			continue;
1837 
1838 		/*
1839 		 * Normally, we need a transaction-safe truncation here.  However, if
1840 		 * the table was either created in the current (sub)transaction or has
1841 		 * a new relfilenode in the current (sub)transaction, then we can just
1842 		 * truncate it in-place, because a rollback would cause the whole
1843 		 * table or the current physical file to be thrown away anyway.
1844 		 */
1845 		if (rel->rd_createSubid == mySubid ||
1846 			rel->rd_newRelfilenodeSubid == mySubid)
1847 		{
1848 			/* Immediate, non-rollbackable truncation is OK */
1849 			heap_truncate_one_rel(rel);
1850 		}
1851 		else
1852 		{
1853 			Oid			heap_relid;
1854 			Oid			toast_relid;
1855 
1856 			/*
1857 			 * This effectively deletes all rows in the table, and may be done
1858 			 * in a serializable transaction.  In that case we must record a
1859 			 * rw-conflict in to this transaction from each transaction
1860 			 * holding a predicate lock on the table.
1861 			 */
1862 			CheckTableForSerializableConflictIn(rel);
1863 
1864 			/*
1865 			 * Need the full transaction-safe pushups.
1866 			 *
1867 			 * Create a new empty storage file for the relation, and assign it
1868 			 * as the relfilenode value. The old storage file is scheduled for
1869 			 * deletion at commit.
1870 			 */
1871 			RelationSetNewRelfilenode(rel, rel->rd_rel->relpersistence);
1872 
1873 			heap_relid = RelationGetRelid(rel);
1874 
1875 			/*
1876 			 * The same for the toast table, if any.
1877 			 */
1878 			toast_relid = rel->rd_rel->reltoastrelid;
1879 			if (OidIsValid(toast_relid))
1880 			{
1881 				Relation	toastrel = relation_open(toast_relid,
1882 													 AccessExclusiveLock);
1883 
1884 				RelationSetNewRelfilenode(toastrel,
1885 										  toastrel->rd_rel->relpersistence);
1886 				table_close(toastrel, NoLock);
1887 			}
1888 
1889 			/*
1890 			 * Reconstruct the indexes to match, and we're done.
1891 			 */
1892 			reindex_relation(heap_relid, REINDEX_REL_PROCESS_TOAST, 0);
1893 		}
1894 
1895 		pgstat_count_truncate(rel);
1896 	}
1897 
1898 	/*
1899 	 * Restart owned sequences if we were asked to.
1900 	 */
1901 	foreach(cell, seq_relids)
1902 	{
1903 		Oid			seq_relid = lfirst_oid(cell);
1904 
1905 		ResetSequence(seq_relid);
1906 	}
1907 
1908 	/*
1909 	 * Write a WAL record to allow this set of actions to be logically
1910 	 * decoded.
1911 	 *
1912 	 * Assemble an array of relids so we can write a single WAL record for the
1913 	 * whole action.
1914 	 */
1915 	if (list_length(relids_logged) > 0)
1916 	{
1917 		xl_heap_truncate xlrec;
1918 		int			i = 0;
1919 
1920 		/* should only get here if wal_level >= logical */
1921 		Assert(XLogLogicalInfoActive());
1922 
1923 		logrelids = palloc(list_length(relids_logged) * sizeof(Oid));
1924 		foreach(cell, relids_logged)
1925 			logrelids[i++] = lfirst_oid(cell);
1926 
1927 		xlrec.dbId = MyDatabaseId;
1928 		xlrec.nrelids = list_length(relids_logged);
1929 		xlrec.flags = 0;
1930 		if (behavior == DROP_CASCADE)
1931 			xlrec.flags |= XLH_TRUNCATE_CASCADE;
1932 		if (restart_seqs)
1933 			xlrec.flags |= XLH_TRUNCATE_RESTART_SEQS;
1934 
1935 		XLogBeginInsert();
1936 		XLogRegisterData((char *) &xlrec, SizeOfHeapTruncate);
1937 		XLogRegisterData((char *) logrelids, list_length(relids_logged) * sizeof(Oid));
1938 
1939 		XLogSetRecordFlags(XLOG_INCLUDE_ORIGIN);
1940 
1941 		(void) XLogInsert(RM_HEAP_ID, XLOG_HEAP_TRUNCATE);
1942 	}
1943 
1944 	/*
1945 	 * Process all AFTER STATEMENT TRUNCATE triggers.
1946 	 */
1947 	resultRelInfo = resultRelInfos;
1948 	foreach(cell, rels)
1949 	{
1950 		estate->es_result_relation_info = resultRelInfo;
1951 		ExecASTruncateTriggers(estate, resultRelInfo);
1952 		resultRelInfo++;
1953 	}
1954 
1955 	/* Handle queued AFTER triggers */
1956 	AfterTriggerEndQuery(estate);
1957 
1958 	/* We can clean up the EState now */
1959 	FreeExecutorState(estate);
1960 
1961 	/*
1962 	 * Close any rels opened by CASCADE (can't do this while EState still
1963 	 * holds refs)
1964 	 */
1965 	rels = list_difference_ptr(rels, explicit_rels);
1966 	foreach(cell, rels)
1967 	{
1968 		Relation	rel = (Relation) lfirst(cell);
1969 
1970 		table_close(rel, NoLock);
1971 	}
1972 }
1973 
1974 /*
1975  * Check that a given relation is safe to truncate.  Subroutine for
1976  * ExecuteTruncate() and RangeVarCallbackForTruncate().
1977  */
1978 static void
truncate_check_rel(Oid relid,Form_pg_class reltuple)1979 truncate_check_rel(Oid relid, Form_pg_class reltuple)
1980 {
1981 	char	   *relname = NameStr(reltuple->relname);
1982 
1983 	/*
1984 	 * Only allow truncate on regular tables and partitioned tables (although,
1985 	 * the latter are only being included here for the following checks; no
1986 	 * physical truncation will occur in their case.)
1987 	 */
1988 	if (reltuple->relkind != RELKIND_RELATION &&
1989 		reltuple->relkind != RELKIND_PARTITIONED_TABLE)
1990 		ereport(ERROR,
1991 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
1992 				 errmsg("\"%s\" is not a table", relname)));
1993 
1994 	if (!allowSystemTableMods && IsSystemClass(relid, reltuple))
1995 		ereport(ERROR,
1996 				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1997 				 errmsg("permission denied: \"%s\" is a system catalog",
1998 						relname)));
1999 
2000 	InvokeObjectTruncateHook(relid);
2001 }
2002 
2003 /*
2004  * Check that current user has the permission to truncate given relation.
2005  */
2006 static void
truncate_check_perms(Oid relid,Form_pg_class reltuple)2007 truncate_check_perms(Oid relid, Form_pg_class reltuple)
2008 {
2009 	char	   *relname = NameStr(reltuple->relname);
2010 	AclResult	aclresult;
2011 
2012 	/* Permissions checks */
2013 	aclresult = pg_class_aclcheck(relid, GetUserId(), ACL_TRUNCATE);
2014 	if (aclresult != ACLCHECK_OK)
2015 		aclcheck_error(aclresult, get_relkind_objtype(reltuple->relkind),
2016 					   relname);
2017 }
2018 
2019 /*
2020  * Set of extra sanity checks to check if a given relation is safe to
2021  * truncate.  This is split with truncate_check_rel() as
2022  * RangeVarCallbackForTruncate() cannot open a Relation yet.
2023  */
2024 static void
truncate_check_activity(Relation rel)2025 truncate_check_activity(Relation rel)
2026 {
2027 	/*
2028 	 * Don't allow truncate on temp tables of other backends ... their local
2029 	 * buffer manager is not going to cope.
2030 	 */
2031 	if (RELATION_IS_OTHER_TEMP(rel))
2032 		ereport(ERROR,
2033 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2034 				 errmsg("cannot truncate temporary tables of other sessions")));
2035 
2036 	/*
2037 	 * Also check for active uses of the relation in the current transaction,
2038 	 * including open scans and pending AFTER trigger events.
2039 	 */
2040 	CheckTableNotInUse(rel, "TRUNCATE");
2041 }
2042 
2043 /*
2044  * storage_name
2045  *	  returns the name corresponding to a typstorage/attstorage enum value
2046  */
2047 static const char *
storage_name(char c)2048 storage_name(char c)
2049 {
2050 	switch (c)
2051 	{
2052 		case TYPSTORAGE_PLAIN:
2053 			return "PLAIN";
2054 		case TYPSTORAGE_EXTERNAL:
2055 			return "EXTERNAL";
2056 		case TYPSTORAGE_EXTENDED:
2057 			return "EXTENDED";
2058 		case TYPSTORAGE_MAIN:
2059 			return "MAIN";
2060 		default:
2061 			return "???";
2062 	}
2063 }
2064 
2065 /*----------
2066  * MergeAttributes
2067  *		Returns new schema given initial schema and superclasses.
2068  *
2069  * Input arguments:
2070  * 'schema' is the column/attribute definition for the table. (It's a list
2071  *		of ColumnDef's.) It is destructively changed.
2072  * 'supers' is a list of OIDs of parent relations, already locked by caller.
2073  * 'relpersistence' is the persistence type of the table.
2074  * 'is_partition' tells if the table is a partition.
2075  *
2076  * Output arguments:
2077  * 'supconstr' receives a list of constraints belonging to the parents,
2078  *		updated as necessary to be valid for the child.
2079  *
2080  * Return value:
2081  * Completed schema list.
2082  *
2083  * Notes:
2084  *	  The order in which the attributes are inherited is very important.
2085  *	  Intuitively, the inherited attributes should come first. If a table
2086  *	  inherits from multiple parents, the order of those attributes are
2087  *	  according to the order of the parents specified in CREATE TABLE.
2088  *
2089  *	  Here's an example:
2090  *
2091  *		create table person (name text, age int4, location point);
2092  *		create table emp (salary int4, manager text) inherits(person);
2093  *		create table student (gpa float8) inherits (person);
2094  *		create table stud_emp (percent int4) inherits (emp, student);
2095  *
2096  *	  The order of the attributes of stud_emp is:
2097  *
2098  *							person {1:name, 2:age, 3:location}
2099  *							/	 \
2100  *			   {6:gpa}	student   emp {4:salary, 5:manager}
2101  *							\	 /
2102  *						   stud_emp {7:percent}
2103  *
2104  *	   If the same attribute name appears multiple times, then it appears
2105  *	   in the result table in the proper location for its first appearance.
2106  *
2107  *	   Constraints (including NOT NULL constraints) for the child table
2108  *	   are the union of all relevant constraints, from both the child schema
2109  *	   and parent tables.
2110  *
2111  *	   The default value for a child column is defined as:
2112  *		(1) If the child schema specifies a default, that value is used.
2113  *		(2) If neither the child nor any parent specifies a default, then
2114  *			the column will not have a default.
2115  *		(3) If conflicting defaults are inherited from different parents
2116  *			(and not overridden by the child), an error is raised.
2117  *		(4) Otherwise the inherited default is used.
2118  *		Rule (3) is new in Postgres 7.1; in earlier releases you got a
2119  *		rather arbitrary choice of which parent default to use.
2120  *----------
2121  */
2122 static List *
MergeAttributes(List * schema,List * supers,char relpersistence,bool is_partition,List ** supconstr)2123 MergeAttributes(List *schema, List *supers, char relpersistence,
2124 				bool is_partition, List **supconstr)
2125 {
2126 	List	   *inhSchema = NIL;
2127 	List	   *constraints = NIL;
2128 	bool		have_bogus_defaults = false;
2129 	int			child_attno;
2130 	static Node bogus_marker = {0}; /* marks conflicting defaults */
2131 	List	   *saved_schema = NIL;
2132 	ListCell   *entry;
2133 
2134 	/*
2135 	 * Check for and reject tables with too many columns. We perform this
2136 	 * check relatively early for two reasons: (a) we don't run the risk of
2137 	 * overflowing an AttrNumber in subsequent code (b) an O(n^2) algorithm is
2138 	 * okay if we're processing <= 1600 columns, but could take minutes to
2139 	 * execute if the user attempts to create a table with hundreds of
2140 	 * thousands of columns.
2141 	 *
2142 	 * Note that we also need to check that we do not exceed this figure after
2143 	 * including columns from inherited relations.
2144 	 */
2145 	if (list_length(schema) > MaxHeapAttributeNumber)
2146 		ereport(ERROR,
2147 				(errcode(ERRCODE_TOO_MANY_COLUMNS),
2148 				 errmsg("tables can have at most %d columns",
2149 						MaxHeapAttributeNumber)));
2150 
2151 	/*
2152 	 * Check for duplicate names in the explicit list of attributes.
2153 	 *
2154 	 * Although we might consider merging such entries in the same way that we
2155 	 * handle name conflicts for inherited attributes, it seems to make more
2156 	 * sense to assume such conflicts are errors.
2157 	 *
2158 	 * We don't use foreach() here because we have two nested loops over the
2159 	 * schema list, with possible element deletions in the inner one.  If we
2160 	 * used foreach_delete_current() it could only fix up the state of one of
2161 	 * the loops, so it seems cleaner to use looping over list indexes for
2162 	 * both loops.  Note that any deletion will happen beyond where the outer
2163 	 * loop is, so its index never needs adjustment.
2164 	 */
2165 	for (int coldefpos = 0; coldefpos < list_length(schema); coldefpos++)
2166 	{
2167 		ColumnDef  *coldef = list_nth_node(ColumnDef, schema, coldefpos);
2168 
2169 		if (!is_partition && coldef->typeName == NULL)
2170 		{
2171 			/*
2172 			 * Typed table column option that does not belong to a column from
2173 			 * the type.  This works because the columns from the type come
2174 			 * first in the list.  (We omit this check for partition column
2175 			 * lists; those are processed separately below.)
2176 			 */
2177 			ereport(ERROR,
2178 					(errcode(ERRCODE_UNDEFINED_COLUMN),
2179 					 errmsg("column \"%s\" does not exist",
2180 							coldef->colname)));
2181 		}
2182 
2183 		/* restpos scans all entries beyond coldef; incr is in loop body */
2184 		for (int restpos = coldefpos + 1; restpos < list_length(schema);)
2185 		{
2186 			ColumnDef  *restdef = list_nth_node(ColumnDef, schema, restpos);
2187 
2188 			if (strcmp(coldef->colname, restdef->colname) == 0)
2189 			{
2190 				if (coldef->is_from_type)
2191 				{
2192 					/*
2193 					 * merge the column options into the column from the type
2194 					 */
2195 					coldef->is_not_null = restdef->is_not_null;
2196 					coldef->raw_default = restdef->raw_default;
2197 					coldef->cooked_default = restdef->cooked_default;
2198 					coldef->constraints = restdef->constraints;
2199 					coldef->is_from_type = false;
2200 					schema = list_delete_nth_cell(schema, restpos);
2201 				}
2202 				else
2203 					ereport(ERROR,
2204 							(errcode(ERRCODE_DUPLICATE_COLUMN),
2205 							 errmsg("column \"%s\" specified more than once",
2206 									coldef->colname)));
2207 			}
2208 			else
2209 				restpos++;
2210 		}
2211 	}
2212 
2213 	/*
2214 	 * In case of a partition, there are no new column definitions, only dummy
2215 	 * ColumnDefs created for column constraints.  Set them aside for now and
2216 	 * process them at the end.
2217 	 */
2218 	if (is_partition)
2219 	{
2220 		saved_schema = schema;
2221 		schema = NIL;
2222 	}
2223 
2224 	/*
2225 	 * Scan the parents left-to-right, and merge their attributes to form a
2226 	 * list of inherited attributes (inhSchema).  Also check to see if we need
2227 	 * to inherit an OID column.
2228 	 */
2229 	child_attno = 0;
2230 	foreach(entry, supers)
2231 	{
2232 		Oid			parent = lfirst_oid(entry);
2233 		Relation	relation;
2234 		TupleDesc	tupleDesc;
2235 		TupleConstr *constr;
2236 		AttrMap    *newattmap;
2237 		List	   *inherited_defaults;
2238 		List	   *cols_with_defaults;
2239 		AttrNumber	parent_attno;
2240 		ListCell   *lc1;
2241 		ListCell   *lc2;
2242 
2243 		/* caller already got lock */
2244 		relation = table_open(parent, NoLock);
2245 
2246 		/*
2247 		 * Check for active uses of the parent partitioned table in the
2248 		 * current transaction, such as being used in some manner by an
2249 		 * enclosing command.
2250 		 */
2251 		if (is_partition)
2252 			CheckTableNotInUse(relation, "CREATE TABLE .. PARTITION OF");
2253 
2254 		/*
2255 		 * We do not allow partitioned tables and partitions to participate in
2256 		 * regular inheritance.
2257 		 */
2258 		if (relation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE &&
2259 			!is_partition)
2260 			ereport(ERROR,
2261 					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
2262 					 errmsg("cannot inherit from partitioned table \"%s\"",
2263 							RelationGetRelationName(relation))));
2264 		if (relation->rd_rel->relispartition && !is_partition)
2265 			ereport(ERROR,
2266 					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
2267 					 errmsg("cannot inherit from partition \"%s\"",
2268 							RelationGetRelationName(relation))));
2269 
2270 		if (relation->rd_rel->relkind != RELKIND_RELATION &&
2271 			relation->rd_rel->relkind != RELKIND_FOREIGN_TABLE &&
2272 			relation->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
2273 			ereport(ERROR,
2274 					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
2275 					 errmsg("inherited relation \"%s\" is not a table or foreign table",
2276 							RelationGetRelationName(relation))));
2277 
2278 		/*
2279 		 * If the parent is permanent, so must be all of its partitions.  Note
2280 		 * that inheritance allows that case.
2281 		 */
2282 		if (is_partition &&
2283 			relation->rd_rel->relpersistence != RELPERSISTENCE_TEMP &&
2284 			relpersistence == RELPERSISTENCE_TEMP)
2285 			ereport(ERROR,
2286 					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
2287 					 errmsg("cannot create a temporary relation as partition of permanent relation \"%s\"",
2288 							RelationGetRelationName(relation))));
2289 
2290 		/* Permanent rels cannot inherit from temporary ones */
2291 		if (relpersistence != RELPERSISTENCE_TEMP &&
2292 			relation->rd_rel->relpersistence == RELPERSISTENCE_TEMP)
2293 			ereport(ERROR,
2294 					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
2295 					 errmsg(!is_partition
2296 							? "cannot inherit from temporary relation \"%s\""
2297 							: "cannot create a permanent relation as partition of temporary relation \"%s\"",
2298 							RelationGetRelationName(relation))));
2299 
2300 		/* If existing rel is temp, it must belong to this session */
2301 		if (relation->rd_rel->relpersistence == RELPERSISTENCE_TEMP &&
2302 			!relation->rd_islocaltemp)
2303 			ereport(ERROR,
2304 					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
2305 					 errmsg(!is_partition
2306 							? "cannot inherit from temporary relation of another session"
2307 							: "cannot create as partition of temporary relation of another session")));
2308 
2309 		/*
2310 		 * We should have an UNDER permission flag for this, but for now,
2311 		 * demand that creator of a child table own the parent.
2312 		 */
2313 		if (!pg_class_ownercheck(RelationGetRelid(relation), GetUserId()))
2314 			aclcheck_error(ACLCHECK_NOT_OWNER, get_relkind_objtype(relation->rd_rel->relkind),
2315 						   RelationGetRelationName(relation));
2316 
2317 		tupleDesc = RelationGetDescr(relation);
2318 		constr = tupleDesc->constr;
2319 
2320 		/*
2321 		 * newattmap->attnums[] will contain the child-table attribute numbers
2322 		 * for the attributes of this parent table.  (They are not the same
2323 		 * for parents after the first one, nor if we have dropped columns.)
2324 		 */
2325 		newattmap = make_attrmap(tupleDesc->natts);
2326 
2327 		/* We can't process inherited defaults until newattmap is complete. */
2328 		inherited_defaults = cols_with_defaults = NIL;
2329 
2330 		for (parent_attno = 1; parent_attno <= tupleDesc->natts;
2331 			 parent_attno++)
2332 		{
2333 			Form_pg_attribute attribute = TupleDescAttr(tupleDesc,
2334 														parent_attno - 1);
2335 			char	   *attributeName = NameStr(attribute->attname);
2336 			int			exist_attno;
2337 			ColumnDef  *def;
2338 
2339 			/*
2340 			 * Ignore dropped columns in the parent.
2341 			 */
2342 			if (attribute->attisdropped)
2343 				continue;		/* leave newattmap->attnums entry as zero */
2344 
2345 			/*
2346 			 * Does it conflict with some previously inherited column?
2347 			 */
2348 			exist_attno = findAttrByName(attributeName, inhSchema);
2349 			if (exist_attno > 0)
2350 			{
2351 				Oid			defTypeId;
2352 				int32		deftypmod;
2353 				Oid			defCollId;
2354 
2355 				/*
2356 				 * Yes, try to merge the two column definitions. They must
2357 				 * have the same type, typmod, and collation.
2358 				 */
2359 				ereport(NOTICE,
2360 						(errmsg("merging multiple inherited definitions of column \"%s\"",
2361 								attributeName)));
2362 				def = (ColumnDef *) list_nth(inhSchema, exist_attno - 1);
2363 				typenameTypeIdAndMod(NULL, def->typeName, &defTypeId, &deftypmod);
2364 				if (defTypeId != attribute->atttypid ||
2365 					deftypmod != attribute->atttypmod)
2366 					ereport(ERROR,
2367 							(errcode(ERRCODE_DATATYPE_MISMATCH),
2368 							 errmsg("inherited column \"%s\" has a type conflict",
2369 									attributeName),
2370 							 errdetail("%s versus %s",
2371 									   format_type_with_typemod(defTypeId,
2372 																deftypmod),
2373 									   format_type_with_typemod(attribute->atttypid,
2374 																attribute->atttypmod))));
2375 				defCollId = GetColumnDefCollation(NULL, def, defTypeId);
2376 				if (defCollId != attribute->attcollation)
2377 					ereport(ERROR,
2378 							(errcode(ERRCODE_COLLATION_MISMATCH),
2379 							 errmsg("inherited column \"%s\" has a collation conflict",
2380 									attributeName),
2381 							 errdetail("\"%s\" versus \"%s\"",
2382 									   get_collation_name(defCollId),
2383 									   get_collation_name(attribute->attcollation))));
2384 
2385 				/* Copy/check storage parameter */
2386 				if (def->storage == 0)
2387 					def->storage = attribute->attstorage;
2388 				else if (def->storage != attribute->attstorage)
2389 					ereport(ERROR,
2390 							(errcode(ERRCODE_DATATYPE_MISMATCH),
2391 							 errmsg("inherited column \"%s\" has a storage parameter conflict",
2392 									attributeName),
2393 							 errdetail("%s versus %s",
2394 									   storage_name(def->storage),
2395 									   storage_name(attribute->attstorage))));
2396 
2397 				def->inhcount++;
2398 				/* Merge of NOT NULL constraints = OR 'em together */
2399 				def->is_not_null |= attribute->attnotnull;
2400 				/* Default and other constraints are handled below */
2401 				newattmap->attnums[parent_attno - 1] = exist_attno;
2402 
2403 				/* Check for GENERATED conflicts */
2404 				if (def->generated != attribute->attgenerated)
2405 					ereport(ERROR,
2406 							(errcode(ERRCODE_DATATYPE_MISMATCH),
2407 							 errmsg("inherited column \"%s\" has a generation conflict",
2408 									attributeName)));
2409 			}
2410 			else
2411 			{
2412 				/*
2413 				 * No, create a new inherited column
2414 				 */
2415 				def = makeNode(ColumnDef);
2416 				def->colname = pstrdup(attributeName);
2417 				def->typeName = makeTypeNameFromOid(attribute->atttypid,
2418 													attribute->atttypmod);
2419 				def->inhcount = 1;
2420 				def->is_local = false;
2421 				def->is_not_null = attribute->attnotnull;
2422 				def->is_from_type = false;
2423 				def->storage = attribute->attstorage;
2424 				def->raw_default = NULL;
2425 				def->cooked_default = NULL;
2426 				def->generated = attribute->attgenerated;
2427 				def->collClause = NULL;
2428 				def->collOid = attribute->attcollation;
2429 				def->constraints = NIL;
2430 				def->location = -1;
2431 				inhSchema = lappend(inhSchema, def);
2432 				newattmap->attnums[parent_attno - 1] = ++child_attno;
2433 			}
2434 
2435 			/*
2436 			 * Locate default if any
2437 			 */
2438 			if (attribute->atthasdef)
2439 			{
2440 				Node	   *this_default = NULL;
2441 				AttrDefault *attrdef;
2442 				int			i;
2443 
2444 				/* Find default in constraint structure */
2445 				Assert(constr != NULL);
2446 				attrdef = constr->defval;
2447 				for (i = 0; i < constr->num_defval; i++)
2448 				{
2449 					if (attrdef[i].adnum == parent_attno)
2450 					{
2451 						this_default = stringToNode(attrdef[i].adbin);
2452 						break;
2453 					}
2454 				}
2455 				Assert(this_default != NULL);
2456 
2457 				/*
2458 				 * If it's a GENERATED default, it might contain Vars that
2459 				 * need to be mapped to the inherited column(s)' new numbers.
2460 				 * We can't do that till newattmap is ready, so just remember
2461 				 * all the inherited default expressions for the moment.
2462 				 */
2463 				inherited_defaults = lappend(inherited_defaults, this_default);
2464 				cols_with_defaults = lappend(cols_with_defaults, def);
2465 			}
2466 		}
2467 
2468 		/*
2469 		 * Now process any inherited default expressions, adjusting attnos
2470 		 * using the completed newattmap map.
2471 		 */
2472 		forboth(lc1, inherited_defaults, lc2, cols_with_defaults)
2473 		{
2474 			Node	   *this_default = (Node *) lfirst(lc1);
2475 			ColumnDef  *def = (ColumnDef *) lfirst(lc2);
2476 			bool		found_whole_row;
2477 
2478 			/* Adjust Vars to match new table's column numbering */
2479 			this_default = map_variable_attnos(this_default,
2480 											   1, 0,
2481 											   newattmap,
2482 											   InvalidOid, &found_whole_row);
2483 
2484 			/*
2485 			 * For the moment we have to reject whole-row variables.  We could
2486 			 * convert them, if we knew the new table's rowtype OID, but that
2487 			 * hasn't been assigned yet.  (A variable could only appear in a
2488 			 * generation expression, so the error message is correct.)
2489 			 */
2490 			if (found_whole_row)
2491 				ereport(ERROR,
2492 						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2493 						 errmsg("cannot convert whole-row table reference"),
2494 						 errdetail("Generation expression for column \"%s\" contains a whole-row reference to table \"%s\".",
2495 								   def->colname,
2496 								   RelationGetRelationName(relation))));
2497 
2498 			/*
2499 			 * If we already had a default from some prior parent, check to
2500 			 * see if they are the same.  If so, no problem; if not, mark the
2501 			 * column as having a bogus default.  Below, we will complain if
2502 			 * the bogus default isn't overridden by the child schema.
2503 			 */
2504 			Assert(def->raw_default == NULL);
2505 			if (def->cooked_default == NULL)
2506 				def->cooked_default = this_default;
2507 			else if (!equal(def->cooked_default, this_default))
2508 			{
2509 				def->cooked_default = &bogus_marker;
2510 				have_bogus_defaults = true;
2511 			}
2512 		}
2513 
2514 		/*
2515 		 * Now copy the CHECK constraints of this parent, adjusting attnos
2516 		 * using the completed newattmap map.  Identically named constraints
2517 		 * are merged if possible, else we throw error.
2518 		 */
2519 		if (constr && constr->num_check > 0)
2520 		{
2521 			ConstrCheck *check = constr->check;
2522 			int			i;
2523 
2524 			for (i = 0; i < constr->num_check; i++)
2525 			{
2526 				char	   *name = check[i].ccname;
2527 				Node	   *expr;
2528 				bool		found_whole_row;
2529 
2530 				/* ignore if the constraint is non-inheritable */
2531 				if (check[i].ccnoinherit)
2532 					continue;
2533 
2534 				/* Adjust Vars to match new table's column numbering */
2535 				expr = map_variable_attnos(stringToNode(check[i].ccbin),
2536 										   1, 0,
2537 										   newattmap,
2538 										   InvalidOid, &found_whole_row);
2539 
2540 				/*
2541 				 * For the moment we have to reject whole-row variables. We
2542 				 * could convert them, if we knew the new table's rowtype OID,
2543 				 * but that hasn't been assigned yet.
2544 				 */
2545 				if (found_whole_row)
2546 					ereport(ERROR,
2547 							(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2548 							 errmsg("cannot convert whole-row table reference"),
2549 							 errdetail("Constraint \"%s\" contains a whole-row reference to table \"%s\".",
2550 									   name,
2551 									   RelationGetRelationName(relation))));
2552 
2553 				/* check for duplicate */
2554 				if (!MergeCheckConstraint(constraints, name, expr))
2555 				{
2556 					/* nope, this is a new one */
2557 					CookedConstraint *cooked;
2558 
2559 					cooked = (CookedConstraint *) palloc(sizeof(CookedConstraint));
2560 					cooked->contype = CONSTR_CHECK;
2561 					cooked->conoid = InvalidOid;	/* until created */
2562 					cooked->name = pstrdup(name);
2563 					cooked->attnum = 0; /* not used for constraints */
2564 					cooked->expr = expr;
2565 					cooked->skip_validation = false;
2566 					cooked->is_local = false;
2567 					cooked->inhcount = 1;
2568 					cooked->is_no_inherit = false;
2569 					constraints = lappend(constraints, cooked);
2570 				}
2571 			}
2572 		}
2573 
2574 		free_attrmap(newattmap);
2575 
2576 		/*
2577 		 * Close the parent rel, but keep our lock on it until xact commit.
2578 		 * That will prevent someone else from deleting or ALTERing the parent
2579 		 * before the child is committed.
2580 		 */
2581 		table_close(relation, NoLock);
2582 	}
2583 
2584 	/*
2585 	 * If we had no inherited attributes, the result schema is just the
2586 	 * explicitly declared columns.  Otherwise, we need to merge the declared
2587 	 * columns into the inherited schema list.  Although, we never have any
2588 	 * explicitly declared columns if the table is a partition.
2589 	 */
2590 	if (inhSchema != NIL)
2591 	{
2592 		int			schema_attno = 0;
2593 
2594 		foreach(entry, schema)
2595 		{
2596 			ColumnDef  *newdef = lfirst(entry);
2597 			char	   *attributeName = newdef->colname;
2598 			int			exist_attno;
2599 
2600 			schema_attno++;
2601 
2602 			/*
2603 			 * Does it conflict with some previously inherited column?
2604 			 */
2605 			exist_attno = findAttrByName(attributeName, inhSchema);
2606 			if (exist_attno > 0)
2607 			{
2608 				ColumnDef  *def;
2609 				Oid			defTypeId,
2610 							newTypeId;
2611 				int32		deftypmod,
2612 							newtypmod;
2613 				Oid			defcollid,
2614 							newcollid;
2615 
2616 				/*
2617 				 * Partitions have only one parent and have no column
2618 				 * definitions of their own, so conflict should never occur.
2619 				 */
2620 				Assert(!is_partition);
2621 
2622 				/*
2623 				 * Yes, try to merge the two column definitions. They must
2624 				 * have the same type, typmod, and collation.
2625 				 */
2626 				if (exist_attno == schema_attno)
2627 					ereport(NOTICE,
2628 							(errmsg("merging column \"%s\" with inherited definition",
2629 									attributeName)));
2630 				else
2631 					ereport(NOTICE,
2632 							(errmsg("moving and merging column \"%s\" with inherited definition", attributeName),
2633 							 errdetail("User-specified column moved to the position of the inherited column.")));
2634 				def = (ColumnDef *) list_nth(inhSchema, exist_attno - 1);
2635 				typenameTypeIdAndMod(NULL, def->typeName, &defTypeId, &deftypmod);
2636 				typenameTypeIdAndMod(NULL, newdef->typeName, &newTypeId, &newtypmod);
2637 				if (defTypeId != newTypeId || deftypmod != newtypmod)
2638 					ereport(ERROR,
2639 							(errcode(ERRCODE_DATATYPE_MISMATCH),
2640 							 errmsg("column \"%s\" has a type conflict",
2641 									attributeName),
2642 							 errdetail("%s versus %s",
2643 									   format_type_with_typemod(defTypeId,
2644 																deftypmod),
2645 									   format_type_with_typemod(newTypeId,
2646 																newtypmod))));
2647 				defcollid = GetColumnDefCollation(NULL, def, defTypeId);
2648 				newcollid = GetColumnDefCollation(NULL, newdef, newTypeId);
2649 				if (defcollid != newcollid)
2650 					ereport(ERROR,
2651 							(errcode(ERRCODE_COLLATION_MISMATCH),
2652 							 errmsg("column \"%s\" has a collation conflict",
2653 									attributeName),
2654 							 errdetail("\"%s\" versus \"%s\"",
2655 									   get_collation_name(defcollid),
2656 									   get_collation_name(newcollid))));
2657 
2658 				/*
2659 				 * Identity is never inherited.  The new column can have an
2660 				 * identity definition, so we always just take that one.
2661 				 */
2662 				def->identity = newdef->identity;
2663 
2664 				/* Copy storage parameter */
2665 				if (def->storage == 0)
2666 					def->storage = newdef->storage;
2667 				else if (newdef->storage != 0 && def->storage != newdef->storage)
2668 					ereport(ERROR,
2669 							(errcode(ERRCODE_DATATYPE_MISMATCH),
2670 							 errmsg("column \"%s\" has a storage parameter conflict",
2671 									attributeName),
2672 							 errdetail("%s versus %s",
2673 									   storage_name(def->storage),
2674 									   storage_name(newdef->storage))));
2675 
2676 				/* Mark the column as locally defined */
2677 				def->is_local = true;
2678 				/* Merge of NOT NULL constraints = OR 'em together */
2679 				def->is_not_null |= newdef->is_not_null;
2680 
2681 				/*
2682 				 * Check for conflicts related to generated columns.
2683 				 *
2684 				 * If the parent column is generated, the child column must be
2685 				 * unadorned and will be made a generated column.  (We could
2686 				 * in theory allow the child column definition specifying the
2687 				 * exact same generation expression, but that's a bit
2688 				 * complicated to implement and doesn't seem very useful.)  We
2689 				 * also check that the child column doesn't specify a default
2690 				 * value or identity, which matches the rules for a single
2691 				 * column in parse_util.c.
2692 				 */
2693 				if (def->generated)
2694 				{
2695 					if (newdef->generated)
2696 						ereport(ERROR,
2697 								(errcode(ERRCODE_INVALID_COLUMN_DEFINITION),
2698 								 errmsg("child column \"%s\" specifies generation expression",
2699 										def->colname),
2700 								 errhint("Omit the generation expression in the definition of the child table column to inherit the generation expression from the parent table.")));
2701 					if (newdef->raw_default && !newdef->generated)
2702 						ereport(ERROR,
2703 								(errcode(ERRCODE_INVALID_COLUMN_DEFINITION),
2704 								 errmsg("column \"%s\" inherits from generated column but specifies default",
2705 										def->colname)));
2706 					if (newdef->identity)
2707 						ereport(ERROR,
2708 								(errcode(ERRCODE_INVALID_COLUMN_DEFINITION),
2709 								 errmsg("column \"%s\" inherits from generated column but specifies identity",
2710 										def->colname)));
2711 				}
2712 
2713 				/*
2714 				 * If the parent column is not generated, then take whatever
2715 				 * the child column definition says.
2716 				 */
2717 				else
2718 				{
2719 					if (newdef->generated)
2720 						def->generated = newdef->generated;
2721 				}
2722 
2723 				/* If new def has a default, override previous default */
2724 				if (newdef->raw_default != NULL)
2725 				{
2726 					def->raw_default = newdef->raw_default;
2727 					def->cooked_default = newdef->cooked_default;
2728 				}
2729 			}
2730 			else
2731 			{
2732 				/*
2733 				 * No, attach new column to result schema
2734 				 */
2735 				inhSchema = lappend(inhSchema, newdef);
2736 			}
2737 		}
2738 
2739 		schema = inhSchema;
2740 
2741 		/*
2742 		 * Check that we haven't exceeded the legal # of columns after merging
2743 		 * in inherited columns.
2744 		 */
2745 		if (list_length(schema) > MaxHeapAttributeNumber)
2746 			ereport(ERROR,
2747 					(errcode(ERRCODE_TOO_MANY_COLUMNS),
2748 					 errmsg("tables can have at most %d columns",
2749 							MaxHeapAttributeNumber)));
2750 	}
2751 
2752 	/*
2753 	 * Now that we have the column definition list for a partition, we can
2754 	 * check whether the columns referenced in the column constraint specs
2755 	 * actually exist.  Also, we merge NOT NULL and defaults into each
2756 	 * corresponding column definition.
2757 	 */
2758 	if (is_partition)
2759 	{
2760 		foreach(entry, saved_schema)
2761 		{
2762 			ColumnDef  *restdef = lfirst(entry);
2763 			bool		found = false;
2764 			ListCell   *l;
2765 
2766 			foreach(l, schema)
2767 			{
2768 				ColumnDef  *coldef = lfirst(l);
2769 
2770 				if (strcmp(coldef->colname, restdef->colname) == 0)
2771 				{
2772 					found = true;
2773 					coldef->is_not_null |= restdef->is_not_null;
2774 
2775 					/*
2776 					 * Override the parent's default value for this column
2777 					 * (coldef->cooked_default) with the partition's local
2778 					 * definition (restdef->raw_default), if there's one. It
2779 					 * should be physically impossible to get a cooked default
2780 					 * in the local definition or a raw default in the
2781 					 * inherited definition, but make sure they're nulls, for
2782 					 * future-proofing.
2783 					 */
2784 					Assert(restdef->cooked_default == NULL);
2785 					Assert(coldef->raw_default == NULL);
2786 					if (restdef->raw_default)
2787 					{
2788 						coldef->raw_default = restdef->raw_default;
2789 						coldef->cooked_default = NULL;
2790 					}
2791 				}
2792 			}
2793 
2794 			/* complain for constraints on columns not in parent */
2795 			if (!found)
2796 				ereport(ERROR,
2797 						(errcode(ERRCODE_UNDEFINED_COLUMN),
2798 						 errmsg("column \"%s\" does not exist",
2799 								restdef->colname)));
2800 		}
2801 	}
2802 
2803 	/*
2804 	 * If we found any conflicting parent default values, check to make sure
2805 	 * they were overridden by the child.
2806 	 */
2807 	if (have_bogus_defaults)
2808 	{
2809 		foreach(entry, schema)
2810 		{
2811 			ColumnDef  *def = lfirst(entry);
2812 
2813 			if (def->cooked_default == &bogus_marker)
2814 			{
2815 				if (def->generated)
2816 					ereport(ERROR,
2817 							(errcode(ERRCODE_INVALID_COLUMN_DEFINITION),
2818 							 errmsg("column \"%s\" inherits conflicting generation expressions",
2819 									def->colname)));
2820 				else
2821 					ereport(ERROR,
2822 							(errcode(ERRCODE_INVALID_COLUMN_DEFINITION),
2823 							 errmsg("column \"%s\" inherits conflicting default values",
2824 									def->colname),
2825 							 errhint("To resolve the conflict, specify a default explicitly.")));
2826 			}
2827 		}
2828 	}
2829 
2830 	*supconstr = constraints;
2831 	return schema;
2832 }
2833 
2834 
2835 /*
2836  * MergeCheckConstraint
2837  *		Try to merge an inherited CHECK constraint with previous ones
2838  *
2839  * If we inherit identically-named constraints from multiple parents, we must
2840  * merge them, or throw an error if they don't have identical definitions.
2841  *
2842  * constraints is a list of CookedConstraint structs for previous constraints.
2843  *
2844  * Returns true if merged (constraint is a duplicate), or false if it's
2845  * got a so-far-unique name, or throws error if conflict.
2846  */
2847 static bool
MergeCheckConstraint(List * constraints,char * name,Node * expr)2848 MergeCheckConstraint(List *constraints, char *name, Node *expr)
2849 {
2850 	ListCell   *lc;
2851 
2852 	foreach(lc, constraints)
2853 	{
2854 		CookedConstraint *ccon = (CookedConstraint *) lfirst(lc);
2855 
2856 		Assert(ccon->contype == CONSTR_CHECK);
2857 
2858 		/* Non-matching names never conflict */
2859 		if (strcmp(ccon->name, name) != 0)
2860 			continue;
2861 
2862 		if (equal(expr, ccon->expr))
2863 		{
2864 			/* OK to merge */
2865 			ccon->inhcount++;
2866 			return true;
2867 		}
2868 
2869 		ereport(ERROR,
2870 				(errcode(ERRCODE_DUPLICATE_OBJECT),
2871 				 errmsg("check constraint name \"%s\" appears multiple times but with different expressions",
2872 						name)));
2873 	}
2874 
2875 	return false;
2876 }
2877 
2878 
2879 /*
2880  * StoreCatalogInheritance
2881  *		Updates the system catalogs with proper inheritance information.
2882  *
2883  * supers is a list of the OIDs of the new relation's direct ancestors.
2884  */
2885 static void
StoreCatalogInheritance(Oid relationId,List * supers,bool child_is_partition)2886 StoreCatalogInheritance(Oid relationId, List *supers,
2887 						bool child_is_partition)
2888 {
2889 	Relation	relation;
2890 	int32		seqNumber;
2891 	ListCell   *entry;
2892 
2893 	/*
2894 	 * sanity checks
2895 	 */
2896 	AssertArg(OidIsValid(relationId));
2897 
2898 	if (supers == NIL)
2899 		return;
2900 
2901 	/*
2902 	 * Store INHERITS information in pg_inherits using direct ancestors only.
2903 	 * Also enter dependencies on the direct ancestors, and make sure they are
2904 	 * marked with relhassubclass = true.
2905 	 *
2906 	 * (Once upon a time, both direct and indirect ancestors were found here
2907 	 * and then entered into pg_ipl.  Since that catalog doesn't exist
2908 	 * anymore, there's no need to look for indirect ancestors.)
2909 	 */
2910 	relation = table_open(InheritsRelationId, RowExclusiveLock);
2911 
2912 	seqNumber = 1;
2913 	foreach(entry, supers)
2914 	{
2915 		Oid			parentOid = lfirst_oid(entry);
2916 
2917 		StoreCatalogInheritance1(relationId, parentOid, seqNumber, relation,
2918 								 child_is_partition);
2919 		seqNumber++;
2920 	}
2921 
2922 	table_close(relation, RowExclusiveLock);
2923 }
2924 
2925 /*
2926  * Make catalog entries showing relationId as being an inheritance child
2927  * of parentOid.  inhRelation is the already-opened pg_inherits catalog.
2928  */
2929 static void
StoreCatalogInheritance1(Oid relationId,Oid parentOid,int32 seqNumber,Relation inhRelation,bool child_is_partition)2930 StoreCatalogInheritance1(Oid relationId, Oid parentOid,
2931 						 int32 seqNumber, Relation inhRelation,
2932 						 bool child_is_partition)
2933 {
2934 	ObjectAddress childobject,
2935 				parentobject;
2936 
2937 	/* store the pg_inherits row */
2938 	StoreSingleInheritance(relationId, parentOid, seqNumber);
2939 
2940 	/*
2941 	 * Store a dependency too
2942 	 */
2943 	parentobject.classId = RelationRelationId;
2944 	parentobject.objectId = parentOid;
2945 	parentobject.objectSubId = 0;
2946 	childobject.classId = RelationRelationId;
2947 	childobject.objectId = relationId;
2948 	childobject.objectSubId = 0;
2949 
2950 	recordDependencyOn(&childobject, &parentobject,
2951 					   child_dependency_type(child_is_partition));
2952 
2953 	/*
2954 	 * Post creation hook of this inheritance. Since object_access_hook
2955 	 * doesn't take multiple object identifiers, we relay oid of parent
2956 	 * relation using auxiliary_id argument.
2957 	 */
2958 	InvokeObjectPostAlterHookArg(InheritsRelationId,
2959 								 relationId, 0,
2960 								 parentOid, false);
2961 
2962 	/*
2963 	 * Mark the parent as having subclasses.
2964 	 */
2965 	SetRelationHasSubclass(parentOid, true);
2966 }
2967 
2968 /*
2969  * Look for an existing schema entry with the given name.
2970  *
2971  * Returns the index (starting with 1) if attribute already exists in schema,
2972  * 0 if it doesn't.
2973  */
2974 static int
findAttrByName(const char * attributeName,List * schema)2975 findAttrByName(const char *attributeName, List *schema)
2976 {
2977 	ListCell   *s;
2978 	int			i = 1;
2979 
2980 	foreach(s, schema)
2981 	{
2982 		ColumnDef  *def = lfirst(s);
2983 
2984 		if (strcmp(attributeName, def->colname) == 0)
2985 			return i;
2986 
2987 		i++;
2988 	}
2989 	return 0;
2990 }
2991 
2992 
2993 /*
2994  * SetRelationHasSubclass
2995  *		Set the value of the relation's relhassubclass field in pg_class.
2996  *
2997  * NOTE: caller must be holding an appropriate lock on the relation.
2998  * ShareUpdateExclusiveLock is sufficient.
2999  *
3000  * NOTE: an important side-effect of this operation is that an SI invalidation
3001  * message is sent out to all backends --- including me --- causing plans
3002  * referencing the relation to be rebuilt with the new list of children.
3003  * This must happen even if we find that no change is needed in the pg_class
3004  * row.
3005  */
3006 void
SetRelationHasSubclass(Oid relationId,bool relhassubclass)3007 SetRelationHasSubclass(Oid relationId, bool relhassubclass)
3008 {
3009 	Relation	relationRelation;
3010 	HeapTuple	tuple;
3011 	Form_pg_class classtuple;
3012 
3013 	/*
3014 	 * Fetch a modifiable copy of the tuple, modify it, update pg_class.
3015 	 */
3016 	relationRelation = table_open(RelationRelationId, RowExclusiveLock);
3017 	tuple = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relationId));
3018 	if (!HeapTupleIsValid(tuple))
3019 		elog(ERROR, "cache lookup failed for relation %u", relationId);
3020 	classtuple = (Form_pg_class) GETSTRUCT(tuple);
3021 
3022 	if (classtuple->relhassubclass != relhassubclass)
3023 	{
3024 		classtuple->relhassubclass = relhassubclass;
3025 		CatalogTupleUpdate(relationRelation, &tuple->t_self, tuple);
3026 	}
3027 	else
3028 	{
3029 		/* no need to change tuple, but force relcache rebuild anyway */
3030 		CacheInvalidateRelcacheByTuple(tuple);
3031 	}
3032 
3033 	heap_freetuple(tuple);
3034 	table_close(relationRelation, RowExclusiveLock);
3035 }
3036 
3037 /*
3038  *		renameatt_check			- basic sanity checks before attribute rename
3039  */
3040 static void
renameatt_check(Oid myrelid,Form_pg_class classform,bool recursing)3041 renameatt_check(Oid myrelid, Form_pg_class classform, bool recursing)
3042 {
3043 	char		relkind = classform->relkind;
3044 
3045 	if (classform->reloftype && !recursing)
3046 		ereport(ERROR,
3047 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
3048 				 errmsg("cannot rename column of typed table")));
3049 
3050 	/*
3051 	 * Renaming the columns of sequences or toast tables doesn't actually
3052 	 * break anything from the system's point of view, since internal
3053 	 * references are by attnum.  But it doesn't seem right to allow users to
3054 	 * change names that are hardcoded into the system, hence the following
3055 	 * restriction.
3056 	 */
3057 	if (relkind != RELKIND_RELATION &&
3058 		relkind != RELKIND_VIEW &&
3059 		relkind != RELKIND_MATVIEW &&
3060 		relkind != RELKIND_COMPOSITE_TYPE &&
3061 		relkind != RELKIND_INDEX &&
3062 		relkind != RELKIND_PARTITIONED_INDEX &&
3063 		relkind != RELKIND_FOREIGN_TABLE &&
3064 		relkind != RELKIND_PARTITIONED_TABLE)
3065 		ereport(ERROR,
3066 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
3067 				 errmsg("\"%s\" is not a table, view, materialized view, composite type, index, or foreign table",
3068 						NameStr(classform->relname))));
3069 
3070 	/*
3071 	 * permissions checking.  only the owner of a class can change its schema.
3072 	 */
3073 	if (!pg_class_ownercheck(myrelid, GetUserId()))
3074 		aclcheck_error(ACLCHECK_NOT_OWNER, get_relkind_objtype(get_rel_relkind(myrelid)),
3075 					   NameStr(classform->relname));
3076 	if (!allowSystemTableMods && IsSystemClass(myrelid, classform))
3077 		ereport(ERROR,
3078 				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
3079 				 errmsg("permission denied: \"%s\" is a system catalog",
3080 						NameStr(classform->relname))));
3081 }
3082 
3083 /*
3084  *		renameatt_internal		- workhorse for renameatt
3085  *
3086  * Return value is the attribute number in the 'myrelid' relation.
3087  */
3088 static AttrNumber
renameatt_internal(Oid myrelid,const char * oldattname,const char * newattname,bool recurse,bool recursing,int expected_parents,DropBehavior behavior)3089 renameatt_internal(Oid myrelid,
3090 				   const char *oldattname,
3091 				   const char *newattname,
3092 				   bool recurse,
3093 				   bool recursing,
3094 				   int expected_parents,
3095 				   DropBehavior behavior)
3096 {
3097 	Relation	targetrelation;
3098 	Relation	attrelation;
3099 	HeapTuple	atttup;
3100 	Form_pg_attribute attform;
3101 	AttrNumber	attnum;
3102 
3103 	/*
3104 	 * Grab an exclusive lock on the target table, which we will NOT release
3105 	 * until end of transaction.
3106 	 */
3107 	targetrelation = relation_open(myrelid, AccessExclusiveLock);
3108 	renameatt_check(myrelid, RelationGetForm(targetrelation), recursing);
3109 
3110 	/*
3111 	 * if the 'recurse' flag is set then we are supposed to rename this
3112 	 * attribute in all classes that inherit from 'relname' (as well as in
3113 	 * 'relname').
3114 	 *
3115 	 * any permissions or problems with duplicate attributes will cause the
3116 	 * whole transaction to abort, which is what we want -- all or nothing.
3117 	 */
3118 	if (recurse)
3119 	{
3120 		List	   *child_oids,
3121 				   *child_numparents;
3122 		ListCell   *lo,
3123 				   *li;
3124 
3125 		/*
3126 		 * we need the number of parents for each child so that the recursive
3127 		 * calls to renameatt() can determine whether there are any parents
3128 		 * outside the inheritance hierarchy being processed.
3129 		 */
3130 		child_oids = find_all_inheritors(myrelid, AccessExclusiveLock,
3131 										 &child_numparents);
3132 
3133 		/*
3134 		 * find_all_inheritors does the recursive search of the inheritance
3135 		 * hierarchy, so all we have to do is process all of the relids in the
3136 		 * list that it returns.
3137 		 */
3138 		forboth(lo, child_oids, li, child_numparents)
3139 		{
3140 			Oid			childrelid = lfirst_oid(lo);
3141 			int			numparents = lfirst_int(li);
3142 
3143 			if (childrelid == myrelid)
3144 				continue;
3145 			/* note we need not recurse again */
3146 			renameatt_internal(childrelid, oldattname, newattname, false, true, numparents, behavior);
3147 		}
3148 	}
3149 	else
3150 	{
3151 		/*
3152 		 * If we are told not to recurse, there had better not be any child
3153 		 * tables; else the rename would put them out of step.
3154 		 *
3155 		 * expected_parents will only be 0 if we are not already recursing.
3156 		 */
3157 		if (expected_parents == 0 &&
3158 			find_inheritance_children(myrelid, NoLock) != NIL)
3159 			ereport(ERROR,
3160 					(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
3161 					 errmsg("inherited column \"%s\" must be renamed in child tables too",
3162 							oldattname)));
3163 	}
3164 
3165 	/* rename attributes in typed tables of composite type */
3166 	if (targetrelation->rd_rel->relkind == RELKIND_COMPOSITE_TYPE)
3167 	{
3168 		List	   *child_oids;
3169 		ListCell   *lo;
3170 
3171 		child_oids = find_typed_table_dependencies(targetrelation->rd_rel->reltype,
3172 												   RelationGetRelationName(targetrelation),
3173 												   behavior);
3174 
3175 		foreach(lo, child_oids)
3176 			renameatt_internal(lfirst_oid(lo), oldattname, newattname, true, true, 0, behavior);
3177 	}
3178 
3179 	attrelation = table_open(AttributeRelationId, RowExclusiveLock);
3180 
3181 	atttup = SearchSysCacheCopyAttName(myrelid, oldattname);
3182 	if (!HeapTupleIsValid(atttup))
3183 		ereport(ERROR,
3184 				(errcode(ERRCODE_UNDEFINED_COLUMN),
3185 				 errmsg("column \"%s\" does not exist",
3186 						oldattname)));
3187 	attform = (Form_pg_attribute) GETSTRUCT(atttup);
3188 
3189 	attnum = attform->attnum;
3190 	if (attnum <= 0)
3191 		ereport(ERROR,
3192 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3193 				 errmsg("cannot rename system column \"%s\"",
3194 						oldattname)));
3195 
3196 	/*
3197 	 * if the attribute is inherited, forbid the renaming.  if this is a
3198 	 * top-level call to renameatt(), then expected_parents will be 0, so the
3199 	 * effect of this code will be to prohibit the renaming if the attribute
3200 	 * is inherited at all.  if this is a recursive call to renameatt(),
3201 	 * expected_parents will be the number of parents the current relation has
3202 	 * within the inheritance hierarchy being processed, so we'll prohibit the
3203 	 * renaming only if there are additional parents from elsewhere.
3204 	 */
3205 	if (attform->attinhcount > expected_parents)
3206 		ereport(ERROR,
3207 				(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
3208 				 errmsg("cannot rename inherited column \"%s\"",
3209 						oldattname)));
3210 
3211 	/* new name should not already exist */
3212 	(void) check_for_column_name_collision(targetrelation, newattname, false);
3213 
3214 	/* apply the update */
3215 	namestrcpy(&(attform->attname), newattname);
3216 
3217 	CatalogTupleUpdate(attrelation, &atttup->t_self, atttup);
3218 
3219 	InvokeObjectPostAlterHook(RelationRelationId, myrelid, attnum);
3220 
3221 	heap_freetuple(atttup);
3222 
3223 	table_close(attrelation, RowExclusiveLock);
3224 
3225 	relation_close(targetrelation, NoLock); /* close rel but keep lock */
3226 
3227 	return attnum;
3228 }
3229 
3230 /*
3231  * Perform permissions and integrity checks before acquiring a relation lock.
3232  */
3233 static void
RangeVarCallbackForRenameAttribute(const RangeVar * rv,Oid relid,Oid oldrelid,void * arg)3234 RangeVarCallbackForRenameAttribute(const RangeVar *rv, Oid relid, Oid oldrelid,
3235 								   void *arg)
3236 {
3237 	HeapTuple	tuple;
3238 	Form_pg_class form;
3239 
3240 	tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
3241 	if (!HeapTupleIsValid(tuple))
3242 		return;					/* concurrently dropped */
3243 	form = (Form_pg_class) GETSTRUCT(tuple);
3244 	renameatt_check(relid, form, false);
3245 	ReleaseSysCache(tuple);
3246 }
3247 
3248 /*
3249  *		renameatt		- changes the name of an attribute in a relation
3250  *
3251  * The returned ObjectAddress is that of the renamed column.
3252  */
3253 ObjectAddress
renameatt(RenameStmt * stmt)3254 renameatt(RenameStmt *stmt)
3255 {
3256 	Oid			relid;
3257 	AttrNumber	attnum;
3258 	ObjectAddress address;
3259 
3260 	/* lock level taken here should match renameatt_internal */
3261 	relid = RangeVarGetRelidExtended(stmt->relation, AccessExclusiveLock,
3262 									 stmt->missing_ok ? RVR_MISSING_OK : 0,
3263 									 RangeVarCallbackForRenameAttribute,
3264 									 NULL);
3265 
3266 	if (!OidIsValid(relid))
3267 	{
3268 		ereport(NOTICE,
3269 				(errmsg("relation \"%s\" does not exist, skipping",
3270 						stmt->relation->relname)));
3271 		return InvalidObjectAddress;
3272 	}
3273 
3274 	attnum =
3275 		renameatt_internal(relid,
3276 						   stmt->subname,	/* old att name */
3277 						   stmt->newname,	/* new att name */
3278 						   stmt->relation->inh, /* recursive? */
3279 						   false,	/* recursing? */
3280 						   0,	/* expected inhcount */
3281 						   stmt->behavior);
3282 
3283 	ObjectAddressSubSet(address, RelationRelationId, relid, attnum);
3284 
3285 	return address;
3286 }
3287 
3288 /*
3289  * same logic as renameatt_internal
3290  */
3291 static ObjectAddress
rename_constraint_internal(Oid myrelid,Oid mytypid,const char * oldconname,const char * newconname,bool recurse,bool recursing,int expected_parents)3292 rename_constraint_internal(Oid myrelid,
3293 						   Oid mytypid,
3294 						   const char *oldconname,
3295 						   const char *newconname,
3296 						   bool recurse,
3297 						   bool recursing,
3298 						   int expected_parents)
3299 {
3300 	Relation	targetrelation = NULL;
3301 	Oid			constraintOid;
3302 	HeapTuple	tuple;
3303 	Form_pg_constraint con;
3304 	ObjectAddress address;
3305 
3306 	AssertArg(!myrelid || !mytypid);
3307 
3308 	if (mytypid)
3309 	{
3310 		constraintOid = get_domain_constraint_oid(mytypid, oldconname, false);
3311 	}
3312 	else
3313 	{
3314 		targetrelation = relation_open(myrelid, AccessExclusiveLock);
3315 
3316 		/*
3317 		 * don't tell it whether we're recursing; we allow changing typed
3318 		 * tables here
3319 		 */
3320 		renameatt_check(myrelid, RelationGetForm(targetrelation), false);
3321 
3322 		constraintOid = get_relation_constraint_oid(myrelid, oldconname, false);
3323 	}
3324 
3325 	tuple = SearchSysCache1(CONSTROID, ObjectIdGetDatum(constraintOid));
3326 	if (!HeapTupleIsValid(tuple))
3327 		elog(ERROR, "cache lookup failed for constraint %u",
3328 			 constraintOid);
3329 	con = (Form_pg_constraint) GETSTRUCT(tuple);
3330 
3331 	if (myrelid && con->contype == CONSTRAINT_CHECK && !con->connoinherit)
3332 	{
3333 		if (recurse)
3334 		{
3335 			List	   *child_oids,
3336 					   *child_numparents;
3337 			ListCell   *lo,
3338 					   *li;
3339 
3340 			child_oids = find_all_inheritors(myrelid, AccessExclusiveLock,
3341 											 &child_numparents);
3342 
3343 			forboth(lo, child_oids, li, child_numparents)
3344 			{
3345 				Oid			childrelid = lfirst_oid(lo);
3346 				int			numparents = lfirst_int(li);
3347 
3348 				if (childrelid == myrelid)
3349 					continue;
3350 
3351 				rename_constraint_internal(childrelid, InvalidOid, oldconname, newconname, false, true, numparents);
3352 			}
3353 		}
3354 		else
3355 		{
3356 			if (expected_parents == 0 &&
3357 				find_inheritance_children(myrelid, NoLock) != NIL)
3358 				ereport(ERROR,
3359 						(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
3360 						 errmsg("inherited constraint \"%s\" must be renamed in child tables too",
3361 								oldconname)));
3362 		}
3363 
3364 		if (con->coninhcount > expected_parents)
3365 			ereport(ERROR,
3366 					(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
3367 					 errmsg("cannot rename inherited constraint \"%s\"",
3368 							oldconname)));
3369 	}
3370 
3371 	if (con->conindid
3372 		&& (con->contype == CONSTRAINT_PRIMARY
3373 			|| con->contype == CONSTRAINT_UNIQUE
3374 			|| con->contype == CONSTRAINT_EXCLUSION))
3375 		/* rename the index; this renames the constraint as well */
3376 		RenameRelationInternal(con->conindid, newconname, false, true);
3377 	else
3378 		RenameConstraintById(constraintOid, newconname);
3379 
3380 	ObjectAddressSet(address, ConstraintRelationId, constraintOid);
3381 
3382 	ReleaseSysCache(tuple);
3383 
3384 	if (targetrelation)
3385 	{
3386 		/*
3387 		 * Invalidate relcache so as others can see the new constraint name.
3388 		 */
3389 		CacheInvalidateRelcache(targetrelation);
3390 
3391 		relation_close(targetrelation, NoLock); /* close rel but keep lock */
3392 	}
3393 
3394 	return address;
3395 }
3396 
3397 ObjectAddress
RenameConstraint(RenameStmt * stmt)3398 RenameConstraint(RenameStmt *stmt)
3399 {
3400 	Oid			relid = InvalidOid;
3401 	Oid			typid = InvalidOid;
3402 
3403 	if (stmt->renameType == OBJECT_DOMCONSTRAINT)
3404 	{
3405 		Relation	rel;
3406 		HeapTuple	tup;
3407 
3408 		typid = typenameTypeId(NULL, makeTypeNameFromNameList(castNode(List, stmt->object)));
3409 		rel = table_open(TypeRelationId, RowExclusiveLock);
3410 		tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
3411 		if (!HeapTupleIsValid(tup))
3412 			elog(ERROR, "cache lookup failed for type %u", typid);
3413 		checkDomainOwner(tup);
3414 		ReleaseSysCache(tup);
3415 		table_close(rel, NoLock);
3416 	}
3417 	else
3418 	{
3419 		/* lock level taken here should match rename_constraint_internal */
3420 		relid = RangeVarGetRelidExtended(stmt->relation, AccessExclusiveLock,
3421 										 stmt->missing_ok ? RVR_MISSING_OK : 0,
3422 										 RangeVarCallbackForRenameAttribute,
3423 										 NULL);
3424 		if (!OidIsValid(relid))
3425 		{
3426 			ereport(NOTICE,
3427 					(errmsg("relation \"%s\" does not exist, skipping",
3428 							stmt->relation->relname)));
3429 			return InvalidObjectAddress;
3430 		}
3431 	}
3432 
3433 	return
3434 		rename_constraint_internal(relid, typid,
3435 								   stmt->subname,
3436 								   stmt->newname,
3437 								   (stmt->relation &&
3438 									stmt->relation->inh),	/* recursive? */
3439 								   false,	/* recursing? */
3440 								   0 /* expected inhcount */ );
3441 
3442 }
3443 
3444 /*
3445  * Execute ALTER TABLE/INDEX/SEQUENCE/VIEW/MATERIALIZED VIEW/FOREIGN TABLE
3446  * RENAME
3447  */
3448 ObjectAddress
RenameRelation(RenameStmt * stmt)3449 RenameRelation(RenameStmt *stmt)
3450 {
3451 	bool		is_index_stmt = stmt->renameType == OBJECT_INDEX;
3452 	Oid			relid;
3453 	ObjectAddress address;
3454 
3455 	/*
3456 	 * Grab an exclusive lock on the target table, index, sequence, view,
3457 	 * materialized view, or foreign table, which we will NOT release until
3458 	 * end of transaction.
3459 	 *
3460 	 * Lock level used here should match RenameRelationInternal, to avoid lock
3461 	 * escalation.  However, because ALTER INDEX can be used with any relation
3462 	 * type, we mustn't believe without verification.
3463 	 */
3464 	for (;;)
3465 	{
3466 		LOCKMODE	lockmode;
3467 		char		relkind;
3468 		bool		obj_is_index;
3469 
3470 		lockmode = is_index_stmt ? ShareUpdateExclusiveLock : AccessExclusiveLock;
3471 
3472 		relid = RangeVarGetRelidExtended(stmt->relation, lockmode,
3473 										 stmt->missing_ok ? RVR_MISSING_OK : 0,
3474 										 RangeVarCallbackForAlterRelation,
3475 										 (void *) stmt);
3476 
3477 		if (!OidIsValid(relid))
3478 		{
3479 			ereport(NOTICE,
3480 					(errmsg("relation \"%s\" does not exist, skipping",
3481 							stmt->relation->relname)));
3482 			return InvalidObjectAddress;
3483 		}
3484 
3485 		/*
3486 		 * We allow mismatched statement and object types (e.g., ALTER INDEX
3487 		 * to rename a table), but we might've used the wrong lock level.  If
3488 		 * that happens, retry with the correct lock level.  We don't bother
3489 		 * if we already acquired AccessExclusiveLock with an index, however.
3490 		 */
3491 		relkind = get_rel_relkind(relid);
3492 		obj_is_index = (relkind == RELKIND_INDEX ||
3493 						relkind == RELKIND_PARTITIONED_INDEX);
3494 		if (obj_is_index || is_index_stmt == obj_is_index)
3495 			break;
3496 
3497 		UnlockRelationOid(relid, lockmode);
3498 		is_index_stmt = obj_is_index;
3499 	}
3500 
3501 	/* Do the work */
3502 	RenameRelationInternal(relid, stmt->newname, false, is_index_stmt);
3503 
3504 	ObjectAddressSet(address, RelationRelationId, relid);
3505 
3506 	return address;
3507 }
3508 
3509 /*
3510  *		RenameRelationInternal - change the name of a relation
3511  */
3512 void
RenameRelationInternal(Oid myrelid,const char * newrelname,bool is_internal,bool is_index)3513 RenameRelationInternal(Oid myrelid, const char *newrelname, bool is_internal, bool is_index)
3514 {
3515 	Relation	targetrelation;
3516 	Relation	relrelation;	/* for RELATION relation */
3517 	HeapTuple	reltup;
3518 	Form_pg_class relform;
3519 	Oid			namespaceId;
3520 
3521 	/*
3522 	 * Grab a lock on the target relation, which we will NOT release until end
3523 	 * of transaction.  We need at least a self-exclusive lock so that
3524 	 * concurrent DDL doesn't overwrite the rename if they start updating
3525 	 * while still seeing the old version.  The lock also guards against
3526 	 * triggering relcache reloads in concurrent sessions, which might not
3527 	 * handle this information changing under them.  For indexes, we can use a
3528 	 * reduced lock level because RelationReloadIndexInfo() handles indexes
3529 	 * specially.
3530 	 */
3531 	targetrelation = relation_open(myrelid, is_index ? ShareUpdateExclusiveLock : AccessExclusiveLock);
3532 	namespaceId = RelationGetNamespace(targetrelation);
3533 
3534 	/*
3535 	 * Find relation's pg_class tuple, and make sure newrelname isn't in use.
3536 	 */
3537 	relrelation = table_open(RelationRelationId, RowExclusiveLock);
3538 
3539 	reltup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(myrelid));
3540 	if (!HeapTupleIsValid(reltup))	/* shouldn't happen */
3541 		elog(ERROR, "cache lookup failed for relation %u", myrelid);
3542 	relform = (Form_pg_class) GETSTRUCT(reltup);
3543 
3544 	if (get_relname_relid(newrelname, namespaceId) != InvalidOid)
3545 		ereport(ERROR,
3546 				(errcode(ERRCODE_DUPLICATE_TABLE),
3547 				 errmsg("relation \"%s\" already exists",
3548 						newrelname)));
3549 
3550 	/*
3551 	 * RenameRelation is careful not to believe the caller's idea of the
3552 	 * relation kind being handled.  We don't have to worry about this, but
3553 	 * let's not be totally oblivious to it.  We can process an index as
3554 	 * not-an-index, but not the other way around.
3555 	 */
3556 	Assert(!is_index ||
3557 		   is_index == (targetrelation->rd_rel->relkind == RELKIND_INDEX ||
3558 						targetrelation->rd_rel->relkind == RELKIND_PARTITIONED_INDEX));
3559 
3560 	/*
3561 	 * Update pg_class tuple with new relname.  (Scribbling on reltup is OK
3562 	 * because it's a copy...)
3563 	 */
3564 	namestrcpy(&(relform->relname), newrelname);
3565 
3566 	CatalogTupleUpdate(relrelation, &reltup->t_self, reltup);
3567 
3568 	InvokeObjectPostAlterHookArg(RelationRelationId, myrelid, 0,
3569 								 InvalidOid, is_internal);
3570 
3571 	heap_freetuple(reltup);
3572 	table_close(relrelation, RowExclusiveLock);
3573 
3574 	/*
3575 	 * Also rename the associated type, if any.
3576 	 */
3577 	if (OidIsValid(targetrelation->rd_rel->reltype))
3578 		RenameTypeInternal(targetrelation->rd_rel->reltype,
3579 						   newrelname, namespaceId);
3580 
3581 	/*
3582 	 * Also rename the associated constraint, if any.
3583 	 */
3584 	if (targetrelation->rd_rel->relkind == RELKIND_INDEX ||
3585 		targetrelation->rd_rel->relkind == RELKIND_PARTITIONED_INDEX)
3586 	{
3587 		Oid			constraintId = get_index_constraint(myrelid);
3588 
3589 		if (OidIsValid(constraintId))
3590 			RenameConstraintById(constraintId, newrelname);
3591 	}
3592 
3593 	/*
3594 	 * Close rel, but keep lock!
3595 	 */
3596 	relation_close(targetrelation, NoLock);
3597 }
3598 
3599 /*
3600  *		ResetRelRewrite - reset relrewrite
3601  */
3602 void
ResetRelRewrite(Oid myrelid)3603 ResetRelRewrite(Oid myrelid)
3604 {
3605 	Relation	relrelation;	/* for RELATION relation */
3606 	HeapTuple	reltup;
3607 	Form_pg_class relform;
3608 
3609 	/*
3610 	 * Find relation's pg_class tuple.
3611 	 */
3612 	relrelation = table_open(RelationRelationId, RowExclusiveLock);
3613 
3614 	reltup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(myrelid));
3615 	if (!HeapTupleIsValid(reltup))	/* shouldn't happen */
3616 		elog(ERROR, "cache lookup failed for relation %u", myrelid);
3617 	relform = (Form_pg_class) GETSTRUCT(reltup);
3618 
3619 	/*
3620 	 * Update pg_class tuple.
3621 	 */
3622 	relform->relrewrite = InvalidOid;
3623 
3624 	CatalogTupleUpdate(relrelation, &reltup->t_self, reltup);
3625 
3626 	heap_freetuple(reltup);
3627 	table_close(relrelation, RowExclusiveLock);
3628 }
3629 
3630 /*
3631  * Disallow ALTER TABLE (and similar commands) when the current backend has
3632  * any open reference to the target table besides the one just acquired by
3633  * the calling command; this implies there's an open cursor or active plan.
3634  * We need this check because our lock doesn't protect us against stomping
3635  * on our own foot, only other people's feet!
3636  *
3637  * For ALTER TABLE, the only case known to cause serious trouble is ALTER
3638  * COLUMN TYPE, and some changes are obviously pretty benign, so this could
3639  * possibly be relaxed to only error out for certain types of alterations.
3640  * But the use-case for allowing any of these things is not obvious, so we
3641  * won't work hard at it for now.
3642  *
3643  * We also reject these commands if there are any pending AFTER trigger events
3644  * for the rel.  This is certainly necessary for the rewriting variants of
3645  * ALTER TABLE, because they don't preserve tuple TIDs and so the pending
3646  * events would try to fetch the wrong tuples.  It might be overly cautious
3647  * in other cases, but again it seems better to err on the side of paranoia.
3648  *
3649  * REINDEX calls this with "rel" referencing the index to be rebuilt; here
3650  * we are worried about active indexscans on the index.  The trigger-event
3651  * check can be skipped, since we are doing no damage to the parent table.
3652  *
3653  * The statement name (eg, "ALTER TABLE") is passed for use in error messages.
3654  */
3655 void
CheckTableNotInUse(Relation rel,const char * stmt)3656 CheckTableNotInUse(Relation rel, const char *stmt)
3657 {
3658 	int			expected_refcnt;
3659 
3660 	expected_refcnt = rel->rd_isnailed ? 2 : 1;
3661 	if (rel->rd_refcnt != expected_refcnt)
3662 		ereport(ERROR,
3663 				(errcode(ERRCODE_OBJECT_IN_USE),
3664 		/* translator: first %s is a SQL command, eg ALTER TABLE */
3665 				 errmsg("cannot %s \"%s\" because it is being used by active queries in this session",
3666 						stmt, RelationGetRelationName(rel))));
3667 
3668 	if (rel->rd_rel->relkind != RELKIND_INDEX &&
3669 		rel->rd_rel->relkind != RELKIND_PARTITIONED_INDEX &&
3670 		AfterTriggerPendingOnRel(RelationGetRelid(rel)))
3671 		ereport(ERROR,
3672 				(errcode(ERRCODE_OBJECT_IN_USE),
3673 		/* translator: first %s is a SQL command, eg ALTER TABLE */
3674 				 errmsg("cannot %s \"%s\" because it has pending trigger events",
3675 						stmt, RelationGetRelationName(rel))));
3676 }
3677 
3678 /*
3679  * AlterTableLookupRelation
3680  *		Look up, and lock, the OID for the relation named by an alter table
3681  *		statement.
3682  */
3683 Oid
AlterTableLookupRelation(AlterTableStmt * stmt,LOCKMODE lockmode)3684 AlterTableLookupRelation(AlterTableStmt *stmt, LOCKMODE lockmode)
3685 {
3686 	return RangeVarGetRelidExtended(stmt->relation, lockmode,
3687 									stmt->missing_ok ? RVR_MISSING_OK : 0,
3688 									RangeVarCallbackForAlterRelation,
3689 									(void *) stmt);
3690 }
3691 
3692 /*
3693  * AlterTable
3694  *		Execute ALTER TABLE, which can be a list of subcommands
3695  *
3696  * ALTER TABLE is performed in three phases:
3697  *		1. Examine subcommands and perform pre-transformation checking.
3698  *		2. Validate and transform subcommands, and update system catalogs.
3699  *		3. Scan table(s) to check new constraints, and optionally recopy
3700  *		   the data into new table(s).
3701  * Phase 3 is not performed unless one or more of the subcommands requires
3702  * it.  The intention of this design is to allow multiple independent
3703  * updates of the table schema to be performed with only one pass over the
3704  * data.
3705  *
3706  * ATPrepCmd performs phase 1.  A "work queue" entry is created for
3707  * each table to be affected (there may be multiple affected tables if the
3708  * commands traverse a table inheritance hierarchy).  Also we do preliminary
3709  * validation of the subcommands.  Because earlier subcommands may change
3710  * the catalog state seen by later commands, there are limits to what can
3711  * be done in this phase.  Generally, this phase acquires table locks,
3712  * checks permissions and relkind, and recurses to find child tables.
3713  *
3714  * ATRewriteCatalogs performs phase 2 for each affected table.  (Note that
3715  * phases 2 and 3 normally do no explicit recursion, since phase 1 already
3716  * did it --- although some subcommands have to recurse in phase 2 instead.)
3717  * Certain subcommands need to be performed before others to avoid
3718  * unnecessary conflicts; for example, DROP COLUMN should come before
3719  * ADD COLUMN.  Therefore phase 1 divides the subcommands into multiple
3720  * lists, one for each logical "pass" of phase 2.
3721  *
3722  * ATRewriteTables performs phase 3 for those tables that need it.
3723  *
3724  * Thanks to the magic of MVCC, an error anywhere along the way rolls back
3725  * the whole operation; we don't have to do anything special to clean up.
3726  *
3727  * The caller must lock the relation, with an appropriate lock level
3728  * for the subcommands requested, using AlterTableGetLockLevel(stmt->cmds)
3729  * or higher. We pass the lock level down
3730  * so that we can apply it recursively to inherited tables. Note that the
3731  * lock level we want as we recurse might well be higher than required for
3732  * that specific subcommand. So we pass down the overall lock requirement,
3733  * rather than reassess it at lower levels.
3734  *
3735  * The caller also provides a "context" which is to be passed back to
3736  * utility.c when we need to execute a subcommand such as CREATE INDEX.
3737  * Some of the fields therein, such as the relid, are used here as well.
3738  */
3739 void
AlterTable(AlterTableStmt * stmt,LOCKMODE lockmode,AlterTableUtilityContext * context)3740 AlterTable(AlterTableStmt *stmt, LOCKMODE lockmode,
3741 		   AlterTableUtilityContext *context)
3742 {
3743 	Relation	rel;
3744 
3745 	/* Caller is required to provide an adequate lock. */
3746 	rel = relation_open(context->relid, NoLock);
3747 
3748 	CheckTableNotInUse(rel, "ALTER TABLE");
3749 
3750 	ATController(stmt, rel, stmt->cmds, stmt->relation->inh, lockmode, context);
3751 }
3752 
3753 /*
3754  * AlterTableInternal
3755  *
3756  * ALTER TABLE with target specified by OID
3757  *
3758  * We do not reject if the relation is already open, because it's quite
3759  * likely that one or more layers of caller have it open.  That means it
3760  * is unsafe to use this entry point for alterations that could break
3761  * existing query plans.  On the assumption it's not used for such, we
3762  * don't have to reject pending AFTER triggers, either.
3763  *
3764  * Also, since we don't have an AlterTableUtilityContext, this cannot be
3765  * used for any subcommand types that require parse transformation or
3766  * could generate subcommands that have to be passed to ProcessUtility.
3767  */
3768 void
AlterTableInternal(Oid relid,List * cmds,bool recurse)3769 AlterTableInternal(Oid relid, List *cmds, bool recurse)
3770 {
3771 	Relation	rel;
3772 	LOCKMODE	lockmode = AlterTableGetLockLevel(cmds);
3773 
3774 	rel = relation_open(relid, lockmode);
3775 
3776 	EventTriggerAlterTableRelid(relid);
3777 
3778 	ATController(NULL, rel, cmds, recurse, lockmode, NULL);
3779 }
3780 
3781 /*
3782  * AlterTableGetLockLevel
3783  *
3784  * Sets the overall lock level required for the supplied list of subcommands.
3785  * Policy for doing this set according to needs of AlterTable(), see
3786  * comments there for overall explanation.
3787  *
3788  * Function is called before and after parsing, so it must give same
3789  * answer each time it is called. Some subcommands are transformed
3790  * into other subcommand types, so the transform must never be made to a
3791  * lower lock level than previously assigned. All transforms are noted below.
3792  *
3793  * Since this is called before we lock the table we cannot use table metadata
3794  * to influence the type of lock we acquire.
3795  *
3796  * There should be no lockmodes hardcoded into the subcommand functions. All
3797  * lockmode decisions for ALTER TABLE are made here only. The one exception is
3798  * ALTER TABLE RENAME which is treated as a different statement type T_RenameStmt
3799  * and does not travel through this section of code and cannot be combined with
3800  * any of the subcommands given here.
3801  *
3802  * Note that Hot Standby only knows about AccessExclusiveLocks on the master
3803  * so any changes that might affect SELECTs running on standbys need to use
3804  * AccessExclusiveLocks even if you think a lesser lock would do, unless you
3805  * have a solution for that also.
3806  *
3807  * Also note that pg_dump uses only an AccessShareLock, meaning that anything
3808  * that takes a lock less than AccessExclusiveLock can change object definitions
3809  * while pg_dump is running. Be careful to check that the appropriate data is
3810  * derived by pg_dump using an MVCC snapshot, rather than syscache lookups,
3811  * otherwise we might end up with an inconsistent dump that can't restore.
3812  */
3813 LOCKMODE
AlterTableGetLockLevel(List * cmds)3814 AlterTableGetLockLevel(List *cmds)
3815 {
3816 	/*
3817 	 * This only works if we read catalog tables using MVCC snapshots.
3818 	 */
3819 	ListCell   *lcmd;
3820 	LOCKMODE	lockmode = ShareUpdateExclusiveLock;
3821 
3822 	foreach(lcmd, cmds)
3823 	{
3824 		AlterTableCmd *cmd = (AlterTableCmd *) lfirst(lcmd);
3825 		LOCKMODE	cmd_lockmode = AccessExclusiveLock; /* default for compiler */
3826 
3827 		switch (cmd->subtype)
3828 		{
3829 				/*
3830 				 * These subcommands rewrite the heap, so require full locks.
3831 				 */
3832 			case AT_AddColumn:	/* may rewrite heap, in some cases and visible
3833 								 * to SELECT */
3834 			case AT_SetTableSpace:	/* must rewrite heap */
3835 			case AT_AlterColumnType:	/* must rewrite heap */
3836 				cmd_lockmode = AccessExclusiveLock;
3837 				break;
3838 
3839 				/*
3840 				 * These subcommands may require addition of toast tables. If
3841 				 * we add a toast table to a table currently being scanned, we
3842 				 * might miss data added to the new toast table by concurrent
3843 				 * insert transactions.
3844 				 */
3845 			case AT_SetStorage: /* may add toast tables, see
3846 								 * ATRewriteCatalogs() */
3847 				cmd_lockmode = AccessExclusiveLock;
3848 				break;
3849 
3850 				/*
3851 				 * Removing constraints can affect SELECTs that have been
3852 				 * optimized assuming the constraint holds true. See also
3853 				 * CloneFkReferenced.
3854 				 */
3855 			case AT_DropConstraint: /* as DROP INDEX */
3856 			case AT_DropNotNull:	/* may change some SQL plans */
3857 				cmd_lockmode = AccessExclusiveLock;
3858 				break;
3859 
3860 				/*
3861 				 * Subcommands that may be visible to concurrent SELECTs
3862 				 */
3863 			case AT_DropColumn: /* change visible to SELECT */
3864 			case AT_AddColumnToView:	/* CREATE VIEW */
3865 			case AT_DropOids:	/* used to equiv to DropColumn */
3866 			case AT_EnableAlwaysRule:	/* may change SELECT rules */
3867 			case AT_EnableReplicaRule:	/* may change SELECT rules */
3868 			case AT_EnableRule: /* may change SELECT rules */
3869 			case AT_DisableRule:	/* may change SELECT rules */
3870 				cmd_lockmode = AccessExclusiveLock;
3871 				break;
3872 
3873 				/*
3874 				 * Changing owner may remove implicit SELECT privileges
3875 				 */
3876 			case AT_ChangeOwner:	/* change visible to SELECT */
3877 				cmd_lockmode = AccessExclusiveLock;
3878 				break;
3879 
3880 				/*
3881 				 * Changing foreign table options may affect optimization.
3882 				 */
3883 			case AT_GenericOptions:
3884 			case AT_AlterColumnGenericOptions:
3885 				cmd_lockmode = AccessExclusiveLock;
3886 				break;
3887 
3888 				/*
3889 				 * These subcommands affect write operations only.
3890 				 */
3891 			case AT_EnableTrig:
3892 			case AT_EnableAlwaysTrig:
3893 			case AT_EnableReplicaTrig:
3894 			case AT_EnableTrigAll:
3895 			case AT_EnableTrigUser:
3896 			case AT_DisableTrig:
3897 			case AT_DisableTrigAll:
3898 			case AT_DisableTrigUser:
3899 				cmd_lockmode = ShareRowExclusiveLock;
3900 				break;
3901 
3902 				/*
3903 				 * These subcommands affect write operations only. XXX
3904 				 * Theoretically, these could be ShareRowExclusiveLock.
3905 				 */
3906 			case AT_ColumnDefault:
3907 			case AT_CookedColumnDefault:
3908 			case AT_AlterConstraint:
3909 			case AT_AddIndex:	/* from ADD CONSTRAINT */
3910 			case AT_AddIndexConstraint:
3911 			case AT_ReplicaIdentity:
3912 			case AT_SetNotNull:
3913 			case AT_EnableRowSecurity:
3914 			case AT_DisableRowSecurity:
3915 			case AT_ForceRowSecurity:
3916 			case AT_NoForceRowSecurity:
3917 			case AT_AddIdentity:
3918 			case AT_DropIdentity:
3919 			case AT_SetIdentity:
3920 			case AT_DropExpression:
3921 				cmd_lockmode = AccessExclusiveLock;
3922 				break;
3923 
3924 			case AT_AddConstraint:
3925 			case AT_AddConstraintRecurse:	/* becomes AT_AddConstraint */
3926 			case AT_ReAddConstraint:	/* becomes AT_AddConstraint */
3927 			case AT_ReAddDomainConstraint:	/* becomes AT_AddConstraint */
3928 				if (IsA(cmd->def, Constraint))
3929 				{
3930 					Constraint *con = (Constraint *) cmd->def;
3931 
3932 					switch (con->contype)
3933 					{
3934 						case CONSTR_EXCLUSION:
3935 						case CONSTR_PRIMARY:
3936 						case CONSTR_UNIQUE:
3937 
3938 							/*
3939 							 * Cases essentially the same as CREATE INDEX. We
3940 							 * could reduce the lock strength to ShareLock if
3941 							 * we can work out how to allow concurrent catalog
3942 							 * updates. XXX Might be set down to
3943 							 * ShareRowExclusiveLock but requires further
3944 							 * analysis.
3945 							 */
3946 							cmd_lockmode = AccessExclusiveLock;
3947 							break;
3948 						case CONSTR_FOREIGN:
3949 
3950 							/*
3951 							 * We add triggers to both tables when we add a
3952 							 * Foreign Key, so the lock level must be at least
3953 							 * as strong as CREATE TRIGGER.
3954 							 */
3955 							cmd_lockmode = ShareRowExclusiveLock;
3956 							break;
3957 
3958 						default:
3959 							cmd_lockmode = AccessExclusiveLock;
3960 					}
3961 				}
3962 				break;
3963 
3964 				/*
3965 				 * These subcommands affect inheritance behaviour. Queries
3966 				 * started before us will continue to see the old inheritance
3967 				 * behaviour, while queries started after we commit will see
3968 				 * new behaviour. No need to prevent reads or writes to the
3969 				 * subtable while we hook it up though. Changing the TupDesc
3970 				 * may be a problem, so keep highest lock.
3971 				 */
3972 			case AT_AddInherit:
3973 			case AT_DropInherit:
3974 				cmd_lockmode = AccessExclusiveLock;
3975 				break;
3976 
3977 				/*
3978 				 * These subcommands affect implicit row type conversion. They
3979 				 * have affects similar to CREATE/DROP CAST on queries. don't
3980 				 * provide for invalidating parse trees as a result of such
3981 				 * changes, so we keep these at AccessExclusiveLock.
3982 				 */
3983 			case AT_AddOf:
3984 			case AT_DropOf:
3985 				cmd_lockmode = AccessExclusiveLock;
3986 				break;
3987 
3988 				/*
3989 				 * Only used by CREATE OR REPLACE VIEW which must conflict
3990 				 * with an SELECTs currently using the view.
3991 				 */
3992 			case AT_ReplaceRelOptions:
3993 				cmd_lockmode = AccessExclusiveLock;
3994 				break;
3995 
3996 				/*
3997 				 * These subcommands affect general strategies for performance
3998 				 * and maintenance, though don't change the semantic results
3999 				 * from normal data reads and writes. Delaying an ALTER TABLE
4000 				 * behind currently active writes only delays the point where
4001 				 * the new strategy begins to take effect, so there is no
4002 				 * benefit in waiting. In this case the minimum restriction
4003 				 * applies: we don't currently allow concurrent catalog
4004 				 * updates.
4005 				 */
4006 			case AT_SetStatistics:	/* Uses MVCC in getTableAttrs() */
4007 			case AT_ClusterOn:	/* Uses MVCC in getIndexes() */
4008 			case AT_DropCluster:	/* Uses MVCC in getIndexes() */
4009 			case AT_SetOptions: /* Uses MVCC in getTableAttrs() */
4010 			case AT_ResetOptions:	/* Uses MVCC in getTableAttrs() */
4011 				cmd_lockmode = ShareUpdateExclusiveLock;
4012 				break;
4013 
4014 			case AT_SetLogged:
4015 			case AT_SetUnLogged:
4016 				cmd_lockmode = AccessExclusiveLock;
4017 				break;
4018 
4019 			case AT_ValidateConstraint: /* Uses MVCC in getConstraints() */
4020 				cmd_lockmode = ShareUpdateExclusiveLock;
4021 				break;
4022 
4023 				/*
4024 				 * Rel options are more complex than first appears. Options
4025 				 * are set here for tables, views and indexes; for historical
4026 				 * reasons these can all be used with ALTER TABLE, so we can't
4027 				 * decide between them using the basic grammar.
4028 				 */
4029 			case AT_SetRelOptions:	/* Uses MVCC in getIndexes() and
4030 									 * getTables() */
4031 			case AT_ResetRelOptions:	/* Uses MVCC in getIndexes() and
4032 										 * getTables() */
4033 				cmd_lockmode = AlterTableGetRelOptionsLockLevel((List *) cmd->def);
4034 				break;
4035 
4036 			case AT_AttachPartition:
4037 				cmd_lockmode = ShareUpdateExclusiveLock;
4038 				break;
4039 
4040 			case AT_DetachPartition:
4041 				cmd_lockmode = AccessExclusiveLock;
4042 				break;
4043 
4044 			case AT_CheckNotNull:
4045 
4046 				/*
4047 				 * This only examines the table's schema; but lock must be
4048 				 * strong enough to prevent concurrent DROP NOT NULL.
4049 				 */
4050 				cmd_lockmode = AccessShareLock;
4051 				break;
4052 
4053 			default:			/* oops */
4054 				elog(ERROR, "unrecognized alter table type: %d",
4055 					 (int) cmd->subtype);
4056 				break;
4057 		}
4058 
4059 		/*
4060 		 * Take the greatest lockmode from any subcommand
4061 		 */
4062 		if (cmd_lockmode > lockmode)
4063 			lockmode = cmd_lockmode;
4064 	}
4065 
4066 	return lockmode;
4067 }
4068 
4069 /*
4070  * ATController provides top level control over the phases.
4071  *
4072  * parsetree is passed in to allow it to be passed to event triggers
4073  * when requested.
4074  */
4075 static void
ATController(AlterTableStmt * parsetree,Relation rel,List * cmds,bool recurse,LOCKMODE lockmode,AlterTableUtilityContext * context)4076 ATController(AlterTableStmt *parsetree,
4077 			 Relation rel, List *cmds, bool recurse, LOCKMODE lockmode,
4078 			 AlterTableUtilityContext *context)
4079 {
4080 	List	   *wqueue = NIL;
4081 	ListCell   *lcmd;
4082 
4083 	/* Phase 1: preliminary examination of commands, create work queue */
4084 	foreach(lcmd, cmds)
4085 	{
4086 		AlterTableCmd *cmd = (AlterTableCmd *) lfirst(lcmd);
4087 
4088 		ATPrepCmd(&wqueue, rel, cmd, recurse, false, lockmode, context);
4089 	}
4090 
4091 	/* Close the relation, but keep lock until commit */
4092 	relation_close(rel, NoLock);
4093 
4094 	/* Phase 2: update system catalogs */
4095 	ATRewriteCatalogs(&wqueue, lockmode, context);
4096 
4097 	/* Phase 3: scan/rewrite tables as needed, and run afterStmts */
4098 	ATRewriteTables(parsetree, &wqueue, lockmode, context);
4099 }
4100 
4101 /*
4102  * ATPrepCmd
4103  *
4104  * Traffic cop for ALTER TABLE Phase 1 operations, including simple
4105  * recursion and permission checks.
4106  *
4107  * Caller must have acquired appropriate lock type on relation already.
4108  * This lock should be held until commit.
4109  */
4110 static void
ATPrepCmd(List ** wqueue,Relation rel,AlterTableCmd * cmd,bool recurse,bool recursing,LOCKMODE lockmode,AlterTableUtilityContext * context)4111 ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd,
4112 		  bool recurse, bool recursing, LOCKMODE lockmode,
4113 		  AlterTableUtilityContext *context)
4114 {
4115 	AlteredTableInfo *tab;
4116 	int			pass = AT_PASS_UNSET;
4117 
4118 	/* Find or create work queue entry for this table */
4119 	tab = ATGetQueueEntry(wqueue, rel);
4120 
4121 	/*
4122 	 * Copy the original subcommand for each table.  This avoids conflicts
4123 	 * when different child tables need to make different parse
4124 	 * transformations (for example, the same column may have different column
4125 	 * numbers in different children).  It also ensures that we don't corrupt
4126 	 * the original parse tree, in case it is saved in plancache.
4127 	 */
4128 	cmd = copyObject(cmd);
4129 
4130 	/*
4131 	 * Do permissions and relkind checking, recursion to child tables if
4132 	 * needed, and any additional phase-1 processing needed.  (But beware of
4133 	 * adding any processing that looks at table details that another
4134 	 * subcommand could change.  In some cases we reject multiple subcommands
4135 	 * that could try to change the same state in contrary ways.)
4136 	 */
4137 	switch (cmd->subtype)
4138 	{
4139 		case AT_AddColumn:		/* ADD COLUMN */
4140 			ATSimplePermissions(rel,
4141 								ATT_TABLE | ATT_COMPOSITE_TYPE | ATT_FOREIGN_TABLE);
4142 			ATPrepAddColumn(wqueue, rel, recurse, recursing, false, cmd,
4143 							lockmode, context);
4144 			/* Recursion occurs during execution phase */
4145 			pass = AT_PASS_ADD_COL;
4146 			break;
4147 		case AT_AddColumnToView:	/* add column via CREATE OR REPLACE VIEW */
4148 			ATSimplePermissions(rel, ATT_VIEW);
4149 			ATPrepAddColumn(wqueue, rel, recurse, recursing, true, cmd,
4150 							lockmode, context);
4151 			/* Recursion occurs during execution phase */
4152 			pass = AT_PASS_ADD_COL;
4153 			break;
4154 		case AT_ColumnDefault:	/* ALTER COLUMN DEFAULT */
4155 
4156 			/*
4157 			 * We allow defaults on views so that INSERT into a view can have
4158 			 * default-ish behavior.  This works because the rewriter
4159 			 * substitutes default values into INSERTs before it expands
4160 			 * rules.
4161 			 */
4162 			ATSimplePermissions(rel, ATT_TABLE | ATT_VIEW | ATT_FOREIGN_TABLE);
4163 			ATSimpleRecursion(wqueue, rel, cmd, recurse, lockmode, context);
4164 			/* No command-specific prep needed */
4165 			pass = cmd->def ? AT_PASS_ADD_OTHERCONSTR : AT_PASS_DROP;
4166 			break;
4167 		case AT_CookedColumnDefault:	/* add a pre-cooked default */
4168 			/* This is currently used only in CREATE TABLE */
4169 			/* (so the permission check really isn't necessary) */
4170 			ATSimplePermissions(rel, ATT_TABLE | ATT_FOREIGN_TABLE);
4171 			/* This command never recurses */
4172 			pass = AT_PASS_ADD_OTHERCONSTR;
4173 			break;
4174 		case AT_AddIdentity:
4175 			ATSimplePermissions(rel, ATT_TABLE | ATT_VIEW | ATT_FOREIGN_TABLE);
4176 			/* This command never recurses */
4177 			pass = AT_PASS_ADD_OTHERCONSTR;
4178 			break;
4179 		case AT_SetIdentity:
4180 			ATSimplePermissions(rel, ATT_TABLE | ATT_VIEW | ATT_FOREIGN_TABLE);
4181 			/* This command never recurses */
4182 			/* This should run after AddIdentity, so do it in MISC pass */
4183 			pass = AT_PASS_MISC;
4184 			break;
4185 		case AT_DropIdentity:
4186 			ATSimplePermissions(rel, ATT_TABLE | ATT_VIEW | ATT_FOREIGN_TABLE);
4187 			/* This command never recurses */
4188 			pass = AT_PASS_DROP;
4189 			break;
4190 		case AT_DropNotNull:	/* ALTER COLUMN DROP NOT NULL */
4191 			ATSimplePermissions(rel, ATT_TABLE | ATT_FOREIGN_TABLE);
4192 			ATPrepDropNotNull(rel, recurse, recursing);
4193 			ATSimpleRecursion(wqueue, rel, cmd, recurse, lockmode, context);
4194 			pass = AT_PASS_DROP;
4195 			break;
4196 		case AT_SetNotNull:		/* ALTER COLUMN SET NOT NULL */
4197 			ATSimplePermissions(rel, ATT_TABLE | ATT_FOREIGN_TABLE);
4198 			/* Need command-specific recursion decision */
4199 			ATPrepSetNotNull(wqueue, rel, cmd, recurse, recursing,
4200 							 lockmode, context);
4201 			pass = AT_PASS_COL_ATTRS;
4202 			break;
4203 		case AT_CheckNotNull:	/* check column is already marked NOT NULL */
4204 			ATSimplePermissions(rel, ATT_TABLE | ATT_FOREIGN_TABLE);
4205 			ATSimpleRecursion(wqueue, rel, cmd, recurse, lockmode, context);
4206 			/* No command-specific prep needed */
4207 			pass = AT_PASS_COL_ATTRS;
4208 			break;
4209 		case AT_DropExpression: /* ALTER COLUMN DROP EXPRESSION */
4210 			ATSimplePermissions(rel, ATT_TABLE | ATT_FOREIGN_TABLE);
4211 			ATSimpleRecursion(wqueue, rel, cmd, recurse, lockmode, context);
4212 			ATPrepDropExpression(rel, cmd, recurse, recursing, lockmode);
4213 			pass = AT_PASS_DROP;
4214 			break;
4215 		case AT_SetStatistics:	/* ALTER COLUMN SET STATISTICS */
4216 			ATSimplePermissions(rel, ATT_TABLE | ATT_MATVIEW | ATT_INDEX | ATT_PARTITIONED_INDEX | ATT_FOREIGN_TABLE);
4217 			ATSimpleRecursion(wqueue, rel, cmd, recurse, lockmode, context);
4218 			/* No command-specific prep needed */
4219 			pass = AT_PASS_MISC;
4220 			break;
4221 		case AT_SetOptions:		/* ALTER COLUMN SET ( options ) */
4222 		case AT_ResetOptions:	/* ALTER COLUMN RESET ( options ) */
4223 			ATSimplePermissions(rel, ATT_TABLE | ATT_MATVIEW | ATT_FOREIGN_TABLE);
4224 			/* This command never recurses */
4225 			pass = AT_PASS_MISC;
4226 			break;
4227 		case AT_SetStorage:		/* ALTER COLUMN SET STORAGE */
4228 			ATSimplePermissions(rel, ATT_TABLE | ATT_MATVIEW | ATT_FOREIGN_TABLE);
4229 			ATSimpleRecursion(wqueue, rel, cmd, recurse, lockmode, context);
4230 			/* No command-specific prep needed */
4231 			pass = AT_PASS_MISC;
4232 			break;
4233 		case AT_DropColumn:		/* DROP COLUMN */
4234 			ATSimplePermissions(rel,
4235 								ATT_TABLE | ATT_COMPOSITE_TYPE | ATT_FOREIGN_TABLE);
4236 			ATPrepDropColumn(wqueue, rel, recurse, recursing, cmd,
4237 							 lockmode, context);
4238 			/* Recursion occurs during execution phase */
4239 			pass = AT_PASS_DROP;
4240 			break;
4241 		case AT_AddIndex:		/* ADD INDEX */
4242 			ATSimplePermissions(rel, ATT_TABLE);
4243 			/* This command never recurses */
4244 			/* No command-specific prep needed */
4245 			pass = AT_PASS_ADD_INDEX;
4246 			break;
4247 		case AT_AddConstraint:	/* ADD CONSTRAINT */
4248 			ATSimplePermissions(rel, ATT_TABLE | ATT_FOREIGN_TABLE);
4249 			/* Recursion occurs during execution phase */
4250 			/* No command-specific prep needed except saving recurse flag */
4251 			if (recurse)
4252 				cmd->subtype = AT_AddConstraintRecurse;
4253 			pass = AT_PASS_ADD_CONSTR;
4254 			break;
4255 		case AT_AddIndexConstraint: /* ADD CONSTRAINT USING INDEX */
4256 			ATSimplePermissions(rel, ATT_TABLE);
4257 			/* This command never recurses */
4258 			/* No command-specific prep needed */
4259 			pass = AT_PASS_ADD_INDEXCONSTR;
4260 			break;
4261 		case AT_DropConstraint: /* DROP CONSTRAINT */
4262 			ATSimplePermissions(rel, ATT_TABLE | ATT_FOREIGN_TABLE);
4263 			ATCheckPartitionsNotInUse(rel, lockmode);
4264 			/* Other recursion occurs during execution phase */
4265 			/* No command-specific prep needed except saving recurse flag */
4266 			if (recurse)
4267 				cmd->subtype = AT_DropConstraintRecurse;
4268 			pass = AT_PASS_DROP;
4269 			break;
4270 		case AT_AlterColumnType:	/* ALTER COLUMN TYPE */
4271 			ATSimplePermissions(rel,
4272 								ATT_TABLE | ATT_COMPOSITE_TYPE | ATT_FOREIGN_TABLE);
4273 			/* See comments for ATPrepAlterColumnType */
4274 			cmd = ATParseTransformCmd(wqueue, tab, rel, cmd, recurse, lockmode,
4275 									  AT_PASS_UNSET, context);
4276 			Assert(cmd != NULL);
4277 			/* Performs own recursion */
4278 			ATPrepAlterColumnType(wqueue, tab, rel, recurse, recursing, cmd,
4279 								  lockmode, context);
4280 			pass = AT_PASS_ALTER_TYPE;
4281 			break;
4282 		case AT_AlterColumnGenericOptions:
4283 			ATSimplePermissions(rel, ATT_FOREIGN_TABLE);
4284 			/* This command never recurses */
4285 			/* No command-specific prep needed */
4286 			pass = AT_PASS_MISC;
4287 			break;
4288 		case AT_ChangeOwner:	/* ALTER OWNER */
4289 			/* This command never recurses */
4290 			/* No command-specific prep needed */
4291 			pass = AT_PASS_MISC;
4292 			break;
4293 		case AT_ClusterOn:		/* CLUSTER ON */
4294 		case AT_DropCluster:	/* SET WITHOUT CLUSTER */
4295 			ATSimplePermissions(rel, ATT_TABLE | ATT_MATVIEW);
4296 			/* These commands never recurse */
4297 			/* No command-specific prep needed */
4298 			pass = AT_PASS_MISC;
4299 			break;
4300 		case AT_SetLogged:		/* SET LOGGED */
4301 			ATSimplePermissions(rel, ATT_TABLE);
4302 			if (tab->chgPersistence)
4303 				ereport(ERROR,
4304 						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
4305 						 errmsg("cannot change persistence setting twice")));
4306 			tab->chgPersistence = ATPrepChangePersistence(rel, true);
4307 			/* force rewrite if necessary; see comment in ATRewriteTables */
4308 			if (tab->chgPersistence)
4309 			{
4310 				tab->rewrite |= AT_REWRITE_ALTER_PERSISTENCE;
4311 				tab->newrelpersistence = RELPERSISTENCE_PERMANENT;
4312 			}
4313 			pass = AT_PASS_MISC;
4314 			break;
4315 		case AT_SetUnLogged:	/* SET UNLOGGED */
4316 			ATSimplePermissions(rel, ATT_TABLE);
4317 			if (tab->chgPersistence)
4318 				ereport(ERROR,
4319 						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
4320 						 errmsg("cannot change persistence setting twice")));
4321 			tab->chgPersistence = ATPrepChangePersistence(rel, false);
4322 			/* force rewrite if necessary; see comment in ATRewriteTables */
4323 			if (tab->chgPersistence)
4324 			{
4325 				tab->rewrite |= AT_REWRITE_ALTER_PERSISTENCE;
4326 				tab->newrelpersistence = RELPERSISTENCE_UNLOGGED;
4327 			}
4328 			pass = AT_PASS_MISC;
4329 			break;
4330 		case AT_DropOids:		/* SET WITHOUT OIDS */
4331 			ATSimplePermissions(rel, ATT_TABLE | ATT_FOREIGN_TABLE);
4332 			pass = AT_PASS_DROP;
4333 			break;
4334 		case AT_SetTableSpace:	/* SET TABLESPACE */
4335 			ATSimplePermissions(rel, ATT_TABLE | ATT_MATVIEW | ATT_INDEX |
4336 								ATT_PARTITIONED_INDEX);
4337 			/* This command never recurses */
4338 			ATPrepSetTableSpace(tab, rel, cmd->name, lockmode);
4339 			pass = AT_PASS_MISC;	/* doesn't actually matter */
4340 			break;
4341 		case AT_SetRelOptions:	/* SET (...) */
4342 		case AT_ResetRelOptions:	/* RESET (...) */
4343 		case AT_ReplaceRelOptions:	/* reset them all, then set just these */
4344 			ATSimplePermissions(rel, ATT_TABLE | ATT_VIEW | ATT_MATVIEW | ATT_INDEX);
4345 			/* This command never recurses */
4346 			/* No command-specific prep needed */
4347 			pass = AT_PASS_MISC;
4348 			break;
4349 		case AT_AddInherit:		/* INHERIT */
4350 			ATSimplePermissions(rel, ATT_TABLE | ATT_FOREIGN_TABLE);
4351 			/* This command never recurses */
4352 			ATPrepAddInherit(rel);
4353 			pass = AT_PASS_MISC;
4354 			break;
4355 		case AT_DropInherit:	/* NO INHERIT */
4356 			ATSimplePermissions(rel, ATT_TABLE | ATT_FOREIGN_TABLE);
4357 			/* This command never recurses */
4358 			/* No command-specific prep needed */
4359 			pass = AT_PASS_MISC;
4360 			break;
4361 		case AT_AlterConstraint:	/* ALTER CONSTRAINT */
4362 			ATSimplePermissions(rel, ATT_TABLE);
4363 			/* Recursion occurs during execution phase */
4364 			pass = AT_PASS_MISC;
4365 			break;
4366 		case AT_ValidateConstraint: /* VALIDATE CONSTRAINT */
4367 			ATSimplePermissions(rel, ATT_TABLE | ATT_FOREIGN_TABLE);
4368 			/* Recursion occurs during execution phase */
4369 			/* No command-specific prep needed except saving recurse flag */
4370 			if (recurse)
4371 				cmd->subtype = AT_ValidateConstraintRecurse;
4372 			pass = AT_PASS_MISC;
4373 			break;
4374 		case AT_ReplicaIdentity:	/* REPLICA IDENTITY ... */
4375 			ATSimplePermissions(rel, ATT_TABLE | ATT_MATVIEW);
4376 			pass = AT_PASS_MISC;
4377 			/* This command never recurses */
4378 			/* No command-specific prep needed */
4379 			break;
4380 		case AT_EnableTrig:		/* ENABLE TRIGGER variants */
4381 		case AT_EnableAlwaysTrig:
4382 		case AT_EnableReplicaTrig:
4383 		case AT_EnableTrigAll:
4384 		case AT_EnableTrigUser:
4385 		case AT_DisableTrig:	/* DISABLE TRIGGER variants */
4386 		case AT_DisableTrigAll:
4387 		case AT_DisableTrigUser:
4388 			ATSimplePermissions(rel, ATT_TABLE | ATT_FOREIGN_TABLE);
4389 			if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
4390 				ATSimpleRecursion(wqueue, rel, cmd, recurse, lockmode, context);
4391 			pass = AT_PASS_MISC;
4392 			break;
4393 		case AT_EnableRule:		/* ENABLE/DISABLE RULE variants */
4394 		case AT_EnableAlwaysRule:
4395 		case AT_EnableReplicaRule:
4396 		case AT_DisableRule:
4397 		case AT_AddOf:			/* OF */
4398 		case AT_DropOf:			/* NOT OF */
4399 		case AT_EnableRowSecurity:
4400 		case AT_DisableRowSecurity:
4401 		case AT_ForceRowSecurity:
4402 		case AT_NoForceRowSecurity:
4403 			ATSimplePermissions(rel, ATT_TABLE);
4404 			/* These commands never recurse */
4405 			/* No command-specific prep needed */
4406 			pass = AT_PASS_MISC;
4407 			break;
4408 		case AT_GenericOptions:
4409 			ATSimplePermissions(rel, ATT_FOREIGN_TABLE);
4410 			/* No command-specific prep needed */
4411 			pass = AT_PASS_MISC;
4412 			break;
4413 		case AT_AttachPartition:
4414 			ATSimplePermissions(rel, ATT_TABLE | ATT_PARTITIONED_INDEX);
4415 			/* No command-specific prep needed */
4416 			pass = AT_PASS_MISC;
4417 			break;
4418 		case AT_DetachPartition:
4419 			ATSimplePermissions(rel, ATT_TABLE);
4420 			/* No command-specific prep needed */
4421 			pass = AT_PASS_MISC;
4422 			break;
4423 		default:				/* oops */
4424 			elog(ERROR, "unrecognized alter table type: %d",
4425 				 (int) cmd->subtype);
4426 			pass = AT_PASS_UNSET;	/* keep compiler quiet */
4427 			break;
4428 	}
4429 	Assert(pass > AT_PASS_UNSET);
4430 
4431 	/* Add the subcommand to the appropriate list for phase 2 */
4432 	tab->subcmds[pass] = lappend(tab->subcmds[pass], cmd);
4433 }
4434 
4435 /*
4436  * ATRewriteCatalogs
4437  *
4438  * Traffic cop for ALTER TABLE Phase 2 operations.  Subcommands are
4439  * dispatched in a "safe" execution order (designed to avoid unnecessary
4440  * conflicts).
4441  */
4442 static void
ATRewriteCatalogs(List ** wqueue,LOCKMODE lockmode,AlterTableUtilityContext * context)4443 ATRewriteCatalogs(List **wqueue, LOCKMODE lockmode,
4444 				  AlterTableUtilityContext *context)
4445 {
4446 	int			pass;
4447 	ListCell   *ltab;
4448 
4449 	/*
4450 	 * We process all the tables "in parallel", one pass at a time.  This is
4451 	 * needed because we may have to propagate work from one table to another
4452 	 * (specifically, ALTER TYPE on a foreign key's PK has to dispatch the
4453 	 * re-adding of the foreign key constraint to the other table).  Work can
4454 	 * only be propagated into later passes, however.
4455 	 */
4456 	for (pass = 0; pass < AT_NUM_PASSES; pass++)
4457 	{
4458 		/* Go through each table that needs to be processed */
4459 		foreach(ltab, *wqueue)
4460 		{
4461 			AlteredTableInfo *tab = (AlteredTableInfo *) lfirst(ltab);
4462 			List	   *subcmds = tab->subcmds[pass];
4463 			Relation	rel;
4464 			ListCell   *lcmd;
4465 
4466 			if (subcmds == NIL)
4467 				continue;
4468 
4469 			/*
4470 			 * Appropriate lock was obtained by phase 1, needn't get it again
4471 			 */
4472 			rel = relation_open(tab->relid, NoLock);
4473 
4474 			foreach(lcmd, subcmds)
4475 				ATExecCmd(wqueue, tab, rel,
4476 						  castNode(AlterTableCmd, lfirst(lcmd)),
4477 						  lockmode, pass, context);
4478 
4479 			/*
4480 			 * After the ALTER TYPE pass, do cleanup work (this is not done in
4481 			 * ATExecAlterColumnType since it should be done only once if
4482 			 * multiple columns of a table are altered).
4483 			 */
4484 			if (pass == AT_PASS_ALTER_TYPE)
4485 				ATPostAlterTypeCleanup(wqueue, tab, lockmode);
4486 
4487 			relation_close(rel, NoLock);
4488 		}
4489 	}
4490 
4491 	/* Check to see if a toast table must be added. */
4492 	foreach(ltab, *wqueue)
4493 	{
4494 		AlteredTableInfo *tab = (AlteredTableInfo *) lfirst(ltab);
4495 
4496 		/*
4497 		 * If the table is source table of ATTACH PARTITION command, we did
4498 		 * not modify anything about it that will change its toasting
4499 		 * requirement, so no need to check.
4500 		 */
4501 		if (((tab->relkind == RELKIND_RELATION ||
4502 			  tab->relkind == RELKIND_PARTITIONED_TABLE) &&
4503 			 tab->partition_constraint == NULL) ||
4504 			tab->relkind == RELKIND_MATVIEW)
4505 			AlterTableCreateToastTable(tab->relid, (Datum) 0, lockmode);
4506 	}
4507 }
4508 
4509 /*
4510  * ATExecCmd: dispatch a subcommand to appropriate execution routine
4511  */
4512 static void
ATExecCmd(List ** wqueue,AlteredTableInfo * tab,Relation rel,AlterTableCmd * cmd,LOCKMODE lockmode,int cur_pass,AlterTableUtilityContext * context)4513 ATExecCmd(List **wqueue, AlteredTableInfo *tab, Relation rel,
4514 		  AlterTableCmd *cmd, LOCKMODE lockmode, int cur_pass,
4515 		  AlterTableUtilityContext *context)
4516 {
4517 	ObjectAddress address = InvalidObjectAddress;
4518 
4519 	switch (cmd->subtype)
4520 	{
4521 		case AT_AddColumn:		/* ADD COLUMN */
4522 		case AT_AddColumnToView:	/* add column via CREATE OR REPLACE VIEW */
4523 			address = ATExecAddColumn(wqueue, tab, rel, &cmd,
4524 									  false, false,
4525 									  lockmode, cur_pass, context);
4526 			break;
4527 		case AT_AddColumnRecurse:
4528 			address = ATExecAddColumn(wqueue, tab, rel, &cmd,
4529 									  true, false,
4530 									  lockmode, cur_pass, context);
4531 			break;
4532 		case AT_ColumnDefault:	/* ALTER COLUMN DEFAULT */
4533 			address = ATExecColumnDefault(rel, cmd->name, cmd->def, lockmode);
4534 			break;
4535 		case AT_CookedColumnDefault:	/* add a pre-cooked default */
4536 			address = ATExecCookedColumnDefault(rel, cmd->num, cmd->def);
4537 			break;
4538 		case AT_AddIdentity:
4539 			cmd = ATParseTransformCmd(wqueue, tab, rel, cmd, false, lockmode,
4540 									  cur_pass, context);
4541 			Assert(cmd != NULL);
4542 			address = ATExecAddIdentity(rel, cmd->name, cmd->def, lockmode);
4543 			break;
4544 		case AT_SetIdentity:
4545 			cmd = ATParseTransformCmd(wqueue, tab, rel, cmd, false, lockmode,
4546 									  cur_pass, context);
4547 			Assert(cmd != NULL);
4548 			address = ATExecSetIdentity(rel, cmd->name, cmd->def, lockmode);
4549 			break;
4550 		case AT_DropIdentity:
4551 			address = ATExecDropIdentity(rel, cmd->name, cmd->missing_ok, lockmode);
4552 			break;
4553 		case AT_DropNotNull:	/* ALTER COLUMN DROP NOT NULL */
4554 			address = ATExecDropNotNull(rel, cmd->name, lockmode);
4555 			break;
4556 		case AT_SetNotNull:		/* ALTER COLUMN SET NOT NULL */
4557 			address = ATExecSetNotNull(tab, rel, cmd->name, lockmode);
4558 			break;
4559 		case AT_CheckNotNull:	/* check column is already marked NOT NULL */
4560 			ATExecCheckNotNull(tab, rel, cmd->name, lockmode);
4561 			break;
4562 		case AT_DropExpression:
4563 			address = ATExecDropExpression(rel, cmd->name, cmd->missing_ok, lockmode);
4564 			break;
4565 		case AT_SetStatistics:	/* ALTER COLUMN SET STATISTICS */
4566 			address = ATExecSetStatistics(rel, cmd->name, cmd->num, cmd->def, lockmode);
4567 			break;
4568 		case AT_SetOptions:		/* ALTER COLUMN SET ( options ) */
4569 			address = ATExecSetOptions(rel, cmd->name, cmd->def, false, lockmode);
4570 			break;
4571 		case AT_ResetOptions:	/* ALTER COLUMN RESET ( options ) */
4572 			address = ATExecSetOptions(rel, cmd->name, cmd->def, true, lockmode);
4573 			break;
4574 		case AT_SetStorage:		/* ALTER COLUMN SET STORAGE */
4575 			address = ATExecSetStorage(rel, cmd->name, cmd->def, lockmode);
4576 			break;
4577 		case AT_DropColumn:		/* DROP COLUMN */
4578 			address = ATExecDropColumn(wqueue, rel, cmd->name,
4579 									   cmd->behavior, false, false,
4580 									   cmd->missing_ok, lockmode,
4581 									   NULL);
4582 			break;
4583 		case AT_DropColumnRecurse:	/* DROP COLUMN with recursion */
4584 			address = ATExecDropColumn(wqueue, rel, cmd->name,
4585 									   cmd->behavior, true, false,
4586 									   cmd->missing_ok, lockmode,
4587 									   NULL);
4588 			break;
4589 		case AT_AddIndex:		/* ADD INDEX */
4590 			address = ATExecAddIndex(tab, rel, (IndexStmt *) cmd->def, false,
4591 									 lockmode);
4592 			break;
4593 		case AT_ReAddIndex:		/* ADD INDEX */
4594 			address = ATExecAddIndex(tab, rel, (IndexStmt *) cmd->def, true,
4595 									 lockmode);
4596 			break;
4597 		case AT_AddConstraint:	/* ADD CONSTRAINT */
4598 			/* Transform the command only during initial examination */
4599 			if (cur_pass == AT_PASS_ADD_CONSTR)
4600 				cmd = ATParseTransformCmd(wqueue, tab, rel, cmd,
4601 										  false, lockmode,
4602 										  cur_pass, context);
4603 			/* Depending on constraint type, might be no more work to do now */
4604 			if (cmd != NULL)
4605 				address =
4606 					ATExecAddConstraint(wqueue, tab, rel,
4607 										(Constraint *) cmd->def,
4608 										false, false, lockmode);
4609 			break;
4610 		case AT_AddConstraintRecurse:	/* ADD CONSTRAINT with recursion */
4611 			/* Transform the command only during initial examination */
4612 			if (cur_pass == AT_PASS_ADD_CONSTR)
4613 				cmd = ATParseTransformCmd(wqueue, tab, rel, cmd,
4614 										  true, lockmode,
4615 										  cur_pass, context);
4616 			/* Depending on constraint type, might be no more work to do now */
4617 			if (cmd != NULL)
4618 				address =
4619 					ATExecAddConstraint(wqueue, tab, rel,
4620 										(Constraint *) cmd->def,
4621 										true, false, lockmode);
4622 			break;
4623 		case AT_ReAddConstraint:	/* Re-add pre-existing check constraint */
4624 			address =
4625 				ATExecAddConstraint(wqueue, tab, rel, (Constraint *) cmd->def,
4626 									true, true, lockmode);
4627 			break;
4628 		case AT_ReAddDomainConstraint:	/* Re-add pre-existing domain check
4629 										 * constraint */
4630 			address =
4631 				AlterDomainAddConstraint(((AlterDomainStmt *) cmd->def)->typeName,
4632 										 ((AlterDomainStmt *) cmd->def)->def,
4633 										 NULL);
4634 			break;
4635 		case AT_ReAddComment:	/* Re-add existing comment */
4636 			address = CommentObject((CommentStmt *) cmd->def);
4637 			break;
4638 		case AT_AddIndexConstraint: /* ADD CONSTRAINT USING INDEX */
4639 			address = ATExecAddIndexConstraint(tab, rel, (IndexStmt *) cmd->def,
4640 											   lockmode);
4641 			break;
4642 		case AT_AlterConstraint:	/* ALTER CONSTRAINT */
4643 			address = ATExecAlterConstraint(rel, cmd, false, false, lockmode);
4644 			break;
4645 		case AT_ValidateConstraint: /* VALIDATE CONSTRAINT */
4646 			address = ATExecValidateConstraint(wqueue, rel, cmd->name, false,
4647 											   false, lockmode);
4648 			break;
4649 		case AT_ValidateConstraintRecurse:	/* VALIDATE CONSTRAINT with
4650 											 * recursion */
4651 			address = ATExecValidateConstraint(wqueue, rel, cmd->name, true,
4652 											   false, lockmode);
4653 			break;
4654 		case AT_DropConstraint: /* DROP CONSTRAINT */
4655 			ATExecDropConstraint(rel, cmd->name, cmd->behavior,
4656 								 false, false,
4657 								 cmd->missing_ok, lockmode);
4658 			break;
4659 		case AT_DropConstraintRecurse:	/* DROP CONSTRAINT with recursion */
4660 			ATExecDropConstraint(rel, cmd->name, cmd->behavior,
4661 								 true, false,
4662 								 cmd->missing_ok, lockmode);
4663 			break;
4664 		case AT_AlterColumnType:	/* ALTER COLUMN TYPE */
4665 			/* parse transformation was done earlier */
4666 			address = ATExecAlterColumnType(tab, rel, cmd, lockmode);
4667 			break;
4668 		case AT_AlterColumnGenericOptions:	/* ALTER COLUMN OPTIONS */
4669 			address =
4670 				ATExecAlterColumnGenericOptions(rel, cmd->name,
4671 												(List *) cmd->def, lockmode);
4672 			break;
4673 		case AT_ChangeOwner:	/* ALTER OWNER */
4674 			ATExecChangeOwner(RelationGetRelid(rel),
4675 							  get_rolespec_oid(cmd->newowner, false),
4676 							  false, lockmode);
4677 			break;
4678 		case AT_ClusterOn:		/* CLUSTER ON */
4679 			address = ATExecClusterOn(rel, cmd->name, lockmode);
4680 			break;
4681 		case AT_DropCluster:	/* SET WITHOUT CLUSTER */
4682 			ATExecDropCluster(rel, lockmode);
4683 			break;
4684 		case AT_SetLogged:		/* SET LOGGED */
4685 		case AT_SetUnLogged:	/* SET UNLOGGED */
4686 			break;
4687 		case AT_DropOids:		/* SET WITHOUT OIDS */
4688 			/* nothing to do here, oid columns don't exist anymore */
4689 			break;
4690 		case AT_SetTableSpace:	/* SET TABLESPACE */
4691 
4692 			/*
4693 			 * Only do this for partitioned tables and indexes, for which this
4694 			 * is just a catalog change.  Other relation types which have
4695 			 * storage are handled by Phase 3.
4696 			 */
4697 			if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE ||
4698 				rel->rd_rel->relkind == RELKIND_PARTITIONED_INDEX)
4699 				ATExecSetTableSpaceNoStorage(rel, tab->newTableSpace);
4700 
4701 			break;
4702 		case AT_SetRelOptions:	/* SET (...) */
4703 		case AT_ResetRelOptions:	/* RESET (...) */
4704 		case AT_ReplaceRelOptions:	/* replace entire option list */
4705 			ATExecSetRelOptions(rel, (List *) cmd->def, cmd->subtype, lockmode);
4706 			break;
4707 		case AT_EnableTrig:		/* ENABLE TRIGGER name */
4708 			ATExecEnableDisableTrigger(rel, cmd->name,
4709 									   TRIGGER_FIRES_ON_ORIGIN, false, lockmode);
4710 			break;
4711 		case AT_EnableAlwaysTrig:	/* ENABLE ALWAYS TRIGGER name */
4712 			ATExecEnableDisableTrigger(rel, cmd->name,
4713 									   TRIGGER_FIRES_ALWAYS, false, lockmode);
4714 			break;
4715 		case AT_EnableReplicaTrig:	/* ENABLE REPLICA TRIGGER name */
4716 			ATExecEnableDisableTrigger(rel, cmd->name,
4717 									   TRIGGER_FIRES_ON_REPLICA, false, lockmode);
4718 			break;
4719 		case AT_DisableTrig:	/* DISABLE TRIGGER name */
4720 			ATExecEnableDisableTrigger(rel, cmd->name,
4721 									   TRIGGER_DISABLED, false, lockmode);
4722 			break;
4723 		case AT_EnableTrigAll:	/* ENABLE TRIGGER ALL */
4724 			ATExecEnableDisableTrigger(rel, NULL,
4725 									   TRIGGER_FIRES_ON_ORIGIN, false, lockmode);
4726 			break;
4727 		case AT_DisableTrigAll: /* DISABLE TRIGGER ALL */
4728 			ATExecEnableDisableTrigger(rel, NULL,
4729 									   TRIGGER_DISABLED, false, lockmode);
4730 			break;
4731 		case AT_EnableTrigUser: /* ENABLE TRIGGER USER */
4732 			ATExecEnableDisableTrigger(rel, NULL,
4733 									   TRIGGER_FIRES_ON_ORIGIN, true, lockmode);
4734 			break;
4735 		case AT_DisableTrigUser:	/* DISABLE TRIGGER USER */
4736 			ATExecEnableDisableTrigger(rel, NULL,
4737 									   TRIGGER_DISABLED, true, lockmode);
4738 			break;
4739 
4740 		case AT_EnableRule:		/* ENABLE RULE name */
4741 			ATExecEnableDisableRule(rel, cmd->name,
4742 									RULE_FIRES_ON_ORIGIN, lockmode);
4743 			break;
4744 		case AT_EnableAlwaysRule:	/* ENABLE ALWAYS RULE name */
4745 			ATExecEnableDisableRule(rel, cmd->name,
4746 									RULE_FIRES_ALWAYS, lockmode);
4747 			break;
4748 		case AT_EnableReplicaRule:	/* ENABLE REPLICA RULE name */
4749 			ATExecEnableDisableRule(rel, cmd->name,
4750 									RULE_FIRES_ON_REPLICA, lockmode);
4751 			break;
4752 		case AT_DisableRule:	/* DISABLE RULE name */
4753 			ATExecEnableDisableRule(rel, cmd->name,
4754 									RULE_DISABLED, lockmode);
4755 			break;
4756 
4757 		case AT_AddInherit:
4758 			address = ATExecAddInherit(rel, (RangeVar *) cmd->def, lockmode);
4759 			break;
4760 		case AT_DropInherit:
4761 			address = ATExecDropInherit(rel, (RangeVar *) cmd->def, lockmode);
4762 			break;
4763 		case AT_AddOf:
4764 			address = ATExecAddOf(rel, (TypeName *) cmd->def, lockmode);
4765 			break;
4766 		case AT_DropOf:
4767 			ATExecDropOf(rel, lockmode);
4768 			break;
4769 		case AT_ReplicaIdentity:
4770 			ATExecReplicaIdentity(rel, (ReplicaIdentityStmt *) cmd->def, lockmode);
4771 			break;
4772 		case AT_EnableRowSecurity:
4773 			ATExecEnableRowSecurity(rel);
4774 			break;
4775 		case AT_DisableRowSecurity:
4776 			ATExecDisableRowSecurity(rel);
4777 			break;
4778 		case AT_ForceRowSecurity:
4779 			ATExecForceNoForceRowSecurity(rel, true);
4780 			break;
4781 		case AT_NoForceRowSecurity:
4782 			ATExecForceNoForceRowSecurity(rel, false);
4783 			break;
4784 		case AT_GenericOptions:
4785 			ATExecGenericOptions(rel, (List *) cmd->def);
4786 			break;
4787 		case AT_AttachPartition:
4788 			cmd = ATParseTransformCmd(wqueue, tab, rel, cmd, false, lockmode,
4789 									  cur_pass, context);
4790 			Assert(cmd != NULL);
4791 			if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
4792 				ATExecAttachPartition(wqueue, rel, (PartitionCmd *) cmd->def);
4793 			else
4794 				ATExecAttachPartitionIdx(wqueue, rel,
4795 										 ((PartitionCmd *) cmd->def)->name);
4796 			break;
4797 		case AT_DetachPartition:
4798 			cmd = ATParseTransformCmd(wqueue, tab, rel, cmd, false, lockmode,
4799 									  cur_pass, context);
4800 			Assert(cmd != NULL);
4801 			/* ATPrepCmd ensures it must be a table */
4802 			Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
4803 			ATExecDetachPartition(rel, ((PartitionCmd *) cmd->def)->name);
4804 			break;
4805 		default:				/* oops */
4806 			elog(ERROR, "unrecognized alter table type: %d",
4807 				 (int) cmd->subtype);
4808 			break;
4809 	}
4810 
4811 	/*
4812 	 * Report the subcommand to interested event triggers.
4813 	 */
4814 	if (cmd)
4815 		EventTriggerCollectAlterTableSubcmd((Node *) cmd, address);
4816 
4817 	/*
4818 	 * Bump the command counter to ensure the next subcommand in the sequence
4819 	 * can see the changes so far
4820 	 */
4821 	CommandCounterIncrement();
4822 }
4823 
4824 /*
4825  * ATParseTransformCmd: perform parse transformation for one subcommand
4826  *
4827  * Returns the transformed subcommand tree, if there is one, else NULL.
4828  *
4829  * The parser may hand back additional AlterTableCmd(s) and/or other
4830  * utility statements, either before or after the original subcommand.
4831  * Other AlterTableCmds are scheduled into the appropriate slot of the
4832  * AlteredTableInfo (they had better be for later passes than the current one).
4833  * Utility statements that are supposed to happen before the AlterTableCmd
4834  * are executed immediately.  Those that are supposed to happen afterwards
4835  * are added to the tab->afterStmts list to be done at the very end.
4836  */
4837 static AlterTableCmd *
ATParseTransformCmd(List ** wqueue,AlteredTableInfo * tab,Relation rel,AlterTableCmd * cmd,bool recurse,LOCKMODE lockmode,int cur_pass,AlterTableUtilityContext * context)4838 ATParseTransformCmd(List **wqueue, AlteredTableInfo *tab, Relation rel,
4839 					AlterTableCmd *cmd, bool recurse, LOCKMODE lockmode,
4840 					int cur_pass, AlterTableUtilityContext *context)
4841 {
4842 	AlterTableCmd *newcmd = NULL;
4843 	AlterTableStmt *atstmt = makeNode(AlterTableStmt);
4844 	List	   *beforeStmts;
4845 	List	   *afterStmts;
4846 	ListCell   *lc;
4847 
4848 	/* Gin up an AlterTableStmt with just this subcommand and this table */
4849 	atstmt->relation =
4850 		makeRangeVar(get_namespace_name(RelationGetNamespace(rel)),
4851 					 pstrdup(RelationGetRelationName(rel)),
4852 					 -1);
4853 	atstmt->relation->inh = recurse;
4854 	atstmt->cmds = list_make1(cmd);
4855 	atstmt->relkind = OBJECT_TABLE; /* needn't be picky here */
4856 	atstmt->missing_ok = false;
4857 
4858 	/* Transform the AlterTableStmt */
4859 	atstmt = transformAlterTableStmt(RelationGetRelid(rel),
4860 									 atstmt,
4861 									 context->queryString,
4862 									 &beforeStmts,
4863 									 &afterStmts);
4864 
4865 	/* Execute any statements that should happen before these subcommand(s) */
4866 	foreach(lc, beforeStmts)
4867 	{
4868 		Node	   *stmt = (Node *) lfirst(lc);
4869 
4870 		ProcessUtilityForAlterTable(stmt, context);
4871 		CommandCounterIncrement();
4872 	}
4873 
4874 	/* Examine the transformed subcommands and schedule them appropriately */
4875 	foreach(lc, atstmt->cmds)
4876 	{
4877 		AlterTableCmd *cmd2 = lfirst_node(AlterTableCmd, lc);
4878 		int			pass;
4879 
4880 		/*
4881 		 * This switch need only cover the subcommand types that can be added
4882 		 * by parse_utilcmd.c; otherwise, we'll use the default strategy of
4883 		 * executing the subcommand immediately, as a substitute for the
4884 		 * original subcommand.  (Note, however, that this does cause
4885 		 * AT_AddConstraint subcommands to be rescheduled into later passes,
4886 		 * which is important for index and foreign key constraints.)
4887 		 *
4888 		 * We assume we needn't do any phase-1 checks for added subcommands.
4889 		 */
4890 		switch (cmd2->subtype)
4891 		{
4892 			case AT_SetNotNull:
4893 				/* Need command-specific recursion decision */
4894 				ATPrepSetNotNull(wqueue, rel, cmd2,
4895 								 recurse, false,
4896 								 lockmode, context);
4897 				pass = AT_PASS_COL_ATTRS;
4898 				break;
4899 			case AT_AddIndex:
4900 				/* This command never recurses */
4901 				/* No command-specific prep needed */
4902 				pass = AT_PASS_ADD_INDEX;
4903 				break;
4904 			case AT_AddIndexConstraint:
4905 				/* This command never recurses */
4906 				/* No command-specific prep needed */
4907 				pass = AT_PASS_ADD_INDEXCONSTR;
4908 				break;
4909 			case AT_AddConstraint:
4910 				/* Recursion occurs during execution phase */
4911 				if (recurse)
4912 					cmd2->subtype = AT_AddConstraintRecurse;
4913 				switch (castNode(Constraint, cmd2->def)->contype)
4914 				{
4915 					case CONSTR_PRIMARY:
4916 					case CONSTR_UNIQUE:
4917 					case CONSTR_EXCLUSION:
4918 						pass = AT_PASS_ADD_INDEXCONSTR;
4919 						break;
4920 					default:
4921 						pass = AT_PASS_ADD_OTHERCONSTR;
4922 						break;
4923 				}
4924 				break;
4925 			case AT_AlterColumnGenericOptions:
4926 				/* This command never recurses */
4927 				/* No command-specific prep needed */
4928 				pass = AT_PASS_MISC;
4929 				break;
4930 			default:
4931 				pass = cur_pass;
4932 				break;
4933 		}
4934 
4935 		if (pass < cur_pass)
4936 		{
4937 			/* Cannot schedule into a pass we already finished */
4938 			elog(ERROR, "ALTER TABLE scheduling failure: too late for pass %d",
4939 				 pass);
4940 		}
4941 		else if (pass > cur_pass)
4942 		{
4943 			/* OK, queue it up for later */
4944 			tab->subcmds[pass] = lappend(tab->subcmds[pass], cmd2);
4945 		}
4946 		else
4947 		{
4948 			/*
4949 			 * We should see at most one subcommand for the current pass,
4950 			 * which is the transformed version of the original subcommand.
4951 			 */
4952 			if (newcmd == NULL && cmd->subtype == cmd2->subtype)
4953 			{
4954 				/* Found the transformed version of our subcommand */
4955 				newcmd = cmd2;
4956 			}
4957 			else
4958 				elog(ERROR, "ALTER TABLE scheduling failure: bogus item for pass %d",
4959 					 pass);
4960 		}
4961 	}
4962 
4963 	/* Queue up any after-statements to happen at the end */
4964 	tab->afterStmts = list_concat(tab->afterStmts, afterStmts);
4965 
4966 	return newcmd;
4967 }
4968 
4969 /*
4970  * ATRewriteTables: ALTER TABLE phase 3
4971  */
4972 static void
ATRewriteTables(AlterTableStmt * parsetree,List ** wqueue,LOCKMODE lockmode,AlterTableUtilityContext * context)4973 ATRewriteTables(AlterTableStmt *parsetree, List **wqueue, LOCKMODE lockmode,
4974 				AlterTableUtilityContext *context)
4975 {
4976 	ListCell   *ltab;
4977 
4978 	/* Go through each table that needs to be checked or rewritten */
4979 	foreach(ltab, *wqueue)
4980 	{
4981 		AlteredTableInfo *tab = (AlteredTableInfo *) lfirst(ltab);
4982 
4983 		/* Relations without storage may be ignored here */
4984 		if (!RELKIND_HAS_STORAGE(tab->relkind))
4985 			continue;
4986 
4987 		/*
4988 		 * If we change column data types or add/remove OIDs, the operation
4989 		 * has to be propagated to tables that use this table's rowtype as a
4990 		 * column type.  tab->newvals will also be non-NULL in the case where
4991 		 * we're adding a column with a default.  We choose to forbid that
4992 		 * case as well, since composite types might eventually support
4993 		 * defaults.
4994 		 *
4995 		 * (Eventually we'll probably need to check for composite type
4996 		 * dependencies even when we're just scanning the table without a
4997 		 * rewrite, but at the moment a composite type does not enforce any
4998 		 * constraints, so it's not necessary/appropriate to enforce them just
4999 		 * during ALTER.)
5000 		 */
5001 		if (tab->newvals != NIL || tab->rewrite > 0)
5002 		{
5003 			Relation	rel;
5004 
5005 			rel = table_open(tab->relid, NoLock);
5006 			find_composite_type_dependencies(rel->rd_rel->reltype, rel, NULL);
5007 			table_close(rel, NoLock);
5008 		}
5009 
5010 		/*
5011 		 * We only need to rewrite the table if at least one column needs to
5012 		 * be recomputed, we are adding/removing the OID column, or we are
5013 		 * changing its persistence.
5014 		 *
5015 		 * There are two reasons for requiring a rewrite when changing
5016 		 * persistence: on one hand, we need to ensure that the buffers
5017 		 * belonging to each of the two relations are marked with or without
5018 		 * BM_PERMANENT properly.  On the other hand, since rewriting creates
5019 		 * and assigns a new relfilenode, we automatically create or drop an
5020 		 * init fork for the relation as appropriate.
5021 		 */
5022 		if (tab->rewrite > 0)
5023 		{
5024 			/* Build a temporary relation and copy data */
5025 			Relation	OldHeap;
5026 			Oid			OIDNewHeap;
5027 			Oid			NewTableSpace;
5028 			char		persistence;
5029 
5030 			OldHeap = table_open(tab->relid, NoLock);
5031 
5032 			/*
5033 			 * We don't support rewriting of system catalogs; there are too
5034 			 * many corner cases and too little benefit.  In particular this
5035 			 * is certainly not going to work for mapped catalogs.
5036 			 */
5037 			if (IsSystemRelation(OldHeap))
5038 				ereport(ERROR,
5039 						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
5040 						 errmsg("cannot rewrite system relation \"%s\"",
5041 								RelationGetRelationName(OldHeap))));
5042 
5043 			if (RelationIsUsedAsCatalogTable(OldHeap))
5044 				ereport(ERROR,
5045 						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
5046 						 errmsg("cannot rewrite table \"%s\" used as a catalog table",
5047 								RelationGetRelationName(OldHeap))));
5048 
5049 			/*
5050 			 * Don't allow rewrite on temp tables of other backends ... their
5051 			 * local buffer manager is not going to cope.
5052 			 */
5053 			if (RELATION_IS_OTHER_TEMP(OldHeap))
5054 				ereport(ERROR,
5055 						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
5056 						 errmsg("cannot rewrite temporary tables of other sessions")));
5057 
5058 			/*
5059 			 * Select destination tablespace (same as original unless user
5060 			 * requested a change)
5061 			 */
5062 			if (tab->newTableSpace)
5063 				NewTableSpace = tab->newTableSpace;
5064 			else
5065 				NewTableSpace = OldHeap->rd_rel->reltablespace;
5066 
5067 			/*
5068 			 * Select persistence of transient table (same as original unless
5069 			 * user requested a change)
5070 			 */
5071 			persistence = tab->chgPersistence ?
5072 				tab->newrelpersistence : OldHeap->rd_rel->relpersistence;
5073 
5074 			table_close(OldHeap, NoLock);
5075 
5076 			/*
5077 			 * Fire off an Event Trigger now, before actually rewriting the
5078 			 * table.
5079 			 *
5080 			 * We don't support Event Trigger for nested commands anywhere,
5081 			 * here included, and parsetree is given NULL when coming from
5082 			 * AlterTableInternal.
5083 			 *
5084 			 * And fire it only once.
5085 			 */
5086 			if (parsetree)
5087 				EventTriggerTableRewrite((Node *) parsetree,
5088 										 tab->relid,
5089 										 tab->rewrite);
5090 
5091 			/*
5092 			 * Create transient table that will receive the modified data.
5093 			 *
5094 			 * Ensure it is marked correctly as logged or unlogged.  We have
5095 			 * to do this here so that buffers for the new relfilenode will
5096 			 * have the right persistence set, and at the same time ensure
5097 			 * that the original filenode's buffers will get read in with the
5098 			 * correct setting (i.e. the original one).  Otherwise a rollback
5099 			 * after the rewrite would possibly result with buffers for the
5100 			 * original filenode having the wrong persistence setting.
5101 			 *
5102 			 * NB: This relies on swap_relation_files() also swapping the
5103 			 * persistence. That wouldn't work for pg_class, but that can't be
5104 			 * unlogged anyway.
5105 			 */
5106 			OIDNewHeap = make_new_heap(tab->relid, NewTableSpace, persistence,
5107 									   lockmode);
5108 
5109 			/*
5110 			 * Copy the heap data into the new table with the desired
5111 			 * modifications, and test the current data within the table
5112 			 * against new constraints generated by ALTER TABLE commands.
5113 			 */
5114 			ATRewriteTable(tab, OIDNewHeap, lockmode);
5115 
5116 			/*
5117 			 * Swap the physical files of the old and new heaps, then rebuild
5118 			 * indexes and discard the old heap.  We can use RecentXmin for
5119 			 * the table's new relfrozenxid because we rewrote all the tuples
5120 			 * in ATRewriteTable, so no older Xid remains in the table.  Also,
5121 			 * we never try to swap toast tables by content, since we have no
5122 			 * interest in letting this code work on system catalogs.
5123 			 */
5124 			finish_heap_swap(tab->relid, OIDNewHeap,
5125 							 false, false, true,
5126 							 !OidIsValid(tab->newTableSpace),
5127 							 RecentXmin,
5128 							 ReadNextMultiXactId(),
5129 							 persistence);
5130 		}
5131 		else
5132 		{
5133 			/*
5134 			 * If required, test the current data within the table against new
5135 			 * constraints generated by ALTER TABLE commands, but don't
5136 			 * rebuild data.
5137 			 */
5138 			if (tab->constraints != NIL || tab->verify_new_notnull ||
5139 				tab->partition_constraint != NULL)
5140 				ATRewriteTable(tab, InvalidOid, lockmode);
5141 
5142 			/*
5143 			 * If we had SET TABLESPACE but no reason to reconstruct tuples,
5144 			 * just do a block-by-block copy.
5145 			 */
5146 			if (tab->newTableSpace)
5147 				ATExecSetTableSpace(tab->relid, tab->newTableSpace, lockmode);
5148 		}
5149 	}
5150 
5151 	/*
5152 	 * Foreign key constraints are checked in a final pass, since (a) it's
5153 	 * generally best to examine each one separately, and (b) it's at least
5154 	 * theoretically possible that we have changed both relations of the
5155 	 * foreign key, and we'd better have finished both rewrites before we try
5156 	 * to read the tables.
5157 	 */
5158 	foreach(ltab, *wqueue)
5159 	{
5160 		AlteredTableInfo *tab = (AlteredTableInfo *) lfirst(ltab);
5161 		Relation	rel = NULL;
5162 		ListCell   *lcon;
5163 
5164 		/* Relations without storage may be ignored here too */
5165 		if (!RELKIND_HAS_STORAGE(tab->relkind))
5166 			continue;
5167 
5168 		foreach(lcon, tab->constraints)
5169 		{
5170 			NewConstraint *con = lfirst(lcon);
5171 
5172 			if (con->contype == CONSTR_FOREIGN)
5173 			{
5174 				Constraint *fkconstraint = (Constraint *) con->qual;
5175 				Relation	refrel;
5176 
5177 				if (rel == NULL)
5178 				{
5179 					/* Long since locked, no need for another */
5180 					rel = table_open(tab->relid, NoLock);
5181 				}
5182 
5183 				refrel = table_open(con->refrelid, RowShareLock);
5184 
5185 				validateForeignKeyConstraint(fkconstraint->conname, rel, refrel,
5186 											 con->refindid,
5187 											 con->conid);
5188 
5189 				/*
5190 				 * No need to mark the constraint row as validated, we did
5191 				 * that when we inserted the row earlier.
5192 				 */
5193 
5194 				table_close(refrel, NoLock);
5195 			}
5196 		}
5197 
5198 		if (rel)
5199 			table_close(rel, NoLock);
5200 	}
5201 
5202 	/* Finally, run any afterStmts that were queued up */
5203 	foreach(ltab, *wqueue)
5204 	{
5205 		AlteredTableInfo *tab = (AlteredTableInfo *) lfirst(ltab);
5206 		ListCell   *lc;
5207 
5208 		foreach(lc, tab->afterStmts)
5209 		{
5210 			Node	   *stmt = (Node *) lfirst(lc);
5211 
5212 			ProcessUtilityForAlterTable(stmt, context);
5213 			CommandCounterIncrement();
5214 		}
5215 	}
5216 }
5217 
5218 /*
5219  * ATRewriteTable: scan or rewrite one table
5220  *
5221  * OIDNewHeap is InvalidOid if we don't need to rewrite
5222  */
5223 static void
ATRewriteTable(AlteredTableInfo * tab,Oid OIDNewHeap,LOCKMODE lockmode)5224 ATRewriteTable(AlteredTableInfo *tab, Oid OIDNewHeap, LOCKMODE lockmode)
5225 {
5226 	Relation	oldrel;
5227 	Relation	newrel;
5228 	TupleDesc	oldTupDesc;
5229 	TupleDesc	newTupDesc;
5230 	bool		needscan = false;
5231 	List	   *notnull_attrs;
5232 	int			i;
5233 	ListCell   *l;
5234 	EState	   *estate;
5235 	CommandId	mycid;
5236 	BulkInsertState bistate;
5237 	int			ti_options;
5238 	ExprState  *partqualstate = NULL;
5239 
5240 	/*
5241 	 * Open the relation(s).  We have surely already locked the existing
5242 	 * table.
5243 	 */
5244 	oldrel = table_open(tab->relid, NoLock);
5245 	oldTupDesc = tab->oldDesc;
5246 	newTupDesc = RelationGetDescr(oldrel);	/* includes all mods */
5247 
5248 	if (OidIsValid(OIDNewHeap))
5249 		newrel = table_open(OIDNewHeap, lockmode);
5250 	else
5251 		newrel = NULL;
5252 
5253 	/*
5254 	 * Prepare a BulkInsertState and options for table_tuple_insert.  The FSM
5255 	 * is empty, so don't bother using it.
5256 	 */
5257 	if (newrel)
5258 	{
5259 		mycid = GetCurrentCommandId(true);
5260 		bistate = GetBulkInsertState();
5261 		ti_options = TABLE_INSERT_SKIP_FSM;
5262 	}
5263 	else
5264 	{
5265 		/* keep compiler quiet about using these uninitialized */
5266 		mycid = 0;
5267 		bistate = NULL;
5268 		ti_options = 0;
5269 	}
5270 
5271 	/*
5272 	 * Generate the constraint and default execution states
5273 	 */
5274 
5275 	estate = CreateExecutorState();
5276 
5277 	/* Build the needed expression execution states */
5278 	foreach(l, tab->constraints)
5279 	{
5280 		NewConstraint *con = lfirst(l);
5281 
5282 		switch (con->contype)
5283 		{
5284 			case CONSTR_CHECK:
5285 				needscan = true;
5286 				con->qualstate = ExecPrepareExpr((Expr *) con->qual, estate);
5287 				break;
5288 			case CONSTR_FOREIGN:
5289 				/* Nothing to do here */
5290 				break;
5291 			default:
5292 				elog(ERROR, "unrecognized constraint type: %d",
5293 					 (int) con->contype);
5294 		}
5295 	}
5296 
5297 	/* Build expression execution states for partition check quals */
5298 	if (tab->partition_constraint)
5299 	{
5300 		needscan = true;
5301 		partqualstate = ExecPrepareExpr(tab->partition_constraint, estate);
5302 	}
5303 
5304 	foreach(l, tab->newvals)
5305 	{
5306 		NewColumnValue *ex = lfirst(l);
5307 
5308 		/* expr already planned */
5309 		ex->exprstate = ExecInitExpr((Expr *) ex->expr, NULL);
5310 	}
5311 
5312 	notnull_attrs = NIL;
5313 	if (newrel || tab->verify_new_notnull)
5314 	{
5315 		/*
5316 		 * If we are rebuilding the tuples OR if we added any new but not
5317 		 * verified NOT NULL constraints, check all not-null constraints. This
5318 		 * is a bit of overkill but it minimizes risk of bugs, and
5319 		 * heap_attisnull is a pretty cheap test anyway.
5320 		 */
5321 		for (i = 0; i < newTupDesc->natts; i++)
5322 		{
5323 			Form_pg_attribute attr = TupleDescAttr(newTupDesc, i);
5324 
5325 			if (attr->attnotnull && !attr->attisdropped)
5326 				notnull_attrs = lappend_int(notnull_attrs, i);
5327 		}
5328 		if (notnull_attrs)
5329 			needscan = true;
5330 	}
5331 
5332 	if (newrel || needscan)
5333 	{
5334 		ExprContext *econtext;
5335 		TupleTableSlot *oldslot;
5336 		TupleTableSlot *newslot;
5337 		TableScanDesc scan;
5338 		MemoryContext oldCxt;
5339 		List	   *dropped_attrs = NIL;
5340 		ListCell   *lc;
5341 		Snapshot	snapshot;
5342 
5343 		if (newrel)
5344 			ereport(DEBUG1,
5345 					(errmsg("rewriting table \"%s\"",
5346 							RelationGetRelationName(oldrel))));
5347 		else
5348 			ereport(DEBUG1,
5349 					(errmsg("verifying table \"%s\"",
5350 							RelationGetRelationName(oldrel))));
5351 
5352 		if (newrel)
5353 		{
5354 			/*
5355 			 * All predicate locks on the tuples or pages are about to be made
5356 			 * invalid, because we move tuples around.  Promote them to
5357 			 * relation locks.
5358 			 */
5359 			TransferPredicateLocksToHeapRelation(oldrel);
5360 		}
5361 
5362 		econtext = GetPerTupleExprContext(estate);
5363 
5364 		/*
5365 		 * Create necessary tuple slots. When rewriting, two slots are needed,
5366 		 * otherwise one suffices. In the case where one slot suffices, we
5367 		 * need to use the new tuple descriptor, otherwise some constraints
5368 		 * can't be evaluated.  Note that even when the tuple layout is the
5369 		 * same and no rewrite is required, the tupDescs might not be
5370 		 * (consider ADD COLUMN without a default).
5371 		 */
5372 		if (tab->rewrite)
5373 		{
5374 			Assert(newrel != NULL);
5375 			oldslot = MakeSingleTupleTableSlot(oldTupDesc,
5376 											   table_slot_callbacks(oldrel));
5377 			newslot = MakeSingleTupleTableSlot(newTupDesc,
5378 											   table_slot_callbacks(newrel));
5379 
5380 			/*
5381 			 * Set all columns in the new slot to NULL initially, to ensure
5382 			 * columns added as part of the rewrite are initialized to NULL.
5383 			 * That is necessary as tab->newvals will not contain an
5384 			 * expression for columns with a NULL default, e.g. when adding a
5385 			 * column without a default together with a column with a default
5386 			 * requiring an actual rewrite.
5387 			 */
5388 			ExecStoreAllNullTuple(newslot);
5389 		}
5390 		else
5391 		{
5392 			oldslot = MakeSingleTupleTableSlot(newTupDesc,
5393 											   table_slot_callbacks(oldrel));
5394 			newslot = NULL;
5395 		}
5396 
5397 		/*
5398 		 * Any attributes that are dropped according to the new tuple
5399 		 * descriptor can be set to NULL. We precompute the list of dropped
5400 		 * attributes to avoid needing to do so in the per-tuple loop.
5401 		 */
5402 		for (i = 0; i < newTupDesc->natts; i++)
5403 		{
5404 			if (TupleDescAttr(newTupDesc, i)->attisdropped)
5405 				dropped_attrs = lappend_int(dropped_attrs, i);
5406 		}
5407 
5408 		/*
5409 		 * Scan through the rows, generating a new row if needed and then
5410 		 * checking all the constraints.
5411 		 */
5412 		snapshot = RegisterSnapshot(GetLatestSnapshot());
5413 		scan = table_beginscan(oldrel, snapshot, 0, NULL);
5414 
5415 		/*
5416 		 * Switch to per-tuple memory context and reset it for each tuple
5417 		 * produced, so we don't leak memory.
5418 		 */
5419 		oldCxt = MemoryContextSwitchTo(GetPerTupleMemoryContext(estate));
5420 
5421 		while (table_scan_getnextslot(scan, ForwardScanDirection, oldslot))
5422 		{
5423 			TupleTableSlot *insertslot;
5424 
5425 			if (tab->rewrite > 0)
5426 			{
5427 				/* Extract data from old tuple */
5428 				slot_getallattrs(oldslot);
5429 				ExecClearTuple(newslot);
5430 
5431 				/* copy attributes */
5432 				memcpy(newslot->tts_values, oldslot->tts_values,
5433 					   sizeof(Datum) * oldslot->tts_nvalid);
5434 				memcpy(newslot->tts_isnull, oldslot->tts_isnull,
5435 					   sizeof(bool) * oldslot->tts_nvalid);
5436 
5437 				/* Set dropped attributes to null in new tuple */
5438 				foreach(lc, dropped_attrs)
5439 					newslot->tts_isnull[lfirst_int(lc)] = true;
5440 
5441 				/*
5442 				 * Constraints and GENERATED expressions might reference the
5443 				 * tableoid column, so fill tts_tableOid with the desired
5444 				 * value.  (We must do this each time, because it gets
5445 				 * overwritten with newrel's OID during storing.)
5446 				 */
5447 				newslot->tts_tableOid = RelationGetRelid(oldrel);
5448 
5449 				/*
5450 				 * Process supplied expressions to replace selected columns.
5451 				 *
5452 				 * First, evaluate expressions whose inputs come from the old
5453 				 * tuple.
5454 				 */
5455 				econtext->ecxt_scantuple = oldslot;
5456 
5457 				foreach(l, tab->newvals)
5458 				{
5459 					NewColumnValue *ex = lfirst(l);
5460 
5461 					if (ex->is_generated)
5462 						continue;
5463 
5464 					newslot->tts_values[ex->attnum - 1]
5465 						= ExecEvalExpr(ex->exprstate,
5466 									   econtext,
5467 									   &newslot->tts_isnull[ex->attnum - 1]);
5468 				}
5469 
5470 				ExecStoreVirtualTuple(newslot);
5471 
5472 				/*
5473 				 * Now, evaluate any expressions whose inputs come from the
5474 				 * new tuple.  We assume these columns won't reference each
5475 				 * other, so that there's no ordering dependency.
5476 				 */
5477 				econtext->ecxt_scantuple = newslot;
5478 
5479 				foreach(l, tab->newvals)
5480 				{
5481 					NewColumnValue *ex = lfirst(l);
5482 
5483 					if (!ex->is_generated)
5484 						continue;
5485 
5486 					newslot->tts_values[ex->attnum - 1]
5487 						= ExecEvalExpr(ex->exprstate,
5488 									   econtext,
5489 									   &newslot->tts_isnull[ex->attnum - 1]);
5490 				}
5491 
5492 				insertslot = newslot;
5493 			}
5494 			else
5495 			{
5496 				/*
5497 				 * If there's no rewrite, old and new table are guaranteed to
5498 				 * have the same AM, so we can just use the old slot to verify
5499 				 * new constraints etc.
5500 				 */
5501 				insertslot = oldslot;
5502 			}
5503 
5504 			/* Now check any constraints on the possibly-changed tuple */
5505 			econtext->ecxt_scantuple = insertslot;
5506 
5507 			foreach(l, notnull_attrs)
5508 			{
5509 				int			attn = lfirst_int(l);
5510 
5511 				if (slot_attisnull(insertslot, attn + 1))
5512 				{
5513 					Form_pg_attribute attr = TupleDescAttr(newTupDesc, attn);
5514 
5515 					ereport(ERROR,
5516 							(errcode(ERRCODE_NOT_NULL_VIOLATION),
5517 							 errmsg("column \"%s\" of relation \"%s\" contains null values",
5518 									NameStr(attr->attname),
5519 									RelationGetRelationName(oldrel)),
5520 							 errtablecol(oldrel, attn + 1)));
5521 				}
5522 			}
5523 
5524 			foreach(l, tab->constraints)
5525 			{
5526 				NewConstraint *con = lfirst(l);
5527 
5528 				switch (con->contype)
5529 				{
5530 					case CONSTR_CHECK:
5531 						if (!ExecCheck(con->qualstate, econtext))
5532 							ereport(ERROR,
5533 									(errcode(ERRCODE_CHECK_VIOLATION),
5534 									 errmsg("check constraint \"%s\" of relation \"%s\" is violated by some row",
5535 											con->name,
5536 											RelationGetRelationName(oldrel)),
5537 									 errtableconstraint(oldrel, con->name)));
5538 						break;
5539 					case CONSTR_FOREIGN:
5540 						/* Nothing to do here */
5541 						break;
5542 					default:
5543 						elog(ERROR, "unrecognized constraint type: %d",
5544 							 (int) con->contype);
5545 				}
5546 			}
5547 
5548 			if (partqualstate && !ExecCheck(partqualstate, econtext))
5549 			{
5550 				if (tab->validate_default)
5551 					ereport(ERROR,
5552 							(errcode(ERRCODE_CHECK_VIOLATION),
5553 							 errmsg("updated partition constraint for default partition \"%s\" would be violated by some row",
5554 									RelationGetRelationName(oldrel)),
5555 							 errtable(oldrel)));
5556 				else
5557 					ereport(ERROR,
5558 							(errcode(ERRCODE_CHECK_VIOLATION),
5559 							 errmsg("partition constraint of relation \"%s\" is violated by some row",
5560 									RelationGetRelationName(oldrel)),
5561 							 errtable(oldrel)));
5562 			}
5563 
5564 			/* Write the tuple out to the new relation */
5565 			if (newrel)
5566 				table_tuple_insert(newrel, insertslot, mycid,
5567 								   ti_options, bistate);
5568 
5569 			ResetExprContext(econtext);
5570 
5571 			CHECK_FOR_INTERRUPTS();
5572 		}
5573 
5574 		MemoryContextSwitchTo(oldCxt);
5575 		table_endscan(scan);
5576 		UnregisterSnapshot(snapshot);
5577 
5578 		ExecDropSingleTupleTableSlot(oldslot);
5579 		if (newslot)
5580 			ExecDropSingleTupleTableSlot(newslot);
5581 	}
5582 
5583 	FreeExecutorState(estate);
5584 
5585 	table_close(oldrel, NoLock);
5586 	if (newrel)
5587 	{
5588 		FreeBulkInsertState(bistate);
5589 
5590 		table_finish_bulk_insert(newrel, ti_options);
5591 
5592 		table_close(newrel, NoLock);
5593 	}
5594 }
5595 
5596 /*
5597  * ATGetQueueEntry: find or create an entry in the ALTER TABLE work queue
5598  */
5599 static AlteredTableInfo *
ATGetQueueEntry(List ** wqueue,Relation rel)5600 ATGetQueueEntry(List **wqueue, Relation rel)
5601 {
5602 	Oid			relid = RelationGetRelid(rel);
5603 	AlteredTableInfo *tab;
5604 	ListCell   *ltab;
5605 
5606 	foreach(ltab, *wqueue)
5607 	{
5608 		tab = (AlteredTableInfo *) lfirst(ltab);
5609 		if (tab->relid == relid)
5610 			return tab;
5611 	}
5612 
5613 	/*
5614 	 * Not there, so add it.  Note that we make a copy of the relation's
5615 	 * existing descriptor before anything interesting can happen to it.
5616 	 */
5617 	tab = (AlteredTableInfo *) palloc0(sizeof(AlteredTableInfo));
5618 	tab->relid = relid;
5619 	tab->relkind = rel->rd_rel->relkind;
5620 	tab->oldDesc = CreateTupleDescCopyConstr(RelationGetDescr(rel));
5621 	tab->newrelpersistence = RELPERSISTENCE_PERMANENT;
5622 	tab->chgPersistence = false;
5623 
5624 	*wqueue = lappend(*wqueue, tab);
5625 
5626 	return tab;
5627 }
5628 
5629 /*
5630  * ATSimplePermissions
5631  *
5632  * - Ensure that it is a relation (or possibly a view)
5633  * - Ensure this user is the owner
5634  * - Ensure that it is not a system table
5635  */
5636 static void
ATSimplePermissions(Relation rel,int allowed_targets)5637 ATSimplePermissions(Relation rel, int allowed_targets)
5638 {
5639 	int			actual_target;
5640 
5641 	switch (rel->rd_rel->relkind)
5642 	{
5643 		case RELKIND_RELATION:
5644 		case RELKIND_PARTITIONED_TABLE:
5645 			actual_target = ATT_TABLE;
5646 			break;
5647 		case RELKIND_VIEW:
5648 			actual_target = ATT_VIEW;
5649 			break;
5650 		case RELKIND_MATVIEW:
5651 			actual_target = ATT_MATVIEW;
5652 			break;
5653 		case RELKIND_INDEX:
5654 			actual_target = ATT_INDEX;
5655 			break;
5656 		case RELKIND_PARTITIONED_INDEX:
5657 			actual_target = ATT_PARTITIONED_INDEX;
5658 			break;
5659 		case RELKIND_COMPOSITE_TYPE:
5660 			actual_target = ATT_COMPOSITE_TYPE;
5661 			break;
5662 		case RELKIND_FOREIGN_TABLE:
5663 			actual_target = ATT_FOREIGN_TABLE;
5664 			break;
5665 		default:
5666 			actual_target = 0;
5667 			break;
5668 	}
5669 
5670 	/* Wrong target type? */
5671 	if ((actual_target & allowed_targets) == 0)
5672 		ATWrongRelkindError(rel, allowed_targets);
5673 
5674 	/* Permissions checks */
5675 	if (!pg_class_ownercheck(RelationGetRelid(rel), GetUserId()))
5676 		aclcheck_error(ACLCHECK_NOT_OWNER, get_relkind_objtype(rel->rd_rel->relkind),
5677 					   RelationGetRelationName(rel));
5678 
5679 	if (!allowSystemTableMods && IsSystemRelation(rel))
5680 		ereport(ERROR,
5681 				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
5682 				 errmsg("permission denied: \"%s\" is a system catalog",
5683 						RelationGetRelationName(rel))));
5684 }
5685 
5686 /*
5687  * ATWrongRelkindError
5688  *
5689  * Throw an error when a relation has been determined to be of the wrong
5690  * type.
5691  */
5692 static void
ATWrongRelkindError(Relation rel,int allowed_targets)5693 ATWrongRelkindError(Relation rel, int allowed_targets)
5694 {
5695 	char	   *msg;
5696 
5697 	switch (allowed_targets)
5698 	{
5699 		case ATT_TABLE:
5700 			msg = _("\"%s\" is not a table");
5701 			break;
5702 		case ATT_TABLE | ATT_VIEW:
5703 			msg = _("\"%s\" is not a table or view");
5704 			break;
5705 		case ATT_TABLE | ATT_VIEW | ATT_FOREIGN_TABLE:
5706 			msg = _("\"%s\" is not a table, view, or foreign table");
5707 			break;
5708 		case ATT_TABLE | ATT_VIEW | ATT_MATVIEW | ATT_INDEX:
5709 			msg = _("\"%s\" is not a table, view, materialized view, or index");
5710 			break;
5711 		case ATT_TABLE | ATT_MATVIEW:
5712 			msg = _("\"%s\" is not a table or materialized view");
5713 			break;
5714 		case ATT_TABLE | ATT_MATVIEW | ATT_INDEX:
5715 			msg = _("\"%s\" is not a table, materialized view, or index");
5716 			break;
5717 		case ATT_TABLE | ATT_MATVIEW | ATT_INDEX | ATT_PARTITIONED_INDEX:
5718 			msg = _("\"%s\" is not a table, materialized view, index, or partitioned index");
5719 			break;
5720 		case ATT_TABLE | ATT_MATVIEW | ATT_INDEX | ATT_PARTITIONED_INDEX | ATT_FOREIGN_TABLE:
5721 			msg = _("\"%s\" is not a table, materialized view, index, partitioned index, or foreign table");
5722 			break;
5723 		case ATT_TABLE | ATT_MATVIEW | ATT_FOREIGN_TABLE:
5724 			msg = _("\"%s\" is not a table, materialized view, or foreign table");
5725 			break;
5726 		case ATT_TABLE | ATT_FOREIGN_TABLE:
5727 			msg = _("\"%s\" is not a table or foreign table");
5728 			break;
5729 		case ATT_TABLE | ATT_COMPOSITE_TYPE | ATT_FOREIGN_TABLE:
5730 			msg = _("\"%s\" is not a table, composite type, or foreign table");
5731 			break;
5732 		case ATT_TABLE | ATT_MATVIEW | ATT_INDEX | ATT_FOREIGN_TABLE:
5733 			msg = _("\"%s\" is not a table, materialized view, index, or foreign table");
5734 			break;
5735 		case ATT_TABLE | ATT_PARTITIONED_INDEX:
5736 			msg = _("\"%s\" is not a table or partitioned index");
5737 			break;
5738 		case ATT_VIEW:
5739 			msg = _("\"%s\" is not a view");
5740 			break;
5741 		case ATT_FOREIGN_TABLE:
5742 			msg = _("\"%s\" is not a foreign table");
5743 			break;
5744 		default:
5745 			/* shouldn't get here, add all necessary cases above */
5746 			msg = _("\"%s\" is of the wrong type");
5747 			break;
5748 	}
5749 
5750 	ereport(ERROR,
5751 			(errcode(ERRCODE_WRONG_OBJECT_TYPE),
5752 			 errmsg(msg, RelationGetRelationName(rel))));
5753 }
5754 
5755 /*
5756  * ATSimpleRecursion
5757  *
5758  * Simple table recursion sufficient for most ALTER TABLE operations.
5759  * All direct and indirect children are processed in an unspecified order.
5760  * Note that if a child inherits from the original table via multiple
5761  * inheritance paths, it will be visited just once.
5762  */
5763 static void
ATSimpleRecursion(List ** wqueue,Relation rel,AlterTableCmd * cmd,bool recurse,LOCKMODE lockmode,AlterTableUtilityContext * context)5764 ATSimpleRecursion(List **wqueue, Relation rel,
5765 				  AlterTableCmd *cmd, bool recurse, LOCKMODE lockmode,
5766 				  AlterTableUtilityContext *context)
5767 {
5768 	/*
5769 	 * Propagate to children, if desired and if there are (or might be) any
5770 	 * children.
5771 	 */
5772 	if (recurse && rel->rd_rel->relhassubclass)
5773 	{
5774 		Oid			relid = RelationGetRelid(rel);
5775 		ListCell   *child;
5776 		List	   *children;
5777 
5778 		children = find_all_inheritors(relid, lockmode, NULL);
5779 
5780 		/*
5781 		 * find_all_inheritors does the recursive search of the inheritance
5782 		 * hierarchy, so all we have to do is process all of the relids in the
5783 		 * list that it returns.
5784 		 */
5785 		foreach(child, children)
5786 		{
5787 			Oid			childrelid = lfirst_oid(child);
5788 			Relation	childrel;
5789 
5790 			if (childrelid == relid)
5791 				continue;
5792 			/* find_all_inheritors already got lock */
5793 			childrel = relation_open(childrelid, NoLock);
5794 			CheckTableNotInUse(childrel, "ALTER TABLE");
5795 			ATPrepCmd(wqueue, childrel, cmd, false, true, lockmode, context);
5796 			relation_close(childrel, NoLock);
5797 		}
5798 	}
5799 }
5800 
5801 /*
5802  * Obtain list of partitions of the given table, locking them all at the given
5803  * lockmode and ensuring that they all pass CheckTableNotInUse.
5804  *
5805  * This function is a no-op if the given relation is not a partitioned table;
5806  * in particular, nothing is done if it's a legacy inheritance parent.
5807  */
5808 static void
ATCheckPartitionsNotInUse(Relation rel,LOCKMODE lockmode)5809 ATCheckPartitionsNotInUse(Relation rel, LOCKMODE lockmode)
5810 {
5811 	if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
5812 	{
5813 		List	   *inh;
5814 		ListCell   *cell;
5815 
5816 		inh = find_all_inheritors(RelationGetRelid(rel), lockmode, NULL);
5817 		/* first element is the parent rel; must ignore it */
5818 		for_each_from(cell, inh, 1)
5819 		{
5820 			Relation	childrel;
5821 
5822 			/* find_all_inheritors already got lock */
5823 			childrel = table_open(lfirst_oid(cell), NoLock);
5824 			CheckTableNotInUse(childrel, "ALTER TABLE");
5825 			table_close(childrel, NoLock);
5826 		}
5827 		list_free(inh);
5828 	}
5829 }
5830 
5831 /*
5832  * ATTypedTableRecursion
5833  *
5834  * Propagate ALTER TYPE operations to the typed tables of that type.
5835  * Also check the RESTRICT/CASCADE behavior.  Given CASCADE, also permit
5836  * recursion to inheritance children of the typed tables.
5837  */
5838 static void
ATTypedTableRecursion(List ** wqueue,Relation rel,AlterTableCmd * cmd,LOCKMODE lockmode,AlterTableUtilityContext * context)5839 ATTypedTableRecursion(List **wqueue, Relation rel, AlterTableCmd *cmd,
5840 					  LOCKMODE lockmode, AlterTableUtilityContext *context)
5841 {
5842 	ListCell   *child;
5843 	List	   *children;
5844 
5845 	Assert(rel->rd_rel->relkind == RELKIND_COMPOSITE_TYPE);
5846 
5847 	children = find_typed_table_dependencies(rel->rd_rel->reltype,
5848 											 RelationGetRelationName(rel),
5849 											 cmd->behavior);
5850 
5851 	foreach(child, children)
5852 	{
5853 		Oid			childrelid = lfirst_oid(child);
5854 		Relation	childrel;
5855 
5856 		childrel = relation_open(childrelid, lockmode);
5857 		CheckTableNotInUse(childrel, "ALTER TABLE");
5858 		ATPrepCmd(wqueue, childrel, cmd, true, true, lockmode, context);
5859 		relation_close(childrel, NoLock);
5860 	}
5861 }
5862 
5863 
5864 /*
5865  * find_composite_type_dependencies
5866  *
5867  * Check to see if the type "typeOid" is being used as a column in some table
5868  * (possibly nested several levels deep in composite types, arrays, etc!).
5869  * Eventually, we'd like to propagate the check or rewrite operation
5870  * into such tables, but for now, just error out if we find any.
5871  *
5872  * Caller should provide either the associated relation of a rowtype,
5873  * or a type name (not both) for use in the error message, if any.
5874  *
5875  * Note that "typeOid" is not necessarily a composite type; it could also be
5876  * another container type such as an array or range, or a domain over one of
5877  * these things.  The name of this function is therefore somewhat historical,
5878  * but it's not worth changing.
5879  *
5880  * We assume that functions and views depending on the type are not reasons
5881  * to reject the ALTER.  (How safe is this really?)
5882  */
5883 void
find_composite_type_dependencies(Oid typeOid,Relation origRelation,const char * origTypeName)5884 find_composite_type_dependencies(Oid typeOid, Relation origRelation,
5885 								 const char *origTypeName)
5886 {
5887 	Relation	depRel;
5888 	ScanKeyData key[2];
5889 	SysScanDesc depScan;
5890 	HeapTuple	depTup;
5891 
5892 	/* since this function recurses, it could be driven to stack overflow */
5893 	check_stack_depth();
5894 
5895 	/*
5896 	 * We scan pg_depend to find those things that depend on the given type.
5897 	 * (We assume we can ignore refobjsubid for a type.)
5898 	 */
5899 	depRel = table_open(DependRelationId, AccessShareLock);
5900 
5901 	ScanKeyInit(&key[0],
5902 				Anum_pg_depend_refclassid,
5903 				BTEqualStrategyNumber, F_OIDEQ,
5904 				ObjectIdGetDatum(TypeRelationId));
5905 	ScanKeyInit(&key[1],
5906 				Anum_pg_depend_refobjid,
5907 				BTEqualStrategyNumber, F_OIDEQ,
5908 				ObjectIdGetDatum(typeOid));
5909 
5910 	depScan = systable_beginscan(depRel, DependReferenceIndexId, true,
5911 								 NULL, 2, key);
5912 
5913 	while (HeapTupleIsValid(depTup = systable_getnext(depScan)))
5914 	{
5915 		Form_pg_depend pg_depend = (Form_pg_depend) GETSTRUCT(depTup);
5916 		Relation	rel;
5917 		Form_pg_attribute att;
5918 
5919 		/* Check for directly dependent types */
5920 		if (pg_depend->classid == TypeRelationId)
5921 		{
5922 			/*
5923 			 * This must be an array, domain, or range containing the given
5924 			 * type, so recursively check for uses of this type.  Note that
5925 			 * any error message will mention the original type not the
5926 			 * container; this is intentional.
5927 			 */
5928 			find_composite_type_dependencies(pg_depend->objid,
5929 											 origRelation, origTypeName);
5930 			continue;
5931 		}
5932 
5933 		/* Else, ignore dependees that aren't user columns of relations */
5934 		/* (we assume system columns are never of interesting types) */
5935 		if (pg_depend->classid != RelationRelationId ||
5936 			pg_depend->objsubid <= 0)
5937 			continue;
5938 
5939 		rel = relation_open(pg_depend->objid, AccessShareLock);
5940 		att = TupleDescAttr(rel->rd_att, pg_depend->objsubid - 1);
5941 
5942 		if (rel->rd_rel->relkind == RELKIND_RELATION ||
5943 			rel->rd_rel->relkind == RELKIND_MATVIEW ||
5944 			rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
5945 		{
5946 			if (origTypeName)
5947 				ereport(ERROR,
5948 						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
5949 						 errmsg("cannot alter type \"%s\" because column \"%s.%s\" uses it",
5950 								origTypeName,
5951 								RelationGetRelationName(rel),
5952 								NameStr(att->attname))));
5953 			else if (origRelation->rd_rel->relkind == RELKIND_COMPOSITE_TYPE)
5954 				ereport(ERROR,
5955 						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
5956 						 errmsg("cannot alter type \"%s\" because column \"%s.%s\" uses it",
5957 								RelationGetRelationName(origRelation),
5958 								RelationGetRelationName(rel),
5959 								NameStr(att->attname))));
5960 			else if (origRelation->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
5961 				ereport(ERROR,
5962 						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
5963 						 errmsg("cannot alter foreign table \"%s\" because column \"%s.%s\" uses its row type",
5964 								RelationGetRelationName(origRelation),
5965 								RelationGetRelationName(rel),
5966 								NameStr(att->attname))));
5967 			else
5968 				ereport(ERROR,
5969 						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
5970 						 errmsg("cannot alter table \"%s\" because column \"%s.%s\" uses its row type",
5971 								RelationGetRelationName(origRelation),
5972 								RelationGetRelationName(rel),
5973 								NameStr(att->attname))));
5974 		}
5975 		else if (OidIsValid(rel->rd_rel->reltype))
5976 		{
5977 			/*
5978 			 * A view or composite type itself isn't a problem, but we must
5979 			 * recursively check for indirect dependencies via its rowtype.
5980 			 */
5981 			find_composite_type_dependencies(rel->rd_rel->reltype,
5982 											 origRelation, origTypeName);
5983 		}
5984 
5985 		relation_close(rel, AccessShareLock);
5986 	}
5987 
5988 	systable_endscan(depScan);
5989 
5990 	relation_close(depRel, AccessShareLock);
5991 }
5992 
5993 
5994 /*
5995  * find_typed_table_dependencies
5996  *
5997  * Check to see if a composite type is being used as the type of a
5998  * typed table.  Abort if any are found and behavior is RESTRICT.
5999  * Else return the list of tables.
6000  */
6001 static List *
find_typed_table_dependencies(Oid typeOid,const char * typeName,DropBehavior behavior)6002 find_typed_table_dependencies(Oid typeOid, const char *typeName, DropBehavior behavior)
6003 {
6004 	Relation	classRel;
6005 	ScanKeyData key[1];
6006 	TableScanDesc scan;
6007 	HeapTuple	tuple;
6008 	List	   *result = NIL;
6009 
6010 	classRel = table_open(RelationRelationId, AccessShareLock);
6011 
6012 	ScanKeyInit(&key[0],
6013 				Anum_pg_class_reloftype,
6014 				BTEqualStrategyNumber, F_OIDEQ,
6015 				ObjectIdGetDatum(typeOid));
6016 
6017 	scan = table_beginscan_catalog(classRel, 1, key);
6018 
6019 	while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
6020 	{
6021 		Form_pg_class classform = (Form_pg_class) GETSTRUCT(tuple);
6022 
6023 		if (behavior == DROP_RESTRICT)
6024 			ereport(ERROR,
6025 					(errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
6026 					 errmsg("cannot alter type \"%s\" because it is the type of a typed table",
6027 							typeName),
6028 					 errhint("Use ALTER ... CASCADE to alter the typed tables too.")));
6029 		else
6030 			result = lappend_oid(result, classform->oid);
6031 	}
6032 
6033 	table_endscan(scan);
6034 	table_close(classRel, AccessShareLock);
6035 
6036 	return result;
6037 }
6038 
6039 
6040 /*
6041  * check_of_type
6042  *
6043  * Check whether a type is suitable for CREATE TABLE OF/ALTER TABLE OF.  If it
6044  * isn't suitable, throw an error.  Currently, we require that the type
6045  * originated with CREATE TYPE AS.  We could support any row type, but doing so
6046  * would require handling a number of extra corner cases in the DDL commands.
6047  * (Also, allowing domain-over-composite would open up a can of worms about
6048  * whether and how the domain's constraints should apply to derived tables.)
6049  */
6050 void
check_of_type(HeapTuple typetuple)6051 check_of_type(HeapTuple typetuple)
6052 {
6053 	Form_pg_type typ = (Form_pg_type) GETSTRUCT(typetuple);
6054 	bool		typeOk = false;
6055 
6056 	if (typ->typtype == TYPTYPE_COMPOSITE)
6057 	{
6058 		Relation	typeRelation;
6059 
6060 		Assert(OidIsValid(typ->typrelid));
6061 		typeRelation = relation_open(typ->typrelid, AccessShareLock);
6062 		typeOk = (typeRelation->rd_rel->relkind == RELKIND_COMPOSITE_TYPE);
6063 
6064 		/*
6065 		 * Close the parent rel, but keep our AccessShareLock on it until xact
6066 		 * commit.  That will prevent someone else from deleting or ALTERing
6067 		 * the type before the typed table creation/conversion commits.
6068 		 */
6069 		relation_close(typeRelation, NoLock);
6070 	}
6071 	if (!typeOk)
6072 		ereport(ERROR,
6073 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
6074 				 errmsg("type %s is not a composite type",
6075 						format_type_be(typ->oid))));
6076 }
6077 
6078 
6079 /*
6080  * ALTER TABLE ADD COLUMN
6081  *
6082  * Adds an additional attribute to a relation making the assumption that
6083  * CHECK, NOT NULL, and FOREIGN KEY constraints will be removed from the
6084  * AT_AddColumn AlterTableCmd by parse_utilcmd.c and added as independent
6085  * AlterTableCmd's.
6086  *
6087  * ADD COLUMN cannot use the normal ALTER TABLE recursion mechanism, because we
6088  * have to decide at runtime whether to recurse or not depending on whether we
6089  * actually add a column or merely merge with an existing column.  (We can't
6090  * check this in a static pre-pass because it won't handle multiple inheritance
6091  * situations correctly.)
6092  */
6093 static void
ATPrepAddColumn(List ** wqueue,Relation rel,bool recurse,bool recursing,bool is_view,AlterTableCmd * cmd,LOCKMODE lockmode,AlterTableUtilityContext * context)6094 ATPrepAddColumn(List **wqueue, Relation rel, bool recurse, bool recursing,
6095 				bool is_view, AlterTableCmd *cmd, LOCKMODE lockmode,
6096 				AlterTableUtilityContext *context)
6097 {
6098 	if (rel->rd_rel->reloftype && !recursing)
6099 		ereport(ERROR,
6100 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
6101 				 errmsg("cannot add column to typed table")));
6102 
6103 	if (rel->rd_rel->relkind == RELKIND_COMPOSITE_TYPE)
6104 		ATTypedTableRecursion(wqueue, rel, cmd, lockmode, context);
6105 
6106 	if (recurse && !is_view)
6107 		cmd->subtype = AT_AddColumnRecurse;
6108 }
6109 
6110 /*
6111  * Add a column to a table.  The return value is the address of the
6112  * new column in the parent relation.
6113  *
6114  * cmd is pass-by-ref so that we can replace it with the parse-transformed
6115  * copy (but that happens only after we check for IF NOT EXISTS).
6116  */
6117 static ObjectAddress
ATExecAddColumn(List ** wqueue,AlteredTableInfo * tab,Relation rel,AlterTableCmd ** cmd,bool recurse,bool recursing,LOCKMODE lockmode,int cur_pass,AlterTableUtilityContext * context)6118 ATExecAddColumn(List **wqueue, AlteredTableInfo *tab, Relation rel,
6119 				AlterTableCmd **cmd,
6120 				bool recurse, bool recursing,
6121 				LOCKMODE lockmode, int cur_pass,
6122 				AlterTableUtilityContext *context)
6123 {
6124 	Oid			myrelid = RelationGetRelid(rel);
6125 	ColumnDef  *colDef = castNode(ColumnDef, (*cmd)->def);
6126 	bool		if_not_exists = (*cmd)->missing_ok;
6127 	Relation	pgclass,
6128 				attrdesc;
6129 	HeapTuple	reltup;
6130 	FormData_pg_attribute attribute;
6131 	int			newattnum;
6132 	char		relkind;
6133 	HeapTuple	typeTuple;
6134 	Oid			typeOid;
6135 	int32		typmod;
6136 	Oid			collOid;
6137 	Form_pg_type tform;
6138 	Expr	   *defval;
6139 	List	   *children;
6140 	ListCell   *child;
6141 	AlterTableCmd *childcmd;
6142 	AclResult	aclresult;
6143 	ObjectAddress address;
6144 
6145 	/* At top level, permission check was done in ATPrepCmd, else do it */
6146 	if (recursing)
6147 		ATSimplePermissions(rel, ATT_TABLE | ATT_FOREIGN_TABLE);
6148 
6149 	if (rel->rd_rel->relispartition && !recursing)
6150 		ereport(ERROR,
6151 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
6152 				 errmsg("cannot add column to a partition")));
6153 
6154 	attrdesc = table_open(AttributeRelationId, RowExclusiveLock);
6155 
6156 	/*
6157 	 * Are we adding the column to a recursion child?  If so, check whether to
6158 	 * merge with an existing definition for the column.  If we do merge, we
6159 	 * must not recurse.  Children will already have the column, and recursing
6160 	 * into them would mess up attinhcount.
6161 	 */
6162 	if (colDef->inhcount > 0)
6163 	{
6164 		HeapTuple	tuple;
6165 
6166 		/* Does child already have a column by this name? */
6167 		tuple = SearchSysCacheCopyAttName(myrelid, colDef->colname);
6168 		if (HeapTupleIsValid(tuple))
6169 		{
6170 			Form_pg_attribute childatt = (Form_pg_attribute) GETSTRUCT(tuple);
6171 			Oid			ctypeId;
6172 			int32		ctypmod;
6173 			Oid			ccollid;
6174 
6175 			/* Child column must match on type, typmod, and collation */
6176 			typenameTypeIdAndMod(NULL, colDef->typeName, &ctypeId, &ctypmod);
6177 			if (ctypeId != childatt->atttypid ||
6178 				ctypmod != childatt->atttypmod)
6179 				ereport(ERROR,
6180 						(errcode(ERRCODE_DATATYPE_MISMATCH),
6181 						 errmsg("child table \"%s\" has different type for column \"%s\"",
6182 								RelationGetRelationName(rel), colDef->colname)));
6183 			ccollid = GetColumnDefCollation(NULL, colDef, ctypeId);
6184 			if (ccollid != childatt->attcollation)
6185 				ereport(ERROR,
6186 						(errcode(ERRCODE_COLLATION_MISMATCH),
6187 						 errmsg("child table \"%s\" has different collation for column \"%s\"",
6188 								RelationGetRelationName(rel), colDef->colname),
6189 						 errdetail("\"%s\" versus \"%s\"",
6190 								   get_collation_name(ccollid),
6191 								   get_collation_name(childatt->attcollation))));
6192 
6193 			/* Bump the existing child att's inhcount */
6194 			childatt->attinhcount++;
6195 			CatalogTupleUpdate(attrdesc, &tuple->t_self, tuple);
6196 
6197 			heap_freetuple(tuple);
6198 
6199 			/* Inform the user about the merge */
6200 			ereport(NOTICE,
6201 					(errmsg("merging definition of column \"%s\" for child \"%s\"",
6202 							colDef->colname, RelationGetRelationName(rel))));
6203 
6204 			table_close(attrdesc, RowExclusiveLock);
6205 			return InvalidObjectAddress;
6206 		}
6207 	}
6208 
6209 	/* skip if the name already exists and if_not_exists is true */
6210 	if (!check_for_column_name_collision(rel, colDef->colname, if_not_exists))
6211 	{
6212 		table_close(attrdesc, RowExclusiveLock);
6213 		return InvalidObjectAddress;
6214 	}
6215 
6216 	/*
6217 	 * Okay, we need to add the column, so go ahead and do parse
6218 	 * transformation.  This can result in queueing up, or even immediately
6219 	 * executing, subsidiary operations (such as creation of unique indexes);
6220 	 * so we mustn't do it until we have made the if_not_exists check.
6221 	 *
6222 	 * When recursing, the command was already transformed and we needn't do
6223 	 * so again.  Also, if context isn't given we can't transform.  (That
6224 	 * currently happens only for AT_AddColumnToView; we expect that view.c
6225 	 * passed us a ColumnDef that doesn't need work.)
6226 	 */
6227 	if (context != NULL && !recursing)
6228 	{
6229 		*cmd = ATParseTransformCmd(wqueue, tab, rel, *cmd, recurse, lockmode,
6230 								   cur_pass, context);
6231 		Assert(*cmd != NULL);
6232 		colDef = castNode(ColumnDef, (*cmd)->def);
6233 	}
6234 
6235 	/*
6236 	 * Cannot add identity column if table has children, because identity does
6237 	 * not inherit.  (Adding column and identity separately will work.)
6238 	 */
6239 	if (colDef->identity &&
6240 		recurse &&
6241 		find_inheritance_children(myrelid, NoLock) != NIL)
6242 		ereport(ERROR,
6243 				(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
6244 				 errmsg("cannot recursively add identity column to table that has child tables")));
6245 
6246 	pgclass = table_open(RelationRelationId, RowExclusiveLock);
6247 
6248 	reltup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(myrelid));
6249 	if (!HeapTupleIsValid(reltup))
6250 		elog(ERROR, "cache lookup failed for relation %u", myrelid);
6251 	relkind = ((Form_pg_class) GETSTRUCT(reltup))->relkind;
6252 
6253 	/* Determine the new attribute's number */
6254 	newattnum = ((Form_pg_class) GETSTRUCT(reltup))->relnatts + 1;
6255 	if (newattnum > MaxHeapAttributeNumber)
6256 		ereport(ERROR,
6257 				(errcode(ERRCODE_TOO_MANY_COLUMNS),
6258 				 errmsg("tables can have at most %d columns",
6259 						MaxHeapAttributeNumber)));
6260 
6261 	typeTuple = typenameType(NULL, colDef->typeName, &typmod);
6262 	tform = (Form_pg_type) GETSTRUCT(typeTuple);
6263 	typeOid = tform->oid;
6264 
6265 	aclresult = pg_type_aclcheck(typeOid, GetUserId(), ACL_USAGE);
6266 	if (aclresult != ACLCHECK_OK)
6267 		aclcheck_error_type(aclresult, typeOid);
6268 
6269 	collOid = GetColumnDefCollation(NULL, colDef, typeOid);
6270 
6271 	/* make sure datatype is legal for a column */
6272 	CheckAttributeType(colDef->colname, typeOid, collOid,
6273 					   list_make1_oid(rel->rd_rel->reltype),
6274 					   0);
6275 
6276 	/* construct new attribute's pg_attribute entry */
6277 	attribute.attrelid = myrelid;
6278 	namestrcpy(&(attribute.attname), colDef->colname);
6279 	attribute.atttypid = typeOid;
6280 	attribute.attstattarget = (newattnum > 0) ? -1 : 0;
6281 	attribute.attlen = tform->typlen;
6282 	attribute.atttypmod = typmod;
6283 	attribute.attnum = newattnum;
6284 	attribute.attbyval = tform->typbyval;
6285 	attribute.attndims = list_length(colDef->typeName->arrayBounds);
6286 	attribute.attstorage = tform->typstorage;
6287 	attribute.attalign = tform->typalign;
6288 	attribute.attnotnull = colDef->is_not_null;
6289 	attribute.atthasdef = false;
6290 	attribute.atthasmissing = false;
6291 	attribute.attidentity = colDef->identity;
6292 	attribute.attgenerated = colDef->generated;
6293 	attribute.attisdropped = false;
6294 	attribute.attislocal = colDef->is_local;
6295 	attribute.attinhcount = colDef->inhcount;
6296 	attribute.attcollation = collOid;
6297 	/* attribute.attacl is handled by InsertPgAttributeTuple */
6298 
6299 	ReleaseSysCache(typeTuple);
6300 
6301 	InsertPgAttributeTuple(attrdesc, &attribute, (Datum) 0, NULL);
6302 
6303 	table_close(attrdesc, RowExclusiveLock);
6304 
6305 	/*
6306 	 * Update pg_class tuple as appropriate
6307 	 */
6308 	((Form_pg_class) GETSTRUCT(reltup))->relnatts = newattnum;
6309 
6310 	CatalogTupleUpdate(pgclass, &reltup->t_self, reltup);
6311 
6312 	heap_freetuple(reltup);
6313 
6314 	/* Post creation hook for new attribute */
6315 	InvokeObjectPostCreateHook(RelationRelationId, myrelid, newattnum);
6316 
6317 	table_close(pgclass, RowExclusiveLock);
6318 
6319 	/* Make the attribute's catalog entry visible */
6320 	CommandCounterIncrement();
6321 
6322 	/*
6323 	 * Store the DEFAULT, if any, in the catalogs
6324 	 */
6325 	if (colDef->raw_default)
6326 	{
6327 		RawColumnDefault *rawEnt;
6328 
6329 		rawEnt = (RawColumnDefault *) palloc(sizeof(RawColumnDefault));
6330 		rawEnt->attnum = attribute.attnum;
6331 		rawEnt->raw_default = copyObject(colDef->raw_default);
6332 
6333 		/*
6334 		 * Attempt to skip a complete table rewrite by storing the specified
6335 		 * DEFAULT value outside of the heap.  This may be disabled inside
6336 		 * AddRelationNewConstraints if the optimization cannot be applied.
6337 		 */
6338 		rawEnt->missingMode = (!colDef->generated);
6339 
6340 		rawEnt->generated = colDef->generated;
6341 
6342 		/*
6343 		 * This function is intended for CREATE TABLE, so it processes a
6344 		 * _list_ of defaults, but we just do one.
6345 		 */
6346 		AddRelationNewConstraints(rel, list_make1(rawEnt), NIL,
6347 								  false, true, false, NULL);
6348 
6349 		/* Make the additional catalog changes visible */
6350 		CommandCounterIncrement();
6351 
6352 		/*
6353 		 * Did the request for a missing value work? If not we'll have to do a
6354 		 * rewrite
6355 		 */
6356 		if (!rawEnt->missingMode)
6357 			tab->rewrite |= AT_REWRITE_DEFAULT_VAL;
6358 	}
6359 
6360 	/*
6361 	 * Tell Phase 3 to fill in the default expression, if there is one.
6362 	 *
6363 	 * If there is no default, Phase 3 doesn't have to do anything, because
6364 	 * that effectively means that the default is NULL.  The heap tuple access
6365 	 * routines always check for attnum > # of attributes in tuple, and return
6366 	 * NULL if so, so without any modification of the tuple data we will get
6367 	 * the effect of NULL values in the new column.
6368 	 *
6369 	 * An exception occurs when the new column is of a domain type: the domain
6370 	 * might have a NOT NULL constraint, or a check constraint that indirectly
6371 	 * rejects nulls.  If there are any domain constraints then we construct
6372 	 * an explicit NULL default value that will be passed through
6373 	 * CoerceToDomain processing.  (This is a tad inefficient, since it causes
6374 	 * rewriting the table which we really don't have to do, but the present
6375 	 * design of domain processing doesn't offer any simple way of checking
6376 	 * the constraints more directly.)
6377 	 *
6378 	 * Note: we use build_column_default, and not just the cooked default
6379 	 * returned by AddRelationNewConstraints, so that the right thing happens
6380 	 * when a datatype's default applies.
6381 	 *
6382 	 * Note: it might seem that this should happen at the end of Phase 2, so
6383 	 * that the effects of subsequent subcommands can be taken into account.
6384 	 * It's intentional that we do it now, though.  The new column should be
6385 	 * filled according to what is said in the ADD COLUMN subcommand, so that
6386 	 * the effects are the same as if this subcommand had been run by itself
6387 	 * and the later subcommands had been issued in new ALTER TABLE commands.
6388 	 *
6389 	 * We can skip this entirely for relations without storage, since Phase 3
6390 	 * is certainly not going to touch them.  System attributes don't have
6391 	 * interesting defaults, either.
6392 	 */
6393 	if (RELKIND_HAS_STORAGE(relkind) && attribute.attnum > 0)
6394 	{
6395 		/*
6396 		 * For an identity column, we can't use build_column_default(),
6397 		 * because the sequence ownership isn't set yet.  So do it manually.
6398 		 */
6399 		if (colDef->identity)
6400 		{
6401 			NextValueExpr *nve = makeNode(NextValueExpr);
6402 
6403 			nve->seqid = RangeVarGetRelid(colDef->identitySequence, NoLock, false);
6404 			nve->typeId = typeOid;
6405 
6406 			defval = (Expr *) nve;
6407 
6408 			/* must do a rewrite for identity columns */
6409 			tab->rewrite |= AT_REWRITE_DEFAULT_VAL;
6410 		}
6411 		else
6412 			defval = (Expr *) build_column_default(rel, attribute.attnum);
6413 
6414 		if (!defval && DomainHasConstraints(typeOid))
6415 		{
6416 			Oid			baseTypeId;
6417 			int32		baseTypeMod;
6418 			Oid			baseTypeColl;
6419 
6420 			baseTypeMod = typmod;
6421 			baseTypeId = getBaseTypeAndTypmod(typeOid, &baseTypeMod);
6422 			baseTypeColl = get_typcollation(baseTypeId);
6423 			defval = (Expr *) makeNullConst(baseTypeId, baseTypeMod, baseTypeColl);
6424 			defval = (Expr *) coerce_to_target_type(NULL,
6425 													(Node *) defval,
6426 													baseTypeId,
6427 													typeOid,
6428 													typmod,
6429 													COERCION_ASSIGNMENT,
6430 													COERCE_IMPLICIT_CAST,
6431 													-1);
6432 			if (defval == NULL) /* should not happen */
6433 				elog(ERROR, "failed to coerce base type to domain");
6434 		}
6435 
6436 		if (defval)
6437 		{
6438 			NewColumnValue *newval;
6439 
6440 			newval = (NewColumnValue *) palloc0(sizeof(NewColumnValue));
6441 			newval->attnum = attribute.attnum;
6442 			newval->expr = expression_planner(defval);
6443 			newval->is_generated = (colDef->generated != '\0');
6444 
6445 			tab->newvals = lappend(tab->newvals, newval);
6446 		}
6447 
6448 		if (DomainHasConstraints(typeOid))
6449 			tab->rewrite |= AT_REWRITE_DEFAULT_VAL;
6450 
6451 		if (!TupleDescAttr(rel->rd_att, attribute.attnum - 1)->atthasmissing)
6452 		{
6453 			/*
6454 			 * If the new column is NOT NULL, and there is no missing value,
6455 			 * tell Phase 3 it needs to check for NULLs.
6456 			 */
6457 			tab->verify_new_notnull |= colDef->is_not_null;
6458 		}
6459 	}
6460 
6461 	/*
6462 	 * Add needed dependency entries for the new column.
6463 	 */
6464 	add_column_datatype_dependency(myrelid, newattnum, attribute.atttypid);
6465 	add_column_collation_dependency(myrelid, newattnum, attribute.attcollation);
6466 
6467 	/*
6468 	 * Propagate to children as appropriate.  Unlike most other ALTER
6469 	 * routines, we have to do this one level of recursion at a time; we can't
6470 	 * use find_all_inheritors to do it in one pass.
6471 	 */
6472 	children = find_inheritance_children(RelationGetRelid(rel), lockmode);
6473 
6474 	/*
6475 	 * If we are told not to recurse, there had better not be any child
6476 	 * tables; else the addition would put them out of step.
6477 	 */
6478 	if (children && !recurse)
6479 		ereport(ERROR,
6480 				(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
6481 				 errmsg("column must be added to child tables too")));
6482 
6483 	/* Children should see column as singly inherited */
6484 	if (!recursing)
6485 	{
6486 		childcmd = copyObject(*cmd);
6487 		colDef = castNode(ColumnDef, childcmd->def);
6488 		colDef->inhcount = 1;
6489 		colDef->is_local = false;
6490 	}
6491 	else
6492 		childcmd = *cmd;		/* no need to copy again */
6493 
6494 	foreach(child, children)
6495 	{
6496 		Oid			childrelid = lfirst_oid(child);
6497 		Relation	childrel;
6498 		AlteredTableInfo *childtab;
6499 
6500 		/* find_inheritance_children already got lock */
6501 		childrel = table_open(childrelid, NoLock);
6502 		CheckTableNotInUse(childrel, "ALTER TABLE");
6503 
6504 		/* Find or create work queue entry for this table */
6505 		childtab = ATGetQueueEntry(wqueue, childrel);
6506 
6507 		/* Recurse to child; return value is ignored */
6508 		ATExecAddColumn(wqueue, childtab, childrel,
6509 						&childcmd, recurse, true,
6510 						lockmode, cur_pass, context);
6511 
6512 		table_close(childrel, NoLock);
6513 	}
6514 
6515 	ObjectAddressSubSet(address, RelationRelationId, myrelid, newattnum);
6516 	return address;
6517 }
6518 
6519 /*
6520  * If a new or renamed column will collide with the name of an existing
6521  * column and if_not_exists is false then error out, else do nothing.
6522  */
6523 static bool
check_for_column_name_collision(Relation rel,const char * colname,bool if_not_exists)6524 check_for_column_name_collision(Relation rel, const char *colname,
6525 								bool if_not_exists)
6526 {
6527 	HeapTuple	attTuple;
6528 	int			attnum;
6529 
6530 	/*
6531 	 * this test is deliberately not attisdropped-aware, since if one tries to
6532 	 * add a column matching a dropped column name, it's gonna fail anyway.
6533 	 */
6534 	attTuple = SearchSysCache2(ATTNAME,
6535 							   ObjectIdGetDatum(RelationGetRelid(rel)),
6536 							   PointerGetDatum(colname));
6537 	if (!HeapTupleIsValid(attTuple))
6538 		return true;
6539 
6540 	attnum = ((Form_pg_attribute) GETSTRUCT(attTuple))->attnum;
6541 	ReleaseSysCache(attTuple);
6542 
6543 	/*
6544 	 * We throw a different error message for conflicts with system column
6545 	 * names, since they are normally not shown and the user might otherwise
6546 	 * be confused about the reason for the conflict.
6547 	 */
6548 	if (attnum <= 0)
6549 		ereport(ERROR,
6550 				(errcode(ERRCODE_DUPLICATE_COLUMN),
6551 				 errmsg("column name \"%s\" conflicts with a system column name",
6552 						colname)));
6553 	else
6554 	{
6555 		if (if_not_exists)
6556 		{
6557 			ereport(NOTICE,
6558 					(errcode(ERRCODE_DUPLICATE_COLUMN),
6559 					 errmsg("column \"%s\" of relation \"%s\" already exists, skipping",
6560 							colname, RelationGetRelationName(rel))));
6561 			return false;
6562 		}
6563 
6564 		ereport(ERROR,
6565 				(errcode(ERRCODE_DUPLICATE_COLUMN),
6566 				 errmsg("column \"%s\" of relation \"%s\" already exists",
6567 						colname, RelationGetRelationName(rel))));
6568 	}
6569 
6570 	return true;
6571 }
6572 
6573 /*
6574  * Install a column's dependency on its datatype.
6575  */
6576 static void
add_column_datatype_dependency(Oid relid,int32 attnum,Oid typid)6577 add_column_datatype_dependency(Oid relid, int32 attnum, Oid typid)
6578 {
6579 	ObjectAddress myself,
6580 				referenced;
6581 
6582 	myself.classId = RelationRelationId;
6583 	myself.objectId = relid;
6584 	myself.objectSubId = attnum;
6585 	referenced.classId = TypeRelationId;
6586 	referenced.objectId = typid;
6587 	referenced.objectSubId = 0;
6588 	recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
6589 }
6590 
6591 /*
6592  * Install a column's dependency on its collation.
6593  */
6594 static void
add_column_collation_dependency(Oid relid,int32 attnum,Oid collid)6595 add_column_collation_dependency(Oid relid, int32 attnum, Oid collid)
6596 {
6597 	ObjectAddress myself,
6598 				referenced;
6599 
6600 	/* We know the default collation is pinned, so don't bother recording it */
6601 	if (OidIsValid(collid) && collid != DEFAULT_COLLATION_OID)
6602 	{
6603 		myself.classId = RelationRelationId;
6604 		myself.objectId = relid;
6605 		myself.objectSubId = attnum;
6606 		referenced.classId = CollationRelationId;
6607 		referenced.objectId = collid;
6608 		referenced.objectSubId = 0;
6609 		recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
6610 	}
6611 }
6612 
6613 /*
6614  * ALTER TABLE ALTER COLUMN DROP NOT NULL
6615  */
6616 
6617 static void
ATPrepDropNotNull(Relation rel,bool recurse,bool recursing)6618 ATPrepDropNotNull(Relation rel, bool recurse, bool recursing)
6619 {
6620 	/*
6621 	 * If the parent is a partitioned table, like check constraints, we do not
6622 	 * support removing the NOT NULL while partitions exist.
6623 	 */
6624 	if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
6625 	{
6626 		PartitionDesc partdesc = RelationGetPartitionDesc(rel);
6627 
6628 		Assert(partdesc != NULL);
6629 		if (partdesc->nparts > 0 && !recurse && !recursing)
6630 			ereport(ERROR,
6631 					(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
6632 					 errmsg("cannot remove constraint from only the partitioned table when partitions exist"),
6633 					 errhint("Do not specify the ONLY keyword.")));
6634 	}
6635 }
6636 
6637 /*
6638  * Return the address of the modified column.  If the column was already
6639  * nullable, InvalidObjectAddress is returned.
6640  */
6641 static ObjectAddress
ATExecDropNotNull(Relation rel,const char * colName,LOCKMODE lockmode)6642 ATExecDropNotNull(Relation rel, const char *colName, LOCKMODE lockmode)
6643 {
6644 	HeapTuple	tuple;
6645 	Form_pg_attribute attTup;
6646 	AttrNumber	attnum;
6647 	Relation	attr_rel;
6648 	List	   *indexoidlist;
6649 	ListCell   *indexoidscan;
6650 	ObjectAddress address;
6651 
6652 	/*
6653 	 * lookup the attribute
6654 	 */
6655 	attr_rel = table_open(AttributeRelationId, RowExclusiveLock);
6656 
6657 	tuple = SearchSysCacheCopyAttName(RelationGetRelid(rel), colName);
6658 	if (!HeapTupleIsValid(tuple))
6659 		ereport(ERROR,
6660 				(errcode(ERRCODE_UNDEFINED_COLUMN),
6661 				 errmsg("column \"%s\" of relation \"%s\" does not exist",
6662 						colName, RelationGetRelationName(rel))));
6663 	attTup = (Form_pg_attribute) GETSTRUCT(tuple);
6664 	attnum = attTup->attnum;
6665 
6666 	/* Prevent them from altering a system attribute */
6667 	if (attnum <= 0)
6668 		ereport(ERROR,
6669 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
6670 				 errmsg("cannot alter system column \"%s\"",
6671 						colName)));
6672 
6673 	if (attTup->attidentity)
6674 		ereport(ERROR,
6675 				(errcode(ERRCODE_SYNTAX_ERROR),
6676 				 errmsg("column \"%s\" of relation \"%s\" is an identity column",
6677 						colName, RelationGetRelationName(rel))));
6678 
6679 	/*
6680 	 * Check that the attribute is not in a primary key
6681 	 *
6682 	 * Note: we'll throw error even if the pkey index is not valid.
6683 	 */
6684 
6685 	/* Loop over all indexes on the relation */
6686 	indexoidlist = RelationGetIndexList(rel);
6687 
6688 	foreach(indexoidscan, indexoidlist)
6689 	{
6690 		Oid			indexoid = lfirst_oid(indexoidscan);
6691 		HeapTuple	indexTuple;
6692 		Form_pg_index indexStruct;
6693 		int			i;
6694 
6695 		indexTuple = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(indexoid));
6696 		if (!HeapTupleIsValid(indexTuple))
6697 			elog(ERROR, "cache lookup failed for index %u", indexoid);
6698 		indexStruct = (Form_pg_index) GETSTRUCT(indexTuple);
6699 
6700 		/* If the index is not a primary key, skip the check */
6701 		if (indexStruct->indisprimary)
6702 		{
6703 			/*
6704 			 * Loop over each attribute in the primary key and see if it
6705 			 * matches the to-be-altered attribute
6706 			 */
6707 			for (i = 0; i < indexStruct->indnkeyatts; i++)
6708 			{
6709 				if (indexStruct->indkey.values[i] == attnum)
6710 					ereport(ERROR,
6711 							(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
6712 							 errmsg("column \"%s\" is in a primary key",
6713 									colName)));
6714 			}
6715 		}
6716 
6717 		ReleaseSysCache(indexTuple);
6718 	}
6719 
6720 	list_free(indexoidlist);
6721 
6722 	/* If rel is partition, shouldn't drop NOT NULL if parent has the same */
6723 	if (rel->rd_rel->relispartition)
6724 	{
6725 		Oid			parentId = get_partition_parent(RelationGetRelid(rel));
6726 		Relation	parent = table_open(parentId, AccessShareLock);
6727 		TupleDesc	tupDesc = RelationGetDescr(parent);
6728 		AttrNumber	parent_attnum;
6729 
6730 		parent_attnum = get_attnum(parentId, colName);
6731 		if (TupleDescAttr(tupDesc, parent_attnum - 1)->attnotnull)
6732 			ereport(ERROR,
6733 					(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
6734 					 errmsg("column \"%s\" is marked NOT NULL in parent table",
6735 							colName)));
6736 		table_close(parent, AccessShareLock);
6737 	}
6738 
6739 	/*
6740 	 * Okay, actually perform the catalog change ... if needed
6741 	 */
6742 	if (attTup->attnotnull)
6743 	{
6744 		attTup->attnotnull = false;
6745 
6746 		CatalogTupleUpdate(attr_rel, &tuple->t_self, tuple);
6747 
6748 		ObjectAddressSubSet(address, RelationRelationId,
6749 							RelationGetRelid(rel), attnum);
6750 	}
6751 	else
6752 		address = InvalidObjectAddress;
6753 
6754 	InvokeObjectPostAlterHook(RelationRelationId,
6755 							  RelationGetRelid(rel), attnum);
6756 
6757 	table_close(attr_rel, RowExclusiveLock);
6758 
6759 	return address;
6760 }
6761 
6762 /*
6763  * ALTER TABLE ALTER COLUMN SET NOT NULL
6764  */
6765 
6766 static void
ATPrepSetNotNull(List ** wqueue,Relation rel,AlterTableCmd * cmd,bool recurse,bool recursing,LOCKMODE lockmode,AlterTableUtilityContext * context)6767 ATPrepSetNotNull(List **wqueue, Relation rel,
6768 				 AlterTableCmd *cmd, bool recurse, bool recursing,
6769 				 LOCKMODE lockmode, AlterTableUtilityContext *context)
6770 {
6771 	/*
6772 	 * If we're already recursing, there's nothing to do; the topmost
6773 	 * invocation of ATSimpleRecursion already visited all children.
6774 	 */
6775 	if (recursing)
6776 		return;
6777 
6778 	/*
6779 	 * If the target column is already marked NOT NULL, we can skip recursing
6780 	 * to children, because their columns should already be marked NOT NULL as
6781 	 * well.  But there's no point in checking here unless the relation has
6782 	 * some children; else we can just wait till execution to check.  (If it
6783 	 * does have children, however, this can save taking per-child locks
6784 	 * unnecessarily.  This greatly improves concurrency in some parallel
6785 	 * restore scenarios.)
6786 	 *
6787 	 * Unfortunately, we can only apply this optimization to partitioned
6788 	 * tables, because traditional inheritance doesn't enforce that child
6789 	 * columns be NOT NULL when their parent is.  (That's a bug that should
6790 	 * get fixed someday.)
6791 	 */
6792 	if (rel->rd_rel->relhassubclass &&
6793 		rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
6794 	{
6795 		HeapTuple	tuple;
6796 		bool		attnotnull;
6797 
6798 		tuple = SearchSysCacheAttName(RelationGetRelid(rel), cmd->name);
6799 
6800 		/* Might as well throw the error now, if name is bad */
6801 		if (!HeapTupleIsValid(tuple))
6802 			ereport(ERROR,
6803 					(errcode(ERRCODE_UNDEFINED_COLUMN),
6804 					 errmsg("column \"%s\" of relation \"%s\" does not exist",
6805 							cmd->name, RelationGetRelationName(rel))));
6806 
6807 		attnotnull = ((Form_pg_attribute) GETSTRUCT(tuple))->attnotnull;
6808 		ReleaseSysCache(tuple);
6809 		if (attnotnull)
6810 			return;
6811 	}
6812 
6813 	/*
6814 	 * If we have ALTER TABLE ONLY ... SET NOT NULL on a partitioned table,
6815 	 * apply ALTER TABLE ... CHECK NOT NULL to every child.  Otherwise, use
6816 	 * normal recursion logic.
6817 	 */
6818 	if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE &&
6819 		!recurse)
6820 	{
6821 		AlterTableCmd *newcmd = makeNode(AlterTableCmd);
6822 
6823 		newcmd->subtype = AT_CheckNotNull;
6824 		newcmd->name = pstrdup(cmd->name);
6825 		ATSimpleRecursion(wqueue, rel, newcmd, true, lockmode, context);
6826 	}
6827 	else
6828 		ATSimpleRecursion(wqueue, rel, cmd, recurse, lockmode, context);
6829 }
6830 
6831 /*
6832  * Return the address of the modified column.  If the column was already NOT
6833  * NULL, InvalidObjectAddress is returned.
6834  */
6835 static ObjectAddress
ATExecSetNotNull(AlteredTableInfo * tab,Relation rel,const char * colName,LOCKMODE lockmode)6836 ATExecSetNotNull(AlteredTableInfo *tab, Relation rel,
6837 				 const char *colName, LOCKMODE lockmode)
6838 {
6839 	HeapTuple	tuple;
6840 	AttrNumber	attnum;
6841 	Relation	attr_rel;
6842 	ObjectAddress address;
6843 
6844 	/*
6845 	 * lookup the attribute
6846 	 */
6847 	attr_rel = table_open(AttributeRelationId, RowExclusiveLock);
6848 
6849 	tuple = SearchSysCacheCopyAttName(RelationGetRelid(rel), colName);
6850 
6851 	if (!HeapTupleIsValid(tuple))
6852 		ereport(ERROR,
6853 				(errcode(ERRCODE_UNDEFINED_COLUMN),
6854 				 errmsg("column \"%s\" of relation \"%s\" does not exist",
6855 						colName, RelationGetRelationName(rel))));
6856 
6857 	attnum = ((Form_pg_attribute) GETSTRUCT(tuple))->attnum;
6858 
6859 	/* Prevent them from altering a system attribute */
6860 	if (attnum <= 0)
6861 		ereport(ERROR,
6862 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
6863 				 errmsg("cannot alter system column \"%s\"",
6864 						colName)));
6865 
6866 	/*
6867 	 * Okay, actually perform the catalog change ... if needed
6868 	 */
6869 	if (!((Form_pg_attribute) GETSTRUCT(tuple))->attnotnull)
6870 	{
6871 		((Form_pg_attribute) GETSTRUCT(tuple))->attnotnull = true;
6872 
6873 		CatalogTupleUpdate(attr_rel, &tuple->t_self, tuple);
6874 
6875 		/*
6876 		 * Ordinarily phase 3 must ensure that no NULLs exist in columns that
6877 		 * are set NOT NULL; however, if we can find a constraint which proves
6878 		 * this then we can skip that.  We needn't bother looking if we've
6879 		 * already found that we must verify some other NOT NULL constraint.
6880 		 */
6881 		if (!tab->verify_new_notnull &&
6882 			!NotNullImpliedByRelConstraints(rel, (Form_pg_attribute) GETSTRUCT(tuple)))
6883 		{
6884 			/* Tell Phase 3 it needs to test the constraint */
6885 			tab->verify_new_notnull = true;
6886 		}
6887 
6888 		ObjectAddressSubSet(address, RelationRelationId,
6889 							RelationGetRelid(rel), attnum);
6890 	}
6891 	else
6892 		address = InvalidObjectAddress;
6893 
6894 	InvokeObjectPostAlterHook(RelationRelationId,
6895 							  RelationGetRelid(rel), attnum);
6896 
6897 	table_close(attr_rel, RowExclusiveLock);
6898 
6899 	return address;
6900 }
6901 
6902 /*
6903  * ALTER TABLE ALTER COLUMN CHECK NOT NULL
6904  *
6905  * This doesn't exist in the grammar, but we generate AT_CheckNotNull
6906  * commands against the partitions of a partitioned table if the user
6907  * writes ALTER TABLE ONLY ... SET NOT NULL on the partitioned table,
6908  * or tries to create a primary key on it (which internally creates
6909  * AT_SetNotNull on the partitioned table).   Such a command doesn't
6910  * allow us to actually modify any partition, but we want to let it
6911  * go through if the partitions are already properly marked.
6912  *
6913  * In future, this might need to adjust the child table's state, likely
6914  * by incrementing an inheritance count for the attnotnull constraint.
6915  * For now we need only check for the presence of the flag.
6916  */
6917 static void
ATExecCheckNotNull(AlteredTableInfo * tab,Relation rel,const char * colName,LOCKMODE lockmode)6918 ATExecCheckNotNull(AlteredTableInfo *tab, Relation rel,
6919 				   const char *colName, LOCKMODE lockmode)
6920 {
6921 	HeapTuple	tuple;
6922 
6923 	tuple = SearchSysCacheAttName(RelationGetRelid(rel), colName);
6924 
6925 	if (!HeapTupleIsValid(tuple))
6926 		ereport(ERROR,
6927 				(errcode(ERRCODE_UNDEFINED_COLUMN),
6928 				 errmsg("column \"%s\" of relation \"%s\" does not exist",
6929 						colName, RelationGetRelationName(rel))));
6930 
6931 	if (!((Form_pg_attribute) GETSTRUCT(tuple))->attnotnull)
6932 		ereport(ERROR,
6933 				(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
6934 				 errmsg("constraint must be added to child tables too"),
6935 				 errdetail("Column \"%s\" of relation \"%s\" is not already NOT NULL.",
6936 						   colName, RelationGetRelationName(rel)),
6937 				 errhint("Do not specify the ONLY keyword.")));
6938 
6939 	ReleaseSysCache(tuple);
6940 }
6941 
6942 /*
6943  * NotNullImpliedByRelConstraints
6944  *		Does rel's existing constraints imply NOT NULL for the given attribute?
6945  */
6946 static bool
NotNullImpliedByRelConstraints(Relation rel,Form_pg_attribute attr)6947 NotNullImpliedByRelConstraints(Relation rel, Form_pg_attribute attr)
6948 {
6949 	NullTest   *nnulltest = makeNode(NullTest);
6950 
6951 	nnulltest->arg = (Expr *) makeVar(1,
6952 									  attr->attnum,
6953 									  attr->atttypid,
6954 									  attr->atttypmod,
6955 									  attr->attcollation,
6956 									  0);
6957 	nnulltest->nulltesttype = IS_NOT_NULL;
6958 
6959 	/*
6960 	 * argisrow = false is correct even for a composite column, because
6961 	 * attnotnull does not represent a SQL-spec IS NOT NULL test in such a
6962 	 * case, just IS DISTINCT FROM NULL.
6963 	 */
6964 	nnulltest->argisrow = false;
6965 	nnulltest->location = -1;
6966 
6967 	if (ConstraintImpliedByRelConstraint(rel, list_make1(nnulltest), NIL))
6968 	{
6969 		ereport(DEBUG1,
6970 				(errmsg("existing constraints on column \"%s.%s\" are sufficient to prove that it does not contain nulls",
6971 						RelationGetRelationName(rel), NameStr(attr->attname))));
6972 		return true;
6973 	}
6974 
6975 	return false;
6976 }
6977 
6978 /*
6979  * ALTER TABLE ALTER COLUMN SET/DROP DEFAULT
6980  *
6981  * Return the address of the affected column.
6982  */
6983 static ObjectAddress
ATExecColumnDefault(Relation rel,const char * colName,Node * newDefault,LOCKMODE lockmode)6984 ATExecColumnDefault(Relation rel, const char *colName,
6985 					Node *newDefault, LOCKMODE lockmode)
6986 {
6987 	TupleDesc	tupdesc = RelationGetDescr(rel);
6988 	AttrNumber	attnum;
6989 	ObjectAddress address;
6990 
6991 	/*
6992 	 * get the number of the attribute
6993 	 */
6994 	attnum = get_attnum(RelationGetRelid(rel), colName);
6995 	if (attnum == InvalidAttrNumber)
6996 		ereport(ERROR,
6997 				(errcode(ERRCODE_UNDEFINED_COLUMN),
6998 				 errmsg("column \"%s\" of relation \"%s\" does not exist",
6999 						colName, RelationGetRelationName(rel))));
7000 
7001 	/* Prevent them from altering a system attribute */
7002 	if (attnum <= 0)
7003 		ereport(ERROR,
7004 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
7005 				 errmsg("cannot alter system column \"%s\"",
7006 						colName)));
7007 
7008 	if (TupleDescAttr(tupdesc, attnum - 1)->attidentity)
7009 		ereport(ERROR,
7010 				(errcode(ERRCODE_SYNTAX_ERROR),
7011 				 errmsg("column \"%s\" of relation \"%s\" is an identity column",
7012 						colName, RelationGetRelationName(rel)),
7013 				 newDefault ? 0 : errhint("Use ALTER TABLE ... ALTER COLUMN ... DROP IDENTITY instead.")));
7014 
7015 	if (TupleDescAttr(tupdesc, attnum - 1)->attgenerated)
7016 		ereport(ERROR,
7017 				(errcode(ERRCODE_SYNTAX_ERROR),
7018 				 errmsg("column \"%s\" of relation \"%s\" is a generated column",
7019 						colName, RelationGetRelationName(rel)),
7020 				 newDefault || TupleDescAttr(tupdesc, attnum - 1)->attgenerated != ATTRIBUTE_GENERATED_STORED ? 0 :
7021 				 errhint("Use ALTER TABLE ... ALTER COLUMN ... DROP EXPRESSION instead.")));
7022 
7023 	/*
7024 	 * Remove any old default for the column.  We use RESTRICT here for
7025 	 * safety, but at present we do not expect anything to depend on the
7026 	 * default.
7027 	 *
7028 	 * We treat removing the existing default as an internal operation when it
7029 	 * is preparatory to adding a new default, but as a user-initiated
7030 	 * operation when the user asked for a drop.
7031 	 */
7032 	RemoveAttrDefault(RelationGetRelid(rel), attnum, DROP_RESTRICT, false,
7033 					  newDefault == NULL ? false : true);
7034 
7035 	if (newDefault)
7036 	{
7037 		/* SET DEFAULT */
7038 		RawColumnDefault *rawEnt;
7039 
7040 		rawEnt = (RawColumnDefault *) palloc(sizeof(RawColumnDefault));
7041 		rawEnt->attnum = attnum;
7042 		rawEnt->raw_default = newDefault;
7043 		rawEnt->missingMode = false;
7044 		rawEnt->generated = '\0';
7045 
7046 		/*
7047 		 * This function is intended for CREATE TABLE, so it processes a
7048 		 * _list_ of defaults, but we just do one.
7049 		 */
7050 		AddRelationNewConstraints(rel, list_make1(rawEnt), NIL,
7051 								  false, true, false, NULL);
7052 	}
7053 
7054 	ObjectAddressSubSet(address, RelationRelationId,
7055 						RelationGetRelid(rel), attnum);
7056 	return address;
7057 }
7058 
7059 /*
7060  * Add a pre-cooked default expression.
7061  *
7062  * Return the address of the affected column.
7063  */
7064 static ObjectAddress
ATExecCookedColumnDefault(Relation rel,AttrNumber attnum,Node * newDefault)7065 ATExecCookedColumnDefault(Relation rel, AttrNumber attnum,
7066 						  Node *newDefault)
7067 {
7068 	ObjectAddress address;
7069 
7070 	/* We assume no checking is required */
7071 
7072 	/*
7073 	 * Remove any old default for the column.  We use RESTRICT here for
7074 	 * safety, but at present we do not expect anything to depend on the
7075 	 * default.  (In ordinary cases, there could not be a default in place
7076 	 * anyway, but it's possible when combining LIKE with inheritance.)
7077 	 */
7078 	RemoveAttrDefault(RelationGetRelid(rel), attnum, DROP_RESTRICT, false,
7079 					  true);
7080 
7081 	(void) StoreAttrDefault(rel, attnum, newDefault, true, false);
7082 
7083 	ObjectAddressSubSet(address, RelationRelationId,
7084 						RelationGetRelid(rel), attnum);
7085 	return address;
7086 }
7087 
7088 /*
7089  * ALTER TABLE ALTER COLUMN ADD IDENTITY
7090  *
7091  * Return the address of the affected column.
7092  */
7093 static ObjectAddress
ATExecAddIdentity(Relation rel,const char * colName,Node * def,LOCKMODE lockmode)7094 ATExecAddIdentity(Relation rel, const char *colName,
7095 				  Node *def, LOCKMODE lockmode)
7096 {
7097 	Relation	attrelation;
7098 	HeapTuple	tuple;
7099 	Form_pg_attribute attTup;
7100 	AttrNumber	attnum;
7101 	ObjectAddress address;
7102 	ColumnDef  *cdef = castNode(ColumnDef, def);
7103 
7104 	attrelation = table_open(AttributeRelationId, RowExclusiveLock);
7105 
7106 	tuple = SearchSysCacheCopyAttName(RelationGetRelid(rel), colName);
7107 	if (!HeapTupleIsValid(tuple))
7108 		ereport(ERROR,
7109 				(errcode(ERRCODE_UNDEFINED_COLUMN),
7110 				 errmsg("column \"%s\" of relation \"%s\" does not exist",
7111 						colName, RelationGetRelationName(rel))));
7112 	attTup = (Form_pg_attribute) GETSTRUCT(tuple);
7113 	attnum = attTup->attnum;
7114 
7115 	/* Can't alter a system attribute */
7116 	if (attnum <= 0)
7117 		ereport(ERROR,
7118 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
7119 				 errmsg("cannot alter system column \"%s\"",
7120 						colName)));
7121 
7122 	/*
7123 	 * Creating a column as identity implies NOT NULL, so adding the identity
7124 	 * to an existing column that is not NOT NULL would create a state that
7125 	 * cannot be reproduced without contortions.
7126 	 */
7127 	if (!attTup->attnotnull)
7128 		ereport(ERROR,
7129 				(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
7130 				 errmsg("column \"%s\" of relation \"%s\" must be declared NOT NULL before identity can be added",
7131 						colName, RelationGetRelationName(rel))));
7132 
7133 	if (attTup->attidentity)
7134 		ereport(ERROR,
7135 				(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
7136 				 errmsg("column \"%s\" of relation \"%s\" is already an identity column",
7137 						colName, RelationGetRelationName(rel))));
7138 
7139 	if (attTup->atthasdef)
7140 		ereport(ERROR,
7141 				(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
7142 				 errmsg("column \"%s\" of relation \"%s\" already has a default value",
7143 						colName, RelationGetRelationName(rel))));
7144 
7145 	attTup->attidentity = cdef->identity;
7146 	CatalogTupleUpdate(attrelation, &tuple->t_self, tuple);
7147 
7148 	InvokeObjectPostAlterHook(RelationRelationId,
7149 							  RelationGetRelid(rel),
7150 							  attTup->attnum);
7151 	ObjectAddressSubSet(address, RelationRelationId,
7152 						RelationGetRelid(rel), attnum);
7153 	heap_freetuple(tuple);
7154 
7155 	table_close(attrelation, RowExclusiveLock);
7156 
7157 	return address;
7158 }
7159 
7160 /*
7161  * ALTER TABLE ALTER COLUMN SET { GENERATED or sequence options }
7162  *
7163  * Return the address of the affected column.
7164  */
7165 static ObjectAddress
ATExecSetIdentity(Relation rel,const char * colName,Node * def,LOCKMODE lockmode)7166 ATExecSetIdentity(Relation rel, const char *colName, Node *def, LOCKMODE lockmode)
7167 {
7168 	ListCell   *option;
7169 	DefElem    *generatedEl = NULL;
7170 	HeapTuple	tuple;
7171 	Form_pg_attribute attTup;
7172 	AttrNumber	attnum;
7173 	Relation	attrelation;
7174 	ObjectAddress address;
7175 
7176 	foreach(option, castNode(List, def))
7177 	{
7178 		DefElem    *defel = lfirst_node(DefElem, option);
7179 
7180 		if (strcmp(defel->defname, "generated") == 0)
7181 		{
7182 			if (generatedEl)
7183 				ereport(ERROR,
7184 						(errcode(ERRCODE_SYNTAX_ERROR),
7185 						 errmsg("conflicting or redundant options")));
7186 			generatedEl = defel;
7187 		}
7188 		else
7189 			elog(ERROR, "option \"%s\" not recognized",
7190 				 defel->defname);
7191 	}
7192 
7193 	/*
7194 	 * Even if there is nothing to change here, we run all the checks.  There
7195 	 * will be a subsequent ALTER SEQUENCE that relies on everything being
7196 	 * there.
7197 	 */
7198 
7199 	attrelation = table_open(AttributeRelationId, RowExclusiveLock);
7200 	tuple = SearchSysCacheCopyAttName(RelationGetRelid(rel), colName);
7201 	if (!HeapTupleIsValid(tuple))
7202 		ereport(ERROR,
7203 				(errcode(ERRCODE_UNDEFINED_COLUMN),
7204 				 errmsg("column \"%s\" of relation \"%s\" does not exist",
7205 						colName, RelationGetRelationName(rel))));
7206 
7207 	attTup = (Form_pg_attribute) GETSTRUCT(tuple);
7208 	attnum = attTup->attnum;
7209 
7210 	if (attnum <= 0)
7211 		ereport(ERROR,
7212 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
7213 				 errmsg("cannot alter system column \"%s\"",
7214 						colName)));
7215 
7216 	if (!attTup->attidentity)
7217 		ereport(ERROR,
7218 				(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
7219 				 errmsg("column \"%s\" of relation \"%s\" is not an identity column",
7220 						colName, RelationGetRelationName(rel))));
7221 
7222 	if (generatedEl)
7223 	{
7224 		attTup->attidentity = defGetInt32(generatedEl);
7225 		CatalogTupleUpdate(attrelation, &tuple->t_self, tuple);
7226 
7227 		InvokeObjectPostAlterHook(RelationRelationId,
7228 								  RelationGetRelid(rel),
7229 								  attTup->attnum);
7230 		ObjectAddressSubSet(address, RelationRelationId,
7231 							RelationGetRelid(rel), attnum);
7232 	}
7233 	else
7234 		address = InvalidObjectAddress;
7235 
7236 	heap_freetuple(tuple);
7237 	table_close(attrelation, RowExclusiveLock);
7238 
7239 	return address;
7240 }
7241 
7242 /*
7243  * ALTER TABLE ALTER COLUMN DROP IDENTITY
7244  *
7245  * Return the address of the affected column.
7246  */
7247 static ObjectAddress
ATExecDropIdentity(Relation rel,const char * colName,bool missing_ok,LOCKMODE lockmode)7248 ATExecDropIdentity(Relation rel, const char *colName, bool missing_ok, LOCKMODE lockmode)
7249 {
7250 	HeapTuple	tuple;
7251 	Form_pg_attribute attTup;
7252 	AttrNumber	attnum;
7253 	Relation	attrelation;
7254 	ObjectAddress address;
7255 	Oid			seqid;
7256 	ObjectAddress seqaddress;
7257 
7258 	attrelation = table_open(AttributeRelationId, RowExclusiveLock);
7259 	tuple = SearchSysCacheCopyAttName(RelationGetRelid(rel), colName);
7260 	if (!HeapTupleIsValid(tuple))
7261 		ereport(ERROR,
7262 				(errcode(ERRCODE_UNDEFINED_COLUMN),
7263 				 errmsg("column \"%s\" of relation \"%s\" does not exist",
7264 						colName, RelationGetRelationName(rel))));
7265 
7266 	attTup = (Form_pg_attribute) GETSTRUCT(tuple);
7267 	attnum = attTup->attnum;
7268 
7269 	if (attnum <= 0)
7270 		ereport(ERROR,
7271 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
7272 				 errmsg("cannot alter system column \"%s\"",
7273 						colName)));
7274 
7275 	if (!attTup->attidentity)
7276 	{
7277 		if (!missing_ok)
7278 			ereport(ERROR,
7279 					(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
7280 					 errmsg("column \"%s\" of relation \"%s\" is not an identity column",
7281 							colName, RelationGetRelationName(rel))));
7282 		else
7283 		{
7284 			ereport(NOTICE,
7285 					(errmsg("column \"%s\" of relation \"%s\" is not an identity column, skipping",
7286 							colName, RelationGetRelationName(rel))));
7287 			heap_freetuple(tuple);
7288 			table_close(attrelation, RowExclusiveLock);
7289 			return InvalidObjectAddress;
7290 		}
7291 	}
7292 
7293 	attTup->attidentity = '\0';
7294 	CatalogTupleUpdate(attrelation, &tuple->t_self, tuple);
7295 
7296 	InvokeObjectPostAlterHook(RelationRelationId,
7297 							  RelationGetRelid(rel),
7298 							  attTup->attnum);
7299 	ObjectAddressSubSet(address, RelationRelationId,
7300 						RelationGetRelid(rel), attnum);
7301 	heap_freetuple(tuple);
7302 
7303 	table_close(attrelation, RowExclusiveLock);
7304 
7305 	/* drop the internal sequence */
7306 	seqid = getIdentitySequence(RelationGetRelid(rel), attnum, false);
7307 	deleteDependencyRecordsForClass(RelationRelationId, seqid,
7308 									RelationRelationId, DEPENDENCY_INTERNAL);
7309 	CommandCounterIncrement();
7310 	seqaddress.classId = RelationRelationId;
7311 	seqaddress.objectId = seqid;
7312 	seqaddress.objectSubId = 0;
7313 	performDeletion(&seqaddress, DROP_RESTRICT, PERFORM_DELETION_INTERNAL);
7314 
7315 	return address;
7316 }
7317 
7318 /*
7319  * ALTER TABLE ALTER COLUMN DROP EXPRESSION
7320  */
7321 static void
ATPrepDropExpression(Relation rel,AlterTableCmd * cmd,bool recurse,bool recursing,LOCKMODE lockmode)7322 ATPrepDropExpression(Relation rel, AlterTableCmd *cmd, bool recurse, bool recursing, LOCKMODE lockmode)
7323 {
7324 	/*
7325 	 * Reject ONLY if there are child tables.  We could implement this, but it
7326 	 * is a bit complicated.  GENERATED clauses must be attached to the column
7327 	 * definition and cannot be added later like DEFAULT, so if a child table
7328 	 * has a generation expression that the parent does not have, the child
7329 	 * column will necessarily be an attlocal column.  So to implement ONLY
7330 	 * here, we'd need extra code to update attislocal of the direct child
7331 	 * tables, somewhat similar to how DROP COLUMN does it, so that the
7332 	 * resulting state can be properly dumped and restored.
7333 	 */
7334 	if (!recurse &&
7335 		find_inheritance_children(RelationGetRelid(rel), lockmode))
7336 		ereport(ERROR,
7337 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
7338 				 errmsg("ALTER TABLE / DROP EXPRESSION must be applied to child tables too")));
7339 
7340 	/*
7341 	 * Cannot drop generation expression from inherited columns.
7342 	 */
7343 	if (!recursing)
7344 	{
7345 		HeapTuple	tuple;
7346 		Form_pg_attribute attTup;
7347 
7348 		tuple = SearchSysCacheCopyAttName(RelationGetRelid(rel), cmd->name);
7349 		if (!HeapTupleIsValid(tuple))
7350 			ereport(ERROR,
7351 					(errcode(ERRCODE_UNDEFINED_COLUMN),
7352 					 errmsg("column \"%s\" of relation \"%s\" does not exist",
7353 							cmd->name, RelationGetRelationName(rel))));
7354 
7355 		attTup = (Form_pg_attribute) GETSTRUCT(tuple);
7356 
7357 		if (attTup->attinhcount > 0)
7358 			ereport(ERROR,
7359 					(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
7360 					 errmsg("cannot drop generation expression from inherited column")));
7361 	}
7362 }
7363 
7364 /*
7365  * Return the address of the affected column.
7366  */
7367 static ObjectAddress
ATExecDropExpression(Relation rel,const char * colName,bool missing_ok,LOCKMODE lockmode)7368 ATExecDropExpression(Relation rel, const char *colName, bool missing_ok, LOCKMODE lockmode)
7369 {
7370 	HeapTuple	tuple;
7371 	Form_pg_attribute attTup;
7372 	AttrNumber	attnum;
7373 	Relation	attrelation;
7374 	ObjectAddress address;
7375 
7376 	attrelation = table_open(AttributeRelationId, RowExclusiveLock);
7377 	tuple = SearchSysCacheCopyAttName(RelationGetRelid(rel), colName);
7378 	if (!HeapTupleIsValid(tuple))
7379 		ereport(ERROR,
7380 				(errcode(ERRCODE_UNDEFINED_COLUMN),
7381 				 errmsg("column \"%s\" of relation \"%s\" does not exist",
7382 						colName, RelationGetRelationName(rel))));
7383 
7384 	attTup = (Form_pg_attribute) GETSTRUCT(tuple);
7385 	attnum = attTup->attnum;
7386 
7387 	if (attnum <= 0)
7388 		ereport(ERROR,
7389 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
7390 				 errmsg("cannot alter system column \"%s\"",
7391 						colName)));
7392 
7393 	if (attTup->attgenerated != ATTRIBUTE_GENERATED_STORED)
7394 	{
7395 		if (!missing_ok)
7396 			ereport(ERROR,
7397 					(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
7398 					 errmsg("column \"%s\" of relation \"%s\" is not a stored generated column",
7399 							colName, RelationGetRelationName(rel))));
7400 		else
7401 		{
7402 			ereport(NOTICE,
7403 					(errmsg("column \"%s\" of relation \"%s\" is not a stored generated column, skipping",
7404 							colName, RelationGetRelationName(rel))));
7405 			heap_freetuple(tuple);
7406 			table_close(attrelation, RowExclusiveLock);
7407 			return InvalidObjectAddress;
7408 		}
7409 	}
7410 
7411 	attTup->attgenerated = '\0';
7412 	CatalogTupleUpdate(attrelation, &tuple->t_self, tuple);
7413 
7414 	InvokeObjectPostAlterHook(RelationRelationId,
7415 							  RelationGetRelid(rel),
7416 							  attTup->attnum);
7417 	ObjectAddressSubSet(address, RelationRelationId,
7418 						RelationGetRelid(rel), attnum);
7419 	heap_freetuple(tuple);
7420 
7421 	table_close(attrelation, RowExclusiveLock);
7422 
7423 	CommandCounterIncrement();
7424 
7425 	RemoveAttrDefault(RelationGetRelid(rel), attnum, DROP_RESTRICT, false, false);
7426 
7427 	/*
7428 	 * Remove all dependencies of this (formerly generated) column on other
7429 	 * columns in the same table.  (See StoreAttrDefault() for which
7430 	 * dependencies are created.)  We don't expect there to be dependencies
7431 	 * between columns of the same table for other reasons, so it's okay to
7432 	 * remove all of them.
7433 	 */
7434 	{
7435 		Relation	depRel;
7436 		ScanKeyData key[3];
7437 		SysScanDesc scan;
7438 		HeapTuple	tup;
7439 
7440 		depRel = table_open(DependRelationId, RowExclusiveLock);
7441 
7442 		ScanKeyInit(&key[0],
7443 					Anum_pg_depend_classid,
7444 					BTEqualStrategyNumber, F_OIDEQ,
7445 					ObjectIdGetDatum(RelationRelationId));
7446 		ScanKeyInit(&key[1],
7447 					Anum_pg_depend_objid,
7448 					BTEqualStrategyNumber, F_OIDEQ,
7449 					ObjectIdGetDatum(RelationGetRelid(rel)));
7450 		ScanKeyInit(&key[2],
7451 					Anum_pg_depend_objsubid,
7452 					BTEqualStrategyNumber, F_INT4EQ,
7453 					Int32GetDatum(attnum));
7454 
7455 		scan = systable_beginscan(depRel, DependDependerIndexId, true,
7456 								  NULL, 3, key);
7457 
7458 		while (HeapTupleIsValid(tup = systable_getnext(scan)))
7459 		{
7460 			Form_pg_depend depform = (Form_pg_depend) GETSTRUCT(tup);
7461 
7462 			if (depform->refclassid == RelationRelationId &&
7463 				depform->refobjid == RelationGetRelid(rel) &&
7464 				depform->refobjsubid != 0 &&
7465 				depform->deptype == DEPENDENCY_AUTO)
7466 			{
7467 				CatalogTupleDelete(depRel, &tup->t_self);
7468 			}
7469 		}
7470 
7471 		systable_endscan(scan);
7472 
7473 		table_close(depRel, RowExclusiveLock);
7474 	}
7475 
7476 	return address;
7477 }
7478 
7479 /*
7480  * ALTER TABLE ALTER COLUMN SET STATISTICS
7481  *
7482  * Return value is the address of the modified column
7483  */
7484 static ObjectAddress
ATExecSetStatistics(Relation rel,const char * colName,int16 colNum,Node * newValue,LOCKMODE lockmode)7485 ATExecSetStatistics(Relation rel, const char *colName, int16 colNum, Node *newValue, LOCKMODE lockmode)
7486 {
7487 	int			newtarget;
7488 	Relation	attrelation;
7489 	HeapTuple	tuple;
7490 	Form_pg_attribute attrtuple;
7491 	AttrNumber	attnum;
7492 	ObjectAddress address;
7493 
7494 	/*
7495 	 * We allow referencing columns by numbers only for indexes, since table
7496 	 * column numbers could contain gaps if columns are later dropped.
7497 	 */
7498 	if (rel->rd_rel->relkind != RELKIND_INDEX &&
7499 		rel->rd_rel->relkind != RELKIND_PARTITIONED_INDEX &&
7500 		!colName)
7501 		ereport(ERROR,
7502 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
7503 				 errmsg("cannot refer to non-index column by number")));
7504 
7505 	Assert(IsA(newValue, Integer));
7506 	newtarget = intVal(newValue);
7507 
7508 	/*
7509 	 * Limit target to a sane range
7510 	 */
7511 	if (newtarget < -1)
7512 	{
7513 		ereport(ERROR,
7514 				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
7515 				 errmsg("statistics target %d is too low",
7516 						newtarget)));
7517 	}
7518 	else if (newtarget > 10000)
7519 	{
7520 		newtarget = 10000;
7521 		ereport(WARNING,
7522 				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
7523 				 errmsg("lowering statistics target to %d",
7524 						newtarget)));
7525 	}
7526 
7527 	attrelation = table_open(AttributeRelationId, RowExclusiveLock);
7528 
7529 	if (colName)
7530 	{
7531 		tuple = SearchSysCacheCopyAttName(RelationGetRelid(rel), colName);
7532 
7533 		if (!HeapTupleIsValid(tuple))
7534 			ereport(ERROR,
7535 					(errcode(ERRCODE_UNDEFINED_COLUMN),
7536 					 errmsg("column \"%s\" of relation \"%s\" does not exist",
7537 							colName, RelationGetRelationName(rel))));
7538 	}
7539 	else
7540 	{
7541 		tuple = SearchSysCacheCopyAttNum(RelationGetRelid(rel), colNum);
7542 
7543 		if (!HeapTupleIsValid(tuple))
7544 			ereport(ERROR,
7545 					(errcode(ERRCODE_UNDEFINED_COLUMN),
7546 					 errmsg("column number %d of relation \"%s\" does not exist",
7547 							colNum, RelationGetRelationName(rel))));
7548 	}
7549 
7550 	attrtuple = (Form_pg_attribute) GETSTRUCT(tuple);
7551 
7552 	attnum = attrtuple->attnum;
7553 	if (attnum <= 0)
7554 		ereport(ERROR,
7555 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
7556 				 errmsg("cannot alter system column \"%s\"",
7557 						colName)));
7558 
7559 	if (rel->rd_rel->relkind == RELKIND_INDEX ||
7560 		rel->rd_rel->relkind == RELKIND_PARTITIONED_INDEX)
7561 	{
7562 		if (attnum > rel->rd_index->indnkeyatts)
7563 			ereport(ERROR,
7564 					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
7565 					 errmsg("cannot alter statistics on included column \"%s\" of index \"%s\"",
7566 							NameStr(attrtuple->attname), RelationGetRelationName(rel))));
7567 		else if (rel->rd_index->indkey.values[attnum - 1] != 0)
7568 			ereport(ERROR,
7569 					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
7570 					 errmsg("cannot alter statistics on non-expression column \"%s\" of index \"%s\"",
7571 							NameStr(attrtuple->attname), RelationGetRelationName(rel)),
7572 					 errhint("Alter statistics on table column instead.")));
7573 	}
7574 
7575 	attrtuple->attstattarget = newtarget;
7576 
7577 	CatalogTupleUpdate(attrelation, &tuple->t_self, tuple);
7578 
7579 	InvokeObjectPostAlterHook(RelationRelationId,
7580 							  RelationGetRelid(rel),
7581 							  attrtuple->attnum);
7582 	ObjectAddressSubSet(address, RelationRelationId,
7583 						RelationGetRelid(rel), attnum);
7584 	heap_freetuple(tuple);
7585 
7586 	table_close(attrelation, RowExclusiveLock);
7587 
7588 	return address;
7589 }
7590 
7591 /*
7592  * Return value is the address of the modified column
7593  */
7594 static ObjectAddress
ATExecSetOptions(Relation rel,const char * colName,Node * options,bool isReset,LOCKMODE lockmode)7595 ATExecSetOptions(Relation rel, const char *colName, Node *options,
7596 				 bool isReset, LOCKMODE lockmode)
7597 {
7598 	Relation	attrelation;
7599 	HeapTuple	tuple,
7600 				newtuple;
7601 	Form_pg_attribute attrtuple;
7602 	AttrNumber	attnum;
7603 	Datum		datum,
7604 				newOptions;
7605 	bool		isnull;
7606 	ObjectAddress address;
7607 	Datum		repl_val[Natts_pg_attribute];
7608 	bool		repl_null[Natts_pg_attribute];
7609 	bool		repl_repl[Natts_pg_attribute];
7610 
7611 	attrelation = table_open(AttributeRelationId, RowExclusiveLock);
7612 
7613 	tuple = SearchSysCacheAttName(RelationGetRelid(rel), colName);
7614 
7615 	if (!HeapTupleIsValid(tuple))
7616 		ereport(ERROR,
7617 				(errcode(ERRCODE_UNDEFINED_COLUMN),
7618 				 errmsg("column \"%s\" of relation \"%s\" does not exist",
7619 						colName, RelationGetRelationName(rel))));
7620 	attrtuple = (Form_pg_attribute) GETSTRUCT(tuple);
7621 
7622 	attnum = attrtuple->attnum;
7623 	if (attnum <= 0)
7624 		ereport(ERROR,
7625 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
7626 				 errmsg("cannot alter system column \"%s\"",
7627 						colName)));
7628 
7629 	/* Generate new proposed attoptions (text array) */
7630 	datum = SysCacheGetAttr(ATTNAME, tuple, Anum_pg_attribute_attoptions,
7631 							&isnull);
7632 	newOptions = transformRelOptions(isnull ? (Datum) 0 : datum,
7633 									 castNode(List, options), NULL, NULL,
7634 									 false, isReset);
7635 	/* Validate new options */
7636 	(void) attribute_reloptions(newOptions, true);
7637 
7638 	/* Build new tuple. */
7639 	memset(repl_null, false, sizeof(repl_null));
7640 	memset(repl_repl, false, sizeof(repl_repl));
7641 	if (newOptions != (Datum) 0)
7642 		repl_val[Anum_pg_attribute_attoptions - 1] = newOptions;
7643 	else
7644 		repl_null[Anum_pg_attribute_attoptions - 1] = true;
7645 	repl_repl[Anum_pg_attribute_attoptions - 1] = true;
7646 	newtuple = heap_modify_tuple(tuple, RelationGetDescr(attrelation),
7647 								 repl_val, repl_null, repl_repl);
7648 
7649 	/* Update system catalog. */
7650 	CatalogTupleUpdate(attrelation, &newtuple->t_self, newtuple);
7651 
7652 	InvokeObjectPostAlterHook(RelationRelationId,
7653 							  RelationGetRelid(rel),
7654 							  attrtuple->attnum);
7655 	ObjectAddressSubSet(address, RelationRelationId,
7656 						RelationGetRelid(rel), attnum);
7657 
7658 	heap_freetuple(newtuple);
7659 
7660 	ReleaseSysCache(tuple);
7661 
7662 	table_close(attrelation, RowExclusiveLock);
7663 
7664 	return address;
7665 }
7666 
7667 /*
7668  * ALTER TABLE ALTER COLUMN SET STORAGE
7669  *
7670  * Return value is the address of the modified column
7671  */
7672 static ObjectAddress
ATExecSetStorage(Relation rel,const char * colName,Node * newValue,LOCKMODE lockmode)7673 ATExecSetStorage(Relation rel, const char *colName, Node *newValue, LOCKMODE lockmode)
7674 {
7675 	char	   *storagemode;
7676 	char		newstorage;
7677 	Relation	attrelation;
7678 	HeapTuple	tuple;
7679 	Form_pg_attribute attrtuple;
7680 	AttrNumber	attnum;
7681 	ObjectAddress address;
7682 	ListCell   *lc;
7683 
7684 	Assert(IsA(newValue, String));
7685 	storagemode = strVal(newValue);
7686 
7687 	if (pg_strcasecmp(storagemode, "plain") == 0)
7688 		newstorage = TYPSTORAGE_PLAIN;
7689 	else if (pg_strcasecmp(storagemode, "external") == 0)
7690 		newstorage = TYPSTORAGE_EXTERNAL;
7691 	else if (pg_strcasecmp(storagemode, "extended") == 0)
7692 		newstorage = TYPSTORAGE_EXTENDED;
7693 	else if (pg_strcasecmp(storagemode, "main") == 0)
7694 		newstorage = TYPSTORAGE_MAIN;
7695 	else
7696 	{
7697 		ereport(ERROR,
7698 				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
7699 				 errmsg("invalid storage type \"%s\"",
7700 						storagemode)));
7701 		newstorage = 0;			/* keep compiler quiet */
7702 	}
7703 
7704 	attrelation = table_open(AttributeRelationId, RowExclusiveLock);
7705 
7706 	tuple = SearchSysCacheCopyAttName(RelationGetRelid(rel), colName);
7707 
7708 	if (!HeapTupleIsValid(tuple))
7709 		ereport(ERROR,
7710 				(errcode(ERRCODE_UNDEFINED_COLUMN),
7711 				 errmsg("column \"%s\" of relation \"%s\" does not exist",
7712 						colName, RelationGetRelationName(rel))));
7713 	attrtuple = (Form_pg_attribute) GETSTRUCT(tuple);
7714 
7715 	attnum = attrtuple->attnum;
7716 	if (attnum <= 0)
7717 		ereport(ERROR,
7718 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
7719 				 errmsg("cannot alter system column \"%s\"",
7720 						colName)));
7721 
7722 	/*
7723 	 * safety check: do not allow toasted storage modes unless column datatype
7724 	 * is TOAST-aware.
7725 	 */
7726 	if (newstorage == TYPSTORAGE_PLAIN || TypeIsToastable(attrtuple->atttypid))
7727 		attrtuple->attstorage = newstorage;
7728 	else
7729 		ereport(ERROR,
7730 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
7731 				 errmsg("column data type %s can only have storage PLAIN",
7732 						format_type_be(attrtuple->atttypid))));
7733 
7734 	CatalogTupleUpdate(attrelation, &tuple->t_self, tuple);
7735 
7736 	InvokeObjectPostAlterHook(RelationRelationId,
7737 							  RelationGetRelid(rel),
7738 							  attrtuple->attnum);
7739 
7740 	heap_freetuple(tuple);
7741 
7742 	/*
7743 	 * Apply the change to indexes as well (only for simple index columns,
7744 	 * matching behavior of index.c ConstructTupleDescriptor()).
7745 	 */
7746 	foreach(lc, RelationGetIndexList(rel))
7747 	{
7748 		Oid			indexoid = lfirst_oid(lc);
7749 		Relation	indrel;
7750 		AttrNumber	indattnum = 0;
7751 
7752 		indrel = index_open(indexoid, lockmode);
7753 
7754 		for (int i = 0; i < indrel->rd_index->indnatts; i++)
7755 		{
7756 			if (indrel->rd_index->indkey.values[i] == attnum)
7757 			{
7758 				indattnum = i + 1;
7759 				break;
7760 			}
7761 		}
7762 
7763 		if (indattnum == 0)
7764 		{
7765 			index_close(indrel, lockmode);
7766 			continue;
7767 		}
7768 
7769 		tuple = SearchSysCacheCopyAttNum(RelationGetRelid(indrel), indattnum);
7770 
7771 		if (HeapTupleIsValid(tuple))
7772 		{
7773 			attrtuple = (Form_pg_attribute) GETSTRUCT(tuple);
7774 			attrtuple->attstorage = newstorage;
7775 
7776 			CatalogTupleUpdate(attrelation, &tuple->t_self, tuple);
7777 
7778 			InvokeObjectPostAlterHook(RelationRelationId,
7779 									  RelationGetRelid(rel),
7780 									  attrtuple->attnum);
7781 
7782 			heap_freetuple(tuple);
7783 		}
7784 
7785 		index_close(indrel, lockmode);
7786 	}
7787 
7788 	table_close(attrelation, RowExclusiveLock);
7789 
7790 	ObjectAddressSubSet(address, RelationRelationId,
7791 						RelationGetRelid(rel), attnum);
7792 	return address;
7793 }
7794 
7795 
7796 /*
7797  * ALTER TABLE DROP COLUMN
7798  *
7799  * DROP COLUMN cannot use the normal ALTER TABLE recursion mechanism,
7800  * because we have to decide at runtime whether to recurse or not depending
7801  * on whether attinhcount goes to zero or not.  (We can't check this in a
7802  * static pre-pass because it won't handle multiple inheritance situations
7803  * correctly.)
7804  */
7805 static void
ATPrepDropColumn(List ** wqueue,Relation rel,bool recurse,bool recursing,AlterTableCmd * cmd,LOCKMODE lockmode,AlterTableUtilityContext * context)7806 ATPrepDropColumn(List **wqueue, Relation rel, bool recurse, bool recursing,
7807 				 AlterTableCmd *cmd, LOCKMODE lockmode,
7808 				 AlterTableUtilityContext *context)
7809 {
7810 	if (rel->rd_rel->reloftype && !recursing)
7811 		ereport(ERROR,
7812 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
7813 				 errmsg("cannot drop column from typed table")));
7814 
7815 	if (rel->rd_rel->relkind == RELKIND_COMPOSITE_TYPE)
7816 		ATTypedTableRecursion(wqueue, rel, cmd, lockmode, context);
7817 
7818 	if (recurse)
7819 		cmd->subtype = AT_DropColumnRecurse;
7820 }
7821 
7822 /*
7823  * Drops column 'colName' from relation 'rel' and returns the address of the
7824  * dropped column.  The column is also dropped (or marked as no longer
7825  * inherited from relation) from the relation's inheritance children, if any.
7826  *
7827  * In the recursive invocations for inheritance child relations, instead of
7828  * dropping the column directly (if to be dropped at all), its object address
7829  * is added to 'addrs', which must be non-NULL in such invocations.  All
7830  * columns are dropped at the same time after all the children have been
7831  * checked recursively.
7832  */
7833 static ObjectAddress
ATExecDropColumn(List ** wqueue,Relation rel,const char * colName,DropBehavior behavior,bool recurse,bool recursing,bool missing_ok,LOCKMODE lockmode,ObjectAddresses * addrs)7834 ATExecDropColumn(List **wqueue, Relation rel, const char *colName,
7835 				 DropBehavior behavior,
7836 				 bool recurse, bool recursing,
7837 				 bool missing_ok, LOCKMODE lockmode,
7838 				 ObjectAddresses *addrs)
7839 {
7840 	HeapTuple	tuple;
7841 	Form_pg_attribute targetatt;
7842 	AttrNumber	attnum;
7843 	List	   *children;
7844 	ObjectAddress object;
7845 	bool		is_expr;
7846 
7847 	/* At top level, permission check was done in ATPrepCmd, else do it */
7848 	if (recursing)
7849 		ATSimplePermissions(rel, ATT_TABLE | ATT_FOREIGN_TABLE);
7850 
7851 	/* Initialize addrs on the first invocation */
7852 	Assert(!recursing || addrs != NULL);
7853 	if (!recursing)
7854 		addrs = new_object_addresses();
7855 
7856 	/*
7857 	 * get the number of the attribute
7858 	 */
7859 	tuple = SearchSysCacheAttName(RelationGetRelid(rel), colName);
7860 	if (!HeapTupleIsValid(tuple))
7861 	{
7862 		if (!missing_ok)
7863 		{
7864 			ereport(ERROR,
7865 					(errcode(ERRCODE_UNDEFINED_COLUMN),
7866 					 errmsg("column \"%s\" of relation \"%s\" does not exist",
7867 							colName, RelationGetRelationName(rel))));
7868 		}
7869 		else
7870 		{
7871 			ereport(NOTICE,
7872 					(errmsg("column \"%s\" of relation \"%s\" does not exist, skipping",
7873 							colName, RelationGetRelationName(rel))));
7874 			return InvalidObjectAddress;
7875 		}
7876 	}
7877 	targetatt = (Form_pg_attribute) GETSTRUCT(tuple);
7878 
7879 	attnum = targetatt->attnum;
7880 
7881 	/* Can't drop a system attribute */
7882 	if (attnum <= 0)
7883 		ereport(ERROR,
7884 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
7885 				 errmsg("cannot drop system column \"%s\"",
7886 						colName)));
7887 
7888 	/*
7889 	 * Don't drop inherited columns, unless recursing (presumably from a drop
7890 	 * of the parent column)
7891 	 */
7892 	if (targetatt->attinhcount > 0 && !recursing)
7893 		ereport(ERROR,
7894 				(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
7895 				 errmsg("cannot drop inherited column \"%s\"",
7896 						colName)));
7897 
7898 	/*
7899 	 * Don't drop columns used in the partition key, either.  (If we let this
7900 	 * go through, the key column's dependencies would cause a cascaded drop
7901 	 * of the whole table, which is surely not what the user expected.)
7902 	 */
7903 	if (has_partition_attrs(rel,
7904 							bms_make_singleton(attnum - FirstLowInvalidHeapAttributeNumber),
7905 							&is_expr))
7906 		ereport(ERROR,
7907 				(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
7908 				 errmsg("cannot drop column \"%s\" because it is part of the partition key of relation \"%s\"",
7909 						colName, RelationGetRelationName(rel))));
7910 
7911 	ReleaseSysCache(tuple);
7912 
7913 	/*
7914 	 * Propagate to children as appropriate.  Unlike most other ALTER
7915 	 * routines, we have to do this one level of recursion at a time; we can't
7916 	 * use find_all_inheritors to do it in one pass.
7917 	 */
7918 	children = find_inheritance_children(RelationGetRelid(rel), lockmode);
7919 
7920 	if (children)
7921 	{
7922 		Relation	attr_rel;
7923 		ListCell   *child;
7924 
7925 		/*
7926 		 * In case of a partitioned table, the column must be dropped from the
7927 		 * partitions as well.
7928 		 */
7929 		if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE && !recurse)
7930 			ereport(ERROR,
7931 					(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
7932 					 errmsg("cannot drop column from only the partitioned table when partitions exist"),
7933 					 errhint("Do not specify the ONLY keyword.")));
7934 
7935 		attr_rel = table_open(AttributeRelationId, RowExclusiveLock);
7936 		foreach(child, children)
7937 		{
7938 			Oid			childrelid = lfirst_oid(child);
7939 			Relation	childrel;
7940 			Form_pg_attribute childatt;
7941 
7942 			/* find_inheritance_children already got lock */
7943 			childrel = table_open(childrelid, NoLock);
7944 			CheckTableNotInUse(childrel, "ALTER TABLE");
7945 
7946 			tuple = SearchSysCacheCopyAttName(childrelid, colName);
7947 			if (!HeapTupleIsValid(tuple))	/* shouldn't happen */
7948 				elog(ERROR, "cache lookup failed for attribute \"%s\" of relation %u",
7949 					 colName, childrelid);
7950 			childatt = (Form_pg_attribute) GETSTRUCT(tuple);
7951 
7952 			if (childatt->attinhcount <= 0) /* shouldn't happen */
7953 				elog(ERROR, "relation %u has non-inherited attribute \"%s\"",
7954 					 childrelid, colName);
7955 
7956 			if (recurse)
7957 			{
7958 				/*
7959 				 * If the child column has other definition sources, just
7960 				 * decrement its inheritance count; if not, recurse to delete
7961 				 * it.
7962 				 */
7963 				if (childatt->attinhcount == 1 && !childatt->attislocal)
7964 				{
7965 					/* Time to delete this child column, too */
7966 					ATExecDropColumn(wqueue, childrel, colName,
7967 									 behavior, true, true,
7968 									 false, lockmode, addrs);
7969 				}
7970 				else
7971 				{
7972 					/* Child column must survive my deletion */
7973 					childatt->attinhcount--;
7974 
7975 					CatalogTupleUpdate(attr_rel, &tuple->t_self, tuple);
7976 
7977 					/* Make update visible */
7978 					CommandCounterIncrement();
7979 				}
7980 			}
7981 			else
7982 			{
7983 				/*
7984 				 * If we were told to drop ONLY in this table (no recursion),
7985 				 * we need to mark the inheritors' attributes as locally
7986 				 * defined rather than inherited.
7987 				 */
7988 				childatt->attinhcount--;
7989 				childatt->attislocal = true;
7990 
7991 				CatalogTupleUpdate(attr_rel, &tuple->t_self, tuple);
7992 
7993 				/* Make update visible */
7994 				CommandCounterIncrement();
7995 			}
7996 
7997 			heap_freetuple(tuple);
7998 
7999 			table_close(childrel, NoLock);
8000 		}
8001 		table_close(attr_rel, RowExclusiveLock);
8002 	}
8003 
8004 	/* Add object to delete */
8005 	object.classId = RelationRelationId;
8006 	object.objectId = RelationGetRelid(rel);
8007 	object.objectSubId = attnum;
8008 	add_exact_object_address(&object, addrs);
8009 
8010 	if (!recursing)
8011 	{
8012 		/* Recursion has ended, drop everything that was collected */
8013 		performMultipleDeletions(addrs, behavior, 0);
8014 		free_object_addresses(addrs);
8015 	}
8016 
8017 	return object;
8018 }
8019 
8020 /*
8021  * ALTER TABLE ADD INDEX
8022  *
8023  * There is no such command in the grammar, but parse_utilcmd.c converts
8024  * UNIQUE and PRIMARY KEY constraints into AT_AddIndex subcommands.  This lets
8025  * us schedule creation of the index at the appropriate time during ALTER.
8026  *
8027  * Return value is the address of the new index.
8028  */
8029 static ObjectAddress
ATExecAddIndex(AlteredTableInfo * tab,Relation rel,IndexStmt * stmt,bool is_rebuild,LOCKMODE lockmode)8030 ATExecAddIndex(AlteredTableInfo *tab, Relation rel,
8031 			   IndexStmt *stmt, bool is_rebuild, LOCKMODE lockmode)
8032 {
8033 	bool		check_rights;
8034 	bool		skip_build;
8035 	bool		quiet;
8036 	ObjectAddress address;
8037 
8038 	Assert(IsA(stmt, IndexStmt));
8039 	Assert(!stmt->concurrent);
8040 
8041 	/* The IndexStmt has already been through transformIndexStmt */
8042 	Assert(stmt->transformed);
8043 
8044 	/* suppress schema rights check when rebuilding existing index */
8045 	check_rights = !is_rebuild;
8046 	/* skip index build if phase 3 will do it or we're reusing an old one */
8047 	skip_build = tab->rewrite > 0 || OidIsValid(stmt->oldNode);
8048 	/* suppress notices when rebuilding existing index */
8049 	quiet = is_rebuild;
8050 
8051 	address = DefineIndex(RelationGetRelid(rel),
8052 						  stmt,
8053 						  InvalidOid,	/* no predefined OID */
8054 						  InvalidOid,	/* no parent index */
8055 						  InvalidOid,	/* no parent constraint */
8056 						  true, /* is_alter_table */
8057 						  check_rights,
8058 						  false,	/* check_not_in_use - we did it already */
8059 						  skip_build,
8060 						  quiet);
8061 
8062 	/*
8063 	 * If TryReuseIndex() stashed a relfilenode for us, we used it for the new
8064 	 * index instead of building from scratch.  Restore associated fields.
8065 	 * This may store InvalidSubTransactionId in both fields, in which case
8066 	 * relcache.c will assume it can rebuild the relcache entry.  Hence, do
8067 	 * this after the CCI that made catalog rows visible to any rebuild.  The
8068 	 * DROP of the old edition of this index will have scheduled the storage
8069 	 * for deletion at commit, so cancel that pending deletion.
8070 	 */
8071 	if (OidIsValid(stmt->oldNode))
8072 	{
8073 		Relation	irel = index_open(address.objectId, NoLock);
8074 
8075 		irel->rd_createSubid = stmt->oldCreateSubid;
8076 		irel->rd_firstRelfilenodeSubid = stmt->oldFirstRelfilenodeSubid;
8077 		RelationPreserveStorage(irel->rd_node, true);
8078 		index_close(irel, NoLock);
8079 	}
8080 
8081 	return address;
8082 }
8083 
8084 /*
8085  * ALTER TABLE ADD CONSTRAINT USING INDEX
8086  *
8087  * Returns the address of the new constraint.
8088  */
8089 static ObjectAddress
ATExecAddIndexConstraint(AlteredTableInfo * tab,Relation rel,IndexStmt * stmt,LOCKMODE lockmode)8090 ATExecAddIndexConstraint(AlteredTableInfo *tab, Relation rel,
8091 						 IndexStmt *stmt, LOCKMODE lockmode)
8092 {
8093 	Oid			index_oid = stmt->indexOid;
8094 	Relation	indexRel;
8095 	char	   *indexName;
8096 	IndexInfo  *indexInfo;
8097 	char	   *constraintName;
8098 	char		constraintType;
8099 	ObjectAddress address;
8100 	bits16		flags;
8101 
8102 	Assert(IsA(stmt, IndexStmt));
8103 	Assert(OidIsValid(index_oid));
8104 	Assert(stmt->isconstraint);
8105 
8106 	/*
8107 	 * Doing this on partitioned tables is not a simple feature to implement,
8108 	 * so let's punt for now.
8109 	 */
8110 	if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
8111 		ereport(ERROR,
8112 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
8113 				 errmsg("ALTER TABLE / ADD CONSTRAINT USING INDEX is not supported on partitioned tables")));
8114 
8115 	indexRel = index_open(index_oid, AccessShareLock);
8116 
8117 	indexName = pstrdup(RelationGetRelationName(indexRel));
8118 
8119 	indexInfo = BuildIndexInfo(indexRel);
8120 
8121 	/* this should have been checked at parse time */
8122 	if (!indexInfo->ii_Unique)
8123 		elog(ERROR, "index \"%s\" is not unique", indexName);
8124 
8125 	/*
8126 	 * Determine name to assign to constraint.  We require a constraint to
8127 	 * have the same name as the underlying index; therefore, use the index's
8128 	 * existing name as the default constraint name, and if the user
8129 	 * explicitly gives some other name for the constraint, rename the index
8130 	 * to match.
8131 	 */
8132 	constraintName = stmt->idxname;
8133 	if (constraintName == NULL)
8134 		constraintName = indexName;
8135 	else if (strcmp(constraintName, indexName) != 0)
8136 	{
8137 		ereport(NOTICE,
8138 				(errmsg("ALTER TABLE / ADD CONSTRAINT USING INDEX will rename index \"%s\" to \"%s\"",
8139 						indexName, constraintName)));
8140 		RenameRelationInternal(index_oid, constraintName, false, true);
8141 	}
8142 
8143 	/* Extra checks needed if making primary key */
8144 	if (stmt->primary)
8145 		index_check_primary_key(rel, indexInfo, true, stmt);
8146 
8147 	/* Note we currently don't support EXCLUSION constraints here */
8148 	if (stmt->primary)
8149 		constraintType = CONSTRAINT_PRIMARY;
8150 	else
8151 		constraintType = CONSTRAINT_UNIQUE;
8152 
8153 	/* Create the catalog entries for the constraint */
8154 	flags = INDEX_CONSTR_CREATE_UPDATE_INDEX |
8155 		INDEX_CONSTR_CREATE_REMOVE_OLD_DEPS |
8156 		(stmt->initdeferred ? INDEX_CONSTR_CREATE_INIT_DEFERRED : 0) |
8157 		(stmt->deferrable ? INDEX_CONSTR_CREATE_DEFERRABLE : 0) |
8158 		(stmt->primary ? INDEX_CONSTR_CREATE_MARK_AS_PRIMARY : 0);
8159 
8160 	address = index_constraint_create(rel,
8161 									  index_oid,
8162 									  InvalidOid,
8163 									  indexInfo,
8164 									  constraintName,
8165 									  constraintType,
8166 									  flags,
8167 									  allowSystemTableMods,
8168 									  false);	/* is_internal */
8169 
8170 	index_close(indexRel, NoLock);
8171 
8172 	return address;
8173 }
8174 
8175 /*
8176  * ALTER TABLE ADD CONSTRAINT
8177  *
8178  * Return value is the address of the new constraint; if no constraint was
8179  * added, InvalidObjectAddress is returned.
8180  */
8181 static ObjectAddress
ATExecAddConstraint(List ** wqueue,AlteredTableInfo * tab,Relation rel,Constraint * newConstraint,bool recurse,bool is_readd,LOCKMODE lockmode)8182 ATExecAddConstraint(List **wqueue, AlteredTableInfo *tab, Relation rel,
8183 					Constraint *newConstraint, bool recurse, bool is_readd,
8184 					LOCKMODE lockmode)
8185 {
8186 	ObjectAddress address = InvalidObjectAddress;
8187 
8188 	Assert(IsA(newConstraint, Constraint));
8189 
8190 	/*
8191 	 * Currently, we only expect to see CONSTR_CHECK and CONSTR_FOREIGN nodes
8192 	 * arriving here (see the preprocessing done in parse_utilcmd.c).  Use a
8193 	 * switch anyway to make it easier to add more code later.
8194 	 */
8195 	switch (newConstraint->contype)
8196 	{
8197 		case CONSTR_CHECK:
8198 			address =
8199 				ATAddCheckConstraint(wqueue, tab, rel,
8200 									 newConstraint, recurse, false, is_readd,
8201 									 lockmode);
8202 			break;
8203 
8204 		case CONSTR_FOREIGN:
8205 
8206 			/*
8207 			 * Assign or validate constraint name
8208 			 */
8209 			if (newConstraint->conname)
8210 			{
8211 				if (ConstraintNameIsUsed(CONSTRAINT_RELATION,
8212 										 RelationGetRelid(rel),
8213 										 newConstraint->conname))
8214 					ereport(ERROR,
8215 							(errcode(ERRCODE_DUPLICATE_OBJECT),
8216 							 errmsg("constraint \"%s\" for relation \"%s\" already exists",
8217 									newConstraint->conname,
8218 									RelationGetRelationName(rel))));
8219 			}
8220 			else
8221 				newConstraint->conname =
8222 					ChooseConstraintName(RelationGetRelationName(rel),
8223 										 ChooseForeignKeyConstraintNameAddition(newConstraint->fk_attrs),
8224 										 "fkey",
8225 										 RelationGetNamespace(rel),
8226 										 NIL);
8227 
8228 			address = ATAddForeignKeyConstraint(wqueue, tab, rel,
8229 												newConstraint, InvalidOid,
8230 												recurse, false,
8231 												lockmode);
8232 			break;
8233 
8234 		default:
8235 			elog(ERROR, "unrecognized constraint type: %d",
8236 				 (int) newConstraint->contype);
8237 	}
8238 
8239 	return address;
8240 }
8241 
8242 /*
8243  * Generate the column-name portion of the constraint name for a new foreign
8244  * key given the list of column names that reference the referenced
8245  * table.  This will be passed to ChooseConstraintName along with the parent
8246  * table name and the "fkey" suffix.
8247  *
8248  * We know that less than NAMEDATALEN characters will actually be used, so we
8249  * can truncate the result once we've generated that many.
8250  *
8251  * XXX see also ChooseExtendedStatisticNameAddition and
8252  * ChooseIndexNameAddition.
8253  */
8254 static char *
ChooseForeignKeyConstraintNameAddition(List * colnames)8255 ChooseForeignKeyConstraintNameAddition(List *colnames)
8256 {
8257 	char		buf[NAMEDATALEN * 2];
8258 	int			buflen = 0;
8259 	ListCell   *lc;
8260 
8261 	buf[0] = '\0';
8262 	foreach(lc, colnames)
8263 	{
8264 		const char *name = strVal(lfirst(lc));
8265 
8266 		if (buflen > 0)
8267 			buf[buflen++] = '_';	/* insert _ between names */
8268 
8269 		/*
8270 		 * At this point we have buflen <= NAMEDATALEN.  name should be less
8271 		 * than NAMEDATALEN already, but use strlcpy for paranoia.
8272 		 */
8273 		strlcpy(buf + buflen, name, NAMEDATALEN);
8274 		buflen += strlen(buf + buflen);
8275 		if (buflen >= NAMEDATALEN)
8276 			break;
8277 	}
8278 	return pstrdup(buf);
8279 }
8280 
8281 /*
8282  * Add a check constraint to a single table and its children.  Returns the
8283  * address of the constraint added to the parent relation, if one gets added,
8284  * or InvalidObjectAddress otherwise.
8285  *
8286  * Subroutine for ATExecAddConstraint.
8287  *
8288  * We must recurse to child tables during execution, rather than using
8289  * ALTER TABLE's normal prep-time recursion.  The reason is that all the
8290  * constraints *must* be given the same name, else they won't be seen as
8291  * related later.  If the user didn't explicitly specify a name, then
8292  * AddRelationNewConstraints would normally assign different names to the
8293  * child constraints.  To fix that, we must capture the name assigned at
8294  * the parent table and pass that down.
8295  */
8296 static ObjectAddress
ATAddCheckConstraint(List ** wqueue,AlteredTableInfo * tab,Relation rel,Constraint * constr,bool recurse,bool recursing,bool is_readd,LOCKMODE lockmode)8297 ATAddCheckConstraint(List **wqueue, AlteredTableInfo *tab, Relation rel,
8298 					 Constraint *constr, bool recurse, bool recursing,
8299 					 bool is_readd, LOCKMODE lockmode)
8300 {
8301 	List	   *newcons;
8302 	ListCell   *lcon;
8303 	List	   *children;
8304 	ListCell   *child;
8305 	ObjectAddress address = InvalidObjectAddress;
8306 
8307 	/* At top level, permission check was done in ATPrepCmd, else do it */
8308 	if (recursing)
8309 		ATSimplePermissions(rel, ATT_TABLE | ATT_FOREIGN_TABLE);
8310 
8311 	/*
8312 	 * Call AddRelationNewConstraints to do the work, making sure it works on
8313 	 * a copy of the Constraint so transformExpr can't modify the original. It
8314 	 * returns a list of cooked constraints.
8315 	 *
8316 	 * If the constraint ends up getting merged with a pre-existing one, it's
8317 	 * omitted from the returned list, which is what we want: we do not need
8318 	 * to do any validation work.  That can only happen at child tables,
8319 	 * though, since we disallow merging at the top level.
8320 	 */
8321 	newcons = AddRelationNewConstraints(rel, NIL,
8322 										list_make1(copyObject(constr)),
8323 										recursing | is_readd,	/* allow_merge */
8324 										!recursing, /* is_local */
8325 										is_readd,	/* is_internal */
8326 										NULL);	/* queryString not available
8327 												 * here */
8328 
8329 	/* we don't expect more than one constraint here */
8330 	Assert(list_length(newcons) <= 1);
8331 
8332 	/* Add each to-be-validated constraint to Phase 3's queue */
8333 	foreach(lcon, newcons)
8334 	{
8335 		CookedConstraint *ccon = (CookedConstraint *) lfirst(lcon);
8336 
8337 		if (!ccon->skip_validation)
8338 		{
8339 			NewConstraint *newcon;
8340 
8341 			newcon = (NewConstraint *) palloc0(sizeof(NewConstraint));
8342 			newcon->name = ccon->name;
8343 			newcon->contype = ccon->contype;
8344 			newcon->qual = ccon->expr;
8345 
8346 			tab->constraints = lappend(tab->constraints, newcon);
8347 		}
8348 
8349 		/* Save the actually assigned name if it was defaulted */
8350 		if (constr->conname == NULL)
8351 			constr->conname = ccon->name;
8352 
8353 		ObjectAddressSet(address, ConstraintRelationId, ccon->conoid);
8354 	}
8355 
8356 	/* At this point we must have a locked-down name to use */
8357 	Assert(constr->conname != NULL);
8358 
8359 	/* Advance command counter in case same table is visited multiple times */
8360 	CommandCounterIncrement();
8361 
8362 	/*
8363 	 * If the constraint got merged with an existing constraint, we're done.
8364 	 * We mustn't recurse to child tables in this case, because they've
8365 	 * already got the constraint, and visiting them again would lead to an
8366 	 * incorrect value for coninhcount.
8367 	 */
8368 	if (newcons == NIL)
8369 		return address;
8370 
8371 	/*
8372 	 * If adding a NO INHERIT constraint, no need to find our children.
8373 	 */
8374 	if (constr->is_no_inherit)
8375 		return address;
8376 
8377 	/*
8378 	 * Propagate to children as appropriate.  Unlike most other ALTER
8379 	 * routines, we have to do this one level of recursion at a time; we can't
8380 	 * use find_all_inheritors to do it in one pass.
8381 	 */
8382 	children = find_inheritance_children(RelationGetRelid(rel), lockmode);
8383 
8384 	/*
8385 	 * Check if ONLY was specified with ALTER TABLE.  If so, allow the
8386 	 * constraint creation only if there are no children currently.  Error out
8387 	 * otherwise.
8388 	 */
8389 	if (!recurse && children != NIL)
8390 		ereport(ERROR,
8391 				(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
8392 				 errmsg("constraint must be added to child tables too")));
8393 
8394 	foreach(child, children)
8395 	{
8396 		Oid			childrelid = lfirst_oid(child);
8397 		Relation	childrel;
8398 		AlteredTableInfo *childtab;
8399 
8400 		/* find_inheritance_children already got lock */
8401 		childrel = table_open(childrelid, NoLock);
8402 		CheckTableNotInUse(childrel, "ALTER TABLE");
8403 
8404 		/* Find or create work queue entry for this table */
8405 		childtab = ATGetQueueEntry(wqueue, childrel);
8406 
8407 		/* Recurse to child */
8408 		ATAddCheckConstraint(wqueue, childtab, childrel,
8409 							 constr, recurse, true, is_readd, lockmode);
8410 
8411 		table_close(childrel, NoLock);
8412 	}
8413 
8414 	return address;
8415 }
8416 
8417 /*
8418  * Add a foreign-key constraint to a single table; return the new constraint's
8419  * address.
8420  *
8421  * Subroutine for ATExecAddConstraint.  Must already hold exclusive
8422  * lock on the rel, and have done appropriate validity checks for it.
8423  * We do permissions checks here, however.
8424  *
8425  * When the referenced or referencing tables (or both) are partitioned,
8426  * multiple pg_constraint rows are required -- one for each partitioned table
8427  * and each partition on each side (fortunately, not one for every combination
8428  * thereof).  We also need action triggers on each leaf partition on the
8429  * referenced side, and check triggers on each leaf partition on the
8430  * referencing side.
8431  */
8432 static ObjectAddress
ATAddForeignKeyConstraint(List ** wqueue,AlteredTableInfo * tab,Relation rel,Constraint * fkconstraint,Oid parentConstr,bool recurse,bool recursing,LOCKMODE lockmode)8433 ATAddForeignKeyConstraint(List **wqueue, AlteredTableInfo *tab, Relation rel,
8434 						  Constraint *fkconstraint, Oid parentConstr,
8435 						  bool recurse, bool recursing, LOCKMODE lockmode)
8436 {
8437 	Relation	pkrel;
8438 	int16		pkattnum[INDEX_MAX_KEYS];
8439 	int16		fkattnum[INDEX_MAX_KEYS];
8440 	Oid			pktypoid[INDEX_MAX_KEYS];
8441 	Oid			fktypoid[INDEX_MAX_KEYS];
8442 	Oid			opclasses[INDEX_MAX_KEYS];
8443 	Oid			pfeqoperators[INDEX_MAX_KEYS];
8444 	Oid			ppeqoperators[INDEX_MAX_KEYS];
8445 	Oid			ffeqoperators[INDEX_MAX_KEYS];
8446 	int			i;
8447 	int			numfks,
8448 				numpks;
8449 	Oid			indexOid;
8450 	bool		old_check_ok;
8451 	ObjectAddress address;
8452 	ListCell   *old_pfeqop_item = list_head(fkconstraint->old_conpfeqop);
8453 
8454 	/*
8455 	 * Grab ShareRowExclusiveLock on the pk table, so that someone doesn't
8456 	 * delete rows out from under us.
8457 	 */
8458 	if (OidIsValid(fkconstraint->old_pktable_oid))
8459 		pkrel = table_open(fkconstraint->old_pktable_oid, ShareRowExclusiveLock);
8460 	else
8461 		pkrel = table_openrv(fkconstraint->pktable, ShareRowExclusiveLock);
8462 
8463 	/*
8464 	 * Validity checks (permission checks wait till we have the column
8465 	 * numbers)
8466 	 */
8467 	if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
8468 	{
8469 		if (!recurse)
8470 			ereport(ERROR,
8471 					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
8472 					 errmsg("cannot use ONLY for foreign key on partitioned table \"%s\" referencing relation \"%s\"",
8473 							RelationGetRelationName(rel),
8474 							RelationGetRelationName(pkrel))));
8475 		if (fkconstraint->skip_validation && !fkconstraint->initially_valid)
8476 			ereport(ERROR,
8477 					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
8478 					 errmsg("cannot add NOT VALID foreign key on partitioned table \"%s\" referencing relation \"%s\"",
8479 							RelationGetRelationName(rel),
8480 							RelationGetRelationName(pkrel)),
8481 					 errdetail("This feature is not yet supported on partitioned tables.")));
8482 	}
8483 
8484 	if (pkrel->rd_rel->relkind != RELKIND_RELATION &&
8485 		pkrel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
8486 		ereport(ERROR,
8487 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
8488 				 errmsg("referenced relation \"%s\" is not a table",
8489 						RelationGetRelationName(pkrel))));
8490 
8491 	if (!allowSystemTableMods && IsSystemRelation(pkrel))
8492 		ereport(ERROR,
8493 				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
8494 				 errmsg("permission denied: \"%s\" is a system catalog",
8495 						RelationGetRelationName(pkrel))));
8496 
8497 	/*
8498 	 * References from permanent or unlogged tables to temp tables, and from
8499 	 * permanent tables to unlogged tables, are disallowed because the
8500 	 * referenced data can vanish out from under us.  References from temp
8501 	 * tables to any other table type are also disallowed, because other
8502 	 * backends might need to run the RI triggers on the perm table, but they
8503 	 * can't reliably see tuples in the local buffers of other backends.
8504 	 */
8505 	switch (rel->rd_rel->relpersistence)
8506 	{
8507 		case RELPERSISTENCE_PERMANENT:
8508 			if (pkrel->rd_rel->relpersistence != RELPERSISTENCE_PERMANENT)
8509 				ereport(ERROR,
8510 						(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
8511 						 errmsg("constraints on permanent tables may reference only permanent tables")));
8512 			break;
8513 		case RELPERSISTENCE_UNLOGGED:
8514 			if (pkrel->rd_rel->relpersistence != RELPERSISTENCE_PERMANENT
8515 				&& pkrel->rd_rel->relpersistence != RELPERSISTENCE_UNLOGGED)
8516 				ereport(ERROR,
8517 						(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
8518 						 errmsg("constraints on unlogged tables may reference only permanent or unlogged tables")));
8519 			break;
8520 		case RELPERSISTENCE_TEMP:
8521 			if (pkrel->rd_rel->relpersistence != RELPERSISTENCE_TEMP)
8522 				ereport(ERROR,
8523 						(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
8524 						 errmsg("constraints on temporary tables may reference only temporary tables")));
8525 			if (!pkrel->rd_islocaltemp || !rel->rd_islocaltemp)
8526 				ereport(ERROR,
8527 						(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
8528 						 errmsg("constraints on temporary tables must involve temporary tables of this session")));
8529 			break;
8530 	}
8531 
8532 	/*
8533 	 * Look up the referencing attributes to make sure they exist, and record
8534 	 * their attnums and type OIDs.
8535 	 */
8536 	MemSet(pkattnum, 0, sizeof(pkattnum));
8537 	MemSet(fkattnum, 0, sizeof(fkattnum));
8538 	MemSet(pktypoid, 0, sizeof(pktypoid));
8539 	MemSet(fktypoid, 0, sizeof(fktypoid));
8540 	MemSet(opclasses, 0, sizeof(opclasses));
8541 	MemSet(pfeqoperators, 0, sizeof(pfeqoperators));
8542 	MemSet(ppeqoperators, 0, sizeof(ppeqoperators));
8543 	MemSet(ffeqoperators, 0, sizeof(ffeqoperators));
8544 
8545 	numfks = transformColumnNameList(RelationGetRelid(rel),
8546 									 fkconstraint->fk_attrs,
8547 									 fkattnum, fktypoid);
8548 
8549 	/*
8550 	 * If the attribute list for the referenced table was omitted, lookup the
8551 	 * definition of the primary key and use it.  Otherwise, validate the
8552 	 * supplied attribute list.  In either case, discover the index OID and
8553 	 * index opclasses, and the attnums and type OIDs of the attributes.
8554 	 */
8555 	if (fkconstraint->pk_attrs == NIL)
8556 	{
8557 		numpks = transformFkeyGetPrimaryKey(pkrel, &indexOid,
8558 											&fkconstraint->pk_attrs,
8559 											pkattnum, pktypoid,
8560 											opclasses);
8561 	}
8562 	else
8563 	{
8564 		numpks = transformColumnNameList(RelationGetRelid(pkrel),
8565 										 fkconstraint->pk_attrs,
8566 										 pkattnum, pktypoid);
8567 		/* Look for an index matching the column list */
8568 		indexOid = transformFkeyCheckAttrs(pkrel, numpks, pkattnum,
8569 										   opclasses);
8570 	}
8571 
8572 	/*
8573 	 * Now we can check permissions.
8574 	 */
8575 	checkFkeyPermissions(pkrel, pkattnum, numpks);
8576 
8577 	/*
8578 	 * Check some things for generated columns.
8579 	 */
8580 	for (i = 0; i < numfks; i++)
8581 	{
8582 		char		attgenerated = TupleDescAttr(RelationGetDescr(rel), fkattnum[i] - 1)->attgenerated;
8583 
8584 		if (attgenerated)
8585 		{
8586 			/*
8587 			 * Check restrictions on UPDATE/DELETE actions, per SQL standard
8588 			 */
8589 			if (fkconstraint->fk_upd_action == FKCONSTR_ACTION_SETNULL ||
8590 				fkconstraint->fk_upd_action == FKCONSTR_ACTION_SETDEFAULT ||
8591 				fkconstraint->fk_upd_action == FKCONSTR_ACTION_CASCADE)
8592 				ereport(ERROR,
8593 						(errcode(ERRCODE_SYNTAX_ERROR),
8594 						 errmsg("invalid %s action for foreign key constraint containing generated column",
8595 								"ON UPDATE")));
8596 			if (fkconstraint->fk_del_action == FKCONSTR_ACTION_SETNULL ||
8597 				fkconstraint->fk_del_action == FKCONSTR_ACTION_SETDEFAULT)
8598 				ereport(ERROR,
8599 						(errcode(ERRCODE_SYNTAX_ERROR),
8600 						 errmsg("invalid %s action for foreign key constraint containing generated column",
8601 								"ON DELETE")));
8602 		}
8603 	}
8604 
8605 	/*
8606 	 * Look up the equality operators to use in the constraint.
8607 	 *
8608 	 * Note that we have to be careful about the difference between the actual
8609 	 * PK column type and the opclass' declared input type, which might be
8610 	 * only binary-compatible with it.  The declared opcintype is the right
8611 	 * thing to probe pg_amop with.
8612 	 */
8613 	if (numfks != numpks)
8614 		ereport(ERROR,
8615 				(errcode(ERRCODE_INVALID_FOREIGN_KEY),
8616 				 errmsg("number of referencing and referenced columns for foreign key disagree")));
8617 
8618 	/*
8619 	 * On the strength of a previous constraint, we might avoid scanning
8620 	 * tables to validate this one.  See below.
8621 	 */
8622 	old_check_ok = (fkconstraint->old_conpfeqop != NIL);
8623 	Assert(!old_check_ok || numfks == list_length(fkconstraint->old_conpfeqop));
8624 
8625 	for (i = 0; i < numpks; i++)
8626 	{
8627 		Oid			pktype = pktypoid[i];
8628 		Oid			fktype = fktypoid[i];
8629 		Oid			fktyped;
8630 		HeapTuple	cla_ht;
8631 		Form_pg_opclass cla_tup;
8632 		Oid			amid;
8633 		Oid			opfamily;
8634 		Oid			opcintype;
8635 		Oid			pfeqop;
8636 		Oid			ppeqop;
8637 		Oid			ffeqop;
8638 		int16		eqstrategy;
8639 		Oid			pfeqop_right;
8640 
8641 		/* We need several fields out of the pg_opclass entry */
8642 		cla_ht = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclasses[i]));
8643 		if (!HeapTupleIsValid(cla_ht))
8644 			elog(ERROR, "cache lookup failed for opclass %u", opclasses[i]);
8645 		cla_tup = (Form_pg_opclass) GETSTRUCT(cla_ht);
8646 		amid = cla_tup->opcmethod;
8647 		opfamily = cla_tup->opcfamily;
8648 		opcintype = cla_tup->opcintype;
8649 		ReleaseSysCache(cla_ht);
8650 
8651 		/*
8652 		 * Check it's a btree; currently this can never fail since no other
8653 		 * index AMs support unique indexes.  If we ever did have other types
8654 		 * of unique indexes, we'd need a way to determine which operator
8655 		 * strategy number is equality.  (Is it reasonable to insist that
8656 		 * every such index AM use btree's number for equality?)
8657 		 */
8658 		if (amid != BTREE_AM_OID)
8659 			elog(ERROR, "only b-tree indexes are supported for foreign keys");
8660 		eqstrategy = BTEqualStrategyNumber;
8661 
8662 		/*
8663 		 * There had better be a primary equality operator for the index.
8664 		 * We'll use it for PK = PK comparisons.
8665 		 */
8666 		ppeqop = get_opfamily_member(opfamily, opcintype, opcintype,
8667 									 eqstrategy);
8668 
8669 		if (!OidIsValid(ppeqop))
8670 			elog(ERROR, "missing operator %d(%u,%u) in opfamily %u",
8671 				 eqstrategy, opcintype, opcintype, opfamily);
8672 
8673 		/*
8674 		 * Are there equality operators that take exactly the FK type? Assume
8675 		 * we should look through any domain here.
8676 		 */
8677 		fktyped = getBaseType(fktype);
8678 
8679 		pfeqop = get_opfamily_member(opfamily, opcintype, fktyped,
8680 									 eqstrategy);
8681 		if (OidIsValid(pfeqop))
8682 		{
8683 			pfeqop_right = fktyped;
8684 			ffeqop = get_opfamily_member(opfamily, fktyped, fktyped,
8685 										 eqstrategy);
8686 		}
8687 		else
8688 		{
8689 			/* keep compiler quiet */
8690 			pfeqop_right = InvalidOid;
8691 			ffeqop = InvalidOid;
8692 		}
8693 
8694 		if (!(OidIsValid(pfeqop) && OidIsValid(ffeqop)))
8695 		{
8696 			/*
8697 			 * Otherwise, look for an implicit cast from the FK type to the
8698 			 * opcintype, and if found, use the primary equality operator.
8699 			 * This is a bit tricky because opcintype might be a polymorphic
8700 			 * type such as ANYARRAY or ANYENUM; so what we have to test is
8701 			 * whether the two actual column types can be concurrently cast to
8702 			 * that type.  (Otherwise, we'd fail to reject combinations such
8703 			 * as int[] and point[].)
8704 			 */
8705 			Oid			input_typeids[2];
8706 			Oid			target_typeids[2];
8707 
8708 			input_typeids[0] = pktype;
8709 			input_typeids[1] = fktype;
8710 			target_typeids[0] = opcintype;
8711 			target_typeids[1] = opcintype;
8712 			if (can_coerce_type(2, input_typeids, target_typeids,
8713 								COERCION_IMPLICIT))
8714 			{
8715 				pfeqop = ffeqop = ppeqop;
8716 				pfeqop_right = opcintype;
8717 			}
8718 		}
8719 
8720 		if (!(OidIsValid(pfeqop) && OidIsValid(ffeqop)))
8721 			ereport(ERROR,
8722 					(errcode(ERRCODE_DATATYPE_MISMATCH),
8723 					 errmsg("foreign key constraint \"%s\" cannot be implemented",
8724 							fkconstraint->conname),
8725 					 errdetail("Key columns \"%s\" and \"%s\" "
8726 							   "are of incompatible types: %s and %s.",
8727 							   strVal(list_nth(fkconstraint->fk_attrs, i)),
8728 							   strVal(list_nth(fkconstraint->pk_attrs, i)),
8729 							   format_type_be(fktype),
8730 							   format_type_be(pktype))));
8731 
8732 		if (old_check_ok)
8733 		{
8734 			/*
8735 			 * When a pfeqop changes, revalidate the constraint.  We could
8736 			 * permit intra-opfamily changes, but that adds subtle complexity
8737 			 * without any concrete benefit for core types.  We need not
8738 			 * assess ppeqop or ffeqop, which RI_Initial_Check() does not use.
8739 			 */
8740 			old_check_ok = (pfeqop == lfirst_oid(old_pfeqop_item));
8741 			old_pfeqop_item = lnext(fkconstraint->old_conpfeqop,
8742 									old_pfeqop_item);
8743 		}
8744 		if (old_check_ok)
8745 		{
8746 			Oid			old_fktype;
8747 			Oid			new_fktype;
8748 			CoercionPathType old_pathtype;
8749 			CoercionPathType new_pathtype;
8750 			Oid			old_castfunc;
8751 			Oid			new_castfunc;
8752 			Form_pg_attribute attr = TupleDescAttr(tab->oldDesc,
8753 												   fkattnum[i] - 1);
8754 
8755 			/*
8756 			 * Identify coercion pathways from each of the old and new FK-side
8757 			 * column types to the right (foreign) operand type of the pfeqop.
8758 			 * We may assume that pg_constraint.conkey is not changing.
8759 			 */
8760 			old_fktype = attr->atttypid;
8761 			new_fktype = fktype;
8762 			old_pathtype = findFkeyCast(pfeqop_right, old_fktype,
8763 										&old_castfunc);
8764 			new_pathtype = findFkeyCast(pfeqop_right, new_fktype,
8765 										&new_castfunc);
8766 
8767 			/*
8768 			 * Upon a change to the cast from the FK column to its pfeqop
8769 			 * operand, revalidate the constraint.  For this evaluation, a
8770 			 * binary coercion cast is equivalent to no cast at all.  While
8771 			 * type implementors should design implicit casts with an eye
8772 			 * toward consistency of operations like equality, we cannot
8773 			 * assume here that they have done so.
8774 			 *
8775 			 * A function with a polymorphic argument could change behavior
8776 			 * arbitrarily in response to get_fn_expr_argtype().  Therefore,
8777 			 * when the cast destination is polymorphic, we only avoid
8778 			 * revalidation if the input type has not changed at all.  Given
8779 			 * just the core data types and operator classes, this requirement
8780 			 * prevents no would-be optimizations.
8781 			 *
8782 			 * If the cast converts from a base type to a domain thereon, then
8783 			 * that domain type must be the opcintype of the unique index.
8784 			 * Necessarily, the primary key column must then be of the domain
8785 			 * type.  Since the constraint was previously valid, all values on
8786 			 * the foreign side necessarily exist on the primary side and in
8787 			 * turn conform to the domain.  Consequently, we need not treat
8788 			 * domains specially here.
8789 			 *
8790 			 * Since we require that all collations share the same notion of
8791 			 * equality (which they do, because texteq reduces to bitwise
8792 			 * equality), we don't compare collation here.
8793 			 *
8794 			 * We need not directly consider the PK type.  It's necessarily
8795 			 * binary coercible to the opcintype of the unique index column,
8796 			 * and ri_triggers.c will only deal with PK datums in terms of
8797 			 * that opcintype.  Changing the opcintype also changes pfeqop.
8798 			 */
8799 			old_check_ok = (new_pathtype == old_pathtype &&
8800 							new_castfunc == old_castfunc &&
8801 							(!IsPolymorphicType(pfeqop_right) ||
8802 							 new_fktype == old_fktype));
8803 		}
8804 
8805 		pfeqoperators[i] = pfeqop;
8806 		ppeqoperators[i] = ppeqop;
8807 		ffeqoperators[i] = ffeqop;
8808 	}
8809 
8810 	/*
8811 	 * Create all the constraint and trigger objects, recursing to partitions
8812 	 * as necessary.  First handle the referenced side.
8813 	 */
8814 	address = addFkRecurseReferenced(wqueue, fkconstraint, rel, pkrel,
8815 									 indexOid,
8816 									 InvalidOid,	/* no parent constraint */
8817 									 numfks,
8818 									 pkattnum,
8819 									 fkattnum,
8820 									 pfeqoperators,
8821 									 ppeqoperators,
8822 									 ffeqoperators,
8823 									 old_check_ok);
8824 
8825 	/* Now handle the referencing side. */
8826 	addFkRecurseReferencing(wqueue, fkconstraint, rel, pkrel,
8827 							indexOid,
8828 							address.objectId,
8829 							numfks,
8830 							pkattnum,
8831 							fkattnum,
8832 							pfeqoperators,
8833 							ppeqoperators,
8834 							ffeqoperators,
8835 							old_check_ok,
8836 							lockmode);
8837 
8838 	/*
8839 	 * Done.  Close pk table, but keep lock until we've committed.
8840 	 */
8841 	table_close(pkrel, NoLock);
8842 
8843 	return address;
8844 }
8845 
8846 /*
8847  * addFkRecurseReferenced
8848  *		subroutine for ATAddForeignKeyConstraint; recurses on the referenced
8849  *		side of the constraint
8850  *
8851  * Create pg_constraint rows for the referenced side of the constraint,
8852  * referencing the parent of the referencing side; also create action triggers
8853  * on leaf partitions.  If the table is partitioned, recurse to handle each
8854  * partition.
8855  *
8856  * wqueue is the ALTER TABLE work queue; can be NULL when not running as part
8857  * of an ALTER TABLE sequence.
8858  * fkconstraint is the constraint being added.
8859  * rel is the root referencing relation.
8860  * pkrel is the referenced relation; might be a partition, if recursing.
8861  * indexOid is the OID of the index (on pkrel) implementing this constraint.
8862  * parentConstr is the OID of a parent constraint; InvalidOid if this is a
8863  * top-level constraint.
8864  * numfks is the number of columns in the foreign key
8865  * pkattnum is the attnum array of referenced attributes.
8866  * fkattnum is the attnum array of referencing attributes.
8867  * pf/pp/ffeqoperators are OID array of operators between columns.
8868  * old_check_ok signals that this constraint replaces an existing one that
8869  * was already validated (thus this one doesn't need validation).
8870  */
8871 static ObjectAddress
addFkRecurseReferenced(List ** wqueue,Constraint * fkconstraint,Relation rel,Relation pkrel,Oid indexOid,Oid parentConstr,int numfks,int16 * pkattnum,int16 * fkattnum,Oid * pfeqoperators,Oid * ppeqoperators,Oid * ffeqoperators,bool old_check_ok)8872 addFkRecurseReferenced(List **wqueue, Constraint *fkconstraint, Relation rel,
8873 					   Relation pkrel, Oid indexOid, Oid parentConstr,
8874 					   int numfks,
8875 					   int16 *pkattnum, int16 *fkattnum, Oid *pfeqoperators,
8876 					   Oid *ppeqoperators, Oid *ffeqoperators, bool old_check_ok)
8877 {
8878 	ObjectAddress address;
8879 	Oid			constrOid;
8880 	char	   *conname;
8881 	bool		conislocal;
8882 	int			coninhcount;
8883 	bool		connoinherit;
8884 
8885 	/*
8886 	 * Verify relkind for each referenced partition.  At the top level, this
8887 	 * is redundant with a previous check, but we need it when recursing.
8888 	 */
8889 	if (pkrel->rd_rel->relkind != RELKIND_RELATION &&
8890 		pkrel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
8891 		ereport(ERROR,
8892 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
8893 				 errmsg("referenced relation \"%s\" is not a table",
8894 						RelationGetRelationName(pkrel))));
8895 
8896 	/*
8897 	 * Caller supplies us with a constraint name; however, it may be used in
8898 	 * this partition, so come up with a different one in that case.
8899 	 */
8900 	if (ConstraintNameIsUsed(CONSTRAINT_RELATION,
8901 							 RelationGetRelid(rel),
8902 							 fkconstraint->conname))
8903 		conname = ChooseConstraintName(RelationGetRelationName(rel),
8904 									   ChooseForeignKeyConstraintNameAddition(fkconstraint->fk_attrs),
8905 									   "fkey",
8906 									   RelationGetNamespace(rel), NIL);
8907 	else
8908 		conname = fkconstraint->conname;
8909 
8910 	if (OidIsValid(parentConstr))
8911 	{
8912 		conislocal = false;
8913 		coninhcount = 1;
8914 		connoinherit = false;
8915 	}
8916 	else
8917 	{
8918 		conislocal = true;
8919 		coninhcount = 0;
8920 
8921 		/*
8922 		 * always inherit for partitioned tables, never for legacy inheritance
8923 		 */
8924 		connoinherit = rel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE;
8925 	}
8926 
8927 	/*
8928 	 * Record the FK constraint in pg_constraint.
8929 	 */
8930 	constrOid = CreateConstraintEntry(conname,
8931 									  RelationGetNamespace(rel),
8932 									  CONSTRAINT_FOREIGN,
8933 									  fkconstraint->deferrable,
8934 									  fkconstraint->initdeferred,
8935 									  fkconstraint->initially_valid,
8936 									  parentConstr,
8937 									  RelationGetRelid(rel),
8938 									  fkattnum,
8939 									  numfks,
8940 									  numfks,
8941 									  InvalidOid,	/* not a domain constraint */
8942 									  indexOid,
8943 									  RelationGetRelid(pkrel),
8944 									  pkattnum,
8945 									  pfeqoperators,
8946 									  ppeqoperators,
8947 									  ffeqoperators,
8948 									  numfks,
8949 									  fkconstraint->fk_upd_action,
8950 									  fkconstraint->fk_del_action,
8951 									  fkconstraint->fk_matchtype,
8952 									  NULL, /* no exclusion constraint */
8953 									  NULL, /* no check constraint */
8954 									  NULL,
8955 									  conislocal,	/* islocal */
8956 									  coninhcount,	/* inhcount */
8957 									  connoinherit, /* conNoInherit */
8958 									  false);	/* is_internal */
8959 
8960 	ObjectAddressSet(address, ConstraintRelationId, constrOid);
8961 
8962 	/*
8963 	 * Mark the child constraint as part of the parent constraint; it must not
8964 	 * be dropped on its own.  (This constraint is deleted when the partition
8965 	 * is detached, but a special check needs to occur that the partition
8966 	 * contains no referenced values.)
8967 	 */
8968 	if (OidIsValid(parentConstr))
8969 	{
8970 		ObjectAddress referenced;
8971 
8972 		ObjectAddressSet(referenced, ConstraintRelationId, parentConstr);
8973 		recordDependencyOn(&address, &referenced, DEPENDENCY_INTERNAL);
8974 	}
8975 
8976 	/* make new constraint visible, in case we add more */
8977 	CommandCounterIncrement();
8978 
8979 	/*
8980 	 * If the referenced table is a plain relation, create the action triggers
8981 	 * that enforce the constraint.
8982 	 */
8983 	if (pkrel->rd_rel->relkind == RELKIND_RELATION)
8984 	{
8985 		createForeignKeyActionTriggers(rel, RelationGetRelid(pkrel),
8986 									   fkconstraint,
8987 									   constrOid, indexOid);
8988 	}
8989 
8990 	/*
8991 	 * If the referenced table is partitioned, recurse on ourselves to handle
8992 	 * each partition.  We need one pg_constraint row created for each
8993 	 * partition in addition to the pg_constraint row for the parent table.
8994 	 */
8995 	if (pkrel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
8996 	{
8997 		PartitionDesc pd = RelationGetPartitionDesc(pkrel);
8998 
8999 		for (int i = 0; i < pd->nparts; i++)
9000 		{
9001 			Relation	partRel;
9002 			AttrMap    *map;
9003 			AttrNumber *mapped_pkattnum;
9004 			Oid			partIndexId;
9005 
9006 			partRel = table_open(pd->oids[i], ShareRowExclusiveLock);
9007 
9008 			/*
9009 			 * Map the attribute numbers in the referenced side of the FK
9010 			 * definition to match the partition's column layout.
9011 			 */
9012 			map = build_attrmap_by_name_if_req(RelationGetDescr(partRel),
9013 											   RelationGetDescr(pkrel));
9014 			if (map)
9015 			{
9016 				mapped_pkattnum = palloc(sizeof(AttrNumber) * numfks);
9017 				for (int j = 0; j < numfks; j++)
9018 					mapped_pkattnum[j] = map->attnums[pkattnum[j] - 1];
9019 			}
9020 			else
9021 				mapped_pkattnum = pkattnum;
9022 
9023 			/* do the deed */
9024 			partIndexId = index_get_partition(partRel, indexOid);
9025 			if (!OidIsValid(partIndexId))
9026 				elog(ERROR, "index for %u not found in partition %s",
9027 					 indexOid, RelationGetRelationName(partRel));
9028 			addFkRecurseReferenced(wqueue, fkconstraint, rel, partRel,
9029 								   partIndexId, constrOid, numfks,
9030 								   mapped_pkattnum, fkattnum,
9031 								   pfeqoperators, ppeqoperators, ffeqoperators,
9032 								   old_check_ok);
9033 
9034 			/* Done -- clean up (but keep the lock) */
9035 			table_close(partRel, NoLock);
9036 			if (map)
9037 			{
9038 				pfree(mapped_pkattnum);
9039 				free_attrmap(map);
9040 			}
9041 		}
9042 	}
9043 
9044 	return address;
9045 }
9046 
9047 /*
9048  * addFkRecurseReferencing
9049  *		subroutine for ATAddForeignKeyConstraint and CloneFkReferencing
9050  *
9051  * If the referencing relation is a plain relation, create the necessary check
9052  * triggers that implement the constraint, and set up for Phase 3 constraint
9053  * verification.  If the referencing relation is a partitioned table, then
9054  * we create a pg_constraint row for it and recurse on this routine for each
9055  * partition.
9056  *
9057  * We assume that the referenced relation is locked against concurrent
9058  * deletions.  If it's a partitioned relation, every partition must be so
9059  * locked.
9060  *
9061  * wqueue is the ALTER TABLE work queue; can be NULL when not running as part
9062  * of an ALTER TABLE sequence.
9063  * fkconstraint is the constraint being added.
9064  * rel is the referencing relation; might be a partition, if recursing.
9065  * pkrel is the root referenced relation.
9066  * indexOid is the OID of the index (on pkrel) implementing this constraint.
9067  * parentConstr is the OID of the parent constraint (there is always one).
9068  * numfks is the number of columns in the foreign key
9069  * pkattnum is the attnum array of referenced attributes.
9070  * fkattnum is the attnum array of referencing attributes.
9071  * pf/pp/ffeqoperators are OID array of operators between columns.
9072  * old_check_ok signals that this constraint replaces an existing one that
9073  *		was already validated (thus this one doesn't need validation).
9074  * lockmode is the lockmode to acquire on partitions when recursing.
9075  */
9076 static void
addFkRecurseReferencing(List ** wqueue,Constraint * fkconstraint,Relation rel,Relation pkrel,Oid indexOid,Oid parentConstr,int numfks,int16 * pkattnum,int16 * fkattnum,Oid * pfeqoperators,Oid * ppeqoperators,Oid * ffeqoperators,bool old_check_ok,LOCKMODE lockmode)9077 addFkRecurseReferencing(List **wqueue, Constraint *fkconstraint, Relation rel,
9078 						Relation pkrel, Oid indexOid, Oid parentConstr,
9079 						int numfks, int16 *pkattnum, int16 *fkattnum,
9080 						Oid *pfeqoperators, Oid *ppeqoperators, Oid *ffeqoperators,
9081 						bool old_check_ok, LOCKMODE lockmode)
9082 {
9083 	AssertArg(OidIsValid(parentConstr));
9084 
9085 	if (rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
9086 		ereport(ERROR,
9087 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
9088 				 errmsg("foreign key constraints are not supported on foreign tables")));
9089 
9090 	/*
9091 	 * If the referencing relation is a plain table, add the check triggers to
9092 	 * it and, if necessary, schedule it to be checked in Phase 3.
9093 	 *
9094 	 * If the relation is partitioned, drill down to do it to its partitions.
9095 	 */
9096 	if (rel->rd_rel->relkind == RELKIND_RELATION)
9097 	{
9098 		createForeignKeyCheckTriggers(RelationGetRelid(rel),
9099 									  RelationGetRelid(pkrel),
9100 									  fkconstraint,
9101 									  parentConstr,
9102 									  indexOid);
9103 
9104 		/*
9105 		 * Tell Phase 3 to check that the constraint is satisfied by existing
9106 		 * rows. We can skip this during table creation, when requested
9107 		 * explicitly by specifying NOT VALID in an ADD FOREIGN KEY command,
9108 		 * and when we're recreating a constraint following a SET DATA TYPE
9109 		 * operation that did not impugn its validity.
9110 		 */
9111 		if (wqueue && !old_check_ok && !fkconstraint->skip_validation)
9112 		{
9113 			NewConstraint *newcon;
9114 			AlteredTableInfo *tab;
9115 
9116 			tab = ATGetQueueEntry(wqueue, rel);
9117 
9118 			newcon = (NewConstraint *) palloc0(sizeof(NewConstraint));
9119 			newcon->name = get_constraint_name(parentConstr);
9120 			newcon->contype = CONSTR_FOREIGN;
9121 			newcon->refrelid = RelationGetRelid(pkrel);
9122 			newcon->refindid = indexOid;
9123 			newcon->conid = parentConstr;
9124 			newcon->qual = (Node *) fkconstraint;
9125 
9126 			tab->constraints = lappend(tab->constraints, newcon);
9127 		}
9128 	}
9129 	else if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
9130 	{
9131 		PartitionDesc pd = RelationGetPartitionDesc(rel);
9132 
9133 		/*
9134 		 * Recurse to take appropriate action on each partition; either we
9135 		 * find an existing constraint to reparent to ours, or we create a new
9136 		 * one.
9137 		 */
9138 		for (int i = 0; i < pd->nparts; i++)
9139 		{
9140 			Oid			partitionId = pd->oids[i];
9141 			Relation	partition = table_open(partitionId, lockmode);
9142 			List	   *partFKs;
9143 			AttrMap    *attmap;
9144 			AttrNumber	mapped_fkattnum[INDEX_MAX_KEYS];
9145 			bool		attached;
9146 			char	   *conname;
9147 			Oid			constrOid;
9148 			ObjectAddress address,
9149 						referenced;
9150 			ListCell   *cell;
9151 
9152 			CheckTableNotInUse(partition, "ALTER TABLE");
9153 
9154 			attmap = build_attrmap_by_name(RelationGetDescr(partition),
9155 										   RelationGetDescr(rel));
9156 			for (int j = 0; j < numfks; j++)
9157 				mapped_fkattnum[j] = attmap->attnums[fkattnum[j] - 1];
9158 
9159 			/* Check whether an existing constraint can be repurposed */
9160 			partFKs = copyObject(RelationGetFKeyList(partition));
9161 			attached = false;
9162 			foreach(cell, partFKs)
9163 			{
9164 				ForeignKeyCacheInfo *fk;
9165 
9166 				fk = lfirst_node(ForeignKeyCacheInfo, cell);
9167 				if (tryAttachPartitionForeignKey(fk,
9168 												 partitionId,
9169 												 parentConstr,
9170 												 numfks,
9171 												 mapped_fkattnum,
9172 												 pkattnum,
9173 												 pfeqoperators))
9174 				{
9175 					attached = true;
9176 					break;
9177 				}
9178 			}
9179 			if (attached)
9180 			{
9181 				table_close(partition, NoLock);
9182 				continue;
9183 			}
9184 
9185 			/*
9186 			 * No luck finding a good constraint to reuse; create our own.
9187 			 */
9188 			if (ConstraintNameIsUsed(CONSTRAINT_RELATION,
9189 									 RelationGetRelid(partition),
9190 									 fkconstraint->conname))
9191 				conname = ChooseConstraintName(RelationGetRelationName(partition),
9192 											   ChooseForeignKeyConstraintNameAddition(fkconstraint->fk_attrs),
9193 											   "fkey",
9194 											   RelationGetNamespace(partition), NIL);
9195 			else
9196 				conname = fkconstraint->conname;
9197 			constrOid =
9198 				CreateConstraintEntry(conname,
9199 									  RelationGetNamespace(partition),
9200 									  CONSTRAINT_FOREIGN,
9201 									  fkconstraint->deferrable,
9202 									  fkconstraint->initdeferred,
9203 									  fkconstraint->initially_valid,
9204 									  parentConstr,
9205 									  partitionId,
9206 									  mapped_fkattnum,
9207 									  numfks,
9208 									  numfks,
9209 									  InvalidOid,
9210 									  indexOid,
9211 									  RelationGetRelid(pkrel),
9212 									  pkattnum,
9213 									  pfeqoperators,
9214 									  ppeqoperators,
9215 									  ffeqoperators,
9216 									  numfks,
9217 									  fkconstraint->fk_upd_action,
9218 									  fkconstraint->fk_del_action,
9219 									  fkconstraint->fk_matchtype,
9220 									  NULL,
9221 									  NULL,
9222 									  NULL,
9223 									  false,
9224 									  1,
9225 									  false,
9226 									  false);
9227 
9228 			/*
9229 			 * Give this constraint partition-type dependencies on the parent
9230 			 * constraint as well as the table.
9231 			 */
9232 			ObjectAddressSet(address, ConstraintRelationId, constrOid);
9233 			ObjectAddressSet(referenced, ConstraintRelationId, parentConstr);
9234 			recordDependencyOn(&address, &referenced, DEPENDENCY_PARTITION_PRI);
9235 			ObjectAddressSet(referenced, RelationRelationId, partitionId);
9236 			recordDependencyOn(&address, &referenced, DEPENDENCY_PARTITION_SEC);
9237 
9238 			/* Make all this visible before recursing */
9239 			CommandCounterIncrement();
9240 
9241 			/* call ourselves to finalize the creation and we're done */
9242 			addFkRecurseReferencing(wqueue, fkconstraint, partition, pkrel,
9243 									indexOid,
9244 									constrOid,
9245 									numfks,
9246 									pkattnum,
9247 									mapped_fkattnum,
9248 									pfeqoperators,
9249 									ppeqoperators,
9250 									ffeqoperators,
9251 									old_check_ok,
9252 									lockmode);
9253 
9254 			table_close(partition, NoLock);
9255 		}
9256 	}
9257 }
9258 
9259 /*
9260  * CloneForeignKeyConstraints
9261  *		Clone foreign keys from a partitioned table to a newly acquired
9262  *		partition.
9263  *
9264  * partitionRel is a partition of parentRel, so we can be certain that it has
9265  * the same columns with the same datatypes.  The columns may be in different
9266  * order, though.
9267  *
9268  * wqueue must be passed to set up phase 3 constraint checking, unless the
9269  * referencing-side partition is known to be empty (such as in CREATE TABLE /
9270  * PARTITION OF).
9271  */
9272 static void
CloneForeignKeyConstraints(List ** wqueue,Relation parentRel,Relation partitionRel)9273 CloneForeignKeyConstraints(List **wqueue, Relation parentRel,
9274 						   Relation partitionRel)
9275 {
9276 	/* This only works for declarative partitioning */
9277 	Assert(parentRel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
9278 
9279 	/*
9280 	 * Clone constraints for which the parent is on the referenced side.
9281 	 */
9282 	CloneFkReferenced(parentRel, partitionRel);
9283 
9284 	/*
9285 	 * Now clone constraints where the parent is on the referencing side.
9286 	 */
9287 	CloneFkReferencing(wqueue, parentRel, partitionRel);
9288 }
9289 
9290 /*
9291  * CloneFkReferenced
9292  *		Subroutine for CloneForeignKeyConstraints
9293  *
9294  * Find all the FKs that have the parent relation on the referenced side;
9295  * clone those constraints to the given partition.  This is to be called
9296  * when the partition is being created or attached.
9297  *
9298  * This recurses to partitions, if the relation being attached is partitioned.
9299  * Recursion is done by calling addFkRecurseReferenced.
9300  */
9301 static void
CloneFkReferenced(Relation parentRel,Relation partitionRel)9302 CloneFkReferenced(Relation parentRel, Relation partitionRel)
9303 {
9304 	Relation	pg_constraint;
9305 	AttrMap    *attmap;
9306 	ListCell   *cell;
9307 	SysScanDesc scan;
9308 	ScanKeyData key[2];
9309 	HeapTuple	tuple;
9310 	List	   *clone = NIL;
9311 
9312 	/*
9313 	 * Search for any constraints where this partition's parent is in the
9314 	 * referenced side.  However, we must not clone any constraint whose
9315 	 * parent constraint is also going to be cloned, to avoid duplicates.  So
9316 	 * do it in two steps: first construct the list of constraints to clone,
9317 	 * then go over that list cloning those whose parents are not in the list.
9318 	 * (We must not rely on the parent being seen first, since the catalog
9319 	 * scan could return children first.)
9320 	 */
9321 	pg_constraint = table_open(ConstraintRelationId, RowShareLock);
9322 	ScanKeyInit(&key[0],
9323 				Anum_pg_constraint_confrelid, BTEqualStrategyNumber,
9324 				F_OIDEQ, ObjectIdGetDatum(RelationGetRelid(parentRel)));
9325 	ScanKeyInit(&key[1],
9326 				Anum_pg_constraint_contype, BTEqualStrategyNumber,
9327 				F_CHAREQ, CharGetDatum(CONSTRAINT_FOREIGN));
9328 	/* This is a seqscan, as we don't have a usable index ... */
9329 	scan = systable_beginscan(pg_constraint, InvalidOid, true,
9330 							  NULL, 2, key);
9331 	while ((tuple = systable_getnext(scan)) != NULL)
9332 	{
9333 		Form_pg_constraint constrForm = (Form_pg_constraint) GETSTRUCT(tuple);
9334 
9335 		clone = lappend_oid(clone, constrForm->oid);
9336 	}
9337 	systable_endscan(scan);
9338 	table_close(pg_constraint, RowShareLock);
9339 
9340 	attmap = build_attrmap_by_name(RelationGetDescr(partitionRel),
9341 								   RelationGetDescr(parentRel));
9342 	foreach(cell, clone)
9343 	{
9344 		Oid			constrOid = lfirst_oid(cell);
9345 		Form_pg_constraint constrForm;
9346 		Relation	fkRel;
9347 		Oid			indexOid;
9348 		Oid			partIndexId;
9349 		int			numfks;
9350 		AttrNumber	conkey[INDEX_MAX_KEYS];
9351 		AttrNumber	mapped_confkey[INDEX_MAX_KEYS];
9352 		AttrNumber	confkey[INDEX_MAX_KEYS];
9353 		Oid			conpfeqop[INDEX_MAX_KEYS];
9354 		Oid			conppeqop[INDEX_MAX_KEYS];
9355 		Oid			conffeqop[INDEX_MAX_KEYS];
9356 		Constraint *fkconstraint;
9357 
9358 		tuple = SearchSysCache1(CONSTROID, constrOid);
9359 		if (!HeapTupleIsValid(tuple))
9360 			elog(ERROR, "cache lookup failed for constraint %u", constrOid);
9361 		constrForm = (Form_pg_constraint) GETSTRUCT(tuple);
9362 
9363 		/*
9364 		 * As explained above: don't try to clone a constraint for which we're
9365 		 * going to clone the parent.
9366 		 */
9367 		if (list_member_oid(clone, constrForm->conparentid))
9368 		{
9369 			ReleaseSysCache(tuple);
9370 			continue;
9371 		}
9372 
9373 		/*
9374 		 * Because we're only expanding the key space at the referenced side,
9375 		 * we don't need to prevent any operation in the referencing table, so
9376 		 * AccessShareLock suffices (assumes that dropping the constraint
9377 		 * acquires AEL).
9378 		 */
9379 		fkRel = table_open(constrForm->conrelid, AccessShareLock);
9380 
9381 		indexOid = constrForm->conindid;
9382 		DeconstructFkConstraintRow(tuple,
9383 								   &numfks,
9384 								   conkey,
9385 								   confkey,
9386 								   conpfeqop,
9387 								   conppeqop,
9388 								   conffeqop);
9389 
9390 		for (int i = 0; i < numfks; i++)
9391 			mapped_confkey[i] = attmap->attnums[confkey[i] - 1];
9392 
9393 		fkconstraint = makeNode(Constraint);
9394 		/* for now this is all we need */
9395 		fkconstraint->conname = NameStr(constrForm->conname);
9396 		fkconstraint->fk_upd_action = constrForm->confupdtype;
9397 		fkconstraint->fk_del_action = constrForm->confdeltype;
9398 		fkconstraint->deferrable = constrForm->condeferrable;
9399 		fkconstraint->initdeferred = constrForm->condeferred;
9400 		fkconstraint->initially_valid = true;
9401 		fkconstraint->fk_matchtype = constrForm->confmatchtype;
9402 
9403 		/* set up colnames that are used to generate the constraint name */
9404 		for (int i = 0; i < numfks; i++)
9405 		{
9406 			Form_pg_attribute att;
9407 
9408 			att = TupleDescAttr(RelationGetDescr(fkRel),
9409 								conkey[i] - 1);
9410 			fkconstraint->fk_attrs = lappend(fkconstraint->fk_attrs,
9411 											 makeString(NameStr(att->attname)));
9412 		}
9413 
9414 		/*
9415 		 * Add the new foreign key constraint pointing to the new partition.
9416 		 * Because this new partition appears in the referenced side of the
9417 		 * constraint, we don't need to set up for Phase 3 check.
9418 		 */
9419 		partIndexId = index_get_partition(partitionRel, indexOid);
9420 		if (!OidIsValid(partIndexId))
9421 			elog(ERROR, "index for %u not found in partition %s",
9422 				 indexOid, RelationGetRelationName(partitionRel));
9423 		addFkRecurseReferenced(NULL,
9424 							   fkconstraint,
9425 							   fkRel,
9426 							   partitionRel,
9427 							   partIndexId,
9428 							   constrOid,
9429 							   numfks,
9430 							   mapped_confkey,
9431 							   conkey,
9432 							   conpfeqop,
9433 							   conppeqop,
9434 							   conffeqop,
9435 							   true);
9436 
9437 		table_close(fkRel, NoLock);
9438 		ReleaseSysCache(tuple);
9439 	}
9440 }
9441 
9442 /*
9443  * CloneFkReferencing
9444  *		Subroutine for CloneForeignKeyConstraints
9445  *
9446  * For each FK constraint of the parent relation in the given list, find an
9447  * equivalent constraint in its partition relation that can be reparented;
9448  * if one cannot be found, create a new constraint in the partition as its
9449  * child.
9450  *
9451  * If wqueue is given, it is used to set up phase-3 verification for each
9452  * cloned constraint; if omitted, we assume that such verification is not
9453  * needed (example: the partition is being created anew).
9454  */
9455 static void
CloneFkReferencing(List ** wqueue,Relation parentRel,Relation partRel)9456 CloneFkReferencing(List **wqueue, Relation parentRel, Relation partRel)
9457 {
9458 	AttrMap    *attmap;
9459 	List	   *partFKs;
9460 	List	   *clone = NIL;
9461 	ListCell   *cell;
9462 
9463 	/* obtain a list of constraints that we need to clone */
9464 	foreach(cell, RelationGetFKeyList(parentRel))
9465 	{
9466 		ForeignKeyCacheInfo *fk = lfirst(cell);
9467 
9468 		clone = lappend_oid(clone, fk->conoid);
9469 	}
9470 
9471 	/*
9472 	 * Silently do nothing if there's nothing to do.  In particular, this
9473 	 * avoids throwing a spurious error for foreign tables.
9474 	 */
9475 	if (clone == NIL)
9476 		return;
9477 
9478 	if (partRel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
9479 		ereport(ERROR,
9480 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
9481 				 errmsg("foreign key constraints are not supported on foreign tables")));
9482 
9483 	/*
9484 	 * The constraint key may differ, if the columns in the partition are
9485 	 * different.  This map is used to convert them.
9486 	 */
9487 	attmap = build_attrmap_by_name(RelationGetDescr(partRel),
9488 								   RelationGetDescr(parentRel));
9489 
9490 	partFKs = copyObject(RelationGetFKeyList(partRel));
9491 
9492 	foreach(cell, clone)
9493 	{
9494 		Oid			parentConstrOid = lfirst_oid(cell);
9495 		Form_pg_constraint constrForm;
9496 		Relation	pkrel;
9497 		HeapTuple	tuple;
9498 		int			numfks;
9499 		AttrNumber	conkey[INDEX_MAX_KEYS];
9500 		AttrNumber	mapped_conkey[INDEX_MAX_KEYS];
9501 		AttrNumber	confkey[INDEX_MAX_KEYS];
9502 		Oid			conpfeqop[INDEX_MAX_KEYS];
9503 		Oid			conppeqop[INDEX_MAX_KEYS];
9504 		Oid			conffeqop[INDEX_MAX_KEYS];
9505 		Constraint *fkconstraint;
9506 		bool		attached;
9507 		Oid			indexOid;
9508 		Oid			constrOid;
9509 		ObjectAddress address,
9510 					referenced;
9511 		ListCell   *cell;
9512 
9513 		tuple = SearchSysCache1(CONSTROID, parentConstrOid);
9514 		if (!HeapTupleIsValid(tuple))
9515 			elog(ERROR, "cache lookup failed for constraint %u",
9516 				 parentConstrOid);
9517 		constrForm = (Form_pg_constraint) GETSTRUCT(tuple);
9518 
9519 		/* Don't clone constraints whose parents are being cloned */
9520 		if (list_member_oid(clone, constrForm->conparentid))
9521 		{
9522 			ReleaseSysCache(tuple);
9523 			continue;
9524 		}
9525 
9526 		/*
9527 		 * Need to prevent concurrent deletions.  If pkrel is a partitioned
9528 		 * relation, that means to lock all partitions.
9529 		 */
9530 		pkrel = table_open(constrForm->confrelid, ShareRowExclusiveLock);
9531 		if (pkrel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
9532 			(void) find_all_inheritors(RelationGetRelid(pkrel),
9533 									   ShareRowExclusiveLock, NULL);
9534 
9535 		DeconstructFkConstraintRow(tuple, &numfks, conkey, confkey,
9536 								   conpfeqop, conppeqop, conffeqop);
9537 		for (int i = 0; i < numfks; i++)
9538 			mapped_conkey[i] = attmap->attnums[conkey[i] - 1];
9539 
9540 		/*
9541 		 * Before creating a new constraint, see whether any existing FKs are
9542 		 * fit for the purpose.  If one is, attach the parent constraint to
9543 		 * it, and don't clone anything.  This way we avoid the expensive
9544 		 * verification step and don't end up with a duplicate FK, and we
9545 		 * don't need to recurse to partitions for this constraint.
9546 		 */
9547 		attached = false;
9548 		foreach(cell, partFKs)
9549 		{
9550 			ForeignKeyCacheInfo *fk = lfirst_node(ForeignKeyCacheInfo, cell);
9551 
9552 			if (tryAttachPartitionForeignKey(fk,
9553 											 RelationGetRelid(partRel),
9554 											 parentConstrOid,
9555 											 numfks,
9556 											 mapped_conkey,
9557 											 confkey,
9558 											 conpfeqop))
9559 			{
9560 				attached = true;
9561 				table_close(pkrel, NoLock);
9562 				break;
9563 			}
9564 		}
9565 		if (attached)
9566 		{
9567 			ReleaseSysCache(tuple);
9568 			continue;
9569 		}
9570 
9571 		/* No dice.  Set up to create our own constraint */
9572 		fkconstraint = makeNode(Constraint);
9573 		if (ConstraintNameIsUsed(CONSTRAINT_RELATION,
9574 								 RelationGetRelid(partRel),
9575 								 NameStr(constrForm->conname)))
9576 			fkconstraint->conname =
9577 				ChooseConstraintName(RelationGetRelationName(partRel),
9578 									 ChooseForeignKeyConstraintNameAddition(fkconstraint->fk_attrs),
9579 									 "fkey",
9580 									 RelationGetNamespace(partRel), NIL);
9581 		else
9582 			fkconstraint->conname = pstrdup(NameStr(constrForm->conname));
9583 		fkconstraint->fk_upd_action = constrForm->confupdtype;
9584 		fkconstraint->fk_del_action = constrForm->confdeltype;
9585 		fkconstraint->deferrable = constrForm->condeferrable;
9586 		fkconstraint->initdeferred = constrForm->condeferred;
9587 		fkconstraint->fk_matchtype = constrForm->confmatchtype;
9588 		for (int i = 0; i < numfks; i++)
9589 		{
9590 			Form_pg_attribute att;
9591 
9592 			att = TupleDescAttr(RelationGetDescr(partRel),
9593 								mapped_conkey[i] - 1);
9594 			fkconstraint->fk_attrs = lappend(fkconstraint->fk_attrs,
9595 											 makeString(NameStr(att->attname)));
9596 		}
9597 
9598 		indexOid = constrForm->conindid;
9599 		constrOid =
9600 			CreateConstraintEntry(fkconstraint->conname,
9601 								  constrForm->connamespace,
9602 								  CONSTRAINT_FOREIGN,
9603 								  fkconstraint->deferrable,
9604 								  fkconstraint->initdeferred,
9605 								  constrForm->convalidated,
9606 								  parentConstrOid,
9607 								  RelationGetRelid(partRel),
9608 								  mapped_conkey,
9609 								  numfks,
9610 								  numfks,
9611 								  InvalidOid,	/* not a domain constraint */
9612 								  indexOid,
9613 								  constrForm->confrelid,	/* same foreign rel */
9614 								  confkey,
9615 								  conpfeqop,
9616 								  conppeqop,
9617 								  conffeqop,
9618 								  numfks,
9619 								  fkconstraint->fk_upd_action,
9620 								  fkconstraint->fk_del_action,
9621 								  fkconstraint->fk_matchtype,
9622 								  NULL,
9623 								  NULL,
9624 								  NULL,
9625 								  false,	/* islocal */
9626 								  1,	/* inhcount */
9627 								  false,	/* conNoInherit */
9628 								  true);
9629 
9630 		/* Set up partition dependencies for the new constraint */
9631 		ObjectAddressSet(address, ConstraintRelationId, constrOid);
9632 		ObjectAddressSet(referenced, ConstraintRelationId, parentConstrOid);
9633 		recordDependencyOn(&address, &referenced, DEPENDENCY_PARTITION_PRI);
9634 		ObjectAddressSet(referenced, RelationRelationId,
9635 						 RelationGetRelid(partRel));
9636 		recordDependencyOn(&address, &referenced, DEPENDENCY_PARTITION_SEC);
9637 
9638 		/* Done with the cloned constraint's tuple */
9639 		ReleaseSysCache(tuple);
9640 
9641 		/* Make all this visible before recursing */
9642 		CommandCounterIncrement();
9643 
9644 		addFkRecurseReferencing(wqueue,
9645 								fkconstraint,
9646 								partRel,
9647 								pkrel,
9648 								indexOid,
9649 								constrOid,
9650 								numfks,
9651 								confkey,
9652 								mapped_conkey,
9653 								conpfeqop,
9654 								conppeqop,
9655 								conffeqop,
9656 								false,	/* no old check exists */
9657 								AccessExclusiveLock);
9658 		table_close(pkrel, NoLock);
9659 	}
9660 }
9661 
9662 /*
9663  * When the parent of a partition receives [the referencing side of] a foreign
9664  * key, we must propagate that foreign key to the partition.  However, the
9665  * partition might already have an equivalent foreign key; this routine
9666  * compares the given ForeignKeyCacheInfo (in the partition) to the FK defined
9667  * by the other parameters.  If they are equivalent, create the link between
9668  * the two constraints and return true.
9669  *
9670  * If the given FK does not match the one defined by rest of the params,
9671  * return false.
9672  */
9673 static bool
tryAttachPartitionForeignKey(ForeignKeyCacheInfo * fk,Oid partRelid,Oid parentConstrOid,int numfks,AttrNumber * mapped_conkey,AttrNumber * confkey,Oid * conpfeqop)9674 tryAttachPartitionForeignKey(ForeignKeyCacheInfo *fk,
9675 							 Oid partRelid,
9676 							 Oid parentConstrOid,
9677 							 int numfks,
9678 							 AttrNumber *mapped_conkey,
9679 							 AttrNumber *confkey,
9680 							 Oid *conpfeqop)
9681 {
9682 	HeapTuple	parentConstrTup;
9683 	Form_pg_constraint parentConstr;
9684 	HeapTuple	partcontup;
9685 	Form_pg_constraint partConstr;
9686 	Relation	trigrel;
9687 	ScanKeyData key;
9688 	SysScanDesc scan;
9689 	HeapTuple	trigtup;
9690 
9691 	parentConstrTup = SearchSysCache1(CONSTROID,
9692 									  ObjectIdGetDatum(parentConstrOid));
9693 	if (!HeapTupleIsValid(parentConstrTup))
9694 		elog(ERROR, "cache lookup failed for constraint %u", parentConstrOid);
9695 	parentConstr = (Form_pg_constraint) GETSTRUCT(parentConstrTup);
9696 
9697 	/*
9698 	 * Do some quick & easy initial checks.  If any of these fail, we cannot
9699 	 * use this constraint.
9700 	 */
9701 	if (fk->confrelid != parentConstr->confrelid || fk->nkeys != numfks)
9702 	{
9703 		ReleaseSysCache(parentConstrTup);
9704 		return false;
9705 	}
9706 	for (int i = 0; i < numfks; i++)
9707 	{
9708 		if (fk->conkey[i] != mapped_conkey[i] ||
9709 			fk->confkey[i] != confkey[i] ||
9710 			fk->conpfeqop[i] != conpfeqop[i])
9711 		{
9712 			ReleaseSysCache(parentConstrTup);
9713 			return false;
9714 		}
9715 	}
9716 
9717 	/*
9718 	 * Looks good so far; do some more extensive checks.  Presumably the check
9719 	 * for 'convalidated' could be dropped, since we don't really care about
9720 	 * that, but let's be careful for now.
9721 	 */
9722 	partcontup = SearchSysCache1(CONSTROID,
9723 								 ObjectIdGetDatum(fk->conoid));
9724 	if (!HeapTupleIsValid(partcontup))
9725 		elog(ERROR, "cache lookup failed for constraint %u", fk->conoid);
9726 	partConstr = (Form_pg_constraint) GETSTRUCT(partcontup);
9727 	if (OidIsValid(partConstr->conparentid) ||
9728 		!partConstr->convalidated ||
9729 		partConstr->condeferrable != parentConstr->condeferrable ||
9730 		partConstr->condeferred != parentConstr->condeferred ||
9731 		partConstr->confupdtype != parentConstr->confupdtype ||
9732 		partConstr->confdeltype != parentConstr->confdeltype ||
9733 		partConstr->confmatchtype != parentConstr->confmatchtype)
9734 	{
9735 		ReleaseSysCache(parentConstrTup);
9736 		ReleaseSysCache(partcontup);
9737 		return false;
9738 	}
9739 
9740 	ReleaseSysCache(partcontup);
9741 	ReleaseSysCache(parentConstrTup);
9742 
9743 	/*
9744 	 * Looks good!  Attach this constraint.  The action triggers in the new
9745 	 * partition become redundant -- the parent table already has equivalent
9746 	 * ones, and those will be able to reach the partition.  Remove the ones
9747 	 * in the partition.  We identify them because they have our constraint
9748 	 * OID, as well as being on the referenced rel.
9749 	 */
9750 	trigrel = table_open(TriggerRelationId, RowExclusiveLock);
9751 	ScanKeyInit(&key,
9752 				Anum_pg_trigger_tgconstraint,
9753 				BTEqualStrategyNumber, F_OIDEQ,
9754 				ObjectIdGetDatum(fk->conoid));
9755 
9756 	scan = systable_beginscan(trigrel, TriggerConstraintIndexId, true,
9757 							  NULL, 1, &key);
9758 	while ((trigtup = systable_getnext(scan)) != NULL)
9759 	{
9760 		Form_pg_trigger trgform = (Form_pg_trigger) GETSTRUCT(trigtup);
9761 		ObjectAddress trigger;
9762 
9763 		if (trgform->tgconstrrelid != fk->conrelid)
9764 			continue;
9765 		if (trgform->tgrelid != fk->confrelid)
9766 			continue;
9767 
9768 		/*
9769 		 * The constraint is originally set up to contain this trigger as an
9770 		 * implementation object, so there's a dependency record that links
9771 		 * the two; however, since the trigger is no longer needed, we remove
9772 		 * the dependency link in order to be able to drop the trigger while
9773 		 * keeping the constraint intact.
9774 		 */
9775 		deleteDependencyRecordsFor(TriggerRelationId,
9776 								   trgform->oid,
9777 								   false);
9778 		/* make dependency deletion visible to performDeletion */
9779 		CommandCounterIncrement();
9780 		ObjectAddressSet(trigger, TriggerRelationId,
9781 						 trgform->oid);
9782 		performDeletion(&trigger, DROP_RESTRICT, 0);
9783 		/* make trigger drop visible, in case the loop iterates */
9784 		CommandCounterIncrement();
9785 	}
9786 
9787 	systable_endscan(scan);
9788 	table_close(trigrel, RowExclusiveLock);
9789 
9790 	ConstraintSetParentConstraint(fk->conoid, parentConstrOid, partRelid);
9791 	CommandCounterIncrement();
9792 	return true;
9793 }
9794 
9795 
9796 /*
9797  * ALTER TABLE ALTER CONSTRAINT
9798  *
9799  * Update the attributes of a constraint.
9800  *
9801  * Currently only works for Foreign Key constraints.
9802  *
9803  * If the constraint is modified, returns its address; otherwise, return
9804  * InvalidObjectAddress.
9805  */
9806 static ObjectAddress
ATExecAlterConstraint(Relation rel,AlterTableCmd * cmd,bool recurse,bool recursing,LOCKMODE lockmode)9807 ATExecAlterConstraint(Relation rel, AlterTableCmd *cmd, bool recurse,
9808 					  bool recursing, LOCKMODE lockmode)
9809 {
9810 	Constraint *cmdcon;
9811 	Relation	conrel;
9812 	Relation	tgrel;
9813 	SysScanDesc scan;
9814 	ScanKeyData skey[3];
9815 	HeapTuple	contuple;
9816 	Form_pg_constraint currcon;
9817 	ObjectAddress address;
9818 	List	   *otherrelids = NIL;
9819 	ListCell   *lc;
9820 
9821 	cmdcon = castNode(Constraint, cmd->def);
9822 
9823 	conrel = table_open(ConstraintRelationId, RowExclusiveLock);
9824 	tgrel = table_open(TriggerRelationId, RowExclusiveLock);
9825 
9826 	/*
9827 	 * Find and check the target constraint
9828 	 */
9829 	ScanKeyInit(&skey[0],
9830 				Anum_pg_constraint_conrelid,
9831 				BTEqualStrategyNumber, F_OIDEQ,
9832 				ObjectIdGetDatum(RelationGetRelid(rel)));
9833 	ScanKeyInit(&skey[1],
9834 				Anum_pg_constraint_contypid,
9835 				BTEqualStrategyNumber, F_OIDEQ,
9836 				ObjectIdGetDatum(InvalidOid));
9837 	ScanKeyInit(&skey[2],
9838 				Anum_pg_constraint_conname,
9839 				BTEqualStrategyNumber, F_NAMEEQ,
9840 				CStringGetDatum(cmdcon->conname));
9841 	scan = systable_beginscan(conrel, ConstraintRelidTypidNameIndexId,
9842 							  true, NULL, 3, skey);
9843 
9844 	/* There can be at most one matching row */
9845 	if (!HeapTupleIsValid(contuple = systable_getnext(scan)))
9846 		ereport(ERROR,
9847 				(errcode(ERRCODE_UNDEFINED_OBJECT),
9848 				 errmsg("constraint \"%s\" of relation \"%s\" does not exist",
9849 						cmdcon->conname, RelationGetRelationName(rel))));
9850 
9851 	currcon = (Form_pg_constraint) GETSTRUCT(contuple);
9852 	if (currcon->contype != CONSTRAINT_FOREIGN)
9853 		ereport(ERROR,
9854 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
9855 				 errmsg("constraint \"%s\" of relation \"%s\" is not a foreign key constraint",
9856 						cmdcon->conname, RelationGetRelationName(rel))));
9857 
9858 	/*
9859 	 * If it's not the topmost constraint, raise an error.
9860 	 *
9861 	 * Altering a non-topmost constraint leaves some triggers untouched, since
9862 	 * they are not directly connected to this constraint; also, pg_dump would
9863 	 * ignore the deferrability status of the individual constraint, since it
9864 	 * only dumps topmost constraints.  Avoid these problems by refusing this
9865 	 * operation and telling the user to alter the parent constraint instead.
9866 	 */
9867 	if (OidIsValid(currcon->conparentid))
9868 	{
9869 		HeapTuple	tp;
9870 		Oid			parent = currcon->conparentid;
9871 		char	   *ancestorname = NULL;
9872 		char	   *ancestortable = NULL;
9873 
9874 		/* Loop to find the topmost constraint */
9875 		while (HeapTupleIsValid(tp = SearchSysCache1(CONSTROID, ObjectIdGetDatum(parent))))
9876 		{
9877 			Form_pg_constraint contup = (Form_pg_constraint) GETSTRUCT(tp);
9878 
9879 			/* If no parent, this is the constraint we want */
9880 			if (!OidIsValid(contup->conparentid))
9881 			{
9882 				ancestorname = pstrdup(NameStr(contup->conname));
9883 				ancestortable = get_rel_name(contup->conrelid);
9884 				ReleaseSysCache(tp);
9885 				break;
9886 			}
9887 
9888 			parent = contup->conparentid;
9889 			ReleaseSysCache(tp);
9890 		}
9891 
9892 		ereport(ERROR,
9893 				(errmsg("cannot alter constraint \"%s\" on relation \"%s\"",
9894 						cmdcon->conname, RelationGetRelationName(rel)),
9895 				 ancestorname && ancestortable ?
9896 				 errdetail("Constraint \"%s\" is derived from constraint \"%s\" of relation \"%s\".",
9897 						   cmdcon->conname, ancestorname, ancestortable) : 0,
9898 				 errhint("You may alter the constraint it derives from, instead.")));
9899 	}
9900 
9901 	/*
9902 	 * Do the actual catalog work.  We can skip changing if already in the
9903 	 * desired state, but not if a partitioned table: partitions need to be
9904 	 * processed regardless, in case they had the constraint locally changed.
9905 	 */
9906 	address = InvalidObjectAddress;
9907 	if (currcon->condeferrable != cmdcon->deferrable ||
9908 		currcon->condeferred != cmdcon->initdeferred ||
9909 		rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
9910 	{
9911 		if (ATExecAlterConstrRecurse(cmdcon, conrel, tgrel, rel, contuple,
9912 									 &otherrelids, lockmode))
9913 			ObjectAddressSet(address, ConstraintRelationId, currcon->oid);
9914 	}
9915 
9916 	/*
9917 	 * ATExecConstrRecurse already invalidated relcache for the relations
9918 	 * having the constraint itself; here we also invalidate for relations
9919 	 * that have any triggers that are part of the constraint.
9920 	 */
9921 	foreach(lc, otherrelids)
9922 		CacheInvalidateRelcacheByRelid(lfirst_oid(lc));
9923 
9924 	systable_endscan(scan);
9925 
9926 	table_close(tgrel, RowExclusiveLock);
9927 	table_close(conrel, RowExclusiveLock);
9928 
9929 	return address;
9930 }
9931 
9932 /*
9933  * Recursive subroutine of ATExecAlterConstraint.  Returns true if the
9934  * constraint is altered.
9935  *
9936  * *otherrelids is appended OIDs of relations containing affected triggers.
9937  *
9938  * Note that we must recurse even when the values are correct, in case
9939  * indirect descendants have had their constraints altered locally.
9940  * (This could be avoided if we forbade altering constraints in partitions
9941  * but existing releases don't do that.)
9942  */
9943 static bool
ATExecAlterConstrRecurse(Constraint * cmdcon,Relation conrel,Relation tgrel,Relation rel,HeapTuple contuple,List ** otherrelids,LOCKMODE lockmode)9944 ATExecAlterConstrRecurse(Constraint *cmdcon, Relation conrel, Relation tgrel,
9945 						 Relation rel, HeapTuple contuple, List **otherrelids,
9946 						 LOCKMODE lockmode)
9947 {
9948 	Form_pg_constraint currcon;
9949 	Oid			conoid;
9950 	Oid			refrelid;
9951 	bool		changed = false;
9952 
9953 	currcon = (Form_pg_constraint) GETSTRUCT(contuple);
9954 	conoid = currcon->oid;
9955 	refrelid = currcon->confrelid;
9956 
9957 	/*
9958 	 * Update pg_constraint with the flags from cmdcon.
9959 	 *
9960 	 * If called to modify a constraint that's already in the desired state,
9961 	 * silently do nothing.
9962 	 */
9963 	if (currcon->condeferrable != cmdcon->deferrable ||
9964 		currcon->condeferred != cmdcon->initdeferred)
9965 	{
9966 		HeapTuple	copyTuple;
9967 		Form_pg_constraint copy_con;
9968 		HeapTuple	tgtuple;
9969 		ScanKeyData tgkey;
9970 		SysScanDesc tgscan;
9971 
9972 		copyTuple = heap_copytuple(contuple);
9973 		copy_con = (Form_pg_constraint) GETSTRUCT(copyTuple);
9974 		copy_con->condeferrable = cmdcon->deferrable;
9975 		copy_con->condeferred = cmdcon->initdeferred;
9976 		CatalogTupleUpdate(conrel, &copyTuple->t_self, copyTuple);
9977 
9978 		InvokeObjectPostAlterHook(ConstraintRelationId,
9979 								  conoid, 0);
9980 
9981 		heap_freetuple(copyTuple);
9982 		changed = true;
9983 
9984 		/* Make new constraint flags visible to others */
9985 		CacheInvalidateRelcache(rel);
9986 
9987 		/*
9988 		 * Now we need to update the multiple entries in pg_trigger that
9989 		 * implement the constraint.
9990 		 */
9991 		ScanKeyInit(&tgkey,
9992 					Anum_pg_trigger_tgconstraint,
9993 					BTEqualStrategyNumber, F_OIDEQ,
9994 					ObjectIdGetDatum(conoid));
9995 		tgscan = systable_beginscan(tgrel, TriggerConstraintIndexId, true,
9996 									NULL, 1, &tgkey);
9997 		while (HeapTupleIsValid(tgtuple = systable_getnext(tgscan)))
9998 		{
9999 			Form_pg_trigger tgform = (Form_pg_trigger) GETSTRUCT(tgtuple);
10000 			Form_pg_trigger copy_tg;
10001 			HeapTuple	copyTuple;
10002 
10003 			/*
10004 			 * Remember OIDs of other relation(s) involved in FK constraint.
10005 			 * (Note: it's likely that we could skip forcing a relcache inval
10006 			 * for other rels that don't have a trigger whose properties
10007 			 * change, but let's be conservative.)
10008 			 */
10009 			if (tgform->tgrelid != RelationGetRelid(rel))
10010 				*otherrelids = list_append_unique_oid(*otherrelids,
10011 													  tgform->tgrelid);
10012 
10013 			/*
10014 			 * Update deferrability of RI_FKey_noaction_del,
10015 			 * RI_FKey_noaction_upd, RI_FKey_check_ins and RI_FKey_check_upd
10016 			 * triggers, but not others; see createForeignKeyActionTriggers
10017 			 * and CreateFKCheckTrigger.
10018 			 */
10019 			if (tgform->tgfoid != F_RI_FKEY_NOACTION_DEL &&
10020 				tgform->tgfoid != F_RI_FKEY_NOACTION_UPD &&
10021 				tgform->tgfoid != F_RI_FKEY_CHECK_INS &&
10022 				tgform->tgfoid != F_RI_FKEY_CHECK_UPD)
10023 				continue;
10024 
10025 			copyTuple = heap_copytuple(tgtuple);
10026 			copy_tg = (Form_pg_trigger) GETSTRUCT(copyTuple);
10027 
10028 			copy_tg->tgdeferrable = cmdcon->deferrable;
10029 			copy_tg->tginitdeferred = cmdcon->initdeferred;
10030 			CatalogTupleUpdate(tgrel, &copyTuple->t_self, copyTuple);
10031 
10032 			InvokeObjectPostAlterHook(TriggerRelationId, tgform->oid, 0);
10033 
10034 			heap_freetuple(copyTuple);
10035 		}
10036 
10037 		systable_endscan(tgscan);
10038 	}
10039 
10040 	/*
10041 	 * If the table at either end of the constraint is partitioned, we need to
10042 	 * recurse and handle every constraint that is a child of this one.
10043 	 *
10044 	 * (This assumes that the recurse flag is forcibly set for partitioned
10045 	 * tables, and not set for legacy inheritance, though we don't check for
10046 	 * that here.)
10047 	 */
10048 	if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE ||
10049 		get_rel_relkind(refrelid) == RELKIND_PARTITIONED_TABLE)
10050 	{
10051 		ScanKeyData pkey;
10052 		SysScanDesc pscan;
10053 		HeapTuple	childtup;
10054 
10055 		ScanKeyInit(&pkey,
10056 					Anum_pg_constraint_conparentid,
10057 					BTEqualStrategyNumber, F_OIDEQ,
10058 					ObjectIdGetDatum(conoid));
10059 
10060 		pscan = systable_beginscan(conrel, ConstraintParentIndexId,
10061 								   true, NULL, 1, &pkey);
10062 
10063 		while (HeapTupleIsValid(childtup = systable_getnext(pscan)))
10064 		{
10065 			Form_pg_constraint childcon = (Form_pg_constraint) GETSTRUCT(childtup);
10066 			Relation	childrel;
10067 
10068 			childrel = table_open(childcon->conrelid, lockmode);
10069 			ATExecAlterConstrRecurse(cmdcon, conrel, tgrel, childrel, childtup,
10070 									 otherrelids, lockmode);
10071 			table_close(childrel, NoLock);
10072 		}
10073 
10074 		systable_endscan(pscan);
10075 	}
10076 
10077 	return changed;
10078 }
10079 
10080 /*
10081  * ALTER TABLE VALIDATE CONSTRAINT
10082  *
10083  * XXX The reason we handle recursion here rather than at Phase 1 is because
10084  * there's no good way to skip recursing when handling foreign keys: there is
10085  * no need to lock children in that case, yet we wouldn't be able to avoid
10086  * doing so at that level.
10087  *
10088  * Return value is the address of the validated constraint.  If the constraint
10089  * was already validated, InvalidObjectAddress is returned.
10090  */
10091 static ObjectAddress
ATExecValidateConstraint(List ** wqueue,Relation rel,char * constrName,bool recurse,bool recursing,LOCKMODE lockmode)10092 ATExecValidateConstraint(List **wqueue, Relation rel, char *constrName,
10093 						 bool recurse, bool recursing, LOCKMODE lockmode)
10094 {
10095 	Relation	conrel;
10096 	SysScanDesc scan;
10097 	ScanKeyData skey[3];
10098 	HeapTuple	tuple;
10099 	Form_pg_constraint con;
10100 	ObjectAddress address;
10101 
10102 	conrel = table_open(ConstraintRelationId, RowExclusiveLock);
10103 
10104 	/*
10105 	 * Find and check the target constraint
10106 	 */
10107 	ScanKeyInit(&skey[0],
10108 				Anum_pg_constraint_conrelid,
10109 				BTEqualStrategyNumber, F_OIDEQ,
10110 				ObjectIdGetDatum(RelationGetRelid(rel)));
10111 	ScanKeyInit(&skey[1],
10112 				Anum_pg_constraint_contypid,
10113 				BTEqualStrategyNumber, F_OIDEQ,
10114 				ObjectIdGetDatum(InvalidOid));
10115 	ScanKeyInit(&skey[2],
10116 				Anum_pg_constraint_conname,
10117 				BTEqualStrategyNumber, F_NAMEEQ,
10118 				CStringGetDatum(constrName));
10119 	scan = systable_beginscan(conrel, ConstraintRelidTypidNameIndexId,
10120 							  true, NULL, 3, skey);
10121 
10122 	/* There can be at most one matching row */
10123 	if (!HeapTupleIsValid(tuple = systable_getnext(scan)))
10124 		ereport(ERROR,
10125 				(errcode(ERRCODE_UNDEFINED_OBJECT),
10126 				 errmsg("constraint \"%s\" of relation \"%s\" does not exist",
10127 						constrName, RelationGetRelationName(rel))));
10128 
10129 	con = (Form_pg_constraint) GETSTRUCT(tuple);
10130 	if (con->contype != CONSTRAINT_FOREIGN &&
10131 		con->contype != CONSTRAINT_CHECK)
10132 		ereport(ERROR,
10133 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
10134 				 errmsg("constraint \"%s\" of relation \"%s\" is not a foreign key or check constraint",
10135 						constrName, RelationGetRelationName(rel))));
10136 
10137 	if (!con->convalidated)
10138 	{
10139 		AlteredTableInfo *tab;
10140 		HeapTuple	copyTuple;
10141 		Form_pg_constraint copy_con;
10142 
10143 		if (con->contype == CONSTRAINT_FOREIGN)
10144 		{
10145 			NewConstraint *newcon;
10146 			Constraint *fkconstraint;
10147 
10148 			/* Queue validation for phase 3 */
10149 			fkconstraint = makeNode(Constraint);
10150 			/* for now this is all we need */
10151 			fkconstraint->conname = constrName;
10152 
10153 			newcon = (NewConstraint *) palloc0(sizeof(NewConstraint));
10154 			newcon->name = constrName;
10155 			newcon->contype = CONSTR_FOREIGN;
10156 			newcon->refrelid = con->confrelid;
10157 			newcon->refindid = con->conindid;
10158 			newcon->conid = con->oid;
10159 			newcon->qual = (Node *) fkconstraint;
10160 
10161 			/* Find or create work queue entry for this table */
10162 			tab = ATGetQueueEntry(wqueue, rel);
10163 			tab->constraints = lappend(tab->constraints, newcon);
10164 
10165 			/*
10166 			 * We disallow creating invalid foreign keys to or from
10167 			 * partitioned tables, so ignoring the recursion bit is okay.
10168 			 */
10169 		}
10170 		else if (con->contype == CONSTRAINT_CHECK)
10171 		{
10172 			List	   *children = NIL;
10173 			ListCell   *child;
10174 			NewConstraint *newcon;
10175 			bool		isnull;
10176 			Datum		val;
10177 			char	   *conbin;
10178 
10179 			/*
10180 			 * If we're recursing, the parent has already done this, so skip
10181 			 * it.  Also, if the constraint is a NO INHERIT constraint, we
10182 			 * shouldn't try to look for it in the children.
10183 			 */
10184 			if (!recursing && !con->connoinherit)
10185 				children = find_all_inheritors(RelationGetRelid(rel),
10186 											   lockmode, NULL);
10187 
10188 			/*
10189 			 * For CHECK constraints, we must ensure that we only mark the
10190 			 * constraint as validated on the parent if it's already validated
10191 			 * on the children.
10192 			 *
10193 			 * We recurse before validating on the parent, to reduce risk of
10194 			 * deadlocks.
10195 			 */
10196 			foreach(child, children)
10197 			{
10198 				Oid			childoid = lfirst_oid(child);
10199 				Relation	childrel;
10200 
10201 				if (childoid == RelationGetRelid(rel))
10202 					continue;
10203 
10204 				/*
10205 				 * If we are told not to recurse, there had better not be any
10206 				 * child tables, because we can't mark the constraint on the
10207 				 * parent valid unless it is valid for all child tables.
10208 				 */
10209 				if (!recurse)
10210 					ereport(ERROR,
10211 							(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
10212 							 errmsg("constraint must be validated on child tables too")));
10213 
10214 				/* find_all_inheritors already got lock */
10215 				childrel = table_open(childoid, NoLock);
10216 
10217 				ATExecValidateConstraint(wqueue, childrel, constrName, false,
10218 										 true, lockmode);
10219 				table_close(childrel, NoLock);
10220 			}
10221 
10222 			/* Queue validation for phase 3 */
10223 			newcon = (NewConstraint *) palloc0(sizeof(NewConstraint));
10224 			newcon->name = constrName;
10225 			newcon->contype = CONSTR_CHECK;
10226 			newcon->refrelid = InvalidOid;
10227 			newcon->refindid = InvalidOid;
10228 			newcon->conid = con->oid;
10229 
10230 			val = SysCacheGetAttr(CONSTROID, tuple,
10231 								  Anum_pg_constraint_conbin, &isnull);
10232 			if (isnull)
10233 				elog(ERROR, "null conbin for constraint %u", con->oid);
10234 
10235 			conbin = TextDatumGetCString(val);
10236 			newcon->qual = (Node *) stringToNode(conbin);
10237 
10238 			/* Find or create work queue entry for this table */
10239 			tab = ATGetQueueEntry(wqueue, rel);
10240 			tab->constraints = lappend(tab->constraints, newcon);
10241 
10242 			/*
10243 			 * Invalidate relcache so that others see the new validated
10244 			 * constraint.
10245 			 */
10246 			CacheInvalidateRelcache(rel);
10247 		}
10248 
10249 		/*
10250 		 * Now update the catalog, while we have the door open.
10251 		 */
10252 		copyTuple = heap_copytuple(tuple);
10253 		copy_con = (Form_pg_constraint) GETSTRUCT(copyTuple);
10254 		copy_con->convalidated = true;
10255 		CatalogTupleUpdate(conrel, &copyTuple->t_self, copyTuple);
10256 
10257 		InvokeObjectPostAlterHook(ConstraintRelationId, con->oid, 0);
10258 
10259 		heap_freetuple(copyTuple);
10260 
10261 		ObjectAddressSet(address, ConstraintRelationId, con->oid);
10262 	}
10263 	else
10264 		address = InvalidObjectAddress; /* already validated */
10265 
10266 	systable_endscan(scan);
10267 
10268 	table_close(conrel, RowExclusiveLock);
10269 
10270 	return address;
10271 }
10272 
10273 
10274 /*
10275  * transformColumnNameList - transform list of column names
10276  *
10277  * Lookup each name and return its attnum and type OID
10278  */
10279 static int
transformColumnNameList(Oid relId,List * colList,int16 * attnums,Oid * atttypids)10280 transformColumnNameList(Oid relId, List *colList,
10281 						int16 *attnums, Oid *atttypids)
10282 {
10283 	ListCell   *l;
10284 	int			attnum;
10285 
10286 	attnum = 0;
10287 	foreach(l, colList)
10288 	{
10289 		char	   *attname = strVal(lfirst(l));
10290 		HeapTuple	atttuple;
10291 
10292 		atttuple = SearchSysCacheAttName(relId, attname);
10293 		if (!HeapTupleIsValid(atttuple))
10294 			ereport(ERROR,
10295 					(errcode(ERRCODE_UNDEFINED_COLUMN),
10296 					 errmsg("column \"%s\" referenced in foreign key constraint does not exist",
10297 							attname)));
10298 		if (attnum >= INDEX_MAX_KEYS)
10299 			ereport(ERROR,
10300 					(errcode(ERRCODE_TOO_MANY_COLUMNS),
10301 					 errmsg("cannot have more than %d keys in a foreign key",
10302 							INDEX_MAX_KEYS)));
10303 		attnums[attnum] = ((Form_pg_attribute) GETSTRUCT(atttuple))->attnum;
10304 		atttypids[attnum] = ((Form_pg_attribute) GETSTRUCT(atttuple))->atttypid;
10305 		ReleaseSysCache(atttuple);
10306 		attnum++;
10307 	}
10308 
10309 	return attnum;
10310 }
10311 
10312 /*
10313  * transformFkeyGetPrimaryKey -
10314  *
10315  *	Look up the names, attnums, and types of the primary key attributes
10316  *	for the pkrel.  Also return the index OID and index opclasses of the
10317  *	index supporting the primary key.
10318  *
10319  *	All parameters except pkrel are output parameters.  Also, the function
10320  *	return value is the number of attributes in the primary key.
10321  *
10322  *	Used when the column list in the REFERENCES specification is omitted.
10323  */
10324 static int
transformFkeyGetPrimaryKey(Relation pkrel,Oid * indexOid,List ** attnamelist,int16 * attnums,Oid * atttypids,Oid * opclasses)10325 transformFkeyGetPrimaryKey(Relation pkrel, Oid *indexOid,
10326 						   List **attnamelist,
10327 						   int16 *attnums, Oid *atttypids,
10328 						   Oid *opclasses)
10329 {
10330 	List	   *indexoidlist;
10331 	ListCell   *indexoidscan;
10332 	HeapTuple	indexTuple = NULL;
10333 	Form_pg_index indexStruct = NULL;
10334 	Datum		indclassDatum;
10335 	bool		isnull;
10336 	oidvector  *indclass;
10337 	int			i;
10338 
10339 	/*
10340 	 * Get the list of index OIDs for the table from the relcache, and look up
10341 	 * each one in the pg_index syscache until we find one marked primary key
10342 	 * (hopefully there isn't more than one such).  Insist it's valid, too.
10343 	 */
10344 	*indexOid = InvalidOid;
10345 
10346 	indexoidlist = RelationGetIndexList(pkrel);
10347 
10348 	foreach(indexoidscan, indexoidlist)
10349 	{
10350 		Oid			indexoid = lfirst_oid(indexoidscan);
10351 
10352 		indexTuple = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(indexoid));
10353 		if (!HeapTupleIsValid(indexTuple))
10354 			elog(ERROR, "cache lookup failed for index %u", indexoid);
10355 		indexStruct = (Form_pg_index) GETSTRUCT(indexTuple);
10356 		if (indexStruct->indisprimary && indexStruct->indisvalid)
10357 		{
10358 			/*
10359 			 * Refuse to use a deferrable primary key.  This is per SQL spec,
10360 			 * and there would be a lot of interesting semantic problems if we
10361 			 * tried to allow it.
10362 			 */
10363 			if (!indexStruct->indimmediate)
10364 				ereport(ERROR,
10365 						(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
10366 						 errmsg("cannot use a deferrable primary key for referenced table \"%s\"",
10367 								RelationGetRelationName(pkrel))));
10368 
10369 			*indexOid = indexoid;
10370 			break;
10371 		}
10372 		ReleaseSysCache(indexTuple);
10373 	}
10374 
10375 	list_free(indexoidlist);
10376 
10377 	/*
10378 	 * Check that we found it
10379 	 */
10380 	if (!OidIsValid(*indexOid))
10381 		ereport(ERROR,
10382 				(errcode(ERRCODE_UNDEFINED_OBJECT),
10383 				 errmsg("there is no primary key for referenced table \"%s\"",
10384 						RelationGetRelationName(pkrel))));
10385 
10386 	/* Must get indclass the hard way */
10387 	indclassDatum = SysCacheGetAttr(INDEXRELID, indexTuple,
10388 									Anum_pg_index_indclass, &isnull);
10389 	Assert(!isnull);
10390 	indclass = (oidvector *) DatumGetPointer(indclassDatum);
10391 
10392 	/*
10393 	 * Now build the list of PK attributes from the indkey definition (we
10394 	 * assume a primary key cannot have expressional elements)
10395 	 */
10396 	*attnamelist = NIL;
10397 	for (i = 0; i < indexStruct->indnkeyatts; i++)
10398 	{
10399 		int			pkattno = indexStruct->indkey.values[i];
10400 
10401 		attnums[i] = pkattno;
10402 		atttypids[i] = attnumTypeId(pkrel, pkattno);
10403 		opclasses[i] = indclass->values[i];
10404 		*attnamelist = lappend(*attnamelist,
10405 							   makeString(pstrdup(NameStr(*attnumAttName(pkrel, pkattno)))));
10406 	}
10407 
10408 	ReleaseSysCache(indexTuple);
10409 
10410 	return i;
10411 }
10412 
10413 /*
10414  * transformFkeyCheckAttrs -
10415  *
10416  *	Make sure that the attributes of a referenced table belong to a unique
10417  *	(or primary key) constraint.  Return the OID of the index supporting
10418  *	the constraint, as well as the opclasses associated with the index
10419  *	columns.
10420  */
10421 static Oid
transformFkeyCheckAttrs(Relation pkrel,int numattrs,int16 * attnums,Oid * opclasses)10422 transformFkeyCheckAttrs(Relation pkrel,
10423 						int numattrs, int16 *attnums,
10424 						Oid *opclasses) /* output parameter */
10425 {
10426 	Oid			indexoid = InvalidOid;
10427 	bool		found = false;
10428 	bool		found_deferrable = false;
10429 	List	   *indexoidlist;
10430 	ListCell   *indexoidscan;
10431 	int			i,
10432 				j;
10433 
10434 	/*
10435 	 * Reject duplicate appearances of columns in the referenced-columns list.
10436 	 * Such a case is forbidden by the SQL standard, and even if we thought it
10437 	 * useful to allow it, there would be ambiguity about how to match the
10438 	 * list to unique indexes (in particular, it'd be unclear which index
10439 	 * opclass goes with which FK column).
10440 	 */
10441 	for (i = 0; i < numattrs; i++)
10442 	{
10443 		for (j = i + 1; j < numattrs; j++)
10444 		{
10445 			if (attnums[i] == attnums[j])
10446 				ereport(ERROR,
10447 						(errcode(ERRCODE_INVALID_FOREIGN_KEY),
10448 						 errmsg("foreign key referenced-columns list must not contain duplicates")));
10449 		}
10450 	}
10451 
10452 	/*
10453 	 * Get the list of index OIDs for the table from the relcache, and look up
10454 	 * each one in the pg_index syscache, and match unique indexes to the list
10455 	 * of attnums we are given.
10456 	 */
10457 	indexoidlist = RelationGetIndexList(pkrel);
10458 
10459 	foreach(indexoidscan, indexoidlist)
10460 	{
10461 		HeapTuple	indexTuple;
10462 		Form_pg_index indexStruct;
10463 
10464 		indexoid = lfirst_oid(indexoidscan);
10465 		indexTuple = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(indexoid));
10466 		if (!HeapTupleIsValid(indexTuple))
10467 			elog(ERROR, "cache lookup failed for index %u", indexoid);
10468 		indexStruct = (Form_pg_index) GETSTRUCT(indexTuple);
10469 
10470 		/*
10471 		 * Must have the right number of columns; must be unique and not a
10472 		 * partial index; forget it if there are any expressions, too. Invalid
10473 		 * indexes are out as well.
10474 		 */
10475 		if (indexStruct->indnkeyatts == numattrs &&
10476 			indexStruct->indisunique &&
10477 			indexStruct->indisvalid &&
10478 			heap_attisnull(indexTuple, Anum_pg_index_indpred, NULL) &&
10479 			heap_attisnull(indexTuple, Anum_pg_index_indexprs, NULL))
10480 		{
10481 			Datum		indclassDatum;
10482 			bool		isnull;
10483 			oidvector  *indclass;
10484 
10485 			/* Must get indclass the hard way */
10486 			indclassDatum = SysCacheGetAttr(INDEXRELID, indexTuple,
10487 											Anum_pg_index_indclass, &isnull);
10488 			Assert(!isnull);
10489 			indclass = (oidvector *) DatumGetPointer(indclassDatum);
10490 
10491 			/*
10492 			 * The given attnum list may match the index columns in any order.
10493 			 * Check for a match, and extract the appropriate opclasses while
10494 			 * we're at it.
10495 			 *
10496 			 * We know that attnums[] is duplicate-free per the test at the
10497 			 * start of this function, and we checked above that the number of
10498 			 * index columns agrees, so if we find a match for each attnums[]
10499 			 * entry then we must have a one-to-one match in some order.
10500 			 */
10501 			for (i = 0; i < numattrs; i++)
10502 			{
10503 				found = false;
10504 				for (j = 0; j < numattrs; j++)
10505 				{
10506 					if (attnums[i] == indexStruct->indkey.values[j])
10507 					{
10508 						opclasses[i] = indclass->values[j];
10509 						found = true;
10510 						break;
10511 					}
10512 				}
10513 				if (!found)
10514 					break;
10515 			}
10516 
10517 			/*
10518 			 * Refuse to use a deferrable unique/primary key.  This is per SQL
10519 			 * spec, and there would be a lot of interesting semantic problems
10520 			 * if we tried to allow it.
10521 			 */
10522 			if (found && !indexStruct->indimmediate)
10523 			{
10524 				/*
10525 				 * Remember that we found an otherwise matching index, so that
10526 				 * we can generate a more appropriate error message.
10527 				 */
10528 				found_deferrable = true;
10529 				found = false;
10530 			}
10531 		}
10532 		ReleaseSysCache(indexTuple);
10533 		if (found)
10534 			break;
10535 	}
10536 
10537 	if (!found)
10538 	{
10539 		if (found_deferrable)
10540 			ereport(ERROR,
10541 					(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
10542 					 errmsg("cannot use a deferrable unique constraint for referenced table \"%s\"",
10543 							RelationGetRelationName(pkrel))));
10544 		else
10545 			ereport(ERROR,
10546 					(errcode(ERRCODE_INVALID_FOREIGN_KEY),
10547 					 errmsg("there is no unique constraint matching given keys for referenced table \"%s\"",
10548 							RelationGetRelationName(pkrel))));
10549 	}
10550 
10551 	list_free(indexoidlist);
10552 
10553 	return indexoid;
10554 }
10555 
10556 /*
10557  * findFkeyCast -
10558  *
10559  *	Wrapper around find_coercion_pathway() for ATAddForeignKeyConstraint().
10560  *	Caller has equal regard for binary coercibility and for an exact match.
10561 */
10562 static CoercionPathType
findFkeyCast(Oid targetTypeId,Oid sourceTypeId,Oid * funcid)10563 findFkeyCast(Oid targetTypeId, Oid sourceTypeId, Oid *funcid)
10564 {
10565 	CoercionPathType ret;
10566 
10567 	if (targetTypeId == sourceTypeId)
10568 	{
10569 		ret = COERCION_PATH_RELABELTYPE;
10570 		*funcid = InvalidOid;
10571 	}
10572 	else
10573 	{
10574 		ret = find_coercion_pathway(targetTypeId, sourceTypeId,
10575 									COERCION_IMPLICIT, funcid);
10576 		if (ret == COERCION_PATH_NONE)
10577 			/* A previously-relied-upon cast is now gone. */
10578 			elog(ERROR, "could not find cast from %u to %u",
10579 				 sourceTypeId, targetTypeId);
10580 	}
10581 
10582 	return ret;
10583 }
10584 
10585 /*
10586  * Permissions checks on the referenced table for ADD FOREIGN KEY
10587  *
10588  * Note: we have already checked that the user owns the referencing table,
10589  * else we'd have failed much earlier; no additional checks are needed for it.
10590  */
10591 static void
checkFkeyPermissions(Relation rel,int16 * attnums,int natts)10592 checkFkeyPermissions(Relation rel, int16 *attnums, int natts)
10593 {
10594 	Oid			roleid = GetUserId();
10595 	AclResult	aclresult;
10596 	int			i;
10597 
10598 	/* Okay if we have relation-level REFERENCES permission */
10599 	aclresult = pg_class_aclcheck(RelationGetRelid(rel), roleid,
10600 								  ACL_REFERENCES);
10601 	if (aclresult == ACLCHECK_OK)
10602 		return;
10603 	/* Else we must have REFERENCES on each column */
10604 	for (i = 0; i < natts; i++)
10605 	{
10606 		aclresult = pg_attribute_aclcheck(RelationGetRelid(rel), attnums[i],
10607 										  roleid, ACL_REFERENCES);
10608 		if (aclresult != ACLCHECK_OK)
10609 			aclcheck_error(aclresult, get_relkind_objtype(rel->rd_rel->relkind),
10610 						   RelationGetRelationName(rel));
10611 	}
10612 }
10613 
10614 /*
10615  * Scan the existing rows in a table to verify they meet a proposed FK
10616  * constraint.
10617  *
10618  * Caller must have opened and locked both relations appropriately.
10619  */
10620 static void
validateForeignKeyConstraint(char * conname,Relation rel,Relation pkrel,Oid pkindOid,Oid constraintOid)10621 validateForeignKeyConstraint(char *conname,
10622 							 Relation rel,
10623 							 Relation pkrel,
10624 							 Oid pkindOid,
10625 							 Oid constraintOid)
10626 {
10627 	TupleTableSlot *slot;
10628 	TableScanDesc scan;
10629 	Trigger		trig;
10630 	Snapshot	snapshot;
10631 	MemoryContext oldcxt;
10632 	MemoryContext perTupCxt;
10633 
10634 	ereport(DEBUG1,
10635 			(errmsg("validating foreign key constraint \"%s\"", conname)));
10636 
10637 	/*
10638 	 * Build a trigger call structure; we'll need it either way.
10639 	 */
10640 	MemSet(&trig, 0, sizeof(trig));
10641 	trig.tgoid = InvalidOid;
10642 	trig.tgname = conname;
10643 	trig.tgenabled = TRIGGER_FIRES_ON_ORIGIN;
10644 	trig.tgisinternal = true;
10645 	trig.tgconstrrelid = RelationGetRelid(pkrel);
10646 	trig.tgconstrindid = pkindOid;
10647 	trig.tgconstraint = constraintOid;
10648 	trig.tgdeferrable = false;
10649 	trig.tginitdeferred = false;
10650 	/* we needn't fill in remaining fields */
10651 
10652 	/*
10653 	 * See if we can do it with a single LEFT JOIN query.  A false result
10654 	 * indicates we must proceed with the fire-the-trigger method.
10655 	 */
10656 	if (RI_Initial_Check(&trig, rel, pkrel))
10657 		return;
10658 
10659 	/*
10660 	 * Scan through each tuple, calling RI_FKey_check_ins (insert trigger) as
10661 	 * if that tuple had just been inserted.  If any of those fail, it should
10662 	 * ereport(ERROR) and that's that.
10663 	 */
10664 	snapshot = RegisterSnapshot(GetLatestSnapshot());
10665 	slot = table_slot_create(rel, NULL);
10666 	scan = table_beginscan(rel, snapshot, 0, NULL);
10667 
10668 	perTupCxt = AllocSetContextCreate(CurrentMemoryContext,
10669 									  "validateForeignKeyConstraint",
10670 									  ALLOCSET_SMALL_SIZES);
10671 	oldcxt = MemoryContextSwitchTo(perTupCxt);
10672 
10673 	while (table_scan_getnextslot(scan, ForwardScanDirection, slot))
10674 	{
10675 		LOCAL_FCINFO(fcinfo, 0);
10676 		TriggerData trigdata = {0};
10677 
10678 		CHECK_FOR_INTERRUPTS();
10679 
10680 		/*
10681 		 * Make a call to the trigger function
10682 		 *
10683 		 * No parameters are passed, but we do set a context
10684 		 */
10685 		MemSet(fcinfo, 0, SizeForFunctionCallInfo(0));
10686 
10687 		/*
10688 		 * We assume RI_FKey_check_ins won't look at flinfo...
10689 		 */
10690 		trigdata.type = T_TriggerData;
10691 		trigdata.tg_event = TRIGGER_EVENT_INSERT | TRIGGER_EVENT_ROW;
10692 		trigdata.tg_relation = rel;
10693 		trigdata.tg_trigtuple = ExecFetchSlotHeapTuple(slot, false, NULL);
10694 		trigdata.tg_trigslot = slot;
10695 		trigdata.tg_trigger = &trig;
10696 
10697 		fcinfo->context = (Node *) &trigdata;
10698 
10699 		RI_FKey_check_ins(fcinfo);
10700 
10701 		MemoryContextReset(perTupCxt);
10702 	}
10703 
10704 	MemoryContextSwitchTo(oldcxt);
10705 	MemoryContextDelete(perTupCxt);
10706 	table_endscan(scan);
10707 	UnregisterSnapshot(snapshot);
10708 	ExecDropSingleTupleTableSlot(slot);
10709 }
10710 
10711 static void
CreateFKCheckTrigger(Oid myRelOid,Oid refRelOid,Constraint * fkconstraint,Oid constraintOid,Oid indexOid,bool on_insert)10712 CreateFKCheckTrigger(Oid myRelOid, Oid refRelOid, Constraint *fkconstraint,
10713 					 Oid constraintOid, Oid indexOid, bool on_insert)
10714 {
10715 	CreateTrigStmt *fk_trigger;
10716 
10717 	/*
10718 	 * Note: for a self-referential FK (referencing and referenced tables are
10719 	 * the same), it is important that the ON UPDATE action fires before the
10720 	 * CHECK action, since both triggers will fire on the same row during an
10721 	 * UPDATE event; otherwise the CHECK trigger will be checking a non-final
10722 	 * state of the row.  Triggers fire in name order, so we ensure this by
10723 	 * using names like "RI_ConstraintTrigger_a_NNNN" for the action triggers
10724 	 * and "RI_ConstraintTrigger_c_NNNN" for the check triggers.
10725 	 */
10726 	fk_trigger = makeNode(CreateTrigStmt);
10727 	fk_trigger->trigname = "RI_ConstraintTrigger_c";
10728 	fk_trigger->relation = NULL;
10729 	fk_trigger->row = true;
10730 	fk_trigger->timing = TRIGGER_TYPE_AFTER;
10731 
10732 	/* Either ON INSERT or ON UPDATE */
10733 	if (on_insert)
10734 	{
10735 		fk_trigger->funcname = SystemFuncName("RI_FKey_check_ins");
10736 		fk_trigger->events = TRIGGER_TYPE_INSERT;
10737 	}
10738 	else
10739 	{
10740 		fk_trigger->funcname = SystemFuncName("RI_FKey_check_upd");
10741 		fk_trigger->events = TRIGGER_TYPE_UPDATE;
10742 	}
10743 
10744 	fk_trigger->columns = NIL;
10745 	fk_trigger->transitionRels = NIL;
10746 	fk_trigger->whenClause = NULL;
10747 	fk_trigger->isconstraint = true;
10748 	fk_trigger->deferrable = fkconstraint->deferrable;
10749 	fk_trigger->initdeferred = fkconstraint->initdeferred;
10750 	fk_trigger->constrrel = NULL;
10751 	fk_trigger->args = NIL;
10752 
10753 	(void) CreateTrigger(fk_trigger, NULL, myRelOid, refRelOid, constraintOid,
10754 						 indexOid, InvalidOid, InvalidOid, NULL, true, false);
10755 
10756 	/* Make changes-so-far visible */
10757 	CommandCounterIncrement();
10758 }
10759 
10760 /*
10761  * createForeignKeyActionTriggers
10762  *		Create the referenced-side "action" triggers that implement a foreign
10763  *		key.
10764  */
10765 static void
createForeignKeyActionTriggers(Relation rel,Oid refRelOid,Constraint * fkconstraint,Oid constraintOid,Oid indexOid)10766 createForeignKeyActionTriggers(Relation rel, Oid refRelOid, Constraint *fkconstraint,
10767 							   Oid constraintOid, Oid indexOid)
10768 {
10769 	CreateTrigStmt *fk_trigger;
10770 
10771 	/*
10772 	 * Build and execute a CREATE CONSTRAINT TRIGGER statement for the ON
10773 	 * DELETE action on the referenced table.
10774 	 */
10775 	fk_trigger = makeNode(CreateTrigStmt);
10776 	fk_trigger->trigname = "RI_ConstraintTrigger_a";
10777 	fk_trigger->relation = NULL;
10778 	fk_trigger->row = true;
10779 	fk_trigger->timing = TRIGGER_TYPE_AFTER;
10780 	fk_trigger->events = TRIGGER_TYPE_DELETE;
10781 	fk_trigger->columns = NIL;
10782 	fk_trigger->transitionRels = NIL;
10783 	fk_trigger->whenClause = NULL;
10784 	fk_trigger->isconstraint = true;
10785 	fk_trigger->constrrel = NULL;
10786 	switch (fkconstraint->fk_del_action)
10787 	{
10788 		case FKCONSTR_ACTION_NOACTION:
10789 			fk_trigger->deferrable = fkconstraint->deferrable;
10790 			fk_trigger->initdeferred = fkconstraint->initdeferred;
10791 			fk_trigger->funcname = SystemFuncName("RI_FKey_noaction_del");
10792 			break;
10793 		case FKCONSTR_ACTION_RESTRICT:
10794 			fk_trigger->deferrable = false;
10795 			fk_trigger->initdeferred = false;
10796 			fk_trigger->funcname = SystemFuncName("RI_FKey_restrict_del");
10797 			break;
10798 		case FKCONSTR_ACTION_CASCADE:
10799 			fk_trigger->deferrable = false;
10800 			fk_trigger->initdeferred = false;
10801 			fk_trigger->funcname = SystemFuncName("RI_FKey_cascade_del");
10802 			break;
10803 		case FKCONSTR_ACTION_SETNULL:
10804 			fk_trigger->deferrable = false;
10805 			fk_trigger->initdeferred = false;
10806 			fk_trigger->funcname = SystemFuncName("RI_FKey_setnull_del");
10807 			break;
10808 		case FKCONSTR_ACTION_SETDEFAULT:
10809 			fk_trigger->deferrable = false;
10810 			fk_trigger->initdeferred = false;
10811 			fk_trigger->funcname = SystemFuncName("RI_FKey_setdefault_del");
10812 			break;
10813 		default:
10814 			elog(ERROR, "unrecognized FK action type: %d",
10815 				 (int) fkconstraint->fk_del_action);
10816 			break;
10817 	}
10818 	fk_trigger->args = NIL;
10819 
10820 	(void) CreateTrigger(fk_trigger, NULL, refRelOid, RelationGetRelid(rel),
10821 						 constraintOid,
10822 						 indexOid, InvalidOid, InvalidOid, NULL, true, false);
10823 
10824 	/* Make changes-so-far visible */
10825 	CommandCounterIncrement();
10826 
10827 	/*
10828 	 * Build and execute a CREATE CONSTRAINT TRIGGER statement for the ON
10829 	 * UPDATE action on the referenced table.
10830 	 */
10831 	fk_trigger = makeNode(CreateTrigStmt);
10832 	fk_trigger->trigname = "RI_ConstraintTrigger_a";
10833 	fk_trigger->relation = NULL;
10834 	fk_trigger->row = true;
10835 	fk_trigger->timing = TRIGGER_TYPE_AFTER;
10836 	fk_trigger->events = TRIGGER_TYPE_UPDATE;
10837 	fk_trigger->columns = NIL;
10838 	fk_trigger->transitionRels = NIL;
10839 	fk_trigger->whenClause = NULL;
10840 	fk_trigger->isconstraint = true;
10841 	fk_trigger->constrrel = NULL;
10842 	switch (fkconstraint->fk_upd_action)
10843 	{
10844 		case FKCONSTR_ACTION_NOACTION:
10845 			fk_trigger->deferrable = fkconstraint->deferrable;
10846 			fk_trigger->initdeferred = fkconstraint->initdeferred;
10847 			fk_trigger->funcname = SystemFuncName("RI_FKey_noaction_upd");
10848 			break;
10849 		case FKCONSTR_ACTION_RESTRICT:
10850 			fk_trigger->deferrable = false;
10851 			fk_trigger->initdeferred = false;
10852 			fk_trigger->funcname = SystemFuncName("RI_FKey_restrict_upd");
10853 			break;
10854 		case FKCONSTR_ACTION_CASCADE:
10855 			fk_trigger->deferrable = false;
10856 			fk_trigger->initdeferred = false;
10857 			fk_trigger->funcname = SystemFuncName("RI_FKey_cascade_upd");
10858 			break;
10859 		case FKCONSTR_ACTION_SETNULL:
10860 			fk_trigger->deferrable = false;
10861 			fk_trigger->initdeferred = false;
10862 			fk_trigger->funcname = SystemFuncName("RI_FKey_setnull_upd");
10863 			break;
10864 		case FKCONSTR_ACTION_SETDEFAULT:
10865 			fk_trigger->deferrable = false;
10866 			fk_trigger->initdeferred = false;
10867 			fk_trigger->funcname = SystemFuncName("RI_FKey_setdefault_upd");
10868 			break;
10869 		default:
10870 			elog(ERROR, "unrecognized FK action type: %d",
10871 				 (int) fkconstraint->fk_upd_action);
10872 			break;
10873 	}
10874 	fk_trigger->args = NIL;
10875 
10876 	(void) CreateTrigger(fk_trigger, NULL, refRelOid, RelationGetRelid(rel),
10877 						 constraintOid,
10878 						 indexOid, InvalidOid, InvalidOid, NULL, true, false);
10879 }
10880 
10881 /*
10882  * createForeignKeyCheckTriggers
10883  *		Create the referencing-side "check" triggers that implement a foreign
10884  *		key.
10885  */
10886 static void
createForeignKeyCheckTriggers(Oid myRelOid,Oid refRelOid,Constraint * fkconstraint,Oid constraintOid,Oid indexOid)10887 createForeignKeyCheckTriggers(Oid myRelOid, Oid refRelOid,
10888 							  Constraint *fkconstraint, Oid constraintOid,
10889 							  Oid indexOid)
10890 {
10891 	CreateFKCheckTrigger(myRelOid, refRelOid, fkconstraint, constraintOid,
10892 						 indexOid, true);
10893 	CreateFKCheckTrigger(myRelOid, refRelOid, fkconstraint, constraintOid,
10894 						 indexOid, false);
10895 }
10896 
10897 /*
10898  * ALTER TABLE DROP CONSTRAINT
10899  *
10900  * Like DROP COLUMN, we can't use the normal ALTER TABLE recursion mechanism.
10901  */
10902 static void
ATExecDropConstraint(Relation rel,const char * constrName,DropBehavior behavior,bool recurse,bool recursing,bool missing_ok,LOCKMODE lockmode)10903 ATExecDropConstraint(Relation rel, const char *constrName,
10904 					 DropBehavior behavior,
10905 					 bool recurse, bool recursing,
10906 					 bool missing_ok, LOCKMODE lockmode)
10907 {
10908 	List	   *children;
10909 	ListCell   *child;
10910 	Relation	conrel;
10911 	Form_pg_constraint con;
10912 	SysScanDesc scan;
10913 	ScanKeyData skey[3];
10914 	HeapTuple	tuple;
10915 	bool		found = false;
10916 	bool		is_no_inherit_constraint = false;
10917 	char		contype;
10918 
10919 	/* At top level, permission check was done in ATPrepCmd, else do it */
10920 	if (recursing)
10921 		ATSimplePermissions(rel, ATT_TABLE | ATT_FOREIGN_TABLE);
10922 
10923 	conrel = table_open(ConstraintRelationId, RowExclusiveLock);
10924 
10925 	/*
10926 	 * Find and drop the target constraint
10927 	 */
10928 	ScanKeyInit(&skey[0],
10929 				Anum_pg_constraint_conrelid,
10930 				BTEqualStrategyNumber, F_OIDEQ,
10931 				ObjectIdGetDatum(RelationGetRelid(rel)));
10932 	ScanKeyInit(&skey[1],
10933 				Anum_pg_constraint_contypid,
10934 				BTEqualStrategyNumber, F_OIDEQ,
10935 				ObjectIdGetDatum(InvalidOid));
10936 	ScanKeyInit(&skey[2],
10937 				Anum_pg_constraint_conname,
10938 				BTEqualStrategyNumber, F_NAMEEQ,
10939 				CStringGetDatum(constrName));
10940 	scan = systable_beginscan(conrel, ConstraintRelidTypidNameIndexId,
10941 							  true, NULL, 3, skey);
10942 
10943 	/* There can be at most one matching row */
10944 	if (HeapTupleIsValid(tuple = systable_getnext(scan)))
10945 	{
10946 		ObjectAddress conobj;
10947 
10948 		con = (Form_pg_constraint) GETSTRUCT(tuple);
10949 
10950 		/* Don't drop inherited constraints */
10951 		if (con->coninhcount > 0 && !recursing)
10952 			ereport(ERROR,
10953 					(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
10954 					 errmsg("cannot drop inherited constraint \"%s\" of relation \"%s\"",
10955 							constrName, RelationGetRelationName(rel))));
10956 
10957 		is_no_inherit_constraint = con->connoinherit;
10958 		contype = con->contype;
10959 
10960 		/*
10961 		 * If it's a foreign-key constraint, we'd better lock the referenced
10962 		 * table and check that that's not in use, just as we've already done
10963 		 * for the constrained table (else we might, eg, be dropping a trigger
10964 		 * that has unfired events).  But we can/must skip that in the
10965 		 * self-referential case.
10966 		 */
10967 		if (contype == CONSTRAINT_FOREIGN &&
10968 			con->confrelid != RelationGetRelid(rel))
10969 		{
10970 			Relation	frel;
10971 
10972 			/* Must match lock taken by RemoveTriggerById: */
10973 			frel = table_open(con->confrelid, AccessExclusiveLock);
10974 			CheckTableNotInUse(frel, "ALTER TABLE");
10975 			table_close(frel, NoLock);
10976 		}
10977 
10978 		/*
10979 		 * Perform the actual constraint deletion
10980 		 */
10981 		conobj.classId = ConstraintRelationId;
10982 		conobj.objectId = con->oid;
10983 		conobj.objectSubId = 0;
10984 
10985 		performDeletion(&conobj, behavior, 0);
10986 
10987 		found = true;
10988 	}
10989 
10990 	systable_endscan(scan);
10991 
10992 	if (!found)
10993 	{
10994 		if (!missing_ok)
10995 		{
10996 			ereport(ERROR,
10997 					(errcode(ERRCODE_UNDEFINED_OBJECT),
10998 					 errmsg("constraint \"%s\" of relation \"%s\" does not exist",
10999 							constrName, RelationGetRelationName(rel))));
11000 		}
11001 		else
11002 		{
11003 			ereport(NOTICE,
11004 					(errmsg("constraint \"%s\" of relation \"%s\" does not exist, skipping",
11005 							constrName, RelationGetRelationName(rel))));
11006 			table_close(conrel, RowExclusiveLock);
11007 			return;
11008 		}
11009 	}
11010 
11011 	/*
11012 	 * For partitioned tables, non-CHECK inherited constraints are dropped via
11013 	 * the dependency mechanism, so we're done here.
11014 	 */
11015 	if (contype != CONSTRAINT_CHECK &&
11016 		rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
11017 	{
11018 		table_close(conrel, RowExclusiveLock);
11019 		return;
11020 	}
11021 
11022 	/*
11023 	 * Propagate to children as appropriate.  Unlike most other ALTER
11024 	 * routines, we have to do this one level of recursion at a time; we can't
11025 	 * use find_all_inheritors to do it in one pass.
11026 	 */
11027 	if (!is_no_inherit_constraint)
11028 		children = find_inheritance_children(RelationGetRelid(rel), lockmode);
11029 	else
11030 		children = NIL;
11031 
11032 	/*
11033 	 * For a partitioned table, if partitions exist and we are told not to
11034 	 * recurse, it's a user error.  It doesn't make sense to have a constraint
11035 	 * be defined only on the parent, especially if it's a partitioned table.
11036 	 */
11037 	if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE &&
11038 		children != NIL && !recurse)
11039 		ereport(ERROR,
11040 				(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
11041 				 errmsg("cannot remove constraint from only the partitioned table when partitions exist"),
11042 				 errhint("Do not specify the ONLY keyword.")));
11043 
11044 	foreach(child, children)
11045 	{
11046 		Oid			childrelid = lfirst_oid(child);
11047 		Relation	childrel;
11048 		HeapTuple	copy_tuple;
11049 
11050 		/* find_inheritance_children already got lock */
11051 		childrel = table_open(childrelid, NoLock);
11052 		CheckTableNotInUse(childrel, "ALTER TABLE");
11053 
11054 		ScanKeyInit(&skey[0],
11055 					Anum_pg_constraint_conrelid,
11056 					BTEqualStrategyNumber, F_OIDEQ,
11057 					ObjectIdGetDatum(childrelid));
11058 		ScanKeyInit(&skey[1],
11059 					Anum_pg_constraint_contypid,
11060 					BTEqualStrategyNumber, F_OIDEQ,
11061 					ObjectIdGetDatum(InvalidOid));
11062 		ScanKeyInit(&skey[2],
11063 					Anum_pg_constraint_conname,
11064 					BTEqualStrategyNumber, F_NAMEEQ,
11065 					CStringGetDatum(constrName));
11066 		scan = systable_beginscan(conrel, ConstraintRelidTypidNameIndexId,
11067 								  true, NULL, 3, skey);
11068 
11069 		/* There can be at most one matching row */
11070 		if (!HeapTupleIsValid(tuple = systable_getnext(scan)))
11071 			ereport(ERROR,
11072 					(errcode(ERRCODE_UNDEFINED_OBJECT),
11073 					 errmsg("constraint \"%s\" of relation \"%s\" does not exist",
11074 							constrName,
11075 							RelationGetRelationName(childrel))));
11076 
11077 		copy_tuple = heap_copytuple(tuple);
11078 
11079 		systable_endscan(scan);
11080 
11081 		con = (Form_pg_constraint) GETSTRUCT(copy_tuple);
11082 
11083 		/* Right now only CHECK constraints can be inherited */
11084 		if (con->contype != CONSTRAINT_CHECK)
11085 			elog(ERROR, "inherited constraint is not a CHECK constraint");
11086 
11087 		if (con->coninhcount <= 0)	/* shouldn't happen */
11088 			elog(ERROR, "relation %u has non-inherited constraint \"%s\"",
11089 				 childrelid, constrName);
11090 
11091 		if (recurse)
11092 		{
11093 			/*
11094 			 * If the child constraint has other definition sources, just
11095 			 * decrement its inheritance count; if not, recurse to delete it.
11096 			 */
11097 			if (con->coninhcount == 1 && !con->conislocal)
11098 			{
11099 				/* Time to delete this child constraint, too */
11100 				ATExecDropConstraint(childrel, constrName, behavior,
11101 									 true, true,
11102 									 false, lockmode);
11103 			}
11104 			else
11105 			{
11106 				/* Child constraint must survive my deletion */
11107 				con->coninhcount--;
11108 				CatalogTupleUpdate(conrel, &copy_tuple->t_self, copy_tuple);
11109 
11110 				/* Make update visible */
11111 				CommandCounterIncrement();
11112 			}
11113 		}
11114 		else
11115 		{
11116 			/*
11117 			 * If we were told to drop ONLY in this table (no recursion), we
11118 			 * need to mark the inheritors' constraints as locally defined
11119 			 * rather than inherited.
11120 			 */
11121 			con->coninhcount--;
11122 			con->conislocal = true;
11123 
11124 			CatalogTupleUpdate(conrel, &copy_tuple->t_self, copy_tuple);
11125 
11126 			/* Make update visible */
11127 			CommandCounterIncrement();
11128 		}
11129 
11130 		heap_freetuple(copy_tuple);
11131 
11132 		table_close(childrel, NoLock);
11133 	}
11134 
11135 	table_close(conrel, RowExclusiveLock);
11136 }
11137 
11138 /*
11139  * ALTER COLUMN TYPE
11140  *
11141  * Unlike other subcommand types, we do parse transformation for ALTER COLUMN
11142  * TYPE during phase 1 --- the AlterTableCmd passed in here is already
11143  * transformed (and must be, because we rely on some transformed fields).
11144  *
11145  * The point of this is that the execution of all ALTER COLUMN TYPEs for a
11146  * table will be done "in parallel" during phase 3, so all the USING
11147  * expressions should be parsed assuming the original column types.  Also,
11148  * this allows a USING expression to refer to a field that will be dropped.
11149  *
11150  * To make this work safely, AT_PASS_DROP then AT_PASS_ALTER_TYPE must be
11151  * the first two execution steps in phase 2; they must not see the effects
11152  * of any other subcommand types, since the USING expressions are parsed
11153  * against the unmodified table's state.
11154  */
11155 static void
ATPrepAlterColumnType(List ** wqueue,AlteredTableInfo * tab,Relation rel,bool recurse,bool recursing,AlterTableCmd * cmd,LOCKMODE lockmode,AlterTableUtilityContext * context)11156 ATPrepAlterColumnType(List **wqueue,
11157 					  AlteredTableInfo *tab, Relation rel,
11158 					  bool recurse, bool recursing,
11159 					  AlterTableCmd *cmd, LOCKMODE lockmode,
11160 					  AlterTableUtilityContext *context)
11161 {
11162 	char	   *colName = cmd->name;
11163 	ColumnDef  *def = (ColumnDef *) cmd->def;
11164 	TypeName   *typeName = def->typeName;
11165 	Node	   *transform = def->cooked_default;
11166 	HeapTuple	tuple;
11167 	Form_pg_attribute attTup;
11168 	AttrNumber	attnum;
11169 	Oid			targettype;
11170 	int32		targettypmod;
11171 	Oid			targetcollid;
11172 	NewColumnValue *newval;
11173 	ParseState *pstate = make_parsestate(NULL);
11174 	AclResult	aclresult;
11175 	bool		is_expr;
11176 
11177 	if (rel->rd_rel->reloftype && !recursing)
11178 		ereport(ERROR,
11179 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
11180 				 errmsg("cannot alter column type of typed table")));
11181 
11182 	/* lookup the attribute so we can check inheritance status */
11183 	tuple = SearchSysCacheAttName(RelationGetRelid(rel), colName);
11184 	if (!HeapTupleIsValid(tuple))
11185 		ereport(ERROR,
11186 				(errcode(ERRCODE_UNDEFINED_COLUMN),
11187 				 errmsg("column \"%s\" of relation \"%s\" does not exist",
11188 						colName, RelationGetRelationName(rel))));
11189 	attTup = (Form_pg_attribute) GETSTRUCT(tuple);
11190 	attnum = attTup->attnum;
11191 
11192 	/* Can't alter a system attribute */
11193 	if (attnum <= 0)
11194 		ereport(ERROR,
11195 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
11196 				 errmsg("cannot alter system column \"%s\"",
11197 						colName)));
11198 
11199 	/*
11200 	 * Don't alter inherited columns.  At outer level, there had better not be
11201 	 * any inherited definition; when recursing, we assume this was checked at
11202 	 * the parent level (see below).
11203 	 */
11204 	if (attTup->attinhcount > 0 && !recursing)
11205 		ereport(ERROR,
11206 				(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
11207 				 errmsg("cannot alter inherited column \"%s\"",
11208 						colName)));
11209 
11210 	/* Don't alter columns used in the partition key */
11211 	if (has_partition_attrs(rel,
11212 							bms_make_singleton(attnum - FirstLowInvalidHeapAttributeNumber),
11213 							&is_expr))
11214 		ereport(ERROR,
11215 				(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
11216 				 errmsg("cannot alter column \"%s\" because it is part of the partition key of relation \"%s\"",
11217 						colName, RelationGetRelationName(rel))));
11218 
11219 	/* Look up the target type */
11220 	typenameTypeIdAndMod(NULL, typeName, &targettype, &targettypmod);
11221 
11222 	aclresult = pg_type_aclcheck(targettype, GetUserId(), ACL_USAGE);
11223 	if (aclresult != ACLCHECK_OK)
11224 		aclcheck_error_type(aclresult, targettype);
11225 
11226 	/* And the collation */
11227 	targetcollid = GetColumnDefCollation(NULL, def, targettype);
11228 
11229 	/* make sure datatype is legal for a column */
11230 	CheckAttributeType(colName, targettype, targetcollid,
11231 					   list_make1_oid(rel->rd_rel->reltype),
11232 					   0);
11233 
11234 	if (tab->relkind == RELKIND_RELATION ||
11235 		tab->relkind == RELKIND_PARTITIONED_TABLE)
11236 	{
11237 		/*
11238 		 * Set up an expression to transform the old data value to the new
11239 		 * type. If a USING option was given, use the expression as
11240 		 * transformed by transformAlterTableStmt, else just take the old
11241 		 * value and try to coerce it.  We do this first so that type
11242 		 * incompatibility can be detected before we waste effort, and because
11243 		 * we need the expression to be parsed against the original table row
11244 		 * type.
11245 		 */
11246 		if (!transform)
11247 		{
11248 			transform = (Node *) makeVar(1, attnum,
11249 										 attTup->atttypid, attTup->atttypmod,
11250 										 attTup->attcollation,
11251 										 0);
11252 		}
11253 
11254 		transform = coerce_to_target_type(pstate,
11255 										  transform, exprType(transform),
11256 										  targettype, targettypmod,
11257 										  COERCION_ASSIGNMENT,
11258 										  COERCE_IMPLICIT_CAST,
11259 										  -1);
11260 		if (transform == NULL)
11261 		{
11262 			/* error text depends on whether USING was specified or not */
11263 			if (def->cooked_default != NULL)
11264 				ereport(ERROR,
11265 						(errcode(ERRCODE_DATATYPE_MISMATCH),
11266 						 errmsg("result of USING clause for column \"%s\""
11267 								" cannot be cast automatically to type %s",
11268 								colName, format_type_be(targettype)),
11269 						 errhint("You might need to add an explicit cast.")));
11270 			else
11271 				ereport(ERROR,
11272 						(errcode(ERRCODE_DATATYPE_MISMATCH),
11273 						 errmsg("column \"%s\" cannot be cast automatically to type %s",
11274 								colName, format_type_be(targettype)),
11275 				/* translator: USING is SQL, don't translate it */
11276 						 errhint("You might need to specify \"USING %s::%s\".",
11277 								 quote_identifier(colName),
11278 								 format_type_with_typemod(targettype,
11279 														  targettypmod))));
11280 		}
11281 
11282 		/* Fix collations after all else */
11283 		assign_expr_collations(pstate, transform);
11284 
11285 		/* Plan the expr now so we can accurately assess the need to rewrite. */
11286 		transform = (Node *) expression_planner((Expr *) transform);
11287 
11288 		/*
11289 		 * Add a work queue item to make ATRewriteTable update the column
11290 		 * contents.
11291 		 */
11292 		newval = (NewColumnValue *) palloc0(sizeof(NewColumnValue));
11293 		newval->attnum = attnum;
11294 		newval->expr = (Expr *) transform;
11295 		newval->is_generated = false;
11296 
11297 		tab->newvals = lappend(tab->newvals, newval);
11298 		if (ATColumnChangeRequiresRewrite(transform, attnum))
11299 			tab->rewrite |= AT_REWRITE_COLUMN_REWRITE;
11300 	}
11301 	else if (transform)
11302 		ereport(ERROR,
11303 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
11304 				 errmsg("\"%s\" is not a table",
11305 						RelationGetRelationName(rel))));
11306 
11307 	if (tab->relkind == RELKIND_COMPOSITE_TYPE ||
11308 		tab->relkind == RELKIND_FOREIGN_TABLE)
11309 	{
11310 		/*
11311 		 * For composite types, do this check now.  Tables will check it later
11312 		 * when the table is being rewritten.
11313 		 */
11314 		find_composite_type_dependencies(rel->rd_rel->reltype, rel, NULL);
11315 	}
11316 
11317 	ReleaseSysCache(tuple);
11318 
11319 	/*
11320 	 * Recurse manually by queueing a new command for each child, if
11321 	 * necessary. We cannot apply ATSimpleRecursion here because we need to
11322 	 * remap attribute numbers in the USING expression, if any.
11323 	 *
11324 	 * If we are told not to recurse, there had better not be any child
11325 	 * tables; else the alter would put them out of step.
11326 	 */
11327 	if (recurse)
11328 	{
11329 		Oid			relid = RelationGetRelid(rel);
11330 		List	   *child_oids,
11331 				   *child_numparents;
11332 		ListCell   *lo,
11333 				   *li;
11334 
11335 		child_oids = find_all_inheritors(relid, lockmode,
11336 										 &child_numparents);
11337 
11338 		/*
11339 		 * find_all_inheritors does the recursive search of the inheritance
11340 		 * hierarchy, so all we have to do is process all of the relids in the
11341 		 * list that it returns.
11342 		 */
11343 		forboth(lo, child_oids, li, child_numparents)
11344 		{
11345 			Oid			childrelid = lfirst_oid(lo);
11346 			int			numparents = lfirst_int(li);
11347 			Relation	childrel;
11348 			HeapTuple	childtuple;
11349 			Form_pg_attribute childattTup;
11350 
11351 			if (childrelid == relid)
11352 				continue;
11353 
11354 			/* find_all_inheritors already got lock */
11355 			childrel = relation_open(childrelid, NoLock);
11356 			CheckTableNotInUse(childrel, "ALTER TABLE");
11357 
11358 			/*
11359 			 * Verify that the child doesn't have any inherited definitions of
11360 			 * this column that came from outside this inheritance hierarchy.
11361 			 * (renameatt makes a similar test, though in a different way
11362 			 * because of its different recursion mechanism.)
11363 			 */
11364 			childtuple = SearchSysCacheAttName(RelationGetRelid(childrel),
11365 											   colName);
11366 			if (!HeapTupleIsValid(childtuple))
11367 				ereport(ERROR,
11368 						(errcode(ERRCODE_UNDEFINED_COLUMN),
11369 						 errmsg("column \"%s\" of relation \"%s\" does not exist",
11370 								colName, RelationGetRelationName(childrel))));
11371 			childattTup = (Form_pg_attribute) GETSTRUCT(childtuple);
11372 
11373 			if (childattTup->attinhcount > numparents)
11374 				ereport(ERROR,
11375 						(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
11376 						 errmsg("cannot alter inherited column \"%s\" of relation \"%s\"",
11377 								colName, RelationGetRelationName(childrel))));
11378 
11379 			ReleaseSysCache(childtuple);
11380 
11381 			/*
11382 			 * Remap the attribute numbers.  If no USING expression was
11383 			 * specified, there is no need for this step.
11384 			 */
11385 			if (def->cooked_default)
11386 			{
11387 				AttrMap    *attmap;
11388 				bool		found_whole_row;
11389 
11390 				/* create a copy to scribble on */
11391 				cmd = copyObject(cmd);
11392 
11393 				attmap = build_attrmap_by_name(RelationGetDescr(childrel),
11394 											   RelationGetDescr(rel));
11395 				((ColumnDef *) cmd->def)->cooked_default =
11396 					map_variable_attnos(def->cooked_default,
11397 										1, 0,
11398 										attmap,
11399 										InvalidOid, &found_whole_row);
11400 				if (found_whole_row)
11401 					ereport(ERROR,
11402 							(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
11403 							 errmsg("cannot convert whole-row table reference"),
11404 							 errdetail("USING expression contains a whole-row table reference.")));
11405 				pfree(attmap);
11406 			}
11407 			ATPrepCmd(wqueue, childrel, cmd, false, true, lockmode, context);
11408 			relation_close(childrel, NoLock);
11409 		}
11410 	}
11411 	else if (!recursing &&
11412 			 find_inheritance_children(RelationGetRelid(rel), NoLock) != NIL)
11413 		ereport(ERROR,
11414 				(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
11415 				 errmsg("type of inherited column \"%s\" must be changed in child tables too",
11416 						colName)));
11417 
11418 	if (tab->relkind == RELKIND_COMPOSITE_TYPE)
11419 		ATTypedTableRecursion(wqueue, rel, cmd, lockmode, context);
11420 }
11421 
11422 /*
11423  * When the data type of a column is changed, a rewrite might not be required
11424  * if the new type is sufficiently identical to the old one, and the USING
11425  * clause isn't trying to insert some other value.  It's safe to skip the
11426  * rewrite in these cases:
11427  *
11428  * - the old type is binary coercible to the new type
11429  * - the new type is an unconstrained domain over the old type
11430  * - {NEW,OLD} or {OLD,NEW} is {timestamptz,timestamp} and the timezone is UTC
11431  *
11432  * In the case of a constrained domain, we could get by with scanning the
11433  * table and checking the constraint rather than actually rewriting it, but we
11434  * don't currently try to do that.
11435  */
11436 static bool
ATColumnChangeRequiresRewrite(Node * expr,AttrNumber varattno)11437 ATColumnChangeRequiresRewrite(Node *expr, AttrNumber varattno)
11438 {
11439 	Assert(expr != NULL);
11440 
11441 	for (;;)
11442 	{
11443 		/* only one varno, so no need to check that */
11444 		if (IsA(expr, Var) && ((Var *) expr)->varattno == varattno)
11445 			return false;
11446 		else if (IsA(expr, RelabelType))
11447 			expr = (Node *) ((RelabelType *) expr)->arg;
11448 		else if (IsA(expr, CoerceToDomain))
11449 		{
11450 			CoerceToDomain *d = (CoerceToDomain *) expr;
11451 
11452 			if (DomainHasConstraints(d->resulttype))
11453 				return true;
11454 			expr = (Node *) d->arg;
11455 		}
11456 		else if (IsA(expr, FuncExpr))
11457 		{
11458 			FuncExpr   *f = (FuncExpr *) expr;
11459 
11460 			switch (f->funcid)
11461 			{
11462 				case F_TIMESTAMPTZ_TIMESTAMP:
11463 				case F_TIMESTAMP_TIMESTAMPTZ:
11464 					if (TimestampTimestampTzRequiresRewrite())
11465 						return true;
11466 					else
11467 						expr = linitial(f->args);
11468 					break;
11469 				default:
11470 					return true;
11471 			}
11472 		}
11473 		else
11474 			return true;
11475 	}
11476 }
11477 
11478 /*
11479  * ALTER COLUMN .. SET DATA TYPE
11480  *
11481  * Return the address of the modified column.
11482  */
11483 static ObjectAddress
ATExecAlterColumnType(AlteredTableInfo * tab,Relation rel,AlterTableCmd * cmd,LOCKMODE lockmode)11484 ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel,
11485 					  AlterTableCmd *cmd, LOCKMODE lockmode)
11486 {
11487 	char	   *colName = cmd->name;
11488 	ColumnDef  *def = (ColumnDef *) cmd->def;
11489 	TypeName   *typeName = def->typeName;
11490 	HeapTuple	heapTup;
11491 	Form_pg_attribute attTup,
11492 				attOldTup;
11493 	AttrNumber	attnum;
11494 	HeapTuple	typeTuple;
11495 	Form_pg_type tform;
11496 	Oid			targettype;
11497 	int32		targettypmod;
11498 	Oid			targetcollid;
11499 	Node	   *defaultexpr;
11500 	Relation	attrelation;
11501 	Relation	depRel;
11502 	ScanKeyData key[3];
11503 	SysScanDesc scan;
11504 	HeapTuple	depTup;
11505 	ObjectAddress address;
11506 
11507 	/*
11508 	 * Clear all the missing values if we're rewriting the table, since this
11509 	 * renders them pointless.
11510 	 */
11511 	if (tab->rewrite)
11512 	{
11513 		Relation	newrel;
11514 
11515 		newrel = table_open(RelationGetRelid(rel), NoLock);
11516 		RelationClearMissing(newrel);
11517 		relation_close(newrel, NoLock);
11518 		/* make sure we don't conflict with later attribute modifications */
11519 		CommandCounterIncrement();
11520 	}
11521 
11522 	attrelation = table_open(AttributeRelationId, RowExclusiveLock);
11523 
11524 	/* Look up the target column */
11525 	heapTup = SearchSysCacheCopyAttName(RelationGetRelid(rel), colName);
11526 	if (!HeapTupleIsValid(heapTup)) /* shouldn't happen */
11527 		ereport(ERROR,
11528 				(errcode(ERRCODE_UNDEFINED_COLUMN),
11529 				 errmsg("column \"%s\" of relation \"%s\" does not exist",
11530 						colName, RelationGetRelationName(rel))));
11531 	attTup = (Form_pg_attribute) GETSTRUCT(heapTup);
11532 	attnum = attTup->attnum;
11533 	attOldTup = TupleDescAttr(tab->oldDesc, attnum - 1);
11534 
11535 	/* Check for multiple ALTER TYPE on same column --- can't cope */
11536 	if (attTup->atttypid != attOldTup->atttypid ||
11537 		attTup->atttypmod != attOldTup->atttypmod)
11538 		ereport(ERROR,
11539 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
11540 				 errmsg("cannot alter type of column \"%s\" twice",
11541 						colName)));
11542 
11543 	/* Look up the target type (should not fail, since prep found it) */
11544 	typeTuple = typenameType(NULL, typeName, &targettypmod);
11545 	tform = (Form_pg_type) GETSTRUCT(typeTuple);
11546 	targettype = tform->oid;
11547 	/* And the collation */
11548 	targetcollid = GetColumnDefCollation(NULL, def, targettype);
11549 
11550 	/*
11551 	 * If there is a default expression for the column, get it and ensure we
11552 	 * can coerce it to the new datatype.  (We must do this before changing
11553 	 * the column type, because build_column_default itself will try to
11554 	 * coerce, and will not issue the error message we want if it fails.)
11555 	 *
11556 	 * We remove any implicit coercion steps at the top level of the old
11557 	 * default expression; this has been agreed to satisfy the principle of
11558 	 * least surprise.  (The conversion to the new column type should act like
11559 	 * it started from what the user sees as the stored expression, and the
11560 	 * implicit coercions aren't going to be shown.)
11561 	 */
11562 	if (attTup->atthasdef)
11563 	{
11564 		defaultexpr = build_column_default(rel, attnum);
11565 		Assert(defaultexpr);
11566 		defaultexpr = strip_implicit_coercions(defaultexpr);
11567 		defaultexpr = coerce_to_target_type(NULL,	/* no UNKNOWN params */
11568 											defaultexpr, exprType(defaultexpr),
11569 											targettype, targettypmod,
11570 											COERCION_ASSIGNMENT,
11571 											COERCE_IMPLICIT_CAST,
11572 											-1);
11573 		if (defaultexpr == NULL)
11574 		{
11575 			if (attTup->attgenerated)
11576 				ereport(ERROR,
11577 						(errcode(ERRCODE_DATATYPE_MISMATCH),
11578 						 errmsg("generation expression for column \"%s\" cannot be cast automatically to type %s",
11579 								colName, format_type_be(targettype))));
11580 			else
11581 				ereport(ERROR,
11582 						(errcode(ERRCODE_DATATYPE_MISMATCH),
11583 						 errmsg("default for column \"%s\" cannot be cast automatically to type %s",
11584 								colName, format_type_be(targettype))));
11585 		}
11586 	}
11587 	else
11588 		defaultexpr = NULL;
11589 
11590 	/*
11591 	 * Find everything that depends on the column (constraints, indexes, etc),
11592 	 * and record enough information to let us recreate the objects.
11593 	 *
11594 	 * The actual recreation does not happen here, but only after we have
11595 	 * performed all the individual ALTER TYPE operations.  We have to save
11596 	 * the info before executing ALTER TYPE, though, else the deparser will
11597 	 * get confused.
11598 	 */
11599 	depRel = table_open(DependRelationId, RowExclusiveLock);
11600 
11601 	ScanKeyInit(&key[0],
11602 				Anum_pg_depend_refclassid,
11603 				BTEqualStrategyNumber, F_OIDEQ,
11604 				ObjectIdGetDatum(RelationRelationId));
11605 	ScanKeyInit(&key[1],
11606 				Anum_pg_depend_refobjid,
11607 				BTEqualStrategyNumber, F_OIDEQ,
11608 				ObjectIdGetDatum(RelationGetRelid(rel)));
11609 	ScanKeyInit(&key[2],
11610 				Anum_pg_depend_refobjsubid,
11611 				BTEqualStrategyNumber, F_INT4EQ,
11612 				Int32GetDatum((int32) attnum));
11613 
11614 	scan = systable_beginscan(depRel, DependReferenceIndexId, true,
11615 							  NULL, 3, key);
11616 
11617 	while (HeapTupleIsValid(depTup = systable_getnext(scan)))
11618 	{
11619 		Form_pg_depend foundDep = (Form_pg_depend) GETSTRUCT(depTup);
11620 		ObjectAddress foundObject;
11621 
11622 		/* We don't expect any PIN dependencies on columns */
11623 		if (foundDep->deptype == DEPENDENCY_PIN)
11624 			elog(ERROR, "cannot alter type of a pinned column");
11625 
11626 		foundObject.classId = foundDep->classid;
11627 		foundObject.objectId = foundDep->objid;
11628 		foundObject.objectSubId = foundDep->objsubid;
11629 
11630 		switch (getObjectClass(&foundObject))
11631 		{
11632 			case OCLASS_CLASS:
11633 				{
11634 					char		relKind = get_rel_relkind(foundObject.objectId);
11635 
11636 					if (relKind == RELKIND_INDEX ||
11637 						relKind == RELKIND_PARTITIONED_INDEX)
11638 					{
11639 						Assert(foundObject.objectSubId == 0);
11640 						RememberIndexForRebuilding(foundObject.objectId, tab);
11641 					}
11642 					else if (relKind == RELKIND_SEQUENCE)
11643 					{
11644 						/*
11645 						 * This must be a SERIAL column's sequence.  We need
11646 						 * not do anything to it.
11647 						 */
11648 						Assert(foundObject.objectSubId == 0);
11649 					}
11650 					else if (relKind == RELKIND_RELATION &&
11651 							 foundObject.objectSubId != 0 &&
11652 							 get_attgenerated(foundObject.objectId, foundObject.objectSubId))
11653 					{
11654 						/*
11655 						 * Changing the type of a column that is used by a
11656 						 * generated column is not allowed by SQL standard. It
11657 						 * might be doable with some thinking and effort.
11658 						 */
11659 						ereport(ERROR,
11660 								(errcode(ERRCODE_SYNTAX_ERROR),
11661 								 errmsg("cannot alter type of a column used by a generated column"),
11662 								 errdetail("Column \"%s\" is used by generated column \"%s\".",
11663 										   colName, get_attname(foundObject.objectId, foundObject.objectSubId, false))));
11664 					}
11665 					else
11666 					{
11667 						/* Not expecting any other direct dependencies... */
11668 						elog(ERROR, "unexpected object depending on column: %s",
11669 							 getObjectDescription(&foundObject));
11670 					}
11671 					break;
11672 				}
11673 
11674 			case OCLASS_CONSTRAINT:
11675 				Assert(foundObject.objectSubId == 0);
11676 				RememberConstraintForRebuilding(foundObject.objectId, tab);
11677 				break;
11678 
11679 			case OCLASS_REWRITE:
11680 				/* XXX someday see if we can cope with revising views */
11681 				ereport(ERROR,
11682 						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
11683 						 errmsg("cannot alter type of a column used by a view or rule"),
11684 						 errdetail("%s depends on column \"%s\"",
11685 								   getObjectDescription(&foundObject),
11686 								   colName)));
11687 				break;
11688 
11689 			case OCLASS_TRIGGER:
11690 
11691 				/*
11692 				 * A trigger can depend on a column because the column is
11693 				 * specified as an update target, or because the column is
11694 				 * used in the trigger's WHEN condition.  The first case would
11695 				 * not require any extra work, but the second case would
11696 				 * require updating the WHEN expression, which will take a
11697 				 * significant amount of new code.  Since we can't easily tell
11698 				 * which case applies, we punt for both.  FIXME someday.
11699 				 */
11700 				ereport(ERROR,
11701 						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
11702 						 errmsg("cannot alter type of a column used in a trigger definition"),
11703 						 errdetail("%s depends on column \"%s\"",
11704 								   getObjectDescription(&foundObject),
11705 								   colName)));
11706 				break;
11707 
11708 			case OCLASS_POLICY:
11709 
11710 				/*
11711 				 * A policy can depend on a column because the column is
11712 				 * specified in the policy's USING or WITH CHECK qual
11713 				 * expressions.  It might be possible to rewrite and recheck
11714 				 * the policy expression, but punt for now.  It's certainly
11715 				 * easy enough to remove and recreate the policy; still, FIXME
11716 				 * someday.
11717 				 */
11718 				ereport(ERROR,
11719 						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
11720 						 errmsg("cannot alter type of a column used in a policy definition"),
11721 						 errdetail("%s depends on column \"%s\"",
11722 								   getObjectDescription(&foundObject),
11723 								   colName)));
11724 				break;
11725 
11726 			case OCLASS_DEFAULT:
11727 
11728 				/*
11729 				 * Ignore the column's default expression, since we will fix
11730 				 * it below.
11731 				 */
11732 				Assert(defaultexpr);
11733 				break;
11734 
11735 			case OCLASS_STATISTIC_EXT:
11736 
11737 				/*
11738 				 * Give the extended-stats machinery a chance to fix anything
11739 				 * that this column type change would break.
11740 				 */
11741 				UpdateStatisticsForTypeChange(foundObject.objectId,
11742 											  RelationGetRelid(rel), attnum,
11743 											  attTup->atttypid, targettype);
11744 				break;
11745 
11746 			case OCLASS_PROC:
11747 			case OCLASS_TYPE:
11748 			case OCLASS_CAST:
11749 			case OCLASS_COLLATION:
11750 			case OCLASS_CONVERSION:
11751 			case OCLASS_LANGUAGE:
11752 			case OCLASS_LARGEOBJECT:
11753 			case OCLASS_OPERATOR:
11754 			case OCLASS_OPCLASS:
11755 			case OCLASS_OPFAMILY:
11756 			case OCLASS_AM:
11757 			case OCLASS_AMOP:
11758 			case OCLASS_AMPROC:
11759 			case OCLASS_SCHEMA:
11760 			case OCLASS_TSPARSER:
11761 			case OCLASS_TSDICT:
11762 			case OCLASS_TSTEMPLATE:
11763 			case OCLASS_TSCONFIG:
11764 			case OCLASS_ROLE:
11765 			case OCLASS_DATABASE:
11766 			case OCLASS_TBLSPACE:
11767 			case OCLASS_FDW:
11768 			case OCLASS_FOREIGN_SERVER:
11769 			case OCLASS_USER_MAPPING:
11770 			case OCLASS_DEFACL:
11771 			case OCLASS_EXTENSION:
11772 			case OCLASS_EVENT_TRIGGER:
11773 			case OCLASS_PUBLICATION:
11774 			case OCLASS_PUBLICATION_REL:
11775 			case OCLASS_SUBSCRIPTION:
11776 			case OCLASS_TRANSFORM:
11777 
11778 				/*
11779 				 * We don't expect any of these sorts of objects to depend on
11780 				 * a column.
11781 				 */
11782 				elog(ERROR, "unexpected object depending on column: %s",
11783 					 getObjectDescription(&foundObject));
11784 				break;
11785 
11786 				/*
11787 				 * There's intentionally no default: case here; we want the
11788 				 * compiler to warn if a new OCLASS hasn't been handled above.
11789 				 */
11790 		}
11791 	}
11792 
11793 	systable_endscan(scan);
11794 
11795 	/*
11796 	 * Now scan for dependencies of this column on other things.  The only
11797 	 * thing we should find is the dependency on the column datatype, which we
11798 	 * want to remove, possibly a collation dependency, and dependencies on
11799 	 * other columns if it is a generated column.
11800 	 */
11801 	ScanKeyInit(&key[0],
11802 				Anum_pg_depend_classid,
11803 				BTEqualStrategyNumber, F_OIDEQ,
11804 				ObjectIdGetDatum(RelationRelationId));
11805 	ScanKeyInit(&key[1],
11806 				Anum_pg_depend_objid,
11807 				BTEqualStrategyNumber, F_OIDEQ,
11808 				ObjectIdGetDatum(RelationGetRelid(rel)));
11809 	ScanKeyInit(&key[2],
11810 				Anum_pg_depend_objsubid,
11811 				BTEqualStrategyNumber, F_INT4EQ,
11812 				Int32GetDatum((int32) attnum));
11813 
11814 	scan = systable_beginscan(depRel, DependDependerIndexId, true,
11815 							  NULL, 3, key);
11816 
11817 	while (HeapTupleIsValid(depTup = systable_getnext(scan)))
11818 	{
11819 		Form_pg_depend foundDep = (Form_pg_depend) GETSTRUCT(depTup);
11820 		ObjectAddress foundObject;
11821 
11822 		foundObject.classId = foundDep->refclassid;
11823 		foundObject.objectId = foundDep->refobjid;
11824 		foundObject.objectSubId = foundDep->refobjsubid;
11825 
11826 		if (foundDep->deptype != DEPENDENCY_NORMAL &&
11827 			foundDep->deptype != DEPENDENCY_AUTO)
11828 			elog(ERROR, "found unexpected dependency type '%c'",
11829 				 foundDep->deptype);
11830 		if (!(foundDep->refclassid == TypeRelationId &&
11831 			  foundDep->refobjid == attTup->atttypid) &&
11832 			!(foundDep->refclassid == CollationRelationId &&
11833 			  foundDep->refobjid == attTup->attcollation) &&
11834 			!(foundDep->refclassid == RelationRelationId &&
11835 			  foundDep->refobjid == RelationGetRelid(rel) &&
11836 			  foundDep->refobjsubid != 0)
11837 			)
11838 			elog(ERROR, "found unexpected dependency for column: %s",
11839 				 getObjectDescription(&foundObject));
11840 
11841 		CatalogTupleDelete(depRel, &depTup->t_self);
11842 	}
11843 
11844 	systable_endscan(scan);
11845 
11846 	table_close(depRel, RowExclusiveLock);
11847 
11848 	/*
11849 	 * Here we go --- change the recorded column type and collation.  (Note
11850 	 * heapTup is a copy of the syscache entry, so okay to scribble on.) First
11851 	 * fix up the missing value if any. There shouldn't be any missing values
11852 	 * for anything except plain tables, but if there are, ignore them.
11853 	 */
11854 	if (rel->rd_rel->relkind == RELKIND_RELATION  && attTup->atthasmissing)
11855 	{
11856 		Datum		missingval;
11857 		bool		missingNull;
11858 
11859 		/* if rewrite is true the missing value should already be cleared */
11860 		Assert(tab->rewrite == 0);
11861 
11862 		/* Get the missing value datum */
11863 		missingval = heap_getattr(heapTup,
11864 								  Anum_pg_attribute_attmissingval,
11865 								  attrelation->rd_att,
11866 								  &missingNull);
11867 
11868 		/* if it's a null array there is nothing to do */
11869 
11870 		if (!missingNull)
11871 		{
11872 			/*
11873 			 * Get the datum out of the array and repack it in a new array
11874 			 * built with the new type data. We assume that since the table
11875 			 * doesn't need rewriting, the actual Datum doesn't need to be
11876 			 * changed, only the array metadata.
11877 			 */
11878 
11879 			int			one = 1;
11880 			bool		isNull;
11881 			Datum		valuesAtt[Natts_pg_attribute];
11882 			bool		nullsAtt[Natts_pg_attribute];
11883 			bool		replacesAtt[Natts_pg_attribute];
11884 			HeapTuple	newTup;
11885 
11886 			MemSet(valuesAtt, 0, sizeof(valuesAtt));
11887 			MemSet(nullsAtt, false, sizeof(nullsAtt));
11888 			MemSet(replacesAtt, false, sizeof(replacesAtt));
11889 
11890 			missingval = array_get_element(missingval,
11891 										   1,
11892 										   &one,
11893 										   0,
11894 										   attTup->attlen,
11895 										   attTup->attbyval,
11896 										   attTup->attalign,
11897 										   &isNull);
11898 			missingval = PointerGetDatum(construct_array(&missingval,
11899 														 1,
11900 														 targettype,
11901 														 tform->typlen,
11902 														 tform->typbyval,
11903 														 tform->typalign));
11904 
11905 			valuesAtt[Anum_pg_attribute_attmissingval - 1] = missingval;
11906 			replacesAtt[Anum_pg_attribute_attmissingval - 1] = true;
11907 			nullsAtt[Anum_pg_attribute_attmissingval - 1] = false;
11908 
11909 			newTup = heap_modify_tuple(heapTup, RelationGetDescr(attrelation),
11910 									   valuesAtt, nullsAtt, replacesAtt);
11911 			heap_freetuple(heapTup);
11912 			heapTup = newTup;
11913 			attTup = (Form_pg_attribute) GETSTRUCT(heapTup);
11914 		}
11915 	}
11916 
11917 	attTup->atttypid = targettype;
11918 	attTup->atttypmod = targettypmod;
11919 	attTup->attcollation = targetcollid;
11920 	attTup->attndims = list_length(typeName->arrayBounds);
11921 	attTup->attlen = tform->typlen;
11922 	attTup->attbyval = tform->typbyval;
11923 	attTup->attalign = tform->typalign;
11924 	attTup->attstorage = tform->typstorage;
11925 
11926 	ReleaseSysCache(typeTuple);
11927 
11928 	CatalogTupleUpdate(attrelation, &heapTup->t_self, heapTup);
11929 
11930 	table_close(attrelation, RowExclusiveLock);
11931 
11932 	/* Install dependencies on new datatype and collation */
11933 	add_column_datatype_dependency(RelationGetRelid(rel), attnum, targettype);
11934 	add_column_collation_dependency(RelationGetRelid(rel), attnum, targetcollid);
11935 
11936 	/*
11937 	 * Drop any pg_statistic entry for the column, since it's now wrong type
11938 	 */
11939 	RemoveStatistics(RelationGetRelid(rel), attnum);
11940 
11941 	InvokeObjectPostAlterHook(RelationRelationId,
11942 							  RelationGetRelid(rel), attnum);
11943 
11944 	/*
11945 	 * Update the default, if present, by brute force --- remove and re-add
11946 	 * the default.  Probably unsafe to take shortcuts, since the new version
11947 	 * may well have additional dependencies.  (It's okay to do this now,
11948 	 * rather than after other ALTER TYPE commands, since the default won't
11949 	 * depend on other column types.)
11950 	 */
11951 	if (defaultexpr)
11952 	{
11953 		/* Must make new row visible since it will be updated again */
11954 		CommandCounterIncrement();
11955 
11956 		/*
11957 		 * We use RESTRICT here for safety, but at present we do not expect
11958 		 * anything to depend on the default.
11959 		 */
11960 		RemoveAttrDefault(RelationGetRelid(rel), attnum, DROP_RESTRICT, true,
11961 						  true);
11962 
11963 		StoreAttrDefault(rel, attnum, defaultexpr, true, false);
11964 	}
11965 
11966 	ObjectAddressSubSet(address, RelationRelationId,
11967 						RelationGetRelid(rel), attnum);
11968 
11969 	/* Cleanup */
11970 	heap_freetuple(heapTup);
11971 
11972 	return address;
11973 }
11974 
11975 /*
11976  * Subroutine for ATExecAlterColumnType: remember that a replica identity
11977  * needs to be reset.
11978  */
11979 static void
RememberReplicaIdentityForRebuilding(Oid indoid,AlteredTableInfo * tab)11980 RememberReplicaIdentityForRebuilding(Oid indoid, AlteredTableInfo *tab)
11981 {
11982 	if (!get_index_isreplident(indoid))
11983 		return;
11984 
11985 	if (tab->replicaIdentityIndex)
11986 		elog(ERROR, "relation %u has multiple indexes marked as replica identity", tab->relid);
11987 
11988 	tab->replicaIdentityIndex = get_rel_name(indoid);
11989 }
11990 
11991 /*
11992  * Subroutine for ATExecAlterColumnType: remember any clustered index.
11993  */
11994 static void
RememberClusterOnForRebuilding(Oid indoid,AlteredTableInfo * tab)11995 RememberClusterOnForRebuilding(Oid indoid, AlteredTableInfo *tab)
11996 {
11997 	if (!get_index_isclustered(indoid))
11998 		return;
11999 
12000 	if (tab->clusterOnIndex)
12001 		elog(ERROR, "relation %u has multiple clustered indexes", tab->relid);
12002 
12003 	tab->clusterOnIndex = get_rel_name(indoid);
12004 }
12005 
12006 /*
12007  * Subroutine for ATExecAlterColumnType: remember that a constraint needs
12008  * to be rebuilt (which we might already know).
12009  */
12010 static void
RememberConstraintForRebuilding(Oid conoid,AlteredTableInfo * tab)12011 RememberConstraintForRebuilding(Oid conoid, AlteredTableInfo *tab)
12012 {
12013 	/*
12014 	 * This de-duplication check is critical for two independent reasons: we
12015 	 * mustn't try to recreate the same constraint twice, and if a constraint
12016 	 * depends on more than one column whose type is to be altered, we must
12017 	 * capture its definition string before applying any of the column type
12018 	 * changes.  ruleutils.c will get confused if we ask again later.
12019 	 */
12020 	if (!list_member_oid(tab->changedConstraintOids, conoid))
12021 	{
12022 		/* OK, capture the constraint's existing definition string */
12023 		char	   *defstring = pg_get_constraintdef_command(conoid);
12024 		Oid			indoid;
12025 
12026 		tab->changedConstraintOids = lappend_oid(tab->changedConstraintOids,
12027 												 conoid);
12028 		tab->changedConstraintDefs = lappend(tab->changedConstraintDefs,
12029 											 defstring);
12030 
12031 		/*
12032 		 * For the index of a constraint, if any, remember if it is used for
12033 		 * the table's replica identity or if it is a clustered index, so that
12034 		 * ATPostAlterTypeCleanup() can queue up commands necessary to restore
12035 		 * those properties.
12036 		 */
12037 		indoid = get_constraint_index(conoid);
12038 		if (OidIsValid(indoid))
12039 		{
12040 			RememberReplicaIdentityForRebuilding(indoid, tab);
12041 			RememberClusterOnForRebuilding(indoid, tab);
12042 		}
12043 	}
12044 }
12045 
12046 /*
12047  * Subroutine for ATExecAlterColumnType: remember that an index needs
12048  * to be rebuilt (which we might already know).
12049  */
12050 static void
RememberIndexForRebuilding(Oid indoid,AlteredTableInfo * tab)12051 RememberIndexForRebuilding(Oid indoid, AlteredTableInfo *tab)
12052 {
12053 	/*
12054 	 * This de-duplication check is critical for two independent reasons: we
12055 	 * mustn't try to recreate the same index twice, and if an index depends
12056 	 * on more than one column whose type is to be altered, we must capture
12057 	 * its definition string before applying any of the column type changes.
12058 	 * ruleutils.c will get confused if we ask again later.
12059 	 */
12060 	if (!list_member_oid(tab->changedIndexOids, indoid))
12061 	{
12062 		/*
12063 		 * Before adding it as an index-to-rebuild, we'd better see if it
12064 		 * belongs to a constraint, and if so rebuild the constraint instead.
12065 		 * Typically this check fails, because constraint indexes normally
12066 		 * have only dependencies on their constraint.  But it's possible for
12067 		 * such an index to also have direct dependencies on table columns,
12068 		 * for example with a partial exclusion constraint.
12069 		 */
12070 		Oid			conoid = get_index_constraint(indoid);
12071 
12072 		if (OidIsValid(conoid))
12073 		{
12074 			RememberConstraintForRebuilding(conoid, tab);
12075 		}
12076 		else
12077 		{
12078 			/* OK, capture the index's existing definition string */
12079 			char	   *defstring = pg_get_indexdef_string(indoid);
12080 
12081 			tab->changedIndexOids = lappend_oid(tab->changedIndexOids,
12082 												indoid);
12083 			tab->changedIndexDefs = lappend(tab->changedIndexDefs,
12084 											defstring);
12085 
12086 			/*
12087 			 * Remember if this index is used for the table's replica identity
12088 			 * or if it is a clustered index, so that ATPostAlterTypeCleanup()
12089 			 * can queue up commands necessary to restore those properties.
12090 			 */
12091 			RememberReplicaIdentityForRebuilding(indoid, tab);
12092 			RememberClusterOnForRebuilding(indoid, tab);
12093 		}
12094 	}
12095 }
12096 
12097 /*
12098  * Cleanup after we've finished all the ALTER TYPE operations for a
12099  * particular relation.  We have to drop and recreate all the indexes
12100  * and constraints that depend on the altered columns.  We do the
12101  * actual dropping here, but re-creation is managed by adding work
12102  * queue entries to do those steps later.
12103  */
12104 static void
ATPostAlterTypeCleanup(List ** wqueue,AlteredTableInfo * tab,LOCKMODE lockmode)12105 ATPostAlterTypeCleanup(List **wqueue, AlteredTableInfo *tab, LOCKMODE lockmode)
12106 {
12107 	ObjectAddress obj;
12108 	ObjectAddresses *objects;
12109 	ListCell   *def_item;
12110 	ListCell   *oid_item;
12111 
12112 	/*
12113 	 * Collect all the constraints and indexes to drop so we can process them
12114 	 * in a single call.  That way we don't have to worry about dependencies
12115 	 * among them.
12116 	 */
12117 	objects = new_object_addresses();
12118 
12119 	/*
12120 	 * Re-parse the index and constraint definitions, and attach them to the
12121 	 * appropriate work queue entries.  We do this before dropping because in
12122 	 * the case of a FOREIGN KEY constraint, we might not yet have exclusive
12123 	 * lock on the table the constraint is attached to, and we need to get
12124 	 * that before reparsing/dropping.
12125 	 *
12126 	 * We can't rely on the output of deparsing to tell us which relation to
12127 	 * operate on, because concurrent activity might have made the name
12128 	 * resolve differently.  Instead, we've got to use the OID of the
12129 	 * constraint or index we're processing to figure out which relation to
12130 	 * operate on.
12131 	 */
12132 	forboth(oid_item, tab->changedConstraintOids,
12133 			def_item, tab->changedConstraintDefs)
12134 	{
12135 		Oid			oldId = lfirst_oid(oid_item);
12136 		HeapTuple	tup;
12137 		Form_pg_constraint con;
12138 		Oid			relid;
12139 		Oid			confrelid;
12140 		char		contype;
12141 		bool		conislocal;
12142 
12143 		tup = SearchSysCache1(CONSTROID, ObjectIdGetDatum(oldId));
12144 		if (!HeapTupleIsValid(tup)) /* should not happen */
12145 			elog(ERROR, "cache lookup failed for constraint %u", oldId);
12146 		con = (Form_pg_constraint) GETSTRUCT(tup);
12147 		if (OidIsValid(con->conrelid))
12148 			relid = con->conrelid;
12149 		else
12150 		{
12151 			/* must be a domain constraint */
12152 			relid = get_typ_typrelid(getBaseType(con->contypid));
12153 			if (!OidIsValid(relid))
12154 				elog(ERROR, "could not identify relation associated with constraint %u", oldId);
12155 		}
12156 		confrelid = con->confrelid;
12157 		contype = con->contype;
12158 		conislocal = con->conislocal;
12159 		ReleaseSysCache(tup);
12160 
12161 		ObjectAddressSet(obj, ConstraintRelationId, oldId);
12162 		add_exact_object_address(&obj, objects);
12163 
12164 		/*
12165 		 * If the constraint is inherited (only), we don't want to inject a
12166 		 * new definition here; it'll get recreated when ATAddCheckConstraint
12167 		 * recurses from adding the parent table's constraint.  But we had to
12168 		 * carry the info this far so that we can drop the constraint below.
12169 		 */
12170 		if (!conislocal)
12171 			continue;
12172 
12173 		/*
12174 		 * When rebuilding an FK constraint that references the table we're
12175 		 * modifying, we might not yet have any lock on the FK's table, so get
12176 		 * one now.  We'll need AccessExclusiveLock for the DROP CONSTRAINT
12177 		 * step, so there's no value in asking for anything weaker.
12178 		 */
12179 		if (relid != tab->relid && contype == CONSTRAINT_FOREIGN)
12180 			LockRelationOid(relid, AccessExclusiveLock);
12181 
12182 		ATPostAlterTypeParse(oldId, relid, confrelid,
12183 							 (char *) lfirst(def_item),
12184 							 wqueue, lockmode, tab->rewrite);
12185 	}
12186 	forboth(oid_item, tab->changedIndexOids,
12187 			def_item, tab->changedIndexDefs)
12188 	{
12189 		Oid			oldId = lfirst_oid(oid_item);
12190 		Oid			relid;
12191 
12192 		relid = IndexGetRelation(oldId, false);
12193 		ATPostAlterTypeParse(oldId, relid, InvalidOid,
12194 							 (char *) lfirst(def_item),
12195 							 wqueue, lockmode, tab->rewrite);
12196 
12197 		ObjectAddressSet(obj, RelationRelationId, oldId);
12198 		add_exact_object_address(&obj, objects);
12199 	}
12200 
12201 	/*
12202 	 * Queue up command to restore replica identity index marking
12203 	 */
12204 	if (tab->replicaIdentityIndex)
12205 	{
12206 		AlterTableCmd *cmd = makeNode(AlterTableCmd);
12207 		ReplicaIdentityStmt *subcmd = makeNode(ReplicaIdentityStmt);
12208 
12209 		subcmd->identity_type = REPLICA_IDENTITY_INDEX;
12210 		subcmd->name = tab->replicaIdentityIndex;
12211 		cmd->subtype = AT_ReplicaIdentity;
12212 		cmd->def = (Node *) subcmd;
12213 
12214 		/* do it after indexes and constraints */
12215 		tab->subcmds[AT_PASS_OLD_CONSTR] =
12216 			lappend(tab->subcmds[AT_PASS_OLD_CONSTR], cmd);
12217 	}
12218 
12219 	/*
12220 	 * Queue up command to restore marking of index used for cluster.
12221 	 */
12222 	if (tab->clusterOnIndex)
12223 	{
12224 		AlterTableCmd *cmd = makeNode(AlterTableCmd);
12225 
12226 		cmd->subtype = AT_ClusterOn;
12227 		cmd->name = tab->clusterOnIndex;
12228 
12229 		/* do it after indexes and constraints */
12230 		tab->subcmds[AT_PASS_OLD_CONSTR] =
12231 			lappend(tab->subcmds[AT_PASS_OLD_CONSTR], cmd);
12232 	}
12233 
12234 	/*
12235 	 * It should be okay to use DROP_RESTRICT here, since nothing else should
12236 	 * be depending on these objects.
12237 	 */
12238 	performMultipleDeletions(objects, DROP_RESTRICT, PERFORM_DELETION_INTERNAL);
12239 
12240 	free_object_addresses(objects);
12241 
12242 	/*
12243 	 * The objects will get recreated during subsequent passes over the work
12244 	 * queue.
12245 	 */
12246 }
12247 
12248 /*
12249  * Parse the previously-saved definition string for a constraint or index
12250  * against the newly-established column data type(s), and queue up the
12251  * resulting command parsetrees for execution.
12252  *
12253  * This might fail if, for example, you have a WHERE clause that uses an
12254  * operator that's not available for the new column type.
12255  */
12256 static void
ATPostAlterTypeParse(Oid oldId,Oid oldRelId,Oid refRelId,char * cmd,List ** wqueue,LOCKMODE lockmode,bool rewrite)12257 ATPostAlterTypeParse(Oid oldId, Oid oldRelId, Oid refRelId, char *cmd,
12258 					 List **wqueue, LOCKMODE lockmode, bool rewrite)
12259 {
12260 	List	   *raw_parsetree_list;
12261 	List	   *querytree_list;
12262 	ListCell   *list_item;
12263 	Relation	rel;
12264 
12265 	/*
12266 	 * We expect that we will get only ALTER TABLE and CREATE INDEX
12267 	 * statements. Hence, there is no need to pass them through
12268 	 * parse_analyze() or the rewriter, but instead we need to pass them
12269 	 * through parse_utilcmd.c to make them ready for execution.
12270 	 */
12271 	raw_parsetree_list = raw_parser(cmd);
12272 	querytree_list = NIL;
12273 	foreach(list_item, raw_parsetree_list)
12274 	{
12275 		RawStmt    *rs = lfirst_node(RawStmt, list_item);
12276 		Node	   *stmt = rs->stmt;
12277 
12278 		if (IsA(stmt, IndexStmt))
12279 			querytree_list = lappend(querytree_list,
12280 									 transformIndexStmt(oldRelId,
12281 														(IndexStmt *) stmt,
12282 														cmd));
12283 		else if (IsA(stmt, AlterTableStmt))
12284 		{
12285 			List	   *beforeStmts;
12286 			List	   *afterStmts;
12287 
12288 			stmt = (Node *) transformAlterTableStmt(oldRelId,
12289 													(AlterTableStmt *) stmt,
12290 													cmd,
12291 													&beforeStmts,
12292 													&afterStmts);
12293 			querytree_list = list_concat(querytree_list, beforeStmts);
12294 			querytree_list = lappend(querytree_list, stmt);
12295 			querytree_list = list_concat(querytree_list, afterStmts);
12296 		}
12297 		else
12298 			querytree_list = lappend(querytree_list, stmt);
12299 	}
12300 
12301 	/* Caller should already have acquired whatever lock we need. */
12302 	rel = relation_open(oldRelId, NoLock);
12303 
12304 	/*
12305 	 * Attach each generated command to the proper place in the work queue.
12306 	 * Note this could result in creation of entirely new work-queue entries.
12307 	 *
12308 	 * Also note that we have to tweak the command subtypes, because it turns
12309 	 * out that re-creation of indexes and constraints has to act a bit
12310 	 * differently from initial creation.
12311 	 */
12312 	foreach(list_item, querytree_list)
12313 	{
12314 		Node	   *stm = (Node *) lfirst(list_item);
12315 		AlteredTableInfo *tab;
12316 
12317 		tab = ATGetQueueEntry(wqueue, rel);
12318 
12319 		if (IsA(stm, IndexStmt))
12320 		{
12321 			IndexStmt  *stmt = (IndexStmt *) stm;
12322 			AlterTableCmd *newcmd;
12323 
12324 			if (!rewrite)
12325 				TryReuseIndex(oldId, stmt);
12326 			stmt->reset_default_tblspc = true;
12327 			/* keep the index's comment */
12328 			stmt->idxcomment = GetComment(oldId, RelationRelationId, 0);
12329 
12330 			newcmd = makeNode(AlterTableCmd);
12331 			newcmd->subtype = AT_ReAddIndex;
12332 			newcmd->def = (Node *) stmt;
12333 			tab->subcmds[AT_PASS_OLD_INDEX] =
12334 				lappend(tab->subcmds[AT_PASS_OLD_INDEX], newcmd);
12335 		}
12336 		else if (IsA(stm, AlterTableStmt))
12337 		{
12338 			AlterTableStmt *stmt = (AlterTableStmt *) stm;
12339 			ListCell   *lcmd;
12340 
12341 			foreach(lcmd, stmt->cmds)
12342 			{
12343 				AlterTableCmd *cmd = castNode(AlterTableCmd, lfirst(lcmd));
12344 
12345 				if (cmd->subtype == AT_AddIndex)
12346 				{
12347 					IndexStmt  *indstmt;
12348 					Oid			indoid;
12349 
12350 					indstmt = castNode(IndexStmt, cmd->def);
12351 					indoid = get_constraint_index(oldId);
12352 
12353 					if (!rewrite)
12354 						TryReuseIndex(indoid, indstmt);
12355 					/* keep any comment on the index */
12356 					indstmt->idxcomment = GetComment(indoid,
12357 													 RelationRelationId, 0);
12358 					indstmt->reset_default_tblspc = true;
12359 
12360 					cmd->subtype = AT_ReAddIndex;
12361 					tab->subcmds[AT_PASS_OLD_INDEX] =
12362 						lappend(tab->subcmds[AT_PASS_OLD_INDEX], cmd);
12363 
12364 					/* recreate any comment on the constraint */
12365 					RebuildConstraintComment(tab,
12366 											 AT_PASS_OLD_INDEX,
12367 											 oldId,
12368 											 rel,
12369 											 NIL,
12370 											 indstmt->idxname);
12371 				}
12372 				else if (cmd->subtype == AT_AddConstraint)
12373 				{
12374 					Constraint *con = castNode(Constraint, cmd->def);
12375 
12376 					con->old_pktable_oid = refRelId;
12377 					/* rewriting neither side of a FK */
12378 					if (con->contype == CONSTR_FOREIGN &&
12379 						!rewrite && tab->rewrite == 0)
12380 						TryReuseForeignKey(oldId, con);
12381 					con->reset_default_tblspc = true;
12382 					cmd->subtype = AT_ReAddConstraint;
12383 					tab->subcmds[AT_PASS_OLD_CONSTR] =
12384 						lappend(tab->subcmds[AT_PASS_OLD_CONSTR], cmd);
12385 
12386 					/* recreate any comment on the constraint */
12387 					RebuildConstraintComment(tab,
12388 											 AT_PASS_OLD_CONSTR,
12389 											 oldId,
12390 											 rel,
12391 											 NIL,
12392 											 con->conname);
12393 				}
12394 				else if (cmd->subtype == AT_SetNotNull)
12395 				{
12396 					/*
12397 					 * The parser will create AT_SetNotNull subcommands for
12398 					 * columns of PRIMARY KEY indexes/constraints, but we need
12399 					 * not do anything with them here, because the columns'
12400 					 * NOT NULL marks will already have been propagated into
12401 					 * the new table definition.
12402 					 */
12403 				}
12404 				else
12405 					elog(ERROR, "unexpected statement subtype: %d",
12406 						 (int) cmd->subtype);
12407 			}
12408 		}
12409 		else if (IsA(stm, AlterDomainStmt))
12410 		{
12411 			AlterDomainStmt *stmt = (AlterDomainStmt *) stm;
12412 
12413 			if (stmt->subtype == 'C')	/* ADD CONSTRAINT */
12414 			{
12415 				Constraint *con = castNode(Constraint, stmt->def);
12416 				AlterTableCmd *cmd = makeNode(AlterTableCmd);
12417 
12418 				cmd->subtype = AT_ReAddDomainConstraint;
12419 				cmd->def = (Node *) stmt;
12420 				tab->subcmds[AT_PASS_OLD_CONSTR] =
12421 					lappend(tab->subcmds[AT_PASS_OLD_CONSTR], cmd);
12422 
12423 				/* recreate any comment on the constraint */
12424 				RebuildConstraintComment(tab,
12425 										 AT_PASS_OLD_CONSTR,
12426 										 oldId,
12427 										 NULL,
12428 										 stmt->typeName,
12429 										 con->conname);
12430 			}
12431 			else
12432 				elog(ERROR, "unexpected statement subtype: %d",
12433 					 (int) stmt->subtype);
12434 		}
12435 		else
12436 			elog(ERROR, "unexpected statement type: %d",
12437 				 (int) nodeTag(stm));
12438 	}
12439 
12440 	relation_close(rel, NoLock);
12441 }
12442 
12443 /*
12444  * Subroutine for ATPostAlterTypeParse() to recreate any existing comment
12445  * for a table or domain constraint that is being rebuilt.
12446  *
12447  * objid is the OID of the constraint.
12448  * Pass "rel" for a table constraint, or "domname" (domain's qualified name
12449  * as a string list) for a domain constraint.
12450  * (We could dig that info, as well as the conname, out of the pg_constraint
12451  * entry; but callers already have them so might as well pass them.)
12452  */
12453 static void
RebuildConstraintComment(AlteredTableInfo * tab,int pass,Oid objid,Relation rel,List * domname,const char * conname)12454 RebuildConstraintComment(AlteredTableInfo *tab, int pass, Oid objid,
12455 						 Relation rel, List *domname,
12456 						 const char *conname)
12457 {
12458 	CommentStmt *cmd;
12459 	char	   *comment_str;
12460 	AlterTableCmd *newcmd;
12461 
12462 	/* Look for comment for object wanted, and leave if none */
12463 	comment_str = GetComment(objid, ConstraintRelationId, 0);
12464 	if (comment_str == NULL)
12465 		return;
12466 
12467 	/* Build CommentStmt node, copying all input data for safety */
12468 	cmd = makeNode(CommentStmt);
12469 	if (rel)
12470 	{
12471 		cmd->objtype = OBJECT_TABCONSTRAINT;
12472 		cmd->object = (Node *)
12473 			list_make3(makeString(get_namespace_name(RelationGetNamespace(rel))),
12474 					   makeString(pstrdup(RelationGetRelationName(rel))),
12475 					   makeString(pstrdup(conname)));
12476 	}
12477 	else
12478 	{
12479 		cmd->objtype = OBJECT_DOMCONSTRAINT;
12480 		cmd->object = (Node *)
12481 			list_make2(makeTypeNameFromNameList(copyObject(domname)),
12482 					   makeString(pstrdup(conname)));
12483 	}
12484 	cmd->comment = comment_str;
12485 
12486 	/* Append it to list of commands */
12487 	newcmd = makeNode(AlterTableCmd);
12488 	newcmd->subtype = AT_ReAddComment;
12489 	newcmd->def = (Node *) cmd;
12490 	tab->subcmds[pass] = lappend(tab->subcmds[pass], newcmd);
12491 }
12492 
12493 /*
12494  * Subroutine for ATPostAlterTypeParse().  Calls out to CheckIndexCompatible()
12495  * for the real analysis, then mutates the IndexStmt based on that verdict.
12496  */
12497 static void
TryReuseIndex(Oid oldId,IndexStmt * stmt)12498 TryReuseIndex(Oid oldId, IndexStmt *stmt)
12499 {
12500 	if (CheckIndexCompatible(oldId,
12501 							 stmt->accessMethod,
12502 							 stmt->indexParams,
12503 							 stmt->excludeOpNames))
12504 	{
12505 		Relation	irel = index_open(oldId, NoLock);
12506 
12507 		/* If it's a partitioned index, there is no storage to share. */
12508 		if (irel->rd_rel->relkind != RELKIND_PARTITIONED_INDEX)
12509 		{
12510 			stmt->oldNode = irel->rd_node.relNode;
12511 			stmt->oldCreateSubid = irel->rd_createSubid;
12512 			stmt->oldFirstRelfilenodeSubid = irel->rd_firstRelfilenodeSubid;
12513 		}
12514 		index_close(irel, NoLock);
12515 	}
12516 }
12517 
12518 /*
12519  * Subroutine for ATPostAlterTypeParse().
12520  *
12521  * Stash the old P-F equality operator into the Constraint node, for possible
12522  * use by ATAddForeignKeyConstraint() in determining whether revalidation of
12523  * this constraint can be skipped.
12524  */
12525 static void
TryReuseForeignKey(Oid oldId,Constraint * con)12526 TryReuseForeignKey(Oid oldId, Constraint *con)
12527 {
12528 	HeapTuple	tup;
12529 	Datum		adatum;
12530 	bool		isNull;
12531 	ArrayType  *arr;
12532 	Oid		   *rawarr;
12533 	int			numkeys;
12534 	int			i;
12535 
12536 	Assert(con->contype == CONSTR_FOREIGN);
12537 	Assert(con->old_conpfeqop == NIL);	/* already prepared this node */
12538 
12539 	tup = SearchSysCache1(CONSTROID, ObjectIdGetDatum(oldId));
12540 	if (!HeapTupleIsValid(tup)) /* should not happen */
12541 		elog(ERROR, "cache lookup failed for constraint %u", oldId);
12542 
12543 	adatum = SysCacheGetAttr(CONSTROID, tup,
12544 							 Anum_pg_constraint_conpfeqop, &isNull);
12545 	if (isNull)
12546 		elog(ERROR, "null conpfeqop for constraint %u", oldId);
12547 	arr = DatumGetArrayTypeP(adatum);	/* ensure not toasted */
12548 	numkeys = ARR_DIMS(arr)[0];
12549 	/* test follows the one in ri_FetchConstraintInfo() */
12550 	if (ARR_NDIM(arr) != 1 ||
12551 		ARR_HASNULL(arr) ||
12552 		ARR_ELEMTYPE(arr) != OIDOID)
12553 		elog(ERROR, "conpfeqop is not a 1-D Oid array");
12554 	rawarr = (Oid *) ARR_DATA_PTR(arr);
12555 
12556 	/* stash a List of the operator Oids in our Constraint node */
12557 	for (i = 0; i < numkeys; i++)
12558 		con->old_conpfeqop = lappend_oid(con->old_conpfeqop, rawarr[i]);
12559 
12560 	ReleaseSysCache(tup);
12561 }
12562 
12563 /*
12564  * ALTER COLUMN .. OPTIONS ( ... )
12565  *
12566  * Returns the address of the modified column
12567  */
12568 static ObjectAddress
ATExecAlterColumnGenericOptions(Relation rel,const char * colName,List * options,LOCKMODE lockmode)12569 ATExecAlterColumnGenericOptions(Relation rel,
12570 								const char *colName,
12571 								List *options,
12572 								LOCKMODE lockmode)
12573 {
12574 	Relation	ftrel;
12575 	Relation	attrel;
12576 	ForeignServer *server;
12577 	ForeignDataWrapper *fdw;
12578 	HeapTuple	tuple;
12579 	HeapTuple	newtuple;
12580 	bool		isnull;
12581 	Datum		repl_val[Natts_pg_attribute];
12582 	bool		repl_null[Natts_pg_attribute];
12583 	bool		repl_repl[Natts_pg_attribute];
12584 	Datum		datum;
12585 	Form_pg_foreign_table fttableform;
12586 	Form_pg_attribute atttableform;
12587 	AttrNumber	attnum;
12588 	ObjectAddress address;
12589 
12590 	if (options == NIL)
12591 		return InvalidObjectAddress;
12592 
12593 	/* First, determine FDW validator associated to the foreign table. */
12594 	ftrel = table_open(ForeignTableRelationId, AccessShareLock);
12595 	tuple = SearchSysCache1(FOREIGNTABLEREL, rel->rd_id);
12596 	if (!HeapTupleIsValid(tuple))
12597 		ereport(ERROR,
12598 				(errcode(ERRCODE_UNDEFINED_OBJECT),
12599 				 errmsg("foreign table \"%s\" does not exist",
12600 						RelationGetRelationName(rel))));
12601 	fttableform = (Form_pg_foreign_table) GETSTRUCT(tuple);
12602 	server = GetForeignServer(fttableform->ftserver);
12603 	fdw = GetForeignDataWrapper(server->fdwid);
12604 
12605 	table_close(ftrel, AccessShareLock);
12606 	ReleaseSysCache(tuple);
12607 
12608 	attrel = table_open(AttributeRelationId, RowExclusiveLock);
12609 	tuple = SearchSysCacheAttName(RelationGetRelid(rel), colName);
12610 	if (!HeapTupleIsValid(tuple))
12611 		ereport(ERROR,
12612 				(errcode(ERRCODE_UNDEFINED_COLUMN),
12613 				 errmsg("column \"%s\" of relation \"%s\" does not exist",
12614 						colName, RelationGetRelationName(rel))));
12615 
12616 	/* Prevent them from altering a system attribute */
12617 	atttableform = (Form_pg_attribute) GETSTRUCT(tuple);
12618 	attnum = atttableform->attnum;
12619 	if (attnum <= 0)
12620 		ereport(ERROR,
12621 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
12622 				 errmsg("cannot alter system column \"%s\"", colName)));
12623 
12624 
12625 	/* Initialize buffers for new tuple values */
12626 	memset(repl_val, 0, sizeof(repl_val));
12627 	memset(repl_null, false, sizeof(repl_null));
12628 	memset(repl_repl, false, sizeof(repl_repl));
12629 
12630 	/* Extract the current options */
12631 	datum = SysCacheGetAttr(ATTNAME,
12632 							tuple,
12633 							Anum_pg_attribute_attfdwoptions,
12634 							&isnull);
12635 	if (isnull)
12636 		datum = PointerGetDatum(NULL);
12637 
12638 	/* Transform the options */
12639 	datum = transformGenericOptions(AttributeRelationId,
12640 									datum,
12641 									options,
12642 									fdw->fdwvalidator);
12643 
12644 	if (PointerIsValid(DatumGetPointer(datum)))
12645 		repl_val[Anum_pg_attribute_attfdwoptions - 1] = datum;
12646 	else
12647 		repl_null[Anum_pg_attribute_attfdwoptions - 1] = true;
12648 
12649 	repl_repl[Anum_pg_attribute_attfdwoptions - 1] = true;
12650 
12651 	/* Everything looks good - update the tuple */
12652 
12653 	newtuple = heap_modify_tuple(tuple, RelationGetDescr(attrel),
12654 								 repl_val, repl_null, repl_repl);
12655 
12656 	CatalogTupleUpdate(attrel, &newtuple->t_self, newtuple);
12657 
12658 	InvokeObjectPostAlterHook(RelationRelationId,
12659 							  RelationGetRelid(rel),
12660 							  atttableform->attnum);
12661 	ObjectAddressSubSet(address, RelationRelationId,
12662 						RelationGetRelid(rel), attnum);
12663 
12664 	ReleaseSysCache(tuple);
12665 
12666 	table_close(attrel, RowExclusiveLock);
12667 
12668 	heap_freetuple(newtuple);
12669 
12670 	return address;
12671 }
12672 
12673 /*
12674  * ALTER TABLE OWNER
12675  *
12676  * recursing is true if we are recursing from a table to its indexes,
12677  * sequences, or toast table.  We don't allow the ownership of those things to
12678  * be changed separately from the parent table.  Also, we can skip permission
12679  * checks (this is necessary not just an optimization, else we'd fail to
12680  * handle toast tables properly).
12681  *
12682  * recursing is also true if ALTER TYPE OWNER is calling us to fix up a
12683  * free-standing composite type.
12684  */
12685 void
ATExecChangeOwner(Oid relationOid,Oid newOwnerId,bool recursing,LOCKMODE lockmode)12686 ATExecChangeOwner(Oid relationOid, Oid newOwnerId, bool recursing, LOCKMODE lockmode)
12687 {
12688 	Relation	target_rel;
12689 	Relation	class_rel;
12690 	HeapTuple	tuple;
12691 	Form_pg_class tuple_class;
12692 
12693 	/*
12694 	 * Get exclusive lock till end of transaction on the target table. Use
12695 	 * relation_open so that we can work on indexes and sequences.
12696 	 */
12697 	target_rel = relation_open(relationOid, lockmode);
12698 
12699 	/* Get its pg_class tuple, too */
12700 	class_rel = table_open(RelationRelationId, RowExclusiveLock);
12701 
12702 	tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relationOid));
12703 	if (!HeapTupleIsValid(tuple))
12704 		elog(ERROR, "cache lookup failed for relation %u", relationOid);
12705 	tuple_class = (Form_pg_class) GETSTRUCT(tuple);
12706 
12707 	/* Can we change the ownership of this tuple? */
12708 	switch (tuple_class->relkind)
12709 	{
12710 		case RELKIND_RELATION:
12711 		case RELKIND_VIEW:
12712 		case RELKIND_MATVIEW:
12713 		case RELKIND_FOREIGN_TABLE:
12714 		case RELKIND_PARTITIONED_TABLE:
12715 			/* ok to change owner */
12716 			break;
12717 		case RELKIND_INDEX:
12718 			if (!recursing)
12719 			{
12720 				/*
12721 				 * Because ALTER INDEX OWNER used to be allowed, and in fact
12722 				 * is generated by old versions of pg_dump, we give a warning
12723 				 * and do nothing rather than erroring out.  Also, to avoid
12724 				 * unnecessary chatter while restoring those old dumps, say
12725 				 * nothing at all if the command would be a no-op anyway.
12726 				 */
12727 				if (tuple_class->relowner != newOwnerId)
12728 					ereport(WARNING,
12729 							(errcode(ERRCODE_WRONG_OBJECT_TYPE),
12730 							 errmsg("cannot change owner of index \"%s\"",
12731 									NameStr(tuple_class->relname)),
12732 							 errhint("Change the ownership of the index's table, instead.")));
12733 				/* quick hack to exit via the no-op path */
12734 				newOwnerId = tuple_class->relowner;
12735 			}
12736 			break;
12737 		case RELKIND_PARTITIONED_INDEX:
12738 			if (recursing)
12739 				break;
12740 			ereport(ERROR,
12741 					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
12742 					 errmsg("cannot change owner of index \"%s\"",
12743 							NameStr(tuple_class->relname)),
12744 					 errhint("Change the ownership of the index's table, instead.")));
12745 			break;
12746 		case RELKIND_SEQUENCE:
12747 			if (!recursing &&
12748 				tuple_class->relowner != newOwnerId)
12749 			{
12750 				/* if it's an owned sequence, disallow changing it by itself */
12751 				Oid			tableId;
12752 				int32		colId;
12753 
12754 				if (sequenceIsOwned(relationOid, DEPENDENCY_AUTO, &tableId, &colId) ||
12755 					sequenceIsOwned(relationOid, DEPENDENCY_INTERNAL, &tableId, &colId))
12756 					ereport(ERROR,
12757 							(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
12758 							 errmsg("cannot change owner of sequence \"%s\"",
12759 									NameStr(tuple_class->relname)),
12760 							 errdetail("Sequence \"%s\" is linked to table \"%s\".",
12761 									   NameStr(tuple_class->relname),
12762 									   get_rel_name(tableId))));
12763 			}
12764 			break;
12765 		case RELKIND_COMPOSITE_TYPE:
12766 			if (recursing)
12767 				break;
12768 			ereport(ERROR,
12769 					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
12770 					 errmsg("\"%s\" is a composite type",
12771 							NameStr(tuple_class->relname)),
12772 					 errhint("Use ALTER TYPE instead.")));
12773 			break;
12774 		case RELKIND_TOASTVALUE:
12775 			if (recursing)
12776 				break;
12777 			/* FALL THRU */
12778 		default:
12779 			ereport(ERROR,
12780 					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
12781 					 errmsg("\"%s\" is not a table, view, sequence, or foreign table",
12782 							NameStr(tuple_class->relname))));
12783 	}
12784 
12785 	/*
12786 	 * If the new owner is the same as the existing owner, consider the
12787 	 * command to have succeeded.  This is for dump restoration purposes.
12788 	 */
12789 	if (tuple_class->relowner != newOwnerId)
12790 	{
12791 		Datum		repl_val[Natts_pg_class];
12792 		bool		repl_null[Natts_pg_class];
12793 		bool		repl_repl[Natts_pg_class];
12794 		Acl		   *newAcl;
12795 		Datum		aclDatum;
12796 		bool		isNull;
12797 		HeapTuple	newtuple;
12798 
12799 		/* skip permission checks when recursing to index or toast table */
12800 		if (!recursing)
12801 		{
12802 			/* Superusers can always do it */
12803 			if (!superuser())
12804 			{
12805 				Oid			namespaceOid = tuple_class->relnamespace;
12806 				AclResult	aclresult;
12807 
12808 				/* Otherwise, must be owner of the existing object */
12809 				if (!pg_class_ownercheck(relationOid, GetUserId()))
12810 					aclcheck_error(ACLCHECK_NOT_OWNER, get_relkind_objtype(get_rel_relkind(relationOid)),
12811 								   RelationGetRelationName(target_rel));
12812 
12813 				/* Must be able to become new owner */
12814 				check_is_member_of_role(GetUserId(), newOwnerId);
12815 
12816 				/* New owner must have CREATE privilege on namespace */
12817 				aclresult = pg_namespace_aclcheck(namespaceOid, newOwnerId,
12818 												  ACL_CREATE);
12819 				if (aclresult != ACLCHECK_OK)
12820 					aclcheck_error(aclresult, OBJECT_SCHEMA,
12821 								   get_namespace_name(namespaceOid));
12822 			}
12823 		}
12824 
12825 		memset(repl_null, false, sizeof(repl_null));
12826 		memset(repl_repl, false, sizeof(repl_repl));
12827 
12828 		repl_repl[Anum_pg_class_relowner - 1] = true;
12829 		repl_val[Anum_pg_class_relowner - 1] = ObjectIdGetDatum(newOwnerId);
12830 
12831 		/*
12832 		 * Determine the modified ACL for the new owner.  This is only
12833 		 * necessary when the ACL is non-null.
12834 		 */
12835 		aclDatum = SysCacheGetAttr(RELOID, tuple,
12836 								   Anum_pg_class_relacl,
12837 								   &isNull);
12838 		if (!isNull)
12839 		{
12840 			newAcl = aclnewowner(DatumGetAclP(aclDatum),
12841 								 tuple_class->relowner, newOwnerId);
12842 			repl_repl[Anum_pg_class_relacl - 1] = true;
12843 			repl_val[Anum_pg_class_relacl - 1] = PointerGetDatum(newAcl);
12844 		}
12845 
12846 		newtuple = heap_modify_tuple(tuple, RelationGetDescr(class_rel), repl_val, repl_null, repl_repl);
12847 
12848 		CatalogTupleUpdate(class_rel, &newtuple->t_self, newtuple);
12849 
12850 		heap_freetuple(newtuple);
12851 
12852 		/*
12853 		 * We must similarly update any per-column ACLs to reflect the new
12854 		 * owner; for neatness reasons that's split out as a subroutine.
12855 		 */
12856 		change_owner_fix_column_acls(relationOid,
12857 									 tuple_class->relowner,
12858 									 newOwnerId);
12859 
12860 		/*
12861 		 * Update owner dependency reference, if any.  A composite type has
12862 		 * none, because it's tracked for the pg_type entry instead of here;
12863 		 * indexes and TOAST tables don't have their own entries either.
12864 		 */
12865 		if (tuple_class->relkind != RELKIND_COMPOSITE_TYPE &&
12866 			tuple_class->relkind != RELKIND_INDEX &&
12867 			tuple_class->relkind != RELKIND_PARTITIONED_INDEX &&
12868 			tuple_class->relkind != RELKIND_TOASTVALUE)
12869 			changeDependencyOnOwner(RelationRelationId, relationOid,
12870 									newOwnerId);
12871 
12872 		/*
12873 		 * Also change the ownership of the table's row type, if it has one
12874 		 */
12875 		if (tuple_class->relkind != RELKIND_INDEX &&
12876 			tuple_class->relkind != RELKIND_PARTITIONED_INDEX)
12877 			AlterTypeOwnerInternal(tuple_class->reltype, newOwnerId);
12878 
12879 		/*
12880 		 * If we are operating on a table or materialized view, also change
12881 		 * the ownership of any indexes and sequences that belong to the
12882 		 * relation, as well as its toast table (if it has one).
12883 		 */
12884 		if (tuple_class->relkind == RELKIND_RELATION ||
12885 			tuple_class->relkind == RELKIND_PARTITIONED_TABLE ||
12886 			tuple_class->relkind == RELKIND_MATVIEW ||
12887 			tuple_class->relkind == RELKIND_TOASTVALUE)
12888 		{
12889 			List	   *index_oid_list;
12890 			ListCell   *i;
12891 
12892 			/* Find all the indexes belonging to this relation */
12893 			index_oid_list = RelationGetIndexList(target_rel);
12894 
12895 			/* For each index, recursively change its ownership */
12896 			foreach(i, index_oid_list)
12897 				ATExecChangeOwner(lfirst_oid(i), newOwnerId, true, lockmode);
12898 
12899 			list_free(index_oid_list);
12900 		}
12901 
12902 		/* If it has a toast table, recurse to change its ownership */
12903 		if (tuple_class->reltoastrelid != InvalidOid)
12904 			ATExecChangeOwner(tuple_class->reltoastrelid, newOwnerId,
12905 							  true, lockmode);
12906 
12907 		/* If it has dependent sequences, recurse to change them too */
12908 		change_owner_recurse_to_sequences(relationOid, newOwnerId, lockmode);
12909 	}
12910 
12911 	InvokeObjectPostAlterHook(RelationRelationId, relationOid, 0);
12912 
12913 	ReleaseSysCache(tuple);
12914 	table_close(class_rel, RowExclusiveLock);
12915 	relation_close(target_rel, NoLock);
12916 }
12917 
12918 /*
12919  * change_owner_fix_column_acls
12920  *
12921  * Helper function for ATExecChangeOwner.  Scan the columns of the table
12922  * and fix any non-null column ACLs to reflect the new owner.
12923  */
12924 static void
change_owner_fix_column_acls(Oid relationOid,Oid oldOwnerId,Oid newOwnerId)12925 change_owner_fix_column_acls(Oid relationOid, Oid oldOwnerId, Oid newOwnerId)
12926 {
12927 	Relation	attRelation;
12928 	SysScanDesc scan;
12929 	ScanKeyData key[1];
12930 	HeapTuple	attributeTuple;
12931 
12932 	attRelation = table_open(AttributeRelationId, RowExclusiveLock);
12933 	ScanKeyInit(&key[0],
12934 				Anum_pg_attribute_attrelid,
12935 				BTEqualStrategyNumber, F_OIDEQ,
12936 				ObjectIdGetDatum(relationOid));
12937 	scan = systable_beginscan(attRelation, AttributeRelidNumIndexId,
12938 							  true, NULL, 1, key);
12939 	while (HeapTupleIsValid(attributeTuple = systable_getnext(scan)))
12940 	{
12941 		Form_pg_attribute att = (Form_pg_attribute) GETSTRUCT(attributeTuple);
12942 		Datum		repl_val[Natts_pg_attribute];
12943 		bool		repl_null[Natts_pg_attribute];
12944 		bool		repl_repl[Natts_pg_attribute];
12945 		Acl		   *newAcl;
12946 		Datum		aclDatum;
12947 		bool		isNull;
12948 		HeapTuple	newtuple;
12949 
12950 		/* Ignore dropped columns */
12951 		if (att->attisdropped)
12952 			continue;
12953 
12954 		aclDatum = heap_getattr(attributeTuple,
12955 								Anum_pg_attribute_attacl,
12956 								RelationGetDescr(attRelation),
12957 								&isNull);
12958 		/* Null ACLs do not require changes */
12959 		if (isNull)
12960 			continue;
12961 
12962 		memset(repl_null, false, sizeof(repl_null));
12963 		memset(repl_repl, false, sizeof(repl_repl));
12964 
12965 		newAcl = aclnewowner(DatumGetAclP(aclDatum),
12966 							 oldOwnerId, newOwnerId);
12967 		repl_repl[Anum_pg_attribute_attacl - 1] = true;
12968 		repl_val[Anum_pg_attribute_attacl - 1] = PointerGetDatum(newAcl);
12969 
12970 		newtuple = heap_modify_tuple(attributeTuple,
12971 									 RelationGetDescr(attRelation),
12972 									 repl_val, repl_null, repl_repl);
12973 
12974 		CatalogTupleUpdate(attRelation, &newtuple->t_self, newtuple);
12975 
12976 		heap_freetuple(newtuple);
12977 	}
12978 	systable_endscan(scan);
12979 	table_close(attRelation, RowExclusiveLock);
12980 }
12981 
12982 /*
12983  * change_owner_recurse_to_sequences
12984  *
12985  * Helper function for ATExecChangeOwner.  Examines pg_depend searching
12986  * for sequences that are dependent on serial columns, and changes their
12987  * ownership.
12988  */
12989 static void
change_owner_recurse_to_sequences(Oid relationOid,Oid newOwnerId,LOCKMODE lockmode)12990 change_owner_recurse_to_sequences(Oid relationOid, Oid newOwnerId, LOCKMODE lockmode)
12991 {
12992 	Relation	depRel;
12993 	SysScanDesc scan;
12994 	ScanKeyData key[2];
12995 	HeapTuple	tup;
12996 
12997 	/*
12998 	 * SERIAL sequences are those having an auto dependency on one of the
12999 	 * table's columns (we don't care *which* column, exactly).
13000 	 */
13001 	depRel = table_open(DependRelationId, AccessShareLock);
13002 
13003 	ScanKeyInit(&key[0],
13004 				Anum_pg_depend_refclassid,
13005 				BTEqualStrategyNumber, F_OIDEQ,
13006 				ObjectIdGetDatum(RelationRelationId));
13007 	ScanKeyInit(&key[1],
13008 				Anum_pg_depend_refobjid,
13009 				BTEqualStrategyNumber, F_OIDEQ,
13010 				ObjectIdGetDatum(relationOid));
13011 	/* we leave refobjsubid unspecified */
13012 
13013 	scan = systable_beginscan(depRel, DependReferenceIndexId, true,
13014 							  NULL, 2, key);
13015 
13016 	while (HeapTupleIsValid(tup = systable_getnext(scan)))
13017 	{
13018 		Form_pg_depend depForm = (Form_pg_depend) GETSTRUCT(tup);
13019 		Relation	seqRel;
13020 
13021 		/* skip dependencies other than auto dependencies on columns */
13022 		if (depForm->refobjsubid == 0 ||
13023 			depForm->classid != RelationRelationId ||
13024 			depForm->objsubid != 0 ||
13025 			!(depForm->deptype == DEPENDENCY_AUTO || depForm->deptype == DEPENDENCY_INTERNAL))
13026 			continue;
13027 
13028 		/* Use relation_open just in case it's an index */
13029 		seqRel = relation_open(depForm->objid, lockmode);
13030 
13031 		/* skip non-sequence relations */
13032 		if (RelationGetForm(seqRel)->relkind != RELKIND_SEQUENCE)
13033 		{
13034 			/* No need to keep the lock */
13035 			relation_close(seqRel, lockmode);
13036 			continue;
13037 		}
13038 
13039 		/* We don't need to close the sequence while we alter it. */
13040 		ATExecChangeOwner(depForm->objid, newOwnerId, true, lockmode);
13041 
13042 		/* Now we can close it.  Keep the lock till end of transaction. */
13043 		relation_close(seqRel, NoLock);
13044 	}
13045 
13046 	systable_endscan(scan);
13047 
13048 	relation_close(depRel, AccessShareLock);
13049 }
13050 
13051 /*
13052  * ALTER TABLE CLUSTER ON
13053  *
13054  * The only thing we have to do is to change the indisclustered bits.
13055  *
13056  * Return the address of the new clustering index.
13057  */
13058 static ObjectAddress
ATExecClusterOn(Relation rel,const char * indexName,LOCKMODE lockmode)13059 ATExecClusterOn(Relation rel, const char *indexName, LOCKMODE lockmode)
13060 {
13061 	Oid			indexOid;
13062 	ObjectAddress address;
13063 
13064 	indexOid = get_relname_relid(indexName, rel->rd_rel->relnamespace);
13065 
13066 	if (!OidIsValid(indexOid))
13067 		ereport(ERROR,
13068 				(errcode(ERRCODE_UNDEFINED_OBJECT),
13069 				 errmsg("index \"%s\" for table \"%s\" does not exist",
13070 						indexName, RelationGetRelationName(rel))));
13071 
13072 	/* Check index is valid to cluster on */
13073 	check_index_is_clusterable(rel, indexOid, false, lockmode);
13074 
13075 	/* And do the work */
13076 	mark_index_clustered(rel, indexOid, false);
13077 
13078 	ObjectAddressSet(address,
13079 					 RelationRelationId, indexOid);
13080 
13081 	return address;
13082 }
13083 
13084 /*
13085  * ALTER TABLE SET WITHOUT CLUSTER
13086  *
13087  * We have to find any indexes on the table that have indisclustered bit
13088  * set and turn it off.
13089  */
13090 static void
ATExecDropCluster(Relation rel,LOCKMODE lockmode)13091 ATExecDropCluster(Relation rel, LOCKMODE lockmode)
13092 {
13093 	mark_index_clustered(rel, InvalidOid, false);
13094 }
13095 
13096 /*
13097  * ALTER TABLE SET TABLESPACE
13098  */
13099 static void
ATPrepSetTableSpace(AlteredTableInfo * tab,Relation rel,const char * tablespacename,LOCKMODE lockmode)13100 ATPrepSetTableSpace(AlteredTableInfo *tab, Relation rel, const char *tablespacename, LOCKMODE lockmode)
13101 {
13102 	Oid			tablespaceId;
13103 
13104 	/* Check that the tablespace exists */
13105 	tablespaceId = get_tablespace_oid(tablespacename, false);
13106 
13107 	/* Check permissions except when moving to database's default */
13108 	if (OidIsValid(tablespaceId) && tablespaceId != MyDatabaseTableSpace)
13109 	{
13110 		AclResult	aclresult;
13111 
13112 		aclresult = pg_tablespace_aclcheck(tablespaceId, GetUserId(), ACL_CREATE);
13113 		if (aclresult != ACLCHECK_OK)
13114 			aclcheck_error(aclresult, OBJECT_TABLESPACE, tablespacename);
13115 	}
13116 
13117 	/* Save info for Phase 3 to do the real work */
13118 	if (OidIsValid(tab->newTableSpace))
13119 		ereport(ERROR,
13120 				(errcode(ERRCODE_SYNTAX_ERROR),
13121 				 errmsg("cannot have multiple SET TABLESPACE subcommands")));
13122 
13123 	tab->newTableSpace = tablespaceId;
13124 }
13125 
13126 /*
13127  * Set, reset, or replace reloptions.
13128  */
13129 static void
ATExecSetRelOptions(Relation rel,List * defList,AlterTableType operation,LOCKMODE lockmode)13130 ATExecSetRelOptions(Relation rel, List *defList, AlterTableType operation,
13131 					LOCKMODE lockmode)
13132 {
13133 	Oid			relid;
13134 	Relation	pgclass;
13135 	HeapTuple	tuple;
13136 	HeapTuple	newtuple;
13137 	Datum		datum;
13138 	bool		isnull;
13139 	Datum		newOptions;
13140 	Datum		repl_val[Natts_pg_class];
13141 	bool		repl_null[Natts_pg_class];
13142 	bool		repl_repl[Natts_pg_class];
13143 	static char *validnsps[] = HEAP_RELOPT_NAMESPACES;
13144 
13145 	if (defList == NIL && operation != AT_ReplaceRelOptions)
13146 		return;					/* nothing to do */
13147 
13148 	pgclass = table_open(RelationRelationId, RowExclusiveLock);
13149 
13150 	/* Fetch heap tuple */
13151 	relid = RelationGetRelid(rel);
13152 	tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
13153 	if (!HeapTupleIsValid(tuple))
13154 		elog(ERROR, "cache lookup failed for relation %u", relid);
13155 
13156 	if (operation == AT_ReplaceRelOptions)
13157 	{
13158 		/*
13159 		 * If we're supposed to replace the reloptions list, we just pretend
13160 		 * there were none before.
13161 		 */
13162 		datum = (Datum) 0;
13163 		isnull = true;
13164 	}
13165 	else
13166 	{
13167 		/* Get the old reloptions */
13168 		datum = SysCacheGetAttr(RELOID, tuple, Anum_pg_class_reloptions,
13169 								&isnull);
13170 	}
13171 
13172 	/* Generate new proposed reloptions (text array) */
13173 	newOptions = transformRelOptions(isnull ? (Datum) 0 : datum,
13174 									 defList, NULL, validnsps, false,
13175 									 operation == AT_ResetRelOptions);
13176 
13177 	/* Validate */
13178 	switch (rel->rd_rel->relkind)
13179 	{
13180 		case RELKIND_RELATION:
13181 		case RELKIND_TOASTVALUE:
13182 		case RELKIND_MATVIEW:
13183 			(void) heap_reloptions(rel->rd_rel->relkind, newOptions, true);
13184 			break;
13185 		case RELKIND_PARTITIONED_TABLE:
13186 			(void) partitioned_table_reloptions(newOptions, true);
13187 			break;
13188 		case RELKIND_VIEW:
13189 			(void) view_reloptions(newOptions, true);
13190 			break;
13191 		case RELKIND_INDEX:
13192 		case RELKIND_PARTITIONED_INDEX:
13193 			(void) index_reloptions(rel->rd_indam->amoptions, newOptions, true);
13194 			break;
13195 		default:
13196 			ereport(ERROR,
13197 					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
13198 					 errmsg("\"%s\" is not a table, view, materialized view, index, or TOAST table",
13199 							RelationGetRelationName(rel))));
13200 			break;
13201 	}
13202 
13203 	/* Special-case validation of view options */
13204 	if (rel->rd_rel->relkind == RELKIND_VIEW)
13205 	{
13206 		Query	   *view_query = get_view_query(rel);
13207 		List	   *view_options = untransformRelOptions(newOptions);
13208 		ListCell   *cell;
13209 		bool		check_option = false;
13210 
13211 		foreach(cell, view_options)
13212 		{
13213 			DefElem    *defel = (DefElem *) lfirst(cell);
13214 
13215 			if (strcmp(defel->defname, "check_option") == 0)
13216 				check_option = true;
13217 		}
13218 
13219 		/*
13220 		 * If the check option is specified, look to see if the view is
13221 		 * actually auto-updatable or not.
13222 		 */
13223 		if (check_option)
13224 		{
13225 			const char *view_updatable_error =
13226 			view_query_is_auto_updatable(view_query, true);
13227 
13228 			if (view_updatable_error)
13229 				ereport(ERROR,
13230 						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
13231 						 errmsg("WITH CHECK OPTION is supported only on automatically updatable views"),
13232 						 errhint("%s", _(view_updatable_error))));
13233 		}
13234 	}
13235 
13236 	/*
13237 	 * All we need do here is update the pg_class row; the new options will be
13238 	 * propagated into relcaches during post-commit cache inval.
13239 	 */
13240 	memset(repl_val, 0, sizeof(repl_val));
13241 	memset(repl_null, false, sizeof(repl_null));
13242 	memset(repl_repl, false, sizeof(repl_repl));
13243 
13244 	if (newOptions != (Datum) 0)
13245 		repl_val[Anum_pg_class_reloptions - 1] = newOptions;
13246 	else
13247 		repl_null[Anum_pg_class_reloptions - 1] = true;
13248 
13249 	repl_repl[Anum_pg_class_reloptions - 1] = true;
13250 
13251 	newtuple = heap_modify_tuple(tuple, RelationGetDescr(pgclass),
13252 								 repl_val, repl_null, repl_repl);
13253 
13254 	CatalogTupleUpdate(pgclass, &newtuple->t_self, newtuple);
13255 
13256 	InvokeObjectPostAlterHook(RelationRelationId, RelationGetRelid(rel), 0);
13257 
13258 	heap_freetuple(newtuple);
13259 
13260 	ReleaseSysCache(tuple);
13261 
13262 	/* repeat the whole exercise for the toast table, if there's one */
13263 	if (OidIsValid(rel->rd_rel->reltoastrelid))
13264 	{
13265 		Relation	toastrel;
13266 		Oid			toastid = rel->rd_rel->reltoastrelid;
13267 
13268 		toastrel = table_open(toastid, lockmode);
13269 
13270 		/* Fetch heap tuple */
13271 		tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(toastid));
13272 		if (!HeapTupleIsValid(tuple))
13273 			elog(ERROR, "cache lookup failed for relation %u", toastid);
13274 
13275 		if (operation == AT_ReplaceRelOptions)
13276 		{
13277 			/*
13278 			 * If we're supposed to replace the reloptions list, we just
13279 			 * pretend there were none before.
13280 			 */
13281 			datum = (Datum) 0;
13282 			isnull = true;
13283 		}
13284 		else
13285 		{
13286 			/* Get the old reloptions */
13287 			datum = SysCacheGetAttr(RELOID, tuple, Anum_pg_class_reloptions,
13288 									&isnull);
13289 		}
13290 
13291 		newOptions = transformRelOptions(isnull ? (Datum) 0 : datum,
13292 										 defList, "toast", validnsps, false,
13293 										 operation == AT_ResetRelOptions);
13294 
13295 		(void) heap_reloptions(RELKIND_TOASTVALUE, newOptions, true);
13296 
13297 		memset(repl_val, 0, sizeof(repl_val));
13298 		memset(repl_null, false, sizeof(repl_null));
13299 		memset(repl_repl, false, sizeof(repl_repl));
13300 
13301 		if (newOptions != (Datum) 0)
13302 			repl_val[Anum_pg_class_reloptions - 1] = newOptions;
13303 		else
13304 			repl_null[Anum_pg_class_reloptions - 1] = true;
13305 
13306 		repl_repl[Anum_pg_class_reloptions - 1] = true;
13307 
13308 		newtuple = heap_modify_tuple(tuple, RelationGetDescr(pgclass),
13309 									 repl_val, repl_null, repl_repl);
13310 
13311 		CatalogTupleUpdate(pgclass, &newtuple->t_self, newtuple);
13312 
13313 		InvokeObjectPostAlterHookArg(RelationRelationId,
13314 									 RelationGetRelid(toastrel), 0,
13315 									 InvalidOid, true);
13316 
13317 		heap_freetuple(newtuple);
13318 
13319 		ReleaseSysCache(tuple);
13320 
13321 		table_close(toastrel, NoLock);
13322 	}
13323 
13324 	table_close(pgclass, RowExclusiveLock);
13325 }
13326 
13327 /*
13328  * Execute ALTER TABLE SET TABLESPACE for cases where there is no tuple
13329  * rewriting to be done, so we just want to copy the data as fast as possible.
13330  */
13331 static void
ATExecSetTableSpace(Oid tableOid,Oid newTableSpace,LOCKMODE lockmode)13332 ATExecSetTableSpace(Oid tableOid, Oid newTableSpace, LOCKMODE lockmode)
13333 {
13334 	Relation	rel;
13335 	Oid			oldTableSpace;
13336 	Oid			reltoastrelid;
13337 	Oid			newrelfilenode;
13338 	RelFileNode newrnode;
13339 	Relation	pg_class;
13340 	HeapTuple	tuple;
13341 	Form_pg_class rd_rel;
13342 	List	   *reltoastidxids = NIL;
13343 	ListCell   *lc;
13344 
13345 	/*
13346 	 * Need lock here in case we are recursing to toast table or index
13347 	 */
13348 	rel = relation_open(tableOid, lockmode);
13349 
13350 	/*
13351 	 * No work if no change in tablespace.
13352 	 */
13353 	oldTableSpace = rel->rd_rel->reltablespace;
13354 	if (newTableSpace == oldTableSpace ||
13355 		(newTableSpace == MyDatabaseTableSpace && oldTableSpace == 0))
13356 	{
13357 		InvokeObjectPostAlterHook(RelationRelationId,
13358 								  RelationGetRelid(rel), 0);
13359 
13360 		relation_close(rel, NoLock);
13361 		return;
13362 	}
13363 
13364 	/*
13365 	 * We cannot support moving mapped relations into different tablespaces.
13366 	 * (In particular this eliminates all shared catalogs.)
13367 	 */
13368 	if (RelationIsMapped(rel))
13369 		ereport(ERROR,
13370 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
13371 				 errmsg("cannot move system relation \"%s\"",
13372 						RelationGetRelationName(rel))));
13373 
13374 	/* Can't move a non-shared relation into pg_global */
13375 	if (newTableSpace == GLOBALTABLESPACE_OID)
13376 		ereport(ERROR,
13377 				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
13378 				 errmsg("only shared relations can be placed in pg_global tablespace")));
13379 
13380 	/*
13381 	 * Don't allow moving temp tables of other backends ... their local buffer
13382 	 * manager is not going to cope.
13383 	 */
13384 	if (RELATION_IS_OTHER_TEMP(rel))
13385 		ereport(ERROR,
13386 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
13387 				 errmsg("cannot move temporary tables of other sessions")));
13388 
13389 	reltoastrelid = rel->rd_rel->reltoastrelid;
13390 	/* Fetch the list of indexes on toast relation if necessary */
13391 	if (OidIsValid(reltoastrelid))
13392 	{
13393 		Relation	toastRel = relation_open(reltoastrelid, lockmode);
13394 
13395 		reltoastidxids = RelationGetIndexList(toastRel);
13396 		relation_close(toastRel, lockmode);
13397 	}
13398 
13399 	/* Get a modifiable copy of the relation's pg_class row */
13400 	pg_class = table_open(RelationRelationId, RowExclusiveLock);
13401 
13402 	tuple = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(tableOid));
13403 	if (!HeapTupleIsValid(tuple))
13404 		elog(ERROR, "cache lookup failed for relation %u", tableOid);
13405 	rd_rel = (Form_pg_class) GETSTRUCT(tuple);
13406 
13407 	/*
13408 	 * Relfilenodes are not unique in databases across tablespaces, so we need
13409 	 * to allocate a new one in the new tablespace.
13410 	 */
13411 	newrelfilenode = GetNewRelFileNode(newTableSpace, NULL,
13412 									   rel->rd_rel->relpersistence);
13413 
13414 	/* Open old and new relation */
13415 	newrnode = rel->rd_node;
13416 	newrnode.relNode = newrelfilenode;
13417 	newrnode.spcNode = newTableSpace;
13418 
13419 	/* hand off to AM to actually create the new filenode and copy the data */
13420 	if (rel->rd_rel->relkind == RELKIND_INDEX)
13421 	{
13422 		index_copy_data(rel, newrnode);
13423 	}
13424 	else
13425 	{
13426 		Assert(rel->rd_rel->relkind == RELKIND_RELATION ||
13427 			   rel->rd_rel->relkind == RELKIND_MATVIEW ||
13428 			   rel->rd_rel->relkind == RELKIND_TOASTVALUE);
13429 		table_relation_copy_data(rel, &newrnode);
13430 	}
13431 
13432 	/*
13433 	 * Update the pg_class row.
13434 	 *
13435 	 * NB: This wouldn't work if ATExecSetTableSpace() were allowed to be
13436 	 * executed on pg_class or its indexes (the above copy wouldn't contain
13437 	 * the updated pg_class entry), but that's forbidden above.
13438 	 */
13439 	rd_rel->reltablespace = (newTableSpace == MyDatabaseTableSpace) ? InvalidOid : newTableSpace;
13440 	rd_rel->relfilenode = newrelfilenode;
13441 	CatalogTupleUpdate(pg_class, &tuple->t_self, tuple);
13442 
13443 	InvokeObjectPostAlterHook(RelationRelationId, RelationGetRelid(rel), 0);
13444 
13445 	heap_freetuple(tuple);
13446 
13447 	table_close(pg_class, RowExclusiveLock);
13448 
13449 	RelationAssumeNewRelfilenode(rel);
13450 
13451 	relation_close(rel, NoLock);
13452 
13453 	/* Make sure the reltablespace change is visible */
13454 	CommandCounterIncrement();
13455 
13456 	/* Move associated toast relation and/or indexes, too */
13457 	if (OidIsValid(reltoastrelid))
13458 		ATExecSetTableSpace(reltoastrelid, newTableSpace, lockmode);
13459 	foreach(lc, reltoastidxids)
13460 		ATExecSetTableSpace(lfirst_oid(lc), newTableSpace, lockmode);
13461 
13462 	/* Clean up */
13463 	list_free(reltoastidxids);
13464 }
13465 
13466 /*
13467  * Special handling of ALTER TABLE SET TABLESPACE for relations with no
13468  * storage that have an interest in preserving tablespace.
13469  *
13470  * Since these have no storage the tablespace can be updated with a simple
13471  * metadata only operation to update the tablespace.
13472  */
13473 static void
ATExecSetTableSpaceNoStorage(Relation rel,Oid newTableSpace)13474 ATExecSetTableSpaceNoStorage(Relation rel, Oid newTableSpace)
13475 {
13476 	HeapTuple	tuple;
13477 	Oid			oldTableSpace;
13478 	Relation	pg_class;
13479 	Form_pg_class rd_rel;
13480 	Oid			reloid = RelationGetRelid(rel);
13481 
13482 	/*
13483 	 * Shouldn't be called on relations having storage; these are processed in
13484 	 * phase 3.
13485 	 */
13486 	Assert(!RELKIND_HAS_STORAGE(rel->rd_rel->relkind));
13487 
13488 	/* Can't allow a non-shared relation in pg_global */
13489 	if (newTableSpace == GLOBALTABLESPACE_OID)
13490 		ereport(ERROR,
13491 				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
13492 				 errmsg("only shared relations can be placed in pg_global tablespace")));
13493 
13494 	/*
13495 	 * No work if no change in tablespace.
13496 	 */
13497 	oldTableSpace = rel->rd_rel->reltablespace;
13498 	if (newTableSpace == oldTableSpace ||
13499 		(newTableSpace == MyDatabaseTableSpace && oldTableSpace == 0))
13500 	{
13501 		InvokeObjectPostAlterHook(RelationRelationId, reloid, 0);
13502 		return;
13503 	}
13504 
13505 	/* Get a modifiable copy of the relation's pg_class row */
13506 	pg_class = table_open(RelationRelationId, RowExclusiveLock);
13507 
13508 	tuple = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(reloid));
13509 	if (!HeapTupleIsValid(tuple))
13510 		elog(ERROR, "cache lookup failed for relation %u", reloid);
13511 	rd_rel = (Form_pg_class) GETSTRUCT(tuple);
13512 
13513 	/* update the pg_class row */
13514 	rd_rel->reltablespace = (newTableSpace == MyDatabaseTableSpace) ? InvalidOid : newTableSpace;
13515 	CatalogTupleUpdate(pg_class, &tuple->t_self, tuple);
13516 
13517 	/* Record dependency on tablespace */
13518 	changeDependencyOnTablespace(RelationRelationId,
13519 								 reloid, rd_rel->reltablespace);
13520 
13521 	InvokeObjectPostAlterHook(RelationRelationId, reloid, 0);
13522 
13523 	heap_freetuple(tuple);
13524 
13525 	table_close(pg_class, RowExclusiveLock);
13526 
13527 	/* Make sure the reltablespace change is visible */
13528 	CommandCounterIncrement();
13529 }
13530 
13531 /*
13532  * Alter Table ALL ... SET TABLESPACE
13533  *
13534  * Allows a user to move all objects of some type in a given tablespace in the
13535  * current database to another tablespace.  Objects can be chosen based on the
13536  * owner of the object also, to allow users to move only their objects.
13537  * The user must have CREATE rights on the new tablespace, as usual.   The main
13538  * permissions handling is done by the lower-level table move function.
13539  *
13540  * All to-be-moved objects are locked first. If NOWAIT is specified and the
13541  * lock can't be acquired then we ereport(ERROR).
13542  */
13543 Oid
AlterTableMoveAll(AlterTableMoveAllStmt * stmt)13544 AlterTableMoveAll(AlterTableMoveAllStmt *stmt)
13545 {
13546 	List	   *relations = NIL;
13547 	ListCell   *l;
13548 	ScanKeyData key[1];
13549 	Relation	rel;
13550 	TableScanDesc scan;
13551 	HeapTuple	tuple;
13552 	Oid			orig_tablespaceoid;
13553 	Oid			new_tablespaceoid;
13554 	List	   *role_oids = roleSpecsToIds(stmt->roles);
13555 
13556 	/* Ensure we were not asked to move something we can't */
13557 	if (stmt->objtype != OBJECT_TABLE && stmt->objtype != OBJECT_INDEX &&
13558 		stmt->objtype != OBJECT_MATVIEW)
13559 		ereport(ERROR,
13560 				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
13561 				 errmsg("only tables, indexes, and materialized views exist in tablespaces")));
13562 
13563 	/* Get the orig and new tablespace OIDs */
13564 	orig_tablespaceoid = get_tablespace_oid(stmt->orig_tablespacename, false);
13565 	new_tablespaceoid = get_tablespace_oid(stmt->new_tablespacename, false);
13566 
13567 	/* Can't move shared relations in to or out of pg_global */
13568 	/* This is also checked by ATExecSetTableSpace, but nice to stop earlier */
13569 	if (orig_tablespaceoid == GLOBALTABLESPACE_OID ||
13570 		new_tablespaceoid == GLOBALTABLESPACE_OID)
13571 		ereport(ERROR,
13572 				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
13573 				 errmsg("cannot move relations in to or out of pg_global tablespace")));
13574 
13575 	/*
13576 	 * Must have CREATE rights on the new tablespace, unless it is the
13577 	 * database default tablespace (which all users implicitly have CREATE
13578 	 * rights on).
13579 	 */
13580 	if (OidIsValid(new_tablespaceoid) && new_tablespaceoid != MyDatabaseTableSpace)
13581 	{
13582 		AclResult	aclresult;
13583 
13584 		aclresult = pg_tablespace_aclcheck(new_tablespaceoid, GetUserId(),
13585 										   ACL_CREATE);
13586 		if (aclresult != ACLCHECK_OK)
13587 			aclcheck_error(aclresult, OBJECT_TABLESPACE,
13588 						   get_tablespace_name(new_tablespaceoid));
13589 	}
13590 
13591 	/*
13592 	 * Now that the checks are done, check if we should set either to
13593 	 * InvalidOid because it is our database's default tablespace.
13594 	 */
13595 	if (orig_tablespaceoid == MyDatabaseTableSpace)
13596 		orig_tablespaceoid = InvalidOid;
13597 
13598 	if (new_tablespaceoid == MyDatabaseTableSpace)
13599 		new_tablespaceoid = InvalidOid;
13600 
13601 	/* no-op */
13602 	if (orig_tablespaceoid == new_tablespaceoid)
13603 		return new_tablespaceoid;
13604 
13605 	/*
13606 	 * Walk the list of objects in the tablespace and move them. This will
13607 	 * only find objects in our database, of course.
13608 	 */
13609 	ScanKeyInit(&key[0],
13610 				Anum_pg_class_reltablespace,
13611 				BTEqualStrategyNumber, F_OIDEQ,
13612 				ObjectIdGetDatum(orig_tablespaceoid));
13613 
13614 	rel = table_open(RelationRelationId, AccessShareLock);
13615 	scan = table_beginscan_catalog(rel, 1, key);
13616 	while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
13617 	{
13618 		Form_pg_class relForm = (Form_pg_class) GETSTRUCT(tuple);
13619 		Oid			relOid = relForm->oid;
13620 
13621 		/*
13622 		 * Do not move objects in pg_catalog as part of this, if an admin
13623 		 * really wishes to do so, they can issue the individual ALTER
13624 		 * commands directly.
13625 		 *
13626 		 * Also, explicitly avoid any shared tables, temp tables, or TOAST
13627 		 * (TOAST will be moved with the main table).
13628 		 */
13629 		if (IsCatalogNamespace(relForm->relnamespace) ||
13630 			relForm->relisshared ||
13631 			isAnyTempNamespace(relForm->relnamespace) ||
13632 			IsToastNamespace(relForm->relnamespace))
13633 			continue;
13634 
13635 		/* Only move the object type requested */
13636 		if ((stmt->objtype == OBJECT_TABLE &&
13637 			 relForm->relkind != RELKIND_RELATION &&
13638 			 relForm->relkind != RELKIND_PARTITIONED_TABLE) ||
13639 			(stmt->objtype == OBJECT_INDEX &&
13640 			 relForm->relkind != RELKIND_INDEX &&
13641 			 relForm->relkind != RELKIND_PARTITIONED_INDEX) ||
13642 			(stmt->objtype == OBJECT_MATVIEW &&
13643 			 relForm->relkind != RELKIND_MATVIEW))
13644 			continue;
13645 
13646 		/* Check if we are only moving objects owned by certain roles */
13647 		if (role_oids != NIL && !list_member_oid(role_oids, relForm->relowner))
13648 			continue;
13649 
13650 		/*
13651 		 * Handle permissions-checking here since we are locking the tables
13652 		 * and also to avoid doing a bunch of work only to fail part-way. Note
13653 		 * that permissions will also be checked by AlterTableInternal().
13654 		 *
13655 		 * Caller must be considered an owner on the table to move it.
13656 		 */
13657 		if (!pg_class_ownercheck(relOid, GetUserId()))
13658 			aclcheck_error(ACLCHECK_NOT_OWNER, get_relkind_objtype(get_rel_relkind(relOid)),
13659 						   NameStr(relForm->relname));
13660 
13661 		if (stmt->nowait &&
13662 			!ConditionalLockRelationOid(relOid, AccessExclusiveLock))
13663 			ereport(ERROR,
13664 					(errcode(ERRCODE_OBJECT_IN_USE),
13665 					 errmsg("aborting because lock on relation \"%s.%s\" is not available",
13666 							get_namespace_name(relForm->relnamespace),
13667 							NameStr(relForm->relname))));
13668 		else
13669 			LockRelationOid(relOid, AccessExclusiveLock);
13670 
13671 		/* Add to our list of objects to move */
13672 		relations = lappend_oid(relations, relOid);
13673 	}
13674 
13675 	table_endscan(scan);
13676 	table_close(rel, AccessShareLock);
13677 
13678 	if (relations == NIL)
13679 		ereport(NOTICE,
13680 				(errcode(ERRCODE_NO_DATA_FOUND),
13681 				 errmsg("no matching relations in tablespace \"%s\" found",
13682 						orig_tablespaceoid == InvalidOid ? "(database default)" :
13683 						get_tablespace_name(orig_tablespaceoid))));
13684 
13685 	/* Everything is locked, loop through and move all of the relations. */
13686 	foreach(l, relations)
13687 	{
13688 		List	   *cmds = NIL;
13689 		AlterTableCmd *cmd = makeNode(AlterTableCmd);
13690 
13691 		cmd->subtype = AT_SetTableSpace;
13692 		cmd->name = stmt->new_tablespacename;
13693 
13694 		cmds = lappend(cmds, cmd);
13695 
13696 		EventTriggerAlterTableStart((Node *) stmt);
13697 		/* OID is set by AlterTableInternal */
13698 		AlterTableInternal(lfirst_oid(l), cmds, false);
13699 		EventTriggerAlterTableEnd();
13700 	}
13701 
13702 	return new_tablespaceoid;
13703 }
13704 
13705 static void
index_copy_data(Relation rel,RelFileNode newrnode)13706 index_copy_data(Relation rel, RelFileNode newrnode)
13707 {
13708 	SMgrRelation dstrel;
13709 
13710 	dstrel = smgropen(newrnode, rel->rd_backend);
13711 	RelationOpenSmgr(rel);
13712 
13713 	/*
13714 	 * Since we copy the file directly without looking at the shared buffers,
13715 	 * we'd better first flush out any pages of the source relation that are
13716 	 * in shared buffers.  We assume no new changes will be made while we are
13717 	 * holding exclusive lock on the rel.
13718 	 */
13719 	FlushRelationBuffers(rel);
13720 
13721 	/*
13722 	 * Create and copy all forks of the relation, and schedule unlinking of
13723 	 * old physical files.
13724 	 *
13725 	 * NOTE: any conflict in relfilenode value will be caught in
13726 	 * RelationCreateStorage().
13727 	 */
13728 	RelationCreateStorage(newrnode, rel->rd_rel->relpersistence);
13729 
13730 	/* copy main fork */
13731 	RelationCopyStorage(rel->rd_smgr, dstrel, MAIN_FORKNUM,
13732 						rel->rd_rel->relpersistence);
13733 
13734 	/* copy those extra forks that exist */
13735 	for (ForkNumber forkNum = MAIN_FORKNUM + 1;
13736 		 forkNum <= MAX_FORKNUM; forkNum++)
13737 	{
13738 		if (smgrexists(rel->rd_smgr, forkNum))
13739 		{
13740 			smgrcreate(dstrel, forkNum, false);
13741 
13742 			/*
13743 			 * WAL log creation if the relation is persistent, or this is the
13744 			 * init fork of an unlogged relation.
13745 			 */
13746 			if (rel->rd_rel->relpersistence == RELPERSISTENCE_PERMANENT ||
13747 				(rel->rd_rel->relpersistence == RELPERSISTENCE_UNLOGGED &&
13748 				 forkNum == INIT_FORKNUM))
13749 				log_smgrcreate(&newrnode, forkNum);
13750 			RelationCopyStorage(rel->rd_smgr, dstrel, forkNum,
13751 								rel->rd_rel->relpersistence);
13752 		}
13753 	}
13754 
13755 	/* drop old relation, and close new one */
13756 	RelationDropStorage(rel);
13757 	smgrclose(dstrel);
13758 }
13759 
13760 /*
13761  * ALTER TABLE ENABLE/DISABLE TRIGGER
13762  *
13763  * We just pass this off to trigger.c.
13764  */
13765 static void
ATExecEnableDisableTrigger(Relation rel,const char * trigname,char fires_when,bool skip_system,LOCKMODE lockmode)13766 ATExecEnableDisableTrigger(Relation rel, const char *trigname,
13767 						   char fires_when, bool skip_system, LOCKMODE lockmode)
13768 {
13769 	EnableDisableTrigger(rel, trigname, fires_when, skip_system, lockmode);
13770 }
13771 
13772 /*
13773  * ALTER TABLE ENABLE/DISABLE RULE
13774  *
13775  * We just pass this off to rewriteDefine.c.
13776  */
13777 static void
ATExecEnableDisableRule(Relation rel,const char * rulename,char fires_when,LOCKMODE lockmode)13778 ATExecEnableDisableRule(Relation rel, const char *rulename,
13779 						char fires_when, LOCKMODE lockmode)
13780 {
13781 	EnableDisableRule(rel, rulename, fires_when);
13782 }
13783 
13784 /*
13785  * ALTER TABLE INHERIT
13786  *
13787  * Add a parent to the child's parents. This verifies that all the columns and
13788  * check constraints of the parent appear in the child and that they have the
13789  * same data types and expressions.
13790  */
13791 static void
ATPrepAddInherit(Relation child_rel)13792 ATPrepAddInherit(Relation child_rel)
13793 {
13794 	if (child_rel->rd_rel->reloftype)
13795 		ereport(ERROR,
13796 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
13797 				 errmsg("cannot change inheritance of typed table")));
13798 
13799 	if (child_rel->rd_rel->relispartition)
13800 		ereport(ERROR,
13801 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
13802 				 errmsg("cannot change inheritance of a partition")));
13803 
13804 	if (child_rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
13805 		ereport(ERROR,
13806 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
13807 				 errmsg("cannot change inheritance of partitioned table")));
13808 }
13809 
13810 /*
13811  * Return the address of the new parent relation.
13812  */
13813 static ObjectAddress
ATExecAddInherit(Relation child_rel,RangeVar * parent,LOCKMODE lockmode)13814 ATExecAddInherit(Relation child_rel, RangeVar *parent, LOCKMODE lockmode)
13815 {
13816 	Relation	parent_rel;
13817 	List	   *children;
13818 	ObjectAddress address;
13819 	const char *trigger_name;
13820 
13821 	/*
13822 	 * A self-exclusive lock is needed here.  See the similar case in
13823 	 * MergeAttributes() for a full explanation.
13824 	 */
13825 	parent_rel = table_openrv(parent, ShareUpdateExclusiveLock);
13826 
13827 	/*
13828 	 * Must be owner of both parent and child -- child was checked by
13829 	 * ATSimplePermissions call in ATPrepCmd
13830 	 */
13831 	ATSimplePermissions(parent_rel, ATT_TABLE | ATT_FOREIGN_TABLE);
13832 
13833 	/* Permanent rels cannot inherit from temporary ones */
13834 	if (parent_rel->rd_rel->relpersistence == RELPERSISTENCE_TEMP &&
13835 		child_rel->rd_rel->relpersistence != RELPERSISTENCE_TEMP)
13836 		ereport(ERROR,
13837 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
13838 				 errmsg("cannot inherit from temporary relation \"%s\"",
13839 						RelationGetRelationName(parent_rel))));
13840 
13841 	/* If parent rel is temp, it must belong to this session */
13842 	if (parent_rel->rd_rel->relpersistence == RELPERSISTENCE_TEMP &&
13843 		!parent_rel->rd_islocaltemp)
13844 		ereport(ERROR,
13845 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
13846 				 errmsg("cannot inherit from temporary relation of another session")));
13847 
13848 	/* Ditto for the child */
13849 	if (child_rel->rd_rel->relpersistence == RELPERSISTENCE_TEMP &&
13850 		!child_rel->rd_islocaltemp)
13851 		ereport(ERROR,
13852 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
13853 				 errmsg("cannot inherit to temporary relation of another session")));
13854 
13855 	/* Prevent partitioned tables from becoming inheritance parents */
13856 	if (parent_rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
13857 		ereport(ERROR,
13858 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
13859 				 errmsg("cannot inherit from partitioned table \"%s\"",
13860 						parent->relname)));
13861 
13862 	/* Likewise for partitions */
13863 	if (parent_rel->rd_rel->relispartition)
13864 		ereport(ERROR,
13865 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
13866 				 errmsg("cannot inherit from a partition")));
13867 
13868 	/*
13869 	 * Prevent circularity by seeing if proposed parent inherits from child.
13870 	 * (In particular, this disallows making a rel inherit from itself.)
13871 	 *
13872 	 * This is not completely bulletproof because of race conditions: in
13873 	 * multi-level inheritance trees, someone else could concurrently be
13874 	 * making another inheritance link that closes the loop but does not join
13875 	 * either of the rels we have locked.  Preventing that seems to require
13876 	 * exclusive locks on the entire inheritance tree, which is a cure worse
13877 	 * than the disease.  find_all_inheritors() will cope with circularity
13878 	 * anyway, so don't sweat it too much.
13879 	 *
13880 	 * We use weakest lock we can on child's children, namely AccessShareLock.
13881 	 */
13882 	children = find_all_inheritors(RelationGetRelid(child_rel),
13883 								   AccessShareLock, NULL);
13884 
13885 	if (list_member_oid(children, RelationGetRelid(parent_rel)))
13886 		ereport(ERROR,
13887 				(errcode(ERRCODE_DUPLICATE_TABLE),
13888 				 errmsg("circular inheritance not allowed"),
13889 				 errdetail("\"%s\" is already a child of \"%s\".",
13890 						   parent->relname,
13891 						   RelationGetRelationName(child_rel))));
13892 
13893 	/*
13894 	 * If child_rel has row-level triggers with transition tables, we
13895 	 * currently don't allow it to become an inheritance child.  See also
13896 	 * prohibitions in ATExecAttachPartition() and CreateTrigger().
13897 	 */
13898 	trigger_name = FindTriggerIncompatibleWithInheritance(child_rel->trigdesc);
13899 	if (trigger_name != NULL)
13900 		ereport(ERROR,
13901 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
13902 				 errmsg("trigger \"%s\" prevents table \"%s\" from becoming an inheritance child",
13903 						trigger_name, RelationGetRelationName(child_rel)),
13904 				 errdetail("ROW triggers with transition tables are not supported in inheritance hierarchies.")));
13905 
13906 	/* OK to create inheritance */
13907 	CreateInheritance(child_rel, parent_rel);
13908 
13909 	ObjectAddressSet(address, RelationRelationId,
13910 					 RelationGetRelid(parent_rel));
13911 
13912 	/* keep our lock on the parent relation until commit */
13913 	table_close(parent_rel, NoLock);
13914 
13915 	return address;
13916 }
13917 
13918 /*
13919  * CreateInheritance
13920  *		Catalog manipulation portion of creating inheritance between a child
13921  *		table and a parent table.
13922  *
13923  * Common to ATExecAddInherit() and ATExecAttachPartition().
13924  */
13925 static void
CreateInheritance(Relation child_rel,Relation parent_rel)13926 CreateInheritance(Relation child_rel, Relation parent_rel)
13927 {
13928 	Relation	catalogRelation;
13929 	SysScanDesc scan;
13930 	ScanKeyData key;
13931 	HeapTuple	inheritsTuple;
13932 	int32		inhseqno;
13933 
13934 	/* Note: get RowExclusiveLock because we will write pg_inherits below. */
13935 	catalogRelation = table_open(InheritsRelationId, RowExclusiveLock);
13936 
13937 	/*
13938 	 * Check for duplicates in the list of parents, and determine the highest
13939 	 * inhseqno already present; we'll use the next one for the new parent.
13940 	 * Also, if proposed child is a partition, it cannot already be
13941 	 * inheriting.
13942 	 *
13943 	 * Note: we do not reject the case where the child already inherits from
13944 	 * the parent indirectly; CREATE TABLE doesn't reject comparable cases.
13945 	 */
13946 	ScanKeyInit(&key,
13947 				Anum_pg_inherits_inhrelid,
13948 				BTEqualStrategyNumber, F_OIDEQ,
13949 				ObjectIdGetDatum(RelationGetRelid(child_rel)));
13950 	scan = systable_beginscan(catalogRelation, InheritsRelidSeqnoIndexId,
13951 							  true, NULL, 1, &key);
13952 
13953 	/* inhseqno sequences start at 1 */
13954 	inhseqno = 0;
13955 	while (HeapTupleIsValid(inheritsTuple = systable_getnext(scan)))
13956 	{
13957 		Form_pg_inherits inh = (Form_pg_inherits) GETSTRUCT(inheritsTuple);
13958 
13959 		if (inh->inhparent == RelationGetRelid(parent_rel))
13960 			ereport(ERROR,
13961 					(errcode(ERRCODE_DUPLICATE_TABLE),
13962 					 errmsg("relation \"%s\" would be inherited from more than once",
13963 							RelationGetRelationName(parent_rel))));
13964 
13965 		if (inh->inhseqno > inhseqno)
13966 			inhseqno = inh->inhseqno;
13967 	}
13968 	systable_endscan(scan);
13969 
13970 	/* Match up the columns and bump attinhcount as needed */
13971 	MergeAttributesIntoExisting(child_rel, parent_rel);
13972 
13973 	/* Match up the constraints and bump coninhcount as needed */
13974 	MergeConstraintsIntoExisting(child_rel, parent_rel);
13975 
13976 	/*
13977 	 * OK, it looks valid.  Make the catalog entries that show inheritance.
13978 	 */
13979 	StoreCatalogInheritance1(RelationGetRelid(child_rel),
13980 							 RelationGetRelid(parent_rel),
13981 							 inhseqno + 1,
13982 							 catalogRelation,
13983 							 parent_rel->rd_rel->relkind ==
13984 							 RELKIND_PARTITIONED_TABLE);
13985 
13986 	/* Now we're done with pg_inherits */
13987 	table_close(catalogRelation, RowExclusiveLock);
13988 }
13989 
13990 /*
13991  * Obtain the source-text form of the constraint expression for a check
13992  * constraint, given its pg_constraint tuple
13993  */
13994 static char *
decompile_conbin(HeapTuple contup,TupleDesc tupdesc)13995 decompile_conbin(HeapTuple contup, TupleDesc tupdesc)
13996 {
13997 	Form_pg_constraint con;
13998 	bool		isnull;
13999 	Datum		attr;
14000 	Datum		expr;
14001 
14002 	con = (Form_pg_constraint) GETSTRUCT(contup);
14003 	attr = heap_getattr(contup, Anum_pg_constraint_conbin, tupdesc, &isnull);
14004 	if (isnull)
14005 		elog(ERROR, "null conbin for constraint %u", con->oid);
14006 
14007 	expr = DirectFunctionCall2(pg_get_expr, attr,
14008 							   ObjectIdGetDatum(con->conrelid));
14009 	return TextDatumGetCString(expr);
14010 }
14011 
14012 /*
14013  * Determine whether two check constraints are functionally equivalent
14014  *
14015  * The test we apply is to see whether they reverse-compile to the same
14016  * source string.  This insulates us from issues like whether attributes
14017  * have the same physical column numbers in parent and child relations.
14018  */
14019 static bool
constraints_equivalent(HeapTuple a,HeapTuple b,TupleDesc tupleDesc)14020 constraints_equivalent(HeapTuple a, HeapTuple b, TupleDesc tupleDesc)
14021 {
14022 	Form_pg_constraint acon = (Form_pg_constraint) GETSTRUCT(a);
14023 	Form_pg_constraint bcon = (Form_pg_constraint) GETSTRUCT(b);
14024 
14025 	if (acon->condeferrable != bcon->condeferrable ||
14026 		acon->condeferred != bcon->condeferred ||
14027 		strcmp(decompile_conbin(a, tupleDesc),
14028 			   decompile_conbin(b, tupleDesc)) != 0)
14029 		return false;
14030 	else
14031 		return true;
14032 }
14033 
14034 /*
14035  * Check columns in child table match up with columns in parent, and increment
14036  * their attinhcount.
14037  *
14038  * Called by CreateInheritance
14039  *
14040  * Currently all parent columns must be found in child. Missing columns are an
14041  * error.  One day we might consider creating new columns like CREATE TABLE
14042  * does.  However, that is widely unpopular --- in the common use case of
14043  * partitioned tables it's a foot-gun.
14044  *
14045  * The data type must match exactly. If the parent column is NOT NULL then
14046  * the child must be as well. Defaults are not compared, however.
14047  */
14048 static void
MergeAttributesIntoExisting(Relation child_rel,Relation parent_rel)14049 MergeAttributesIntoExisting(Relation child_rel, Relation parent_rel)
14050 {
14051 	Relation	attrrel;
14052 	AttrNumber	parent_attno;
14053 	int			parent_natts;
14054 	TupleDesc	tupleDesc;
14055 	HeapTuple	tuple;
14056 	bool		child_is_partition = false;
14057 
14058 	attrrel = table_open(AttributeRelationId, RowExclusiveLock);
14059 
14060 	tupleDesc = RelationGetDescr(parent_rel);
14061 	parent_natts = tupleDesc->natts;
14062 
14063 	/* If parent_rel is a partitioned table, child_rel must be a partition */
14064 	if (parent_rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
14065 		child_is_partition = true;
14066 
14067 	for (parent_attno = 1; parent_attno <= parent_natts; parent_attno++)
14068 	{
14069 		Form_pg_attribute attribute = TupleDescAttr(tupleDesc,
14070 													parent_attno - 1);
14071 		char	   *attributeName = NameStr(attribute->attname);
14072 
14073 		/* Ignore dropped columns in the parent. */
14074 		if (attribute->attisdropped)
14075 			continue;
14076 
14077 		/* Find same column in child (matching on column name). */
14078 		tuple = SearchSysCacheCopyAttName(RelationGetRelid(child_rel),
14079 										  attributeName);
14080 		if (HeapTupleIsValid(tuple))
14081 		{
14082 			/* Check they are same type, typmod, and collation */
14083 			Form_pg_attribute childatt = (Form_pg_attribute) GETSTRUCT(tuple);
14084 
14085 			if (attribute->atttypid != childatt->atttypid ||
14086 				attribute->atttypmod != childatt->atttypmod)
14087 				ereport(ERROR,
14088 						(errcode(ERRCODE_DATATYPE_MISMATCH),
14089 						 errmsg("child table \"%s\" has different type for column \"%s\"",
14090 								RelationGetRelationName(child_rel),
14091 								attributeName)));
14092 
14093 			if (attribute->attcollation != childatt->attcollation)
14094 				ereport(ERROR,
14095 						(errcode(ERRCODE_COLLATION_MISMATCH),
14096 						 errmsg("child table \"%s\" has different collation for column \"%s\"",
14097 								RelationGetRelationName(child_rel),
14098 								attributeName)));
14099 
14100 			/*
14101 			 * Check child doesn't discard NOT NULL property.  (Other
14102 			 * constraints are checked elsewhere.)
14103 			 */
14104 			if (attribute->attnotnull && !childatt->attnotnull)
14105 				ereport(ERROR,
14106 						(errcode(ERRCODE_DATATYPE_MISMATCH),
14107 						 errmsg("column \"%s\" in child table must be marked NOT NULL",
14108 								attributeName)));
14109 
14110 			/*
14111 			 * If parent column is generated, child column must be, too.
14112 			 */
14113 			if (attribute->attgenerated && !childatt->attgenerated)
14114 				ereport(ERROR,
14115 						(errcode(ERRCODE_DATATYPE_MISMATCH),
14116 						 errmsg("column \"%s\" in child table must be a generated column",
14117 								attributeName)));
14118 
14119 			/*
14120 			 * Check that both generation expressions match.
14121 			 *
14122 			 * The test we apply is to see whether they reverse-compile to the
14123 			 * same source string.  This insulates us from issues like whether
14124 			 * attributes have the same physical column numbers in parent and
14125 			 * child relations.  (See also constraints_equivalent().)
14126 			 */
14127 			if (attribute->attgenerated && childatt->attgenerated)
14128 			{
14129 				TupleConstr *child_constr = child_rel->rd_att->constr;
14130 				TupleConstr *parent_constr = parent_rel->rd_att->constr;
14131 				char	   *child_expr = NULL;
14132 				char	   *parent_expr = NULL;
14133 
14134 				Assert(child_constr != NULL);
14135 				Assert(parent_constr != NULL);
14136 
14137 				for (int i = 0; i < child_constr->num_defval; i++)
14138 				{
14139 					if (child_constr->defval[i].adnum == childatt->attnum)
14140 					{
14141 						child_expr =
14142 							TextDatumGetCString(DirectFunctionCall2(pg_get_expr,
14143 																	CStringGetTextDatum(child_constr->defval[i].adbin),
14144 																	ObjectIdGetDatum(child_rel->rd_id)));
14145 						break;
14146 					}
14147 				}
14148 				Assert(child_expr != NULL);
14149 
14150 				for (int i = 0; i < parent_constr->num_defval; i++)
14151 				{
14152 					if (parent_constr->defval[i].adnum == attribute->attnum)
14153 					{
14154 						parent_expr =
14155 							TextDatumGetCString(DirectFunctionCall2(pg_get_expr,
14156 																	CStringGetTextDatum(parent_constr->defval[i].adbin),
14157 																	ObjectIdGetDatum(parent_rel->rd_id)));
14158 						break;
14159 					}
14160 				}
14161 				Assert(parent_expr != NULL);
14162 
14163 				if (strcmp(child_expr, parent_expr) != 0)
14164 					ereport(ERROR,
14165 						(errcode(ERRCODE_DATATYPE_MISMATCH),
14166 						 errmsg("column \"%s\" in child table has a conflicting generation expression",
14167 								attributeName)));
14168 			}
14169 
14170 			/*
14171 			 * OK, bump the child column's inheritance count.  (If we fail
14172 			 * later on, this change will just roll back.)
14173 			 */
14174 			childatt->attinhcount++;
14175 
14176 			/*
14177 			 * In case of partitions, we must enforce that value of attislocal
14178 			 * is same in all partitions. (Note: there are only inherited
14179 			 * attributes in partitions)
14180 			 */
14181 			if (child_is_partition)
14182 			{
14183 				Assert(childatt->attinhcount == 1);
14184 				childatt->attislocal = false;
14185 			}
14186 
14187 			CatalogTupleUpdate(attrrel, &tuple->t_self, tuple);
14188 			heap_freetuple(tuple);
14189 		}
14190 		else
14191 		{
14192 			ereport(ERROR,
14193 					(errcode(ERRCODE_DATATYPE_MISMATCH),
14194 					 errmsg("child table is missing column \"%s\"",
14195 							attributeName)));
14196 		}
14197 	}
14198 
14199 	table_close(attrrel, RowExclusiveLock);
14200 }
14201 
14202 /*
14203  * Check constraints in child table match up with constraints in parent,
14204  * and increment their coninhcount.
14205  *
14206  * Constraints that are marked ONLY in the parent are ignored.
14207  *
14208  * Called by CreateInheritance
14209  *
14210  * Currently all constraints in parent must be present in the child. One day we
14211  * may consider adding new constraints like CREATE TABLE does.
14212  *
14213  * XXX This is O(N^2) which may be an issue with tables with hundreds of
14214  * constraints. As long as tables have more like 10 constraints it shouldn't be
14215  * a problem though. Even 100 constraints ought not be the end of the world.
14216  *
14217  * XXX See MergeWithExistingConstraint too if you change this code.
14218  */
14219 static void
MergeConstraintsIntoExisting(Relation child_rel,Relation parent_rel)14220 MergeConstraintsIntoExisting(Relation child_rel, Relation parent_rel)
14221 {
14222 	Relation	catalog_relation;
14223 	TupleDesc	tuple_desc;
14224 	SysScanDesc parent_scan;
14225 	ScanKeyData parent_key;
14226 	HeapTuple	parent_tuple;
14227 	bool		child_is_partition = false;
14228 
14229 	catalog_relation = table_open(ConstraintRelationId, RowExclusiveLock);
14230 	tuple_desc = RelationGetDescr(catalog_relation);
14231 
14232 	/* If parent_rel is a partitioned table, child_rel must be a partition */
14233 	if (parent_rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
14234 		child_is_partition = true;
14235 
14236 	/* Outer loop scans through the parent's constraint definitions */
14237 	ScanKeyInit(&parent_key,
14238 				Anum_pg_constraint_conrelid,
14239 				BTEqualStrategyNumber, F_OIDEQ,
14240 				ObjectIdGetDatum(RelationGetRelid(parent_rel)));
14241 	parent_scan = systable_beginscan(catalog_relation, ConstraintRelidTypidNameIndexId,
14242 									 true, NULL, 1, &parent_key);
14243 
14244 	while (HeapTupleIsValid(parent_tuple = systable_getnext(parent_scan)))
14245 	{
14246 		Form_pg_constraint parent_con = (Form_pg_constraint) GETSTRUCT(parent_tuple);
14247 		SysScanDesc child_scan;
14248 		ScanKeyData child_key;
14249 		HeapTuple	child_tuple;
14250 		bool		found = false;
14251 
14252 		if (parent_con->contype != CONSTRAINT_CHECK)
14253 			continue;
14254 
14255 		/* if the parent's constraint is marked NO INHERIT, it's not inherited */
14256 		if (parent_con->connoinherit)
14257 			continue;
14258 
14259 		/* Search for a child constraint matching this one */
14260 		ScanKeyInit(&child_key,
14261 					Anum_pg_constraint_conrelid,
14262 					BTEqualStrategyNumber, F_OIDEQ,
14263 					ObjectIdGetDatum(RelationGetRelid(child_rel)));
14264 		child_scan = systable_beginscan(catalog_relation, ConstraintRelidTypidNameIndexId,
14265 										true, NULL, 1, &child_key);
14266 
14267 		while (HeapTupleIsValid(child_tuple = systable_getnext(child_scan)))
14268 		{
14269 			Form_pg_constraint child_con = (Form_pg_constraint) GETSTRUCT(child_tuple);
14270 			HeapTuple	child_copy;
14271 
14272 			if (child_con->contype != CONSTRAINT_CHECK)
14273 				continue;
14274 
14275 			if (strcmp(NameStr(parent_con->conname),
14276 					   NameStr(child_con->conname)) != 0)
14277 				continue;
14278 
14279 			if (!constraints_equivalent(parent_tuple, child_tuple, tuple_desc))
14280 				ereport(ERROR,
14281 						(errcode(ERRCODE_DATATYPE_MISMATCH),
14282 						 errmsg("child table \"%s\" has different definition for check constraint \"%s\"",
14283 								RelationGetRelationName(child_rel),
14284 								NameStr(parent_con->conname))));
14285 
14286 			/* If the child constraint is "no inherit" then cannot merge */
14287 			if (child_con->connoinherit)
14288 				ereport(ERROR,
14289 						(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
14290 						 errmsg("constraint \"%s\" conflicts with non-inherited constraint on child table \"%s\"",
14291 								NameStr(child_con->conname),
14292 								RelationGetRelationName(child_rel))));
14293 
14294 			/*
14295 			 * If the child constraint is "not valid" then cannot merge with a
14296 			 * valid parent constraint
14297 			 */
14298 			if (parent_con->convalidated && !child_con->convalidated)
14299 				ereport(ERROR,
14300 						(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
14301 						 errmsg("constraint \"%s\" conflicts with NOT VALID constraint on child table \"%s\"",
14302 								NameStr(child_con->conname),
14303 								RelationGetRelationName(child_rel))));
14304 
14305 			/*
14306 			 * OK, bump the child constraint's inheritance count.  (If we fail
14307 			 * later on, this change will just roll back.)
14308 			 */
14309 			child_copy = heap_copytuple(child_tuple);
14310 			child_con = (Form_pg_constraint) GETSTRUCT(child_copy);
14311 			child_con->coninhcount++;
14312 
14313 			/*
14314 			 * In case of partitions, an inherited constraint must be
14315 			 * inherited only once since it cannot have multiple parents and
14316 			 * it is never considered local.
14317 			 */
14318 			if (child_is_partition)
14319 			{
14320 				Assert(child_con->coninhcount == 1);
14321 				child_con->conislocal = false;
14322 			}
14323 
14324 			CatalogTupleUpdate(catalog_relation, &child_copy->t_self, child_copy);
14325 			heap_freetuple(child_copy);
14326 
14327 			found = true;
14328 			break;
14329 		}
14330 
14331 		systable_endscan(child_scan);
14332 
14333 		if (!found)
14334 			ereport(ERROR,
14335 					(errcode(ERRCODE_DATATYPE_MISMATCH),
14336 					 errmsg("child table is missing constraint \"%s\"",
14337 							NameStr(parent_con->conname))));
14338 	}
14339 
14340 	systable_endscan(parent_scan);
14341 	table_close(catalog_relation, RowExclusiveLock);
14342 }
14343 
14344 /*
14345  * ALTER TABLE NO INHERIT
14346  *
14347  * Return value is the address of the relation that is no longer parent.
14348  */
14349 static ObjectAddress
ATExecDropInherit(Relation rel,RangeVar * parent,LOCKMODE lockmode)14350 ATExecDropInherit(Relation rel, RangeVar *parent, LOCKMODE lockmode)
14351 {
14352 	ObjectAddress address;
14353 	Relation	parent_rel;
14354 
14355 	if (rel->rd_rel->relispartition)
14356 		ereport(ERROR,
14357 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
14358 				 errmsg("cannot change inheritance of a partition")));
14359 
14360 	/*
14361 	 * AccessShareLock on the parent is probably enough, seeing that DROP
14362 	 * TABLE doesn't lock parent tables at all.  We need some lock since we'll
14363 	 * be inspecting the parent's schema.
14364 	 */
14365 	parent_rel = table_openrv(parent, AccessShareLock);
14366 
14367 	/*
14368 	 * We don't bother to check ownership of the parent table --- ownership of
14369 	 * the child is presumed enough rights.
14370 	 */
14371 
14372 	/* Off to RemoveInheritance() where most of the work happens */
14373 	RemoveInheritance(rel, parent_rel);
14374 
14375 	ObjectAddressSet(address, RelationRelationId,
14376 					 RelationGetRelid(parent_rel));
14377 
14378 	/* keep our lock on the parent relation until commit */
14379 	table_close(parent_rel, NoLock);
14380 
14381 	return address;
14382 }
14383 
14384 /*
14385  * RemoveInheritance
14386  *
14387  * Drop a parent from the child's parents. This just adjusts the attinhcount
14388  * and attislocal of the columns and removes the pg_inherit and pg_depend
14389  * entries.
14390  *
14391  * If attinhcount goes to 0 then attislocal gets set to true. If it goes back
14392  * up attislocal stays true, which means if a child is ever removed from a
14393  * parent then its columns will never be automatically dropped which may
14394  * surprise. But at least we'll never surprise by dropping columns someone
14395  * isn't expecting to be dropped which would actually mean data loss.
14396  *
14397  * coninhcount and conislocal for inherited constraints are adjusted in
14398  * exactly the same way.
14399  *
14400  * Common to ATExecDropInherit() and ATExecDetachPartition().
14401  */
14402 static void
RemoveInheritance(Relation child_rel,Relation parent_rel)14403 RemoveInheritance(Relation child_rel, Relation parent_rel)
14404 {
14405 	Relation	catalogRelation;
14406 	SysScanDesc scan;
14407 	ScanKeyData key[3];
14408 	HeapTuple	attributeTuple,
14409 				constraintTuple;
14410 	List	   *connames;
14411 	bool		found;
14412 	bool		child_is_partition = false;
14413 
14414 	/* If parent_rel is a partitioned table, child_rel must be a partition */
14415 	if (parent_rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
14416 		child_is_partition = true;
14417 
14418 	found = DeleteInheritsTuple(RelationGetRelid(child_rel),
14419 								RelationGetRelid(parent_rel));
14420 	if (!found)
14421 	{
14422 		if (child_is_partition)
14423 			ereport(ERROR,
14424 					(errcode(ERRCODE_UNDEFINED_TABLE),
14425 					 errmsg("relation \"%s\" is not a partition of relation \"%s\"",
14426 							RelationGetRelationName(child_rel),
14427 							RelationGetRelationName(parent_rel))));
14428 		else
14429 			ereport(ERROR,
14430 					(errcode(ERRCODE_UNDEFINED_TABLE),
14431 					 errmsg("relation \"%s\" is not a parent of relation \"%s\"",
14432 							RelationGetRelationName(parent_rel),
14433 							RelationGetRelationName(child_rel))));
14434 	}
14435 
14436 	/*
14437 	 * Search through child columns looking for ones matching parent rel
14438 	 */
14439 	catalogRelation = table_open(AttributeRelationId, RowExclusiveLock);
14440 	ScanKeyInit(&key[0],
14441 				Anum_pg_attribute_attrelid,
14442 				BTEqualStrategyNumber, F_OIDEQ,
14443 				ObjectIdGetDatum(RelationGetRelid(child_rel)));
14444 	scan = systable_beginscan(catalogRelation, AttributeRelidNumIndexId,
14445 							  true, NULL, 1, key);
14446 	while (HeapTupleIsValid(attributeTuple = systable_getnext(scan)))
14447 	{
14448 		Form_pg_attribute att = (Form_pg_attribute) GETSTRUCT(attributeTuple);
14449 
14450 		/* Ignore if dropped or not inherited */
14451 		if (att->attisdropped)
14452 			continue;
14453 		if (att->attinhcount <= 0)
14454 			continue;
14455 
14456 		if (SearchSysCacheExistsAttName(RelationGetRelid(parent_rel),
14457 										NameStr(att->attname)))
14458 		{
14459 			/* Decrement inhcount and possibly set islocal to true */
14460 			HeapTuple	copyTuple = heap_copytuple(attributeTuple);
14461 			Form_pg_attribute copy_att = (Form_pg_attribute) GETSTRUCT(copyTuple);
14462 
14463 			copy_att->attinhcount--;
14464 			if (copy_att->attinhcount == 0)
14465 				copy_att->attislocal = true;
14466 
14467 			CatalogTupleUpdate(catalogRelation, &copyTuple->t_self, copyTuple);
14468 			heap_freetuple(copyTuple);
14469 		}
14470 	}
14471 	systable_endscan(scan);
14472 	table_close(catalogRelation, RowExclusiveLock);
14473 
14474 	/*
14475 	 * Likewise, find inherited check constraints and disinherit them. To do
14476 	 * this, we first need a list of the names of the parent's check
14477 	 * constraints.  (We cheat a bit by only checking for name matches,
14478 	 * assuming that the expressions will match.)
14479 	 */
14480 	catalogRelation = table_open(ConstraintRelationId, RowExclusiveLock);
14481 	ScanKeyInit(&key[0],
14482 				Anum_pg_constraint_conrelid,
14483 				BTEqualStrategyNumber, F_OIDEQ,
14484 				ObjectIdGetDatum(RelationGetRelid(parent_rel)));
14485 	scan = systable_beginscan(catalogRelation, ConstraintRelidTypidNameIndexId,
14486 							  true, NULL, 1, key);
14487 
14488 	connames = NIL;
14489 
14490 	while (HeapTupleIsValid(constraintTuple = systable_getnext(scan)))
14491 	{
14492 		Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(constraintTuple);
14493 
14494 		if (con->contype == CONSTRAINT_CHECK)
14495 			connames = lappend(connames, pstrdup(NameStr(con->conname)));
14496 	}
14497 
14498 	systable_endscan(scan);
14499 
14500 	/* Now scan the child's constraints */
14501 	ScanKeyInit(&key[0],
14502 				Anum_pg_constraint_conrelid,
14503 				BTEqualStrategyNumber, F_OIDEQ,
14504 				ObjectIdGetDatum(RelationGetRelid(child_rel)));
14505 	scan = systable_beginscan(catalogRelation, ConstraintRelidTypidNameIndexId,
14506 							  true, NULL, 1, key);
14507 
14508 	while (HeapTupleIsValid(constraintTuple = systable_getnext(scan)))
14509 	{
14510 		Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(constraintTuple);
14511 		bool		match;
14512 		ListCell   *lc;
14513 
14514 		if (con->contype != CONSTRAINT_CHECK)
14515 			continue;
14516 
14517 		match = false;
14518 		foreach(lc, connames)
14519 		{
14520 			if (strcmp(NameStr(con->conname), (char *) lfirst(lc)) == 0)
14521 			{
14522 				match = true;
14523 				break;
14524 			}
14525 		}
14526 
14527 		if (match)
14528 		{
14529 			/* Decrement inhcount and possibly set islocal to true */
14530 			HeapTuple	copyTuple = heap_copytuple(constraintTuple);
14531 			Form_pg_constraint copy_con = (Form_pg_constraint) GETSTRUCT(copyTuple);
14532 
14533 			if (copy_con->coninhcount <= 0) /* shouldn't happen */
14534 				elog(ERROR, "relation %u has non-inherited constraint \"%s\"",
14535 					 RelationGetRelid(child_rel), NameStr(copy_con->conname));
14536 
14537 			copy_con->coninhcount--;
14538 			if (copy_con->coninhcount == 0)
14539 				copy_con->conislocal = true;
14540 
14541 			CatalogTupleUpdate(catalogRelation, &copyTuple->t_self, copyTuple);
14542 			heap_freetuple(copyTuple);
14543 		}
14544 	}
14545 
14546 	systable_endscan(scan);
14547 	table_close(catalogRelation, RowExclusiveLock);
14548 
14549 	drop_parent_dependency(RelationGetRelid(child_rel),
14550 						   RelationRelationId,
14551 						   RelationGetRelid(parent_rel),
14552 						   child_dependency_type(child_is_partition));
14553 
14554 	/*
14555 	 * Post alter hook of this inherits. Since object_access_hook doesn't take
14556 	 * multiple object identifiers, we relay oid of parent relation using
14557 	 * auxiliary_id argument.
14558 	 */
14559 	InvokeObjectPostAlterHookArg(InheritsRelationId,
14560 								 RelationGetRelid(child_rel), 0,
14561 								 RelationGetRelid(parent_rel), false);
14562 }
14563 
14564 /*
14565  * Drop the dependency created by StoreCatalogInheritance1 (CREATE TABLE
14566  * INHERITS/ALTER TABLE INHERIT -- refclassid will be RelationRelationId) or
14567  * heap_create_with_catalog (CREATE TABLE OF/ALTER TABLE OF -- refclassid will
14568  * be TypeRelationId).  There's no convenient way to do this, so go trawling
14569  * through pg_depend.
14570  */
14571 static void
drop_parent_dependency(Oid relid,Oid refclassid,Oid refobjid,DependencyType deptype)14572 drop_parent_dependency(Oid relid, Oid refclassid, Oid refobjid,
14573 					   DependencyType deptype)
14574 {
14575 	Relation	catalogRelation;
14576 	SysScanDesc scan;
14577 	ScanKeyData key[3];
14578 	HeapTuple	depTuple;
14579 
14580 	catalogRelation = table_open(DependRelationId, RowExclusiveLock);
14581 
14582 	ScanKeyInit(&key[0],
14583 				Anum_pg_depend_classid,
14584 				BTEqualStrategyNumber, F_OIDEQ,
14585 				ObjectIdGetDatum(RelationRelationId));
14586 	ScanKeyInit(&key[1],
14587 				Anum_pg_depend_objid,
14588 				BTEqualStrategyNumber, F_OIDEQ,
14589 				ObjectIdGetDatum(relid));
14590 	ScanKeyInit(&key[2],
14591 				Anum_pg_depend_objsubid,
14592 				BTEqualStrategyNumber, F_INT4EQ,
14593 				Int32GetDatum(0));
14594 
14595 	scan = systable_beginscan(catalogRelation, DependDependerIndexId, true,
14596 							  NULL, 3, key);
14597 
14598 	while (HeapTupleIsValid(depTuple = systable_getnext(scan)))
14599 	{
14600 		Form_pg_depend dep = (Form_pg_depend) GETSTRUCT(depTuple);
14601 
14602 		if (dep->refclassid == refclassid &&
14603 			dep->refobjid == refobjid &&
14604 			dep->refobjsubid == 0 &&
14605 			dep->deptype == deptype)
14606 			CatalogTupleDelete(catalogRelation, &depTuple->t_self);
14607 	}
14608 
14609 	systable_endscan(scan);
14610 	table_close(catalogRelation, RowExclusiveLock);
14611 }
14612 
14613 /*
14614  * ALTER TABLE OF
14615  *
14616  * Attach a table to a composite type, as though it had been created with CREATE
14617  * TABLE OF.  All attname, atttypid, atttypmod and attcollation must match.  The
14618  * subject table must not have inheritance parents.  These restrictions ensure
14619  * that you cannot create a configuration impossible with CREATE TABLE OF alone.
14620  *
14621  * The address of the type is returned.
14622  */
14623 static ObjectAddress
ATExecAddOf(Relation rel,const TypeName * ofTypename,LOCKMODE lockmode)14624 ATExecAddOf(Relation rel, const TypeName *ofTypename, LOCKMODE lockmode)
14625 {
14626 	Oid			relid = RelationGetRelid(rel);
14627 	Type		typetuple;
14628 	Form_pg_type typeform;
14629 	Oid			typeid;
14630 	Relation	inheritsRelation,
14631 				relationRelation;
14632 	SysScanDesc scan;
14633 	ScanKeyData key;
14634 	AttrNumber	table_attno,
14635 				type_attno;
14636 	TupleDesc	typeTupleDesc,
14637 				tableTupleDesc;
14638 	ObjectAddress tableobj,
14639 				typeobj;
14640 	HeapTuple	classtuple;
14641 
14642 	/* Validate the type. */
14643 	typetuple = typenameType(NULL, ofTypename, NULL);
14644 	check_of_type(typetuple);
14645 	typeform = (Form_pg_type) GETSTRUCT(typetuple);
14646 	typeid = typeform->oid;
14647 
14648 	/* Fail if the table has any inheritance parents. */
14649 	inheritsRelation = table_open(InheritsRelationId, AccessShareLock);
14650 	ScanKeyInit(&key,
14651 				Anum_pg_inherits_inhrelid,
14652 				BTEqualStrategyNumber, F_OIDEQ,
14653 				ObjectIdGetDatum(relid));
14654 	scan = systable_beginscan(inheritsRelation, InheritsRelidSeqnoIndexId,
14655 							  true, NULL, 1, &key);
14656 	if (HeapTupleIsValid(systable_getnext(scan)))
14657 		ereport(ERROR,
14658 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
14659 				 errmsg("typed tables cannot inherit")));
14660 	systable_endscan(scan);
14661 	table_close(inheritsRelation, AccessShareLock);
14662 
14663 	/*
14664 	 * Check the tuple descriptors for compatibility.  Unlike inheritance, we
14665 	 * require that the order also match.  However, attnotnull need not match.
14666 	 */
14667 	typeTupleDesc = lookup_rowtype_tupdesc(typeid, -1);
14668 	tableTupleDesc = RelationGetDescr(rel);
14669 	table_attno = 1;
14670 	for (type_attno = 1; type_attno <= typeTupleDesc->natts; type_attno++)
14671 	{
14672 		Form_pg_attribute type_attr,
14673 					table_attr;
14674 		const char *type_attname,
14675 				   *table_attname;
14676 
14677 		/* Get the next non-dropped type attribute. */
14678 		type_attr = TupleDescAttr(typeTupleDesc, type_attno - 1);
14679 		if (type_attr->attisdropped)
14680 			continue;
14681 		type_attname = NameStr(type_attr->attname);
14682 
14683 		/* Get the next non-dropped table attribute. */
14684 		do
14685 		{
14686 			if (table_attno > tableTupleDesc->natts)
14687 				ereport(ERROR,
14688 						(errcode(ERRCODE_DATATYPE_MISMATCH),
14689 						 errmsg("table is missing column \"%s\"",
14690 								type_attname)));
14691 			table_attr = TupleDescAttr(tableTupleDesc, table_attno - 1);
14692 			table_attno++;
14693 		} while (table_attr->attisdropped);
14694 		table_attname = NameStr(table_attr->attname);
14695 
14696 		/* Compare name. */
14697 		if (strncmp(table_attname, type_attname, NAMEDATALEN) != 0)
14698 			ereport(ERROR,
14699 					(errcode(ERRCODE_DATATYPE_MISMATCH),
14700 					 errmsg("table has column \"%s\" where type requires \"%s\"",
14701 							table_attname, type_attname)));
14702 
14703 		/* Compare type. */
14704 		if (table_attr->atttypid != type_attr->atttypid ||
14705 			table_attr->atttypmod != type_attr->atttypmod ||
14706 			table_attr->attcollation != type_attr->attcollation)
14707 			ereport(ERROR,
14708 					(errcode(ERRCODE_DATATYPE_MISMATCH),
14709 					 errmsg("table \"%s\" has different type for column \"%s\"",
14710 							RelationGetRelationName(rel), type_attname)));
14711 	}
14712 	DecrTupleDescRefCount(typeTupleDesc);
14713 
14714 	/* Any remaining columns at the end of the table had better be dropped. */
14715 	for (; table_attno <= tableTupleDesc->natts; table_attno++)
14716 	{
14717 		Form_pg_attribute table_attr = TupleDescAttr(tableTupleDesc,
14718 													 table_attno - 1);
14719 
14720 		if (!table_attr->attisdropped)
14721 			ereport(ERROR,
14722 					(errcode(ERRCODE_DATATYPE_MISMATCH),
14723 					 errmsg("table has extra column \"%s\"",
14724 							NameStr(table_attr->attname))));
14725 	}
14726 
14727 	/* If the table was already typed, drop the existing dependency. */
14728 	if (rel->rd_rel->reloftype)
14729 		drop_parent_dependency(relid, TypeRelationId, rel->rd_rel->reloftype,
14730 							   DEPENDENCY_NORMAL);
14731 
14732 	/* Record a dependency on the new type. */
14733 	tableobj.classId = RelationRelationId;
14734 	tableobj.objectId = relid;
14735 	tableobj.objectSubId = 0;
14736 	typeobj.classId = TypeRelationId;
14737 	typeobj.objectId = typeid;
14738 	typeobj.objectSubId = 0;
14739 	recordDependencyOn(&tableobj, &typeobj, DEPENDENCY_NORMAL);
14740 
14741 	/* Update pg_class.reloftype */
14742 	relationRelation = table_open(RelationRelationId, RowExclusiveLock);
14743 	classtuple = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
14744 	if (!HeapTupleIsValid(classtuple))
14745 		elog(ERROR, "cache lookup failed for relation %u", relid);
14746 	((Form_pg_class) GETSTRUCT(classtuple))->reloftype = typeid;
14747 	CatalogTupleUpdate(relationRelation, &classtuple->t_self, classtuple);
14748 
14749 	InvokeObjectPostAlterHook(RelationRelationId, relid, 0);
14750 
14751 	heap_freetuple(classtuple);
14752 	table_close(relationRelation, RowExclusiveLock);
14753 
14754 	ReleaseSysCache(typetuple);
14755 
14756 	return typeobj;
14757 }
14758 
14759 /*
14760  * ALTER TABLE NOT OF
14761  *
14762  * Detach a typed table from its originating type.  Just clear reloftype and
14763  * remove the dependency.
14764  */
14765 static void
ATExecDropOf(Relation rel,LOCKMODE lockmode)14766 ATExecDropOf(Relation rel, LOCKMODE lockmode)
14767 {
14768 	Oid			relid = RelationGetRelid(rel);
14769 	Relation	relationRelation;
14770 	HeapTuple	tuple;
14771 
14772 	if (!OidIsValid(rel->rd_rel->reloftype))
14773 		ereport(ERROR,
14774 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
14775 				 errmsg("\"%s\" is not a typed table",
14776 						RelationGetRelationName(rel))));
14777 
14778 	/*
14779 	 * We don't bother to check ownership of the type --- ownership of the
14780 	 * table is presumed enough rights.  No lock required on the type, either.
14781 	 */
14782 
14783 	drop_parent_dependency(relid, TypeRelationId, rel->rd_rel->reloftype,
14784 						   DEPENDENCY_NORMAL);
14785 
14786 	/* Clear pg_class.reloftype */
14787 	relationRelation = table_open(RelationRelationId, RowExclusiveLock);
14788 	tuple = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
14789 	if (!HeapTupleIsValid(tuple))
14790 		elog(ERROR, "cache lookup failed for relation %u", relid);
14791 	((Form_pg_class) GETSTRUCT(tuple))->reloftype = InvalidOid;
14792 	CatalogTupleUpdate(relationRelation, &tuple->t_self, tuple);
14793 
14794 	InvokeObjectPostAlterHook(RelationRelationId, relid, 0);
14795 
14796 	heap_freetuple(tuple);
14797 	table_close(relationRelation, RowExclusiveLock);
14798 }
14799 
14800 /*
14801  * relation_mark_replica_identity: Update a table's replica identity
14802  *
14803  * Iff ri_type = REPLICA_IDENTITY_INDEX, indexOid must be the Oid of a suitable
14804  * index. Otherwise, it should be InvalidOid.
14805  */
14806 static void
relation_mark_replica_identity(Relation rel,char ri_type,Oid indexOid,bool is_internal)14807 relation_mark_replica_identity(Relation rel, char ri_type, Oid indexOid,
14808 							   bool is_internal)
14809 {
14810 	Relation	pg_index;
14811 	Relation	pg_class;
14812 	HeapTuple	pg_class_tuple;
14813 	HeapTuple	pg_index_tuple;
14814 	Form_pg_class pg_class_form;
14815 	Form_pg_index pg_index_form;
14816 
14817 	ListCell   *index;
14818 
14819 	/*
14820 	 * Check whether relreplident has changed, and update it if so.
14821 	 */
14822 	pg_class = table_open(RelationRelationId, RowExclusiveLock);
14823 	pg_class_tuple = SearchSysCacheCopy1(RELOID,
14824 										 ObjectIdGetDatum(RelationGetRelid(rel)));
14825 	if (!HeapTupleIsValid(pg_class_tuple))
14826 		elog(ERROR, "cache lookup failed for relation \"%s\"",
14827 			 RelationGetRelationName(rel));
14828 	pg_class_form = (Form_pg_class) GETSTRUCT(pg_class_tuple);
14829 	if (pg_class_form->relreplident != ri_type)
14830 	{
14831 		pg_class_form->relreplident = ri_type;
14832 		CatalogTupleUpdate(pg_class, &pg_class_tuple->t_self, pg_class_tuple);
14833 	}
14834 	table_close(pg_class, RowExclusiveLock);
14835 	heap_freetuple(pg_class_tuple);
14836 
14837 	/*
14838 	 * Check whether the correct index is marked indisreplident; if so, we're
14839 	 * done.
14840 	 */
14841 	if (OidIsValid(indexOid))
14842 	{
14843 		Assert(ri_type == REPLICA_IDENTITY_INDEX);
14844 
14845 		pg_index_tuple = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(indexOid));
14846 		if (!HeapTupleIsValid(pg_index_tuple))
14847 			elog(ERROR, "cache lookup failed for index %u", indexOid);
14848 		pg_index_form = (Form_pg_index) GETSTRUCT(pg_index_tuple);
14849 
14850 		if (pg_index_form->indisreplident)
14851 		{
14852 			ReleaseSysCache(pg_index_tuple);
14853 			return;
14854 		}
14855 		ReleaseSysCache(pg_index_tuple);
14856 	}
14857 
14858 	/*
14859 	 * Clear the indisreplident flag from any index that had it previously,
14860 	 * and set it for any index that should have it now.
14861 	 */
14862 	pg_index = table_open(IndexRelationId, RowExclusiveLock);
14863 	foreach(index, RelationGetIndexList(rel))
14864 	{
14865 		Oid			thisIndexOid = lfirst_oid(index);
14866 		bool		dirty = false;
14867 
14868 		pg_index_tuple = SearchSysCacheCopy1(INDEXRELID,
14869 											 ObjectIdGetDatum(thisIndexOid));
14870 		if (!HeapTupleIsValid(pg_index_tuple))
14871 			elog(ERROR, "cache lookup failed for index %u", thisIndexOid);
14872 		pg_index_form = (Form_pg_index) GETSTRUCT(pg_index_tuple);
14873 
14874 		/*
14875 		 * Unset the bit if set.  We know it's wrong because we checked this
14876 		 * earlier.
14877 		 */
14878 		if (pg_index_form->indisreplident)
14879 		{
14880 			dirty = true;
14881 			pg_index_form->indisreplident = false;
14882 		}
14883 		else if (thisIndexOid == indexOid)
14884 		{
14885 			dirty = true;
14886 			pg_index_form->indisreplident = true;
14887 		}
14888 
14889 		if (dirty)
14890 		{
14891 			CatalogTupleUpdate(pg_index, &pg_index_tuple->t_self, pg_index_tuple);
14892 			InvokeObjectPostAlterHookArg(IndexRelationId, thisIndexOid, 0,
14893 										 InvalidOid, is_internal);
14894 		}
14895 		heap_freetuple(pg_index_tuple);
14896 	}
14897 
14898 	table_close(pg_index, RowExclusiveLock);
14899 }
14900 
14901 /*
14902  * ALTER TABLE <name> REPLICA IDENTITY ...
14903  */
14904 static void
ATExecReplicaIdentity(Relation rel,ReplicaIdentityStmt * stmt,LOCKMODE lockmode)14905 ATExecReplicaIdentity(Relation rel, ReplicaIdentityStmt *stmt, LOCKMODE lockmode)
14906 {
14907 	Oid			indexOid;
14908 	Relation	indexRel;
14909 	int			key;
14910 
14911 	if (stmt->identity_type == REPLICA_IDENTITY_DEFAULT)
14912 	{
14913 		relation_mark_replica_identity(rel, stmt->identity_type, InvalidOid, true);
14914 		return;
14915 	}
14916 	else if (stmt->identity_type == REPLICA_IDENTITY_FULL)
14917 	{
14918 		relation_mark_replica_identity(rel, stmt->identity_type, InvalidOid, true);
14919 		return;
14920 	}
14921 	else if (stmt->identity_type == REPLICA_IDENTITY_NOTHING)
14922 	{
14923 		relation_mark_replica_identity(rel, stmt->identity_type, InvalidOid, true);
14924 		return;
14925 	}
14926 	else if (stmt->identity_type == REPLICA_IDENTITY_INDEX)
14927 	{
14928 		 /* fallthrough */ ;
14929 	}
14930 	else
14931 		elog(ERROR, "unexpected identity type %u", stmt->identity_type);
14932 
14933 
14934 	/* Check that the index exists */
14935 	indexOid = get_relname_relid(stmt->name, rel->rd_rel->relnamespace);
14936 	if (!OidIsValid(indexOid))
14937 		ereport(ERROR,
14938 				(errcode(ERRCODE_UNDEFINED_OBJECT),
14939 				 errmsg("index \"%s\" for table \"%s\" does not exist",
14940 						stmt->name, RelationGetRelationName(rel))));
14941 
14942 	indexRel = index_open(indexOid, ShareLock);
14943 
14944 	/* Check that the index is on the relation we're altering. */
14945 	if (indexRel->rd_index == NULL ||
14946 		indexRel->rd_index->indrelid != RelationGetRelid(rel))
14947 		ereport(ERROR,
14948 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
14949 				 errmsg("\"%s\" is not an index for table \"%s\"",
14950 						RelationGetRelationName(indexRel),
14951 						RelationGetRelationName(rel))));
14952 	/* The AM must support uniqueness, and the index must in fact be unique. */
14953 	if (!indexRel->rd_indam->amcanunique ||
14954 		!indexRel->rd_index->indisunique)
14955 		ereport(ERROR,
14956 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
14957 				 errmsg("cannot use non-unique index \"%s\" as replica identity",
14958 						RelationGetRelationName(indexRel))));
14959 	/* Deferred indexes are not guaranteed to be always unique. */
14960 	if (!indexRel->rd_index->indimmediate)
14961 		ereport(ERROR,
14962 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
14963 				 errmsg("cannot use non-immediate index \"%s\" as replica identity",
14964 						RelationGetRelationName(indexRel))));
14965 	/* Expression indexes aren't supported. */
14966 	if (RelationGetIndexExpressions(indexRel) != NIL)
14967 		ereport(ERROR,
14968 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
14969 				 errmsg("cannot use expression index \"%s\" as replica identity",
14970 						RelationGetRelationName(indexRel))));
14971 	/* Predicate indexes aren't supported. */
14972 	if (RelationGetIndexPredicate(indexRel) != NIL)
14973 		ereport(ERROR,
14974 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
14975 				 errmsg("cannot use partial index \"%s\" as replica identity",
14976 						RelationGetRelationName(indexRel))));
14977 	/* And neither are invalid indexes. */
14978 	if (!indexRel->rd_index->indisvalid)
14979 		ereport(ERROR,
14980 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
14981 				 errmsg("cannot use invalid index \"%s\" as replica identity",
14982 						RelationGetRelationName(indexRel))));
14983 
14984 	/* Check index for nullable columns. */
14985 	for (key = 0; key < IndexRelationGetNumberOfKeyAttributes(indexRel); key++)
14986 	{
14987 		int16		attno = indexRel->rd_index->indkey.values[key];
14988 		Form_pg_attribute attr;
14989 
14990 		/*
14991 		 * Reject any other system columns.  (Going forward, we'll disallow
14992 		 * indexes containing such columns in the first place, but they might
14993 		 * exist in older branches.)
14994 		 */
14995 		if (attno <= 0)
14996 			ereport(ERROR,
14997 					(errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
14998 					 errmsg("index \"%s\" cannot be used as replica identity because column %d is a system column",
14999 							RelationGetRelationName(indexRel), attno)));
15000 
15001 		attr = TupleDescAttr(rel->rd_att, attno - 1);
15002 		if (!attr->attnotnull)
15003 			ereport(ERROR,
15004 					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
15005 					 errmsg("index \"%s\" cannot be used as replica identity because column \"%s\" is nullable",
15006 							RelationGetRelationName(indexRel),
15007 							NameStr(attr->attname))));
15008 	}
15009 
15010 	/* This index is suitable for use as a replica identity. Mark it. */
15011 	relation_mark_replica_identity(rel, stmt->identity_type, indexOid, true);
15012 
15013 	index_close(indexRel, NoLock);
15014 }
15015 
15016 /*
15017  * ALTER TABLE ENABLE/DISABLE ROW LEVEL SECURITY
15018  */
15019 static void
ATExecEnableRowSecurity(Relation rel)15020 ATExecEnableRowSecurity(Relation rel)
15021 {
15022 	Relation	pg_class;
15023 	Oid			relid;
15024 	HeapTuple	tuple;
15025 
15026 	relid = RelationGetRelid(rel);
15027 
15028 	pg_class = table_open(RelationRelationId, RowExclusiveLock);
15029 
15030 	tuple = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
15031 
15032 	if (!HeapTupleIsValid(tuple))
15033 		elog(ERROR, "cache lookup failed for relation %u", relid);
15034 
15035 	((Form_pg_class) GETSTRUCT(tuple))->relrowsecurity = true;
15036 	CatalogTupleUpdate(pg_class, &tuple->t_self, tuple);
15037 
15038 	table_close(pg_class, RowExclusiveLock);
15039 	heap_freetuple(tuple);
15040 }
15041 
15042 static void
ATExecDisableRowSecurity(Relation rel)15043 ATExecDisableRowSecurity(Relation rel)
15044 {
15045 	Relation	pg_class;
15046 	Oid			relid;
15047 	HeapTuple	tuple;
15048 
15049 	relid = RelationGetRelid(rel);
15050 
15051 	/* Pull the record for this relation and update it */
15052 	pg_class = table_open(RelationRelationId, RowExclusiveLock);
15053 
15054 	tuple = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
15055 
15056 	if (!HeapTupleIsValid(tuple))
15057 		elog(ERROR, "cache lookup failed for relation %u", relid);
15058 
15059 	((Form_pg_class) GETSTRUCT(tuple))->relrowsecurity = false;
15060 	CatalogTupleUpdate(pg_class, &tuple->t_self, tuple);
15061 
15062 	table_close(pg_class, RowExclusiveLock);
15063 	heap_freetuple(tuple);
15064 }
15065 
15066 /*
15067  * ALTER TABLE FORCE/NO FORCE ROW LEVEL SECURITY
15068  */
15069 static void
ATExecForceNoForceRowSecurity(Relation rel,bool force_rls)15070 ATExecForceNoForceRowSecurity(Relation rel, bool force_rls)
15071 {
15072 	Relation	pg_class;
15073 	Oid			relid;
15074 	HeapTuple	tuple;
15075 
15076 	relid = RelationGetRelid(rel);
15077 
15078 	pg_class = table_open(RelationRelationId, RowExclusiveLock);
15079 
15080 	tuple = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
15081 
15082 	if (!HeapTupleIsValid(tuple))
15083 		elog(ERROR, "cache lookup failed for relation %u", relid);
15084 
15085 	((Form_pg_class) GETSTRUCT(tuple))->relforcerowsecurity = force_rls;
15086 	CatalogTupleUpdate(pg_class, &tuple->t_self, tuple);
15087 
15088 	table_close(pg_class, RowExclusiveLock);
15089 	heap_freetuple(tuple);
15090 }
15091 
15092 /*
15093  * ALTER FOREIGN TABLE <name> OPTIONS (...)
15094  */
15095 static void
ATExecGenericOptions(Relation rel,List * options)15096 ATExecGenericOptions(Relation rel, List *options)
15097 {
15098 	Relation	ftrel;
15099 	ForeignServer *server;
15100 	ForeignDataWrapper *fdw;
15101 	HeapTuple	tuple;
15102 	bool		isnull;
15103 	Datum		repl_val[Natts_pg_foreign_table];
15104 	bool		repl_null[Natts_pg_foreign_table];
15105 	bool		repl_repl[Natts_pg_foreign_table];
15106 	Datum		datum;
15107 	Form_pg_foreign_table tableform;
15108 
15109 	if (options == NIL)
15110 		return;
15111 
15112 	ftrel = table_open(ForeignTableRelationId, RowExclusiveLock);
15113 
15114 	tuple = SearchSysCacheCopy1(FOREIGNTABLEREL, rel->rd_id);
15115 	if (!HeapTupleIsValid(tuple))
15116 		ereport(ERROR,
15117 				(errcode(ERRCODE_UNDEFINED_OBJECT),
15118 				 errmsg("foreign table \"%s\" does not exist",
15119 						RelationGetRelationName(rel))));
15120 	tableform = (Form_pg_foreign_table) GETSTRUCT(tuple);
15121 	server = GetForeignServer(tableform->ftserver);
15122 	fdw = GetForeignDataWrapper(server->fdwid);
15123 
15124 	memset(repl_val, 0, sizeof(repl_val));
15125 	memset(repl_null, false, sizeof(repl_null));
15126 	memset(repl_repl, false, sizeof(repl_repl));
15127 
15128 	/* Extract the current options */
15129 	datum = SysCacheGetAttr(FOREIGNTABLEREL,
15130 							tuple,
15131 							Anum_pg_foreign_table_ftoptions,
15132 							&isnull);
15133 	if (isnull)
15134 		datum = PointerGetDatum(NULL);
15135 
15136 	/* Transform the options */
15137 	datum = transformGenericOptions(ForeignTableRelationId,
15138 									datum,
15139 									options,
15140 									fdw->fdwvalidator);
15141 
15142 	if (PointerIsValid(DatumGetPointer(datum)))
15143 		repl_val[Anum_pg_foreign_table_ftoptions - 1] = datum;
15144 	else
15145 		repl_null[Anum_pg_foreign_table_ftoptions - 1] = true;
15146 
15147 	repl_repl[Anum_pg_foreign_table_ftoptions - 1] = true;
15148 
15149 	/* Everything looks good - update the tuple */
15150 
15151 	tuple = heap_modify_tuple(tuple, RelationGetDescr(ftrel),
15152 							  repl_val, repl_null, repl_repl);
15153 
15154 	CatalogTupleUpdate(ftrel, &tuple->t_self, tuple);
15155 
15156 	/*
15157 	 * Invalidate relcache so that all sessions will refresh any cached plans
15158 	 * that might depend on the old options.
15159 	 */
15160 	CacheInvalidateRelcache(rel);
15161 
15162 	InvokeObjectPostAlterHook(ForeignTableRelationId,
15163 							  RelationGetRelid(rel), 0);
15164 
15165 	table_close(ftrel, RowExclusiveLock);
15166 
15167 	heap_freetuple(tuple);
15168 }
15169 
15170 /*
15171  * Preparation phase for SET LOGGED/UNLOGGED
15172  *
15173  * This verifies that we're not trying to change a temp table.  Also,
15174  * existing foreign key constraints are checked to avoid ending up with
15175  * permanent tables referencing unlogged tables.
15176  *
15177  * Return value is false if the operation is a no-op (in which case the
15178  * checks are skipped), otherwise true.
15179  */
15180 static bool
ATPrepChangePersistence(Relation rel,bool toLogged)15181 ATPrepChangePersistence(Relation rel, bool toLogged)
15182 {
15183 	Relation	pg_constraint;
15184 	HeapTuple	tuple;
15185 	SysScanDesc scan;
15186 	ScanKeyData skey[1];
15187 
15188 	/*
15189 	 * Disallow changing status for a temp table.  Also verify whether we can
15190 	 * get away with doing nothing; in such cases we don't need to run the
15191 	 * checks below, either.
15192 	 */
15193 	switch (rel->rd_rel->relpersistence)
15194 	{
15195 		case RELPERSISTENCE_TEMP:
15196 			ereport(ERROR,
15197 					(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
15198 					 errmsg("cannot change logged status of table \"%s\" because it is temporary",
15199 							RelationGetRelationName(rel)),
15200 					 errtable(rel)));
15201 			break;
15202 		case RELPERSISTENCE_PERMANENT:
15203 			if (toLogged)
15204 				/* nothing to do */
15205 				return false;
15206 			break;
15207 		case RELPERSISTENCE_UNLOGGED:
15208 			if (!toLogged)
15209 				/* nothing to do */
15210 				return false;
15211 			break;
15212 	}
15213 
15214 	/*
15215 	 * Check that the table is not part any publication when changing to
15216 	 * UNLOGGED as UNLOGGED tables can't be published.
15217 	 */
15218 	if (!toLogged &&
15219 		list_length(GetRelationPublications(RelationGetRelid(rel))) > 0)
15220 		ereport(ERROR,
15221 				(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
15222 				 errmsg("cannot change table \"%s\" to unlogged because it is part of a publication",
15223 						RelationGetRelationName(rel)),
15224 				 errdetail("Unlogged relations cannot be replicated.")));
15225 
15226 	/*
15227 	 * Check existing foreign key constraints to preserve the invariant that
15228 	 * permanent tables cannot reference unlogged ones.  Self-referencing
15229 	 * foreign keys can safely be ignored.
15230 	 */
15231 	pg_constraint = table_open(ConstraintRelationId, AccessShareLock);
15232 
15233 	/*
15234 	 * Scan conrelid if changing to permanent, else confrelid.  This also
15235 	 * determines whether a useful index exists.
15236 	 */
15237 	ScanKeyInit(&skey[0],
15238 				toLogged ? Anum_pg_constraint_conrelid :
15239 				Anum_pg_constraint_confrelid,
15240 				BTEqualStrategyNumber, F_OIDEQ,
15241 				ObjectIdGetDatum(RelationGetRelid(rel)));
15242 	scan = systable_beginscan(pg_constraint,
15243 							  toLogged ? ConstraintRelidTypidNameIndexId : InvalidOid,
15244 							  true, NULL, 1, skey);
15245 
15246 	while (HeapTupleIsValid(tuple = systable_getnext(scan)))
15247 	{
15248 		Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(tuple);
15249 
15250 		if (con->contype == CONSTRAINT_FOREIGN)
15251 		{
15252 			Oid			foreignrelid;
15253 			Relation	foreignrel;
15254 
15255 			/* the opposite end of what we used as scankey */
15256 			foreignrelid = toLogged ? con->confrelid : con->conrelid;
15257 
15258 			/* ignore if self-referencing */
15259 			if (RelationGetRelid(rel) == foreignrelid)
15260 				continue;
15261 
15262 			foreignrel = relation_open(foreignrelid, AccessShareLock);
15263 
15264 			if (toLogged)
15265 			{
15266 				if (foreignrel->rd_rel->relpersistence != RELPERSISTENCE_PERMANENT)
15267 					ereport(ERROR,
15268 							(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
15269 							 errmsg("could not change table \"%s\" to logged because it references unlogged table \"%s\"",
15270 									RelationGetRelationName(rel),
15271 									RelationGetRelationName(foreignrel)),
15272 							 errtableconstraint(rel, NameStr(con->conname))));
15273 			}
15274 			else
15275 			{
15276 				if (foreignrel->rd_rel->relpersistence == RELPERSISTENCE_PERMANENT)
15277 					ereport(ERROR,
15278 							(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
15279 							 errmsg("could not change table \"%s\" to unlogged because it references logged table \"%s\"",
15280 									RelationGetRelationName(rel),
15281 									RelationGetRelationName(foreignrel)),
15282 							 errtableconstraint(rel, NameStr(con->conname))));
15283 			}
15284 
15285 			relation_close(foreignrel, AccessShareLock);
15286 		}
15287 	}
15288 
15289 	systable_endscan(scan);
15290 
15291 	table_close(pg_constraint, AccessShareLock);
15292 
15293 	return true;
15294 }
15295 
15296 /*
15297  * Execute ALTER TABLE SET SCHEMA
15298  */
15299 ObjectAddress
AlterTableNamespace(AlterObjectSchemaStmt * stmt,Oid * oldschema)15300 AlterTableNamespace(AlterObjectSchemaStmt *stmt, Oid *oldschema)
15301 {
15302 	Relation	rel;
15303 	Oid			relid;
15304 	Oid			oldNspOid;
15305 	Oid			nspOid;
15306 	RangeVar   *newrv;
15307 	ObjectAddresses *objsMoved;
15308 	ObjectAddress myself;
15309 
15310 	relid = RangeVarGetRelidExtended(stmt->relation, AccessExclusiveLock,
15311 									 stmt->missing_ok ? RVR_MISSING_OK : 0,
15312 									 RangeVarCallbackForAlterRelation,
15313 									 (void *) stmt);
15314 
15315 	if (!OidIsValid(relid))
15316 	{
15317 		ereport(NOTICE,
15318 				(errmsg("relation \"%s\" does not exist, skipping",
15319 						stmt->relation->relname)));
15320 		return InvalidObjectAddress;
15321 	}
15322 
15323 	rel = relation_open(relid, NoLock);
15324 
15325 	oldNspOid = RelationGetNamespace(rel);
15326 
15327 	/* If it's an owned sequence, disallow moving it by itself. */
15328 	if (rel->rd_rel->relkind == RELKIND_SEQUENCE)
15329 	{
15330 		Oid			tableId;
15331 		int32		colId;
15332 
15333 		if (sequenceIsOwned(relid, DEPENDENCY_AUTO, &tableId, &colId) ||
15334 			sequenceIsOwned(relid, DEPENDENCY_INTERNAL, &tableId, &colId))
15335 			ereport(ERROR,
15336 					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
15337 					 errmsg("cannot move an owned sequence into another schema"),
15338 					 errdetail("Sequence \"%s\" is linked to table \"%s\".",
15339 							   RelationGetRelationName(rel),
15340 							   get_rel_name(tableId))));
15341 	}
15342 
15343 	/* Get and lock schema OID and check its permissions. */
15344 	newrv = makeRangeVar(stmt->newschema, RelationGetRelationName(rel), -1);
15345 	nspOid = RangeVarGetAndCheckCreationNamespace(newrv, NoLock, NULL);
15346 
15347 	/* common checks on switching namespaces */
15348 	CheckSetNamespace(oldNspOid, nspOid);
15349 
15350 	objsMoved = new_object_addresses();
15351 	AlterTableNamespaceInternal(rel, oldNspOid, nspOid, objsMoved);
15352 	free_object_addresses(objsMoved);
15353 
15354 	ObjectAddressSet(myself, RelationRelationId, relid);
15355 
15356 	if (oldschema)
15357 		*oldschema = oldNspOid;
15358 
15359 	/* close rel, but keep lock until commit */
15360 	relation_close(rel, NoLock);
15361 
15362 	return myself;
15363 }
15364 
15365 /*
15366  * The guts of relocating a table or materialized view to another namespace:
15367  * besides moving the relation itself, its dependent objects are relocated to
15368  * the new schema.
15369  */
15370 void
AlterTableNamespaceInternal(Relation rel,Oid oldNspOid,Oid nspOid,ObjectAddresses * objsMoved)15371 AlterTableNamespaceInternal(Relation rel, Oid oldNspOid, Oid nspOid,
15372 							ObjectAddresses *objsMoved)
15373 {
15374 	Relation	classRel;
15375 
15376 	Assert(objsMoved != NULL);
15377 
15378 	/* OK, modify the pg_class row and pg_depend entry */
15379 	classRel = table_open(RelationRelationId, RowExclusiveLock);
15380 
15381 	AlterRelationNamespaceInternal(classRel, RelationGetRelid(rel), oldNspOid,
15382 								   nspOid, true, objsMoved);
15383 
15384 	/* Fix the table's row type too */
15385 	AlterTypeNamespaceInternal(rel->rd_rel->reltype,
15386 							   nspOid, false, false, objsMoved);
15387 
15388 	/* Fix other dependent stuff */
15389 	if (rel->rd_rel->relkind == RELKIND_RELATION ||
15390 		rel->rd_rel->relkind == RELKIND_MATVIEW ||
15391 		rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
15392 	{
15393 		AlterIndexNamespaces(classRel, rel, oldNspOid, nspOid, objsMoved);
15394 		AlterSeqNamespaces(classRel, rel, oldNspOid, nspOid,
15395 						   objsMoved, AccessExclusiveLock);
15396 		AlterConstraintNamespaces(RelationGetRelid(rel), oldNspOid, nspOid,
15397 								  false, objsMoved);
15398 	}
15399 
15400 	table_close(classRel, RowExclusiveLock);
15401 }
15402 
15403 /*
15404  * The guts of relocating a relation to another namespace: fix the pg_class
15405  * entry, and the pg_depend entry if any.  Caller must already have
15406  * opened and write-locked pg_class.
15407  */
15408 void
AlterRelationNamespaceInternal(Relation classRel,Oid relOid,Oid oldNspOid,Oid newNspOid,bool hasDependEntry,ObjectAddresses * objsMoved)15409 AlterRelationNamespaceInternal(Relation classRel, Oid relOid,
15410 							   Oid oldNspOid, Oid newNspOid,
15411 							   bool hasDependEntry,
15412 							   ObjectAddresses *objsMoved)
15413 {
15414 	HeapTuple	classTup;
15415 	Form_pg_class classForm;
15416 	ObjectAddress thisobj;
15417 	bool		already_done = false;
15418 
15419 	classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relOid));
15420 	if (!HeapTupleIsValid(classTup))
15421 		elog(ERROR, "cache lookup failed for relation %u", relOid);
15422 	classForm = (Form_pg_class) GETSTRUCT(classTup);
15423 
15424 	Assert(classForm->relnamespace == oldNspOid);
15425 
15426 	thisobj.classId = RelationRelationId;
15427 	thisobj.objectId = relOid;
15428 	thisobj.objectSubId = 0;
15429 
15430 	/*
15431 	 * If the object has already been moved, don't move it again.  If it's
15432 	 * already in the right place, don't move it, but still fire the object
15433 	 * access hook.
15434 	 */
15435 	already_done = object_address_present(&thisobj, objsMoved);
15436 	if (!already_done && oldNspOid != newNspOid)
15437 	{
15438 		/* check for duplicate name (more friendly than unique-index failure) */
15439 		if (get_relname_relid(NameStr(classForm->relname),
15440 							  newNspOid) != InvalidOid)
15441 			ereport(ERROR,
15442 					(errcode(ERRCODE_DUPLICATE_TABLE),
15443 					 errmsg("relation \"%s\" already exists in schema \"%s\"",
15444 							NameStr(classForm->relname),
15445 							get_namespace_name(newNspOid))));
15446 
15447 		/* classTup is a copy, so OK to scribble on */
15448 		classForm->relnamespace = newNspOid;
15449 
15450 		CatalogTupleUpdate(classRel, &classTup->t_self, classTup);
15451 
15452 		/* Update dependency on schema if caller said so */
15453 		if (hasDependEntry &&
15454 			changeDependencyFor(RelationRelationId,
15455 								relOid,
15456 								NamespaceRelationId,
15457 								oldNspOid,
15458 								newNspOid) != 1)
15459 			elog(ERROR, "failed to change schema dependency for relation \"%s\"",
15460 				 NameStr(classForm->relname));
15461 	}
15462 	if (!already_done)
15463 	{
15464 		add_exact_object_address(&thisobj, objsMoved);
15465 
15466 		InvokeObjectPostAlterHook(RelationRelationId, relOid, 0);
15467 	}
15468 
15469 	heap_freetuple(classTup);
15470 }
15471 
15472 /*
15473  * Move all indexes for the specified relation to another namespace.
15474  *
15475  * Note: we assume adequate permission checking was done by the caller,
15476  * and that the caller has a suitable lock on the owning relation.
15477  */
15478 static void
AlterIndexNamespaces(Relation classRel,Relation rel,Oid oldNspOid,Oid newNspOid,ObjectAddresses * objsMoved)15479 AlterIndexNamespaces(Relation classRel, Relation rel,
15480 					 Oid oldNspOid, Oid newNspOid, ObjectAddresses *objsMoved)
15481 {
15482 	List	   *indexList;
15483 	ListCell   *l;
15484 
15485 	indexList = RelationGetIndexList(rel);
15486 
15487 	foreach(l, indexList)
15488 	{
15489 		Oid			indexOid = lfirst_oid(l);
15490 		ObjectAddress thisobj;
15491 
15492 		thisobj.classId = RelationRelationId;
15493 		thisobj.objectId = indexOid;
15494 		thisobj.objectSubId = 0;
15495 
15496 		/*
15497 		 * Note: currently, the index will not have its own dependency on the
15498 		 * namespace, so we don't need to do changeDependencyFor(). There's no
15499 		 * row type in pg_type, either.
15500 		 *
15501 		 * XXX this objsMoved test may be pointless -- surely we have a single
15502 		 * dependency link from a relation to each index?
15503 		 */
15504 		if (!object_address_present(&thisobj, objsMoved))
15505 		{
15506 			AlterRelationNamespaceInternal(classRel, indexOid,
15507 										   oldNspOid, newNspOid,
15508 										   false, objsMoved);
15509 			add_exact_object_address(&thisobj, objsMoved);
15510 		}
15511 	}
15512 
15513 	list_free(indexList);
15514 }
15515 
15516 /*
15517  * Move all identity and SERIAL-column sequences of the specified relation to another
15518  * namespace.
15519  *
15520  * Note: we assume adequate permission checking was done by the caller,
15521  * and that the caller has a suitable lock on the owning relation.
15522  */
15523 static void
AlterSeqNamespaces(Relation classRel,Relation rel,Oid oldNspOid,Oid newNspOid,ObjectAddresses * objsMoved,LOCKMODE lockmode)15524 AlterSeqNamespaces(Relation classRel, Relation rel,
15525 				   Oid oldNspOid, Oid newNspOid, ObjectAddresses *objsMoved,
15526 				   LOCKMODE lockmode)
15527 {
15528 	Relation	depRel;
15529 	SysScanDesc scan;
15530 	ScanKeyData key[2];
15531 	HeapTuple	tup;
15532 
15533 	/*
15534 	 * SERIAL sequences are those having an auto dependency on one of the
15535 	 * table's columns (we don't care *which* column, exactly).
15536 	 */
15537 	depRel = table_open(DependRelationId, AccessShareLock);
15538 
15539 	ScanKeyInit(&key[0],
15540 				Anum_pg_depend_refclassid,
15541 				BTEqualStrategyNumber, F_OIDEQ,
15542 				ObjectIdGetDatum(RelationRelationId));
15543 	ScanKeyInit(&key[1],
15544 				Anum_pg_depend_refobjid,
15545 				BTEqualStrategyNumber, F_OIDEQ,
15546 				ObjectIdGetDatum(RelationGetRelid(rel)));
15547 	/* we leave refobjsubid unspecified */
15548 
15549 	scan = systable_beginscan(depRel, DependReferenceIndexId, true,
15550 							  NULL, 2, key);
15551 
15552 	while (HeapTupleIsValid(tup = systable_getnext(scan)))
15553 	{
15554 		Form_pg_depend depForm = (Form_pg_depend) GETSTRUCT(tup);
15555 		Relation	seqRel;
15556 
15557 		/* skip dependencies other than auto dependencies on columns */
15558 		if (depForm->refobjsubid == 0 ||
15559 			depForm->classid != RelationRelationId ||
15560 			depForm->objsubid != 0 ||
15561 			!(depForm->deptype == DEPENDENCY_AUTO || depForm->deptype == DEPENDENCY_INTERNAL))
15562 			continue;
15563 
15564 		/* Use relation_open just in case it's an index */
15565 		seqRel = relation_open(depForm->objid, lockmode);
15566 
15567 		/* skip non-sequence relations */
15568 		if (RelationGetForm(seqRel)->relkind != RELKIND_SEQUENCE)
15569 		{
15570 			/* No need to keep the lock */
15571 			relation_close(seqRel, lockmode);
15572 			continue;
15573 		}
15574 
15575 		/* Fix the pg_class and pg_depend entries */
15576 		AlterRelationNamespaceInternal(classRel, depForm->objid,
15577 									   oldNspOid, newNspOid,
15578 									   true, objsMoved);
15579 
15580 		/*
15581 		 * Sequences have entries in pg_type. We need to be careful to move
15582 		 * them to the new namespace, too.
15583 		 */
15584 		AlterTypeNamespaceInternal(RelationGetForm(seqRel)->reltype,
15585 								   newNspOid, false, false, objsMoved);
15586 
15587 		/* Now we can close it.  Keep the lock till end of transaction. */
15588 		relation_close(seqRel, NoLock);
15589 	}
15590 
15591 	systable_endscan(scan);
15592 
15593 	relation_close(depRel, AccessShareLock);
15594 }
15595 
15596 
15597 /*
15598  * This code supports
15599  *	CREATE TEMP TABLE ... ON COMMIT { DROP | PRESERVE ROWS | DELETE ROWS }
15600  *
15601  * Because we only support this for TEMP tables, it's sufficient to remember
15602  * the state in a backend-local data structure.
15603  */
15604 
15605 /*
15606  * Register a newly-created relation's ON COMMIT action.
15607  */
15608 void
register_on_commit_action(Oid relid,OnCommitAction action)15609 register_on_commit_action(Oid relid, OnCommitAction action)
15610 {
15611 	OnCommitItem *oc;
15612 	MemoryContext oldcxt;
15613 
15614 	/*
15615 	 * We needn't bother registering the relation unless there is an ON COMMIT
15616 	 * action we need to take.
15617 	 */
15618 	if (action == ONCOMMIT_NOOP || action == ONCOMMIT_PRESERVE_ROWS)
15619 		return;
15620 
15621 	oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
15622 
15623 	oc = (OnCommitItem *) palloc(sizeof(OnCommitItem));
15624 	oc->relid = relid;
15625 	oc->oncommit = action;
15626 	oc->creating_subid = GetCurrentSubTransactionId();
15627 	oc->deleting_subid = InvalidSubTransactionId;
15628 
15629 	/*
15630 	 * We use lcons() here so that ON COMMIT actions are processed in reverse
15631 	 * order of registration.  That might not be essential but it seems
15632 	 * reasonable.
15633 	 */
15634 	on_commits = lcons(oc, on_commits);
15635 
15636 	MemoryContextSwitchTo(oldcxt);
15637 }
15638 
15639 /*
15640  * Unregister any ON COMMIT action when a relation is deleted.
15641  *
15642  * Actually, we only mark the OnCommitItem entry as to be deleted after commit.
15643  */
15644 void
remove_on_commit_action(Oid relid)15645 remove_on_commit_action(Oid relid)
15646 {
15647 	ListCell   *l;
15648 
15649 	foreach(l, on_commits)
15650 	{
15651 		OnCommitItem *oc = (OnCommitItem *) lfirst(l);
15652 
15653 		if (oc->relid == relid)
15654 		{
15655 			oc->deleting_subid = GetCurrentSubTransactionId();
15656 			break;
15657 		}
15658 	}
15659 }
15660 
15661 /*
15662  * Perform ON COMMIT actions.
15663  *
15664  * This is invoked just before actually committing, since it's possible
15665  * to encounter errors.
15666  */
15667 void
PreCommit_on_commit_actions(void)15668 PreCommit_on_commit_actions(void)
15669 {
15670 	ListCell   *l;
15671 	List	   *oids_to_truncate = NIL;
15672 	List	   *oids_to_drop = NIL;
15673 
15674 	foreach(l, on_commits)
15675 	{
15676 		OnCommitItem *oc = (OnCommitItem *) lfirst(l);
15677 
15678 		/* Ignore entry if already dropped in this xact */
15679 		if (oc->deleting_subid != InvalidSubTransactionId)
15680 			continue;
15681 
15682 		switch (oc->oncommit)
15683 		{
15684 			case ONCOMMIT_NOOP:
15685 			case ONCOMMIT_PRESERVE_ROWS:
15686 				/* Do nothing (there shouldn't be such entries, actually) */
15687 				break;
15688 			case ONCOMMIT_DELETE_ROWS:
15689 
15690 				/*
15691 				 * If this transaction hasn't accessed any temporary
15692 				 * relations, we can skip truncating ON COMMIT DELETE ROWS
15693 				 * tables, as they must still be empty.
15694 				 */
15695 				if ((MyXactFlags & XACT_FLAGS_ACCESSEDTEMPNAMESPACE))
15696 					oids_to_truncate = lappend_oid(oids_to_truncate, oc->relid);
15697 				break;
15698 			case ONCOMMIT_DROP:
15699 				oids_to_drop = lappend_oid(oids_to_drop, oc->relid);
15700 				break;
15701 		}
15702 	}
15703 
15704 	/*
15705 	 * Truncate relations before dropping so that all dependencies between
15706 	 * relations are removed after they are worked on.  Doing it like this
15707 	 * might be a waste as it is possible that a relation being truncated will
15708 	 * be dropped anyway due to its parent being dropped, but this makes the
15709 	 * code more robust because of not having to re-check that the relation
15710 	 * exists at truncation time.
15711 	 */
15712 	if (oids_to_truncate != NIL)
15713 		heap_truncate(oids_to_truncate);
15714 
15715 	if (oids_to_drop != NIL)
15716 	{
15717 		ObjectAddresses *targetObjects = new_object_addresses();
15718 		ListCell   *l;
15719 
15720 		foreach(l, oids_to_drop)
15721 		{
15722 			ObjectAddress object;
15723 
15724 			object.classId = RelationRelationId;
15725 			object.objectId = lfirst_oid(l);
15726 			object.objectSubId = 0;
15727 
15728 			Assert(!object_address_present(&object, targetObjects));
15729 
15730 			add_exact_object_address(&object, targetObjects);
15731 		}
15732 
15733 		/*
15734 		 * Since this is an automatic drop, rather than one directly initiated
15735 		 * by the user, we pass the PERFORM_DELETION_INTERNAL flag.
15736 		 */
15737 		performMultipleDeletions(targetObjects, DROP_CASCADE,
15738 								 PERFORM_DELETION_INTERNAL | PERFORM_DELETION_QUIETLY);
15739 
15740 #ifdef USE_ASSERT_CHECKING
15741 
15742 		/*
15743 		 * Note that table deletion will call remove_on_commit_action, so the
15744 		 * entry should get marked as deleted.
15745 		 */
15746 		foreach(l, on_commits)
15747 		{
15748 			OnCommitItem *oc = (OnCommitItem *) lfirst(l);
15749 
15750 			if (oc->oncommit != ONCOMMIT_DROP)
15751 				continue;
15752 
15753 			Assert(oc->deleting_subid != InvalidSubTransactionId);
15754 		}
15755 #endif
15756 	}
15757 }
15758 
15759 /*
15760  * Post-commit or post-abort cleanup for ON COMMIT management.
15761  *
15762  * All we do here is remove no-longer-needed OnCommitItem entries.
15763  *
15764  * During commit, remove entries that were deleted during this transaction;
15765  * during abort, remove those created during this transaction.
15766  */
15767 void
AtEOXact_on_commit_actions(bool isCommit)15768 AtEOXact_on_commit_actions(bool isCommit)
15769 {
15770 	ListCell   *cur_item;
15771 
15772 	foreach(cur_item, on_commits)
15773 	{
15774 		OnCommitItem *oc = (OnCommitItem *) lfirst(cur_item);
15775 
15776 		if (isCommit ? oc->deleting_subid != InvalidSubTransactionId :
15777 			oc->creating_subid != InvalidSubTransactionId)
15778 		{
15779 			/* cur_item must be removed */
15780 			on_commits = foreach_delete_current(on_commits, cur_item);
15781 			pfree(oc);
15782 		}
15783 		else
15784 		{
15785 			/* cur_item must be preserved */
15786 			oc->creating_subid = InvalidSubTransactionId;
15787 			oc->deleting_subid = InvalidSubTransactionId;
15788 		}
15789 	}
15790 }
15791 
15792 /*
15793  * Post-subcommit or post-subabort cleanup for ON COMMIT management.
15794  *
15795  * During subabort, we can immediately remove entries created during this
15796  * subtransaction.  During subcommit, just relabel entries marked during
15797  * this subtransaction as being the parent's responsibility.
15798  */
15799 void
AtEOSubXact_on_commit_actions(bool isCommit,SubTransactionId mySubid,SubTransactionId parentSubid)15800 AtEOSubXact_on_commit_actions(bool isCommit, SubTransactionId mySubid,
15801 							  SubTransactionId parentSubid)
15802 {
15803 	ListCell   *cur_item;
15804 
15805 	foreach(cur_item, on_commits)
15806 	{
15807 		OnCommitItem *oc = (OnCommitItem *) lfirst(cur_item);
15808 
15809 		if (!isCommit && oc->creating_subid == mySubid)
15810 		{
15811 			/* cur_item must be removed */
15812 			on_commits = foreach_delete_current(on_commits, cur_item);
15813 			pfree(oc);
15814 		}
15815 		else
15816 		{
15817 			/* cur_item must be preserved */
15818 			if (oc->creating_subid == mySubid)
15819 				oc->creating_subid = parentSubid;
15820 			if (oc->deleting_subid == mySubid)
15821 				oc->deleting_subid = isCommit ? parentSubid : InvalidSubTransactionId;
15822 		}
15823 	}
15824 }
15825 
15826 /*
15827  * This is intended as a callback for RangeVarGetRelidExtended().  It allows
15828  * the relation to be locked only if (1) it's a plain table, materialized
15829  * view, or TOAST table and (2) the current user is the owner (or the
15830  * superuser).  This meets the permission-checking needs of CLUSTER, REINDEX
15831  * TABLE, and REFRESH MATERIALIZED VIEW; we expose it here so that it can be
15832  * used by all.
15833  */
15834 void
RangeVarCallbackOwnsTable(const RangeVar * relation,Oid relId,Oid oldRelId,void * arg)15835 RangeVarCallbackOwnsTable(const RangeVar *relation,
15836 						  Oid relId, Oid oldRelId, void *arg)
15837 {
15838 	char		relkind;
15839 
15840 	/* Nothing to do if the relation was not found. */
15841 	if (!OidIsValid(relId))
15842 		return;
15843 
15844 	/*
15845 	 * If the relation does exist, check whether it's an index.  But note that
15846 	 * the relation might have been dropped between the time we did the name
15847 	 * lookup and now.  In that case, there's nothing to do.
15848 	 */
15849 	relkind = get_rel_relkind(relId);
15850 	if (!relkind)
15851 		return;
15852 	if (relkind != RELKIND_RELATION && relkind != RELKIND_TOASTVALUE &&
15853 		relkind != RELKIND_MATVIEW && relkind != RELKIND_PARTITIONED_TABLE)
15854 		ereport(ERROR,
15855 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
15856 				 errmsg("\"%s\" is not a table or materialized view", relation->relname)));
15857 
15858 	/* Check permissions */
15859 	if (!pg_class_ownercheck(relId, GetUserId()))
15860 		aclcheck_error(ACLCHECK_NOT_OWNER, get_relkind_objtype(get_rel_relkind(relId)), relation->relname);
15861 }
15862 
15863 /*
15864  * Callback to RangeVarGetRelidExtended() for TRUNCATE processing.
15865  */
15866 static void
RangeVarCallbackForTruncate(const RangeVar * relation,Oid relId,Oid oldRelId,void * arg)15867 RangeVarCallbackForTruncate(const RangeVar *relation,
15868 							Oid relId, Oid oldRelId, void *arg)
15869 {
15870 	HeapTuple	tuple;
15871 
15872 	/* Nothing to do if the relation was not found. */
15873 	if (!OidIsValid(relId))
15874 		return;
15875 
15876 	tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relId));
15877 	if (!HeapTupleIsValid(tuple))	/* should not happen */
15878 		elog(ERROR, "cache lookup failed for relation %u", relId);
15879 
15880 	truncate_check_rel(relId, (Form_pg_class) GETSTRUCT(tuple));
15881 	truncate_check_perms(relId, (Form_pg_class) GETSTRUCT(tuple));
15882 
15883 	ReleaseSysCache(tuple);
15884 }
15885 
15886 /*
15887  * Callback to RangeVarGetRelidExtended(), similar to
15888  * RangeVarCallbackOwnsTable() but without checks on the type of the relation.
15889  */
15890 void
RangeVarCallbackOwnsRelation(const RangeVar * relation,Oid relId,Oid oldRelId,void * arg)15891 RangeVarCallbackOwnsRelation(const RangeVar *relation,
15892 							 Oid relId, Oid oldRelId, void *arg)
15893 {
15894 	HeapTuple	tuple;
15895 
15896 	/* Nothing to do if the relation was not found. */
15897 	if (!OidIsValid(relId))
15898 		return;
15899 
15900 	tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relId));
15901 	if (!HeapTupleIsValid(tuple))	/* should not happen */
15902 		elog(ERROR, "cache lookup failed for relation %u", relId);
15903 
15904 	if (!pg_class_ownercheck(relId, GetUserId()))
15905 		aclcheck_error(ACLCHECK_NOT_OWNER, get_relkind_objtype(get_rel_relkind(relId)),
15906 					   relation->relname);
15907 
15908 	if (!allowSystemTableMods &&
15909 		IsSystemClass(relId, (Form_pg_class) GETSTRUCT(tuple)))
15910 		ereport(ERROR,
15911 				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
15912 				 errmsg("permission denied: \"%s\" is a system catalog",
15913 						relation->relname)));
15914 
15915 	ReleaseSysCache(tuple);
15916 }
15917 
15918 /*
15919  * Common RangeVarGetRelid callback for rename, set schema, and alter table
15920  * processing.
15921  */
15922 static void
RangeVarCallbackForAlterRelation(const RangeVar * rv,Oid relid,Oid oldrelid,void * arg)15923 RangeVarCallbackForAlterRelation(const RangeVar *rv, Oid relid, Oid oldrelid,
15924 								 void *arg)
15925 {
15926 	Node	   *stmt = (Node *) arg;
15927 	ObjectType	reltype;
15928 	HeapTuple	tuple;
15929 	Form_pg_class classform;
15930 	AclResult	aclresult;
15931 	char		relkind;
15932 
15933 	tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
15934 	if (!HeapTupleIsValid(tuple))
15935 		return;					/* concurrently dropped */
15936 	classform = (Form_pg_class) GETSTRUCT(tuple);
15937 	relkind = classform->relkind;
15938 
15939 	/* Must own relation. */
15940 	if (!pg_class_ownercheck(relid, GetUserId()))
15941 		aclcheck_error(ACLCHECK_NOT_OWNER, get_relkind_objtype(get_rel_relkind(relid)), rv->relname);
15942 
15943 	/* No system table modifications unless explicitly allowed. */
15944 	if (!allowSystemTableMods && IsSystemClass(relid, classform))
15945 		ereport(ERROR,
15946 				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
15947 				 errmsg("permission denied: \"%s\" is a system catalog",
15948 						rv->relname)));
15949 
15950 	/*
15951 	 * Extract the specified relation type from the statement parse tree.
15952 	 *
15953 	 * Also, for ALTER .. RENAME, check permissions: the user must (still)
15954 	 * have CREATE rights on the containing namespace.
15955 	 */
15956 	if (IsA(stmt, RenameStmt))
15957 	{
15958 		aclresult = pg_namespace_aclcheck(classform->relnamespace,
15959 										  GetUserId(), ACL_CREATE);
15960 		if (aclresult != ACLCHECK_OK)
15961 			aclcheck_error(aclresult, OBJECT_SCHEMA,
15962 						   get_namespace_name(classform->relnamespace));
15963 		reltype = ((RenameStmt *) stmt)->renameType;
15964 	}
15965 	else if (IsA(stmt, AlterObjectSchemaStmt))
15966 		reltype = ((AlterObjectSchemaStmt *) stmt)->objectType;
15967 
15968 	else if (IsA(stmt, AlterTableStmt))
15969 		reltype = ((AlterTableStmt *) stmt)->relkind;
15970 	else
15971 	{
15972 		elog(ERROR, "unrecognized node type: %d", (int) nodeTag(stmt));
15973 		reltype = OBJECT_TABLE; /* placate compiler */
15974 	}
15975 
15976 	/*
15977 	 * For compatibility with prior releases, we allow ALTER TABLE to be used
15978 	 * with most other types of relations (but not composite types). We allow
15979 	 * similar flexibility for ALTER INDEX in the case of RENAME, but not
15980 	 * otherwise.  Otherwise, the user must select the correct form of the
15981 	 * command for the relation at issue.
15982 	 */
15983 	if (reltype == OBJECT_SEQUENCE && relkind != RELKIND_SEQUENCE)
15984 		ereport(ERROR,
15985 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
15986 				 errmsg("\"%s\" is not a sequence", rv->relname)));
15987 
15988 	if (reltype == OBJECT_VIEW && relkind != RELKIND_VIEW)
15989 		ereport(ERROR,
15990 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
15991 				 errmsg("\"%s\" is not a view", rv->relname)));
15992 
15993 	if (reltype == OBJECT_MATVIEW && relkind != RELKIND_MATVIEW)
15994 		ereport(ERROR,
15995 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
15996 				 errmsg("\"%s\" is not a materialized view", rv->relname)));
15997 
15998 	if (reltype == OBJECT_FOREIGN_TABLE && relkind != RELKIND_FOREIGN_TABLE)
15999 		ereport(ERROR,
16000 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
16001 				 errmsg("\"%s\" is not a foreign table", rv->relname)));
16002 
16003 	if (reltype == OBJECT_TYPE && relkind != RELKIND_COMPOSITE_TYPE)
16004 		ereport(ERROR,
16005 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
16006 				 errmsg("\"%s\" is not a composite type", rv->relname)));
16007 
16008 	if (reltype == OBJECT_INDEX && relkind != RELKIND_INDEX &&
16009 		relkind != RELKIND_PARTITIONED_INDEX
16010 		&& !IsA(stmt, RenameStmt))
16011 		ereport(ERROR,
16012 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
16013 				 errmsg("\"%s\" is not an index", rv->relname)));
16014 
16015 	/*
16016 	 * Don't allow ALTER TABLE on composite types. We want people to use ALTER
16017 	 * TYPE for that.
16018 	 */
16019 	if (reltype != OBJECT_TYPE && relkind == RELKIND_COMPOSITE_TYPE)
16020 		ereport(ERROR,
16021 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
16022 				 errmsg("\"%s\" is a composite type", rv->relname),
16023 				 errhint("Use ALTER TYPE instead.")));
16024 
16025 	/*
16026 	 * Don't allow ALTER TABLE .. SET SCHEMA on relations that can't be moved
16027 	 * to a different schema, such as indexes and TOAST tables.
16028 	 */
16029 	if (IsA(stmt, AlterObjectSchemaStmt) &&
16030 		relkind != RELKIND_RELATION &&
16031 		relkind != RELKIND_VIEW &&
16032 		relkind != RELKIND_MATVIEW &&
16033 		relkind != RELKIND_SEQUENCE &&
16034 		relkind != RELKIND_FOREIGN_TABLE &&
16035 		relkind != RELKIND_PARTITIONED_TABLE)
16036 		ereport(ERROR,
16037 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
16038 				 errmsg("\"%s\" is not a table, view, materialized view, sequence, or foreign table",
16039 						rv->relname)));
16040 
16041 	ReleaseSysCache(tuple);
16042 }
16043 
16044 /*
16045  * Transform any expressions present in the partition key
16046  *
16047  * Returns a transformed PartitionSpec, as well as the strategy code
16048  */
16049 static PartitionSpec *
transformPartitionSpec(Relation rel,PartitionSpec * partspec,char * strategy)16050 transformPartitionSpec(Relation rel, PartitionSpec *partspec, char *strategy)
16051 {
16052 	PartitionSpec *newspec;
16053 	ParseState *pstate;
16054 	ParseNamespaceItem *nsitem;
16055 	ListCell   *l;
16056 
16057 	newspec = makeNode(PartitionSpec);
16058 
16059 	newspec->strategy = partspec->strategy;
16060 	newspec->partParams = NIL;
16061 	newspec->location = partspec->location;
16062 
16063 	/* Parse partitioning strategy name */
16064 	if (pg_strcasecmp(partspec->strategy, "hash") == 0)
16065 		*strategy = PARTITION_STRATEGY_HASH;
16066 	else if (pg_strcasecmp(partspec->strategy, "list") == 0)
16067 		*strategy = PARTITION_STRATEGY_LIST;
16068 	else if (pg_strcasecmp(partspec->strategy, "range") == 0)
16069 		*strategy = PARTITION_STRATEGY_RANGE;
16070 	else
16071 		ereport(ERROR,
16072 				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
16073 				 errmsg("unrecognized partitioning strategy \"%s\"",
16074 						partspec->strategy)));
16075 
16076 	/* Check valid number of columns for strategy */
16077 	if (*strategy == PARTITION_STRATEGY_LIST &&
16078 		list_length(partspec->partParams) != 1)
16079 		ereport(ERROR,
16080 				(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
16081 				 errmsg("cannot use \"list\" partition strategy with more than one column")));
16082 
16083 	/*
16084 	 * Create a dummy ParseState and insert the target relation as its sole
16085 	 * rangetable entry.  We need a ParseState for transformExpr.
16086 	 */
16087 	pstate = make_parsestate(NULL);
16088 	nsitem = addRangeTableEntryForRelation(pstate, rel, AccessShareLock,
16089 										   NULL, false, true);
16090 	addNSItemToQuery(pstate, nsitem, true, true, true);
16091 
16092 	/* take care of any partition expressions */
16093 	foreach(l, partspec->partParams)
16094 	{
16095 		PartitionElem *pelem = castNode(PartitionElem, lfirst(l));
16096 
16097 		if (pelem->expr)
16098 		{
16099 			/* Copy, to avoid scribbling on the input */
16100 			pelem = copyObject(pelem);
16101 
16102 			/* Now do parse transformation of the expression */
16103 			pelem->expr = transformExpr(pstate, pelem->expr,
16104 										EXPR_KIND_PARTITION_EXPRESSION);
16105 
16106 			/* we have to fix its collations too */
16107 			assign_expr_collations(pstate, pelem->expr);
16108 		}
16109 
16110 		newspec->partParams = lappend(newspec->partParams, pelem);
16111 	}
16112 
16113 	return newspec;
16114 }
16115 
16116 /*
16117  * Compute per-partition-column information from a list of PartitionElems.
16118  * Expressions in the PartitionElems must be parse-analyzed already.
16119  */
16120 static void
ComputePartitionAttrs(ParseState * pstate,Relation rel,List * partParams,AttrNumber * partattrs,List ** partexprs,Oid * partopclass,Oid * partcollation,char strategy)16121 ComputePartitionAttrs(ParseState *pstate, Relation rel, List *partParams, AttrNumber *partattrs,
16122 					  List **partexprs, Oid *partopclass, Oid *partcollation,
16123 					  char strategy)
16124 {
16125 	int			attn;
16126 	ListCell   *lc;
16127 	Oid			am_oid;
16128 
16129 	attn = 0;
16130 	foreach(lc, partParams)
16131 	{
16132 		PartitionElem *pelem = castNode(PartitionElem, lfirst(lc));
16133 		Oid			atttype;
16134 		Oid			attcollation;
16135 
16136 		if (pelem->name != NULL)
16137 		{
16138 			/* Simple attribute reference */
16139 			HeapTuple	atttuple;
16140 			Form_pg_attribute attform;
16141 
16142 			atttuple = SearchSysCacheAttName(RelationGetRelid(rel),
16143 											 pelem->name);
16144 			if (!HeapTupleIsValid(atttuple))
16145 				ereport(ERROR,
16146 						(errcode(ERRCODE_UNDEFINED_COLUMN),
16147 						 errmsg("column \"%s\" named in partition key does not exist",
16148 								pelem->name),
16149 						 parser_errposition(pstate, pelem->location)));
16150 			attform = (Form_pg_attribute) GETSTRUCT(atttuple);
16151 
16152 			if (attform->attnum <= 0)
16153 				ereport(ERROR,
16154 						(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
16155 						 errmsg("cannot use system column \"%s\" in partition key",
16156 								pelem->name),
16157 						 parser_errposition(pstate, pelem->location)));
16158 
16159 			/*
16160 			 * Generated columns cannot work: They are computed after BEFORE
16161 			 * triggers, but partition routing is done before all triggers.
16162 			 */
16163 			if (attform->attgenerated)
16164 				ereport(ERROR,
16165 						(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
16166 						 errmsg("cannot use generated column in partition key"),
16167 						 errdetail("Column \"%s\" is a generated column.",
16168 								   pelem->name),
16169 						 parser_errposition(pstate, pelem->location)));
16170 
16171 			partattrs[attn] = attform->attnum;
16172 			atttype = attform->atttypid;
16173 			attcollation = attform->attcollation;
16174 			ReleaseSysCache(atttuple);
16175 		}
16176 		else
16177 		{
16178 			/* Expression */
16179 			Node	   *expr = pelem->expr;
16180 			char		partattname[16];
16181 
16182 			Assert(expr != NULL);
16183 			atttype = exprType(expr);
16184 			attcollation = exprCollation(expr);
16185 
16186 			/*
16187 			 * The expression must be of a storable type (e.g., not RECORD).
16188 			 * The test is the same as for whether a table column is of a safe
16189 			 * type (which is why we needn't check for the non-expression
16190 			 * case).
16191 			 */
16192 			snprintf(partattname, sizeof(partattname), "%d", attn + 1);
16193 			CheckAttributeType(partattname,
16194 							   atttype, attcollation,
16195 							   NIL, CHKATYPE_IS_PARTKEY);
16196 
16197 			/*
16198 			 * Strip any top-level COLLATE clause.  This ensures that we treat
16199 			 * "x COLLATE y" and "(x COLLATE y)" alike.
16200 			 */
16201 			while (IsA(expr, CollateExpr))
16202 				expr = (Node *) ((CollateExpr *) expr)->arg;
16203 
16204 			if (IsA(expr, Var) &&
16205 				((Var *) expr)->varattno > 0)
16206 			{
16207 				/*
16208 				 * User wrote "(column)" or "(column COLLATE something)".
16209 				 * Treat it like simple attribute anyway.
16210 				 */
16211 				partattrs[attn] = ((Var *) expr)->varattno;
16212 			}
16213 			else
16214 			{
16215 				Bitmapset  *expr_attrs = NULL;
16216 				int			i;
16217 
16218 				partattrs[attn] = 0;	/* marks the column as expression */
16219 				*partexprs = lappend(*partexprs, expr);
16220 
16221 				/*
16222 				 * Try to simplify the expression before checking for
16223 				 * mutability.  The main practical value of doing it in this
16224 				 * order is that an inline-able SQL-language function will be
16225 				 * accepted if its expansion is immutable, whether or not the
16226 				 * function itself is marked immutable.
16227 				 *
16228 				 * Note that expression_planner does not change the passed in
16229 				 * expression destructively and we have already saved the
16230 				 * expression to be stored into the catalog above.
16231 				 */
16232 				expr = (Node *) expression_planner((Expr *) expr);
16233 
16234 				/*
16235 				 * Partition expression cannot contain mutable functions,
16236 				 * because a given row must always map to the same partition
16237 				 * as long as there is no change in the partition boundary
16238 				 * structure.
16239 				 */
16240 				if (contain_mutable_functions(expr))
16241 					ereport(ERROR,
16242 							(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
16243 							 errmsg("functions in partition key expression must be marked IMMUTABLE")));
16244 
16245 				/*
16246 				 * transformPartitionSpec() should have already rejected
16247 				 * subqueries, aggregates, window functions, and SRFs, based
16248 				 * on the EXPR_KIND_ for partition expressions.
16249 				 */
16250 
16251 				/*
16252 				 * Cannot allow system column references, since that would
16253 				 * make partition routing impossible: their values won't be
16254 				 * known yet when we need to do that.
16255 				 */
16256 				pull_varattnos(expr, 1, &expr_attrs);
16257 				for (i = FirstLowInvalidHeapAttributeNumber; i < 0; i++)
16258 				{
16259 					if (bms_is_member(i - FirstLowInvalidHeapAttributeNumber,
16260 									  expr_attrs))
16261 						ereport(ERROR,
16262 								(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
16263 								 errmsg("partition key expressions cannot contain system column references")));
16264 				}
16265 
16266 				/*
16267 				 * Generated columns cannot work: They are computed after
16268 				 * BEFORE triggers, but partition routing is done before all
16269 				 * triggers.
16270 				 */
16271 				i = -1;
16272 				while ((i = bms_next_member(expr_attrs, i)) >= 0)
16273 				{
16274 					AttrNumber	attno = i + FirstLowInvalidHeapAttributeNumber;
16275 
16276 					if (attno > 0 &&
16277 						TupleDescAttr(RelationGetDescr(rel), attno - 1)->attgenerated)
16278 						ereport(ERROR,
16279 								(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
16280 								 errmsg("cannot use generated column in partition key"),
16281 								 errdetail("Column \"%s\" is a generated column.",
16282 										   get_attname(RelationGetRelid(rel), attno, false)),
16283 								 parser_errposition(pstate, pelem->location)));
16284 				}
16285 
16286 				/*
16287 				 * While it is not exactly *wrong* for a partition expression
16288 				 * to be a constant, it seems better to reject such keys.
16289 				 */
16290 				if (IsA(expr, Const))
16291 					ereport(ERROR,
16292 							(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
16293 							 errmsg("cannot use constant expression as partition key")));
16294 			}
16295 		}
16296 
16297 		/*
16298 		 * Apply collation override if any
16299 		 */
16300 		if (pelem->collation)
16301 			attcollation = get_collation_oid(pelem->collation, false);
16302 
16303 		/*
16304 		 * Check we have a collation iff it's a collatable type.  The only
16305 		 * expected failures here are (1) COLLATE applied to a noncollatable
16306 		 * type, or (2) partition expression had an unresolved collation. But
16307 		 * we might as well code this to be a complete consistency check.
16308 		 */
16309 		if (type_is_collatable(atttype))
16310 		{
16311 			if (!OidIsValid(attcollation))
16312 				ereport(ERROR,
16313 						(errcode(ERRCODE_INDETERMINATE_COLLATION),
16314 						 errmsg("could not determine which collation to use for partition expression"),
16315 						 errhint("Use the COLLATE clause to set the collation explicitly.")));
16316 		}
16317 		else
16318 		{
16319 			if (OidIsValid(attcollation))
16320 				ereport(ERROR,
16321 						(errcode(ERRCODE_DATATYPE_MISMATCH),
16322 						 errmsg("collations are not supported by type %s",
16323 								format_type_be(atttype))));
16324 		}
16325 
16326 		partcollation[attn] = attcollation;
16327 
16328 		/*
16329 		 * Identify the appropriate operator class.  For list and range
16330 		 * partitioning, we use a btree operator class; hash partitioning uses
16331 		 * a hash operator class.
16332 		 */
16333 		if (strategy == PARTITION_STRATEGY_HASH)
16334 			am_oid = HASH_AM_OID;
16335 		else
16336 			am_oid = BTREE_AM_OID;
16337 
16338 		if (!pelem->opclass)
16339 		{
16340 			partopclass[attn] = GetDefaultOpClass(atttype, am_oid);
16341 
16342 			if (!OidIsValid(partopclass[attn]))
16343 			{
16344 				if (strategy == PARTITION_STRATEGY_HASH)
16345 					ereport(ERROR,
16346 							(errcode(ERRCODE_UNDEFINED_OBJECT),
16347 							 errmsg("data type %s has no default operator class for access method \"%s\"",
16348 									format_type_be(atttype), "hash"),
16349 							 errhint("You must specify a hash operator class or define a default hash operator class for the data type.")));
16350 				else
16351 					ereport(ERROR,
16352 							(errcode(ERRCODE_UNDEFINED_OBJECT),
16353 							 errmsg("data type %s has no default operator class for access method \"%s\"",
16354 									format_type_be(atttype), "btree"),
16355 							 errhint("You must specify a btree operator class or define a default btree operator class for the data type.")));
16356 
16357 			}
16358 		}
16359 		else
16360 			partopclass[attn] = ResolveOpClass(pelem->opclass,
16361 											   atttype,
16362 											   am_oid == HASH_AM_OID ? "hash" : "btree",
16363 											   am_oid);
16364 
16365 		attn++;
16366 	}
16367 }
16368 
16369 /*
16370  * PartConstraintImpliedByRelConstraint
16371  *		Do scanrel's existing constraints imply the partition constraint?
16372  *
16373  * "Existing constraints" include its check constraints and column-level
16374  * NOT NULL constraints.  partConstraint describes the partition constraint,
16375  * in implicit-AND form.
16376  */
16377 bool
PartConstraintImpliedByRelConstraint(Relation scanrel,List * partConstraint)16378 PartConstraintImpliedByRelConstraint(Relation scanrel,
16379 									 List *partConstraint)
16380 {
16381 	List	   *existConstraint = NIL;
16382 	TupleConstr *constr = RelationGetDescr(scanrel)->constr;
16383 	int			i;
16384 
16385 	if (constr && constr->has_not_null)
16386 	{
16387 		int			natts = scanrel->rd_att->natts;
16388 
16389 		for (i = 1; i <= natts; i++)
16390 		{
16391 			Form_pg_attribute att = TupleDescAttr(scanrel->rd_att, i - 1);
16392 
16393 			if (att->attnotnull && !att->attisdropped)
16394 			{
16395 				NullTest   *ntest = makeNode(NullTest);
16396 
16397 				ntest->arg = (Expr *) makeVar(1,
16398 											  i,
16399 											  att->atttypid,
16400 											  att->atttypmod,
16401 											  att->attcollation,
16402 											  0);
16403 				ntest->nulltesttype = IS_NOT_NULL;
16404 
16405 				/*
16406 				 * argisrow=false is correct even for a composite column,
16407 				 * because attnotnull does not represent a SQL-spec IS NOT
16408 				 * NULL test in such a case, just IS DISTINCT FROM NULL.
16409 				 */
16410 				ntest->argisrow = false;
16411 				ntest->location = -1;
16412 				existConstraint = lappend(existConstraint, ntest);
16413 			}
16414 		}
16415 	}
16416 
16417 	return ConstraintImpliedByRelConstraint(scanrel, partConstraint, existConstraint);
16418 }
16419 
16420 /*
16421  * ConstraintImpliedByRelConstraint
16422  *		Do scanrel's existing constraints imply the given constraint?
16423  *
16424  * testConstraint is the constraint to validate. provenConstraint is a
16425  * caller-provided list of conditions which this function may assume
16426  * to be true. Both provenConstraint and testConstraint must be in
16427  * implicit-AND form, must only contain immutable clauses, and must
16428  * contain only Vars with varno = 1.
16429  */
16430 bool
ConstraintImpliedByRelConstraint(Relation scanrel,List * testConstraint,List * provenConstraint)16431 ConstraintImpliedByRelConstraint(Relation scanrel, List *testConstraint, List *provenConstraint)
16432 {
16433 	List	   *existConstraint = list_copy(provenConstraint);
16434 	TupleConstr *constr = RelationGetDescr(scanrel)->constr;
16435 	int			num_check,
16436 				i;
16437 
16438 	num_check = (constr != NULL) ? constr->num_check : 0;
16439 	for (i = 0; i < num_check; i++)
16440 	{
16441 		Node	   *cexpr;
16442 
16443 		/*
16444 		 * If this constraint hasn't been fully validated yet, we must ignore
16445 		 * it here.
16446 		 */
16447 		if (!constr->check[i].ccvalid)
16448 			continue;
16449 
16450 		cexpr = stringToNode(constr->check[i].ccbin);
16451 
16452 		/*
16453 		 * Run each expression through const-simplification and
16454 		 * canonicalization.  It is necessary, because we will be comparing it
16455 		 * to similarly-processed partition constraint expressions, and may
16456 		 * fail to detect valid matches without this.
16457 		 */
16458 		cexpr = eval_const_expressions(NULL, cexpr);
16459 		cexpr = (Node *) canonicalize_qual((Expr *) cexpr, true);
16460 
16461 		existConstraint = list_concat(existConstraint,
16462 									  make_ands_implicit((Expr *) cexpr));
16463 	}
16464 
16465 	/*
16466 	 * Try to make the proof.  Since we are comparing CHECK constraints, we
16467 	 * need to use weak implication, i.e., we assume existConstraint is
16468 	 * not-false and try to prove the same for testConstraint.
16469 	 *
16470 	 * Note that predicate_implied_by assumes its first argument is known
16471 	 * immutable.  That should always be true for both NOT NULL and partition
16472 	 * constraints, so we don't test it here.
16473 	 */
16474 	return predicate_implied_by(testConstraint, existConstraint, true);
16475 }
16476 
16477 /*
16478  * QueuePartitionConstraintValidation
16479  *
16480  * Add an entry to wqueue to have the given partition constraint validated by
16481  * Phase 3, for the given relation, and all its children.
16482  *
16483  * We first verify whether the given constraint is implied by pre-existing
16484  * relation constraints; if it is, there's no need to scan the table to
16485  * validate, so don't queue in that case.
16486  */
16487 static void
QueuePartitionConstraintValidation(List ** wqueue,Relation scanrel,List * partConstraint,bool validate_default)16488 QueuePartitionConstraintValidation(List **wqueue, Relation scanrel,
16489 								   List *partConstraint,
16490 								   bool validate_default)
16491 {
16492 	/*
16493 	 * Based on the table's existing constraints, determine whether or not we
16494 	 * may skip scanning the table.
16495 	 */
16496 	if (PartConstraintImpliedByRelConstraint(scanrel, partConstraint))
16497 	{
16498 		if (!validate_default)
16499 			ereport(DEBUG1,
16500 					(errmsg("partition constraint for table \"%s\" is implied by existing constraints",
16501 							RelationGetRelationName(scanrel))));
16502 		else
16503 			ereport(DEBUG1,
16504 					(errmsg("updated partition constraint for default partition \"%s\" is implied by existing constraints",
16505 							RelationGetRelationName(scanrel))));
16506 		return;
16507 	}
16508 
16509 	/*
16510 	 * Constraints proved insufficient. For plain relations, queue a
16511 	 * validation item now; for partitioned tables, recurse to process each
16512 	 * partition.
16513 	 */
16514 	if (scanrel->rd_rel->relkind == RELKIND_RELATION)
16515 	{
16516 		AlteredTableInfo *tab;
16517 
16518 		/* Grab a work queue entry. */
16519 		tab = ATGetQueueEntry(wqueue, scanrel);
16520 		Assert(tab->partition_constraint == NULL);
16521 		tab->partition_constraint = (Expr *) linitial(partConstraint);
16522 		tab->validate_default = validate_default;
16523 	}
16524 	else if (scanrel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
16525 	{
16526 		PartitionDesc partdesc = RelationGetPartitionDesc(scanrel);
16527 		int			i;
16528 
16529 		for (i = 0; i < partdesc->nparts; i++)
16530 		{
16531 			Relation	part_rel;
16532 			List	   *thisPartConstraint;
16533 
16534 			/*
16535 			 * This is the minimum lock we need to prevent deadlocks.
16536 			 */
16537 			part_rel = table_open(partdesc->oids[i], AccessExclusiveLock);
16538 
16539 			/*
16540 			 * Adjust the constraint for scanrel so that it matches this
16541 			 * partition's attribute numbers.
16542 			 */
16543 			thisPartConstraint =
16544 				map_partition_varattnos(partConstraint, 1,
16545 										part_rel, scanrel);
16546 
16547 			QueuePartitionConstraintValidation(wqueue, part_rel,
16548 											   thisPartConstraint,
16549 											   validate_default);
16550 			table_close(part_rel, NoLock);	/* keep lock till commit */
16551 		}
16552 	}
16553 }
16554 
16555 /*
16556  * ALTER TABLE <name> ATTACH PARTITION <partition-name> FOR VALUES
16557  *
16558  * Return the address of the newly attached partition.
16559  */
16560 static ObjectAddress
ATExecAttachPartition(List ** wqueue,Relation rel,PartitionCmd * cmd)16561 ATExecAttachPartition(List **wqueue, Relation rel, PartitionCmd *cmd)
16562 {
16563 	Relation	attachrel,
16564 				catalog;
16565 	List	   *attachrel_children;
16566 	List	   *partConstraint;
16567 	SysScanDesc scan;
16568 	ScanKeyData skey;
16569 	AttrNumber	attno;
16570 	int			natts;
16571 	TupleDesc	tupleDesc;
16572 	ObjectAddress address;
16573 	const char *trigger_name;
16574 	Oid			defaultPartOid;
16575 	List	   *partBoundConstraint;
16576 
16577 	/*
16578 	 * We must lock the default partition if one exists, because attaching a
16579 	 * new partition will change its partition constraint.
16580 	 */
16581 	defaultPartOid =
16582 		get_default_oid_from_partdesc(RelationGetPartitionDesc(rel));
16583 	if (OidIsValid(defaultPartOid))
16584 		LockRelationOid(defaultPartOid, AccessExclusiveLock);
16585 
16586 	attachrel = table_openrv(cmd->name, AccessExclusiveLock);
16587 
16588 	/*
16589 	 * XXX I think it'd be a good idea to grab locks on all tables referenced
16590 	 * by FKs at this point also.
16591 	 */
16592 
16593 	/*
16594 	 * Must be owner of both parent and source table -- parent was checked by
16595 	 * ATSimplePermissions call in ATPrepCmd
16596 	 */
16597 	ATSimplePermissions(attachrel, ATT_TABLE | ATT_FOREIGN_TABLE);
16598 
16599 	/* A partition can only have one parent */
16600 	if (attachrel->rd_rel->relispartition)
16601 		ereport(ERROR,
16602 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
16603 				 errmsg("\"%s\" is already a partition",
16604 						RelationGetRelationName(attachrel))));
16605 
16606 	if (OidIsValid(attachrel->rd_rel->reloftype))
16607 		ereport(ERROR,
16608 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
16609 				 errmsg("cannot attach a typed table as partition")));
16610 
16611 	/*
16612 	 * Table being attached should not already be part of inheritance; either
16613 	 * as a child table...
16614 	 */
16615 	catalog = table_open(InheritsRelationId, AccessShareLock);
16616 	ScanKeyInit(&skey,
16617 				Anum_pg_inherits_inhrelid,
16618 				BTEqualStrategyNumber, F_OIDEQ,
16619 				ObjectIdGetDatum(RelationGetRelid(attachrel)));
16620 	scan = systable_beginscan(catalog, InheritsRelidSeqnoIndexId, true,
16621 							  NULL, 1, &skey);
16622 	if (HeapTupleIsValid(systable_getnext(scan)))
16623 		ereport(ERROR,
16624 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
16625 				 errmsg("cannot attach inheritance child as partition")));
16626 	systable_endscan(scan);
16627 
16628 	/* ...or as a parent table (except the case when it is partitioned) */
16629 	ScanKeyInit(&skey,
16630 				Anum_pg_inherits_inhparent,
16631 				BTEqualStrategyNumber, F_OIDEQ,
16632 				ObjectIdGetDatum(RelationGetRelid(attachrel)));
16633 	scan = systable_beginscan(catalog, InheritsParentIndexId, true, NULL,
16634 							  1, &skey);
16635 	if (HeapTupleIsValid(systable_getnext(scan)) &&
16636 		attachrel->rd_rel->relkind == RELKIND_RELATION)
16637 		ereport(ERROR,
16638 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
16639 				 errmsg("cannot attach inheritance parent as partition")));
16640 	systable_endscan(scan);
16641 	table_close(catalog, AccessShareLock);
16642 
16643 	/*
16644 	 * Prevent circularity by seeing if rel is a partition of attachrel. (In
16645 	 * particular, this disallows making a rel a partition of itself.)
16646 	 *
16647 	 * We do that by checking if rel is a member of the list of attachrel's
16648 	 * partitions provided the latter is partitioned at all.  We want to avoid
16649 	 * having to construct this list again, so we request the strongest lock
16650 	 * on all partitions.  We need the strongest lock, because we may decide
16651 	 * to scan them if we find out that the table being attached (or its leaf
16652 	 * partitions) may contain rows that violate the partition constraint. If
16653 	 * the table has a constraint that would prevent such rows, which by
16654 	 * definition is present in all the partitions, we need not scan the
16655 	 * table, nor its partitions.  But we cannot risk a deadlock by taking a
16656 	 * weaker lock now and the stronger one only when needed.
16657 	 */
16658 	attachrel_children = find_all_inheritors(RelationGetRelid(attachrel),
16659 											 AccessExclusiveLock, NULL);
16660 	if (list_member_oid(attachrel_children, RelationGetRelid(rel)))
16661 		ereport(ERROR,
16662 				(errcode(ERRCODE_DUPLICATE_TABLE),
16663 				 errmsg("circular inheritance not allowed"),
16664 				 errdetail("\"%s\" is already a child of \"%s\".",
16665 						   RelationGetRelationName(rel),
16666 						   RelationGetRelationName(attachrel))));
16667 
16668 	/* If the parent is permanent, so must be all of its partitions. */
16669 	if (rel->rd_rel->relpersistence != RELPERSISTENCE_TEMP &&
16670 		attachrel->rd_rel->relpersistence == RELPERSISTENCE_TEMP)
16671 		ereport(ERROR,
16672 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
16673 				 errmsg("cannot attach a temporary relation as partition of permanent relation \"%s\"",
16674 						RelationGetRelationName(rel))));
16675 
16676 	/* Temp parent cannot have a partition that is itself not a temp */
16677 	if (rel->rd_rel->relpersistence == RELPERSISTENCE_TEMP &&
16678 		attachrel->rd_rel->relpersistence != RELPERSISTENCE_TEMP)
16679 		ereport(ERROR,
16680 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
16681 				 errmsg("cannot attach a permanent relation as partition of temporary relation \"%s\"",
16682 						RelationGetRelationName(rel))));
16683 
16684 	/* If the parent is temp, it must belong to this session */
16685 	if (rel->rd_rel->relpersistence == RELPERSISTENCE_TEMP &&
16686 		!rel->rd_islocaltemp)
16687 		ereport(ERROR,
16688 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
16689 				 errmsg("cannot attach as partition of temporary relation of another session")));
16690 
16691 	/* Ditto for the partition */
16692 	if (attachrel->rd_rel->relpersistence == RELPERSISTENCE_TEMP &&
16693 		!attachrel->rd_islocaltemp)
16694 		ereport(ERROR,
16695 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
16696 				 errmsg("cannot attach temporary relation of another session as partition")));
16697 
16698 	/* Check if there are any columns in attachrel that aren't in the parent */
16699 	tupleDesc = RelationGetDescr(attachrel);
16700 	natts = tupleDesc->natts;
16701 	for (attno = 1; attno <= natts; attno++)
16702 	{
16703 		Form_pg_attribute attribute = TupleDescAttr(tupleDesc, attno - 1);
16704 		char	   *attributeName = NameStr(attribute->attname);
16705 
16706 		/* Ignore dropped */
16707 		if (attribute->attisdropped)
16708 			continue;
16709 
16710 		/* Try to find the column in parent (matching on column name) */
16711 		if (!SearchSysCacheExists2(ATTNAME,
16712 								   ObjectIdGetDatum(RelationGetRelid(rel)),
16713 								   CStringGetDatum(attributeName)))
16714 			ereport(ERROR,
16715 					(errcode(ERRCODE_DATATYPE_MISMATCH),
16716 					 errmsg("table \"%s\" contains column \"%s\" not found in parent \"%s\"",
16717 							RelationGetRelationName(attachrel), attributeName,
16718 							RelationGetRelationName(rel)),
16719 					 errdetail("The new partition may contain only the columns present in parent.")));
16720 	}
16721 
16722 	/*
16723 	 * If child_rel has row-level triggers with transition tables, we
16724 	 * currently don't allow it to become a partition.  See also prohibitions
16725 	 * in ATExecAddInherit() and CreateTrigger().
16726 	 */
16727 	trigger_name = FindTriggerIncompatibleWithInheritance(attachrel->trigdesc);
16728 	if (trigger_name != NULL)
16729 		ereport(ERROR,
16730 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
16731 				 errmsg("trigger \"%s\" prevents table \"%s\" from becoming a partition",
16732 						trigger_name, RelationGetRelationName(attachrel)),
16733 				 errdetail("ROW triggers with transition tables are not supported on partitions")));
16734 
16735 	/*
16736 	 * Check that the new partition's bound is valid and does not overlap any
16737 	 * of existing partitions of the parent - note that it does not return on
16738 	 * error.
16739 	 */
16740 	check_new_partition_bound(RelationGetRelationName(attachrel), rel,
16741 							  cmd->bound);
16742 
16743 	/* OK to create inheritance.  Rest of the checks performed there */
16744 	CreateInheritance(attachrel, rel);
16745 
16746 	/* Update the pg_class entry. */
16747 	StorePartitionBound(attachrel, rel, cmd->bound);
16748 
16749 	/* Ensure there exists a correct set of indexes in the partition. */
16750 	AttachPartitionEnsureIndexes(rel, attachrel);
16751 
16752 	/* and triggers */
16753 	CloneRowTriggersToPartition(rel, attachrel);
16754 
16755 	/*
16756 	 * Clone foreign key constraints.  Callee is responsible for setting up
16757 	 * for phase 3 constraint verification.
16758 	 */
16759 	CloneForeignKeyConstraints(wqueue, rel, attachrel);
16760 
16761 	/*
16762 	 * Generate partition constraint from the partition bound specification.
16763 	 * If the parent itself is a partition, make sure to include its
16764 	 * constraint as well.
16765 	 */
16766 	partBoundConstraint = get_qual_from_partbound(attachrel, rel, cmd->bound);
16767 	partConstraint = list_concat(partBoundConstraint,
16768 								 RelationGetPartitionQual(rel));
16769 
16770 	/* Skip validation if there are no constraints to validate. */
16771 	if (partConstraint)
16772 	{
16773 		/*
16774 		 * Run the partition quals through const-simplification similar to
16775 		 * check constraints.  We skip canonicalize_qual, though, because
16776 		 * partition quals should be in canonical form already.
16777 		 */
16778 		partConstraint =
16779 			(List *) eval_const_expressions(NULL,
16780 											(Node *) partConstraint);
16781 
16782 		/* XXX this sure looks wrong */
16783 		partConstraint = list_make1(make_ands_explicit(partConstraint));
16784 
16785 		/*
16786 		 * Adjust the generated constraint to match this partition's attribute
16787 		 * numbers.
16788 		 */
16789 		partConstraint = map_partition_varattnos(partConstraint, 1, attachrel,
16790 												 rel);
16791 
16792 		/* Validate partition constraints against the table being attached. */
16793 		QueuePartitionConstraintValidation(wqueue, attachrel, partConstraint,
16794 										   false);
16795 	}
16796 
16797 	/*
16798 	 * If we're attaching a partition other than the default partition and a
16799 	 * default one exists, then that partition's partition constraint changes,
16800 	 * so add an entry to the work queue to validate it, too.  (We must not do
16801 	 * this when the partition being attached is the default one; we already
16802 	 * did it above!)
16803 	 */
16804 	if (OidIsValid(defaultPartOid))
16805 	{
16806 		Relation	defaultrel;
16807 		List	   *defPartConstraint;
16808 
16809 		Assert(!cmd->bound->is_default);
16810 
16811 		/* we already hold a lock on the default partition */
16812 		defaultrel = table_open(defaultPartOid, NoLock);
16813 		defPartConstraint =
16814 			get_proposed_default_constraint(partBoundConstraint);
16815 
16816 		/*
16817 		 * Map the Vars in the constraint expression from rel's attnos to
16818 		 * defaultrel's.
16819 		 */
16820 		defPartConstraint =
16821 			map_partition_varattnos(defPartConstraint,
16822 									1, defaultrel, rel);
16823 		QueuePartitionConstraintValidation(wqueue, defaultrel,
16824 										   defPartConstraint, true);
16825 
16826 		/* keep our lock until commit. */
16827 		table_close(defaultrel, NoLock);
16828 	}
16829 
16830 	ObjectAddressSet(address, RelationRelationId, RelationGetRelid(attachrel));
16831 
16832 	/*
16833 	 * If the partition we just attached is partitioned itself, invalidate
16834 	 * relcache for all descendent partitions too to ensure that their
16835 	 * rd_partcheck expression trees are rebuilt; partitions already locked
16836 	 * at the beginning of this function.
16837 	 */
16838 	if (attachrel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
16839 	{
16840 		ListCell *l;
16841 
16842 		foreach(l, attachrel_children)
16843 		{
16844 			CacheInvalidateRelcacheByRelid(lfirst_oid(l));
16845 		}
16846 	}
16847 
16848 	/* keep our lock until commit */
16849 	table_close(attachrel, NoLock);
16850 
16851 	return address;
16852 }
16853 
16854 /*
16855  * AttachPartitionEnsureIndexes
16856  *		subroutine for ATExecAttachPartition to create/match indexes
16857  *
16858  * Enforce the indexing rule for partitioned tables during ALTER TABLE / ATTACH
16859  * PARTITION: every partition must have an index attached to each index on the
16860  * partitioned table.
16861  */
16862 static void
AttachPartitionEnsureIndexes(Relation rel,Relation attachrel)16863 AttachPartitionEnsureIndexes(Relation rel, Relation attachrel)
16864 {
16865 	List	   *idxes;
16866 	List	   *attachRelIdxs;
16867 	Relation   *attachrelIdxRels;
16868 	IndexInfo **attachInfos;
16869 	int			i;
16870 	ListCell   *cell;
16871 	MemoryContext cxt;
16872 	MemoryContext oldcxt;
16873 
16874 	cxt = AllocSetContextCreate(CurrentMemoryContext,
16875 								"AttachPartitionEnsureIndexes",
16876 								ALLOCSET_DEFAULT_SIZES);
16877 	oldcxt = MemoryContextSwitchTo(cxt);
16878 
16879 	idxes = RelationGetIndexList(rel);
16880 	attachRelIdxs = RelationGetIndexList(attachrel);
16881 	attachrelIdxRels = palloc(sizeof(Relation) * list_length(attachRelIdxs));
16882 	attachInfos = palloc(sizeof(IndexInfo *) * list_length(attachRelIdxs));
16883 
16884 	/* Build arrays of all existing indexes and their IndexInfos */
16885 	i = 0;
16886 	foreach(cell, attachRelIdxs)
16887 	{
16888 		Oid			cldIdxId = lfirst_oid(cell);
16889 
16890 		attachrelIdxRels[i] = index_open(cldIdxId, AccessShareLock);
16891 		attachInfos[i] = BuildIndexInfo(attachrelIdxRels[i]);
16892 		i++;
16893 	}
16894 
16895 	/*
16896 	 * If we're attaching a foreign table, we must fail if any of the indexes
16897 	 * is a constraint index; otherwise, there's nothing to do here.  Do this
16898 	 * before starting work, to avoid wasting the effort of building a few
16899 	 * non-unique indexes before coming across a unique one.
16900 	 */
16901 	if (attachrel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
16902 	{
16903 		foreach(cell, idxes)
16904 		{
16905 			Oid			idx = lfirst_oid(cell);
16906 			Relation	idxRel = index_open(idx, AccessShareLock);
16907 
16908 			if (idxRel->rd_index->indisunique ||
16909 				idxRel->rd_index->indisprimary)
16910 				ereport(ERROR,
16911 						(errcode(ERRCODE_WRONG_OBJECT_TYPE),
16912 						 errmsg("cannot attach foreign table \"%s\" as partition of partitioned table \"%s\"",
16913 								RelationGetRelationName(attachrel),
16914 								RelationGetRelationName(rel)),
16915 						 errdetail("Table \"%s\" contains unique indexes.",
16916 								   RelationGetRelationName(rel))));
16917 			index_close(idxRel, AccessShareLock);
16918 		}
16919 
16920 		goto out;
16921 	}
16922 
16923 	/*
16924 	 * For each index on the partitioned table, find a matching one in the
16925 	 * partition-to-be; if one is not found, create one.
16926 	 */
16927 	foreach(cell, idxes)
16928 	{
16929 		Oid			idx = lfirst_oid(cell);
16930 		Relation	idxRel = index_open(idx, AccessShareLock);
16931 		IndexInfo  *info;
16932 		AttrMap    *attmap;
16933 		bool		found = false;
16934 		Oid			constraintOid;
16935 
16936 		/*
16937 		 * Ignore indexes in the partitioned table other than partitioned
16938 		 * indexes.
16939 		 */
16940 		if (idxRel->rd_rel->relkind != RELKIND_PARTITIONED_INDEX)
16941 		{
16942 			index_close(idxRel, AccessShareLock);
16943 			continue;
16944 		}
16945 
16946 		/* construct an indexinfo to compare existing indexes against */
16947 		info = BuildIndexInfo(idxRel);
16948 		attmap = build_attrmap_by_name(RelationGetDescr(attachrel),
16949 									   RelationGetDescr(rel));
16950 		constraintOid = get_relation_idx_constraint_oid(RelationGetRelid(rel), idx);
16951 
16952 		/*
16953 		 * Scan the list of existing indexes in the partition-to-be, and mark
16954 		 * the first matching, unattached one we find, if any, as partition of
16955 		 * the parent index.  If we find one, we're done.
16956 		 */
16957 		for (i = 0; i < list_length(attachRelIdxs); i++)
16958 		{
16959 			Oid			cldIdxId = RelationGetRelid(attachrelIdxRels[i]);
16960 			Oid			cldConstrOid = InvalidOid;
16961 
16962 			/* does this index have a parent?  if so, can't use it */
16963 			if (attachrelIdxRels[i]->rd_rel->relispartition)
16964 				continue;
16965 
16966 			if (CompareIndexInfo(attachInfos[i], info,
16967 								 attachrelIdxRels[i]->rd_indcollation,
16968 								 idxRel->rd_indcollation,
16969 								 attachrelIdxRels[i]->rd_opfamily,
16970 								 idxRel->rd_opfamily,
16971 								 attmap))
16972 			{
16973 				/*
16974 				 * If this index is being created in the parent because of a
16975 				 * constraint, then the child needs to have a constraint also,
16976 				 * so look for one.  If there is no such constraint, this
16977 				 * index is no good, so keep looking.
16978 				 */
16979 				if (OidIsValid(constraintOid))
16980 				{
16981 					cldConstrOid =
16982 						get_relation_idx_constraint_oid(RelationGetRelid(attachrel),
16983 														cldIdxId);
16984 					/* no dice */
16985 					if (!OidIsValid(cldConstrOid))
16986 						continue;
16987 				}
16988 
16989 				/* bingo. */
16990 				IndexSetParentIndex(attachrelIdxRels[i], idx);
16991 				if (OidIsValid(constraintOid))
16992 					ConstraintSetParentConstraint(cldConstrOid, constraintOid,
16993 												  RelationGetRelid(attachrel));
16994 				found = true;
16995 
16996 				CommandCounterIncrement();
16997 				break;
16998 			}
16999 		}
17000 
17001 		/*
17002 		 * If no suitable index was found in the partition-to-be, create one
17003 		 * now.
17004 		 */
17005 		if (!found)
17006 		{
17007 			IndexStmt  *stmt;
17008 			Oid			constraintOid;
17009 
17010 			stmt = generateClonedIndexStmt(NULL,
17011 										   idxRel, attmap,
17012 										   &constraintOid);
17013 			DefineIndex(RelationGetRelid(attachrel), stmt, InvalidOid,
17014 						RelationGetRelid(idxRel),
17015 						constraintOid,
17016 						true, false, false, false, false);
17017 		}
17018 
17019 		index_close(idxRel, AccessShareLock);
17020 	}
17021 
17022 out:
17023 	/* Clean up. */
17024 	for (i = 0; i < list_length(attachRelIdxs); i++)
17025 		index_close(attachrelIdxRels[i], AccessShareLock);
17026 	MemoryContextSwitchTo(oldcxt);
17027 	MemoryContextDelete(cxt);
17028 }
17029 
17030 /*
17031  * CloneRowTriggersToPartition
17032  *		subroutine for ATExecAttachPartition/DefineRelation to create row
17033  *		triggers on partitions
17034  */
17035 static void
CloneRowTriggersToPartition(Relation parent,Relation partition)17036 CloneRowTriggersToPartition(Relation parent, Relation partition)
17037 {
17038 	Relation	pg_trigger;
17039 	ScanKeyData key;
17040 	SysScanDesc scan;
17041 	HeapTuple	tuple;
17042 	MemoryContext perTupCxt;
17043 
17044 	ScanKeyInit(&key, Anum_pg_trigger_tgrelid, BTEqualStrategyNumber,
17045 				F_OIDEQ, ObjectIdGetDatum(RelationGetRelid(parent)));
17046 	pg_trigger = table_open(TriggerRelationId, RowExclusiveLock);
17047 	scan = systable_beginscan(pg_trigger, TriggerRelidNameIndexId,
17048 							  true, NULL, 1, &key);
17049 
17050 	perTupCxt = AllocSetContextCreate(CurrentMemoryContext,
17051 									  "clone trig", ALLOCSET_SMALL_SIZES);
17052 
17053 	while (HeapTupleIsValid(tuple = systable_getnext(scan)))
17054 	{
17055 		Form_pg_trigger trigForm = (Form_pg_trigger) GETSTRUCT(tuple);
17056 		CreateTrigStmt *trigStmt;
17057 		Node	   *qual = NULL;
17058 		Datum		value;
17059 		bool		isnull;
17060 		List	   *cols = NIL;
17061 		List	   *trigargs = NIL;
17062 		MemoryContext oldcxt;
17063 
17064 		/*
17065 		 * Ignore statement-level triggers; those are not cloned.
17066 		 */
17067 		if (!TRIGGER_FOR_ROW(trigForm->tgtype))
17068 			continue;
17069 
17070 		/*
17071 		 * Internal triggers require careful examination.  Ideally, we don't
17072 		 * clone them.  However, if our parent is itself a partition, there
17073 		 * might be internal triggers that must not be skipped; for example,
17074 		 * triggers on our parent that are in turn clones from its parent (our
17075 		 * grandparent) are marked internal, yet they are to be cloned.
17076 		 *
17077 		 * Note we dare not verify that the other trigger belongs to an
17078 		 * ancestor relation of our parent, because that creates deadlock
17079 		 * opportunities.
17080 		 */
17081 		if (trigForm->tgisinternal &&
17082 			(!parent->rd_rel->relispartition ||
17083 			 !OidIsValid(trigForm->tgparentid)))
17084 			continue;
17085 
17086 		/*
17087 		 * Complain if we find an unexpected trigger type.
17088 		 */
17089 		if (!TRIGGER_FOR_BEFORE(trigForm->tgtype) &&
17090 			!TRIGGER_FOR_AFTER(trigForm->tgtype))
17091 			elog(ERROR, "unexpected trigger \"%s\" found",
17092 				 NameStr(trigForm->tgname));
17093 
17094 		/* Use short-lived context for CREATE TRIGGER */
17095 		oldcxt = MemoryContextSwitchTo(perTupCxt);
17096 
17097 		/*
17098 		 * If there is a WHEN clause, generate a 'cooked' version of it that's
17099 		 * appropriate for the partition.
17100 		 */
17101 		value = heap_getattr(tuple, Anum_pg_trigger_tgqual,
17102 							 RelationGetDescr(pg_trigger), &isnull);
17103 		if (!isnull)
17104 		{
17105 			qual = stringToNode(TextDatumGetCString(value));
17106 			qual = (Node *) map_partition_varattnos((List *) qual, PRS2_OLD_VARNO,
17107 													partition, parent);
17108 			qual = (Node *) map_partition_varattnos((List *) qual, PRS2_NEW_VARNO,
17109 													partition, parent);
17110 		}
17111 
17112 		/*
17113 		 * If there is a column list, transform it to a list of column names.
17114 		 * Note we don't need to map this list in any way ...
17115 		 */
17116 		if (trigForm->tgattr.dim1 > 0)
17117 		{
17118 			int			i;
17119 
17120 			for (i = 0; i < trigForm->tgattr.dim1; i++)
17121 			{
17122 				Form_pg_attribute col;
17123 
17124 				col = TupleDescAttr(parent->rd_att,
17125 									trigForm->tgattr.values[i] - 1);
17126 				cols = lappend(cols,
17127 							   makeString(pstrdup(NameStr(col->attname))));
17128 			}
17129 		}
17130 
17131 		/* Reconstruct trigger arguments list. */
17132 		if (trigForm->tgnargs > 0)
17133 		{
17134 			char	   *p;
17135 
17136 			value = heap_getattr(tuple, Anum_pg_trigger_tgargs,
17137 								 RelationGetDescr(pg_trigger), &isnull);
17138 			if (isnull)
17139 				elog(ERROR, "tgargs is null for trigger \"%s\" in partition \"%s\"",
17140 					 NameStr(trigForm->tgname), RelationGetRelationName(partition));
17141 
17142 			p = (char *) VARDATA_ANY(DatumGetByteaPP(value));
17143 
17144 			for (int i = 0; i < trigForm->tgnargs; i++)
17145 			{
17146 				trigargs = lappend(trigargs, makeString(pstrdup(p)));
17147 				p += strlen(p) + 1;
17148 			}
17149 		}
17150 
17151 		trigStmt = makeNode(CreateTrigStmt);
17152 		trigStmt->trigname = NameStr(trigForm->tgname);
17153 		trigStmt->relation = NULL;
17154 		trigStmt->funcname = NULL;	/* passed separately */
17155 		trigStmt->args = trigargs;
17156 		trigStmt->row = true;
17157 		trigStmt->timing = trigForm->tgtype & TRIGGER_TYPE_TIMING_MASK;
17158 		trigStmt->events = trigForm->tgtype & TRIGGER_TYPE_EVENT_MASK;
17159 		trigStmt->columns = cols;
17160 		trigStmt->whenClause = NULL;	/* passed separately */
17161 		trigStmt->isconstraint = OidIsValid(trigForm->tgconstraint);
17162 		trigStmt->transitionRels = NIL; /* not supported at present */
17163 		trigStmt->deferrable = trigForm->tgdeferrable;
17164 		trigStmt->initdeferred = trigForm->tginitdeferred;
17165 		trigStmt->constrrel = NULL; /* passed separately */
17166 
17167 		CreateTriggerFiringOn(trigStmt, NULL, RelationGetRelid(partition),
17168 							  trigForm->tgconstrrelid, InvalidOid, InvalidOid,
17169 							  trigForm->tgfoid, trigForm->oid, qual,
17170 							  false, true, trigForm->tgenabled);
17171 
17172 		MemoryContextSwitchTo(oldcxt);
17173 		MemoryContextReset(perTupCxt);
17174 	}
17175 
17176 	MemoryContextDelete(perTupCxt);
17177 
17178 	systable_endscan(scan);
17179 	table_close(pg_trigger, RowExclusiveLock);
17180 }
17181 
17182 /*
17183  * ALTER TABLE DETACH PARTITION
17184  *
17185  * Return the address of the relation that is no longer a partition of rel.
17186  */
17187 static ObjectAddress
ATExecDetachPartition(Relation rel,RangeVar * name)17188 ATExecDetachPartition(Relation rel, RangeVar *name)
17189 {
17190 	Relation	partRel,
17191 				classRel;
17192 	HeapTuple	tuple,
17193 				newtuple;
17194 	Datum		new_val[Natts_pg_class];
17195 	bool		new_null[Natts_pg_class],
17196 				new_repl[Natts_pg_class];
17197 	ObjectAddress address;
17198 	Oid			defaultPartOid;
17199 	List	   *indexes;
17200 	List	   *fks;
17201 	ListCell   *cell;
17202 
17203 	/*
17204 	 * We must lock the default partition, because detaching this partition
17205 	 * will change its partition constraint.
17206 	 */
17207 	defaultPartOid =
17208 		get_default_oid_from_partdesc(RelationGetPartitionDesc(rel));
17209 	if (OidIsValid(defaultPartOid))
17210 		LockRelationOid(defaultPartOid, AccessExclusiveLock);
17211 
17212 	partRel = table_openrv(name, ShareUpdateExclusiveLock);
17213 
17214 	/* Ensure that foreign keys still hold after this detach */
17215 	ATDetachCheckNoForeignKeyRefs(partRel);
17216 
17217 	/* All inheritance related checks are performed within the function */
17218 	RemoveInheritance(partRel, rel);
17219 
17220 	/* Update pg_class tuple */
17221 	classRel = table_open(RelationRelationId, RowExclusiveLock);
17222 	tuple = SearchSysCacheCopy1(RELOID,
17223 								ObjectIdGetDatum(RelationGetRelid(partRel)));
17224 	if (!HeapTupleIsValid(tuple))
17225 		elog(ERROR, "cache lookup failed for relation %u",
17226 			 RelationGetRelid(partRel));
17227 	Assert(((Form_pg_class) GETSTRUCT(tuple))->relispartition);
17228 
17229 	/* Clear relpartbound and reset relispartition */
17230 	memset(new_val, 0, sizeof(new_val));
17231 	memset(new_null, false, sizeof(new_null));
17232 	memset(new_repl, false, sizeof(new_repl));
17233 	new_val[Anum_pg_class_relpartbound - 1] = (Datum) 0;
17234 	new_null[Anum_pg_class_relpartbound - 1] = true;
17235 	new_repl[Anum_pg_class_relpartbound - 1] = true;
17236 	newtuple = heap_modify_tuple(tuple, RelationGetDescr(classRel),
17237 								 new_val, new_null, new_repl);
17238 
17239 	((Form_pg_class) GETSTRUCT(newtuple))->relispartition = false;
17240 	CatalogTupleUpdate(classRel, &newtuple->t_self, newtuple);
17241 	heap_freetuple(newtuple);
17242 
17243 	if (OidIsValid(defaultPartOid))
17244 	{
17245 		/*
17246 		 * If the relation being detached is the default partition itself,
17247 		 * remove it from the parent's pg_partitioned_table entry.
17248 		 *
17249 		 * If not, we must invalidate default partition's relcache entry, as
17250 		 * in StorePartitionBound: its partition constraint depends on every
17251 		 * other partition's partition constraint.
17252 		 */
17253 		if (RelationGetRelid(partRel) == defaultPartOid)
17254 			update_default_partition_oid(RelationGetRelid(rel), InvalidOid);
17255 		else
17256 			CacheInvalidateRelcacheByRelid(defaultPartOid);
17257 	}
17258 
17259 	/* detach indexes too */
17260 	indexes = RelationGetIndexList(partRel);
17261 	foreach(cell, indexes)
17262 	{
17263 		Oid			idxid = lfirst_oid(cell);
17264 		Relation	idx;
17265 		Oid			constrOid;
17266 
17267 		if (!has_superclass(idxid))
17268 			continue;
17269 
17270 		Assert((IndexGetRelation(get_partition_parent(idxid), false) ==
17271 				RelationGetRelid(rel)));
17272 
17273 		idx = index_open(idxid, AccessExclusiveLock);
17274 		IndexSetParentIndex(idx, InvalidOid);
17275 
17276 		/* If there's a constraint associated with the index, detach it too */
17277 		constrOid = get_relation_idx_constraint_oid(RelationGetRelid(partRel),
17278 													idxid);
17279 		if (OidIsValid(constrOid))
17280 			ConstraintSetParentConstraint(constrOid, InvalidOid, InvalidOid);
17281 
17282 		index_close(idx, NoLock);
17283 	}
17284 	table_close(classRel, RowExclusiveLock);
17285 
17286 	/* Drop any triggers that were cloned on creation/attach. */
17287 	DropClonedTriggersFromPartition(RelationGetRelid(partRel));
17288 
17289 	/*
17290 	 * Detach any foreign keys that are inherited.  This includes creating
17291 	 * additional action triggers.
17292 	 */
17293 	fks = copyObject(RelationGetFKeyList(partRel));
17294 	foreach(cell, fks)
17295 	{
17296 		ForeignKeyCacheInfo *fk = lfirst(cell);
17297 		HeapTuple	contup;
17298 		Form_pg_constraint conform;
17299 		Constraint *fkconstraint;
17300 
17301 		contup = SearchSysCache1(CONSTROID, ObjectIdGetDatum(fk->conoid));
17302 		if (!HeapTupleIsValid(contup))
17303 			elog(ERROR, "cache lookup failed for constraint %u", fk->conoid);
17304 		conform = (Form_pg_constraint) GETSTRUCT(contup);
17305 
17306 		/* consider only the inherited foreign keys */
17307 		if (conform->contype != CONSTRAINT_FOREIGN ||
17308 			!OidIsValid(conform->conparentid))
17309 		{
17310 			ReleaseSysCache(contup);
17311 			continue;
17312 		}
17313 
17314 		/* unset conparentid and adjust conislocal, coninhcount, etc. */
17315 		ConstraintSetParentConstraint(fk->conoid, InvalidOid, InvalidOid);
17316 
17317 		/*
17318 		 * Make the action triggers on the referenced relation.  When this was
17319 		 * a partition the action triggers pointed to the parent rel (they
17320 		 * still do), but now we need separate ones of our own.
17321 		 */
17322 		fkconstraint = makeNode(Constraint);
17323 		fkconstraint->conname = pstrdup(NameStr(conform->conname));
17324 		fkconstraint->fk_upd_action = conform->confupdtype;
17325 		fkconstraint->fk_del_action = conform->confdeltype;
17326 		fkconstraint->deferrable = conform->condeferrable;
17327 		fkconstraint->initdeferred = conform->condeferred;
17328 
17329 		createForeignKeyActionTriggers(partRel, conform->confrelid,
17330 									   fkconstraint, fk->conoid,
17331 									   conform->conindid);
17332 
17333 		ReleaseSysCache(contup);
17334 	}
17335 	list_free_deep(fks);
17336 
17337 	/*
17338 	 * Any sub-constraints that are in the referenced-side of a larger
17339 	 * constraint have to be removed.  This partition is no longer part of the
17340 	 * key space of the constraint.
17341 	 */
17342 	foreach(cell, GetParentedForeignKeyRefs(partRel))
17343 	{
17344 		Oid			constrOid = lfirst_oid(cell);
17345 		ObjectAddress constraint;
17346 
17347 		ConstraintSetParentConstraint(constrOid, InvalidOid, InvalidOid);
17348 		deleteDependencyRecordsForClass(ConstraintRelationId,
17349 										constrOid,
17350 										ConstraintRelationId,
17351 										DEPENDENCY_INTERNAL);
17352 		CommandCounterIncrement();
17353 
17354 		ObjectAddressSet(constraint, ConstraintRelationId, constrOid);
17355 		performDeletion(&constraint, DROP_RESTRICT, 0);
17356 	}
17357 	CommandCounterIncrement();
17358 
17359 	/*
17360 	 * Invalidate the parent's relcache so that the partition is no longer
17361 	 * included in its partition descriptor.
17362 	 */
17363 	CacheInvalidateRelcache(rel);
17364 
17365 	/*
17366 	 * If the partition we just detached is partitioned itself, invalidate
17367 	 * relcache for all descendent partitions too to ensure that their
17368 	 * rd_partcheck expression trees are rebuilt; must lock partitions
17369 	 * before doing so, using the same lockmode as what partRel has been
17370 	 * locked with by the caller.
17371 	 */
17372 	if (partRel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
17373 	{
17374 		List   *children;
17375 
17376 		children = find_all_inheritors(RelationGetRelid(partRel),
17377 									   AccessExclusiveLock, NULL);
17378 		foreach(cell, children)
17379 		{
17380 			CacheInvalidateRelcacheByRelid(lfirst_oid(cell));
17381 		}
17382 	}
17383 
17384 	ObjectAddressSet(address, RelationRelationId, RelationGetRelid(partRel));
17385 
17386 	/* keep our lock until commit */
17387 	table_close(partRel, NoLock);
17388 
17389 	return address;
17390 }
17391 
17392 /*
17393  * DropClonedTriggersFromPartition
17394  *		subroutine for ATExecDetachPartition to remove any triggers that were
17395  *		cloned to the partition when it was created-as-partition or attached.
17396  *		This undoes what CloneRowTriggersToPartition did.
17397  */
17398 static void
DropClonedTriggersFromPartition(Oid partitionId)17399 DropClonedTriggersFromPartition(Oid partitionId)
17400 {
17401 	ScanKeyData skey;
17402 	SysScanDesc scan;
17403 	HeapTuple	trigtup;
17404 	Relation	tgrel;
17405 	ObjectAddresses *objects;
17406 
17407 	objects = new_object_addresses();
17408 
17409 	/*
17410 	 * Scan pg_trigger to search for all triggers on this rel.
17411 	 */
17412 	ScanKeyInit(&skey, Anum_pg_trigger_tgrelid, BTEqualStrategyNumber,
17413 				F_OIDEQ, ObjectIdGetDatum(partitionId));
17414 	tgrel = table_open(TriggerRelationId, RowExclusiveLock);
17415 	scan = systable_beginscan(tgrel, TriggerRelidNameIndexId,
17416 							  true, NULL, 1, &skey);
17417 	while (HeapTupleIsValid(trigtup = systable_getnext(scan)))
17418 	{
17419 		Form_pg_trigger pg_trigger = (Form_pg_trigger) GETSTRUCT(trigtup);
17420 		ObjectAddress trig;
17421 
17422 		/* Ignore triggers that weren't cloned */
17423 		if (!OidIsValid(pg_trigger->tgparentid))
17424 			continue;
17425 
17426 		/*
17427 		 * This is ugly, but necessary: remove the dependency markings on the
17428 		 * trigger so that it can be removed.
17429 		 */
17430 		deleteDependencyRecordsForClass(TriggerRelationId, pg_trigger->oid,
17431 										TriggerRelationId,
17432 										DEPENDENCY_PARTITION_PRI);
17433 		deleteDependencyRecordsForClass(TriggerRelationId, pg_trigger->oid,
17434 										RelationRelationId,
17435 										DEPENDENCY_PARTITION_SEC);
17436 
17437 		/* remember this trigger to remove it below */
17438 		ObjectAddressSet(trig, TriggerRelationId, pg_trigger->oid);
17439 		add_exact_object_address(&trig, objects);
17440 	}
17441 
17442 	/* make the dependency removal visible to the deletion below */
17443 	CommandCounterIncrement();
17444 	performMultipleDeletions(objects, DROP_RESTRICT, PERFORM_DELETION_INTERNAL);
17445 
17446 	/* done */
17447 	free_object_addresses(objects);
17448 	systable_endscan(scan);
17449 	table_close(tgrel, RowExclusiveLock);
17450 }
17451 
17452 /*
17453  * Before acquiring lock on an index, acquire the same lock on the owning
17454  * table.
17455  */
17456 struct AttachIndexCallbackState
17457 {
17458 	Oid			partitionOid;
17459 	Oid			parentTblOid;
17460 	bool		lockedParentTbl;
17461 };
17462 
17463 static void
RangeVarCallbackForAttachIndex(const RangeVar * rv,Oid relOid,Oid oldRelOid,void * arg)17464 RangeVarCallbackForAttachIndex(const RangeVar *rv, Oid relOid, Oid oldRelOid,
17465 							   void *arg)
17466 {
17467 	struct AttachIndexCallbackState *state;
17468 	Form_pg_class classform;
17469 	HeapTuple	tuple;
17470 
17471 	state = (struct AttachIndexCallbackState *) arg;
17472 
17473 	if (!state->lockedParentTbl)
17474 	{
17475 		LockRelationOid(state->parentTblOid, AccessShareLock);
17476 		state->lockedParentTbl = true;
17477 	}
17478 
17479 	/*
17480 	 * If we previously locked some other heap, and the name we're looking up
17481 	 * no longer refers to an index on that relation, release the now-useless
17482 	 * lock.  XXX maybe we should do *after* we verify whether the index does
17483 	 * not actually belong to the same relation ...
17484 	 */
17485 	if (relOid != oldRelOid && OidIsValid(state->partitionOid))
17486 	{
17487 		UnlockRelationOid(state->partitionOid, AccessShareLock);
17488 		state->partitionOid = InvalidOid;
17489 	}
17490 
17491 	/* Didn't find a relation, so no need for locking or permission checks. */
17492 	if (!OidIsValid(relOid))
17493 		return;
17494 
17495 	tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relOid));
17496 	if (!HeapTupleIsValid(tuple))
17497 		return;					/* concurrently dropped, so nothing to do */
17498 	classform = (Form_pg_class) GETSTRUCT(tuple);
17499 	if (classform->relkind != RELKIND_PARTITIONED_INDEX &&
17500 		classform->relkind != RELKIND_INDEX)
17501 		ereport(ERROR,
17502 				(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
17503 				 errmsg("\"%s\" is not an index", rv->relname)));
17504 	ReleaseSysCache(tuple);
17505 
17506 	/*
17507 	 * Since we need only examine the heap's tupledesc, an access share lock
17508 	 * on it (preventing any DDL) is sufficient.
17509 	 */
17510 	state->partitionOid = IndexGetRelation(relOid, false);
17511 	LockRelationOid(state->partitionOid, AccessShareLock);
17512 }
17513 
17514 /*
17515  * ALTER INDEX i1 ATTACH PARTITION i2
17516  */
17517 static ObjectAddress
ATExecAttachPartitionIdx(List ** wqueue,Relation parentIdx,RangeVar * name)17518 ATExecAttachPartitionIdx(List **wqueue, Relation parentIdx, RangeVar *name)
17519 {
17520 	Relation	partIdx;
17521 	Relation	partTbl;
17522 	Relation	parentTbl;
17523 	ObjectAddress address;
17524 	Oid			partIdxId;
17525 	Oid			currParent;
17526 	struct AttachIndexCallbackState state;
17527 
17528 	/*
17529 	 * We need to obtain lock on the index 'name' to modify it, but we also
17530 	 * need to read its owning table's tuple descriptor -- so we need to lock
17531 	 * both.  To avoid deadlocks, obtain lock on the table before doing so on
17532 	 * the index.  Furthermore, we need to examine the parent table of the
17533 	 * partition, so lock that one too.
17534 	 */
17535 	state.partitionOid = InvalidOid;
17536 	state.parentTblOid = parentIdx->rd_index->indrelid;
17537 	state.lockedParentTbl = false;
17538 	partIdxId =
17539 		RangeVarGetRelidExtended(name, AccessExclusiveLock, 0,
17540 								 RangeVarCallbackForAttachIndex,
17541 								 (void *) &state);
17542 	/* Not there? */
17543 	if (!OidIsValid(partIdxId))
17544 		ereport(ERROR,
17545 				(errcode(ERRCODE_UNDEFINED_OBJECT),
17546 				 errmsg("index \"%s\" does not exist", name->relname)));
17547 
17548 	/* no deadlock risk: RangeVarGetRelidExtended already acquired the lock */
17549 	partIdx = relation_open(partIdxId, AccessExclusiveLock);
17550 
17551 	/* we already hold locks on both tables, so this is safe: */
17552 	parentTbl = relation_open(parentIdx->rd_index->indrelid, AccessShareLock);
17553 	partTbl = relation_open(partIdx->rd_index->indrelid, NoLock);
17554 
17555 	ObjectAddressSet(address, RelationRelationId, RelationGetRelid(partIdx));
17556 
17557 	/* Silently do nothing if already in the right state */
17558 	currParent = partIdx->rd_rel->relispartition ?
17559 		get_partition_parent(partIdxId) : InvalidOid;
17560 	if (currParent != RelationGetRelid(parentIdx))
17561 	{
17562 		IndexInfo  *childInfo;
17563 		IndexInfo  *parentInfo;
17564 		AttrMap    *attmap;
17565 		bool		found;
17566 		int			i;
17567 		PartitionDesc partDesc;
17568 		Oid			constraintOid,
17569 					cldConstrId = InvalidOid;
17570 
17571 		/*
17572 		 * If this partition already has an index attached, refuse the
17573 		 * operation.
17574 		 */
17575 		refuseDupeIndexAttach(parentIdx, partIdx, partTbl);
17576 
17577 		if (OidIsValid(currParent))
17578 			ereport(ERROR,
17579 					(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
17580 					 errmsg("cannot attach index \"%s\" as a partition of index \"%s\"",
17581 							RelationGetRelationName(partIdx),
17582 							RelationGetRelationName(parentIdx)),
17583 					 errdetail("Index \"%s\" is already attached to another index.",
17584 							   RelationGetRelationName(partIdx))));
17585 
17586 		/* Make sure it indexes a partition of the other index's table */
17587 		partDesc = RelationGetPartitionDesc(parentTbl);
17588 		found = false;
17589 		for (i = 0; i < partDesc->nparts; i++)
17590 		{
17591 			if (partDesc->oids[i] == state.partitionOid)
17592 			{
17593 				found = true;
17594 				break;
17595 			}
17596 		}
17597 		if (!found)
17598 			ereport(ERROR,
17599 					(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
17600 					 errmsg("cannot attach index \"%s\" as a partition of index \"%s\"",
17601 							RelationGetRelationName(partIdx),
17602 							RelationGetRelationName(parentIdx)),
17603 					 errdetail("Index \"%s\" is not an index on any partition of table \"%s\".",
17604 							   RelationGetRelationName(partIdx),
17605 							   RelationGetRelationName(parentTbl))));
17606 
17607 		/* Ensure the indexes are compatible */
17608 		childInfo = BuildIndexInfo(partIdx);
17609 		parentInfo = BuildIndexInfo(parentIdx);
17610 		attmap = build_attrmap_by_name(RelationGetDescr(partTbl),
17611 									   RelationGetDescr(parentTbl));
17612 		if (!CompareIndexInfo(childInfo, parentInfo,
17613 							  partIdx->rd_indcollation,
17614 							  parentIdx->rd_indcollation,
17615 							  partIdx->rd_opfamily,
17616 							  parentIdx->rd_opfamily,
17617 							  attmap))
17618 			ereport(ERROR,
17619 					(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
17620 					 errmsg("cannot attach index \"%s\" as a partition of index \"%s\"",
17621 							RelationGetRelationName(partIdx),
17622 							RelationGetRelationName(parentIdx)),
17623 					 errdetail("The index definitions do not match.")));
17624 
17625 		/*
17626 		 * If there is a constraint in the parent, make sure there is one in
17627 		 * the child too.
17628 		 */
17629 		constraintOid = get_relation_idx_constraint_oid(RelationGetRelid(parentTbl),
17630 														RelationGetRelid(parentIdx));
17631 
17632 		if (OidIsValid(constraintOid))
17633 		{
17634 			cldConstrId = get_relation_idx_constraint_oid(RelationGetRelid(partTbl),
17635 														  partIdxId);
17636 			if (!OidIsValid(cldConstrId))
17637 				ereport(ERROR,
17638 						(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
17639 						 errmsg("cannot attach index \"%s\" as a partition of index \"%s\"",
17640 								RelationGetRelationName(partIdx),
17641 								RelationGetRelationName(parentIdx)),
17642 						 errdetail("The index \"%s\" belongs to a constraint in table \"%s\" but no constraint exists for index \"%s\".",
17643 								   RelationGetRelationName(parentIdx),
17644 								   RelationGetRelationName(parentTbl),
17645 								   RelationGetRelationName(partIdx))));
17646 		}
17647 
17648 		/* All good -- do it */
17649 		IndexSetParentIndex(partIdx, RelationGetRelid(parentIdx));
17650 		if (OidIsValid(constraintOid))
17651 			ConstraintSetParentConstraint(cldConstrId, constraintOid,
17652 										  RelationGetRelid(partTbl));
17653 
17654 		free_attrmap(attmap);
17655 
17656 		validatePartitionedIndex(parentIdx, parentTbl);
17657 	}
17658 
17659 	relation_close(parentTbl, AccessShareLock);
17660 	/* keep these locks till commit */
17661 	relation_close(partTbl, NoLock);
17662 	relation_close(partIdx, NoLock);
17663 
17664 	return address;
17665 }
17666 
17667 /*
17668  * Verify whether the given partition already contains an index attached
17669  * to the given partitioned index.  If so, raise an error.
17670  */
17671 static void
refuseDupeIndexAttach(Relation parentIdx,Relation partIdx,Relation partitionTbl)17672 refuseDupeIndexAttach(Relation parentIdx, Relation partIdx, Relation partitionTbl)
17673 {
17674 	Oid			existingIdx;
17675 
17676 	existingIdx = index_get_partition(partitionTbl,
17677 									  RelationGetRelid(parentIdx));
17678 	if (OidIsValid(existingIdx))
17679 		ereport(ERROR,
17680 				(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
17681 				 errmsg("cannot attach index \"%s\" as a partition of index \"%s\"",
17682 						RelationGetRelationName(partIdx),
17683 						RelationGetRelationName(parentIdx)),
17684 				 errdetail("Another index is already attached for partition \"%s\".",
17685 						   RelationGetRelationName(partitionTbl))));
17686 }
17687 
17688 /*
17689  * Verify whether the set of attached partition indexes to a parent index on
17690  * a partitioned table is complete.  If it is, mark the parent index valid.
17691  *
17692  * This should be called each time a partition index is attached.
17693  */
17694 static void
validatePartitionedIndex(Relation partedIdx,Relation partedTbl)17695 validatePartitionedIndex(Relation partedIdx, Relation partedTbl)
17696 {
17697 	Relation	inheritsRel;
17698 	SysScanDesc scan;
17699 	ScanKeyData key;
17700 	int			tuples = 0;
17701 	HeapTuple	inhTup;
17702 	bool		updated = false;
17703 
17704 	Assert(partedIdx->rd_rel->relkind == RELKIND_PARTITIONED_INDEX);
17705 
17706 	/*
17707 	 * Scan pg_inherits for this parent index.  Count each valid index we find
17708 	 * (verifying the pg_index entry for each), and if we reach the total
17709 	 * amount we expect, we can mark this parent index as valid.
17710 	 */
17711 	inheritsRel = table_open(InheritsRelationId, AccessShareLock);
17712 	ScanKeyInit(&key, Anum_pg_inherits_inhparent,
17713 				BTEqualStrategyNumber, F_OIDEQ,
17714 				ObjectIdGetDatum(RelationGetRelid(partedIdx)));
17715 	scan = systable_beginscan(inheritsRel, InheritsParentIndexId, true,
17716 							  NULL, 1, &key);
17717 	while ((inhTup = systable_getnext(scan)) != NULL)
17718 	{
17719 		Form_pg_inherits inhForm = (Form_pg_inherits) GETSTRUCT(inhTup);
17720 		HeapTuple	indTup;
17721 		Form_pg_index indexForm;
17722 
17723 		indTup = SearchSysCache1(INDEXRELID,
17724 								 ObjectIdGetDatum(inhForm->inhrelid));
17725 		if (!HeapTupleIsValid(indTup))
17726 			elog(ERROR, "cache lookup failed for index %u", inhForm->inhrelid);
17727 		indexForm = (Form_pg_index) GETSTRUCT(indTup);
17728 		if (indexForm->indisvalid)
17729 			tuples += 1;
17730 		ReleaseSysCache(indTup);
17731 	}
17732 
17733 	/* Done with pg_inherits */
17734 	systable_endscan(scan);
17735 	table_close(inheritsRel, AccessShareLock);
17736 
17737 	/*
17738 	 * If we found as many inherited indexes as the partitioned table has
17739 	 * partitions, we're good; update pg_index to set indisvalid.
17740 	 */
17741 	if (tuples == RelationGetPartitionDesc(partedTbl)->nparts)
17742 	{
17743 		Relation	idxRel;
17744 		HeapTuple	newtup;
17745 
17746 		idxRel = table_open(IndexRelationId, RowExclusiveLock);
17747 
17748 		newtup = heap_copytuple(partedIdx->rd_indextuple);
17749 		((Form_pg_index) GETSTRUCT(newtup))->indisvalid = true;
17750 		updated = true;
17751 
17752 		CatalogTupleUpdate(idxRel, &partedIdx->rd_indextuple->t_self, newtup);
17753 
17754 		table_close(idxRel, RowExclusiveLock);
17755 	}
17756 
17757 	/*
17758 	 * If this index is in turn a partition of a larger index, validating it
17759 	 * might cause the parent to become valid also.  Try that.
17760 	 */
17761 	if (updated && partedIdx->rd_rel->relispartition)
17762 	{
17763 		Oid			parentIdxId,
17764 					parentTblId;
17765 		Relation	parentIdx,
17766 					parentTbl;
17767 
17768 		/* make sure we see the validation we just did */
17769 		CommandCounterIncrement();
17770 
17771 		parentIdxId = get_partition_parent(RelationGetRelid(partedIdx));
17772 		parentTblId = get_partition_parent(RelationGetRelid(partedTbl));
17773 		parentIdx = relation_open(parentIdxId, AccessExclusiveLock);
17774 		parentTbl = relation_open(parentTblId, AccessExclusiveLock);
17775 		Assert(!parentIdx->rd_index->indisvalid);
17776 
17777 		validatePartitionedIndex(parentIdx, parentTbl);
17778 
17779 		relation_close(parentIdx, AccessExclusiveLock);
17780 		relation_close(parentTbl, AccessExclusiveLock);
17781 	}
17782 }
17783 
17784 /*
17785  * Return an OID list of constraints that reference the given relation
17786  * that are marked as having a parent constraints.
17787  */
17788 static List *
GetParentedForeignKeyRefs(Relation partition)17789 GetParentedForeignKeyRefs(Relation partition)
17790 {
17791 	Relation	pg_constraint;
17792 	HeapTuple	tuple;
17793 	SysScanDesc scan;
17794 	ScanKeyData key[2];
17795 	List	   *constraints = NIL;
17796 
17797 	/*
17798 	 * If no indexes, or no columns are referenceable by FKs, we can avoid the
17799 	 * scan.
17800 	 */
17801 	if (RelationGetIndexList(partition) == NIL ||
17802 		bms_is_empty(RelationGetIndexAttrBitmap(partition,
17803 												INDEX_ATTR_BITMAP_KEY)))
17804 		return NIL;
17805 
17806 	/* Search for constraints referencing this table */
17807 	pg_constraint = table_open(ConstraintRelationId, AccessShareLock);
17808 	ScanKeyInit(&key[0],
17809 				Anum_pg_constraint_confrelid, BTEqualStrategyNumber,
17810 				F_OIDEQ, ObjectIdGetDatum(RelationGetRelid(partition)));
17811 	ScanKeyInit(&key[1],
17812 				Anum_pg_constraint_contype, BTEqualStrategyNumber,
17813 				F_CHAREQ, CharGetDatum(CONSTRAINT_FOREIGN));
17814 
17815 	/* XXX This is a seqscan, as we don't have a usable index */
17816 	scan = systable_beginscan(pg_constraint, InvalidOid, true, NULL, 2, key);
17817 	while ((tuple = systable_getnext(scan)) != NULL)
17818 	{
17819 		Form_pg_constraint constrForm = (Form_pg_constraint) GETSTRUCT(tuple);
17820 
17821 		/*
17822 		 * We only need to process constraints that are part of larger ones.
17823 		 */
17824 		if (!OidIsValid(constrForm->conparentid))
17825 			continue;
17826 
17827 		constraints = lappend_oid(constraints, constrForm->oid);
17828 	}
17829 
17830 	systable_endscan(scan);
17831 	table_close(pg_constraint, AccessShareLock);
17832 
17833 	return constraints;
17834 }
17835 
17836 /*
17837  * During DETACH PARTITION, verify that any foreign keys pointing to the
17838  * partitioned table would not become invalid.  An error is raised if any
17839  * referenced values exist.
17840  */
17841 static void
ATDetachCheckNoForeignKeyRefs(Relation partition)17842 ATDetachCheckNoForeignKeyRefs(Relation partition)
17843 {
17844 	List	   *constraints;
17845 	ListCell   *cell;
17846 
17847 	constraints = GetParentedForeignKeyRefs(partition);
17848 
17849 	foreach(cell, constraints)
17850 	{
17851 		Oid			constrOid = lfirst_oid(cell);
17852 		HeapTuple	tuple;
17853 		Form_pg_constraint constrForm;
17854 		Relation	rel;
17855 		Trigger		trig;
17856 
17857 		tuple = SearchSysCache1(CONSTROID, ObjectIdGetDatum(constrOid));
17858 		if (!HeapTupleIsValid(tuple))
17859 			elog(ERROR, "cache lookup failed for constraint %u", constrOid);
17860 		constrForm = (Form_pg_constraint) GETSTRUCT(tuple);
17861 
17862 		Assert(OidIsValid(constrForm->conparentid));
17863 		Assert(constrForm->confrelid == RelationGetRelid(partition));
17864 
17865 		/* prevent data changes into the referencing table until commit */
17866 		rel = table_open(constrForm->conrelid, ShareLock);
17867 
17868 		MemSet(&trig, 0, sizeof(trig));
17869 		trig.tgoid = InvalidOid;
17870 		trig.tgname = NameStr(constrForm->conname);
17871 		trig.tgenabled = TRIGGER_FIRES_ON_ORIGIN;
17872 		trig.tgisinternal = true;
17873 		trig.tgconstrrelid = RelationGetRelid(partition);
17874 		trig.tgconstrindid = constrForm->conindid;
17875 		trig.tgconstraint = constrForm->oid;
17876 		trig.tgdeferrable = false;
17877 		trig.tginitdeferred = false;
17878 		/* we needn't fill in remaining fields */
17879 
17880 		RI_PartitionRemove_Check(&trig, rel, partition);
17881 
17882 		ReleaseSysCache(tuple);
17883 
17884 		table_close(rel, NoLock);
17885 	}
17886 }
17887