Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * tablecmds.c
4 : * Commands for creating and altering table structures and settings
5 : *
6 : * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group
7 : * Portions Copyright (c) 1994, Regents of the University of California
8 : *
9 : *
10 : * IDENTIFICATION
11 : * src/backend/commands/tablecmds.c
12 : *
13 : *-------------------------------------------------------------------------
14 : */
15 : #include "postgres.h"
16 :
17 : #include "access/attmap.h"
18 : #include "access/genam.h"
19 : #include "access/heapam.h"
20 : #include "access/heapam_xlog.h"
21 : #include "access/multixact.h"
22 : #include "access/reloptions.h"
23 : #include "access/relscan.h"
24 : #include "access/sysattr.h"
25 : #include "access/tableam.h"
26 : #include "access/toast_compression.h"
27 : #include "access/xact.h"
28 : #include "access/xlog.h"
29 : #include "access/xloginsert.h"
30 : #include "catalog/catalog.h"
31 : #include "catalog/heap.h"
32 : #include "catalog/index.h"
33 : #include "catalog/namespace.h"
34 : #include "catalog/objectaccess.h"
35 : #include "catalog/partition.h"
36 : #include "catalog/pg_am.h"
37 : #include "catalog/pg_attrdef.h"
38 : #include "catalog/pg_collation.h"
39 : #include "catalog/pg_constraint.h"
40 : #include "catalog/pg_depend.h"
41 : #include "catalog/pg_foreign_table.h"
42 : #include "catalog/pg_inherits.h"
43 : #include "catalog/pg_largeobject.h"
44 : #include "catalog/pg_namespace.h"
45 : #include "catalog/pg_opclass.h"
46 : #include "catalog/pg_statistic_ext.h"
47 : #include "catalog/pg_tablespace.h"
48 : #include "catalog/pg_trigger.h"
49 : #include "catalog/pg_type.h"
50 : #include "catalog/storage.h"
51 : #include "catalog/storage_xlog.h"
52 : #include "catalog/toasting.h"
53 : #include "commands/cluster.h"
54 : #include "commands/comment.h"
55 : #include "commands/defrem.h"
56 : #include "commands/event_trigger.h"
57 : #include "commands/policy.h"
58 : #include "commands/sequence.h"
59 : #include "commands/tablecmds.h"
60 : #include "commands/tablespace.h"
61 : #include "commands/trigger.h"
62 : #include "commands/typecmds.h"
63 : #include "commands/user.h"
64 : #include "executor/executor.h"
65 : #include "foreign/fdwapi.h"
66 : #include "foreign/foreign.h"
67 : #include "miscadmin.h"
68 : #include "nodes/makefuncs.h"
69 : #include "nodes/nodeFuncs.h"
70 : #include "nodes/parsenodes.h"
71 : #include "optimizer/optimizer.h"
72 : #include "parser/parse_clause.h"
73 : #include "parser/parse_coerce.h"
74 : #include "parser/parse_collate.h"
75 : #include "parser/parse_expr.h"
76 : #include "parser/parse_oper.h"
77 : #include "parser/parse_relation.h"
78 : #include "parser/parse_type.h"
79 : #include "parser/parse_utilcmd.h"
80 : #include "parser/parser.h"
81 : #include "partitioning/partbounds.h"
82 : #include "partitioning/partdesc.h"
83 : #include "pgstat.h"
84 : #include "rewrite/rewriteDefine.h"
85 : #include "rewrite/rewriteHandler.h"
86 : #include "rewrite/rewriteManip.h"
87 : #include "storage/bufmgr.h"
88 : #include "storage/lmgr.h"
89 : #include "storage/lock.h"
90 : #include "storage/predicate.h"
91 : #include "storage/smgr.h"
92 : #include "tcop/utility.h"
93 : #include "utils/acl.h"
94 : #include "utils/builtins.h"
95 : #include "utils/fmgroids.h"
96 : #include "utils/inval.h"
97 : #include "utils/lsyscache.h"
98 : #include "utils/memutils.h"
99 : #include "utils/partcache.h"
100 : #include "utils/relcache.h"
101 : #include "utils/ruleutils.h"
102 : #include "utils/snapmgr.h"
103 : #include "utils/syscache.h"
104 : #include "utils/timestamp.h"
105 : #include "utils/typcache.h"
106 : #include "utils/usercontext.h"
107 :
108 : /*
109 : * ON COMMIT action list
110 : */
111 : typedef struct OnCommitItem
112 : {
113 : Oid relid; /* relid of relation */
114 : OnCommitAction oncommit; /* what to do at end of xact */
115 :
116 : /*
117 : * If this entry was created during the current transaction,
118 : * creating_subid is the ID of the creating subxact; if created in a prior
119 : * transaction, creating_subid is zero. If deleted during the current
120 : * transaction, deleting_subid is the ID of the deleting subxact; if no
121 : * deletion request is pending, deleting_subid is zero.
122 : */
123 : SubTransactionId creating_subid;
124 : SubTransactionId deleting_subid;
125 : } OnCommitItem;
126 :
127 : static List *on_commits = NIL;
128 :
129 :
130 : /*
131 : * State information for ALTER TABLE
132 : *
133 : * The pending-work queue for an ALTER TABLE is a List of AlteredTableInfo
134 : * structs, one for each table modified by the operation (the named table
135 : * plus any child tables that are affected). We save lists of subcommands
136 : * to apply to this table (possibly modified by parse transformation steps);
137 : * these lists will be executed in Phase 2. If a Phase 3 step is needed,
138 : * necessary information is stored in the constraints and newvals lists.
139 : *
140 : * Phase 2 is divided into multiple passes; subcommands are executed in
141 : * a pass determined by subcommand type.
142 : */
143 :
144 : #define AT_PASS_UNSET -1 /* UNSET will cause ERROR */
145 : #define AT_PASS_DROP 0 /* DROP (all flavors) */
146 : #define AT_PASS_ALTER_TYPE 1 /* ALTER COLUMN TYPE */
147 : #define AT_PASS_OLD_INDEX 2 /* re-add existing indexes */
148 : #define AT_PASS_OLD_CONSTR 3 /* re-add existing constraints */
149 : /* We could support a RENAME COLUMN pass here, but not currently used */
150 : #define AT_PASS_ADD_COL 4 /* ADD COLUMN */
151 : #define AT_PASS_ADD_CONSTR 5 /* ADD constraints (initial examination) */
152 : #define AT_PASS_COL_ATTRS 6 /* set column attributes, eg NOT NULL */
153 : #define AT_PASS_ADD_INDEXCONSTR 7 /* ADD index-based constraints */
154 : #define AT_PASS_ADD_INDEX 8 /* ADD indexes */
155 : #define AT_PASS_ADD_OTHERCONSTR 9 /* ADD other constraints, defaults */
156 : #define AT_PASS_MISC 10 /* other stuff */
157 : #define AT_NUM_PASSES 11
158 :
159 : typedef struct AlteredTableInfo
160 : {
161 : /* Information saved before any work commences: */
162 : Oid relid; /* Relation to work on */
163 : char relkind; /* Its relkind */
164 : TupleDesc oldDesc; /* Pre-modification tuple descriptor */
165 :
166 : /*
167 : * Transiently set during Phase 2, normally set to NULL.
168 : *
169 : * ATRewriteCatalogs sets this when it starts, and closes when ATExecCmd
170 : * returns control. This can be exploited by ATExecCmd subroutines to
171 : * close/reopen across transaction boundaries.
172 : */
173 : Relation rel;
174 :
175 : /* Information saved by Phase 1 for Phase 2: */
176 : List *subcmds[AT_NUM_PASSES]; /* Lists of AlterTableCmd */
177 : /* Information saved by Phases 1/2 for Phase 3: */
178 : List *constraints; /* List of NewConstraint */
179 : List *newvals; /* List of NewColumnValue */
180 : List *afterStmts; /* List of utility command parsetrees */
181 : bool verify_new_notnull; /* T if we should recheck NOT NULL */
182 : int rewrite; /* Reason for forced rewrite, if any */
183 : Oid newAccessMethod; /* new access method; 0 means no change */
184 : Oid newTableSpace; /* new tablespace; 0 means no change */
185 : bool chgPersistence; /* T if SET LOGGED/UNLOGGED is used */
186 : char newrelpersistence; /* if above is true */
187 : Expr *partition_constraint; /* for attach partition validation */
188 : /* true, if validating default due to some other attach/detach */
189 : bool validate_default;
190 : /* Objects to rebuild after completing ALTER TYPE operations */
191 : List *changedConstraintOids; /* OIDs of constraints to rebuild */
192 : List *changedConstraintDefs; /* string definitions of same */
193 : List *changedIndexOids; /* OIDs of indexes to rebuild */
194 : List *changedIndexDefs; /* string definitions of same */
195 : char *replicaIdentityIndex; /* index to reset as REPLICA IDENTITY */
196 : char *clusterOnIndex; /* index to use for CLUSTER */
197 : List *changedStatisticsOids; /* OIDs of statistics to rebuild */
198 : List *changedStatisticsDefs; /* string definitions of same */
199 : } AlteredTableInfo;
200 :
201 : /* Struct describing one new constraint to check in Phase 3 scan */
202 : /* Note: new NOT NULL constraints are handled elsewhere */
203 : typedef struct NewConstraint
204 : {
205 : char *name; /* Constraint name, or NULL if none */
206 : ConstrType contype; /* CHECK or FOREIGN */
207 : Oid refrelid; /* PK rel, if FOREIGN */
208 : Oid refindid; /* OID of PK's index, if FOREIGN */
209 : Oid conid; /* OID of pg_constraint entry, if FOREIGN */
210 : Node *qual; /* Check expr or CONSTR_FOREIGN Constraint */
211 : ExprState *qualstate; /* Execution state for CHECK expr */
212 : } NewConstraint;
213 :
214 : /*
215 : * Struct describing one new column value that needs to be computed during
216 : * Phase 3 copy (this could be either a new column with a non-null default, or
217 : * a column that we're changing the type of). Columns without such an entry
218 : * are just copied from the old table during ATRewriteTable. Note that the
219 : * expr is an expression over *old* table values, except when is_generated
220 : * is true; then it is an expression over columns of the *new* tuple.
221 : */
222 : typedef struct NewColumnValue
223 : {
224 : AttrNumber attnum; /* which column */
225 : Expr *expr; /* expression to compute */
226 : ExprState *exprstate; /* execution state */
227 : bool is_generated; /* is it a GENERATED expression? */
228 : } NewColumnValue;
229 :
230 : /*
231 : * Error-reporting support for RemoveRelations
232 : */
233 : struct dropmsgstrings
234 : {
235 : char kind;
236 : int nonexistent_code;
237 : const char *nonexistent_msg;
238 : const char *skipping_msg;
239 : const char *nota_msg;
240 : const char *drophint_msg;
241 : };
242 :
243 : static const struct dropmsgstrings dropmsgstringarray[] = {
244 : {RELKIND_RELATION,
245 : ERRCODE_UNDEFINED_TABLE,
246 : gettext_noop("table \"%s\" does not exist"),
247 : gettext_noop("table \"%s\" does not exist, skipping"),
248 : gettext_noop("\"%s\" is not a table"),
249 : gettext_noop("Use DROP TABLE to remove a table.")},
250 : {RELKIND_SEQUENCE,
251 : ERRCODE_UNDEFINED_TABLE,
252 : gettext_noop("sequence \"%s\" does not exist"),
253 : gettext_noop("sequence \"%s\" does not exist, skipping"),
254 : gettext_noop("\"%s\" is not a sequence"),
255 : gettext_noop("Use DROP SEQUENCE to remove a sequence.")},
256 : {RELKIND_VIEW,
257 : ERRCODE_UNDEFINED_TABLE,
258 : gettext_noop("view \"%s\" does not exist"),
259 : gettext_noop("view \"%s\" does not exist, skipping"),
260 : gettext_noop("\"%s\" is not a view"),
261 : gettext_noop("Use DROP VIEW to remove a view.")},
262 : {RELKIND_MATVIEW,
263 : ERRCODE_UNDEFINED_TABLE,
264 : gettext_noop("materialized view \"%s\" does not exist"),
265 : gettext_noop("materialized view \"%s\" does not exist, skipping"),
266 : gettext_noop("\"%s\" is not a materialized view"),
267 : gettext_noop("Use DROP MATERIALIZED VIEW to remove a materialized view.")},
268 : {RELKIND_INDEX,
269 : ERRCODE_UNDEFINED_OBJECT,
270 : gettext_noop("index \"%s\" does not exist"),
271 : gettext_noop("index \"%s\" does not exist, skipping"),
272 : gettext_noop("\"%s\" is not an index"),
273 : gettext_noop("Use DROP INDEX to remove an index.")},
274 : {RELKIND_COMPOSITE_TYPE,
275 : ERRCODE_UNDEFINED_OBJECT,
276 : gettext_noop("type \"%s\" does not exist"),
277 : gettext_noop("type \"%s\" does not exist, skipping"),
278 : gettext_noop("\"%s\" is not a type"),
279 : gettext_noop("Use DROP TYPE to remove a type.")},
280 : {RELKIND_FOREIGN_TABLE,
281 : ERRCODE_UNDEFINED_OBJECT,
282 : gettext_noop("foreign table \"%s\" does not exist"),
283 : gettext_noop("foreign table \"%s\" does not exist, skipping"),
284 : gettext_noop("\"%s\" is not a foreign table"),
285 : gettext_noop("Use DROP FOREIGN TABLE to remove a foreign table.")},
286 : {RELKIND_PARTITIONED_TABLE,
287 : ERRCODE_UNDEFINED_TABLE,
288 : gettext_noop("table \"%s\" does not exist"),
289 : gettext_noop("table \"%s\" does not exist, skipping"),
290 : gettext_noop("\"%s\" is not a table"),
291 : gettext_noop("Use DROP TABLE to remove a table.")},
292 : {RELKIND_PARTITIONED_INDEX,
293 : ERRCODE_UNDEFINED_OBJECT,
294 : gettext_noop("index \"%s\" does not exist"),
295 : gettext_noop("index \"%s\" does not exist, skipping"),
296 : gettext_noop("\"%s\" is not an index"),
297 : gettext_noop("Use DROP INDEX to remove an index.")},
298 : {'\0', 0, NULL, NULL, NULL, NULL}
299 : };
300 :
301 : /* communication between RemoveRelations and RangeVarCallbackForDropRelation */
302 : struct DropRelationCallbackState
303 : {
304 : /* These fields are set by RemoveRelations: */
305 : char expected_relkind;
306 : LOCKMODE heap_lockmode;
307 : /* These fields are state to track which subsidiary locks are held: */
308 : Oid heapOid;
309 : Oid partParentOid;
310 : /* These fields are passed back by RangeVarCallbackForDropRelation: */
311 : char actual_relkind;
312 : char actual_relpersistence;
313 : };
314 :
315 : /* Alter table target-type flags for ATSimplePermissions */
316 : #define ATT_TABLE 0x0001
317 : #define ATT_VIEW 0x0002
318 : #define ATT_MATVIEW 0x0004
319 : #define ATT_INDEX 0x0008
320 : #define ATT_COMPOSITE_TYPE 0x0010
321 : #define ATT_FOREIGN_TABLE 0x0020
322 : #define ATT_PARTITIONED_INDEX 0x0040
323 : #define ATT_SEQUENCE 0x0080
324 :
325 : /*
326 : * ForeignTruncateInfo
327 : *
328 : * Information related to truncation of foreign tables. This is used for
329 : * the elements in a hash table. It uses the server OID as lookup key,
330 : * and includes a per-server list of all foreign tables involved in the
331 : * truncation.
332 : */
333 : typedef struct ForeignTruncateInfo
334 : {
335 : Oid serverid;
336 : List *rels;
337 : } ForeignTruncateInfo;
338 :
339 : /*
340 : * Partition tables are expected to be dropped when the parent partitioned
341 : * table gets dropped. Hence for partitioning we use AUTO dependency.
342 : * Otherwise, for regular inheritance use NORMAL dependency.
343 : */
344 : #define child_dependency_type(child_is_partition) \
345 : ((child_is_partition) ? DEPENDENCY_AUTO : DEPENDENCY_NORMAL)
346 :
347 : static void truncate_check_rel(Oid relid, Form_pg_class reltuple);
348 : static void truncate_check_perms(Oid relid, Form_pg_class reltuple);
349 : static void truncate_check_activity(Relation rel);
350 : static void RangeVarCallbackForTruncate(const RangeVar *relation,
351 : Oid relId, Oid oldRelId, void *arg);
352 : static List *MergeAttributes(List *schema, List *supers, char relpersistence,
353 : bool is_partition, List **supconstr);
354 : static bool MergeCheckConstraint(List *constraints, char *name, Node *expr);
355 : static void MergeAttributesIntoExisting(Relation child_rel, Relation parent_rel);
356 : static void MergeConstraintsIntoExisting(Relation child_rel, Relation parent_rel);
357 : static void StoreCatalogInheritance(Oid relationId, List *supers,
358 : bool child_is_partition);
359 : static void StoreCatalogInheritance1(Oid relationId, Oid parentOid,
360 : int32 seqNumber, Relation inhRelation,
361 : bool child_is_partition);
362 : static int findAttrByName(const char *attributeName, List *schema);
363 : static void AlterIndexNamespaces(Relation classRel, Relation rel,
364 : Oid oldNspOid, Oid newNspOid, ObjectAddresses *objsMoved);
365 : static void AlterSeqNamespaces(Relation classRel, Relation rel,
366 : Oid oldNspOid, Oid newNspOid, ObjectAddresses *objsMoved,
367 : LOCKMODE lockmode);
368 : static ObjectAddress ATExecAlterConstraint(Relation rel, AlterTableCmd *cmd,
369 : bool recurse, bool recursing, LOCKMODE lockmode);
370 : static bool ATExecAlterConstrRecurse(Constraint *cmdcon, Relation conrel, Relation tgrel,
371 : Relation rel, HeapTuple contuple, List **otherrelids,
372 : LOCKMODE lockmode);
373 : static ObjectAddress ATExecValidateConstraint(List **wqueue,
374 : Relation rel, char *constrName,
375 : bool recurse, bool recursing, LOCKMODE lockmode);
376 : static int transformColumnNameList(Oid relId, List *colList,
377 : int16 *attnums, Oid *atttypids);
378 : static int transformFkeyGetPrimaryKey(Relation pkrel, Oid *indexOid,
379 : List **attnamelist,
380 : int16 *attnums, Oid *atttypids,
381 : Oid *opclasses);
382 : static Oid transformFkeyCheckAttrs(Relation pkrel,
383 : int numattrs, int16 *attnums,
384 : Oid *opclasses);
385 : static void checkFkeyPermissions(Relation rel, int16 *attnums, int natts);
386 : static CoercionPathType findFkeyCast(Oid targetTypeId, Oid sourceTypeId,
387 : Oid *funcid);
388 : static void validateForeignKeyConstraint(char *conname,
389 : Relation rel, Relation pkrel,
390 : Oid pkindOid, Oid constraintOid);
391 : static void ATController(AlterTableStmt *parsetree,
392 : Relation rel, List *cmds, bool recurse, LOCKMODE lockmode,
393 : AlterTableUtilityContext *context);
394 : static void ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd,
395 : bool recurse, bool recursing, LOCKMODE lockmode,
396 : AlterTableUtilityContext *context);
397 : static void ATRewriteCatalogs(List **wqueue, LOCKMODE lockmode,
398 : AlterTableUtilityContext *context);
399 : static void ATExecCmd(List **wqueue, AlteredTableInfo *tab,
400 : AlterTableCmd *cmd, LOCKMODE lockmode, int cur_pass,
401 : AlterTableUtilityContext *context);
402 : static AlterTableCmd *ATParseTransformCmd(List **wqueue, AlteredTableInfo *tab,
403 : Relation rel, AlterTableCmd *cmd,
404 : bool recurse, LOCKMODE lockmode,
405 : int cur_pass,
406 : AlterTableUtilityContext *context);
407 : static void ATRewriteTables(AlterTableStmt *parsetree,
408 : List **wqueue, LOCKMODE lockmode,
409 : AlterTableUtilityContext *context);
410 : static void ATRewriteTable(AlteredTableInfo *tab, Oid OIDNewHeap, LOCKMODE lockmode);
411 : static AlteredTableInfo *ATGetQueueEntry(List **wqueue, Relation rel);
412 : static void ATSimplePermissions(AlterTableType cmdtype, Relation rel, int allowed_targets);
413 : static void ATSimpleRecursion(List **wqueue, Relation rel,
414 : AlterTableCmd *cmd, bool recurse, LOCKMODE lockmode,
415 : AlterTableUtilityContext *context);
416 : static void ATCheckPartitionsNotInUse(Relation rel, LOCKMODE lockmode);
417 : static void ATTypedTableRecursion(List **wqueue, Relation rel, AlterTableCmd *cmd,
418 : LOCKMODE lockmode,
419 : AlterTableUtilityContext *context);
420 : static List *find_typed_table_dependencies(Oid typeOid, const char *typeName,
421 : DropBehavior behavior);
422 : static void ATPrepAddColumn(List **wqueue, Relation rel, bool recurse, bool recursing,
423 : bool is_view, AlterTableCmd *cmd, LOCKMODE lockmode,
424 : AlterTableUtilityContext *context);
425 : static ObjectAddress ATExecAddColumn(List **wqueue, AlteredTableInfo *tab,
426 : Relation rel, AlterTableCmd **cmd,
427 : bool recurse, bool recursing,
428 : LOCKMODE lockmode, int cur_pass,
429 : AlterTableUtilityContext *context);
430 : static bool check_for_column_name_collision(Relation rel, const char *colname,
431 : bool if_not_exists);
432 : static void add_column_datatype_dependency(Oid relid, int32 attnum, Oid typid);
433 : static void add_column_collation_dependency(Oid relid, int32 attnum, Oid collid);
434 : static void ATPrepDropNotNull(Relation rel, bool recurse, bool recursing);
435 : static ObjectAddress ATExecDropNotNull(Relation rel, const char *colName, LOCKMODE lockmode);
436 : static void ATPrepSetNotNull(List **wqueue, Relation rel,
437 : AlterTableCmd *cmd, bool recurse, bool recursing,
438 : LOCKMODE lockmode,
439 : AlterTableUtilityContext *context);
440 : static ObjectAddress ATExecSetNotNull(AlteredTableInfo *tab, Relation rel,
441 : const char *colName, LOCKMODE lockmode);
442 : static void ATExecCheckNotNull(AlteredTableInfo *tab, Relation rel,
443 : const char *colName, LOCKMODE lockmode);
444 : static bool NotNullImpliedByRelConstraints(Relation rel, Form_pg_attribute attr);
445 : static bool ConstraintImpliedByRelConstraint(Relation scanrel,
446 : List *testConstraint, List *provenConstraint);
447 : static ObjectAddress ATExecColumnDefault(Relation rel, const char *colName,
448 : Node *newDefault, LOCKMODE lockmode);
449 : static ObjectAddress ATExecCookedColumnDefault(Relation rel, AttrNumber attnum,
450 : Node *newDefault);
451 : static ObjectAddress ATExecAddIdentity(Relation rel, const char *colName,
452 : Node *def, LOCKMODE lockmode);
453 : static ObjectAddress ATExecSetIdentity(Relation rel, const char *colName,
454 : Node *def, LOCKMODE lockmode);
455 : static ObjectAddress ATExecDropIdentity(Relation rel, const char *colName, bool missing_ok, LOCKMODE lockmode);
456 : static void ATPrepDropExpression(Relation rel, AlterTableCmd *cmd, bool recurse, bool recursing, LOCKMODE lockmode);
457 : static ObjectAddress ATExecDropExpression(Relation rel, const char *colName, bool missing_ok, LOCKMODE lockmode);
458 : static ObjectAddress ATExecSetStatistics(Relation rel, const char *colName, int16 colNum,
459 : Node *newValue, LOCKMODE lockmode);
460 : static ObjectAddress ATExecSetOptions(Relation rel, const char *colName,
461 : Node *options, bool isReset, LOCKMODE lockmode);
462 : static ObjectAddress ATExecSetStorage(Relation rel, const char *colName,
463 : Node *newValue, LOCKMODE lockmode);
464 : static void ATPrepDropColumn(List **wqueue, Relation rel, bool recurse, bool recursing,
465 : AlterTableCmd *cmd, LOCKMODE lockmode,
466 : AlterTableUtilityContext *context);
467 : static ObjectAddress ATExecDropColumn(List **wqueue, Relation rel, const char *colName,
468 : DropBehavior behavior,
469 : bool recurse, bool recursing,
470 : bool missing_ok, LOCKMODE lockmode,
471 : ObjectAddresses *addrs);
472 : static ObjectAddress ATExecAddIndex(AlteredTableInfo *tab, Relation rel,
473 : IndexStmt *stmt, bool is_rebuild, LOCKMODE lockmode);
474 : static ObjectAddress ATExecAddStatistics(AlteredTableInfo *tab, Relation rel,
475 : CreateStatsStmt *stmt, bool is_rebuild, LOCKMODE lockmode);
476 : static ObjectAddress ATExecAddConstraint(List **wqueue,
477 : AlteredTableInfo *tab, Relation rel,
478 : Constraint *newConstraint, bool recurse, bool is_readd,
479 : LOCKMODE lockmode);
480 : static char *ChooseForeignKeyConstraintNameAddition(List *colnames);
481 : static ObjectAddress ATExecAddIndexConstraint(AlteredTableInfo *tab, Relation rel,
482 : IndexStmt *stmt, LOCKMODE lockmode);
483 : static ObjectAddress ATAddCheckConstraint(List **wqueue,
484 : AlteredTableInfo *tab, Relation rel,
485 : Constraint *constr,
486 : bool recurse, bool recursing, bool is_readd,
487 : LOCKMODE lockmode);
488 : static ObjectAddress ATAddForeignKeyConstraint(List **wqueue, AlteredTableInfo *tab,
489 : Relation rel, Constraint *fkconstraint,
490 : bool recurse, bool recursing,
491 : LOCKMODE lockmode);
492 : static ObjectAddress addFkRecurseReferenced(List **wqueue, Constraint *fkconstraint,
493 : Relation rel, Relation pkrel, Oid indexOid, Oid parentConstr,
494 : int numfks, int16 *pkattnum, int16 *fkattnum,
495 : Oid *pfeqoperators, Oid *ppeqoperators, Oid *ffeqoperators,
496 : int numfkdelsetcols, int16 *fkdelsetcols,
497 : bool old_check_ok,
498 : Oid parentDelTrigger, Oid parentUpdTrigger);
499 : static void validateFkOnDeleteSetColumns(int numfks, const int16 *fkattnums,
500 : int numfksetcols, const int16 *fksetcolsattnums,
501 : List *fksetcols);
502 : static void addFkRecurseReferencing(List **wqueue, Constraint *fkconstraint,
503 : Relation rel, Relation pkrel, Oid indexOid, Oid parentConstr,
504 : int numfks, int16 *pkattnum, int16 *fkattnum,
505 : Oid *pfeqoperators, Oid *ppeqoperators, Oid *ffeqoperators,
506 : int numfkdelsetcols, int16 *fkdelsetcols,
507 : bool old_check_ok, LOCKMODE lockmode,
508 : Oid parentInsTrigger, Oid parentUpdTrigger);
509 : static void CloneForeignKeyConstraints(List **wqueue, Relation parentRel,
510 : Relation partitionRel);
511 : static void CloneFkReferenced(Relation parentRel, Relation partitionRel);
512 : static void CloneFkReferencing(List **wqueue, Relation parentRel,
513 : Relation partRel);
514 : static void createForeignKeyCheckTriggers(Oid myRelOid, Oid refRelOid,
515 : Constraint *fkconstraint, Oid constraintOid,
516 : Oid indexOid,
517 : Oid parentInsTrigger, Oid parentUpdTrigger,
518 : Oid *insertTrigOid, Oid *updateTrigOid);
519 : static void createForeignKeyActionTriggers(Relation rel, Oid refRelOid,
520 : Constraint *fkconstraint, Oid constraintOid,
521 : Oid indexOid,
522 : Oid parentDelTrigger, Oid parentUpdTrigger,
523 : Oid *deleteTrigOid, Oid *updateTrigOid);
524 : static bool tryAttachPartitionForeignKey(ForeignKeyCacheInfo *fk,
525 : Oid partRelid,
526 : Oid parentConstrOid, int numfks,
527 : AttrNumber *mapped_conkey, AttrNumber *confkey,
528 : Oid *conpfeqop,
529 : Oid parentInsTrigger,
530 : Oid parentUpdTrigger,
531 : Relation trigrel);
532 : static void GetForeignKeyActionTriggers(Relation trigrel,
533 : Oid conoid, Oid confrelid, Oid conrelid,
534 : Oid *deleteTriggerOid,
535 : Oid *updateTriggerOid);
536 : static void GetForeignKeyCheckTriggers(Relation trigrel,
537 : Oid conoid, Oid confrelid, Oid conrelid,
538 : Oid *insertTriggerOid,
539 : Oid *updateTriggerOid);
540 : static void ATExecDropConstraint(Relation rel, const char *constrName,
541 : DropBehavior behavior,
542 : bool recurse, bool recursing,
543 : bool missing_ok, LOCKMODE lockmode);
544 : static void ATPrepAlterColumnType(List **wqueue,
545 : AlteredTableInfo *tab, Relation rel,
546 : bool recurse, bool recursing,
547 : AlterTableCmd *cmd, LOCKMODE lockmode,
548 : AlterTableUtilityContext *context);
549 : static bool ATColumnChangeRequiresRewrite(Node *expr, AttrNumber varattno);
550 : static ObjectAddress ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel,
551 : AlterTableCmd *cmd, LOCKMODE lockmode);
552 : static void RememberConstraintForRebuilding(Oid conoid, AlteredTableInfo *tab);
553 : static void RememberIndexForRebuilding(Oid indoid, AlteredTableInfo *tab);
554 : static void RememberStatisticsForRebuilding(Oid stxoid, AlteredTableInfo *tab);
555 : static void ATPostAlterTypeCleanup(List **wqueue, AlteredTableInfo *tab,
556 : LOCKMODE lockmode);
557 : static void ATPostAlterTypeParse(Oid oldId, Oid oldRelId, Oid refRelId,
558 : char *cmd, List **wqueue, LOCKMODE lockmode,
559 : bool rewrite);
560 : static void RebuildConstraintComment(AlteredTableInfo *tab, int pass,
561 : Oid objid, Relation rel, List *domname,
562 : const char *conname);
563 : static void TryReuseIndex(Oid oldId, IndexStmt *stmt);
564 : static void TryReuseForeignKey(Oid oldId, Constraint *con);
565 : static ObjectAddress ATExecAlterColumnGenericOptions(Relation rel, const char *colName,
566 : List *options, LOCKMODE lockmode);
567 : static void change_owner_fix_column_acls(Oid relationOid,
568 : Oid oldOwnerId, Oid newOwnerId);
569 : static void change_owner_recurse_to_sequences(Oid relationOid,
570 : Oid newOwnerId, LOCKMODE lockmode);
571 : static ObjectAddress ATExecClusterOn(Relation rel, const char *indexName,
572 : LOCKMODE lockmode);
573 : static void ATExecDropCluster(Relation rel, LOCKMODE lockmode);
574 : static void ATPrepSetAccessMethod(AlteredTableInfo *tab, Relation rel, const char *amname);
575 : static bool ATPrepChangePersistence(Relation rel, bool toLogged);
576 : static void ATPrepSetTableSpace(AlteredTableInfo *tab, Relation rel,
577 : const char *tablespacename, LOCKMODE lockmode);
578 : static void ATExecSetTableSpace(Oid tableOid, Oid newTableSpace, LOCKMODE lockmode);
579 : static void ATExecSetTableSpaceNoStorage(Relation rel, Oid newTableSpace);
580 : static void ATExecSetRelOptions(Relation rel, List *defList,
581 : AlterTableType operation,
582 : LOCKMODE lockmode);
583 : static void ATExecEnableDisableTrigger(Relation rel, const char *trigname,
584 : char fires_when, bool skip_system, bool recurse,
585 : LOCKMODE lockmode);
586 : static void ATExecEnableDisableRule(Relation rel, const char *rulename,
587 : char fires_when, LOCKMODE lockmode);
588 : static void ATPrepAddInherit(Relation child_rel);
589 : static ObjectAddress ATExecAddInherit(Relation child_rel, RangeVar *parent, LOCKMODE lockmode);
590 : static ObjectAddress ATExecDropInherit(Relation rel, RangeVar *parent, LOCKMODE lockmode);
591 : static void drop_parent_dependency(Oid relid, Oid refclassid, Oid refobjid,
592 : DependencyType deptype);
593 : static ObjectAddress ATExecAddOf(Relation rel, const TypeName *ofTypename, LOCKMODE lockmode);
594 : static void ATExecDropOf(Relation rel, LOCKMODE lockmode);
595 : static void ATExecReplicaIdentity(Relation rel, ReplicaIdentityStmt *stmt, LOCKMODE lockmode);
596 : static void ATExecGenericOptions(Relation rel, List *options);
597 : static void ATExecSetRowSecurity(Relation rel, bool rls);
598 : static void ATExecForceNoForceRowSecurity(Relation rel, bool force_rls);
599 : static ObjectAddress ATExecSetCompression(Relation rel,
600 : const char *column, Node *newValue, LOCKMODE lockmode);
601 :
602 : static void index_copy_data(Relation rel, RelFileLocator newrlocator);
603 : static const char *storage_name(char c);
604 :
605 : static void RangeVarCallbackForDropRelation(const RangeVar *rel, Oid relOid,
606 : Oid oldRelOid, void *arg);
607 : static void RangeVarCallbackForAlterRelation(const RangeVar *rv, Oid relid,
608 : Oid oldrelid, void *arg);
609 : static PartitionSpec *transformPartitionSpec(Relation rel, PartitionSpec *partspec);
610 : static void ComputePartitionAttrs(ParseState *pstate, Relation rel, List *partParams, AttrNumber *partattrs,
611 : List **partexprs, Oid *partopclass, Oid *partcollation,
612 : PartitionStrategy strategy);
613 : static void CreateInheritance(Relation child_rel, Relation parent_rel);
614 : static void RemoveInheritance(Relation child_rel, Relation parent_rel,
615 : bool expect_detached);
616 : static ObjectAddress ATExecAttachPartition(List **wqueue, Relation rel,
617 : PartitionCmd *cmd,
618 : AlterTableUtilityContext *context);
619 : static void AttachPartitionEnsureIndexes(Relation rel, Relation attachrel);
620 : static void QueuePartitionConstraintValidation(List **wqueue, Relation scanrel,
621 : List *partConstraint,
622 : bool validate_default);
623 : static void CloneRowTriggersToPartition(Relation parent, Relation partition);
624 : static void DetachAddConstraintIfNeeded(List **wqueue, Relation partRel);
625 : static void DropClonedTriggersFromPartition(Oid partitionId);
626 : static ObjectAddress ATExecDetachPartition(List **wqueue, AlteredTableInfo *tab,
627 : Relation rel, RangeVar *name,
628 : bool concurrent);
629 : static void DetachPartitionFinalize(Relation rel, Relation partRel,
630 : bool concurrent, Oid defaultPartOid);
631 : static ObjectAddress ATExecDetachPartitionFinalize(Relation rel, RangeVar *name);
632 : static ObjectAddress ATExecAttachPartitionIdx(List **wqueue, Relation parentIdx,
633 : RangeVar *name);
634 : static void validatePartitionedIndex(Relation partedIdx, Relation partedTbl);
635 : static void refuseDupeIndexAttach(Relation parentIdx, Relation partIdx,
636 : Relation partitionTbl);
637 : static List *GetParentedForeignKeyRefs(Relation partition);
638 : static void ATDetachCheckNoForeignKeyRefs(Relation partition);
639 : static char GetAttributeCompression(Oid atttypid, char *compression);
640 : static char GetAttributeStorage(Oid atttypid, const char *storagemode);
641 :
642 :
643 : /* ----------------------------------------------------------------
644 : * DefineRelation
645 : * Creates a new relation.
646 : *
647 : * stmt carries parsetree information from an ordinary CREATE TABLE statement.
648 : * The other arguments are used to extend the behavior for other cases:
649 : * relkind: relkind to assign to the new relation
650 : * ownerId: if not InvalidOid, use this as the new relation's owner.
651 : * typaddress: if not null, it's set to the pg_type entry's address.
652 : * queryString: for error reporting
653 : *
654 : * Note that permissions checks are done against current user regardless of
655 : * ownerId. A nonzero ownerId is used when someone is creating a relation
656 : * "on behalf of" someone else, so we still want to see that the current user
657 : * has permissions to do it.
658 : *
659 : * If successful, returns the address of the new relation.
660 : * ----------------------------------------------------------------
661 : */
662 : ObjectAddress
663 125330 : DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId,
664 : ObjectAddress *typaddress, const char *queryString)
665 : {
666 : char relname[NAMEDATALEN];
667 : Oid namespaceId;
668 : Oid relationId;
669 : Oid tablespaceId;
670 : Relation rel;
671 : TupleDesc descriptor;
672 : List *inheritOids;
673 : List *old_constraints;
674 : List *rawDefaults;
675 : List *cookedDefaults;
676 : Datum reloptions;
677 : ListCell *listptr;
678 : AttrNumber attnum;
679 : bool partitioned;
680 : static char *validnsps[] = HEAP_RELOPT_NAMESPACES;
681 : Oid ofTypeId;
682 : ObjectAddress address;
683 : LOCKMODE parentLockmode;
684 125330 : const char *accessMethod = NULL;
685 125330 : Oid accessMethodId = InvalidOid;
686 :
687 : /*
688 : * Truncate relname to appropriate length (probably a waste of time, as
689 : * parser should have done this already).
690 : */
691 125330 : strlcpy(relname, stmt->relation->relname, NAMEDATALEN);
692 :
693 : /*
694 : * Check consistency of arguments
695 : */
696 125330 : if (stmt->oncommit != ONCOMMIT_NOOP
697 172 : && stmt->relation->relpersistence != RELPERSISTENCE_TEMP)
698 12 : ereport(ERROR,
699 : (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
700 : errmsg("ON COMMIT can only be used on temporary tables")));
701 :
702 125318 : if (stmt->partspec != NULL)
703 : {
704 4378 : if (relkind != RELKIND_RELATION)
705 0 : elog(ERROR, "unexpected relkind: %d", (int) relkind);
706 :
707 4378 : relkind = RELKIND_PARTITIONED_TABLE;
708 4378 : partitioned = true;
709 : }
710 : else
711 120940 : partitioned = false;
712 :
713 : /*
714 : * Look up the namespace in which we are supposed to create the relation,
715 : * check we have permission to create there, lock it against concurrent
716 : * drop, and mark stmt->relation as RELPERSISTENCE_TEMP if a temporary
717 : * namespace is selected.
718 : */
719 : namespaceId =
720 125318 : RangeVarGetAndCheckCreationNamespace(stmt->relation, NoLock, NULL);
721 :
722 : /*
723 : * Security check: disallow creating temp tables from security-restricted
724 : * code. This is needed because calling code might not expect untrusted
725 : * tables to appear in pg_temp at the front of its search path.
726 : */
727 125318 : if (stmt->relation->relpersistence == RELPERSISTENCE_TEMP
728 2876 : && InSecurityRestrictedOperation())
729 0 : ereport(ERROR,
730 : (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
731 : errmsg("cannot create temporary table within security-restricted operation")));
732 :
733 : /*
734 : * Determine the lockmode to use when scanning parents. A self-exclusive
735 : * lock is needed here.
736 : *
737 : * For regular inheritance, if two backends attempt to add children to the
738 : * same parent simultaneously, and that parent has no pre-existing
739 : * children, then both will attempt to update the parent's relhassubclass
740 : * field, leading to a "tuple concurrently updated" error. Also, this
741 : * interlocks against a concurrent ANALYZE on the parent table, which
742 : * might otherwise be attempting to clear the parent's relhassubclass
743 : * field, if its previous children were recently dropped.
744 : *
745 : * If the child table is a partition, then we instead grab an exclusive
746 : * lock on the parent because its partition descriptor will be changed by
747 : * addition of the new partition.
748 : */
749 125318 : parentLockmode = (stmt->partbound != NULL ? AccessExclusiveLock :
750 : ShareUpdateExclusiveLock);
751 :
752 : /* Determine the list of OIDs of the parents. */
753 125318 : inheritOids = NIL;
754 134232 : foreach(listptr, stmt->inhRelations)
755 : {
756 8914 : RangeVar *rv = (RangeVar *) lfirst(listptr);
757 : Oid parentOid;
758 :
759 8914 : parentOid = RangeVarGetRelid(rv, parentLockmode, false);
760 :
761 : /*
762 : * Reject duplications in the list of parents.
763 : */
764 8914 : if (list_member_oid(inheritOids, parentOid))
765 0 : ereport(ERROR,
766 : (errcode(ERRCODE_DUPLICATE_TABLE),
767 : errmsg("relation \"%s\" would be inherited from more than once",
768 : get_rel_name(parentOid))));
769 :
770 8914 : inheritOids = lappend_oid(inheritOids, parentOid);
771 : }
772 :
773 : /*
774 : * Select tablespace to use: an explicitly indicated one, or (in the case
775 : * of a partitioned table) the parent's, if it has one.
776 : */
777 125318 : if (stmt->tablespacename)
778 : {
779 104 : tablespaceId = get_tablespace_oid(stmt->tablespacename, false);
780 :
781 98 : if (partitioned && tablespaceId == MyDatabaseTableSpace)
782 6 : ereport(ERROR,
783 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
784 : errmsg("cannot specify default tablespace for partitioned relations")));
785 : }
786 125214 : else if (stmt->partbound)
787 : {
788 : /*
789 : * For partitions, when no other tablespace is specified, we default
790 : * the tablespace to the parent partitioned table's.
791 : */
792 : Assert(list_length(inheritOids) == 1);
793 7264 : tablespaceId = get_rel_tablespace(linitial_oid(inheritOids));
794 : }
795 : else
796 117950 : tablespaceId = InvalidOid;
797 :
798 : /* still nothing? use the default */
799 125306 : if (!OidIsValid(tablespaceId))
800 125192 : tablespaceId = GetDefaultTablespace(stmt->relation->relpersistence,
801 : partitioned);
802 :
803 : /* Check permissions except when using database's default */
804 125300 : if (OidIsValid(tablespaceId) && tablespaceId != MyDatabaseTableSpace)
805 : {
806 : AclResult aclresult;
807 :
808 132 : aclresult = object_aclcheck(TableSpaceRelationId, tablespaceId, GetUserId(),
809 : ACL_CREATE);
810 132 : if (aclresult != ACLCHECK_OK)
811 6 : aclcheck_error(aclresult, OBJECT_TABLESPACE,
812 6 : get_tablespace_name(tablespaceId));
813 : }
814 :
815 : /* In all cases disallow placing user relations in pg_global */
816 125294 : if (tablespaceId == GLOBALTABLESPACE_OID)
817 18 : ereport(ERROR,
818 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
819 : errmsg("only shared relations can be placed in pg_global tablespace")));
820 :
821 : /* Identify user ID that will own the table */
822 125276 : if (!OidIsValid(ownerId))
823 125112 : ownerId = GetUserId();
824 :
825 : /*
826 : * Parse and validate reloptions, if any.
827 : */
828 125276 : reloptions = transformRelOptions((Datum) 0, stmt->options, NULL, validnsps,
829 : true, false);
830 :
831 125258 : switch (relkind)
832 : {
833 87298 : case RELKIND_VIEW:
834 87298 : (void) view_reloptions(reloptions, true);
835 87280 : break;
836 4360 : case RELKIND_PARTITIONED_TABLE:
837 4360 : (void) partitioned_table_reloptions(reloptions, true);
838 4354 : break;
839 33600 : default:
840 33600 : (void) heap_reloptions(relkind, reloptions, true);
841 : }
842 :
843 125138 : if (stmt->ofTypename)
844 : {
845 : AclResult aclresult;
846 :
847 86 : ofTypeId = typenameTypeId(NULL, stmt->ofTypename);
848 :
849 86 : aclresult = object_aclcheck(TypeRelationId, ofTypeId, GetUserId(), ACL_USAGE);
850 86 : if (aclresult != ACLCHECK_OK)
851 6 : aclcheck_error_type(aclresult, ofTypeId);
852 : }
853 : else
854 125052 : ofTypeId = InvalidOid;
855 :
856 : /*
857 : * Look up inheritance ancestors and generate relation schema, including
858 : * inherited attributes. (Note that stmt->tableElts is destructively
859 : * modified by MergeAttributes.)
860 : */
861 124964 : stmt->tableElts =
862 125132 : MergeAttributes(stmt->tableElts, inheritOids,
863 125132 : stmt->relation->relpersistence,
864 125132 : stmt->partbound != NULL,
865 : &old_constraints);
866 :
867 : /*
868 : * Create a tuple descriptor from the relation schema. Note that this
869 : * deals with column names, types, and NOT NULL constraints, but not
870 : * default values or CHECK constraints; we handle those below.
871 : */
872 124964 : descriptor = BuildDescForRelation(stmt->tableElts);
873 :
874 : /*
875 : * Find columns with default values and prepare for insertion of the
876 : * defaults. Pre-cooked (that is, inherited) defaults go into a list of
877 : * CookedConstraint structs that we'll pass to heap_create_with_catalog,
878 : * while raw defaults go into a list of RawColumnDefault structs that will
879 : * be processed by AddRelationNewConstraints. (We can't deal with raw
880 : * expressions until we can do transformExpr.)
881 : *
882 : * We can set the atthasdef flags now in the tuple descriptor; this just
883 : * saves StoreAttrDefault from having to do an immediate update of the
884 : * pg_attribute rows.
885 : */
886 124940 : rawDefaults = NIL;
887 124940 : cookedDefaults = NIL;
888 124940 : attnum = 0;
889 :
890 1094782 : foreach(listptr, stmt->tableElts)
891 : {
892 969860 : ColumnDef *colDef = lfirst(listptr);
893 : Form_pg_attribute attr;
894 :
895 969860 : attnum++;
896 969860 : attr = TupleDescAttr(descriptor, attnum - 1);
897 :
898 969860 : if (colDef->raw_default != NULL)
899 : {
900 : RawColumnDefault *rawEnt;
901 :
902 : Assert(colDef->cooked_default == NULL);
903 :
904 2286 : rawEnt = (RawColumnDefault *) palloc(sizeof(RawColumnDefault));
905 2286 : rawEnt->attnum = attnum;
906 2286 : rawEnt->raw_default = colDef->raw_default;
907 2286 : rawEnt->missingMode = false;
908 2286 : rawEnt->generated = colDef->generated;
909 2286 : rawDefaults = lappend(rawDefaults, rawEnt);
910 2286 : attr->atthasdef = true;
911 : }
912 967574 : else if (colDef->cooked_default != NULL)
913 : {
914 : CookedConstraint *cooked;
915 :
916 326 : cooked = (CookedConstraint *) palloc(sizeof(CookedConstraint));
917 326 : cooked->contype = CONSTR_DEFAULT;
918 326 : cooked->conoid = InvalidOid; /* until created */
919 326 : cooked->name = NULL;
920 326 : cooked->attnum = attnum;
921 326 : cooked->expr = colDef->cooked_default;
922 326 : cooked->skip_validation = false;
923 326 : cooked->is_local = true; /* not used for defaults */
924 326 : cooked->inhcount = 0; /* ditto */
925 326 : cooked->is_no_inherit = false;
926 326 : cookedDefaults = lappend(cookedDefaults, cooked);
927 326 : attr->atthasdef = true;
928 : }
929 :
930 969860 : if (colDef->identity)
931 132 : attr->attidentity = colDef->identity;
932 :
933 969860 : if (colDef->generated)
934 914 : attr->attgenerated = colDef->generated;
935 :
936 969860 : if (colDef->compression)
937 82 : attr->attcompression = GetAttributeCompression(attr->atttypid,
938 : colDef->compression);
939 :
940 969848 : if (colDef->storage_name)
941 12 : attr->attstorage = GetAttributeStorage(attr->atttypid, colDef->storage_name);
942 : }
943 :
944 : /*
945 : * If the statement hasn't specified an access method, but we're defining
946 : * a type of relation that needs one, use the default.
947 : */
948 124922 : if (stmt->accessMethod != NULL)
949 : {
950 114 : accessMethod = stmt->accessMethod;
951 :
952 114 : if (partitioned)
953 6 : ereport(ERROR,
954 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
955 : errmsg("specifying a table access method is not supported on a partitioned table")));
956 : }
957 124808 : else if (RELKIND_HAS_TABLE_AM(relkind))
958 30648 : accessMethod = default_table_access_method;
959 :
960 : /* look up the access method, verify it is for a table */
961 124916 : if (accessMethod != NULL)
962 30756 : accessMethodId = get_table_am_oid(accessMethod, false);
963 :
964 : /*
965 : * Create the relation. Inherited defaults and constraints are passed in
966 : * for immediate handling --- since they don't need parsing, they can be
967 : * stored immediately.
968 : */
969 124898 : relationId = heap_create_with_catalog(relname,
970 : namespaceId,
971 : tablespaceId,
972 : InvalidOid,
973 : InvalidOid,
974 : ofTypeId,
975 : ownerId,
976 : accessMethodId,
977 : descriptor,
978 : list_concat(cookedDefaults,
979 : old_constraints),
980 : relkind,
981 124898 : stmt->relation->relpersistence,
982 : false,
983 : false,
984 : stmt->oncommit,
985 : reloptions,
986 : true,
987 : allowSystemTableMods,
988 : false,
989 : InvalidOid,
990 : typaddress);
991 :
992 : /*
993 : * We must bump the command counter to make the newly-created relation
994 : * tuple visible for opening.
995 : */
996 124874 : CommandCounterIncrement();
997 :
998 : /*
999 : * Open the new relation and acquire exclusive lock on it. This isn't
1000 : * really necessary for locking out other backends (since they can't see
1001 : * the new rel anyway until we commit), but it keeps the lock manager from
1002 : * complaining about deadlock risks.
1003 : */
1004 124874 : rel = relation_open(relationId, AccessExclusiveLock);
1005 :
1006 : /*
1007 : * Now add any newly specified column default and generation expressions
1008 : * to the new relation. These are passed to us in the form of raw
1009 : * parsetrees; we need to transform them to executable expression trees
1010 : * before they can be added. The most convenient way to do that is to
1011 : * apply the parser's transformExpr routine, but transformExpr doesn't
1012 : * work unless we have a pre-existing relation. So, the transformation has
1013 : * to be postponed to this final step of CREATE TABLE.
1014 : *
1015 : * This needs to be before processing the partitioning clauses because
1016 : * those could refer to generated columns.
1017 : */
1018 124874 : if (rawDefaults)
1019 1934 : AddRelationNewConstraints(rel, rawDefaults, NIL,
1020 : true, true, false, queryString);
1021 :
1022 : /*
1023 : * Make column generation expressions visible for use by partitioning.
1024 : */
1025 124772 : CommandCounterIncrement();
1026 :
1027 : /* Process and store partition bound, if any. */
1028 124772 : if (stmt->partbound)
1029 : {
1030 : PartitionBoundSpec *bound;
1031 : ParseState *pstate;
1032 7210 : Oid parentId = linitial_oid(inheritOids),
1033 : defaultPartOid;
1034 : Relation parent,
1035 7210 : defaultRel = NULL;
1036 : ParseNamespaceItem *nsitem;
1037 :
1038 : /* Already have strong enough lock on the parent */
1039 7210 : parent = table_open(parentId, NoLock);
1040 :
1041 : /*
1042 : * We are going to try to validate the partition bound specification
1043 : * against the partition key of parentRel, so it better have one.
1044 : */
1045 7210 : if (parent->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
1046 12 : ereport(ERROR,
1047 : (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1048 : errmsg("\"%s\" is not partitioned",
1049 : RelationGetRelationName(parent))));
1050 :
1051 : /*
1052 : * The partition constraint of the default partition depends on the
1053 : * partition bounds of every other partition. It is possible that
1054 : * another backend might be about to execute a query on the default
1055 : * partition table, and that the query relies on previously cached
1056 : * default partition constraints. We must therefore take a table lock
1057 : * strong enough to prevent all queries on the default partition from
1058 : * proceeding until we commit and send out a shared-cache-inval notice
1059 : * that will make them update their index lists.
1060 : *
1061 : * Order of locking: The relation being added won't be visible to
1062 : * other backends until it is committed, hence here in
1063 : * DefineRelation() the order of locking the default partition and the
1064 : * relation being added does not matter. But at all other places we
1065 : * need to lock the default relation before we lock the relation being
1066 : * added or removed i.e. we should take the lock in same order at all
1067 : * the places such that lock parent, lock default partition and then
1068 : * lock the partition so as to avoid a deadlock.
1069 : */
1070 : defaultPartOid =
1071 7198 : get_default_oid_from_partdesc(RelationGetPartitionDesc(parent,
1072 : true));
1073 7198 : if (OidIsValid(defaultPartOid))
1074 366 : defaultRel = table_open(defaultPartOid, AccessExclusiveLock);
1075 :
1076 : /* Transform the bound values */
1077 7198 : pstate = make_parsestate(NULL);
1078 7198 : pstate->p_sourcetext = queryString;
1079 :
1080 : /*
1081 : * Add an nsitem containing this relation, so that transformExpr
1082 : * called on partition bound expressions is able to report errors
1083 : * using a proper context.
1084 : */
1085 7198 : nsitem = addRangeTableEntryForRelation(pstate, rel, AccessShareLock,
1086 : NULL, false, false);
1087 7198 : addNSItemToQuery(pstate, nsitem, false, true, true);
1088 :
1089 7198 : bound = transformPartitionBound(pstate, parent, stmt->partbound);
1090 :
1091 : /*
1092 : * Check first that the new partition's bound is valid and does not
1093 : * overlap with any of existing partitions of the parent.
1094 : */
1095 6994 : check_new_partition_bound(relname, parent, bound, pstate);
1096 :
1097 : /*
1098 : * If the default partition exists, its partition constraints will
1099 : * change after the addition of this new partition such that it won't
1100 : * allow any row that qualifies for this new partition. So, check that
1101 : * the existing data in the default partition satisfies the constraint
1102 : * as it will exist after adding this partition.
1103 : */
1104 6880 : if (OidIsValid(defaultPartOid))
1105 : {
1106 336 : check_default_partition_contents(parent, defaultRel, bound);
1107 : /* Keep the lock until commit. */
1108 318 : table_close(defaultRel, NoLock);
1109 : }
1110 :
1111 : /* Update the pg_class entry. */
1112 6862 : StorePartitionBound(rel, parent, bound);
1113 :
1114 6862 : table_close(parent, NoLock);
1115 : }
1116 :
1117 : /* Store inheritance information for new rel. */
1118 124424 : StoreCatalogInheritance(relationId, inheritOids, stmt->partbound != NULL);
1119 :
1120 : /*
1121 : * Process the partitioning specification (if any) and store the partition
1122 : * key information into the catalog.
1123 : */
1124 124424 : if (partitioned)
1125 : {
1126 : ParseState *pstate;
1127 : int partnatts;
1128 : AttrNumber partattrs[PARTITION_MAX_KEYS];
1129 : Oid partopclass[PARTITION_MAX_KEYS];
1130 : Oid partcollation[PARTITION_MAX_KEYS];
1131 4348 : List *partexprs = NIL;
1132 :
1133 4348 : pstate = make_parsestate(NULL);
1134 4348 : pstate->p_sourcetext = queryString;
1135 :
1136 4348 : partnatts = list_length(stmt->partspec->partParams);
1137 :
1138 : /* Protect fixed-size arrays here and in executor */
1139 4348 : if (partnatts > PARTITION_MAX_KEYS)
1140 0 : ereport(ERROR,
1141 : (errcode(ERRCODE_TOO_MANY_COLUMNS),
1142 : errmsg("cannot partition using more than %d columns",
1143 : PARTITION_MAX_KEYS)));
1144 :
1145 : /*
1146 : * We need to transform the raw parsetrees corresponding to partition
1147 : * expressions into executable expression trees. Like column defaults
1148 : * and CHECK constraints, we could not have done the transformation
1149 : * earlier.
1150 : */
1151 4348 : stmt->partspec = transformPartitionSpec(rel, stmt->partspec);
1152 :
1153 4318 : ComputePartitionAttrs(pstate, rel, stmt->partspec->partParams,
1154 : partattrs, &partexprs, partopclass,
1155 4318 : partcollation, stmt->partspec->strategy);
1156 :
1157 4234 : StorePartitionKey(rel, stmt->partspec->strategy, partnatts, partattrs,
1158 : partexprs,
1159 : partopclass, partcollation);
1160 :
1161 : /* make it all visible */
1162 4234 : CommandCounterIncrement();
1163 : }
1164 :
1165 : /*
1166 : * If we're creating a partition, create now all the indexes, triggers,
1167 : * FKs defined in the parent.
1168 : *
1169 : * We can't do it earlier, because DefineIndex wants to know the partition
1170 : * key which we just stored.
1171 : */
1172 124310 : if (stmt->partbound)
1173 : {
1174 6856 : Oid parentId = linitial_oid(inheritOids);
1175 : Relation parent;
1176 : List *idxlist;
1177 : ListCell *cell;
1178 :
1179 : /* Already have strong enough lock on the parent */
1180 6856 : parent = table_open(parentId, NoLock);
1181 6856 : idxlist = RelationGetIndexList(parent);
1182 :
1183 : /*
1184 : * For each index in the parent table, create one in the partition
1185 : */
1186 8054 : foreach(cell, idxlist)
1187 : {
1188 1216 : Relation idxRel = index_open(lfirst_oid(cell), AccessShareLock);
1189 : AttrMap *attmap;
1190 : IndexStmt *idxstmt;
1191 : Oid constraintOid;
1192 :
1193 1216 : if (rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
1194 : {
1195 36 : if (idxRel->rd_index->indisunique)
1196 12 : ereport(ERROR,
1197 : (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1198 : errmsg("cannot create foreign partition of partitioned table \"%s\"",
1199 : RelationGetRelationName(parent)),
1200 : errdetail("Table \"%s\" contains indexes that are unique.",
1201 : RelationGetRelationName(parent))));
1202 : else
1203 : {
1204 24 : index_close(idxRel, AccessShareLock);
1205 24 : continue;
1206 : }
1207 : }
1208 :
1209 1180 : attmap = build_attrmap_by_name(RelationGetDescr(rel),
1210 : RelationGetDescr(parent),
1211 : false);
1212 : idxstmt =
1213 1180 : generateClonedIndexStmt(NULL, idxRel,
1214 : attmap, &constraintOid);
1215 1180 : DefineIndex(RelationGetRelid(rel),
1216 : idxstmt,
1217 : InvalidOid,
1218 : RelationGetRelid(idxRel),
1219 : constraintOid,
1220 : -1,
1221 : false, false, false, false, false);
1222 :
1223 1174 : index_close(idxRel, AccessShareLock);
1224 : }
1225 :
1226 6838 : list_free(idxlist);
1227 :
1228 : /*
1229 : * If there are any row-level triggers, clone them to the new
1230 : * partition.
1231 : */
1232 6838 : if (parent->trigdesc != NULL)
1233 376 : CloneRowTriggersToPartition(parent, rel);
1234 :
1235 : /*
1236 : * And foreign keys too. Note that because we're freshly creating the
1237 : * table, there is no need to verify these new constraints.
1238 : */
1239 6838 : CloneForeignKeyConstraints(NULL, parent, rel);
1240 :
1241 6838 : table_close(parent, NoLock);
1242 : }
1243 :
1244 : /*
1245 : * Now add any newly specified CHECK constraints to the new relation. Same
1246 : * as for defaults above, but these need to come after partitioning is set
1247 : * up.
1248 : */
1249 124292 : if (stmt->constraints)
1250 554 : AddRelationNewConstraints(rel, NIL, stmt->constraints,
1251 : true, true, false, queryString);
1252 :
1253 124274 : ObjectAddressSet(address, RelationRelationId, relationId);
1254 :
1255 : /*
1256 : * Clean up. We keep lock on new relation (although it shouldn't be
1257 : * visible to anyone else anyway, until commit).
1258 : */
1259 124274 : relation_close(rel, NoLock);
1260 :
1261 124274 : return address;
1262 : }
1263 :
1264 : /*
1265 : * Emit the right error or warning message for a "DROP" command issued on a
1266 : * non-existent relation
1267 : */
1268 : static void
1269 1036 : DropErrorMsgNonExistent(RangeVar *rel, char rightkind, bool missing_ok)
1270 : {
1271 : const struct dropmsgstrings *rentry;
1272 :
1273 1150 : if (rel->schemaname != NULL &&
1274 114 : !OidIsValid(LookupNamespaceNoError(rel->schemaname)))
1275 : {
1276 42 : if (!missing_ok)
1277 : {
1278 0 : ereport(ERROR,
1279 : (errcode(ERRCODE_UNDEFINED_SCHEMA),
1280 : errmsg("schema \"%s\" does not exist", rel->schemaname)));
1281 : }
1282 : else
1283 : {
1284 42 : ereport(NOTICE,
1285 : (errmsg("schema \"%s\" does not exist, skipping",
1286 : rel->schemaname)));
1287 : }
1288 42 : return;
1289 : }
1290 :
1291 1290 : for (rentry = dropmsgstringarray; rentry->kind != '\0'; rentry++)
1292 : {
1293 1290 : if (rentry->kind == rightkind)
1294 : {
1295 994 : if (!missing_ok)
1296 : {
1297 132 : ereport(ERROR,
1298 : (errcode(rentry->nonexistent_code),
1299 : errmsg(rentry->nonexistent_msg, rel->relname)));
1300 : }
1301 : else
1302 : {
1303 862 : ereport(NOTICE, (errmsg(rentry->skipping_msg, rel->relname)));
1304 862 : break;
1305 : }
1306 : }
1307 : }
1308 :
1309 : Assert(rentry->kind != '\0'); /* Should be impossible */
1310 : }
1311 :
1312 : /*
1313 : * Emit the right error message for a "DROP" command issued on a
1314 : * relation of the wrong type
1315 : */
1316 : static void
1317 0 : DropErrorMsgWrongType(const char *relname, char wrongkind, char rightkind)
1318 : {
1319 : const struct dropmsgstrings *rentry;
1320 : const struct dropmsgstrings *wentry;
1321 :
1322 0 : for (rentry = dropmsgstringarray; rentry->kind != '\0'; rentry++)
1323 0 : if (rentry->kind == rightkind)
1324 0 : break;
1325 : Assert(rentry->kind != '\0');
1326 :
1327 0 : for (wentry = dropmsgstringarray; wentry->kind != '\0'; wentry++)
1328 0 : if (wentry->kind == wrongkind)
1329 0 : break;
1330 : /* wrongkind could be something we don't have in our table... */
1331 :
1332 0 : ereport(ERROR,
1333 : (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1334 : errmsg(rentry->nota_msg, relname),
1335 : (wentry->kind != '\0') ? errhint("%s", _(wentry->drophint_msg)) : 0));
1336 : }
1337 :
1338 : /*
1339 : * RemoveRelations
1340 : * Implements DROP TABLE, DROP INDEX, DROP SEQUENCE, DROP VIEW,
1341 : * DROP MATERIALIZED VIEW, DROP FOREIGN TABLE
1342 : */
1343 : void
1344 14978 : RemoveRelations(DropStmt *drop)
1345 : {
1346 : ObjectAddresses *objects;
1347 : char relkind;
1348 : ListCell *cell;
1349 14978 : int flags = 0;
1350 14978 : LOCKMODE lockmode = AccessExclusiveLock;
1351 :
1352 : /* DROP CONCURRENTLY uses a weaker lock, and has some restrictions */
1353 14978 : if (drop->concurrent)
1354 : {
1355 : /*
1356 : * Note that for temporary relations this lock may get upgraded later
1357 : * on, but as no other session can access a temporary relation, this
1358 : * is actually fine.
1359 : */
1360 110 : lockmode = ShareUpdateExclusiveLock;
1361 : Assert(drop->removeType == OBJECT_INDEX);
1362 110 : if (list_length(drop->objects) != 1)
1363 6 : ereport(ERROR,
1364 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1365 : errmsg("DROP INDEX CONCURRENTLY does not support dropping multiple objects")));
1366 104 : if (drop->behavior == DROP_CASCADE)
1367 0 : ereport(ERROR,
1368 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1369 : errmsg("DROP INDEX CONCURRENTLY does not support CASCADE")));
1370 : }
1371 :
1372 : /*
1373 : * First we identify all the relations, then we delete them in a single
1374 : * performMultipleDeletions() call. This is to avoid unwanted DROP
1375 : * RESTRICT errors if one of the relations depends on another.
1376 : */
1377 :
1378 : /* Determine required relkind */
1379 14972 : switch (drop->removeType)
1380 : {
1381 13038 : case OBJECT_TABLE:
1382 13038 : relkind = RELKIND_RELATION;
1383 13038 : break;
1384 :
1385 696 : case OBJECT_INDEX:
1386 696 : relkind = RELKIND_INDEX;
1387 696 : break;
1388 :
1389 172 : case OBJECT_SEQUENCE:
1390 172 : relkind = RELKIND_SEQUENCE;
1391 172 : break;
1392 :
1393 804 : case OBJECT_VIEW:
1394 804 : relkind = RELKIND_VIEW;
1395 804 : break;
1396 :
1397 114 : case OBJECT_MATVIEW:
1398 114 : relkind = RELKIND_MATVIEW;
1399 114 : break;
1400 :
1401 148 : case OBJECT_FOREIGN_TABLE:
1402 148 : relkind = RELKIND_FOREIGN_TABLE;
1403 148 : break;
1404 :
1405 0 : default:
1406 0 : elog(ERROR, "unrecognized drop object type: %d",
1407 : (int) drop->removeType);
1408 : relkind = 0; /* keep compiler quiet */
1409 : break;
1410 : }
1411 :
1412 : /* Lock and validate each relation; build a list of object addresses */
1413 14972 : objects = new_object_addresses();
1414 :
1415 33206 : foreach(cell, drop->objects)
1416 : {
1417 18392 : RangeVar *rel = makeRangeVarFromNameList((List *) lfirst(cell));
1418 : Oid relOid;
1419 : ObjectAddress obj;
1420 : struct DropRelationCallbackState state;
1421 :
1422 : /*
1423 : * These next few steps are a great deal like relation_openrv, but we
1424 : * don't bother building a relcache entry since we don't need it.
1425 : *
1426 : * Check for shared-cache-inval messages before trying to access the
1427 : * relation. This is needed to cover the case where the name
1428 : * identifies a rel that has been dropped and recreated since the
1429 : * start of our transaction: if we don't flush the old syscache entry,
1430 : * then we'll latch onto that entry and suffer an error later.
1431 : */
1432 18392 : AcceptInvalidationMessages();
1433 :
1434 : /* Look up the appropriate relation using namespace search. */
1435 18392 : state.expected_relkind = relkind;
1436 36784 : state.heap_lockmode = drop->concurrent ?
1437 18392 : ShareUpdateExclusiveLock : AccessExclusiveLock;
1438 : /* We must initialize these fields to show that no locks are held: */
1439 18392 : state.heapOid = InvalidOid;
1440 18392 : state.partParentOid = InvalidOid;
1441 :
1442 18392 : relOid = RangeVarGetRelidExtended(rel, lockmode, RVR_MISSING_OK,
1443 : RangeVarCallbackForDropRelation,
1444 : (void *) &state);
1445 :
1446 : /* Not there? */
1447 18372 : if (!OidIsValid(relOid))
1448 : {
1449 1036 : DropErrorMsgNonExistent(rel, relkind, drop->missing_ok);
1450 904 : continue;
1451 : }
1452 :
1453 : /*
1454 : * Decide if concurrent mode needs to be used here or not. The
1455 : * callback retrieved the rel's persistence for us.
1456 : */
1457 17336 : if (drop->concurrent &&
1458 98 : state.actual_relpersistence != RELPERSISTENCE_TEMP)
1459 : {
1460 : Assert(list_length(drop->objects) == 1 &&
1461 : drop->removeType == OBJECT_INDEX);
1462 80 : flags |= PERFORM_DELETION_CONCURRENTLY;
1463 : }
1464 :
1465 : /*
1466 : * Concurrent index drop cannot be used with partitioned indexes,
1467 : * either.
1468 : */
1469 17336 : if ((flags & PERFORM_DELETION_CONCURRENTLY) != 0 &&
1470 80 : state.actual_relkind == RELKIND_PARTITIONED_INDEX)
1471 6 : ereport(ERROR,
1472 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1473 : errmsg("cannot drop partitioned index \"%s\" concurrently",
1474 : rel->relname)));
1475 :
1476 : /*
1477 : * If we're told to drop a partitioned index, we must acquire lock on
1478 : * all the children of its parent partitioned table before proceeding.
1479 : * Otherwise we'd try to lock the child index partitions before their
1480 : * tables, leading to potential deadlock against other sessions that
1481 : * will lock those objects in the other order.
1482 : */
1483 17330 : if (state.actual_relkind == RELKIND_PARTITIONED_INDEX)
1484 52 : (void) find_all_inheritors(state.heapOid,
1485 : state.heap_lockmode,
1486 : NULL);
1487 :
1488 : /* OK, we're ready to delete this one */
1489 17330 : obj.classId = RelationRelationId;
1490 17330 : obj.objectId = relOid;
1491 17330 : obj.objectSubId = 0;
1492 :
1493 17330 : add_exact_object_address(&obj, objects);
1494 : }
1495 :
1496 14814 : performMultipleDeletions(objects, drop->behavior, flags);
1497 :
1498 14678 : free_object_addresses(objects);
1499 14678 : }
1500 :
1501 : /*
1502 : * Before acquiring a table lock, check whether we have sufficient rights.
1503 : * In the case of DROP INDEX, also try to lock the table before the index.
1504 : * Also, if the table to be dropped is a partition, we try to lock the parent
1505 : * first.
1506 : */
1507 : static void
1508 18520 : RangeVarCallbackForDropRelation(const RangeVar *rel, Oid relOid, Oid oldRelOid,
1509 : void *arg)
1510 : {
1511 : HeapTuple tuple;
1512 : struct DropRelationCallbackState *state;
1513 : char expected_relkind;
1514 : bool is_partition;
1515 : Form_pg_class classform;
1516 : LOCKMODE heap_lockmode;
1517 18520 : bool invalid_system_index = false;
1518 :
1519 18520 : state = (struct DropRelationCallbackState *) arg;
1520 18520 : heap_lockmode = state->heap_lockmode;
1521 :
1522 : /*
1523 : * If we previously locked some other index's heap, and the name we're
1524 : * looking up no longer refers to that relation, release the now-useless
1525 : * lock.
1526 : */
1527 18520 : if (relOid != oldRelOid && OidIsValid(state->heapOid))
1528 : {
1529 0 : UnlockRelationOid(state->heapOid, heap_lockmode);
1530 0 : state->heapOid = InvalidOid;
1531 : }
1532 :
1533 : /*
1534 : * Similarly, if we previously locked some other partition's heap, and the
1535 : * name we're looking up no longer refers to that relation, release the
1536 : * now-useless lock.
1537 : */
1538 18520 : if (relOid != oldRelOid && OidIsValid(state->partParentOid))
1539 : {
1540 0 : UnlockRelationOid(state->partParentOid, AccessExclusiveLock);
1541 0 : state->partParentOid = InvalidOid;
1542 : }
1543 :
1544 : /* Didn't find a relation, so no need for locking or permission checks. */
1545 18520 : if (!OidIsValid(relOid))
1546 1038 : return;
1547 :
1548 17482 : tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relOid));
1549 17482 : if (!HeapTupleIsValid(tuple))
1550 0 : return; /* concurrently dropped, so nothing to do */
1551 17482 : classform = (Form_pg_class) GETSTRUCT(tuple);
1552 17482 : is_partition = classform->relispartition;
1553 :
1554 : /* Pass back some data to save lookups in RemoveRelations */
1555 17482 : state->actual_relkind = classform->relkind;
1556 17482 : state->actual_relpersistence = classform->relpersistence;
1557 :
1558 : /*
1559 : * Both RELKIND_RELATION and RELKIND_PARTITIONED_TABLE are OBJECT_TABLE,
1560 : * but RemoveRelations() can only pass one relkind for a given relation.
1561 : * It chooses RELKIND_RELATION for both regular and partitioned tables.
1562 : * That means we must be careful before giving the wrong type error when
1563 : * the relation is RELKIND_PARTITIONED_TABLE. An equivalent problem
1564 : * exists with indexes.
1565 : */
1566 17482 : if (classform->relkind == RELKIND_PARTITIONED_TABLE)
1567 2536 : expected_relkind = RELKIND_RELATION;
1568 14946 : else if (classform->relkind == RELKIND_PARTITIONED_INDEX)
1569 62 : expected_relkind = RELKIND_INDEX;
1570 : else
1571 14884 : expected_relkind = classform->relkind;
1572 :
1573 17482 : if (state->expected_relkind != expected_relkind)
1574 0 : DropErrorMsgWrongType(rel->relname, classform->relkind,
1575 0 : state->expected_relkind);
1576 :
1577 : /* Allow DROP to either table owner or schema owner */
1578 17482 : if (!object_ownercheck(RelationRelationId, relOid, GetUserId()) &&
1579 18 : !object_ownercheck(NamespaceRelationId, classform->relnamespace, GetUserId()))
1580 18 : aclcheck_error(ACLCHECK_NOT_OWNER,
1581 18 : get_relkind_objtype(classform->relkind),
1582 18 : rel->relname);
1583 :
1584 : /*
1585 : * Check the case of a system index that might have been invalidated by a
1586 : * failed concurrent process and allow its drop. For the time being, this
1587 : * only concerns indexes of toast relations that became invalid during a
1588 : * REINDEX CONCURRENTLY process.
1589 : */
1590 17464 : if (IsSystemClass(relOid, classform) && classform->relkind == RELKIND_INDEX)
1591 : {
1592 : HeapTuple locTuple;
1593 : Form_pg_index indexform;
1594 : bool indisvalid;
1595 :
1596 0 : locTuple = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(relOid));
1597 0 : if (!HeapTupleIsValid(locTuple))
1598 : {
1599 0 : ReleaseSysCache(tuple);
1600 0 : return;
1601 : }
1602 :
1603 0 : indexform = (Form_pg_index) GETSTRUCT(locTuple);
1604 0 : indisvalid = indexform->indisvalid;
1605 0 : ReleaseSysCache(locTuple);
1606 :
1607 : /* Mark object as being an invalid index of system catalogs */
1608 0 : if (!indisvalid)
1609 0 : invalid_system_index = true;
1610 : }
1611 :
1612 : /* In the case of an invalid index, it is fine to bypass this check */
1613 17464 : if (!invalid_system_index && !allowSystemTableMods && IsSystemClass(relOid, classform))
1614 2 : ereport(ERROR,
1615 : (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1616 : errmsg("permission denied: \"%s\" is a system catalog",
1617 : rel->relname)));
1618 :
1619 17462 : ReleaseSysCache(tuple);
1620 :
1621 : /*
1622 : * In DROP INDEX, attempt to acquire lock on the parent table before
1623 : * locking the index. index_drop() will need this anyway, and since
1624 : * regular queries lock tables before their indexes, we risk deadlock if
1625 : * we do it the other way around. No error if we don't find a pg_index
1626 : * entry, though --- the relation may have been dropped. Note that this
1627 : * code will execute for either plain or partitioned indexes.
1628 : */
1629 17462 : if (expected_relkind == RELKIND_INDEX &&
1630 : relOid != oldRelOid)
1631 : {
1632 678 : state->heapOid = IndexGetRelation(relOid, true);
1633 678 : if (OidIsValid(state->heapOid))
1634 678 : LockRelationOid(state->heapOid, heap_lockmode);
1635 : }
1636 :
1637 : /*
1638 : * Similarly, if the relation is a partition, we must acquire lock on its
1639 : * parent before locking the partition. That's because queries lock the
1640 : * parent before its partitions, so we risk deadlock if we do it the other
1641 : * way around.
1642 : */
1643 17462 : if (is_partition && relOid != oldRelOid)
1644 : {
1645 586 : state->partParentOid = get_partition_parent(relOid, true);
1646 586 : if (OidIsValid(state->partParentOid))
1647 586 : LockRelationOid(state->partParentOid, AccessExclusiveLock);
1648 : }
1649 : }
1650 :
1651 : /*
1652 : * ExecuteTruncate
1653 : * Executes a TRUNCATE command.
1654 : *
1655 : * This is a multi-relation truncate. We first open and grab exclusive
1656 : * lock on all relations involved, checking permissions and otherwise
1657 : * verifying that the relation is OK for truncation. Note that if relations
1658 : * are foreign tables, at this stage, we have not yet checked that their
1659 : * foreign data in external data sources are OK for truncation. These are
1660 : * checked when foreign data are actually truncated later. In CASCADE mode,
1661 : * relations having FK references to the targeted relations are automatically
1662 : * added to the group; in RESTRICT mode, we check that all FK references are
1663 : * internal to the group that's being truncated. Finally all the relations
1664 : * are truncated and reindexed.
1665 : */
1666 : void
1667 1326 : ExecuteTruncate(TruncateStmt *stmt)
1668 : {
1669 1326 : List *rels = NIL;
1670 1326 : List *relids = NIL;
1671 1326 : List *relids_logged = NIL;
1672 : ListCell *cell;
1673 :
1674 : /*
1675 : * Open, exclusive-lock, and check all the explicitly-specified relations
1676 : */
1677 2806 : foreach(cell, stmt->relations)
1678 : {
1679 1528 : RangeVar *rv = lfirst(cell);
1680 : Relation rel;
1681 1528 : bool recurse = rv->inh;
1682 : Oid myrelid;
1683 1528 : LOCKMODE lockmode = AccessExclusiveLock;
1684 :
1685 1528 : myrelid = RangeVarGetRelidExtended(rv, lockmode,
1686 : 0, RangeVarCallbackForTruncate,
1687 : NULL);
1688 :
1689 : /* don't throw error for "TRUNCATE foo, foo" */
1690 1492 : if (list_member_oid(relids, myrelid))
1691 2 : continue;
1692 :
1693 : /* open the relation, we already hold a lock on it */
1694 1490 : rel = table_open(myrelid, NoLock);
1695 :
1696 : /*
1697 : * RangeVarGetRelidExtended() has done most checks with its callback,
1698 : * but other checks with the now-opened Relation remain.
1699 : */
1700 1490 : truncate_check_activity(rel);
1701 :
1702 1490 : rels = lappend(rels, rel);
1703 1490 : relids = lappend_oid(relids, myrelid);
1704 :
1705 : /* Log this relation only if needed for logical decoding */
1706 1490 : if (RelationIsLogicallyLogged(rel))
1707 74 : relids_logged = lappend_oid(relids_logged, myrelid);
1708 :
1709 1490 : if (recurse)
1710 : {
1711 : ListCell *child;
1712 : List *children;
1713 :
1714 1428 : children = find_all_inheritors(myrelid, lockmode, NULL);
1715 :
1716 4492 : foreach(child, children)
1717 : {
1718 3064 : Oid childrelid = lfirst_oid(child);
1719 :
1720 3064 : if (list_member_oid(relids, childrelid))
1721 1428 : continue;
1722 :
1723 : /* find_all_inheritors already got lock */
1724 1636 : rel = table_open(childrelid, NoLock);
1725 :
1726 : /*
1727 : * It is possible that the parent table has children that are
1728 : * temp tables of other backends. We cannot safely access
1729 : * such tables (because of buffering issues), and the best
1730 : * thing to do is to silently ignore them. Note that this
1731 : * check is the same as one of the checks done in
1732 : * truncate_check_activity() called below, still it is kept
1733 : * here for simplicity.
1734 : */
1735 1636 : if (RELATION_IS_OTHER_TEMP(rel))
1736 : {
1737 8 : table_close(rel, lockmode);
1738 8 : continue;
1739 : }
1740 :
1741 : /*
1742 : * Inherited TRUNCATE commands perform access permission
1743 : * checks on the parent table only. So we skip checking the
1744 : * children's permissions and don't call
1745 : * truncate_check_perms() here.
1746 : */
1747 1628 : truncate_check_rel(RelationGetRelid(rel), rel->rd_rel);
1748 1628 : truncate_check_activity(rel);
1749 :
1750 1628 : rels = lappend(rels, rel);
1751 1628 : relids = lappend_oid(relids, childrelid);
1752 :
1753 : /* Log this relation only if needed for logical decoding */
1754 1628 : if (RelationIsLogicallyLogged(rel))
1755 32 : relids_logged = lappend_oid(relids_logged, childrelid);
1756 : }
1757 : }
1758 62 : else if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
1759 12 : ereport(ERROR,
1760 : (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1761 : errmsg("cannot truncate only a partitioned table"),
1762 : errhint("Do not specify the ONLY keyword, or use TRUNCATE ONLY on the partitions directly.")));
1763 : }
1764 :
1765 1278 : ExecuteTruncateGuts(rels, relids, relids_logged,
1766 1278 : stmt->behavior, stmt->restart_seqs, false);
1767 :
1768 : /* And close the rels */
1769 4148 : foreach(cell, rels)
1770 : {
1771 2952 : Relation rel = (Relation) lfirst(cell);
1772 :
1773 2952 : table_close(rel, NoLock);
1774 : }
1775 1196 : }
1776 :
1777 : /*
1778 : * ExecuteTruncateGuts
1779 : *
1780 : * Internal implementation of TRUNCATE. This is called by the actual TRUNCATE
1781 : * command (see above) as well as replication subscribers that execute a
1782 : * replicated TRUNCATE action.
1783 : *
1784 : * explicit_rels is the list of Relations to truncate that the command
1785 : * specified. relids is the list of Oids corresponding to explicit_rels.
1786 : * relids_logged is the list of Oids (a subset of relids) that require
1787 : * WAL-logging. This is all a bit redundant, but the existing callers have
1788 : * this information handy in this form.
1789 : */
1790 : void
1791 1312 : ExecuteTruncateGuts(List *explicit_rels,
1792 : List *relids,
1793 : List *relids_logged,
1794 : DropBehavior behavior, bool restart_seqs,
1795 : bool run_as_table_owner)
1796 : {
1797 : List *rels;
1798 1312 : List *seq_relids = NIL;
1799 1312 : HTAB *ft_htab = NULL;
1800 : EState *estate;
1801 : ResultRelInfo *resultRelInfos;
1802 : ResultRelInfo *resultRelInfo;
1803 : SubTransactionId mySubid;
1804 : ListCell *cell;
1805 : Oid *logrelids;
1806 :
1807 : /*
1808 : * Check the explicitly-specified relations.
1809 : *
1810 : * In CASCADE mode, suck in all referencing relations as well. This
1811 : * requires multiple iterations to find indirectly-dependent relations. At
1812 : * each phase, we need to exclusive-lock new rels before looking for their
1813 : * dependencies, else we might miss something. Also, we check each rel as
1814 : * soon as we open it, to avoid a faux pas such as holding lock for a long
1815 : * time on a rel we have no permissions for.
1816 : */
1817 1312 : rels = list_copy(explicit_rels);
1818 1312 : if (behavior == DROP_CASCADE)
1819 : {
1820 : for (;;)
1821 40 : {
1822 : List *newrelids;
1823 :
1824 80 : newrelids = heap_truncate_find_FKs(relids);
1825 80 : if (newrelids == NIL)
1826 40 : break; /* nothing else to add */
1827 :
1828 134 : foreach(cell, newrelids)
1829 : {
1830 94 : Oid relid = lfirst_oid(cell);
1831 : Relation rel;
1832 :
1833 94 : rel = table_open(relid, AccessExclusiveLock);
1834 94 : ereport(NOTICE,
1835 : (errmsg("truncate cascades to table \"%s\"",
1836 : RelationGetRelationName(rel))));
1837 94 : truncate_check_rel(relid, rel->rd_rel);
1838 94 : truncate_check_perms(relid, rel->rd_rel);
1839 94 : truncate_check_activity(rel);
1840 94 : rels = lappend(rels, rel);
1841 94 : relids = lappend_oid(relids, relid);
1842 :
1843 : /* Log this relation only if needed for logical decoding */
1844 94 : if (RelationIsLogicallyLogged(rel))
1845 0 : relids_logged = lappend_oid(relids_logged, relid);
1846 : }
1847 : }
1848 : }
1849 :
1850 : /*
1851 : * Check foreign key references. In CASCADE mode, this should be
1852 : * unnecessary since we just pulled in all the references; but as a
1853 : * cross-check, do it anyway if in an Assert-enabled build.
1854 : */
1855 : #ifdef USE_ASSERT_CHECKING
1856 : heap_truncate_check_FKs(rels, false);
1857 : #else
1858 1312 : if (behavior == DROP_RESTRICT)
1859 1272 : heap_truncate_check_FKs(rels, false);
1860 : #endif
1861 :
1862 : /*
1863 : * If we are asked to restart sequences, find all the sequences, lock them
1864 : * (we need AccessExclusiveLock for ResetSequence), and check permissions.
1865 : * We want to do this early since it's pointless to do all the truncation
1866 : * work only to fail on sequence permissions.
1867 : */
1868 1238 : if (restart_seqs)
1869 : {
1870 52 : foreach(cell, rels)
1871 : {
1872 26 : Relation rel = (Relation) lfirst(cell);
1873 26 : List *seqlist = getOwnedSequences(RelationGetRelid(rel));
1874 : ListCell *seqcell;
1875 :
1876 62 : foreach(seqcell, seqlist)
1877 : {
1878 36 : Oid seq_relid = lfirst_oid(seqcell);
1879 : Relation seq_rel;
1880 :
1881 36 : seq_rel = relation_open(seq_relid, AccessExclusiveLock);
1882 :
1883 : /* This check must match AlterSequence! */
1884 36 : if (!object_ownercheck(RelationRelationId, seq_relid, GetUserId()))
1885 0 : aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_SEQUENCE,
1886 0 : RelationGetRelationName(seq_rel));
1887 :
1888 36 : seq_relids = lappend_oid(seq_relids, seq_relid);
1889 :
1890 36 : relation_close(seq_rel, NoLock);
1891 : }
1892 : }
1893 : }
1894 :
1895 : /* Prepare to catch AFTER triggers. */
1896 1238 : AfterTriggerBeginQuery();
1897 :
1898 : /*
1899 : * To fire triggers, we'll need an EState as well as a ResultRelInfo for
1900 : * each relation. We don't need to call ExecOpenIndices, though.
1901 : *
1902 : * We put the ResultRelInfos in the es_opened_result_relations list, even
1903 : * though we don't have a range table and don't populate the
1904 : * es_result_relations array. That's a bit bogus, but it's enough to make
1905 : * ExecGetTriggerResultRel() find them.
1906 : */
1907 1238 : estate = CreateExecutorState();
1908 : resultRelInfos = (ResultRelInfo *)
1909 1238 : palloc(list_length(rels) * sizeof(ResultRelInfo));
1910 1238 : resultRelInfo = resultRelInfos;
1911 4358 : foreach(cell, rels)
1912 : {
1913 3120 : Relation rel = (Relation) lfirst(cell);
1914 :
1915 3120 : InitResultRelInfo(resultRelInfo,
1916 : rel,
1917 : 0, /* dummy rangetable index */
1918 : NULL,
1919 : 0);
1920 3120 : estate->es_opened_result_relations =
1921 3120 : lappend(estate->es_opened_result_relations, resultRelInfo);
1922 3120 : resultRelInfo++;
1923 : }
1924 :
1925 : /*
1926 : * Process all BEFORE STATEMENT TRUNCATE triggers before we begin
1927 : * truncating (this is because one of them might throw an error). Also, if
1928 : * we were to allow them to prevent statement execution, that would need
1929 : * to be handled here.
1930 : */
1931 1238 : resultRelInfo = resultRelInfos;
1932 4358 : foreach(cell, rels)
1933 : {
1934 : UserContext ucxt;
1935 :
1936 3120 : if (run_as_table_owner)
1937 66 : SwitchToUntrustedUser(resultRelInfo->ri_RelationDesc->rd_rel->relowner,
1938 : &ucxt);
1939 3120 : ExecBSTruncateTriggers(estate, resultRelInfo);
1940 3120 : if (run_as_table_owner)
1941 66 : RestoreUserContext(&ucxt);
1942 3120 : resultRelInfo++;
1943 : }
1944 :
1945 : /*
1946 : * OK, truncate each table.
1947 : */
1948 1238 : mySubid = GetCurrentSubTransactionId();
1949 :
1950 4358 : foreach(cell, rels)
1951 : {
1952 3120 : Relation rel = (Relation) lfirst(cell);
1953 :
1954 : /* Skip partitioned tables as there is nothing to do */
1955 3120 : if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
1956 644 : continue;
1957 :
1958 : /*
1959 : * Build the lists of foreign tables belonging to each foreign server
1960 : * and pass each list to the foreign data wrapper's callback function,
1961 : * so that each server can truncate its all foreign tables in bulk.
1962 : * Each list is saved as a single entry in a hash table that uses the
1963 : * server OID as lookup key.
1964 : */
1965 2476 : if (rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
1966 : {
1967 34 : Oid serverid = GetForeignServerIdByRelId(RelationGetRelid(rel));
1968 : bool found;
1969 : ForeignTruncateInfo *ft_info;
1970 :
1971 : /* First time through, initialize hashtable for foreign tables */
1972 34 : if (!ft_htab)
1973 : {
1974 : HASHCTL hctl;
1975 :
1976 30 : memset(&hctl, 0, sizeof(HASHCTL));
1977 30 : hctl.keysize = sizeof(Oid);
1978 30 : hctl.entrysize = sizeof(ForeignTruncateInfo);
1979 30 : hctl.hcxt = CurrentMemoryContext;
1980 :
1981 30 : ft_htab = hash_create("TRUNCATE for Foreign Tables",
1982 : 32, /* start small and extend */
1983 : &hctl,
1984 : HASH_ELEM | HASH_BLOBS | HASH_CONTEXT);
1985 : }
1986 :
1987 : /* Find or create cached entry for the foreign table */
1988 34 : ft_info = hash_search(ft_htab, &serverid, HASH_ENTER, &found);
1989 34 : if (!found)
1990 : {
1991 30 : ft_info->serverid = serverid;
1992 30 : ft_info->rels = NIL;
1993 : }
1994 :
1995 : /*
1996 : * Save the foreign table in the entry of the server that the
1997 : * foreign table belongs to.
1998 : */
1999 34 : ft_info->rels = lappend(ft_info->rels, rel);
2000 34 : continue;
2001 : }
2002 :
2003 : /*
2004 : * Normally, we need a transaction-safe truncation here. However, if
2005 : * the table was either created in the current (sub)transaction or has
2006 : * a new relfilenumber in the current (sub)transaction, then we can
2007 : * just truncate it in-place, because a rollback would cause the whole
2008 : * table or the current physical file to be thrown away anyway.
2009 : */
2010 2442 : if (rel->rd_createSubid == mySubid ||
2011 2416 : rel->rd_newRelfilelocatorSubid == mySubid)
2012 : {
2013 : /* Immediate, non-rollbackable truncation is OK */
2014 90 : heap_truncate_one_rel(rel);
2015 : }
2016 : else
2017 : {
2018 : Oid heap_relid;
2019 : Oid toast_relid;
2020 2352 : ReindexParams reindex_params = {0};
2021 :
2022 : /*
2023 : * This effectively deletes all rows in the table, and may be done
2024 : * in a serializable transaction. In that case we must record a
2025 : * rw-conflict in to this transaction from each transaction
2026 : * holding a predicate lock on the table.
2027 : */
2028 2352 : CheckTableForSerializableConflictIn(rel);
2029 :
2030 : /*
2031 : * Need the full transaction-safe pushups.
2032 : *
2033 : * Create a new empty storage file for the relation, and assign it
2034 : * as the relfilenumber value. The old storage file is scheduled
2035 : * for deletion at commit.
2036 : */
2037 2352 : RelationSetNewRelfilenumber(rel, rel->rd_rel->relpersistence);
2038 :
2039 2352 : heap_relid = RelationGetRelid(rel);
2040 :
2041 : /*
2042 : * The same for the toast table, if any.
2043 : */
2044 2352 : toast_relid = rel->rd_rel->reltoastrelid;
2045 2352 : if (OidIsValid(toast_relid))
2046 : {
2047 1400 : Relation toastrel = relation_open(toast_relid,
2048 : AccessExclusiveLock);
2049 :
2050 1400 : RelationSetNewRelfilenumber(toastrel,
2051 1400 : toastrel->rd_rel->relpersistence);
2052 1400 : table_close(toastrel, NoLock);
2053 : }
2054 :
2055 : /*
2056 : * Reconstruct the indexes to match, and we're done.
2057 : */
2058 2352 : reindex_relation(heap_relid, REINDEX_REL_PROCESS_TOAST,
2059 : &reindex_params);
2060 : }
2061 :
2062 2442 : pgstat_count_truncate(rel);
2063 : }
2064 :
2065 : /* Now go through the hash table, and truncate foreign tables */
2066 1238 : if (ft_htab)
2067 : {
2068 : ForeignTruncateInfo *ft_info;
2069 : HASH_SEQ_STATUS seq;
2070 :
2071 30 : hash_seq_init(&seq, ft_htab);
2072 :
2073 30 : PG_TRY();
2074 : {
2075 52 : while ((ft_info = hash_seq_search(&seq)) != NULL)
2076 : {
2077 30 : FdwRoutine *routine = GetFdwRoutineByServerId(ft_info->serverid);
2078 :
2079 : /* truncate_check_rel() has checked that already */
2080 : Assert(routine->ExecForeignTruncate != NULL);
2081 :
2082 30 : routine->ExecForeignTruncate(ft_info->rels,
2083 : behavior,
2084 : restart_seqs);
2085 : }
2086 : }
2087 8 : PG_FINALLY();
2088 : {
2089 30 : hash_destroy(ft_htab);
2090 : }
2091 30 : PG_END_TRY();
2092 : }
2093 :
2094 : /*
2095 : * Restart owned sequences if we were asked to.
2096 : */
2097 1266 : foreach(cell, seq_relids)
2098 : {
2099 36 : Oid seq_relid = lfirst_oid(cell);
2100 :
2101 36 : ResetSequence(seq_relid);
2102 : }
2103 :
2104 : /*
2105 : * Write a WAL record to allow this set of actions to be logically
2106 : * decoded.
2107 : *
2108 : * Assemble an array of relids so we can write a single WAL record for the
2109 : * whole action.
2110 : */
2111 1230 : if (relids_logged != NIL)
2112 : {
2113 : xl_heap_truncate xlrec;
2114 94 : int i = 0;
2115 :
2116 : /* should only get here if wal_level >= logical */
2117 : Assert(XLogLogicalInfoActive());
2118 :
2119 94 : logrelids = palloc(list_length(relids_logged) * sizeof(Oid));
2120 266 : foreach(cell, relids_logged)
2121 172 : logrelids[i++] = lfirst_oid(cell);
2122 :
2123 94 : xlrec.dbId = MyDatabaseId;
2124 94 : xlrec.nrelids = list_length(relids_logged);
2125 94 : xlrec.flags = 0;
2126 94 : if (behavior == DROP_CASCADE)
2127 2 : xlrec.flags |= XLH_TRUNCATE_CASCADE;
2128 94 : if (restart_seqs)
2129 6 : xlrec.flags |= XLH_TRUNCATE_RESTART_SEQS;
2130 :
2131 94 : XLogBeginInsert();
2132 94 : XLogRegisterData((char *) &xlrec, SizeOfHeapTruncate);
2133 94 : XLogRegisterData((char *) logrelids, list_length(relids_logged) * sizeof(Oid));
2134 :
2135 94 : XLogSetRecordFlags(XLOG_INCLUDE_ORIGIN);
2136 :
2137 94 : (void) XLogInsert(RM_HEAP_ID, XLOG_HEAP_TRUNCATE);
2138 : }
2139 :
2140 : /*
2141 : * Process all AFTER STATEMENT TRUNCATE triggers.
2142 : */
2143 1230 : resultRelInfo = resultRelInfos;
2144 4342 : foreach(cell, rels)
2145 : {
2146 : UserContext ucxt;
2147 :
2148 3112 : if (run_as_table_owner)
2149 66 : SwitchToUntrustedUser(resultRelInfo->ri_RelationDesc->rd_rel->relowner,
2150 : &ucxt);
2151 3112 : ExecASTruncateTriggers(estate, resultRelInfo);
2152 3112 : if (run_as_table_owner)
2153 66 : RestoreUserContext(&ucxt);
2154 3112 : resultRelInfo++;
2155 : }
2156 :
2157 : /* Handle queued AFTER triggers */
2158 1230 : AfterTriggerEndQuery(estate);
2159 :
2160 : /* We can clean up the EState now */
2161 1230 : FreeExecutorState(estate);
2162 :
2163 : /*
2164 : * Close any rels opened by CASCADE (can't do this while EState still
2165 : * holds refs)
2166 : */
2167 1230 : rels = list_difference_ptr(rels, explicit_rels);
2168 1324 : foreach(cell, rels)
2169 : {
2170 94 : Relation rel = (Relation) lfirst(cell);
2171 :
2172 94 : table_close(rel, NoLock);
2173 : }
2174 1230 : }
2175 :
2176 : /*
2177 : * Check that a given relation is safe to truncate. Subroutine for
2178 : * ExecuteTruncate() and RangeVarCallbackForTruncate().
2179 : */
2180 : static void
2181 3328 : truncate_check_rel(Oid relid, Form_pg_class reltuple)
2182 : {
2183 3328 : char *relname = NameStr(reltuple->relname);
2184 :
2185 : /*
2186 : * Only allow truncate on regular tables, foreign tables using foreign
2187 : * data wrappers supporting TRUNCATE and partitioned tables (although, the
2188 : * latter are only being included here for the following checks; no
2189 : * physical truncation will occur in their case.).
2190 : */
2191 3328 : if (reltuple->relkind == RELKIND_FOREIGN_TABLE)
2192 : {
2193 36 : Oid serverid = GetForeignServerIdByRelId(relid);
2194 36 : FdwRoutine *fdwroutine = GetFdwRoutineByServerId(serverid);
2195 :
2196 36 : if (!fdwroutine->ExecForeignTruncate)
2197 2 : ereport(ERROR,
2198 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2199 : errmsg("cannot truncate foreign table \"%s\"",
2200 : relname)));
2201 : }
2202 3292 : else if (reltuple->relkind != RELKIND_RELATION &&
2203 660 : reltuple->relkind != RELKIND_PARTITIONED_TABLE)
2204 0 : ereport(ERROR,
2205 : (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2206 : errmsg("\"%s\" is not a table", relname)));
2207 :
2208 : /*
2209 : * Most system catalogs can't be truncated at all, or at least not unless
2210 : * allow_system_table_mods=on. As an exception, however, we allow
2211 : * pg_largeobject to be truncated as part of pg_upgrade, because we need
2212 : * to change its relfilenode to match the old cluster, and allowing a
2213 : * TRUNCATE command to be executed is the easiest way of doing that.
2214 : */
2215 3326 : if (!allowSystemTableMods && IsSystemClass(relid, reltuple)
2216 14 : && (!IsBinaryUpgrade || relid != LargeObjectRelationId))
2217 2 : ereport(ERROR,
2218 : (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
2219 : errmsg("permission denied: \"%s\" is a system catalog",
2220 : relname)));
2221 :
2222 3324 : InvokeObjectTruncateHook(relid);
2223 3324 : }
2224 :
2225 : /*
2226 : * Check that current user has the permission to truncate given relation.
2227 : */
2228 : static void
2229 1696 : truncate_check_perms(Oid relid, Form_pg_class reltuple)
2230 : {
2231 1696 : char *relname = NameStr(reltuple->relname);
2232 : AclResult aclresult;
2233 :
2234 : /* Permissions checks */
2235 1696 : aclresult = pg_class_aclcheck(relid, GetUserId(), ACL_TRUNCATE);
2236 1696 : if (aclresult != ACLCHECK_OK)
2237 32 : aclcheck_error(aclresult, get_relkind_objtype(reltuple->relkind),
2238 : relname);
2239 1664 : }
2240 :
2241 : /*
2242 : * Set of extra sanity checks to check if a given relation is safe to
2243 : * truncate. This is split with truncate_check_rel() as
2244 : * RangeVarCallbackForTruncate() cannot open a Relation yet.
2245 : */
2246 : static void
2247 3212 : truncate_check_activity(Relation rel)
2248 : {
2249 : /*
2250 : * Don't allow truncate on temp tables of other backends ... their local
2251 : * buffer manager is not going to cope.
2252 : */
2253 3212 : if (RELATION_IS_OTHER_TEMP(rel))
2254 0 : ereport(ERROR,
2255 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2256 : errmsg("cannot truncate temporary tables of other sessions")));
2257 :
2258 : /*
2259 : * Also check for active uses of the relation in the current transaction,
2260 : * including open scans and pending AFTER trigger events.
2261 : */
2262 3212 : CheckTableNotInUse(rel, "TRUNCATE");
2263 3212 : }
2264 :
2265 : /*
2266 : * storage_name
2267 : * returns the name corresponding to a typstorage/attstorage enum value
2268 : */
2269 : static const char *
2270 24 : storage_name(char c)
2271 : {
2272 24 : switch (c)
2273 : {
2274 0 : case TYPSTORAGE_PLAIN:
2275 0 : return "PLAIN";
2276 0 : case TYPSTORAGE_EXTERNAL:
2277 0 : return "EXTERNAL";
2278 12 : case TYPSTORAGE_EXTENDED:
2279 12 : return "EXTENDED";
2280 12 : case TYPSTORAGE_MAIN:
2281 12 : return "MAIN";
2282 0 : default:
2283 0 : return "???";
2284 : }
2285 : }
2286 :
2287 : /*----------
2288 : * MergeAttributes
2289 : * Returns new schema given initial schema and superclasses.
2290 : *
2291 : * Input arguments:
2292 : * 'schema' is the column/attribute definition for the table. (It's a list
2293 : * of ColumnDef's.) It is destructively changed.
2294 : * 'supers' is a list of OIDs of parent relations, already locked by caller.
2295 : * 'relpersistence' is the persistence type of the table.
2296 : * 'is_partition' tells if the table is a partition.
2297 : *
2298 : * Output arguments:
2299 : * 'supconstr' receives a list of constraints belonging to the parents,
2300 : * updated as necessary to be valid for the child.
2301 : *
2302 : * Return value:
2303 : * Completed schema list.
2304 : *
2305 : * Notes:
2306 : * The order in which the attributes are inherited is very important.
2307 : * Intuitively, the inherited attributes should come first. If a table
2308 : * inherits from multiple parents, the order of those attributes are
2309 : * according to the order of the parents specified in CREATE TABLE.
2310 : *
2311 : * Here's an example:
2312 : *
2313 : * create table person (name text, age int4, location point);
2314 : * create table emp (salary int4, manager text) inherits(person);
2315 : * create table student (gpa float8) inherits (person);
2316 : * create table stud_emp (percent int4) inherits (emp, student);
2317 : *
2318 : * The order of the attributes of stud_emp is:
2319 : *
2320 : * person {1:name, 2:age, 3:location}
2321 : * / \
2322 : * {6:gpa} student emp {4:salary, 5:manager}
2323 : * \ /
2324 : * stud_emp {7:percent}
2325 : *
2326 : * If the same attribute name appears multiple times, then it appears
2327 : * in the result table in the proper location for its first appearance.
2328 : *
2329 : * Constraints (including NOT NULL constraints) for the child table
2330 : * are the union of all relevant constraints, from both the child schema
2331 : * and parent tables.
2332 : *
2333 : * The default value for a child column is defined as:
2334 : * (1) If the child schema specifies a default, that value is used.
2335 : * (2) If neither the child nor any parent specifies a default, then
2336 : * the column will not have a default.
2337 : * (3) If conflicting defaults are inherited from different parents
2338 : * (and not overridden by the child), an error is raised.
2339 : * (4) Otherwise the inherited default is used.
2340 : *
2341 : * Note that the default-value infrastructure is used for generated
2342 : * columns' expressions too, so most of the preceding paragraph applies
2343 : * to generation expressions too. We insist that a child column be
2344 : * generated if and only if its parent(s) are, but it need not have
2345 : * the same generation expression.
2346 : *----------
2347 : */
2348 : static List *
2349 125132 : MergeAttributes(List *schema, List *supers, char relpersistence,
2350 : bool is_partition, List **supconstr)
2351 : {
2352 125132 : List *inhSchema = NIL;
2353 125132 : List *constraints = NIL;
2354 125132 : bool have_bogus_defaults = false;
2355 : int child_attno;
2356 : static Node bogus_marker = {0}; /* marks conflicting defaults */
2357 125132 : List *saved_schema = NIL;
2358 : ListCell *entry;
2359 :
2360 : /*
2361 : * Check for and reject tables with too many columns. We perform this
2362 : * check relatively early for two reasons: (a) we don't run the risk of
2363 : * overflowing an AttrNumber in subsequent code (b) an O(n^2) algorithm is
2364 : * okay if we're processing <= 1600 columns, but could take minutes to
2365 : * execute if the user attempts to create a table with hundreds of
2366 : * thousands of columns.
2367 : *
2368 : * Note that we also need to check that we do not exceed this figure after
2369 : * including columns from inherited relations.
2370 : */
2371 125132 : if (list_length(schema) > MaxHeapAttributeNumber)
2372 0 : ereport(ERROR,
2373 : (errcode(ERRCODE_TOO_MANY_COLUMNS),
2374 : errmsg("tables can have at most %d columns",
2375 : MaxHeapAttributeNumber)));
2376 :
2377 : /*
2378 : * Check for duplicate names in the explicit list of attributes.
2379 : *
2380 : * Although we might consider merging such entries in the same way that we
2381 : * handle name conflicts for inherited attributes, it seems to make more
2382 : * sense to assume such conflicts are errors.
2383 : *
2384 : * We don't use foreach() here because we have two nested loops over the
2385 : * schema list, with possible element deletions in the inner one. If we
2386 : * used foreach_delete_current() it could only fix up the state of one of
2387 : * the loops, so it seems cleaner to use looping over list indexes for
2388 : * both loops. Note that any deletion will happen beyond where the outer
2389 : * loop is, so its index never needs adjustment.
2390 : */
2391 1078102 : for (int coldefpos = 0; coldefpos < list_length(schema); coldefpos++)
2392 : {
2393 952994 : ColumnDef *coldef = list_nth_node(ColumnDef, schema, coldefpos);
2394 :
2395 952994 : if (!is_partition && coldef->typeName == NULL)
2396 : {
2397 : /*
2398 : * Typed table column option that does not belong to a column from
2399 : * the type. This works because the columns from the type come
2400 : * first in the list. (We omit this check for partition column
2401 : * lists; those are processed separately below.)
2402 : */
2403 6 : ereport(ERROR,
2404 : (errcode(ERRCODE_UNDEFINED_COLUMN),
2405 : errmsg("column \"%s\" does not exist",
2406 : coldef->colname)));
2407 : }
2408 :
2409 : /* restpos scans all entries beyond coldef; incr is in loop body */
2410 13470146 : for (int restpos = coldefpos + 1; restpos < list_length(schema);)
2411 : {
2412 12517176 : ColumnDef *restdef = list_nth_node(ColumnDef, schema, restpos);
2413 :
2414 12517176 : if (strcmp(coldef->colname, restdef->colname) == 0)
2415 : {
2416 50 : if (coldef->is_from_type)
2417 : {
2418 : /*
2419 : * merge the column options into the column from the type
2420 : */
2421 32 : coldef->is_not_null = restdef->is_not_null;
2422 32 : coldef->raw_default = restdef->raw_default;
2423 32 : coldef->cooked_default = restdef->cooked_default;
2424 32 : coldef->constraints = restdef->constraints;
2425 32 : coldef->is_from_type = false;
2426 32 : schema = list_delete_nth_cell(schema, restpos);
2427 : }
2428 : else
2429 18 : ereport(ERROR,
2430 : (errcode(ERRCODE_DUPLICATE_COLUMN),
2431 : errmsg("column \"%s\" specified more than once",
2432 : coldef->colname)));
2433 : }
2434 : else
2435 12517126 : restpos++;
2436 : }
2437 : }
2438 :
2439 : /*
2440 : * In case of a partition, there are no new column definitions, only dummy
2441 : * ColumnDefs created for column constraints. Set them aside for now and
2442 : * process them at the end.
2443 : */
2444 125108 : if (is_partition)
2445 : {
2446 7252 : saved_schema = schema;
2447 7252 : schema = NIL;
2448 : }
2449 :
2450 : /*
2451 : * Scan the parents left-to-right, and merge their attributes to form a
2452 : * list of inherited attributes (inhSchema). Also check to see if we need
2453 : * to inherit an OID column.
2454 : */
2455 125108 : child_attno = 0;
2456 133926 : foreach(entry, supers)
2457 : {
2458 8890 : Oid parent = lfirst_oid(entry);
2459 : Relation relation;
2460 : TupleDesc tupleDesc;
2461 : TupleConstr *constr;
2462 : AttrMap *newattmap;
2463 : List *inherited_defaults;
2464 : List *cols_with_defaults;
2465 : AttrNumber parent_attno;
2466 : ListCell *lc1;
2467 : ListCell *lc2;
2468 :
2469 : /* caller already got lock */
2470 8890 : relation = table_open(parent, NoLock);
2471 :
2472 : /*
2473 : * Check for active uses of the parent partitioned table in the
2474 : * current transaction, such as being used in some manner by an
2475 : * enclosing command.
2476 : */
2477 8890 : if (is_partition)
2478 7252 : CheckTableNotInUse(relation, "CREATE TABLE .. PARTITION OF");
2479 :
2480 : /*
2481 : * We do not allow partitioned tables and partitions to participate in
2482 : * regular inheritance.
2483 : */
2484 8884 : if (relation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE &&
2485 7240 : !is_partition)
2486 6 : ereport(ERROR,
2487 : (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2488 : errmsg("cannot inherit from partitioned table \"%s\"",
2489 : RelationGetRelationName(relation))));
2490 8878 : if (relation->rd_rel->relispartition && !is_partition)
2491 6 : ereport(ERROR,
2492 : (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2493 : errmsg("cannot inherit from partition \"%s\"",
2494 : RelationGetRelationName(relation))));
2495 :
2496 8872 : if (relation->rd_rel->relkind != RELKIND_RELATION &&
2497 7254 : relation->rd_rel->relkind != RELKIND_FOREIGN_TABLE &&
2498 7234 : relation->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
2499 0 : ereport(ERROR,
2500 : (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2501 : errmsg("inherited relation \"%s\" is not a table or foreign table",
2502 : RelationGetRelationName(relation))));
2503 :
2504 : /*
2505 : * If the parent is permanent, so must be all of its partitions. Note
2506 : * that inheritance allows that case.
2507 : */
2508 8872 : if (is_partition &&
2509 7246 : relation->rd_rel->relpersistence != RELPERSISTENCE_TEMP &&
2510 : relpersistence == RELPERSISTENCE_TEMP)
2511 6 : ereport(ERROR,
2512 : (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2513 : errmsg("cannot create a temporary relation as partition of permanent relation \"%s\"",
2514 : RelationGetRelationName(relation))));
2515 :
2516 : /* Permanent rels cannot inherit from temporary ones */
2517 8866 : if (relpersistence != RELPERSISTENCE_TEMP &&
2518 8524 : relation->rd_rel->relpersistence == RELPERSISTENCE_TEMP)
2519 24 : ereport(ERROR,
2520 : (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2521 : errmsg(!is_partition
2522 : ? "cannot inherit from temporary relation \"%s\""
2523 : : "cannot create a permanent relation as partition of temporary relation \"%s\"",
2524 : RelationGetRelationName(relation))));
2525 :
2526 : /* If existing rel is temp, it must belong to this session */
2527 8842 : if (relation->rd_rel->relpersistence == RELPERSISTENCE_TEMP &&
2528 294 : !relation->rd_islocaltemp)
2529 0 : ereport(ERROR,
2530 : (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2531 : errmsg(!is_partition
2532 : ? "cannot inherit from temporary relation of another session"
2533 : : "cannot create as partition of temporary relation of another session")));
2534 :
2535 : /*
2536 : * We should have an UNDER permission flag for this, but for now,
2537 : * demand that creator of a child table own the parent.
2538 : */
2539 8842 : if (!object_ownercheck(RelationRelationId, RelationGetRelid(relation), GetUserId()))
2540 0 : aclcheck_error(ACLCHECK_NOT_OWNER, get_relkind_objtype(relation->rd_rel->relkind),
2541 0 : RelationGetRelationName(relation));
2542 :
2543 8842 : tupleDesc = RelationGetDescr(relation);
2544 8842 : constr = tupleDesc->constr;
2545 :
2546 : /*
2547 : * newattmap->attnums[] will contain the child-table attribute numbers
2548 : * for the attributes of this parent table. (They are not the same
2549 : * for parents after the first one, nor if we have dropped columns.)
2550 : */
2551 8842 : newattmap = make_attrmap(tupleDesc->natts);
2552 :
2553 : /* We can't process inherited defaults until newattmap is complete. */
2554 8842 : inherited_defaults = cols_with_defaults = NIL;
2555 :
2556 26826 : for (parent_attno = 1; parent_attno <= tupleDesc->natts;
2557 17984 : parent_attno++)
2558 : {
2559 18008 : Form_pg_attribute attribute = TupleDescAttr(tupleDesc,
2560 : parent_attno - 1);
2561 18008 : char *attributeName = NameStr(attribute->attname);
2562 : int exist_attno;
2563 : ColumnDef *def;
2564 :
2565 : /*
2566 : * Ignore dropped columns in the parent.
2567 : */
2568 18008 : if (attribute->attisdropped)
2569 192 : continue; /* leave newattmap->attnums entry as zero */
2570 :
2571 : /*
2572 : * Does it conflict with some previously inherited column?
2573 : */
2574 17816 : exist_attno = findAttrByName(attributeName, inhSchema);
2575 17816 : if (exist_attno > 0)
2576 : {
2577 : Oid defTypeId;
2578 : int32 deftypmod;
2579 : Oid defCollId;
2580 :
2581 : /*
2582 : * Yes, try to merge the two column definitions.
2583 : */
2584 194 : ereport(NOTICE,
2585 : (errmsg("merging multiple inherited definitions of column \"%s\"",
2586 : attributeName)));
2587 194 : def = (ColumnDef *) list_nth(inhSchema, exist_attno - 1);
2588 :
2589 : /*
2590 : * Must have the same type and typmod
2591 : */
2592 194 : typenameTypeIdAndMod(NULL, def->typeName, &defTypeId, &deftypmod);
2593 194 : if (defTypeId != attribute->atttypid ||
2594 194 : deftypmod != attribute->atttypmod)
2595 0 : ereport(ERROR,
2596 : (errcode(ERRCODE_DATATYPE_MISMATCH),
2597 : errmsg("inherited column \"%s\" has a type conflict",
2598 : attributeName),
2599 : errdetail("%s versus %s",
2600 : format_type_with_typemod(defTypeId,
2601 : deftypmod),
2602 : format_type_with_typemod(attribute->atttypid,
2603 : attribute->atttypmod))));
2604 :
2605 : /*
2606 : * Must have the same collation
2607 : */
2608 194 : defCollId = GetColumnDefCollation(NULL, def, defTypeId);
2609 194 : if (defCollId != attribute->attcollation)
2610 0 : ereport(ERROR,
2611 : (errcode(ERRCODE_COLLATION_MISMATCH),
2612 : errmsg("inherited column \"%s\" has a collation conflict",
2613 : attributeName),
2614 : errdetail("\"%s\" versus \"%s\"",
2615 : get_collation_name(defCollId),
2616 : get_collation_name(attribute->attcollation))));
2617 :
2618 : /*
2619 : * Copy/check storage parameter
2620 : */
2621 194 : if (def->storage == 0)
2622 0 : def->storage = attribute->attstorage;
2623 194 : else if (def->storage != attribute->attstorage)
2624 6 : ereport(ERROR,
2625 : (errcode(ERRCODE_DATATYPE_MISMATCH),
2626 : errmsg("inherited column \"%s\" has a storage parameter conflict",
2627 : attributeName),
2628 : errdetail("%s versus %s",
2629 : storage_name(def->storage),
2630 : storage_name(attribute->attstorage))));
2631 :
2632 : /*
2633 : * Copy/check compression parameter
2634 : */
2635 188 : if (CompressionMethodIsValid(attribute->attcompression))
2636 : {
2637 : const char *compression =
2638 6 : GetCompressionMethodName(attribute->attcompression);
2639 :
2640 6 : if (def->compression == NULL)
2641 0 : def->compression = pstrdup(compression);
2642 6 : else if (strcmp(def->compression, compression) != 0)
2643 6 : ereport(ERROR,
2644 : (errcode(ERRCODE_DATATYPE_MISMATCH),
2645 : errmsg("column \"%s\" has a compression method conflict",
2646 : attributeName),
2647 : errdetail("%s versus %s", def->compression, compression)));
2648 : }
2649 :
2650 : /*
2651 : * Merge of NOT NULL constraints = OR 'em together
2652 : */
2653 182 : def->is_not_null |= attribute->attnotnull;
2654 :
2655 : /*
2656 : * Check for GENERATED conflicts
2657 : */
2658 182 : if (def->generated != attribute->attgenerated)
2659 12 : ereport(ERROR,
2660 : (errcode(ERRCODE_DATATYPE_MISMATCH),
2661 : errmsg("inherited column \"%s\" has a generation conflict",
2662 : attributeName)));
2663 :
2664 : /*
2665 : * Default and other constraints are handled below
2666 : */
2667 :
2668 170 : def->inhcount++;
2669 170 : if (def->inhcount < 0)
2670 0 : ereport(ERROR,
2671 : errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
2672 : errmsg("too many inheritance parents"));
2673 :
2674 170 : newattmap->attnums[parent_attno - 1] = exist_attno;
2675 : }
2676 : else
2677 : {
2678 : /*
2679 : * No, create a new inherited column
2680 : */
2681 17622 : def = makeNode(ColumnDef);
2682 17622 : def->colname = pstrdup(attributeName);
2683 17622 : def->typeName = makeTypeNameFromOid(attribute->atttypid,
2684 : attribute->atttypmod);
2685 17622 : def->inhcount = 1;
2686 17622 : def->is_local = false;
2687 17622 : def->is_not_null = attribute->attnotnull;
2688 17622 : def->is_from_type = false;
2689 17622 : def->storage = attribute->attstorage;
2690 17622 : def->raw_default = NULL;
2691 17622 : def->cooked_default = NULL;
2692 17622 : def->generated = attribute->attgenerated;
2693 17622 : def->collClause = NULL;
2694 17622 : def->collOid = attribute->attcollation;
2695 17622 : def->constraints = NIL;
2696 17622 : def->location = -1;
2697 17622 : if (CompressionMethodIsValid(attribute->attcompression))
2698 18 : def->compression =
2699 18 : pstrdup(GetCompressionMethodName(attribute->attcompression));
2700 : else
2701 17604 : def->compression = NULL;
2702 17622 : inhSchema = lappend(inhSchema, def);
2703 17622 : newattmap->attnums[parent_attno - 1] = ++child_attno;
2704 : }
2705 :
2706 : /*
2707 : * Locate default/generation expression if any
2708 : */
2709 17792 : if (attribute->atthasdef)
2710 : {
2711 532 : Node *this_default = NULL;
2712 :
2713 : /* Find default in constraint structure */
2714 532 : if (constr != NULL)
2715 : {
2716 532 : AttrDefault *attrdef = constr->defval;
2717 :
2718 580 : for (int i = 0; i < constr->num_defval; i++)
2719 : {
2720 580 : if (attrdef[i].adnum == parent_attno)
2721 : {
2722 532 : this_default = stringToNode(attrdef[i].adbin);
2723 532 : break;
2724 : }
2725 : }
2726 : }
2727 532 : if (this_default == NULL)
2728 0 : elog(ERROR, "default expression not found for attribute %d of relation \"%s\"",
2729 : parent_attno, RelationGetRelationName(relation));
2730 :
2731 : /*
2732 : * If it's a GENERATED default, it might contain Vars that
2733 : * need to be mapped to the inherited column(s)' new numbers.
2734 : * We can't do that till newattmap is ready, so just remember
2735 : * all the inherited default expressions for the moment.
2736 : */
2737 532 : inherited_defaults = lappend(inherited_defaults, this_default);
2738 532 : cols_with_defaults = lappend(cols_with_defaults, def);
2739 : }
2740 : }
2741 :
2742 : /*
2743 : * Now process any inherited default expressions, adjusting attnos
2744 : * using the completed newattmap map.
2745 : */
2746 9350 : forboth(lc1, inherited_defaults, lc2, cols_with_defaults)
2747 : {
2748 532 : Node *this_default = (Node *) lfirst(lc1);
2749 532 : ColumnDef *def = (ColumnDef *) lfirst(lc2);
2750 : bool found_whole_row;
2751 :
2752 : /* Adjust Vars to match new table's column numbering */
2753 532 : this_default = map_variable_attnos(this_default,
2754 : 1, 0,
2755 : newattmap,
2756 : InvalidOid, &found_whole_row);
2757 :
2758 : /*
2759 : * For the moment we have to reject whole-row variables. We could
2760 : * convert them, if we knew the new table's rowtype OID, but that
2761 : * hasn't been assigned yet. (A variable could only appear in a
2762 : * generation expression, so the error message is correct.)
2763 : */
2764 532 : if (found_whole_row)
2765 0 : ereport(ERROR,
2766 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2767 : errmsg("cannot convert whole-row table reference"),
2768 : errdetail("Generation expression for column \"%s\" contains a whole-row reference to table \"%s\".",
2769 : def->colname,
2770 : RelationGetRelationName(relation))));
2771 :
2772 : /*
2773 : * If we already had a default from some prior parent, check to
2774 : * see if they are the same. If so, no problem; if not, mark the
2775 : * column as having a bogus default. Below, we will complain if
2776 : * the bogus default isn't overridden by the child schema.
2777 : */
2778 : Assert(def->raw_default == NULL);
2779 532 : if (def->cooked_default == NULL)
2780 502 : def->cooked_default = this_default;
2781 30 : else if (!equal(def->cooked_default, this_default))
2782 : {
2783 24 : def->cooked_default = &bogus_marker;
2784 24 : have_bogus_defaults = true;
2785 : }
2786 : }
2787 :
2788 : /*
2789 : * Now copy the CHECK constraints of this parent, adjusting attnos
2790 : * using the completed newattmap map. Identically named constraints
2791 : * are merged if possible, else we throw error.
2792 : */
2793 8818 : if (constr && constr->num_check > 0)
2794 : {
2795 196 : ConstrCheck *check = constr->check;
2796 : int i;
2797 :
2798 422 : for (i = 0; i < constr->num_check; i++)
2799 : {
2800 226 : char *name = check[i].ccname;
2801 : Node *expr;
2802 : bool found_whole_row;
2803 :
2804 : /* ignore if the constraint is non-inheritable */
2805 226 : if (check[i].ccnoinherit)
2806 42 : continue;
2807 :
2808 : /* Adjust Vars to match new table's column numbering */
2809 184 : expr = map_variable_attnos(stringToNode(check[i].ccbin),
2810 : 1, 0,
2811 : newattmap,
2812 : InvalidOid, &found_whole_row);
2813 :
2814 : /*
2815 : * For the moment we have to reject whole-row variables. We
2816 : * could convert them, if we knew the new table's rowtype OID,
2817 : * but that hasn't been assigned yet.
2818 : */
2819 184 : if (found_whole_row)
2820 0 : ereport(ERROR,
2821 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2822 : errmsg("cannot convert whole-row table reference"),
2823 : errdetail("Constraint \"%s\" contains a whole-row reference to table \"%s\".",
2824 : name,
2825 : RelationGetRelationName(relation))));
2826 :
2827 : /* check for duplicate */
2828 184 : if (!MergeCheckConstraint(constraints, name, expr))
2829 : {
2830 : /* nope, this is a new one */
2831 : CookedConstraint *cooked;
2832 :
2833 172 : cooked = (CookedConstraint *) palloc(sizeof(CookedConstraint));
2834 172 : cooked->contype = CONSTR_CHECK;
2835 172 : cooked->conoid = InvalidOid; /* until created */
2836 172 : cooked->name = pstrdup(name);
2837 172 : cooked->attnum = 0; /* not used for constraints */
2838 172 : cooked->expr = expr;
2839 172 : cooked->skip_validation = false;
2840 172 : cooked->is_local = false;
2841 172 : cooked->inhcount = 1;
2842 172 : cooked->is_no_inherit = false;
2843 172 : constraints = lappend(constraints, cooked);
2844 : }
2845 : }
2846 : }
2847 :
2848 8818 : free_attrmap(newattmap);
2849 :
2850 : /*
2851 : * Close the parent rel, but keep our lock on it until xact commit.
2852 : * That will prevent someone else from deleting or ALTERing the parent
2853 : * before the child is committed.
2854 : */
2855 8818 : table_close(relation, NoLock);
2856 : }
2857 :
2858 : /*
2859 : * If we had no inherited attributes, the result schema is just the
2860 : * explicitly declared columns. Otherwise, we need to merge the declared
2861 : * columns into the inherited schema list. Although, we never have any
2862 : * explicitly declared columns if the table is a partition.
2863 : */
2864 125036 : if (inhSchema != NIL)
2865 : {
2866 8624 : int schema_attno = 0;
2867 :
2868 9336 : foreach(entry, schema)
2869 : {
2870 760 : ColumnDef *newdef = lfirst(entry);
2871 760 : char *attributeName = newdef->colname;
2872 : int exist_attno;
2873 :
2874 760 : schema_attno++;
2875 :
2876 : /*
2877 : * Does it conflict with some previously inherited column?
2878 : */
2879 760 : exist_attno = findAttrByName(attributeName, inhSchema);
2880 760 : if (exist_attno > 0)
2881 : {
2882 : ColumnDef *def;
2883 : Oid defTypeId,
2884 : newTypeId;
2885 : int32 deftypmod,
2886 : newtypmod;
2887 : Oid defcollid,
2888 : newcollid;
2889 :
2890 : /*
2891 : * Partitions have only one parent and have no column
2892 : * definitions of their own, so conflict should never occur.
2893 : */
2894 : Assert(!is_partition);
2895 :
2896 : /*
2897 : * Yes, try to merge the two column definitions.
2898 : */
2899 226 : if (exist_attno == schema_attno)
2900 204 : ereport(NOTICE,
2901 : (errmsg("merging column \"%s\" with inherited definition",
2902 : attributeName)));
2903 : else
2904 22 : ereport(NOTICE,
2905 : (errmsg("moving and merging column \"%s\" with inherited definition", attributeName),
2906 : errdetail("User-specified column moved to the position of the inherited column.")));
2907 226 : def = (ColumnDef *) list_nth(inhSchema, exist_attno - 1);
2908 :
2909 : /*
2910 : * Must have the same type and typmod
2911 : */
2912 226 : typenameTypeIdAndMod(NULL, def->typeName, &defTypeId, &deftypmod);
2913 226 : typenameTypeIdAndMod(NULL, newdef->typeName, &newTypeId, &newtypmod);
2914 226 : if (defTypeId != newTypeId || deftypmod != newtypmod)
2915 12 : ereport(ERROR,
2916 : (errcode(ERRCODE_DATATYPE_MISMATCH),
2917 : errmsg("column \"%s\" has a type conflict",
2918 : attributeName),
2919 : errdetail("%s versus %s",
2920 : format_type_with_typemod(defTypeId,
2921 : deftypmod),
2922 : format_type_with_typemod(newTypeId,
2923 : newtypmod))));
2924 :
2925 : /*
2926 : * Must have the same collation
2927 : */
2928 214 : defcollid = GetColumnDefCollation(NULL, def, defTypeId);
2929 214 : newcollid = GetColumnDefCollation(NULL, newdef, newTypeId);
2930 214 : if (defcollid != newcollid)
2931 6 : ereport(ERROR,
2932 : (errcode(ERRCODE_COLLATION_MISMATCH),
2933 : errmsg("column \"%s\" has a collation conflict",
2934 : attributeName),
2935 : errdetail("\"%s\" versus \"%s\"",
2936 : get_collation_name(defcollid),
2937 : get_collation_name(newcollid))));
2938 :
2939 : /*
2940 : * Identity is never inherited. The new column can have an
2941 : * identity definition, so we always just take that one.
2942 : */
2943 208 : def->identity = newdef->identity;
2944 :
2945 : /*
2946 : * Copy storage parameter
2947 : */
2948 208 : if (def->storage == 0)
2949 0 : def->storage = newdef->storage;
2950 208 : else if (newdef->storage != 0 && def->storage != newdef->storage)
2951 6 : ereport(ERROR,
2952 : (errcode(ERRCODE_DATATYPE_MISMATCH),
2953 : errmsg("column \"%s\" has a storage parameter conflict",
2954 : attributeName),
2955 : errdetail("%s versus %s",
2956 : storage_name(def->storage),
2957 : storage_name(newdef->storage))));
2958 :
2959 : /*
2960 : * Copy compression parameter
2961 : */
2962 202 : if (def->compression == NULL)
2963 196 : def->compression = newdef->compression;
2964 6 : else if (newdef->compression != NULL)
2965 : {
2966 6 : if (strcmp(def->compression, newdef->compression) != 0)
2967 6 : ereport(ERROR,
2968 : (errcode(ERRCODE_DATATYPE_MISMATCH),
2969 : errmsg("column \"%s\" has a compression method conflict",
2970 : attributeName),
2971 : errdetail("%s versus %s", def->compression, newdef->compression)));
2972 : }
2973 :
2974 : /*
2975 : * Merge of NOT NULL constraints = OR 'em together
2976 : */
2977 196 : def->is_not_null |= newdef->is_not_null;
2978 :
2979 : /*
2980 : * Check for conflicts related to generated columns.
2981 : *
2982 : * If the parent column is generated, the child column will be
2983 : * made a generated column if it isn't already. If it is a
2984 : * generated column, we'll take its generation expression in
2985 : * preference to the parent's. We must check that the child
2986 : * column doesn't specify a default value or identity, which
2987 : * matches the rules for a single column in parse_utilcmd.c.
2988 : *
2989 : * Conversely, if the parent column is not generated, the
2990 : * child column can't be either. (We used to allow that, but
2991 : * it results in being able to override the generation
2992 : * expression via UPDATEs through the parent.)
2993 : */
2994 196 : if (def->generated)
2995 : {
2996 26 : if (newdef->raw_default && !newdef->generated)
2997 6 : ereport(ERROR,
2998 : (errcode(ERRCODE_INVALID_COLUMN_DEFINITION),
2999 : errmsg("column \"%s\" inherits from generated column but specifies default",
3000 : def->colname)));
3001 20 : if (newdef->identity)
3002 6 : ereport(ERROR,
3003 : (errcode(ERRCODE_INVALID_COLUMN_DEFINITION),
3004 : errmsg("column \"%s\" inherits from generated column but specifies identity",
3005 : def->colname)));
3006 : }
3007 : else
3008 : {
3009 170 : if (newdef->generated)
3010 6 : ereport(ERROR,
3011 : (errcode(ERRCODE_INVALID_COLUMN_DEFINITION),
3012 : errmsg("child column \"%s\" specifies generation expression",
3013 : def->colname),
3014 : errhint("A child table column cannot be generated unless its parent column is.")));
3015 : }
3016 :
3017 : /*
3018 : * If new def has a default, override previous default
3019 : */
3020 178 : if (newdef->raw_default != NULL)
3021 : {
3022 18 : def->raw_default = newdef->raw_default;
3023 18 : def->cooked_default = newdef->cooked_default;
3024 : }
3025 :
3026 : /* Mark the column as locally defined */
3027 178 : def->is_local = true;
3028 : }
3029 : else
3030 : {
3031 : /*
3032 : * No, attach new column to result schema
3033 : */
3034 534 : inhSchema = lappend(inhSchema, newdef);
3035 : }
3036 : }
3037 :
3038 8576 : schema = inhSchema;
3039 :
3040 : /*
3041 : * Check that we haven't exceeded the legal # of columns after merging
3042 : * in inherited columns.
3043 : */
3044 8576 : if (list_length(schema) > MaxHeapAttributeNumber)
3045 0 : ereport(ERROR,
3046 : (errcode(ERRCODE_TOO_MANY_COLUMNS),
3047 : errmsg("tables can have at most %d columns",
3048 : MaxHeapAttributeNumber)));
3049 : }
3050 :
3051 : /*
3052 : * Now that we have the column definition list for a partition, we can
3053 : * check whether the columns referenced in the column constraint specs
3054 : * actually exist. Also, we merge parent's NOT NULL constraints and
3055 : * defaults into each corresponding column definition.
3056 : */
3057 124988 : if (is_partition)
3058 : {
3059 7416 : foreach(entry, saved_schema)
3060 : {
3061 206 : ColumnDef *restdef = lfirst(entry);
3062 206 : bool found = false;
3063 : ListCell *l;
3064 :
3065 774 : foreach(l, schema)
3066 : {
3067 580 : ColumnDef *coldef = lfirst(l);
3068 :
3069 580 : if (strcmp(coldef->colname, restdef->colname) == 0)
3070 : {
3071 206 : found = true;
3072 206 : coldef->is_not_null |= restdef->is_not_null;
3073 :
3074 : /*
3075 : * Check for conflicts related to generated columns.
3076 : *
3077 : * Same rules as above: generated-ness has to match the
3078 : * parent, but the contents of the generation expression
3079 : * can be different.
3080 : */
3081 206 : if (coldef->generated)
3082 : {
3083 104 : if (restdef->raw_default && !restdef->generated)
3084 6 : ereport(ERROR,
3085 : (errcode(ERRCODE_INVALID_COLUMN_DEFINITION),
3086 : errmsg("column \"%s\" inherits from generated column but specifies default",
3087 : restdef->colname)));
3088 98 : if (restdef->identity)
3089 0 : ereport(ERROR,
3090 : (errcode(ERRCODE_INVALID_COLUMN_DEFINITION),
3091 : errmsg("column \"%s\" inherits from generated column but specifies identity",
3092 : restdef->colname)));
3093 : }
3094 : else
3095 : {
3096 102 : if (restdef->generated)
3097 6 : ereport(ERROR,
3098 : (errcode(ERRCODE_INVALID_COLUMN_DEFINITION),
3099 : errmsg("child column \"%s\" specifies generation expression",
3100 : restdef->colname),
3101 : errhint("A child table column cannot be generated unless its parent column is.")));
3102 : }
3103 :
3104 : /*
3105 : * Override the parent's default value for this column
3106 : * (coldef->cooked_default) with the partition's local
3107 : * definition (restdef->raw_default), if there's one. It
3108 : * should be physically impossible to get a cooked default
3109 : * in the local definition or a raw default in the
3110 : * inherited definition, but make sure they're nulls, for
3111 : * future-proofing.
3112 : */
3113 : Assert(restdef->cooked_default == NULL);
3114 : Assert(coldef->raw_default == NULL);
3115 194 : if (restdef->raw_default)
3116 : {
3117 122 : coldef->raw_default = restdef->raw_default;
3118 122 : coldef->cooked_default = NULL;
3119 : }
3120 : }
3121 : }
3122 :
3123 : /* complain for constraints on columns not in parent */
3124 194 : if (!found)
3125 0 : ereport(ERROR,
3126 : (errcode(ERRCODE_UNDEFINED_COLUMN),
3127 : errmsg("column \"%s\" does not exist",
3128 : restdef->colname)));
3129 : }
3130 : }
3131 :
3132 : /*
3133 : * If we found any conflicting parent default values, check to make sure
3134 : * they were overridden by the child.
3135 : */
3136 124976 : if (have_bogus_defaults)
3137 : {
3138 54 : foreach(entry, schema)
3139 : {
3140 42 : ColumnDef *def = lfirst(entry);
3141 :
3142 42 : if (def->cooked_default == &bogus_marker)
3143 : {
3144 12 : if (def->generated)
3145 6 : ereport(ERROR,
3146 : (errcode(ERRCODE_INVALID_COLUMN_DEFINITION),
3147 : errmsg("column \"%s\" inherits conflicting generation expressions",
3148 : def->colname),
3149 : errhint("To resolve the conflict, specify a generation expression explicitly.")));
3150 : else
3151 6 : ereport(ERROR,
3152 : (errcode(ERRCODE_INVALID_COLUMN_DEFINITION),
3153 : errmsg("column \"%s\" inherits conflicting default values",
3154 : def->colname),
3155 : errhint("To resolve the conflict, specify a default explicitly.")));
3156 : }
3157 : }
3158 : }
3159 :
3160 124964 : *supconstr = constraints;
3161 124964 : return schema;
3162 : }
3163 :
3164 :
3165 : /*
3166 : * MergeCheckConstraint
3167 : * Try to merge an inherited CHECK constraint with previous ones
3168 : *
3169 : * If we inherit identically-named constraints from multiple parents, we must
3170 : * merge them, or throw an error if they don't have identical definitions.
3171 : *
3172 : * constraints is a list of CookedConstraint structs for previous constraints.
3173 : *
3174 : * Returns true if merged (constraint is a duplicate), or false if it's
3175 : * got a so-far-unique name, or throws error if conflict.
3176 : */
3177 : static bool
3178 184 : MergeCheckConstraint(List *constraints, char *name, Node *expr)
3179 : {
3180 : ListCell *lc;
3181 :
3182 214 : foreach(lc, constraints)
3183 : {
3184 42 : CookedConstraint *ccon = (CookedConstraint *) lfirst(lc);
3185 :
3186 : Assert(ccon->contype == CONSTR_CHECK);
3187 :
3188 : /* Non-matching names never conflict */
3189 42 : if (strcmp(ccon->name, name) != 0)
3190 30 : continue;
3191 :
3192 12 : if (equal(expr, ccon->expr))
3193 : {
3194 : /* OK to merge */
3195 12 : ccon->inhcount++;
3196 12 : if (ccon->inhcount < 0)
3197 0 : ereport(ERROR,
3198 : errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
3199 : errmsg("too many inheritance parents"));
3200 12 : return true;
3201 : }
3202 :
3203 0 : ereport(ERROR,
3204 : (errcode(ERRCODE_DUPLICATE_OBJECT),
3205 : errmsg("check constraint name \"%s\" appears multiple times but with different expressions",
3206 : name)));
3207 : }
3208 :
3209 172 : return false;
3210 : }
3211 :
3212 :
3213 : /*
3214 : * StoreCatalogInheritance
3215 : * Updates the system catalogs with proper inheritance information.
3216 : *
3217 : * supers is a list of the OIDs of the new relation's direct ancestors.
3218 : */
3219 : static void
3220 124424 : StoreCatalogInheritance(Oid relationId, List *supers,
3221 : bool child_is_partition)
3222 : {
3223 : Relation relation;
3224 : int32 seqNumber;
3225 : ListCell *entry;
3226 :
3227 : /*
3228 : * sanity checks
3229 : */
3230 : Assert(OidIsValid(relationId));
3231 :
3232 124424 : if (supers == NIL)
3233 116208 : return;
3234 :
3235 : /*
3236 : * Store INHERITS information in pg_inherits using direct ancestors only.
3237 : * Also enter dependencies on the direct ancestors, and make sure they are
3238 : * marked with relhassubclass = true.
3239 : *
3240 : * (Once upon a time, both direct and indirect ancestors were found here
3241 : * and then entered into pg_ipl. Since that catalog doesn't exist
3242 : * anymore, there's no need to look for indirect ancestors.)
3243 : */
3244 8216 : relation = table_open(InheritsRelationId, RowExclusiveLock);
3245 :
3246 8216 : seqNumber = 1;
3247 16578 : foreach(entry, supers)
3248 : {
3249 8362 : Oid parentOid = lfirst_oid(entry);
3250 :
3251 8362 : StoreCatalogInheritance1(relationId, parentOid, seqNumber, relation,
3252 : child_is_partition);
3253 8362 : seqNumber++;
3254 : }
3255 :
3256 8216 : table_close(relation, RowExclusiveLock);
3257 : }
3258 :
3259 : /*
3260 : * Make catalog entries showing relationId as being an inheritance child
3261 : * of parentOid. inhRelation is the already-opened pg_inherits catalog.
3262 : */
3263 : static void
3264 10410 : StoreCatalogInheritance1(Oid relationId, Oid parentOid,
3265 : int32 seqNumber, Relation inhRelation,
3266 : bool child_is_partition)
3267 : {
3268 : ObjectAddress childobject,
3269 : parentobject;
3270 :
3271 : /* store the pg_inherits row */
3272 10410 : StoreSingleInheritance(relationId, parentOid, seqNumber);
3273 :
3274 : /*
3275 : * Store a dependency too
3276 : */
3277 10410 : parentobject.classId = RelationRelationId;
3278 10410 : parentobject.objectId = parentOid;
3279 10410 : parentobject.objectSubId = 0;
3280 10410 : childobject.classId = RelationRelationId;
3281 10410 : childobject.objectId = relationId;
3282 10410 : childobject.objectSubId = 0;
3283 :
3284 10410 : recordDependencyOn(&childobject, &parentobject,
3285 : child_dependency_type(child_is_partition));
3286 :
3287 : /*
3288 : * Post creation hook of this inheritance. Since object_access_hook
3289 : * doesn't take multiple object identifiers, we relay oid of parent
3290 : * relation using auxiliary_id argument.
3291 : */
3292 10410 : InvokeObjectPostAlterHookArg(InheritsRelationId,
3293 : relationId, 0,
3294 : parentOid, false);
3295 :
3296 : /*
3297 : * Mark the parent as having subclasses.
3298 : */
3299 10410 : SetRelationHasSubclass(parentOid, true);
3300 10410 : }
3301 :
3302 : /*
3303 : * Look for an existing schema entry with the given name.
3304 : *
3305 : * Returns the index (starting with 1) if attribute already exists in schema,
3306 : * 0 if it doesn't.
3307 : */
3308 : static int
3309 18576 : findAttrByName(const char *attributeName, List *schema)
3310 : {
3311 : ListCell *s;
3312 18576 : int i = 1;
3313 :
3314 33218 : foreach(s, schema)
3315 : {
3316 15062 : ColumnDef *def = lfirst(s);
3317 :
3318 15062 : if (strcmp(attributeName, def->colname) == 0)
3319 420 : return i;
3320 :
3321 14642 : i++;
3322 : }
3323 18156 : return 0;
3324 : }
3325 :
3326 :
3327 : /*
3328 : * SetRelationHasSubclass
3329 : * Set the value of the relation's relhassubclass field in pg_class.
3330 : *
3331 : * NOTE: caller must be holding an appropriate lock on the relation.
3332 : * ShareUpdateExclusiveLock is sufficient.
3333 : *
3334 : * NOTE: an important side-effect of this operation is that an SI invalidation
3335 : * message is sent out to all backends --- including me --- causing plans
3336 : * referencing the relation to be rebuilt with the new list of children.
3337 : * This must happen even if we find that no change is needed in the pg_class
3338 : * row.
3339 : */
3340 : void
3341 13016 : SetRelationHasSubclass(Oid relationId, bool relhassubclass)
3342 : {
3343 : Relation relationRelation;
3344 : HeapTuple tuple;
3345 : Form_pg_class classtuple;
3346 :
3347 : /*
3348 : * Fetch a modifiable copy of the tuple, modify it, update pg_class.
3349 : */
3350 13016 : relationRelation = table_open(RelationRelationId, RowExclusiveLock);
3351 13016 : tuple = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relationId));
3352 13016 : if (!HeapTupleIsValid(tuple))
3353 0 : elog(ERROR, "cache lookup failed for relation %u", relationId);
3354 13016 : classtuple = (Form_pg_class) GETSTRUCT(tuple);
3355 :
3356 13016 : if (classtuple->relhassubclass != relhassubclass)
3357 : {
3358 6410 : classtuple->relhassubclass = relhassubclass;
3359 6410 : CatalogTupleUpdate(relationRelation, &tuple->t_self, tuple);
3360 : }
3361 : else
3362 : {
3363 : /* no need to change tuple, but force relcache rebuild anyway */
3364 6606 : CacheInvalidateRelcacheByTuple(tuple);
3365 : }
3366 :
3367 13016 : heap_freetuple(tuple);
3368 13016 : table_close(relationRelation, RowExclusiveLock);
3369 13016 : }
3370 :
3371 : /*
3372 : * CheckRelationTableSpaceMove
3373 : * Check if relation can be moved to new tablespace.
3374 : *
3375 : * NOTE: The caller must hold AccessExclusiveLock on the relation.
3376 : *
3377 : * Returns true if the relation can be moved to the new tablespace; raises
3378 : * an error if it is not possible to do the move; returns false if the move
3379 : * would have no effect.
3380 : */
3381 : bool
3382 226 : CheckRelationTableSpaceMove(Relation rel, Oid newTableSpaceId)
3383 : {
3384 : Oid oldTableSpaceId;
3385 :
3386 : /*
3387 : * No work if no change in tablespace. Note that MyDatabaseTableSpace is
3388 : * stored as 0.
3389 : */
3390 226 : oldTableSpaceId = rel->rd_rel->reltablespace;
3391 226 : if (newTableSpaceId == oldTableSpaceId ||
3392 218 : (newTableSpaceId == MyDatabaseTableSpace && oldTableSpaceId == 0))
3393 10 : return false;
3394 :
3395 : /*
3396 : * We cannot support moving mapped relations into different tablespaces.
3397 : * (In particular this eliminates all shared catalogs.)
3398 : */
3399 216 : if (RelationIsMapped(rel))
3400 0 : ereport(ERROR,
3401 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3402 : errmsg("cannot move system relation \"%s\"",
3403 : RelationGetRelationName(rel))));
3404 :
3405 : /* Cannot move a non-shared relation into pg_global */
3406 216 : if (newTableSpaceId == GLOBALTABLESPACE_OID)
3407 12 : ereport(ERROR,
3408 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
3409 : errmsg("only shared relations can be placed in pg_global tablespace")));
3410 :
3411 : /*
3412 : * Do not allow moving temp tables of other backends ... their local
3413 : * buffer manager is not going to cope.
3414 : */
3415 204 : if (RELATION_IS_OTHER_TEMP(rel))
3416 0 : ereport(ERROR,
3417 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3418 : errmsg("cannot move temporary tables of other sessions")));
3419 :
3420 204 : return true;
3421 : }
3422 :
3423 : /*
3424 : * SetRelationTableSpace
3425 : * Set new reltablespace and relfilenumber in pg_class entry.
3426 : *
3427 : * newTableSpaceId is the new tablespace for the relation, and
3428 : * newRelFilenumber its new filenumber. If newRelFilenumber is
3429 : * InvalidRelFileNumber, this field is not updated.
3430 : *
3431 : * NOTE: The caller must hold AccessExclusiveLock on the relation.
3432 : *
3433 : * The caller of this routine had better check if a relation can be
3434 : * moved to this new tablespace by calling CheckRelationTableSpaceMove()
3435 : * first, and is responsible for making the change visible with
3436 : * CommandCounterIncrement().
3437 : */
3438 : void
3439 204 : SetRelationTableSpace(Relation rel,
3440 : Oid newTableSpaceId,
3441 : RelFileNumber newRelFilenumber)
3442 : {
3443 : Relation pg_class;
3444 : HeapTuple tuple;
3445 : Form_pg_class rd_rel;
3446 204 : Oid reloid = RelationGetRelid(rel);
3447 :
3448 : Assert(CheckRelationTableSpaceMove(rel, newTableSpaceId));
3449 :
3450 : /* Get a modifiable copy of the relation's pg_class row. */
3451 204 : pg_class = table_open(RelationRelationId, RowExclusiveLock);
3452 :
3453 204 : tuple = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(reloid));
3454 204 : if (!HeapTupleIsValid(tuple))
3455 0 : elog(ERROR, "cache lookup failed for relation %u", reloid);
3456 204 : rd_rel = (Form_pg_class) GETSTRUCT(tuple);
3457 :
3458 : /* Update the pg_class row. */
3459 408 : rd_rel->reltablespace = (newTableSpaceId == MyDatabaseTableSpace) ?
3460 204 : InvalidOid : newTableSpaceId;
3461 204 : if (RelFileNumberIsValid(newRelFilenumber))
3462 160 : rd_rel->relfilenode = newRelFilenumber;
3463 204 : CatalogTupleUpdate(pg_class, &tuple->t_self, tuple);
3464 :
3465 : /*
3466 : * Record dependency on tablespace. This is only required for relations
3467 : * that have no physical storage.
3468 : */
3469 204 : if (!RELKIND_HAS_STORAGE(rel->rd_rel->relkind))
3470 30 : changeDependencyOnTablespace(RelationRelationId, reloid,
3471 : rd_rel->reltablespace);
3472 :
3473 204 : heap_freetuple(tuple);
3474 204 : table_close(pg_class, RowExclusiveLock);
3475 204 : }
3476 :
3477 : /*
3478 : * renameatt_check - basic sanity checks before attribute rename
3479 : */
3480 : static void
3481 958 : renameatt_check(Oid myrelid, Form_pg_class classform, bool recursing)
3482 : {
3483 958 : char relkind = classform->relkind;
3484 :
3485 958 : if (classform->reloftype && !recursing)
3486 6 : ereport(ERROR,
3487 : (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3488 : errmsg("cannot rename column of typed table")));
3489 :
3490 : /*
3491 : * Renaming the columns of sequences or toast tables doesn't actually
3492 : * break anything from the system's point of view, since internal
3493 : * references are by attnum. But it doesn't seem right to allow users to
3494 : * change names that are hardcoded into the system, hence the following
3495 : * restriction.
3496 : */
3497 952 : if (relkind != RELKIND_RELATION &&
3498 84 : relkind != RELKIND_VIEW &&
3499 84 : relkind != RELKIND_MATVIEW &&
3500 36 : relkind != RELKIND_COMPOSITE_TYPE &&
3501 36 : relkind != RELKIND_INDEX &&
3502 36 : relkind != RELKIND_PARTITIONED_INDEX &&
3503 0 : relkind != RELKIND_FOREIGN_TABLE &&
3504 : relkind != RELKIND_PARTITIONED_TABLE)
3505 0 : ereport(ERROR,
3506 : (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3507 : errmsg("cannot rename columns of relation \"%s\"",
3508 : NameStr(classform->relname)),
3509 : errdetail_relkind_not_supported(relkind)));
3510 :
3511 : /*
3512 : * permissions checking. only the owner of a class can change its schema.
3513 : */
3514 952 : if (!object_ownercheck(RelationRelationId, myrelid, GetUserId()))
3515 0 : aclcheck_error(ACLCHECK_NOT_OWNER, get_relkind_objtype(get_rel_relkind(myrelid)),
3516 0 : NameStr(classform->relname));
3517 952 : if (!allowSystemTableMods && IsSystemClass(myrelid, classform))
3518 2 : ereport(ERROR,
3519 : (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
3520 : errmsg("permission denied: \"%s\" is a system catalog",
3521 : NameStr(classform->relname))));
3522 950 : }
3523 :
3524 : /*
3525 : * renameatt_internal - workhorse for renameatt
3526 : *
3527 : * Return value is the attribute number in the 'myrelid' relation.
3528 : */
3529 : static AttrNumber
3530 534 : renameatt_internal(Oid myrelid,
3531 : const char *oldattname,
3532 : const char *newattname,
3533 : bool recurse,
3534 : bool recursing,
3535 : int expected_parents,
3536 : DropBehavior behavior)
3537 : {
3538 : Relation targetrelation;
3539 : Relation attrelation;
3540 : HeapTuple atttup;
3541 : Form_pg_attribute attform;
3542 : AttrNumber attnum;
3543 :
3544 : /*
3545 : * Grab an exclusive lock on the target table, which we will NOT release
3546 : * until end of transaction.
3547 : */
3548 534 : targetrelation = relation_open(myrelid, AccessExclusiveLock);
3549 534 : renameatt_check(myrelid, RelationGetForm(targetrelation), recursing);
3550 :
3551 : /*
3552 : * if the 'recurse' flag is set then we are supposed to rename this
3553 : * attribute in all classes that inherit from 'relname' (as well as in
3554 : * 'relname').
3555 : *
3556 : * any permissions or problems with duplicate attributes will cause the
3557 : * whole transaction to abort, which is what we want -- all or nothing.
3558 : */
3559 534 : if (recurse)
3560 : {
3561 : List *child_oids,
3562 : *child_numparents;
3563 : ListCell *lo,
3564 : *li;
3565 :
3566 : /*
3567 : * we need the number of parents for each child so that the recursive
3568 : * calls to renameatt() can determine whether there are any parents
3569 : * outside the inheritance hierarchy being processed.
3570 : */
3571 230 : child_oids = find_all_inheritors(myrelid, AccessExclusiveLock,
3572 : &child_numparents);
3573 :
3574 : /*
3575 : * find_all_inheritors does the recursive search of the inheritance
3576 : * hierarchy, so all we have to do is process all of the relids in the
3577 : * list that it returns.
3578 : */
3579 698 : forboth(lo, child_oids, li, child_numparents)
3580 : {
3581 498 : Oid childrelid = lfirst_oid(lo);
3582 498 : int numparents = lfirst_int(li);
3583 :
3584 498 : if (childrelid == myrelid)
3585 230 : continue;
3586 : /* note we need not recurse again */
3587 268 : renameatt_internal(childrelid, oldattname, newattname, false, true, numparents, behavior);
3588 : }
3589 : }
3590 : else
3591 : {
3592 : /*
3593 : * If we are told not to recurse, there had better not be any child
3594 : * tables; else the rename would put them out of step.
3595 : *
3596 : * expected_parents will only be 0 if we are not already recursing.
3597 : */
3598 340 : if (expected_parents == 0 &&
3599 36 : find_inheritance_children(myrelid, NoLock) != NIL)
3600 12 : ereport(ERROR,
3601 : (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
3602 : errmsg("inherited column \"%s\" must be renamed in child tables too",
3603 : oldattname)));
3604 : }
3605 :
3606 : /* rename attributes in typed tables of composite type */
3607 492 : if (targetrelation->rd_rel->relkind == RELKIND_COMPOSITE_TYPE)
3608 : {
3609 : List *child_oids;
3610 : ListCell *lo;
3611 :
3612 24 : child_oids = find_typed_table_dependencies(targetrelation->rd_rel->reltype,
3613 24 : RelationGetRelationName(targetrelation),
3614 : behavior);
3615 :
3616 24 : foreach(lo, child_oids)
3617 6 : renameatt_internal(lfirst_oid(lo), oldattname, newattname, true, true, 0, behavior);
3618 : }
3619 :
3620 486 : attrelation = table_open(AttributeRelationId, RowExclusiveLock);
3621 :
3622 486 : atttup = SearchSysCacheCopyAttName(myrelid, oldattname);
3623 486 : if (!HeapTupleIsValid(atttup))
3624 24 : ereport(ERROR,
3625 : (errcode(ERRCODE_UNDEFINED_COLUMN),
3626 : errmsg("column \"%s\" does not exist",
3627 : oldattname)));
3628 462 : attform = (Form_pg_attribute) GETSTRUCT(atttup);
3629 :
3630 462 : attnum = attform->attnum;
3631 462 : if (attnum <= 0)
3632 0 : ereport(ERROR,
3633 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3634 : errmsg("cannot rename system column \"%s\"",
3635 : oldattname)));
3636 :
3637 : /*
3638 : * if the attribute is inherited, forbid the renaming. if this is a
3639 : * top-level call to renameatt(), then expected_parents will be 0, so the
3640 : * effect of this code will be to prohibit the renaming if the attribute
3641 : * is inherited at all. if this is a recursive call to renameatt(),
3642 : * expected_parents will be the number of parents the current relation has
3643 : * within the inheritance hierarchy being processed, so we'll prohibit the
3644 : * renaming only if there are additional parents from elsewhere.
3645 : */
3646 462 : if (attform->attinhcount > expected_parents)
3647 30 : ereport(ERROR,
3648 : (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
3649 : errmsg("cannot rename inherited column \"%s\"",
3650 : oldattname)));
3651 :
3652 : /* new name should not already exist */
3653 432 : (void) check_for_column_name_collision(targetrelation, newattname, false);
3654 :
3655 : /* apply the update */
3656 420 : namestrcpy(&(attform->attname), newattname);
3657 :
3658 420 : CatalogTupleUpdate(attrelation, &atttup->t_self, atttup);
3659 :
3660 420 : InvokeObjectPostAlterHook(RelationRelationId, myrelid, attnum);
3661 :
3662 420 : heap_freetuple(atttup);
3663 :
3664 420 : table_close(attrelation, RowExclusiveLock);
3665 :
3666 420 : relation_close(targetrelation, NoLock); /* close rel but keep lock */
3667 :
3668 420 : return attnum;
3669 : }
3670 :
3671 : /*
3672 : * Perform permissions and integrity checks before acquiring a relation lock.
3673 : */
3674 : static void
3675 382 : RangeVarCallbackForRenameAttribute(const RangeVar *rv, Oid relid, Oid oldrelid,
3676 : void *arg)
3677 : {
3678 : HeapTuple tuple;
3679 : Form_pg_class form;
3680 :
3681 382 : tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
3682 382 : if (!HeapTupleIsValid(tuple))
3683 36 : return; /* concurrently dropped */
3684 346 : form = (Form_pg_class) GETSTRUCT(tuple);
3685 346 : renameatt_check(relid, form, false);
3686 338 : ReleaseSysCache(tuple);
3687 : }
3688 :
3689 : /*
3690 : * renameatt - changes the name of an attribute in a relation
3691 : *
3692 : * The returned ObjectAddress is that of the renamed column.
3693 : */
3694 : ObjectAddress
3695 298 : renameatt(RenameStmt *stmt)
3696 : {
3697 : Oid relid;
3698 : AttrNumber attnum;
3699 : ObjectAddress address;
3700 :
3701 : /* lock level taken here should match renameatt_internal */
3702 298 : relid = RangeVarGetRelidExtended(stmt->relation, AccessExclusiveLock,
3703 298 : stmt->missing_ok ? RVR_MISSING_OK : 0,
3704 : RangeVarCallbackForRenameAttribute,
3705 : NULL);
3706 :
3707 284 : if (!OidIsValid(relid))
3708 : {
3709 24 : ereport(NOTICE,
3710 : (errmsg("relation \"%s\" does not exist, skipping",
3711 : stmt->relation->relname)));
3712 24 : return InvalidObjectAddress;
3713 : }
3714 :
3715 : attnum =
3716 260 : renameatt_internal(relid,
3717 260 : stmt->subname, /* old att name */
3718 260 : stmt->newname, /* new att name */
3719 260 : stmt->relation->inh, /* recursive? */
3720 : false, /* recursing? */
3721 : 0, /* expected inhcount */
3722 : stmt->behavior);
3723 :
3724 176 : ObjectAddressSubSet(address, RelationRelationId, relid, attnum);
3725 :
3726 176 : return address;
3727 : }
3728 :
3729 : /*
3730 : * same logic as renameatt_internal
3731 : */
3732 : static ObjectAddress
3733 84 : rename_constraint_internal(Oid myrelid,
3734 : Oid mytypid,
3735 : const char *oldconname,
3736 : const char *newconname,
3737 : bool recurse,
3738 : bool recursing,
3739 : int expected_parents)
3740 : {
3741 84 : Relation targetrelation = NULL;
3742 : Oid constraintOid;
3743 : HeapTuple tuple;
3744 : Form_pg_constraint con;
3745 : ObjectAddress address;
3746 :
3747 : Assert(!myrelid || !mytypid);
3748 :
3749 84 : if (mytypid)
3750 : {
3751 6 : constraintOid = get_domain_constraint_oid(mytypid, oldconname, false);
3752 : }
3753 : else
3754 : {
3755 78 : targetrelation = relation_open(myrelid, AccessExclusiveLock);
3756 :
3757 : /*
3758 : * don't tell it whether we're recursing; we allow changing typed
3759 : * tables here
3760 : */
3761 78 : renameatt_check(myrelid, RelationGetForm(targetrelation), false);
3762 :
3763 78 : constraintOid = get_relation_constraint_oid(myrelid, oldconname, false);
3764 : }
3765 :
3766 84 : tuple = SearchSysCache1(CONSTROID, ObjectIdGetDatum(constraintOid));
3767 84 : if (!HeapTupleIsValid(tuple))
3768 0 : elog(ERROR, "cache lookup failed for constraint %u",
3769 : constraintOid);
3770 84 : con = (Form_pg_constraint) GETSTRUCT(tuple);
3771 :
3772 84 : if (myrelid && con->contype == CONSTRAINT_CHECK && !con->connoinherit)
3773 : {
3774 48 : if (recurse)
3775 : {
3776 : List *child_oids,
3777 : *child_numparents;
3778 : ListCell *lo,
3779 : *li;
3780 :
3781 30 : child_oids = find_all_inheritors(myrelid, AccessExclusiveLock,
3782 : &child_numparents);
3783 :
3784 72 : forboth(lo, child_oids, li, child_numparents)
3785 : {
3786 42 : Oid childrelid = lfirst_oid(lo);
3787 42 : int numparents = lfirst_int(li);
3788 :
3789 42 : if (childrelid == myrelid)
3790 30 : continue;
3791 :
3792 12 : rename_constraint_internal(childrelid, InvalidOid, oldconname, newconname, false, true, numparents);
3793 : }
3794 : }
3795 : else
3796 : {
3797 24 : if (expected_parents == 0 &&
3798 6 : find_inheritance_children(myrelid, NoLock) != NIL)
3799 6 : ereport(ERROR,
3800 : (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
3801 : errmsg("inherited constraint \"%s\" must be renamed in child tables too",
3802 : oldconname)));
3803 : }
3804 :
3805 42 : if (con->coninhcount > expected_parents)
3806 6 : ereport(ERROR,
3807 : (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
3808 : errmsg("cannot rename inherited constraint \"%s\"",
3809 : oldconname)));
3810 : }
3811 :
3812 72 : if (con->conindid
3813 18 : && (con->contype == CONSTRAINT_PRIMARY
3814 6 : || con->contype == CONSTRAINT_UNIQUE
3815 0 : || con->contype == CONSTRAINT_EXCLUSION))
3816 : /* rename the index; this renames the constraint as well */
3817 18 : RenameRelationInternal(con->conindid, newconname, false, true);
3818 : else
3819 54 : RenameConstraintById(constraintOid, newconname);
3820 :
3821 72 : ObjectAddressSet(address, ConstraintRelationId, constraintOid);
3822 :
3823 72 : ReleaseSysCache(tuple);
3824 :
3825 72 : if (targetrelation)
3826 : {
3827 : /*
3828 : * Invalidate relcache so as others can see the new constraint name.
3829 : */
3830 66 : CacheInvalidateRelcache(targetrelation);
3831 :
3832 66 : relation_close(targetrelation, NoLock); /* close rel but keep lock */
3833 : }
3834 :
3835 72 : return address;
3836 : }
3837 :
3838 : ObjectAddress
3839 78 : RenameConstraint(RenameStmt *stmt)
3840 : {
3841 78 : Oid relid = InvalidOid;
3842 78 : Oid typid = InvalidOid;
3843 :
3844 78 : if (stmt->renameType == OBJECT_DOMCONSTRAINT)
3845 : {
3846 : Relation rel;
3847 : HeapTuple tup;
3848 :
3849 6 : typid = typenameTypeId(NULL, makeTypeNameFromNameList(castNode(List, stmt->object)));
3850 6 : rel = table_open(TypeRelationId, RowExclusiveLock);
3851 6 : tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
3852 6 : if (!HeapTupleIsValid(tup))
3853 0 : elog(ERROR, "cache lookup failed for type %u", typid);
3854 6 : checkDomainOwner(tup);
3855 6 : ReleaseSysCache(tup);
3856 6 : table_close(rel, NoLock);
3857 : }
3858 : else
3859 : {
3860 : /* lock level taken here should match rename_constraint_internal */
3861 72 : relid = RangeVarGetRelidExtended(stmt->relation, AccessExclusiveLock,
3862 72 : stmt->missing_ok ? RVR_MISSING_OK : 0,
3863 : RangeVarCallbackForRenameAttribute,
3864 : NULL);
3865 72 : if (!OidIsValid(relid))
3866 : {
3867 6 : ereport(NOTICE,
3868 : (errmsg("relation \"%s\" does not exist, skipping",
3869 : stmt->relation->relname)));
3870 6 : return InvalidObjectAddress;
3871 : }
3872 : }
3873 :
3874 : return
3875 72 : rename_constraint_internal(relid, typid,
3876 72 : stmt->subname,
3877 72 : stmt->newname,
3878 138 : (stmt->relation &&
3879 66 : stmt->relation->inh), /* recursive? */
3880 : false, /* recursing? */
3881 : 0 /* expected inhcount */ );
3882 : }
3883 :
3884 : /*
3885 : * Execute ALTER TABLE/INDEX/SEQUENCE/VIEW/MATERIALIZED VIEW/FOREIGN TABLE
3886 : * RENAME
3887 : */
3888 : ObjectAddress
3889 510 : RenameRelation(RenameStmt *stmt)
3890 : {
3891 510 : bool is_index_stmt = stmt->renameType == OBJECT_INDEX;
3892 : Oid relid;
3893 : ObjectAddress address;
3894 :
3895 : /*
3896 : * Grab an exclusive lock on the target table, index, sequence, view,
3897 : * materialized view, or foreign table, which we will NOT release until
3898 : * end of transaction.
3899 : *
3900 : * Lock level used here should match RenameRelationInternal, to avoid lock
3901 : * escalation. However, because ALTER INDEX can be used with any relation
3902 : * type, we mustn't believe without verification.
3903 : */
3904 : for (;;)
3905 12 : {
3906 : LOCKMODE lockmode;
3907 : char relkind;
3908 : bool obj_is_index;
3909 :
3910 522 : lockmode = is_index_stmt ? ShareUpdateExclusiveLock : AccessExclusiveLock;
3911 :
3912 522 : relid = RangeVarGetRelidExtended(stmt->relation, lockmode,
3913 522 : stmt->missing_ok ? RVR_MISSING_OK : 0,
3914 : RangeVarCallbackForAlterRelation,
3915 : (void *) stmt);
3916 :
3917 472 : if (!OidIsValid(relid))
3918 : {
3919 18 : ereport(NOTICE,
3920 : (errmsg("relation \"%s\" does not exist, skipping",
3921 : stmt->relation->relname)));
3922 18 : return InvalidObjectAddress;
3923 : }
3924 :
3925 : /*
3926 : * We allow mismatched statement and object types (e.g., ALTER INDEX
3927 : * to rename a table), but we might've used the wrong lock level. If
3928 : * that happens, retry with the correct lock level. We don't bother
3929 : * if we already acquired AccessExclusiveLock with an index, however.
3930 : */
3931 454 : relkind = get_rel_relkind(relid);
3932 454 : obj_is_index = (relkind == RELKIND_INDEX ||
3933 : relkind == RELKIND_PARTITIONED_INDEX);
3934 454 : if (obj_is_index || is_index_stmt == obj_is_index)
3935 : break;
3936 :
3937 12 : UnlockRelationOid(relid, lockmode);
3938 12 : is_index_stmt = obj_is_index;
3939 : }
3940 :
3941 : /* Do the work */
3942 442 : RenameRelationInternal(relid, stmt->newname, false, is_index_stmt);
3943 :
3944 430 : ObjectAddressSet(address, RelationRelationId, relid);
3945 :
3946 430 : return address;
3947 : }
3948 :
3949 : /*
3950 : * RenameRelationInternal - change the name of a relation
3951 : */
3952 : void
3953 1150 : RenameRelationInternal(Oid myrelid, const char *newrelname, bool is_internal, bool is_index)
3954 : {
3955 : Relation targetrelation;
3956 : Relation relrelation; /* for RELATION relation */
3957 : HeapTuple reltup;
3958 : Form_pg_class relform;
3959 : Oid namespaceId;
3960 :
3961 : /*
3962 : * Grab a lock on the target relation, which we will NOT release until end
3963 : * of transaction. We need at least a self-exclusive lock so that
3964 : * concurrent DDL doesn't overwrite the rename if they start updating
3965 : * while still seeing the old version. The lock also guards against
3966 : * triggering relcache reloads in concurrent sessions, which might not
3967 : * handle this information changing under them. For indexes, we can use a
3968 : * reduced lock level because RelationReloadIndexInfo() handles indexes
3969 : * specially.
3970 : */
3971 1150 : targetrelation = relation_open(myrelid, is_index ? ShareUpdateExclusiveLock : AccessExclusiveLock);
3972 1150 : namespaceId = RelationGetNamespace(targetrelation);
3973 :
3974 : /*
3975 : * Find relation's pg_class tuple, and make sure newrelname isn't in use.
3976 : */
3977 1150 : relrelation = table_open(RelationRelationId, RowExclusiveLock);
3978 :
3979 1150 : reltup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(myrelid));
3980 1150 : if (!HeapTupleIsValid(reltup)) /* shouldn't happen */
3981 0 : elog(ERROR, "cache lookup failed for relation %u", myrelid);
3982 1150 : relform = (Form_pg_class) GETSTRUCT(reltup);
3983 :
3984 1150 : if (get_relname_relid(newrelname, namespaceId) != InvalidOid)
3985 12 : ereport(ERROR,
3986 : (errcode(ERRCODE_DUPLICATE_TABLE),
3987 : errmsg("relation \"%s\" already exists",
3988 : newrelname)));
3989 :
3990 : /*
3991 : * RenameRelation is careful not to believe the caller's idea of the
3992 : * relation kind being handled. We don't have to worry about this, but
3993 : * let's not be totally oblivious to it. We can process an index as
3994 : * not-an-index, but not the other way around.
3995 : */
3996 : Assert(!is_index ||
3997 : is_index == (targetrelation->rd_rel->relkind == RELKIND_INDEX ||
3998 : targetrelation->rd_rel->relkind == RELKIND_PARTITIONED_INDEX));
3999 :
4000 : /*
4001 : * Update pg_class tuple with new relname. (Scribbling on reltup is OK
4002 : * because it's a copy...)
4003 : */
4004 1138 : namestrcpy(&(relform->relname), newrelname);
4005 :
4006 1138 : CatalogTupleUpdate(relrelation, &reltup->t_self, reltup);
4007 :
4008 1138 : InvokeObjectPostAlterHookArg(RelationRelationId, myrelid, 0,
4009 : InvalidOid, is_internal);
4010 :
4011 1138 : heap_freetuple(reltup);
4012 1138 : table_close(relrelation, RowExclusiveLock);
4013 :
4014 : /*
4015 : * Also rename the associated type, if any.
4016 : */
4017 1138 : if (OidIsValid(targetrelation->rd_rel->reltype))
4018 124 : RenameTypeInternal(targetrelation->rd_rel->reltype,
4019 : newrelname, namespaceId);
4020 :
4021 : /*
4022 : * Also rename the associated constraint, if any.
4023 : */
4024 1138 : if (targetrelation->rd_rel->relkind == RELKIND_INDEX ||
4025 616 : targetrelation->rd_rel->relkind == RELKIND_PARTITIONED_INDEX)
4026 : {
4027 540 : Oid constraintId = get_index_constraint(myrelid);
4028 :
4029 540 : if (OidIsValid(constraintId))
4030 36 : RenameConstraintById(constraintId, newrelname);
4031 : }
4032 :
4033 : /*
4034 : * Close rel, but keep lock!
4035 : */
4036 1138 : relation_close(targetrelation, NoLock);
4037 1138 : }
4038 :
4039 : /*
4040 : * ResetRelRewrite - reset relrewrite
4041 : */
4042 : void
4043 340 : ResetRelRewrite(Oid myrelid)
4044 : {
4045 : Relation relrelation; /* for RELATION relation */
4046 : HeapTuple reltup;
4047 : Form_pg_class relform;
4048 :
4049 : /*
4050 : * Find relation's pg_class tuple.
4051 : */
4052 340 : relrelation = table_open(RelationRelationId, RowExclusiveLock);
4053 :
4054 340 : reltup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(myrelid));
4055 340 : if (!HeapTupleIsValid(reltup)) /* shouldn't happen */
4056 0 : elog(ERROR, "cache lookup failed for relation %u", myrelid);
4057 340 : relform = (Form_pg_class) GETSTRUCT(reltup);
4058 :
4059 : /*
4060 : * Update pg_class tuple.
4061 : */
4062 340 : relform->relrewrite = InvalidOid;
4063 :
4064 340 : CatalogTupleUpdate(relrelation, &reltup->t_self, reltup);
4065 :
4066 340 : heap_freetuple(reltup);
4067 340 : table_close(relrelation, RowExclusiveLock);
4068 340 : }
4069 :
4070 : /*
4071 : * Disallow ALTER TABLE (and similar commands) when the current backend has
4072 : * any open reference to the target table besides the one just acquired by
4073 : * the calling command; this implies there's an open cursor or active plan.
4074 : * We need this check because our lock doesn't protect us against stomping
4075 : * on our own foot, only other people's feet!
4076 : *
4077 : * For ALTER TABLE, the only case known to cause serious trouble is ALTER
4078 : * COLUMN TYPE, and some changes are obviously pretty benign, so this could
4079 : * possibly be relaxed to only error out for certain types of alterations.
4080 : * But the use-case for allowing any of these things is not obvious, so we
4081 : * won't work hard at it for now.
4082 : *
4083 : * We also reject these commands if there are any pending AFTER trigger events
4084 : * for the rel. This is certainly necessary for the rewriting variants of
4085 : * ALTER TABLE, because they don't preserve tuple TIDs and so the pending
4086 : * events would try to fetch the wrong tuples. It might be overly cautious
4087 : * in other cases, but again it seems better to err on the side of paranoia.
4088 : *
4089 : * REINDEX calls this with "rel" referencing the index to be rebuilt; here
4090 : * we are worried about active indexscans on the index. The trigger-event
4091 : * check can be skipped, since we are doing no damage to the parent table.
4092 : *
4093 : * The statement name (eg, "ALTER TABLE") is passed for use in error messages.
4094 : */
4095 : void
4096 173792 : CheckTableNotInUse(Relation rel, const char *stmt)
4097 : {
4098 : int expected_refcnt;
4099 :
4100 173792 : expected_refcnt = rel->rd_isnailed ? 2 : 1;
4101 173792 : if (rel->rd_refcnt != expected_refcnt)
4102 24 : ereport(ERROR,
4103 : (errcode(ERRCODE_OBJECT_IN_USE),
4104 : /* translator: first %s is a SQL command, eg ALTER TABLE */
4105 : errmsg("cannot %s \"%s\" because it is being used by active queries in this session",
4106 : stmt, RelationGetRelationName(rel))));
4107 :
4108 173768 : if (rel->rd_rel->relkind != RELKIND_INDEX &&
4109 297196 : rel->rd_rel->relkind != RELKIND_PARTITIONED_INDEX &&
4110 147716 : AfterTriggerPendingOnRel(RelationGetRelid(rel)))
4111 18 : ereport(ERROR,
4112 : (errcode(ERRCODE_OBJECT_IN_USE),
4113 : /* translator: first %s is a SQL command, eg ALTER TABLE */
4114 : errmsg("cannot %s \"%s\" because it has pending trigger events",
4115 : stmt, RelationGetRelationName(rel))));
4116 173750 : }
4117 :
4118 : /*
4119 : * AlterTableLookupRelation
4120 : * Look up, and lock, the OID for the relation named by an alter table
4121 : * statement.
4122 : */
4123 : Oid
4124 83548 : AlterTableLookupRelation(AlterTableStmt *stmt, LOCKMODE lockmode)
4125 : {
4126 167012 : return RangeVarGetRelidExtended(stmt->relation, lockmode,
4127 83548 : stmt->missing_ok ? RVR_MISSING_OK : 0,
4128 : RangeVarCallbackForAlterRelation,
4129 : (void *) stmt);
4130 : }
4131 :
4132 : /*
4133 : * AlterTable
4134 : * Execute ALTER TABLE, which can be a list of subcommands
4135 : *
4136 : * ALTER TABLE is performed in three phases:
4137 : * 1. Examine subcommands and perform pre-transformation checking.
4138 : * 2. Validate and transform subcommands, and update system catalogs.
4139 : * 3. Scan table(s) to check new constraints, and optionally recopy
4140 : * the data into new table(s).
4141 : * Phase 3 is not performed unless one or more of the subcommands requires
4142 : * it. The intention of this design is to allow multiple independent
4143 : * updates of the table schema to be performed with only one pass over the
4144 : * data.
4145 : *
4146 : * ATPrepCmd performs phase 1. A "work queue" entry is created for
4147 : * each table to be affected (there may be multiple affected tables if the
4148 : * commands traverse a table inheritance hierarchy). Also we do preliminary
4149 : * validation of the subcommands. Because earlier subcommands may change
4150 : * the catalog state seen by later commands, there are limits to what can
4151 : * be done in this phase. Generally, this phase acquires table locks,
4152 : * checks permissions and relkind, and recurses to find child tables.
4153 : *
4154 : * ATRewriteCatalogs performs phase 2 for each affected table.
4155 : * Certain subcommands need to be performed before others to avoid
4156 : * unnecessary conflicts; for example, DROP COLUMN should come before
4157 : * ADD COLUMN. Therefore phase 1 divides the subcommands into multiple
4158 : * lists, one for each logical "pass" of phase 2.
4159 : *
4160 : * ATRewriteTables performs phase 3 for those tables that need it.
4161 : *
4162 : * For most subcommand types, phases 2 and 3 do no explicit recursion,
4163 : * since phase 1 already does it. However, for certain subcommand types
4164 : * it is only possible to determine how to recurse at phase 2 time; for
4165 : * those cases, phase 1 sets the cmd->recurse flag.
4166 : *
4167 : * Thanks to the magic of MVCC, an error anywhere along the way rolls back
4168 : * the whole operation; we don't have to do anything special to clean up.
4169 : *
4170 : * The caller must lock the relation, with an appropriate lock level
4171 : * for the subcommands requested, using AlterTableGetLockLevel(stmt->cmds)
4172 : * or higher. We pass the lock level down
4173 : * so that we can apply it recursively to inherited tables. Note that the
4174 : * lock level we want as we recurse might well be higher than required for
4175 : * that specific subcommand. So we pass down the overall lock requirement,
4176 : * rather than reassess it at lower levels.
4177 : *
4178 : * The caller also provides a "context" which is to be passed back to
4179 : * utility.c when we need to execute a subcommand such as CREATE INDEX.
4180 : * Some of the fields therein, such as the relid, are used here as well.
4181 : */
4182 : void
4183 83326 : AlterTable(AlterTableStmt *stmt, LOCKMODE lockmode,
4184 : AlterTableUtilityContext *context)
4185 : {
4186 : Relation rel;
4187 :
4188 : /* Caller is required to provide an adequate lock. */
4189 83326 : rel = relation_open(context->relid, NoLock);
4190 :
4191 83326 : CheckTableNotInUse(rel, "ALTER TABLE");
4192 :
4193 83308 : ATController(stmt, rel, stmt->cmds, stmt->relation->inh, lockmode, context);
4194 80706 : }
4195 :
4196 : /*
4197 : * AlterTableInternal
4198 : *
4199 : * ALTER TABLE with target specified by OID
4200 : *
4201 : * We do not reject if the relation is already open, because it's quite
4202 : * likely that one or more layers of caller have it open. That means it
4203 : * is unsafe to use this entry point for alterations that could break
4204 : * existing query plans. On the assumption it's not used for such, we
4205 : * don't have to reject pending AFTER triggers, either.
4206 : *
4207 : * Also, since we don't have an AlterTableUtilityContext, this cannot be
4208 : * used for any subcommand types that require parse transformation or
4209 : * could generate subcommands that have to be passed to ProcessUtility.
4210 : */
4211 : void
4212 278 : AlterTableInternal(Oid relid, List *cmds, bool recurse)
4213 : {
4214 : Relation rel;
4215 278 : LOCKMODE lockmode = AlterTableGetLockLevel(cmds);
4216 :
4217 278 : rel = relation_open(relid, lockmode);
4218 :
4219 278 : EventTriggerAlterTableRelid(relid);
4220 :
4221 278 : ATController(NULL, rel, cmds, recurse, lockmode, NULL);
4222 278 : }
4223 :
4224 : /*
4225 : * AlterTableGetLockLevel
4226 : *
4227 : * Sets the overall lock level required for the supplied list of subcommands.
4228 : * Policy for doing this set according to needs of AlterTable(), see
4229 : * comments there for overall explanation.
4230 : *
4231 : * Function is called before and after parsing, so it must give same
4232 : * answer each time it is called. Some subcommands are transformed
4233 : * into other subcommand types, so the transform must never be made to a
4234 : * lower lock level than previously assigned. All transforms are noted below.
4235 : *
4236 : * Since this is called before we lock the table we cannot use table metadata
4237 : * to influence the type of lock we acquire.
4238 : *
4239 : * There should be no lockmodes hardcoded into the subcommand functions. All
4240 : * lockmode decisions for ALTER TABLE are made here only. The one exception is
4241 : * ALTER TABLE RENAME which is treated as a different statement type T_RenameStmt
4242 : * and does not travel through this section of code and cannot be combined with
4243 : * any of the subcommands given here.
4244 : *
4245 : * Note that Hot Standby only knows about AccessExclusiveLocks on the primary
4246 : * so any changes that might affect SELECTs running on standbys need to use
4247 : * AccessExclusiveLocks even if you think a lesser lock would do, unless you
4248 : * have a solution for that also.
4249 : *
4250 : * Also note that pg_dump uses only an AccessShareLock, meaning that anything
4251 : * that takes a lock less than AccessExclusiveLock can change object definitions
4252 : * while pg_dump is running. Be careful to check that the appropriate data is
4253 : * derived by pg_dump using an MVCC snapshot, rather than syscache lookups,
4254 : * otherwise we might end up with an inconsistent dump that can't restore.
4255 : */
4256 : LOCKMODE
4257 83826 : AlterTableGetLockLevel(List *cmds)
4258 : {
4259 : /*
4260 : * This only works if we read catalog tables using MVCC snapshots.
4261 : */
4262 : ListCell *lcmd;
4263 83826 : LOCKMODE lockmode = ShareUpdateExclusiveLock;
4264 :
4265 168548 : foreach(lcmd, cmds)
4266 : {
4267 84722 : AlterTableCmd *cmd = (AlterTableCmd *) lfirst(lcmd);
4268 84722 : LOCKMODE cmd_lockmode = AccessExclusiveLock; /* default for compiler */
4269 :
4270 84722 : switch (cmd->subtype)
4271 : {
4272 : /*
4273 : * These subcommands rewrite the heap, so require full locks.
4274 : */
4275 2968 : case AT_AddColumn: /* may rewrite heap, in some cases and visible
4276 : * to SELECT */
4277 : case AT_SetAccessMethod: /* must rewrite heap */
4278 : case AT_SetTableSpace: /* must rewrite heap */
4279 : case AT_AlterColumnType: /* must rewrite heap */
4280 2968 : cmd_lockmode = AccessExclusiveLock;
4281 2968 : break;
4282 :
4283 : /*
4284 : * These subcommands may require addition of toast tables. If
4285 : * we add a toast table to a table currently being scanned, we
4286 : * might miss data added to the new toast table by concurrent
4287 : * insert transactions.
4288 : */
4289 208 : case AT_SetStorage: /* may add toast tables, see
4290 : * ATRewriteCatalogs() */
4291 208 : cmd_lockmode = AccessExclusiveLock;
4292 208 : break;
4293 :
4294 : /*
4295 : * Removing constraints can affect SELECTs that have been
4296 : * optimized assuming the constraint holds true. See also
4297 : * CloneFkReferenced.
4298 : */
4299 696 : case AT_DropConstraint: /* as DROP INDEX */
4300 : case AT_DropNotNull: /* may change some SQL plans */
4301 696 : cmd_lockmode = AccessExclusiveLock;
4302 696 : break;
4303 :
4304 : /*
4305 : * Subcommands that may be visible to concurrent SELECTs
4306 : */
4307 1628 : case AT_DropColumn: /* change visible to SELECT */
4308 : case AT_AddColumnToView: /* CREATE VIEW */
4309 : case AT_DropOids: /* used to equiv to DropColumn */
4310 : case AT_EnableAlwaysRule: /* may change SELECT rules */
4311 : case AT_EnableReplicaRule: /* may change SELECT rules */
4312 : case AT_EnableRule: /* may change SELECT rules */
4313 : case AT_DisableRule: /* may change SELECT rules */
4314 1628 : cmd_lockmode = AccessExclusiveLock;
4315 1628 : break;
4316 :
4317 : /*
4318 : * Changing owner may remove implicit SELECT privileges
4319 : */
4320 1716 : case AT_ChangeOwner: /* change visible to SELECT */
4321 1716 : cmd_lockmode = AccessExclusiveLock;
4322 1716 : break;
4323 :
4324 : /*
4325 : * Changing foreign table options may affect optimization.
4326 : */
4327 234 : case AT_GenericOptions:
4328 : case AT_AlterColumnGenericOptions:
4329 234 : cmd_lockmode = AccessExclusiveLock;
4330 234 : break;
4331 :
4332 : /*
4333 : * These subcommands affect write operations only.
4334 : */
4335 336 : case AT_EnableTrig:
4336 : case AT_EnableAlwaysTrig:
4337 : case AT_EnableReplicaTrig:
4338 : case AT_EnableTrigAll:
4339 : case AT_EnableTrigUser:
4340 : case AT_DisableTrig:
4341 : case AT_DisableTrigAll:
4342 : case AT_DisableTrigUser:
4343 336 : cmd_lockmode = ShareRowExclusiveLock;
4344 336 : break;
4345 :
4346 : /*
4347 : * These subcommands affect write operations only. XXX
4348 : * Theoretically, these could be ShareRowExclusiveLock.
4349 : */
4350 2092 : case AT_ColumnDefault:
4351 : case AT_CookedColumnDefault:
4352 : case AT_AlterConstraint:
4353 : case AT_AddIndex: /* from ADD CONSTRAINT */
4354 : case AT_AddIndexConstraint:
4355 : case AT_ReplicaIdentity:
4356 : case AT_SetNotNull:
4357 : case AT_EnableRowSecurity:
4358 : case AT_DisableRowSecurity:
4359 : case AT_ForceRowSecurity:
4360 : case AT_NoForceRowSecurity:
4361 : case AT_AddIdentity:
4362 : case AT_DropIdentity:
4363 : case AT_SetIdentity:
4364 : case AT_DropExpression:
4365 : case AT_SetCompression:
4366 2092 : cmd_lockmode = AccessExclusiveLock;
4367 2092 : break;
4368 :
4369 69846 : case AT_AddConstraint:
4370 : case AT_ReAddConstraint: /* becomes AT_AddConstraint */
4371 : case AT_ReAddDomainConstraint: /* becomes AT_AddConstraint */
4372 69846 : if (IsA(cmd->def, Constraint))
4373 : {
4374 69846 : Constraint *con = (Constraint *) cmd->def;
4375 :
4376 69846 : switch (con->contype)
4377 : {
4378 67186 : case CONSTR_EXCLUSION:
4379 : case CONSTR_PRIMARY:
4380 : case CONSTR_UNIQUE:
4381 :
4382 : /*
4383 : * Cases essentially the same as CREATE INDEX. We
4384 : * could reduce the lock strength to ShareLock if
4385 : * we can work out how to allow concurrent catalog
4386 : * updates. XXX Might be set down to
4387 : * ShareRowExclusiveLock but requires further
4388 : * analysis.
4389 : */
4390 67186 : cmd_lockmode = AccessExclusiveLock;
4391 67186 : break;
4392 2000 : case CONSTR_FOREIGN:
4393 :
4394 : /*
4395 : * We add triggers to both tables when we add a
4396 : * Foreign Key, so the lock level must be at least
4397 : * as strong as CREATE TRIGGER.
4398 : */
4399 2000 : cmd_lockmode = ShareRowExclusiveLock;
4400 2000 : break;
4401 :
4402 660 : default:
4403 660 : cmd_lockmode = AccessExclusiveLock;
4404 : }
4405 0 : }
4406 69846 : break;
4407 :
4408 : /*
4409 : * These subcommands affect inheritance behaviour. Queries
4410 : * started before us will continue to see the old inheritance
4411 : * behaviour, while queries started after we commit will see
4412 : * new behaviour. No need to prevent reads or writes to the
4413 : * subtable while we hook it up though. Changing the TupDesc
4414 : * may be a problem, so keep highest lock.
4415 : */
4416 306 : case AT_AddInherit:
4417 : case AT_DropInherit:
4418 306 : cmd_lockmode = AccessExclusiveLock;
4419 306 : break;
4420 :
4421 : /*
4422 : * These subcommands affect implicit row type conversion. They
4423 : * have affects similar to CREATE/DROP CAST on queries. don't
4424 : * provide for invalidating parse trees as a result of such
4425 : * changes, so we keep these at AccessExclusiveLock.
4426 : */
4427 72 : case AT_AddOf:
4428 : case AT_DropOf:
4429 72 : cmd_lockmode = AccessExclusiveLock;
4430 72 : break;
4431 :
4432 : /*
4433 : * Only used by CREATE OR REPLACE VIEW which must conflict
4434 : * with an SELECTs currently using the view.
4435 : */
4436 194 : case AT_ReplaceRelOptions:
4437 194 : cmd_lockmode = AccessExclusiveLock;
4438 194 : break;
4439 :
4440 : /*
4441 : * These subcommands affect general strategies for performance
4442 : * and maintenance, though don't change the semantic results
4443 : * from normal data reads and writes. Delaying an ALTER TABLE
4444 : * behind currently active writes only delays the point where
4445 : * the new strategy begins to take effect, so there is no
4446 : * benefit in waiting. In this case the minimum restriction
4447 : * applies: we don't currently allow concurrent catalog
4448 : * updates.
4449 : */
4450 234 : case AT_SetStatistics: /* Uses MVCC in getTableAttrs() */
4451 : case AT_ClusterOn: /* Uses MVCC in getIndexes() */
4452 : case AT_DropCluster: /* Uses MVCC in getIndexes() */
4453 : case AT_SetOptions: /* Uses MVCC in getTableAttrs() */
4454 : case AT_ResetOptions: /* Uses MVCC in getTableAttrs() */
4455 234 : cmd_lockmode = ShareUpdateExclusiveLock;
4456 234 : break;
4457 :
4458 70 : case AT_SetLogged:
4459 : case AT_SetUnLogged:
4460 70 : cmd_lockmode = AccessExclusiveLock;
4461 70 : break;
4462 :
4463 388 : case AT_ValidateConstraint: /* Uses MVCC in getConstraints() */
4464 388 : cmd_lockmode = ShareUpdateExclusiveLock;
4465 388 : break;
4466 :
4467 : /*
4468 : * Rel options are more complex than first appears. Options
4469 : * are set here for tables, views and indexes; for historical
4470 : * reasons these can all be used with ALTER TABLE, so we can't
4471 : * decide between them using the basic grammar.
4472 : */
4473 734 : case AT_SetRelOptions: /* Uses MVCC in getIndexes() and
4474 : * getTables() */
4475 : case AT_ResetRelOptions: /* Uses MVCC in getIndexes() and
4476 : * getTables() */
4477 734 : cmd_lockmode = AlterTableGetRelOptionsLockLevel((List *) cmd->def);
4478 734 : break;
4479 :
4480 2470 : case AT_AttachPartition:
4481 2470 : cmd_lockmode = ShareUpdateExclusiveLock;
4482 2470 : break;
4483 :
4484 516 : case AT_DetachPartition:
4485 516 : if (((PartitionCmd *) cmd->def)->concurrent)
4486 158 : cmd_lockmode = ShareUpdateExclusiveLock;
4487 : else
4488 358 : cmd_lockmode = AccessExclusiveLock;
4489 516 : break;
4490 :
4491 14 : case AT_DetachPartitionFinalize:
4492 14 : cmd_lockmode = ShareUpdateExclusiveLock;
4493 14 : break;
4494 :
4495 0 : case AT_CheckNotNull:
4496 :
4497 : /*
4498 : * This only examines the table's schema; but lock must be
4499 : * strong enough to prevent concurrent DROP NOT NULL.
4500 : */
4501 0 : cmd_lockmode = AccessShareLock;
4502 0 : break;
4503 :
4504 0 : default: /* oops */
4505 0 : elog(ERROR, "unrecognized alter table type: %d",
4506 : (int) cmd->subtype);
4507 : break;
4508 : }
4509 :
4510 : /*
4511 : * Take the greatest lockmode from any subcommand
4512 : */
4513 84722 : if (cmd_lockmode > lockmode)
4514 80014 : lockmode = cmd_lockmode;
4515 : }
4516 :
4517 83826 : return lockmode;
4518 : }
4519 :
4520 : /*
4521 : * ATController provides top level control over the phases.
4522 : *
4523 : * parsetree is passed in to allow it to be passed to event triggers
4524 : * when requested.
4525 : */
4526 : static void
4527 83586 : ATController(AlterTableStmt *parsetree,
4528 : Relation rel, List *cmds, bool recurse, LOCKMODE lockmode,
4529 : AlterTableUtilityContext *context)
4530 : {
4531 83586 : List *wqueue = NIL;
4532 : ListCell *lcmd;
4533 :
4534 : /* Phase 1: preliminary examination of commands, create work queue */
4535 167784 : foreach(lcmd, cmds)
4536 : {
4537 84476 : AlterTableCmd *cmd = (AlterTableCmd *) lfirst(lcmd);
4538 :
4539 84476 : ATPrepCmd(&wqueue, rel, cmd, recurse, false, lockmode, context);
4540 : }
4541 :
4542 : /* Close the relation, but keep lock until commit */
4543 83308 : relation_close(rel, NoLock);
4544 :
4545 : /* Phase 2: update system catalogs */
4546 83308 : ATRewriteCatalogs(&wqueue, lockmode, context);
4547 :
4548 : /* Phase 3: scan/rewrite tables as needed, and run afterStmts */
4549 81284 : ATRewriteTables(parsetree, &wqueue, lockmode, context);
4550 80984 : }
4551 :
4552 : /*
4553 : * ATPrepCmd
4554 : *
4555 : * Traffic cop for ALTER TABLE Phase 1 operations, including simple
4556 : * recursion and permission checks.
4557 : *
4558 : * Caller must have acquired appropriate lock type on relation already.
4559 : * This lock should be held until commit.
4560 : */
4561 : static void
4562 85090 : ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd,
4563 : bool recurse, bool recursing, LOCKMODE lockmode,
4564 : AlterTableUtilityContext *context)
4565 : {
4566 : AlteredTableInfo *tab;
4567 85090 : int pass = AT_PASS_UNSET;
4568 :
4569 : /* Find or create work queue entry for this table */
4570 85090 : tab = ATGetQueueEntry(wqueue, rel);
4571 :
4572 : /*
4573 : * Disallow any ALTER TABLE other than ALTER TABLE DETACH FINALIZE on
4574 : * partitions that are pending detach.
4575 : */
4576 85090 : if (rel->rd_rel->relispartition &&
4577 2500 : cmd->subtype != AT_DetachPartitionFinalize &&
4578 1250 : PartitionHasPendingDetach(RelationGetRelid(rel)))
4579 2 : ereport(ERROR,
4580 : errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
4581 : errmsg("cannot alter partition \"%s\" with an incomplete detach",
4582 : RelationGetRelationName(rel)),
4583 : errhint("Use ALTER TABLE ... DETACH PARTITION ... FINALIZE to complete the pending detach operation."));
4584 :
4585 : /*
4586 : * Copy the original subcommand for each table, so we can scribble on it.
4587 : * This avoids conflicts when different child tables need to make
4588 : * different parse transformations (for example, the same column may have
4589 : * different column numbers in different children).
4590 : */
4591 85088 : cmd = copyObject(cmd);
4592 :
4593 : /*
4594 : * Do permissions and relkind checking, recursion to child tables if
4595 : * needed, and any additional phase-1 processing needed. (But beware of
4596 : * adding any processing that looks at table details that another
4597 : * subcommand could change. In some cases we reject multiple subcommands
4598 : * that could try to change the same state in contrary ways.)
4599 : */
4600 85088 : switch (cmd->subtype)
4601 : {
4602 1806 : case AT_AddColumn: /* ADD COLUMN */
4603 1806 : ATSimplePermissions(cmd->subtype, rel,
4604 : ATT_TABLE | ATT_COMPOSITE_TYPE | ATT_FOREIGN_TABLE);
4605 1806 : ATPrepAddColumn(wqueue, rel, recurse, recursing, false, cmd,
4606 : lockmode, context);
4607 : /* Recursion occurs during execution phase */
4608 1794 : pass = AT_PASS_ADD_COL;
4609 1794 : break;
4610 24 : case AT_AddColumnToView: /* add column via CREATE OR REPLACE VIEW */
4611 24 : ATSimplePermissions(cmd->subtype, rel, ATT_VIEW);
4612 24 : ATPrepAddColumn(wqueue, rel, recurse, recursing, true, cmd,
4613 : lockmode, context);
4614 : /* Recursion occurs during execution phase */
4615 24 : pass = AT_PASS_ADD_COL;
4616 24 : break;
4617 532 : case AT_ColumnDefault: /* ALTER COLUMN DEFAULT */
4618 :
4619 : /*
4620 : * We allow defaults on views so that INSERT into a view can have
4621 : * default-ish behavior. This works because the rewriter
4622 : * substitutes default values into INSERTs before it expands
4623 : * rules.
4624 : */
4625 532 : ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_VIEW | ATT_FOREIGN_TABLE);
4626 532 : ATSimpleRecursion(wqueue, rel, cmd, recurse, lockmode, context);
4627 : /* No command-specific prep needed */
4628 532 : pass = cmd->def ? AT_PASS_ADD_OTHERCONSTR : AT_PASS_DROP;
4629 532 : break;
4630 56 : case AT_CookedColumnDefault: /* add a pre-cooked default */
4631 : /* This is currently used only in CREATE TABLE */
4632 : /* (so the permission check really isn't necessary) */
4633 56 : ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_FOREIGN_TABLE);
4634 : /* This command never recurses */
4635 56 : pass = AT_PASS_ADD_OTHERCONSTR;
4636 56 : break;
4637 102 : case AT_AddIdentity:
4638 102 : ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_VIEW | ATT_FOREIGN_TABLE);
4639 : /* This command never recurses */
4640 102 : pass = AT_PASS_ADD_OTHERCONSTR;
4641 102 : break;
4642 38 : case AT_SetIdentity:
4643 38 : ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_VIEW | ATT_FOREIGN_TABLE);
4644 : /* This command never recurses */
4645 : /* This should run after AddIdentity, so do it in MISC pass */
4646 38 : pass = AT_PASS_MISC;
4647 38 : break;
4648 38 : case AT_DropIdentity:
4649 38 : ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_VIEW | ATT_FOREIGN_TABLE);
4650 : /* This command never recurses */
4651 38 : pass = AT_PASS_DROP;
4652 38 : break;
4653 176 : case AT_DropNotNull: /* ALTER COLUMN DROP NOT NULL */
4654 176 : ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_FOREIGN_TABLE);
4655 170 : ATPrepDropNotNull(rel, recurse, recursing);
4656 164 : ATSimpleRecursion(wqueue, rel, cmd, recurse, lockmode, context);
4657 164 : pass = AT_PASS_DROP;
4658 164 : break;
4659 542 : case AT_SetNotNull: /* ALTER COLUMN SET NOT NULL */
4660 542 : ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_FOREIGN_TABLE);
4661 : /* Need command-specific recursion decision */
4662 536 : ATPrepSetNotNull(wqueue, rel, cmd, recurse, recursing,
4663 : lockmode, context);
4664 536 : pass = AT_PASS_COL_ATTRS;
4665 536 : break;
4666 84 : case AT_CheckNotNull: /* check column is already marked NOT NULL */
4667 84 : ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_FOREIGN_TABLE);
4668 84 : ATSimpleRecursion(wqueue, rel, cmd, recurse, lockmode, context);
4669 : /* No command-specific prep needed */
4670 84 : pass = AT_PASS_COL_ATTRS;
4671 84 : break;
4672 44 : case AT_DropExpression: /* ALTER COLUMN DROP EXPRESSION */
4673 44 : ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_FOREIGN_TABLE);
4674 44 : ATSimpleRecursion(wqueue, rel, cmd, recurse, lockmode, context);
4675 44 : ATPrepDropExpression(rel, cmd, recurse, recursing, lockmode);
4676 32 : pass = AT_PASS_DROP;
4677 32 : break;
4678 164 : case AT_SetStatistics: /* ALTER COLUMN SET STATISTICS */
4679 164 : ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_MATVIEW | ATT_INDEX | ATT_PARTITIONED_INDEX | ATT_FOREIGN_TABLE);
4680 164 : ATSimpleRecursion(wqueue, rel, cmd, recurse, lockmode, context);
4681 : /* No command-specific prep needed */
4682 164 : pass = AT_PASS_MISC;
4683 164 : break;
4684 44 : case AT_SetOptions: /* ALTER COLUMN SET ( options ) */
4685 : case AT_ResetOptions: /* ALTER COLUMN RESET ( options ) */
4686 44 : ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_MATVIEW | ATT_FOREIGN_TABLE);
4687 : /* This command never recurses */
4688 32 : pass = AT_PASS_MISC;
4689 32 : break;
4690 230 : case AT_SetStorage: /* ALTER COLUMN SET STORAGE */
4691 230 : ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_MATVIEW | ATT_FOREIGN_TABLE);
4692 230 : ATSimpleRecursion(wqueue, rel, cmd, recurse, lockmode, context);
4693 : /* No command-specific prep needed */
4694 230 : pass = AT_PASS_MISC;
4695 230 : break;
4696 66 : case AT_SetCompression: /* ALTER COLUMN SET COMPRESSION */
4697 66 : ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_MATVIEW);
4698 : /* This command never recurses */
4699 : /* No command-specific prep needed */
4700 66 : pass = AT_PASS_MISC;
4701 66 : break;
4702 1562 : case AT_DropColumn: /* DROP COLUMN */
4703 1562 : ATSimplePermissions(cmd->subtype, rel,
4704 : ATT_TABLE | ATT_COMPOSITE_TYPE | ATT_FOREIGN_TABLE);
4705 1556 : ATPrepDropColumn(wqueue, rel, recurse, recursing, cmd,
4706 : lockmode, context);
4707 : /* Recursion occurs during execution phase */
4708 1544 : pass = AT_PASS_DROP;
4709 1544 : break;
4710 0 : case AT_AddIndex: /* ADD INDEX */
4711 0 : ATSimplePermissions(cmd->subtype, rel, ATT_TABLE);
4712 : /* This command never recurses */
4713 : /* No command-specific prep needed */
4714 0 : pass = AT_PASS_ADD_INDEX;
4715 0 : break;
4716 69820 : case AT_AddConstraint: /* ADD CONSTRAINT */
4717 69820 : ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_FOREIGN_TABLE);
4718 : /* Recursion occurs during execution phase */
4719 : /* No command-specific prep needed except saving recurse flag */
4720 69820 : if (recurse)
4721 69514 : cmd->recurse = true;
4722 69820 : pass = AT_PASS_ADD_CONSTR;
4723 69820 : break;
4724 0 : case AT_AddIndexConstraint: /* ADD CONSTRAINT USING INDEX */
4725 0 : ATSimplePermissions(cmd->subtype, rel, ATT_TABLE);
4726 : /* This command never recurses */
4727 : /* No command-specific prep needed */
4728 0 : pass = AT_PASS_ADD_INDEXCONSTR;
4729 0 : break;
4730 510 : case AT_DropConstraint: /* DROP CONSTRAINT */
4731 510 : ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_FOREIGN_TABLE);
4732 510 : ATCheckPartitionsNotInUse(rel, lockmode);
4733 : /* Other recursion occurs during execution phase */
4734 : /* No command-specific prep needed except saving recurse flag */
4735 504 : if (recurse)
4736 480 : cmd->recurse = true;
4737 504 : pass = AT_PASS_DROP;
4738 504 : break;
4739 1110 : case AT_AlterColumnType: /* ALTER COLUMN TYPE */
4740 1110 : ATSimplePermissions(cmd->subtype, rel,
4741 : ATT_TABLE | ATT_COMPOSITE_TYPE | ATT_FOREIGN_TABLE);
4742 : /* See comments for ATPrepAlterColumnType */
4743 1110 : cmd = ATParseTransformCmd(wqueue, tab, rel, cmd, recurse, lockmode,
4744 : AT_PASS_UNSET, context);
4745 : Assert(cmd != NULL);
4746 : /* Performs own recursion */
4747 1104 : ATPrepAlterColumnType(wqueue, tab, rel, recurse, recursing, cmd,
4748 : lockmode, context);
4749 960 : pass = AT_PASS_ALTER_TYPE;
4750 960 : break;
4751 164 : case AT_AlterColumnGenericOptions:
4752 164 : ATSimplePermissions(cmd->subtype, rel, ATT_FOREIGN_TABLE);
4753 : /* This command never recurses */
4754 : /* No command-specific prep needed */
4755 164 : pass = AT_PASS_MISC;
4756 164 : break;
4757 1692 : case AT_ChangeOwner: /* ALTER OWNER */
4758 : /* This command never recurses */
4759 : /* No command-specific prep needed */
4760 1692 : pass = AT_PASS_MISC;
4761 1692 : break;
4762 64 : case AT_ClusterOn: /* CLUSTER ON */
4763 : case AT_DropCluster: /* SET WITHOUT CLUSTER */
4764 64 : ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_MATVIEW);
4765 : /* These commands never recurse */
4766 : /* No command-specific prep needed */
4767 64 : pass = AT_PASS_MISC;
4768 64 : break;
4769 32 : case AT_SetLogged: /* SET LOGGED */
4770 32 : ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_SEQUENCE);
4771 32 : if (tab->chgPersistence)
4772 0 : ereport(ERROR,
4773 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
4774 : errmsg("cannot change persistence setting twice")));
4775 32 : tab->chgPersistence = ATPrepChangePersistence(rel, true);
4776 : /* force rewrite if necessary; see comment in ATRewriteTables */
4777 26 : if (tab->chgPersistence)
4778 : {
4779 20 : tab->rewrite |= AT_REWRITE_ALTER_PERSISTENCE;
4780 20 : tab->newrelpersistence = RELPERSISTENCE_PERMANENT;
4781 : }
4782 26 : pass = AT_PASS_MISC;
4783 26 : break;
4784 38 : case AT_SetUnLogged: /* SET UNLOGGED */
4785 38 : ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_SEQUENCE);
4786 38 : if (tab->chgPersistence)
4787 0 : ereport(ERROR,
4788 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
4789 : errmsg("cannot change persistence setting twice")));
4790 38 : tab->chgPersistence = ATPrepChangePersistence(rel, false);
4791 : /* force rewrite if necessary; see comment in ATRewriteTables */
4792 32 : if (tab->chgPersistence)
4793 : {
4794 26 : tab->rewrite |= AT_REWRITE_ALTER_PERSISTENCE;
4795 26 : tab->newrelpersistence = RELPERSISTENCE_UNLOGGED;
4796 : }
4797 32 : pass = AT_PASS_MISC;
4798 32 : break;
4799 6 : case AT_DropOids: /* SET WITHOUT OIDS */
4800 6 : ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_FOREIGN_TABLE);
4801 6 : pass = AT_PASS_DROP;
4802 6 : break;
4803 48 : case AT_SetAccessMethod: /* SET ACCESS METHOD */
4804 48 : ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_MATVIEW);
4805 :
4806 : /* partitioned tables don't have an access method */
4807 48 : if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
4808 6 : ereport(ERROR,
4809 : (errcode(ERRCODE_WRONG_OBJECT_TYPE),
4810 : errmsg("cannot change access method of a partitioned table")));
4811 :
4812 : /* check if another access method change was already requested */
4813 42 : if (OidIsValid(tab->newAccessMethod))
4814 12 : ereport(ERROR,
4815 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
4816 : errmsg("cannot have multiple SET ACCESS METHOD subcommands")));
4817 :
4818 30 : ATPrepSetAccessMethod(tab, rel, cmd->name);
4819 30 : pass = AT_PASS_MISC; /* does not matter; no work in Phase 2 */
4820 30 : break;
4821 158 : case AT_SetTableSpace: /* SET TABLESPACE */
4822 158 : ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_MATVIEW | ATT_INDEX |
4823 : ATT_PARTITIONED_INDEX);
4824 : /* This command never recurses */
4825 158 : ATPrepSetTableSpace(tab, rel, cmd->name, lockmode);
4826 158 : pass = AT_PASS_MISC; /* doesn't actually matter */
4827 158 : break;
4828 928 : case AT_SetRelOptions: /* SET (...) */
4829 : case AT_ResetRelOptions: /* RESET (...) */
4830 : case AT_ReplaceRelOptions: /* reset them all, then set just these */
4831 928 : ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_VIEW | ATT_MATVIEW | ATT_INDEX);
4832 : /* This command never recurses */
4833 : /* No command-specific prep needed */
4834 928 : pass = AT_PASS_MISC;
4835 928 : break;
4836 268 : case AT_AddInherit: /* INHERIT */
4837 268 : ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_FOREIGN_TABLE);
4838 : /* This command never recurses */
4839 268 : ATPrepAddInherit(rel);
4840 250 : pass = AT_PASS_MISC;
4841 250 : break;
4842 38 : case AT_DropInherit: /* NO INHERIT */
4843 38 : ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_FOREIGN_TABLE);
4844 : /* This command never recurses */
4845 : /* No command-specific prep needed */
4846 38 : pass = AT_PASS_MISC;
4847 38 : break;
4848 72 : case AT_AlterConstraint: /* ALTER CONSTRAINT */
4849 72 : ATSimplePermissions(cmd->subtype, rel, ATT_TABLE);
4850 : /* Recursion occurs during execution phase */
4851 66 : pass = AT_PASS_MISC;
4852 66 : break;
4853 388 : case AT_ValidateConstraint: /* VALIDATE CONSTRAINT */
4854 388 : ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_FOREIGN_TABLE);
4855 : /* Recursion occurs during execution phase */
4856 : /* No command-specific prep needed except saving recurse flag */
4857 388 : if (recurse)
4858 388 : cmd->recurse = true;
4859 388 : pass = AT_PASS_MISC;
4860 388 : break;
4861 390 : case AT_ReplicaIdentity: /* REPLICA IDENTITY ... */
4862 390 : ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_MATVIEW);
4863 390 : pass = AT_PASS_MISC;
4864 : /* This command never recurses */
4865 : /* No command-specific prep needed */
4866 390 : break;
4867 336 : case AT_EnableTrig: /* ENABLE TRIGGER variants */
4868 : case AT_EnableAlwaysTrig:
4869 : case AT_EnableReplicaTrig:
4870 : case AT_EnableTrigAll:
4871 : case AT_EnableTrigUser:
4872 : case AT_DisableTrig: /* DISABLE TRIGGER variants */
4873 : case AT_DisableTrigAll:
4874 : case AT_DisableTrigUser:
4875 336 : ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_FOREIGN_TABLE);
4876 : /* Set up recursion for phase 2; no other prep needed */
4877 336 : if (recurse)
4878 308 : cmd->recurse = true;
4879 336 : pass = AT_PASS_MISC;
4880 336 : break;
4881 484 : case AT_EnableRule: /* ENABLE/DISABLE RULE variants */
4882 : case AT_EnableAlwaysRule:
4883 : case AT_EnableReplicaRule:
4884 : case AT_DisableRule:
4885 : case AT_AddOf: /* OF */
4886 : case AT_DropOf: /* NOT OF */
4887 : case AT_EnableRowSecurity:
4888 : case AT_DisableRowSecurity:
4889 : case AT_ForceRowSecurity:
4890 : case AT_NoForceRowSecurity:
4891 484 : ATSimplePermissions(cmd->subtype, rel, ATT_TABLE);
4892 : /* These commands never recurse */
4893 : /* No command-specific prep needed */
4894 484 : pass = AT_PASS_MISC;
4895 484 : break;
4896 46 : case AT_GenericOptions:
4897 46 : ATSimplePermissions(cmd->subtype, rel, ATT_FOREIGN_TABLE);
4898 : /* No command-specific prep needed */
4899 46 : pass = AT_PASS_MISC;
4900 46 : break;
4901 2458 : case AT_AttachPartition:
4902 2458 : ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_PARTITIONED_INDEX);
4903 : /* No command-specific prep needed */
4904 2458 : pass = AT_PASS_MISC;
4905 2458 : break;
4906 516 : case AT_DetachPartition:
4907 516 : ATSimplePermissions(cmd->subtype, rel, ATT_TABLE);
4908 : /* No command-specific prep needed */
4909 510 : pass = AT_PASS_MISC;
4910 510 : break;
4911 14 : case AT_DetachPartitionFinalize:
4912 14 : ATSimplePermissions(cmd->subtype, rel, ATT_TABLE);
4913 : /* No command-specific prep needed */
4914 14 : pass = AT_PASS_MISC;
4915 14 : break;
4916 0 : default: /* oops */
4917 0 : elog(ERROR, "unrecognized alter table type: %d",
4918 : (int) cmd->subtype);
4919 : pass = AT_PASS_UNSET; /* keep compiler quiet */
4920 : break;
4921 : }
4922 : Assert(pass > AT_PASS_UNSET);
4923 :
4924 : /* Add the subcommand to the appropriate list for phase 2 */
4925 84800 : tab->subcmds[pass] = lappend(tab->subcmds[pass], cmd);
4926 84800 : }
4927 :
4928 : /*
4929 : * ATRewriteCatalogs
4930 : *
4931 : * Traffic cop for ALTER TABLE Phase 2 operations. Subcommands are
4932 : * dispatched in a "safe" execution order (designed to avoid unnecessary
4933 : * conflicts).
4934 : */
4935 : static void
4936 83308 : ATRewriteCatalogs(List **wqueue, LOCKMODE lockmode,
4937 : AlterTableUtilityContext *context)
4938 : {
4939 : int pass;
4940 : ListCell *ltab;
4941 :
4942 : /*
4943 : * We process all the tables "in parallel", one pass at a time. This is
4944 : * needed because we may have to propagate work from one table to another
4945 : * (specifically, ALTER TYPE on a foreign key's PK has to dispatch the
4946 : * re-adding of the foreign key constraint to the other table). Work can
4947 : * only be propagated into later passes, however.
4948 : */
4949 991318 : for (pass = 0; pass < AT_NUM_PASSES; pass++)
4950 : {
4951 : /* Go through each table that needs to be processed */
4952 1829940 : foreach(ltab, *wqueue)
4953 : {
4954 921930 : AlteredTableInfo *tab = (AlteredTableInfo *) lfirst(ltab);
4955 921930 : List *subcmds = tab->subcmds[pass];
4956 : ListCell *lcmd;
4957 :
4958 921930 : if (subcmds == NIL)
4959 729686 : continue;
4960 :
4961 : /*
4962 : * Open the relation and store it in tab. This allows subroutines
4963 : * close and reopen, if necessary. Appropriate lock was obtained
4964 : * by phase 1, needn't get it again.
4965 : */
4966 192244 : tab->rel = relation_open(tab->relid, NoLock);
4967 :
4968 395494 : foreach(lcmd, subcmds)
4969 205274 : ATExecCmd(wqueue, tab,
4970 205274 : lfirst_node(AlterTableCmd, lcmd),
4971 : lockmode, pass, context);
4972 :
4973 : /*
4974 : * After the ALTER TYPE pass, do cleanup work (this is not done in
4975 : * ATExecAlterColumnType since it should be done only once if
4976 : * multiple columns of a table are altered).
4977 : */
4978 190220 : if (pass == AT_PASS_ALTER_TYPE)
4979 864 : ATPostAlterTypeCleanup(wqueue, tab, lockmode);
4980 :
4981 190220 : if (tab->rel)
4982 : {
4983 190220 : relation_close(tab->rel, NoLock);
4984 190220 : tab->rel = NULL;
4985 : }
4986 : }
4987 : }
4988 :
4989 : /* Check to see if a toast table must be added. */
4990 166034 : foreach(ltab, *wqueue)
4991 : {
4992 84750 : AlteredTableInfo *tab = (AlteredTableInfo *) lfirst(ltab);
4993 :
4994 : /*
4995 : * If the table is source table of ATTACH PARTITION command, we did
4996 : * not modify anything about it that will change its toasting
4997 : * requirement, so no need to check.
4998 : */
4999 84750 : if (((tab->relkind == RELKIND_RELATION ||
5000 5328 : tab->relkind == RELKIND_PARTITIONED_TABLE) &&
5001 82940 : tab->partition_constraint == NULL) ||
5002 3628 : tab->relkind == RELKIND_MATVIEW)
5003 81172 : AlterTableCreateToastTable(tab->relid, (Datum) 0, lockmode);
5004 : }
5005 81284 : }
5006 :
5007 : /*
5008 : * ATExecCmd: dispatch a subcommand to appropriate execution routine
5009 : */
5010 : static void
5011 205274 : ATExecCmd(List **wqueue, AlteredTableInfo *tab,
5012 : AlterTableCmd *cmd, LOCKMODE lockmode, int cur_pass,
5013 : AlterTableUtilityContext *context)
5014 : {
5015 205274 : ObjectAddress address = InvalidObjectAddress;
5016 205274 : Relation rel = tab->rel;
5017 :
5018 205274 : switch (cmd->subtype)
5019 : {
5020 1812 : case AT_AddColumn: /* ADD COLUMN */
5021 : case AT_AddColumnToView: /* add column via CREATE OR REPLACE VIEW */
5022 1812 : address = ATExecAddColumn(wqueue, tab, rel, &cmd,
5023 1812 : cmd->recurse, false,
5024 : lockmode, cur_pass, context);
5025 1698 : break;
5026 532 : case AT_ColumnDefault: /* ALTER COLUMN DEFAULT */
5027 532 : address = ATExecColumnDefault(rel, cmd->name, cmd->def, lockmode);
5028 484 : break;
5029 56 : case AT_CookedColumnDefault: /* add a pre-cooked default */
5030 56 : address = ATExecCookedColumnDefault(rel, cmd->num, cmd->def);
5031 56 : break;
5032 102 : case AT_AddIdentity:
5033 102 : cmd = ATParseTransformCmd(wqueue, tab, rel, cmd, false, lockmode,
5034 : cur_pass, context);
5035 : Assert(cmd != NULL);
5036 96 : address = ATExecAddIdentity(rel, cmd->name, cmd->def, lockmode);
5037 72 : break;
5038 38 : case AT_SetIdentity:
5039 38 : cmd = ATParseTransformCmd(wqueue, tab, rel, cmd, false, lockmode,
5040 : cur_pass, context);
5041 : Assert(cmd != NULL);
5042 38 : address = ATExecSetIdentity(rel, cmd->name, cmd->def, lockmode);
5043 32 : break;
5044 38 : case AT_DropIdentity:
5045 38 : address = ATExecDropIdentity(rel, cmd->name, cmd->missing_ok, lockmode);
5046 32 : break;
5047 164 : case AT_DropNotNull: /* ALTER COLUMN DROP NOT NULL */
5048 164 : address = ATExecDropNotNull(rel, cmd->name, lockmode);
5049 110 : break;
5050 50650 : case AT_SetNotNull: /* ALTER COLUMN SET NOT NULL */
5051 50650 : address = ATExecSetNotNull(tab, rel, cmd->name, lockmode);
5052 50614 : break;
5053 30 : case AT_CheckNotNull: /* check column is already marked NOT NULL */
5054 30 : ATExecCheckNotNull(tab, rel, cmd->name, lockmode);
5055 18 : break;
5056 32 : case AT_DropExpression:
5057 32 : address = ATExecDropExpression(rel, cmd->name, cmd->missing_ok, lockmode);
5058 26 : break;
5059 164 : case AT_SetStatistics: /* ALTER COLUMN SET STATISTICS */
5060 164 : address = ATExecSetStatistics(rel, cmd->name, cmd->num, cmd->def, lockmode);
5061 116 : break;
5062 26 : case AT_SetOptions: /* ALTER COLUMN SET ( options ) */
5063 26 : address = ATExecSetOptions(rel, cmd->name, cmd->def, false, lockmode);
5064 26 : break;
5065 6 : case AT_ResetOptions: /* ALTER COLUMN RESET ( options ) */
5066 6 : address = ATExecSetOptions(rel, cmd->name, cmd->def, true, lockmode);
5067 6 : break;
5068 230 : case AT_SetStorage: /* ALTER COLUMN SET STORAGE */
5069 230 : address = ATExecSetStorage(rel, cmd->name, cmd->def, lockmode);
5070 218 : break;
5071 66 : case AT_SetCompression: /* ALTER COLUMN SET COMPRESSION */
5072 66 : address = ATExecSetCompression(rel, cmd->name, cmd->def,
5073 : lockmode);
5074 60 : break;
5075 1544 : case AT_DropColumn: /* DROP COLUMN */
5076 1544 : address = ATExecDropColumn(wqueue, rel, cmd->name,
5077 1544 : cmd->behavior, cmd->recurse, false,
5078 1544 : cmd->missing_ok, lockmode,
5079 : NULL);
5080 1376 : break;
5081 854 : case AT_AddIndex: /* ADD INDEX */
5082 854 : address = ATExecAddIndex(tab, rel, (IndexStmt *) cmd->def, false,
5083 : lockmode);
5084 750 : break;
5085 398 : case AT_ReAddIndex: /* ADD INDEX */
5086 398 : address = ATExecAddIndex(tab, rel, (IndexStmt *) cmd->def, true,
5087 : lockmode);
5088 398 : break;
5089 14 : case AT_ReAddStatistics: /* ADD STATISTICS */
5090 14 : address = ATExecAddStatistics(tab, rel, (CreateStatsStmt *) cmd->def,
5091 : true, lockmode);
5092 14 : break;
5093 72510 : case AT_AddConstraint: /* ADD CONSTRAINT */
5094 : /* Transform the command only during initial examination */
5095 72510 : if (cur_pass == AT_PASS_ADD_CONSTR)
5096 69790 : cmd = ATParseTransformCmd(wqueue, tab, rel, cmd,
5097 69820 : cmd->recurse, lockmode,
5098 : cur_pass, context);
5099 : /* Depending on constraint type, might be no more work to do now */
5100 72480 : if (cmd != NULL)
5101 : address =
5102 2690 : ATExecAddConstraint(wqueue, tab, rel,
5103 2690 : (Constraint *) cmd->def,
5104 2690 : cmd->recurse, false, lockmode);
5105 72106 : break;
5106 120 : case AT_ReAddConstraint: /* Re-add pre-existing check constraint */
5107 : address =
5108 120 : ATExecAddConstraint(wqueue, tab, rel, (Constraint *) cmd->def,
5109 : true, true, lockmode);
5110 108 : break;
5111 14 : case AT_ReAddDomainConstraint: /* Re-add pre-existing domain check
5112 : * constraint */
5113 : address =
5114 14 : AlterDomainAddConstraint(((AlterDomainStmt *) cmd->def)->typeName,
5115 14 : ((AlterDomainStmt *) cmd->def)->def,
5116 : NULL);
5117 8 : break;
5118 54 : case AT_ReAddComment: /* Re-add existing comment */
5119 54 : address = CommentObject((CommentStmt *) cmd->def);
5120 54 : break;
5121 66282 : case AT_AddIndexConstraint: /* ADD CONSTRAINT USING INDEX */
5122 66282 : address = ATExecAddIndexConstraint(tab, rel, (IndexStmt *) cmd->def,
5123 : lockmode);
5124 66270 : break;
5125 66 : case AT_AlterConstraint: /* ALTER CONSTRAINT */
5126 66 : address = ATExecAlterConstraint(rel, cmd, false, false, lockmode);
5127 54 : break;
5128 388 : case AT_ValidateConstraint: /* VALIDATE CONSTRAINT */
5129 388 : address = ATExecValidateConstraint(wqueue, rel, cmd->name, cmd->recurse,
5130 : false, lockmode);
5131 388 : break;
5132 504 : case AT_DropConstraint: /* DROP CONSTRAINT */
5133 504 : ATExecDropConstraint(rel, cmd->name, cmd->behavior,
5134 504 : cmd->recurse, false,
5135 504 : cmd->missing_ok, lockmode);
5136 336 : break;
5137 930 : case AT_AlterColumnType: /* ALTER COLUMN TYPE */
5138 : /* parse transformation was done earlier */
5139 930 : address = ATExecAlterColumnType(tab, rel, cmd, lockmode);
5140 894 : break;
5141 164 : case AT_AlterColumnGenericOptions: /* ALTER COLUMN OPTIONS */
5142 : address =
5143 164 : ATExecAlterColumnGenericOptions(rel, cmd->name,
5144 164 : (List *) cmd->def, lockmode);
5145 158 : break;
5146 1692 : case AT_ChangeOwner: /* ALTER OWNER */
5147 1686 : ATExecChangeOwner(RelationGetRelid(rel),
5148 1692 : get_rolespec_oid(cmd->newowner, false),
5149 : false, lockmode);
5150 1674 : break;
5151 64 : case AT_ClusterOn: /* CLUSTER ON */
5152 64 : address = ATExecClusterOn(rel, cmd->name, lockmode);
5153 58 : break;
5154 18 : case AT_DropCluster: /* SET WITHOUT CLUSTER */
5155 18 : ATExecDropCluster(rel, lockmode);
5156 12 : break;
5157 58 : case AT_SetLogged: /* SET LOGGED */
5158 : case AT_SetUnLogged: /* SET UNLOGGED */
5159 58 : break;
5160 6 : case AT_DropOids: /* SET WITHOUT OIDS */
5161 : /* nothing to do here, oid columns don't exist anymore */
5162 6 : break;
5163 18 : case AT_SetAccessMethod: /* SET ACCESS METHOD */
5164 : /* handled specially in Phase 3 */
5165 18 : break;
5166 158 : case AT_SetTableSpace: /* SET TABLESPACE */
5167 :
5168 : /*
5169 : * Only do this for partitioned tables and indexes, for which this
5170 : * is just a catalog change. Other relation types which have
5171 : * storage are handled by Phase 3.
5172 : */
5173 158 : if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE ||
5174 146 : rel->rd_rel->relkind == RELKIND_PARTITIONED_INDEX)
5175 36 : ATExecSetTableSpaceNoStorage(rel, tab->newTableSpace);
5176 :
5177 152 : break;
5178 928 : case AT_SetRelOptions: /* SET (...) */
5179 : case AT_ResetRelOptions: /* RESET (...) */
5180 : case AT_ReplaceRelOptions: /* replace entire option list */
5181 928 : ATExecSetRelOptions(rel, (List *) cmd->def, cmd->subtype, lockmode);
5182 876 : break;
5183 120 : case AT_EnableTrig: /* ENABLE TRIGGER name */
5184 120 : ATExecEnableDisableTrigger(rel, cmd->name,
5185 : TRIGGER_FIRES_ON_ORIGIN, false,
5186 120 : cmd->recurse,
5187 : lockmode);
5188 120 : break;
5189 40 : case AT_EnableAlwaysTrig: /* ENABLE ALWAYS TRIGGER name */
5190 40 : ATExecEnableDisableTrigger(rel, cmd->name,
5191 : TRIGGER_FIRES_ALWAYS, false,
5192 40 : cmd->recurse,
5193 : lockmode);
5194 40 : break;
5195 16 : case AT_EnableReplicaTrig: /* ENABLE REPLICA TRIGGER name */
5196 16 : ATExecEnableDisableTrigger(rel, cmd->name,
5197 : TRIGGER_FIRES_ON_REPLICA, false,
5198 16 : cmd->recurse,
5199 : lockmode);
5200 16 : break;
5201 136 : case AT_DisableTrig: /* DISABLE TRIGGER name */
5202 136 : ATExecEnableDisableTrigger(rel, cmd->name,
5203 : TRIGGER_DISABLED, false,
5204 136 : cmd->recurse,
5205 : lockmode);
5206 136 : break;
5207 0 : case AT_EnableTrigAll: /* ENABLE TRIGGER ALL */
5208 0 : ATExecEnableDisableTrigger(rel, NULL,
5209 : TRIGGER_FIRES_ON_ORIGIN, false,
5210 0 : cmd->recurse,
5211 : lockmode);
5212 0 : break;
5213 12 : case AT_DisableTrigAll: /* DISABLE TRIGGER ALL */
5214 12 : ATExecEnableDisableTrigger(rel, NULL,
5215 : TRIGGER_DISABLED, false,
5216 12 : cmd->recurse,
5217 : lockmode);
5218 12 : break;
5219 0 : case AT_EnableTrigUser: /* ENABLE TRIGGER USER */
5220 0 : ATExecEnableDisableTrigger(rel, NULL,
5221 : TRIGGER_FIRES_ON_ORIGIN, true,
5222 0 : cmd->recurse,
5223 : lockmode);
5224 0 : break;
5225 12 : case AT_DisableTrigUser: /* DISABLE TRIGGER USER */
5226 12 : ATExecEnableDisableTrigger(rel, NULL,
5227 : TRIGGER_DISABLED, true,
5228 12 : cmd->recurse,
5229 : lockmode);
5230 12 : break;
5231 :
5232 6 : case AT_EnableRule: /* ENABLE RULE name */
5233 6 : ATExecEnableDisableRule(rel, cmd->name,
5234 : RULE_FIRES_ON_ORIGIN, lockmode);
5235 6 : break;
5236 0 : case AT_EnableAlwaysRule: /* ENABLE ALWAYS RULE name */
5237 0 : ATExecEnableDisableRule(rel, cmd->name,
5238 : RULE_FIRES_ALWAYS, lockmode);
5239 0 : break;
5240 6 : case AT_EnableReplicaRule: /* ENABLE REPLICA RULE name */
5241 6 : ATExecEnableDisableRule(rel, cmd->name,
5242 : RULE_FIRES_ON_REPLICA, lockmode);
5243 6 : break;
5244 6 : case AT_DisableRule: /* DISABLE RULE name */
5245 6 : ATExecEnableDisableRule(rel, cmd->name,
5246 : RULE_DISABLED, lockmode);
5247 6 : break;
5248 :
5249 250 : case AT_AddInherit:
5250 250 : address = ATExecAddInherit(rel, (RangeVar *) cmd->def, lockmode);
5251 178 : break;
5252 38 : case AT_DropInherit:
5253 38 : address = ATExecDropInherit(rel, (RangeVar *) cmd->def, lockmode);
5254 32 : break;
5255 66 : case AT_AddOf:
5256 66 : address = ATExecAddOf(rel, (TypeName *) cmd->def, lockmode);
5257 30 : break;
5258 6 : case AT_DropOf:
5259 6 : ATExecDropOf(rel, lockmode);
5260 6 : break;
5261 408 : case AT_ReplicaIdentity:
5262 408 : ATExecReplicaIdentity(rel, (ReplicaIdentityStmt *) cmd->def, lockmode);
5263 366 : break;
5264 276 : case AT_EnableRowSecurity:
5265 276 : ATExecSetRowSecurity(rel, true);
5266 276 : break;
5267 8 : case AT_DisableRowSecurity:
5268 8 : ATExecSetRowSecurity(rel, false);
5269 8 : break;
5270 80 : case AT_ForceRowSecurity:
5271 80 : ATExecForceNoForceRowSecurity(rel, true);
5272 80 : break;
5273 30 : case AT_NoForceRowSecurity:
5274 30 : ATExecForceNoForceRowSecurity(rel, false);
5275 30 : break;
5276 46 : case AT_GenericOptions:
5277 46 : ATExecGenericOptions(rel, (List *) cmd->def);
5278 44 : break;
5279 2458 : case AT_AttachPartition:
5280 2458 : cmd = ATParseTransformCmd(wqueue, tab, rel, cmd, false, lockmode,
5281 : cur_pass, context);
5282 : Assert(cmd != NULL);
5283 2428 : if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
5284 2068 : address = ATExecAttachPartition(wqueue, rel, (PartitionCmd *) cmd->def,
5285 : context);
5286 : else
5287 360 : address = ATExecAttachPartitionIdx(wqueue, rel,
5288 360 : ((PartitionCmd *) cmd->def)->name);
5289 2122 : break;
5290 510 : case AT_DetachPartition:
5291 510 : cmd = ATParseTransformCmd(wqueue, tab, rel, cmd, false, lockmode,
5292 : cur_pass, context);
5293 : Assert(cmd != NULL);
5294 : /* ATPrepCmd ensures it must be a table */
5295 : Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
5296 504 : address = ATExecDetachPartition(wqueue, tab, rel,
5297 504 : ((PartitionCmd *) cmd->def)->name,
5298 504 : ((PartitionCmd *) cmd->def)->concurrent);
5299 374 : break;
5300 14 : case AT_DetachPartitionFinalize:
5301 14 : address = ATExecDetachPartitionFinalize(rel, ((PartitionCmd *) cmd->def)->name);
5302 14 : break;
5303 0 : default: /* oops */
5304 0 : elog(ERROR, "unrecognized alter table type: %d",
5305 : (int) cmd->subtype);
5306 : break;
5307 : }
5308 :
5309 : /*
5310 : * Report the subcommand to interested event triggers.
5311 : */
5312 203250 : if (cmd)
5313 133460 : EventTriggerCollectAlterTableSubcmd((Node *) cmd, address);
5314 :
5315 : /*
5316 : * Bump the command counter to ensure the next subcommand in the sequence
5317 : * can see the changes so far
5318 : */
5319 203250 : CommandCounterIncrement();
5320 203250 : }
5321 :
5322 : /*
5323 : * ATParseTransformCmd: perform parse transformation for one subcommand
5324 : *
5325 : * Returns the transformed subcommand tree, if there is one, else NULL.
5326 : *
5327 : * The parser may hand back additional AlterTableCmd(s) and/or other
5328 : * utility statements, either before or after the original subcommand.
5329 : * Other AlterTableCmds are scheduled into the appropriate slot of the
5330 : * AlteredTableInfo (they had better be for later passes than the current one).
5331 : * Utility statements that are supposed to happen before the AlterTableCmd
5332 : * are executed immediately. Those that are supposed to happen afterwards
5333 : * are added to the tab->afterStmts list to be done at the very end.
5334 : */
5335 : static AlterTableCmd *
5336 75730 : ATParseTransformCmd(List **wqueue, AlteredTableInfo *tab, Relation rel,
5337 : AlterTableCmd *cmd, bool recurse, LOCKMODE lockmode,
5338 : int cur_pass, AlterTableUtilityContext *context)
5339 : {
5340 75730 : AlterTableCmd *newcmd = NULL;
5341 75730 : AlterTableStmt *atstmt = makeNode(AlterTableStmt);
5342 : List *beforeStmts;
5343 : List *afterStmts;
5344 : ListCell *lc;
5345 :
5346 : /* Gin up an AlterTableStmt with just this subcommand and this table */
5347 75730 : atstmt->relation =
5348 75730 : makeRangeVar(get_namespace_name(RelationGetNamespace(rel)),
5349 75730 : pstrdup(RelationGetRelationName(rel)),
5350 : -1);
5351 75730 : atstmt->relation->inh = recurse;
5352 75730 : atstmt->cmds = list_make1(cmd);
5353 75730 : atstmt->objtype = OBJECT_TABLE; /* needn't be picky here */
5354 75730 : atstmt->missing_ok = false;
5355 :
5356 : /* Transform the AlterTableStmt */
5357 75730 : atstmt = transformAlterTableStmt(RelationGetRelid(rel),
5358 : atstmt,
5359 : context->queryString,
5360 : &beforeStmts,
5361 : &afterStmts);
5362 :
5363 : /* Execute any statements that should happen before these subcommand(s) */
5364 75974 : foreach(lc, beforeStmts)
5365 : {
5366 322 : Node *stmt = (Node *) lfirst(lc);
5367 :
5368 322 : ProcessUtilityForAlterTable(stmt, context);
5369 310 : CommandCounterIncrement();
5370 : }
5371 :
5372 : /* Examine the transformed subcommands and schedule them appropriately */
5373 201478 : foreach(lc, atstmt->cmds)
5374 : {
5375 125826 : AlterTableCmd *cmd2 = lfirst_node(AlterTableCmd, lc);
5376 : int pass;
5377 :
5378 : /*
5379 : * This switch need only cover the subcommand types that can be added
5380 : * by parse_utilcmd.c; otherwise, we'll use the default strategy of
5381 : * executing the subcommand immediately, as a substitute for the
5382 : * original subcommand. (Note, however, that this does cause
5383 : * AT_AddConstraint subcommands to be rescheduled into later passes,
5384 : * which is important for index and foreign key constraints.)
5385 : *
5386 : * We assume we needn't do any phase-1 checks for added subcommands.
5387 : */
5388 125826 : switch (cmd2->subtype)
5389 : {
5390 50114 : case AT_SetNotNull:
5391 : /* Need command-specific recursion decision */
5392 50114 : ATPrepSetNotNull(wqueue, rel, cmd2,
5393 : recurse, false,
5394 : lockmode, context);
5395 50114 : pass = AT_PASS_COL_ATTRS;
5396 50114 : break;
5397 878 : case AT_AddIndex:
5398 : /* This command never recurses */
5399 : /* No command-specific prep needed */
5400 878 : pass = AT_PASS_ADD_INDEX;
5401 878 : break;
5402 66282 : case AT_AddIndexConstraint:
5403 : /* This command never recurses */
5404 : /* No command-specific prep needed */
5405 66282 : pass = AT_PASS_ADD_INDEXCONSTR;
5406 66282 : break;
5407 2690 : case AT_AddConstraint:
5408 : /* Recursion occurs during execution phase */
5409 2690 : if (recurse)
5410 2648 : cmd2->recurse = true;
5411 2690 : switch (castNode(Constraint, cmd2->def)->contype)
5412 : {
5413 0 : case CONSTR_PRIMARY:
5414 : case CONSTR_UNIQUE:
5415 : case CONSTR_EXCLUSION:
5416 0 : pass = AT_PASS_ADD_INDEXCONSTR;
5417 0 : break;
5418 2690 : default:
5419 2690 : pass = AT_PASS_ADD_OTHERCONSTR;
5420 2690 : break;
5421 : }
5422 2690 : break;
5423 0 : case AT_AlterColumnGenericOptions:
5424 : /* This command never recurses */
5425 : /* No command-specific prep needed */
5426 0 : pass = AT_PASS_MISC;
5427 0 : break;
5428 5862 : default:
5429 5862 : pass = cur_pass;
5430 5862 : break;
5431 : }
5432 :
5433 125826 : if (pass < cur_pass)
5434 : {
5435 : /* Cannot schedule into a pass we already finished */
5436 0 : elog(ERROR, "ALTER TABLE scheduling failure: too late for pass %d",
5437 : pass);
5438 : }
5439 125826 : else if (pass > cur_pass)
5440 : {
5441 : /* OK, queue it up for later */
5442 119964 : tab->subcmds[pass] = lappend(tab->subcmds[pass], cmd2);
5443 : }
5444 : else
5445 : {
5446 : /*
5447 : * We should see at most one subcommand for the current pass,
5448 : * which is the transformed version of the original subcommand.
5449 : */
5450 5862 : if (newcmd == NULL && cmd->subtype == cmd2->subtype)
5451 : {
5452 : /* Found the transformed version of our subcommand */
5453 5862 : newcmd = cmd2;
5454 : }
5455 : else
5456 0 : elog(ERROR, "ALTER TABLE scheduling failure: bogus item for pass %d",
5457 : pass);
5458 : }
5459 : }
5460 :
5461 : /* Queue up any after-statements to happen at the end */
5462 75652 : tab->afterStmts = list_concat(tab->afterStmts, afterStmts);
5463 :
5464 75652 : return newcmd;
5465 : }
5466 :
5467 : /*
5468 : * ATRewriteTables: ALTER TABLE phase 3
5469 : */
5470 : static void
5471 81284 : ATRewriteTables(AlterTableStmt *parsetree, List **wqueue, LOCKMODE lockmode,
5472 : AlterTableUtilityContext *context)
5473 : {
5474 : ListCell *ltab;
5475 :
5476 : /* Go through each table that needs to be checked or rewritten */
5477 165784 : foreach(ltab, *wqueue)
5478 : {
5479 84738 : AlteredTableInfo *tab = (AlteredTableInfo *) lfirst(ltab);
5480 :
5481 : /* Relations without storage may be ignored here */
5482 84738 : if (!RELKIND_HAS_STORAGE(tab->relkind))
5483 5052 : continue;
5484 :
5485 : /*
5486 : * If we change column data types, the operation has to be propagated
5487 : * to tables that use this table's rowtype as a column type.
5488 : * tab->newvals will also be non-NULL in the case where we're adding a
5489 : * column with a default. We choose to forbid that case as well,
5490 : * since composite types might eventually support defaults.
5491 : *
5492 : * (Eventually we'll probably need to check for composite type
5493 : * dependencies even when we're just scanning the table without a
5494 : * rewrite, but at the moment a composite type does not enforce any
5495 : * constraints, so it's not necessary/appropriate to enforce them just
5496 : * during ALTER.)
5497 : */
5498 79686 : if (tab->newvals != NIL || tab->rewrite > 0)
5499 : {
5500 : Relation rel;
5501 :
5502 1314 : rel = table_open(tab->relid, NoLock);
5503 1314 : find_composite_type_dependencies(rel->rd_rel->reltype, rel, NULL);
5504 1302 : table_close(rel, NoLock);
5505 : }
5506 :
5507 : /*
5508 : * We only need to rewrite the table if at least one column needs to
5509 : * be recomputed, or we are changing its persistence or access method.
5510 : *
5511 : * There are two reasons for requiring a rewrite when changing
5512 : * persistence: on one hand, we need to ensure that the buffers
5513 : * belonging to each of the two relations are marked with or without
5514 : * BM_PERMANENT properly. On the other hand, since rewriting creates
5515 : * and assigns a new relfilenumber, we automatically create or drop an
5516 : * init fork for the relation as appropriate.
5517 : */
5518 79674 : if (tab->rewrite > 0 && tab->relkind != RELKIND_SEQUENCE)
5519 716 : {
5520 : /* Build a temporary relation and copy data */
5521 : Relation OldHeap;
5522 : Oid OIDNewHeap;
5523 : Oid NewAccessMethod;
5524 : Oid NewTableSpace;
5525 : char persistence;
5526 :
5527 748 : OldHeap = table_open(tab->relid, NoLock);
5528 :
5529 : /*
5530 : * We don't support rewriting of system catalogs; there are too
5531 : * many corner cases and too little benefit. In particular this
5532 : * is certainly not going to work for mapped catalogs.
5533 : */
5534 748 : if (IsSystemRelation(OldHeap))
5535 0 : ereport(ERROR,
5536 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
5537 : errmsg("cannot rewrite system relation \"%s\"",
5538 : RelationGetRelationName(OldHeap))));
5539 :
5540 748 : if (RelationIsUsedAsCatalogTable(OldHeap))
5541 2 : ereport(ERROR,
5542 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
5543 : errmsg("cannot rewrite table \"%s\" used as a catalog table",
5544 : RelationGetRelationName(OldHeap))));
5545 :
5546 : /*
5547 : * Don't allow rewrite on temp tables of other backends ... their
5548 : * local buffer manager is not going to cope.
5549 : */
5550 746 : if (RELATION_IS_OTHER_TEMP(OldHeap))
5551 0 : ereport(ERROR,
5552 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
5553 : errmsg("cannot rewrite temporary tables of other sessions")));
5554 :
5555 : /*
5556 : * Select destination tablespace (same as original unless user
5557 : * requested a change)
5558 : */
5559 746 : if (tab->newTableSpace)
5560 0 : NewTableSpace = tab->newTableSpace;
5561 : else
5562 746 : NewTableSpace = OldHeap->rd_rel->reltablespace;
5563 :
5564 : /*
5565 : * Select destination access method (same as original unless user
5566 : * requested a change)
5567 : */
5568 746 : if (OidIsValid(tab->newAccessMethod))
5569 18 : NewAccessMethod = tab->newAccessMethod;
5570 : else
5571 728 : NewAccessMethod = OldHeap->rd_rel->relam;
5572 :
5573 : /*
5574 : * Select persistence of transient table (same as original unless
5575 : * user requested a change)
5576 : */
5577 746 : persistence = tab->chgPersistence ?
5578 712 : tab->newrelpersistence : OldHeap->rd_rel->relpersistence;
5579 :
5580 746 : table_close(OldHeap, NoLock);
5581 :
5582 : /*
5583 : * Fire off an Event Trigger now, before actually rewriting the
5584 : * table.
5585 : *
5586 : * We don't support Event Trigger for nested commands anywhere,
5587 : * here included, and parsetree is given NULL when coming from
5588 : * AlterTableInternal.
5589 : *
5590 : * And fire it only once.
5591 : */
5592 746 : if (parsetree)
5593 746 : EventTriggerTableRewrite((Node *) parsetree,
5594 : tab->relid,
5595 : tab->rewrite);
5596 :
5597 : /*
5598 : * Create transient table that will receive the modified data.
5599 : *
5600 : * Ensure it is marked correctly as logged or unlogged. We have
5601 : * to do this here so that buffers for the new relfilenumber will
5602 : * have the right persistence set, and at the same time ensure
5603 : * that the original filenumbers's buffers will get read in with
5604 : * the correct setting (i.e. the original one). Otherwise a
5605 : * rollback after the rewrite would possibly result with buffers
5606 : * for the original filenumbers having the wrong persistence
5607 : * setting.
5608 : *
5609 : * NB: This relies on swap_relation_files() also swapping the
5610 : * persistence. That wouldn't work for pg_class, but that can't be
5611 : * unlogged anyway.
5612 : */
5613 740 : OIDNewHeap = make_new_heap(tab->relid, NewTableSpace, NewAccessMethod,
5614 : persistence, lockmode);
5615 :
5616 : /*
5617 : * Copy the heap data into the new table with the desired
5618 : * modifications, and test the current data within the table
5619 : * against new constraints generated by ALTER TABLE commands.
5620 : */
5621 740 : ATRewriteTable(tab, OIDNewHeap, lockmode);
5622 :
5623 : /*
5624 : * Swap the physical files of the old and new heaps, then rebuild
5625 : * indexes and discard the old heap. We can use RecentXmin for
5626 : * the table's new relfrozenxid because we rewrote all the tuples
5627 : * in ATRewriteTable, so no older Xid remains in the table. Also,
5628 : * we never try to swap toast tables by content, since we have no
5629 : * interest in letting this code work on system catalogs.
5630 : */
5631 722 : finish_heap_swap(tab->relid, OIDNewHeap,
5632 : false, false, true,
5633 722 : !OidIsValid(tab->newTableSpace),
5634 : RecentXmin,
5635 : ReadNextMultiXactId(),
5636 : persistence);
5637 :
5638 716 : InvokeObjectPostAlterHook(RelationRelationId, tab->relid, 0);
5639 : }
5640 78926 : else if (tab->rewrite > 0 && tab->relkind == RELKIND_SEQUENCE)
5641 : {
5642 12 : if (tab->chgPersistence)
5643 12 : SequenceChangePersistence(tab->relid, tab->newrelpersistence);
5644 : }
5645 : else
5646 : {
5647 : /*
5648 : * If required, test the current data within the table against new
5649 : * constraints generated by ALTER TABLE commands, but don't
5650 : * rebuild data.
5651 : */
5652 78914 : if (tab->constraints != NIL || tab->verify_new_notnull ||
5653 76798 : tab->partition_constraint != NULL)
5654 3798 : ATRewriteTable(tab, InvalidOid, lockmode);
5655 :
5656 : /*
5657 : * If we had SET TABLESPACE but no reason to reconstruct tuples,
5658 : * just do a block-by-block copy.
5659 : */
5660 78720 : if (tab->newTableSpace)
5661 122 : ATExecSetTableSpace(tab->relid, tab->newTableSpace, lockmode);
5662 : }
5663 :
5664 : /*
5665 : * Also change persistence of owned sequences, so that it matches the
5666 : * table persistence.
5667 : */
5668 79448 : if (tab->chgPersistence)
5669 : {
5670 46 : List *seqlist = getOwnedSequences(tab->relid);
5671 : ListCell *lc;
5672 :
5673 76 : foreach(lc, seqlist)
5674 : {
5675 30 : Oid seq_relid = lfirst_oid(lc);
5676 :
5677 30 : SequenceChangePersistence(seq_relid, tab->newrelpersistence);
5678 : }
5679 : }
5680 : }
5681 :
5682 : /*
5683 : * Foreign key constraints are checked in a final pass, since (a) it's
5684 : * generally best to examine each one separately, and (b) it's at least
5685 : * theoretically possible that we have changed both relations of the
5686 : * foreign key, and we'd better have finished both rewrites before we try
5687 : * to read the tables.
5688 : */
5689 165360 : foreach(ltab, *wqueue)
5690 : {
5691 84376 : AlteredTableInfo *tab = (AlteredTableInfo *) lfirst(ltab);
5692 84376 : Relation rel = NULL;
5693 : ListCell *lcon;
5694 :
5695 : /* Relations without storage may be ignored here too */
5696 84376 : if (!RELKIND_HAS_STORAGE(tab->relkind))
5697 4978 : continue;
5698 :
5699 80914 : foreach(lcon, tab->constraints)
5700 : {
5701 1578 : NewConstraint *con = lfirst(lcon);
5702 :
5703 1578 : if (con->contype == CONSTR_FOREIGN)
5704 : {
5705 932 : Constraint *fkconstraint = (Constraint *) con->qual;
5706 : Relation refrel;
5707 :
5708 932 : if (rel == NULL)
5709 : {
5710 : /* Long since locked, no need for another */
5711 920 : rel = table_open(tab->relid, NoLock);
5712 : }
5713 :
5714 932 : refrel = table_open(con->refrelid, RowShareLock);
5715 :
5716 932 : validateForeignKeyConstraint(fkconstraint->conname, rel, refrel,
5717 : con->refindid,
5718 : con->conid);
5719 :
5720 : /*
5721 : * No need to mark the constraint row as validated, we did
5722 : * that when we inserted the row earlier.
5723 : */
5724 :
5725 870 : table_close(refrel, NoLock);
5726 : }
5727 : }
5728 :
5729 79336 : if (rel)
5730 858 : table_close(rel, NoLock);
5731 : }
5732 :
5733 : /* Finally, run any afterStmts that were queued up */
5734 165260 : foreach(ltab, *wqueue)
5735 : {
5736 84276 : AlteredTableInfo *tab = (AlteredTableInfo *) lfirst(ltab);
5737 : ListCell *lc;
5738 :
5739 84344 : foreach(lc, tab->afterStmts)
5740 : {
5741 68 : Node *stmt = (Node *) lfirst(lc);
5742 :
5743 68 : ProcessUtilityForAlterTable(stmt, context);
5744 68 : CommandCounterIncrement();
5745 : }
5746 : }
5747 80984 : }
5748 :
5749 : /*
5750 : * ATRewriteTable: scan or rewrite one table
5751 : *
5752 : * OIDNewHeap is InvalidOid if we don't need to rewrite
5753 : */
5754 : static void
5755 4538 : ATRewriteTable(AlteredTableInfo *tab, Oid OIDNewHeap, LOCKMODE lockmode)
5756 : {
5757 : Relation oldrel;
5758 : Relation newrel;
5759 : TupleDesc oldTupDesc;
5760 : TupleDesc newTupDesc;
5761 4538 : bool needscan = false;
5762 : List *notnull_attrs;
5763 : int i;
5764 : ListCell *l;
5765 : EState *estate;
5766 : CommandId mycid;
5767 : BulkInsertState bistate;
5768 : int ti_options;
5769 4538 : ExprState *partqualstate = NULL;
5770 :
5771 : /*
5772 : * Open the relation(s). We have surely already locked the existing
5773 : * table.
5774 : */
5775 4538 : oldrel = table_open(tab->relid, NoLock);
5776 4538 : oldTupDesc = tab->oldDesc;
5777 4538 : newTupDesc = RelationGetDescr(oldrel); /* includes all mods */
5778 :
5779 4538 : if (OidIsValid(OIDNewHeap))
5780 740 : newrel = table_open(OIDNewHeap, lockmode);
5781 : else
5782 3798 : newrel = NULL;
5783 :
5784 : /*
5785 : * Prepare a BulkInsertState and options for table_tuple_insert. The FSM
5786 : * is empty, so don't bother using it.
5787 : */
5788 4538 : if (newrel)
5789 : {
5790 740 : mycid = GetCurrentCommandId(true);
5791 740 : bistate = GetBulkInsertState();
5792 740 : ti_options = TABLE_INSERT_SKIP_FSM;
5793 : }
5794 : else
5795 : {
5796 : /* keep compiler quiet about using these uninitialized */
5797 3798 : mycid = 0;
5798 3798 : bistate = NULL;
5799 3798 : ti_options = 0;
5800 : }
5801 :
5802 : /*
5803 : * Generate the constraint and default execution states
5804 : */
5805 :
5806 4538 : estate = CreateExecutorState();
5807 :
5808 : /* Build the needed expression execution states */
5809 6206 : foreach(l, tab->constraints)
5810 : {
5811 1668 : NewConstraint *con = lfirst(l);
5812 :
5813 1668 : switch (con->contype)
5814 : {
5815 730 : case CONSTR_CHECK:
5816 730 : needscan = true;
5817 730 : con->qualstate = ExecPrepareExpr((Expr *) con->qual, estate);
5818 730 : break;
5819 938 : case CONSTR_FOREIGN:
5820 : /* Nothing to do here */
5821 938 : break;
5822 0 : default:
5823 0 : elog(ERROR, "unrecognized constraint type: %d",
5824 : (int) con->contype);
5825 : }
5826 : }
5827 :
5828 : /* Build expression execution states for partition check quals */
5829 4538 : if (tab->partition_constraint)
5830 : {
5831 1812 : needscan = true;
5832 1812 : partqualstate = ExecPrepareExpr(tab->partition_constraint, estate);
5833 : }
5834 :
5835 5304 : foreach(l, tab->newvals)
5836 : {
5837 766 : NewColumnValue *ex = lfirst(l);
5838 :
5839 : /* expr already planned */
5840 766 : ex->exprstate = ExecInitExpr((Expr *) ex->expr, NULL);
5841 : }
5842 :
5843 4538 : notnull_attrs = NIL;
5844 4538 : if (newrel || tab->verify_new_notnull)
5845 : {
5846 : /*
5847 : * If we are rebuilding the tuples OR if we added any new but not
5848 : * verified NOT NULL constraints, check all not-null constraints. This
5849 : * is a bit of overkill but it minimizes risk of bugs, and
5850 : * heap_attisnull is a pretty cheap test anyway.
5851 : */
5852 5016 : for (i = 0; i < newTupDesc->natts; i++)
5853 : {
5854 3706 : Form_pg_attribute attr = TupleDescAttr(newTupDesc, i);
5855 :
5856 3706 : if (attr->attnotnull && !attr->attisdropped)
5857 1332 : notnull_attrs = lappend_int(notnull_attrs, i);
5858 : }
5859 1310 : if (notnull_attrs)
5860 932 : needscan = true;
5861 : }
5862 :
5863 4538 : if (newrel || needscan)
5864 : {
5865 : ExprContext *econtext;
5866 : TupleTableSlot *oldslot;
5867 : TupleTableSlot *newslot;
5868 : TableScanDesc scan;
5869 : MemoryContext oldCxt;
5870 3772 : List *dropped_attrs = NIL;
5871 : ListCell *lc;
5872 : Snapshot snapshot;
5873 :
5874 3772 : if (newrel)
5875 740 : ereport(DEBUG1,
5876 : (errmsg_internal("rewriting table \"%s\"",
5877 : RelationGetRelationName(oldrel))));
5878 : else
5879 3032 : ereport(DEBUG1,
5880 : (errmsg_internal("verifying table \"%s\"",
5881 : RelationGetRelationName(oldrel))));
5882 :
5883 3772 : if (newrel)
5884 : {
5885 : /*
5886 : * All predicate locks on the tuples or pages are about to be made
5887 : * invalid, because we move tuples around. Promote them to
5888 : * relation locks.
5889 : */
5890 740 : TransferPredicateLocksToHeapRelation(oldrel);
5891 : }
5892 :
5893 3772 : econtext = GetPerTupleExprContext(estate);
5894 :
5895 : /*
5896 : * Create necessary tuple slots. When rewriting, two slots are needed,
5897 : * otherwise one suffices. In the case where one slot suffices, we
5898 : * need to use the new tuple descriptor, otherwise some constraints
5899 : * can't be evaluated. Note that even when the tuple layout is the
5900 : * same and no rewrite is required, the tupDescs might not be
5901 : * (consider ADD COLUMN without a default).
5902 : */
5903 3772 : if (tab->rewrite)
5904 : {
5905 : Assert(newrel != NULL);
5906 740 : oldslot = MakeSingleTupleTableSlot(oldTupDesc,
5907 : table_slot_callbacks(oldrel));
5908 740 : newslot = MakeSingleTupleTableSlot(newTupDesc,
5909 : table_slot_callbacks(newrel));
5910 :
5911 : /*
5912 : * Set all columns in the new slot to NULL initially, to ensure
5913 : * columns added as part of the rewrite are initialized to NULL.
5914 : * That is necessary as tab->newvals will not contain an
5915 : * expression for columns with a NULL default, e.g. when adding a
5916 : * column without a default together with a column with a default
5917 : * requiring an actual rewrite.
5918 : */
5919 740 : ExecStoreAllNullTuple(newslot);
5920 : }
5921 : else
5922 : {
5923 3032 : oldslot = MakeSingleTupleTableSlot(newTupDesc,
5924 : table_slot_callbacks(oldrel));
5925 3032 : newslot = NULL;
5926 : }
5927 :
5928 : /*
5929 : * Any attributes that are dropped according to the new tuple
5930 : * descriptor can be set to NULL. We precompute the list of dropped
5931 : * attributes to avoid needing to do so in the per-tuple loop.
5932 : */
5933 13436 : for (i = 0; i < newTupDesc->natts; i++)
5934 : {
5935 9664 : if (TupleDescAttr(newTupDesc, i)->attisdropped)
5936 754 : dropped_attrs = lappend_int(dropped_attrs, i);
5937 : }
5938 :
5939 : /*
5940 : * Scan through the rows, generating a new row if needed and then
5941 : * checking all the constraints.
5942 : */
5943 3772 : snapshot = RegisterSnapshot(GetLatestSnapshot());
5944 3772 : scan = table_beginscan(oldrel, snapshot, 0, NULL);
5945 :
5946 : /*
5947 : * Switch to per-tuple memory context and reset it for each tuple
5948 : * produced, so we don't leak memory.
5949 : */
5950 3772 : oldCxt = MemoryContextSwitchTo(GetPerTupleMemoryContext(estate));
5951 :
5952 765996 : while (table_scan_getnextslot(scan, ForwardScanDirection, oldslot))
5953 : {
5954 : TupleTableSlot *insertslot;
5955 :
5956 762436 : if (tab->rewrite > 0)
5957 : {
5958 : /* Extract data from old tuple */
5959 97306 : slot_getallattrs(oldslot);
5960 97306 : ExecClearTuple(newslot);
5961 :
5962 : /* copy attributes */
5963 97306 : memcpy(newslot->tts_values, oldslot->tts_values,
5964 97306 : sizeof(Datum) * oldslot->tts_nvalid);
5965 97306 : memcpy(newslot->tts_isnull, oldslot->tts_isnull,
5966 97306 : sizeof(bool) * oldslot->tts_nvalid);
5967 :
5968 : /* Set dropped attributes to null in new tuple */
5969 97392 : foreach(lc, dropped_attrs)
5970 86 : newslot->tts_isnull[lfirst_int(lc)] = true;
5971 :
5972 : /*
5973 : * Constraints and GENERATED expressions might reference the
5974 : * tableoid column, so fill tts_tableOid with the desired
5975 : * value. (We must do this each time, because it gets
5976 : * overwritten with newrel's OID during storing.)
5977 : */
5978 97306 : newslot->tts_tableOid = RelationGetRelid(oldrel);
5979 :
5980 : /*
5981 : * Process supplied expressions to replace selected columns.
5982 : *
5983 : * First, evaluate expressions whose inputs come from the old
5984 : * tuple.
5985 : */
5986 97306 : econtext->ecxt_scantuple = oldslot;
5987 :
5988 200582 : foreach(l, tab->newvals)
5989 : {
5990 103288 : NewColumnValue *ex = lfirst(l);
5991 :
5992 103288 : if (ex->is_generated)
5993 60 : continue;
5994 :
5995 103228 : newslot->tts_values[ex->attnum - 1]
5996 103216 : = ExecEvalExpr(ex->exprstate,
5997 : econtext,
5998 103228 : &newslot->tts_isnull[ex->attnum - 1]);
5999 : }
6000 :
6001 97294 : ExecStoreVirtualTuple(newslot);
6002 :
6003 : /*
6004 : * Now, evaluate any expressions whose inputs come from the
6005 : * new tuple. We assume these columns won't reference each
6006 : * other, so that there's no ordering dependency.
6007 : */
6008 97294 : econtext->ecxt_scantuple = newslot;
6009 :
6010 200570 : foreach(l, tab->newvals)
6011 : {
6012 103276 : NewColumnValue *ex = lfirst(l);
6013 :
6014 103276 : if (!ex->is_generated)
6015 103216 : continue;
6016 :
6017 60 : newslot->tts_values[ex->attnum - 1]
6018 60 : = ExecEvalExpr(ex->exprstate,
6019 : econtext,
6020 60 : &newslot->tts_isnull[ex->attnum - 1]);
6021 : }
6022 :
6023 97294 : insertslot = newslot;
6024 : }
6025 : else
6026 : {
6027 : /*
6028 : * If there's no rewrite, old and new table are guaranteed to
6029 : * have the same AM, so we can just use the old slot to verify
6030 : * new constraints etc.
6031 : */
6032 665130 : insertslot = oldslot;
6033 : }
6034 :
6035 : /* Now check any constraints on the possibly-changed tuple */
6036 762424 : econtext->ecxt_scantuple = insertslot;
6037 :
6038 3338556 : foreach(l, notnull_attrs)
6039 : {
6040 2576192 : int attn = lfirst_int(l);
6041 :
6042 2576192 : if (slot_attisnull(insertslot, attn + 1))
6043 : {
6044 60 : Form_pg_attribute attr = TupleDescAttr(newTupDesc, attn);
6045 :
6046 60 : ereport(ERROR,
6047 : (errcode(ERRCODE_NOT_NULL_VIOLATION),
6048 : errmsg("column \"%s\" of relation \"%s\" contains null values",
6049 : NameStr(attr->attname),
6050 : RelationGetRelationName(oldrel)),
6051 : errtablecol(oldrel, attn + 1)));
6052 : }
6053 : }
6054 :
6055 770446 : foreach(l, tab->constraints)
6056 : {
6057 8148 : NewConstraint *con = lfirst(l);
6058 :
6059 8148 : switch (con->contype)
6060 : {
6061 8060 : case CONSTR_CHECK:
6062 8060 : if (!ExecCheck(con->qualstate, econtext))
6063 66 : ereport(ERROR,
6064 : (errcode(ERRCODE_CHECK_VIOLATION),
6065 : errmsg("check constraint \"%s\" of relation \"%s\" is violated by some row",
6066 : con->name,
6067 : RelationGetRelationName(oldrel)),
6068 : errtableconstraint(oldrel, con->name)));
6069 7994 : break;
6070 88 : case CONSTR_FOREIGN:
6071 : /* Nothing to do here */
6072 88 : break;
6073 0 : default:
6074 0 : elog(ERROR, "unrecognized constraint type: %d",
6075 : (int) con->contype);
6076 : }
6077 : }
6078 :
6079 762298 : if (partqualstate && !ExecCheck(partqualstate, econtext))
6080 : {
6081 74 : if (tab->validate_default)
6082 26 : ereport(ERROR,
6083 : (errcode(ERRCODE_CHECK_VIOLATION),
6084 : errmsg("updated partition constraint for default partition \"%s\" would be violated by some row",
6085 : RelationGetRelationName(oldrel)),
6086 : errtable(oldrel)));
6087 : else
6088 48 : ereport(ERROR,
6089 : (errcode(ERRCODE_CHECK_VIOLATION),
6090 : errmsg("partition constraint of relation \"%s\" is violated by some row",
6091 : RelationGetRelationName(oldrel)),
6092 : errtable(oldrel)));
6093 : }
6094 :
6095 : /* Write the tuple out to the new relation */
6096 762224 : if (newrel)
6097 97288 : table_tuple_insert(newrel, insertslot, mycid,
6098 : ti_options, bistate);
6099 :
6100 762224 : ResetExprContext(econtext);
6101 :
6102 762224 : CHECK_FOR_INTERRUPTS();
6103 : }
6104 :
6105 3560 : MemoryContextSwitchTo(oldCxt);
6106 3560 : table_endscan(scan);
6107 3560 : UnregisterSnapshot(snapshot);
6108 :
6109 3560 : ExecDropSingleTupleTableSlot(oldslot);
6110 3560 : if (newslot)
6111 722 : ExecDropSingleTupleTableSlot(newslot);
6112 : }
6113 :
6114 4326 : FreeExecutorState(estate);
6115 :
6116 4326 : table_close(oldrel, NoLock);
6117 4326 : if (newrel)
6118 : {
6119 722 : FreeBulkInsertState(bistate);
6120 :
6121 722 : table_finish_bulk_insert(newrel, ti_options);
6122 :
6123 722 : table_close(newrel, NoLock);
6124 : }
6125 4326 : }
6126 :
6127 : /*
6128 : * ATGetQueueEntry: find or create an entry in the ALTER TABLE work queue
6129 : */
6130 : static AlteredTableInfo *
6131 89622 : ATGetQueueEntry(List **wqueue, Relation rel)
6132 : {
6133 89622 : Oid relid = RelationGetRelid(rel);
6134 : AlteredTableInfo *tab;
6135 : ListCell *ltab;
6136 :
6137 97998 : foreach(ltab, *wqueue)
6138 : {
6139 10756 : tab = (AlteredTableInfo *) lfirst(ltab);
6140 10756 : if (tab->relid == relid)
6141 2380 : return tab;
6142 : }
6143 :
6144 : /*
6145 : * Not there, so add it. Note that we make a copy of the relation's
6146 : * existing descriptor before anything interesting can happen to it.
6147 : */
6148 87242 : tab = (AlteredTableInfo *) palloc0(sizeof(AlteredTableInfo));
6149 87242 : tab->relid = relid;
6150 87242 : tab->rel = NULL; /* set later */
6151 87242 : tab->relkind = rel->rd_rel->relkind;
6152 87242 : tab->oldDesc = CreateTupleDescCopyConstr(RelationGetDescr(rel));
6153 87242 : tab->newAccessMethod = InvalidOid;
6154 87242 : tab->newTableSpace = InvalidOid;
6155 87242 : tab->newrelpersistence = RELPERSISTENCE_PERMANENT;
6156 87242 : tab->chgPersistence = false;
6157 :
6158 87242 : *wqueue = lappend(*wqueue, tab);
6159 :
6160 87242 : return tab;
6161 : }
6162 :
6163 : static const char *
6164 42 : alter_table_type_to_string(AlterTableType cmdtype)
6165 : {
6166 42 : switch (cmdtype)
6167 : {
6168 0 : case AT_AddColumn:
6169 : case AT_AddColumnToView:
6170 0 : return "ADD COLUMN";
6171 0 : case AT_ColumnDefault:
6172 : case AT_CookedColumnDefault:
6173 0 : return "ALTER COLUMN ... SET DEFAULT";
6174 6 : case AT_DropNotNull:
6175 6 : return "ALTER COLUMN ... DROP NOT NULL";
6176 6 : case AT_SetNotNull:
6177 6 : return "ALTER COLUMN ... SET NOT NULL";
6178 0 : case AT_DropExpression:
6179 0 : return "ALTER COLUMN ... DROP EXPRESSION";
6180 0 : case AT_CheckNotNull:
6181 0 : return NULL; /* not real grammar */
6182 0 : case AT_SetStatistics:
6183 0 : return "ALTER COLUMN ... SET STATISTICS";
6184 12 : case AT_SetOptions:
6185 12 : return "ALTER COLUMN ... SET";
6186 0 : case AT_ResetOptions:
6187 0 : return "ALTER COLUMN ... RESET";
6188 0 : case AT_SetStorage:
6189 0 : return "ALTER COLUMN ... SET STORAGE";
6190 0 : case AT_SetCompression:
6191 0 : return "ALTER COLUMN ... SET COMPRESSION";
6192 6 : case AT_DropColumn:
6193 6 : return "DROP COLUMN";
6194 0 : case AT_AddIndex:
6195 : case AT_ReAddIndex:
6196 0 : return NULL; /* not real grammar */
6197 0 : case AT_AddConstraint:
6198 : case AT_ReAddConstraint:
6199 : case AT_ReAddDomainConstraint:
6200 : case AT_AddIndexConstraint:
6201 0 : return "ADD CONSTRAINT";
6202 6 : case AT_AlterConstraint:
6203 6 : return "ALTER CONSTRAINT";
6204 0 : case AT_ValidateConstraint:
6205 0 : return "VALIDATE CONSTRAINT";
6206 0 : case AT_DropConstraint:
6207 0 : return "DROP CONSTRAINT";
6208 0 : case AT_ReAddComment:
6209 0 : return NULL; /* not real grammar */
6210 0 : case AT_AlterColumnType:
6211 0 : return "ALTER COLUMN ... SET DATA TYPE";
6212 0 : case AT_AlterColumnGenericOptions:
6213 0 : return "ALTER COLUMN ... OPTIONS";
6214 0 : case AT_ChangeOwner:
6215 0 : return "OWNER TO";
6216 0 : case AT_ClusterOn:
6217 0 : return "CLUSTER ON";
6218 0 : case AT_DropCluster:
6219 0 : return "SET WITHOUT CLUSTER";
6220 0 : case AT_SetAccessMethod:
6221 0 : return "SET ACCESS METHOD";
6222 0 : case AT_SetLogged:
6223 0 : return "SET LOGGED";
6224 0 : case AT_SetUnLogged:
6225 0 : return "SET UNLOGGED";
6226 0 : case AT_DropOids:
6227 0 : return "SET WITHOUT OIDS";
6228 0 : case AT_SetTableSpace:
6229 0 : return "SET TABLESPACE";
6230 0 : case AT_SetRelOptions:
6231 0 : return "SET";
6232 0 : case AT_ResetRelOptions:
6233 0 : return "RESET";
6234 0 : case AT_ReplaceRelOptions:
6235 0 : return NULL; /* not real grammar */
6236 0 : case AT_EnableTrig:
6237 0 : return "ENABLE TRIGGER";
6238 0 : case AT_EnableAlwaysTrig:
6239 0 : return "ENABLE ALWAYS TRIGGER";
6240 0 : case AT_EnableReplicaTrig:
6241 0 : return "ENABLE REPLICA TRIGGER";
6242 0 : case AT_DisableTrig:
6243 0 : return "DISABLE TRIGGER";
6244 0 : case AT_EnableTrigAll:
6245 0 : return "ENABLE TRIGGER ALL";
6246 0 : case AT_DisableTrigAll:
6247 0 : return "DISABLE TRIGGER ALL";
6248 0 : case AT_EnableTrigUser:
6249 0 : return "ENABLE TRIGGER USER";
6250 0 : case AT_DisableTrigUser:
6251 0 : return "DISABLE TRIGGER USER";
6252 0 : case AT_EnableRule:
6253 0 : return "ENABLE RULE";
6254 0 : case AT_EnableAlwaysRule:
6255 0 : return "ENABLE ALWAYS RULE";
6256 0 : case AT_EnableReplicaRule:
6257 0 : return "ENABLE REPLICA RULE";
6258 0 : case AT_DisableRule:
6259 0 : return "DISABLE RULE";
6260 0 : case AT_AddInherit:
6261 0 : return "INHERIT";
6262 0 : case AT_DropInherit:
6263 0 : return "NO INHERIT";
6264 0 : case AT_AddOf:
6265 0 : return "OF";
6266 0 : case AT_DropOf:
6267 0 : return "NOT OF";
6268 0 : case AT_ReplicaIdentity:
6269 0 : return "REPLICA IDENTITY";
6270 0 : case AT_EnableRowSecurity:
6271 0 : return "ENABLE ROW SECURITY";
6272 0 : case AT_DisableRowSecurity:
6273 0 : return "DISABLE ROW SECURITY";
6274 0 : case AT_ForceRowSecurity:
6275 0 : return "FORCE ROW SECURITY";
6276 0 : case AT_NoForceRowSecurity:
6277 0 : return "NO FORCE ROW SECURITY";
6278 0 : case AT_GenericOptions:
6279 0 : return "OPTIONS";
6280 0 : case AT_AttachPartition:
6281 0 : return "ATTACH PARTITION";
6282 6 : case AT_DetachPartition:
6283 6 : return "DETACH PARTITION";
6284 0 : case AT_DetachPartitionFinalize:
6285 0 : return "DETACH PARTITION ... FINALIZE";
6286 0 : case AT_AddIdentity:
6287 0 : return "ALTER COLUMN ... ADD IDENTITY";
6288 0 : case AT_SetIdentity:
6289 0 : return "ALTER COLUMN ... SET";
6290 0 : case AT_DropIdentity:
6291 0 : return "ALTER COLUMN ... DROP IDENTITY";
6292 0 : case AT_ReAddStatistics:
6293 0 : return NULL; /* not real grammar */
6294 : }
6295 :
6296 0 : return NULL;
6297 : }
6298 :
6299 : /*
6300 : * ATSimplePermissions
6301 : *
6302 : * - Ensure that it is a relation (or possibly a view)
6303 : * - Ensure this user is the owner
6304 : * - Ensure that it is not a system table
6305 : */
6306 : static void
6307 87344 : ATSimplePermissions(AlterTableType cmdtype, Relation rel, int allowed_targets)
6308 : {
6309 : int actual_target;
6310 :
6311 87344 : switch (rel->rd_rel->relkind)
6312 : {
6313 85184 : case RELKIND_RELATION:
6314 : case RELKIND_PARTITIONED_TABLE:
6315 85184 : actual_target = ATT_TABLE;
6316 85184 : break;
6317 396 : case RELKIND_VIEW:
6318 396 : actual_target = ATT_VIEW;
6319 396 : break;
6320 46 : case RELKIND_MATVIEW:
6321 46 : actual_target = ATT_MATVIEW;
6322 46 : break;
6323 226 : case RELKIND_INDEX:
6324 226 : actual_target = ATT_INDEX;
6325 226 : break;
6326 402 : case RELKIND_PARTITIONED_INDEX:
6327 402 : actual_target = ATT_PARTITIONED_INDEX;
6328 402 : break;
6329 214 : case RELKIND_COMPOSITE_TYPE:
6330 214 : actual_target = ATT_COMPOSITE_TYPE;
6331 214 : break;
6332 864 : case RELKIND_FOREIGN_TABLE:
6333 864 : actual_target = ATT_FOREIGN_TABLE;
6334 864 : break;
6335 12 : case RELKIND_SEQUENCE:
6336 12 : actual_target = ATT_SEQUENCE;
6337 12 : break;
6338 0 : default:
6339 0 : actual_target = 0;
6340 0 : break;
6341 : }
6342 :
6343 : /* Wrong target type? */
6344 87344 : if ((actual_target & allowed_targets) == 0)
6345 : {
6346 42 : const char *action_str = alter_table_type_to_string(cmdtype);
6347 :
6348 42 : if (action_str)
6349 42 : ereport(ERROR,
6350 : (errcode(ERRCODE_WRONG_OBJECT_TYPE),
6351 : /* translator: %s is a group of some SQL keywords */
6352 : errmsg("ALTER action %s cannot be performed on relation \"%s\"",
6353 : action_str, RelationGetRelationName(rel)),
6354 : errdetail_relkind_not_supported(rel->rd_rel->relkind)));
6355 : else
6356 : /* internal error? */
6357 0 : elog(ERROR, "invalid ALTER action attempted on relation \"%s\"",
6358 : RelationGetRelationName(rel));
6359 : }
6360 :
6361 : /* Permissions checks */
6362 87302 : if (!object_ownercheck(RelationRelationId, RelationGetRelid(rel), GetUserId()))
6363 6 : aclcheck_error(ACLCHECK_NOT_OWNER, get_relkind_objtype(rel->rd_rel->relkind),
6364 6 : RelationGetRelationName(rel));
6365 :
6366 87296 : if (!allowSystemTableMods && IsSystemRelation(rel))
6367 0 : ereport(ERROR,
6368 : (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
6369 : errmsg("permission denied: \"%s\" is a system catalog",
6370 : RelationGetRelationName(rel))));
6371 87296 : }
6372 :
6373 : /*
6374 : * ATSimpleRecursion
6375 : *
6376 : * Simple table recursion sufficient for most ALTER TABLE operations.
6377 : * All direct and indirect children are processed in an unspecified order.
6378 : * Note that if a child inherits from the original table via multiple
6379 : * inheritance paths, it will be visited just once.
6380 : */
6381 : static void
6382 51650 : ATSimpleRecursion(List **wqueue, Relation rel,
6383 : AlterTableCmd *cmd, bool recurse, LOCKMODE lockmode,
6384 : AlterTableUtilityContext *context)
6385 : {
6386 : /*
6387 : * Propagate to children, if desired and if there are (or might be) any
6388 : * children.
6389 : */
6390 51650 : if (recurse && rel->rd_rel->relhassubclass)
6391 : {
6392 172 : Oid relid = RelationGetRelid(rel);
6393 : ListCell *child;
6394 : List *children;
6395 :
6396 172 : children = find_all_inheritors(relid, lockmode, NULL);
6397 :
6398 : /*
6399 : * find_all_inheritors does the recursive search of the inheritance
6400 : * hierarchy, so all we have to do is process all of the relids in the
6401 : * list that it returns.
6402 : */
6403 726 : foreach(child, children)
6404 : {
6405 554 : Oid childrelid = lfirst_oid(child);
6406 : Relation childrel;
6407 :
6408 554 : if (childrelid == relid)
6409 172 : continue;
6410 : /* find_all_inheritors already got lock */
6411 382 : childrel = relation_open(childrelid, NoLock);
6412 382 : CheckTableNotInUse(childrel, "ALTER TABLE");
6413 382 : ATPrepCmd(wqueue, childrel, cmd, false, true, lockmode, context);
6414 382 : relation_close(childrel, NoLock);
6415 : }
6416 : }
6417 51650 : }
6418 :
6419 : /*
6420 : * Obtain list of partitions of the given table, locking them all at the given
6421 : * lockmode and ensuring that they all pass CheckTableNotInUse.
6422 : *
6423 : * This function is a no-op if the given relation is not a partitioned table;
6424 : * in particular, nothing is done if it's a legacy inheritance parent.
6425 : */
6426 : static void
6427 510 : ATCheckPartitionsNotInUse(Relation rel, LOCKMODE lockmode)
6428 : {
6429 510 : if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
6430 : {
6431 : List *inh;
6432 : ListCell *cell;
6433 :
6434 122 : inh = find_all_inheritors(RelationGetRelid(rel), lockmode, NULL);
6435 : /* first element is the parent rel; must ignore it */
6436 412 : for_each_from(cell, inh, 1)
6437 : {
6438 : Relation childrel;
6439 :
6440 : /* find_all_inheritors already got lock */
6441 296 : childrel = table_open(lfirst_oid(cell), NoLock);
6442 296 : CheckTableNotInUse(childrel, "ALTER TABLE");
6443 290 : table_close(childrel, NoLock);
6444 : }
6445 116 : list_free(inh);
6446 : }
6447 504 : }
6448 :
6449 : /*
6450 : * ATTypedTableRecursion
6451 : *
6452 : * Propagate ALTER TYPE operations to the typed tables of that type.
6453 : * Also check the RESTRICT/CASCADE behavior. Given CASCADE, also permit
6454 : * recursion to inheritance children of the typed tables.
6455 : */
6456 : static void
6457 190 : ATTypedTableRecursion(List **wqueue, Relation rel, AlterTableCmd *cmd,
6458 : LOCKMODE lockmode, AlterTableUtilityContext *context)
6459 : {
6460 : ListCell *child;
6461 : List *children;
6462 :
6463 : Assert(rel->rd_rel->relkind == RELKIND_COMPOSITE_TYPE);
6464 :
6465 190 : children = find_typed_table_dependencies(rel->rd_rel->reltype,
6466 190 : RelationGetRelationName(rel),
6467 : cmd->behavior);
6468 :
6469 202 : foreach(child, children)
6470 : {
6471 30 : Oid childrelid = lfirst_oid(child);
6472 : Relation childrel;
6473 :
6474 30 : childrel = relation_open(childrelid, lockmode);
6475 30 : CheckTableNotInUse(childrel, "ALTER TABLE");
6476 30 : ATPrepCmd(wqueue, childrel, cmd, true, true, lockmode, context);
6477 30 : relation_close(childrel, NoLock);
6478 : }
6479 172 : }
6480 :
6481 :
6482 : /*
6483 : * find_composite_type_dependencies
6484 : *
6485 : * Check to see if the type "typeOid" is being used as a column in some table
6486 : * (possibly nested several levels deep in composite types, arrays, etc!).
6487 : * Eventually, we'd like to propagate the check or rewrite operation
6488 : * into such tables, but for now, just error out if we find any.
6489 : *
6490 : * Caller should provide either the associated relation of a rowtype,
6491 : * or a type name (not both) for use in the error message, if any.
6492 : *
6493 : * Note that "typeOid" is not necessarily a composite type; it could also be
6494 : * another container type such as an array or range, or a domain over one of
6495 : * these things. The name of this function is therefore somewhat historical,
6496 : * but it's not worth changing.
6497 : *
6498 : * We assume that functions and views depending on the type are not reasons
6499 : * to reject the ALTER. (How safe is this really?)
6500 : */
6501 : void
6502 3528 : find_composite_type_dependencies(Oid typeOid, Relation origRelation,
6503 : const char *origTypeName)
6504 : {
6505 : Relation depRel;
6506 : ScanKeyData key[2];
6507 : SysScanDesc depScan;
6508 : HeapTuple depTup;
6509 :
6510 : /* since this function recurses, it could be driven to stack overflow */
6511 3528 : check_stack_depth();
6512 :
6513 : /*
6514 : * We scan pg_depend to find those things that depend on the given type.
6515 : * (We assume we can ignore refobjsubid for a type.)
6516 : */
6517 3528 : depRel = table_open(DependRelationId, AccessShareLock);
6518 :
6519 3528 : ScanKeyInit(&key[0],
6520 : Anum_pg_depend_refclassid,
6521 : BTEqualStrategyNumber, F_OIDEQ,
6522 : ObjectIdGetDatum(TypeRelationId));
6523 3528 : ScanKeyInit(&key[1],
6524 : Anum_pg_depend_refobjid,
6525 : BTEqualStrategyNumber, F_OIDEQ,
6526 : ObjectIdGetDatum(typeOid));
6527 :
6528 3528 : depScan = systable_beginscan(depRel, DependReferenceIndexId, true,
6529 : NULL, 2, key);
6530 :
6531 5478 : while (HeapTupleIsValid(depTup = systable_getnext(depScan)))
6532 : {
6533 2046 : Form_pg_depend pg_depend = (Form_pg_depend) GETSTRUCT(depTup);
6534 : Relation rel;
6535 : TupleDesc tupleDesc;
6536 : Form_pg_attribute att;
6537 :
6538 : /* Check for directly dependent types */
6539 2046 : if (pg_depend->classid == TypeRelationId)
6540 : {
6541 : /*
6542 : * This must be an array, domain, or range containing the given
6543 : * type, so recursively check for uses of this type. Note that
6544 : * any error message will mention the original type not the
6545 : * container; this is intentional.
6546 : */
6547 1700 : find_composite_type_dependencies(pg_depend->objid,
6548 : origRelation, origTypeName);
6549 1676 : continue;
6550 : }
6551 :
6552 : /* Else, ignore dependees that aren't relations */
6553 346 : if (pg_depend->classid != RelationRelationId)
6554 122 : continue;
6555 :
6556 224 : rel = relation_open(pg_depend->objid, AccessShareLock);
6557 224 : tupleDesc = RelationGetDescr(rel);
6558 :
6559 : /*
6560 : * If objsubid identifies a specific column, refer to that in error
6561 : * messages. Otherwise, search to see if there's a user column of the
6562 : * type. (We assume system columns are never of interesting types.)
6563 : * The search is needed because an index containing an expression
6564 : * column of the target type will just be recorded as a whole-relation
6565 : * dependency. If we do not find a column of the type, the dependency
6566 : * must indicate that the type is transiently referenced in an index
6567 : * expression but not stored on disk, which we assume is OK, just as
6568 : * we do for references in views. (It could also be that the target
6569 : * type is embedded in some container type that is stored in an index
6570 : * column, but the previous recursion should catch such cases.)
6571 : */
6572 224 : if (pg_depend->objsubid > 0 && pg_depend->objsubid <= tupleDesc->natts)
6573 66 : att = TupleDescAttr(tupleDesc, pg_depend->objsubid - 1);
6574 : else
6575 : {
6576 158 : att = NULL;
6577 406 : for (int attno = 1; attno <= tupleDesc->natts; attno++)
6578 : {
6579 254 : att = TupleDescAttr(tupleDesc, attno - 1);
6580 254 : if (att->atttypid == typeOid && !att->attisdropped)
6581 6 : break;
6582 248 : att = NULL;
6583 : }
6584 158 : if (att == NULL)
6585 : {
6586 : /* No such column, so assume OK */
6587 152 : relation_close(rel, AccessShareLock);
6588 152 : continue;
6589 : }
6590 : }
6591 :
6592 : /*
6593 : * We definitely should reject if the relation has storage. If it's
6594 : * partitioned, then perhaps we don't have to reject: if there are
6595 : * partitions then we'll fail when we find one, else there is no
6596 : * stored data to worry about. However, it's possible that the type
6597 : * change would affect conclusions about whether the type is sortable
6598 : * or hashable and thus (if it's a partitioning column) break the
6599 : * partitioning rule. For now, reject for partitioned rels too.
6600 : */
6601 72 : if (RELKIND_HAS_STORAGE(rel->rd_rel->relkind) ||
6602 0 : RELKIND_HAS_PARTITIONS(rel->rd_rel->relkind))
6603 : {
6604 72 : if (origTypeName)
6605 30 : ereport(ERROR,
6606 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
6607 : errmsg("cannot alter type \"%s\" because column \"%s.%s\" uses it",
6608 : origTypeName,
6609 : RelationGetRelationName(rel),
6610 : NameStr(att->attname))));
6611 42 : else if (origRelation->rd_rel->relkind == RELKIND_COMPOSITE_TYPE)
6612 18 : ereport(ERROR,
6613 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
6614 : errmsg("cannot alter type \"%s\" because column \"%s.%s\" uses it",
6615 : RelationGetRelationName(origRelation),
6616 : RelationGetRelationName(rel),
6617 : NameStr(att->attname))));
6618 24 : else if (origRelation->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
6619 6 : ereport(ERROR,
6620 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
6621 : errmsg("cannot alter foreign table \"%s\" because column \"%s.%s\" uses its row type",
6622 : RelationGetRelationName(origRelation),
6623 : RelationGetRelationName(rel),
6624 : NameStr(att->attname))));
6625 : else
6626 18 : ereport(ERROR,
6627 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
6628 : errmsg("cannot alter table \"%s\" because column \"%s.%s\" uses its row type",
6629 : RelationGetRelationName(origRelation),
6630 : RelationGetRelationName(rel),
6631 : NameStr(att->attname))));
6632 : }
6633 0 : else if (OidIsValid(rel->rd_rel->reltype))
6634 : {
6635 : /*
6636 : * A view or composite type itself isn't a problem, but we must
6637 : * recursively check for indirect dependencies via its rowtype.
6638 : */
6639 0 : find_composite_type_dependencies(rel->rd_rel->reltype,
6640 : origRelation, origTypeName);
6641 : }
6642 :
6643 0 : relation_close(rel, AccessShareLock);
6644 : }
6645 :
6646 3432 : systable_endscan(depScan);
6647 :
6648 3432 : relation_close(depRel, AccessShareLock);
6649 3432 : }
6650 :
6651 :
6652 : /*
6653 : * find_typed_table_dependencies
6654 : *
6655 : * Check to see if a composite type is being used as the type of a
6656 : * typed table. Abort if any are found and behavior is RESTRICT.
6657 : * Else return the list of tables.
6658 : */
6659 : static List *
6660 214 : find_typed_table_dependencies(Oid typeOid, const char *typeName, DropBehavior behavior)
6661 : {
6662 : Relation classRel;
6663 : ScanKeyData key[1];
6664 : TableScanDesc scan;
6665 : HeapTuple tuple;
6666 214 : List *result = NIL;
6667 :
6668 214 : classRel = table_open(RelationRelationId, AccessShareLock);
6669 :
6670 214 : ScanKeyInit(&key[0],
6671 : Anum_pg_class_reloftype,
6672 : BTEqualStrategyNumber, F_OIDEQ,
6673 : ObjectIdGetDatum(typeOid));
6674 :
6675 214 : scan = table_beginscan_catalog(classRel, 1, key);
6676 :
6677 250 : while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
6678 : {
6679 60 : Form_pg_class classform = (Form_pg_class) GETSTRUCT(tuple);
6680 :
6681 60 : if (behavior == DROP_RESTRICT)
6682 24 : ereport(ERROR,
6683 : (errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
6684 : errmsg("cannot alter type \"%s\" because it is the type of a typed table",
6685 : typeName),
6686 : errhint("Use ALTER ... CASCADE to alter the typed tables too.")));
6687 : else
6688 36 : result = lappend_oid(result, classform->oid);
6689 : }
6690 :
6691 190 : table_endscan(scan);
6692 190 : table_close(classRel, AccessShareLock);
6693 :
6694 190 : return result;
6695 : }
6696 :
6697 :
6698 : /*
6699 : * check_of_type
6700 : *
6701 : * Check whether a type is suitable for CREATE TABLE OF/ALTER TABLE OF. If it
6702 : * isn't suitable, throw an error. Currently, we require that the type
6703 : * originated with CREATE TYPE AS. We could support any row type, but doing so
6704 : * would require handling a number of extra corner cases in the DDL commands.
6705 : * (Also, allowing domain-over-composite would open up a can of worms about
6706 : * whether and how the domain's constraints should apply to derived tables.)
6707 : */
6708 : void
6709 170 : check_of_type(HeapTuple typetuple)
6710 : {
6711 170 : Form_pg_type typ = (Form_pg_type) GETSTRUCT(typetuple);
6712 170 : bool typeOk = false;
6713 :
6714 170 : if (typ->typtype == TYPTYPE_COMPOSITE)
6715 : {
6716 : Relation typeRelation;
6717 :
6718 : Assert(OidIsValid(typ->typrelid));
6719 170 : typeRelation = relation_open(typ->typrelid, AccessShareLock);
6720 170 : typeOk = (typeRelation->rd_rel->relkind == RELKIND_COMPOSITE_TYPE);
6721 :
6722 : /*
6723 : * Close the parent rel, but keep our AccessShareLock on it until xact
6724 : * commit. That will prevent someone else from deleting or ALTERing
6725 : * the type before the typed table creation/conversion commits.
6726 : */
6727 170 : relation_close(typeRelation, NoLock);
6728 : }
6729 170 : if (!typeOk)
6730 6 : ereport(ERROR,
6731 : (errcode(ERRCODE_WRONG_OBJECT_TYPE),
6732 : errmsg("type %s is not a composite type",
6733 : format_type_be(typ->oid))));
6734 164 : }
6735 :
6736 :
6737 : /*
6738 : * ALTER TABLE ADD COLUMN
6739 : *
6740 : * Adds an additional attribute to a relation making the assumption that
6741 : * CHECK, NOT NULL, and FOREIGN KEY constraints will be removed from the
6742 : * AT_AddColumn AlterTableCmd by parse_utilcmd.c and added as independent
6743 : * AlterTableCmd's.
6744 : *
6745 : * ADD COLUMN cannot use the normal ALTER TABLE recursion mechanism, because we
6746 : * have to decide at runtime whether to recurse or not depending on whether we
6747 : * actually add a column or merely merge with an existing column. (We can't
6748 : * check this in a static pre-pass because it won't handle multiple inheritance
6749 : * situations correctly.)
6750 : */
6751 : static void
6752 1830 : ATPrepAddColumn(List **wqueue, Relation rel, bool recurse, bool recursing,
6753 : bool is_view, AlterTableCmd *cmd, LOCKMODE lockmode,
6754 : AlterTableUtilityContext *context)
6755 : {
6756 1830 : if (rel->rd_rel->reloftype && !recursing)
6757 6 : ereport(ERROR,
6758 : (errcode(ERRCODE_WRONG_OBJECT_TYPE),
6759 : errmsg("cannot add column to typed table")));
6760 :
6761 1824 : if (rel->rd_rel->relkind == RELKIND_COMPOSITE_TYPE)
6762 58 : ATTypedTableRecursion(wqueue, rel, cmd, lockmode, context);
6763 :
6764 1818 : if (recurse && !is_view)
6765 1718 : cmd->recurse = true;
6766 1818 : }
6767 :
6768 : /*
6769 : * Add a column to a table. The return value is the address of the
6770 : * new column in the parent relation.
6771 : *
6772 : * cmd is pass-by-ref so that we can replace it with the parse-transformed
6773 : * copy (but that happens only after we check for IF NOT EXISTS).
6774 : */
6775 : static ObjectAddress
6776 2388 : ATExecAddColumn(List **wqueue, AlteredTableInfo *tab, Relation rel,
6777 : AlterTableCmd **cmd,
6778 : bool recurse, bool recursing,
6779 : LOCKMODE lockmode, int cur_pass,
6780 : AlterTableUtilityContext *context)
6781 : {
6782 2388 : Oid myrelid = RelationGetRelid(rel);
6783 2388 : ColumnDef *colDef = castNode(ColumnDef, (*cmd)->def);
6784 2388 : bool if_not_exists = (*cmd)->missing_ok;
6785 : Relation pgclass,
6786 : attrdesc;
6787 : HeapTuple reltup;
6788 : FormData_pg_attribute attribute;
6789 : int newattnum;
6790 : char relkind;
6791 : HeapTuple typeTuple;
6792 : Oid typeOid;
6793 : int32 typmod;
6794 : Oid collOid;
6795 : Form_pg_type tform;
6796 : Expr *defval;
6797 : List *children;
6798 : ListCell *child;
6799 : AlterTableCmd *childcmd;
6800 : AclResult aclresult;
6801 : ObjectAddress address;
6802 : TupleDesc tupdesc;
6803 2388 : FormData_pg_attribute *aattr[] = {&attribute};
6804 :
6805 : /* At top level, permission check was done in ATPrepCmd, else do it */
6806 2388 : if (recursing)
6807 576 : ATSimplePermissions((*cmd)->subtype, rel, ATT_TABLE | ATT_FOREIGN_TABLE);
6808 :
6809 2388 : if (rel->rd_rel->relispartition && !recursing)
6810 12 : ereport(ERROR,
6811 : (errcode(ERRCODE_WRONG_OBJECT_TYPE),
6812 : errmsg("cannot add column to a partition")));
6813 :
6814 2376 : attrdesc = table_open(AttributeRelationId, RowExclusiveLock);
6815 :
6816 : /*
6817 : * Are we adding the column to a recursion child? If so, check whether to
6818 : * merge with an existing definition for the column. If we do merge, we
6819 : * must not recurse. Children will already have the column, and recursing
6820 : * into them would mess up attinhcount.
6821 : */
6822 2376 : if (colDef->inhcount > 0)
6823 : {
6824 : HeapTuple tuple;
6825 :
6826 : /* Does child already have a column by this name? */
6827 576 : tuple = SearchSysCacheCopyAttName(myrelid, colDef->colname);
6828 576 : if (HeapTupleIsValid(tuple))
6829 : {
6830 24 : Form_pg_attribute childatt = (Form_pg_attribute) GETSTRUCT(tuple);
6831 : Oid ctypeId;
6832 : int32 ctypmod;
6833 : Oid ccollid;
6834 :
6835 : /* Child column must match on type, typmod, and collation */
6836 24 : typenameTypeIdAndMod(NULL, colDef->typeName, &ctypeId, &ctypmod);
6837 24 : if (ctypeId != childatt->atttypid ||
6838 24 : ctypmod != childatt->atttypmod)
6839 0 : ereport(ERROR,
6840 : (errcode(ERRCODE_DATATYPE_MISMATCH),
6841 : errmsg("child table \"%s\" has different type for column \"%s\"",
6842 : RelationGetRelationName(rel), colDef->colname)));
6843 24 : ccollid = GetColumnDefCollation(NULL, colDef, ctypeId);
6844 24 : if (ccollid != childatt->attcollation)
6845 0 : ereport(ERROR,
6846 : (errcode(ERRCODE_COLLATION_MISMATCH),
6847 : errmsg("child table \"%s\" has different collation for column \"%s\"",
6848 : RelationGetRelationName(rel), colDef->colname),
6849 : errdetail("\"%s\" versus \"%s\"",
6850 : get_collation_name(ccollid),
6851 : get_collation_name(childatt->attcollation))));
6852 :
6853 : /* Bump the existing child att's inhcount */
6854 24 : childatt->attinhcount++;
6855 24 : if (childatt->attinhcount < 0)
6856 0 : ereport(ERROR,
6857 : errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
6858 : errmsg("too many inheritance parents"));
6859 24 : CatalogTupleUpdate(attrdesc, &tuple->t_self, tuple);
6860 :
6861 24 : heap_freetuple(tuple);
6862 :
6863 : /* Inform the user about the merge */
6864 24 : ereport(NOTICE,
6865 : (errmsg("merging definition of column \"%s\" for child \"%s\"",
6866 : colDef->colname, RelationGetRelationName(rel))));
6867 :
6868 24 : table_close(attrdesc, RowExclusiveLock);
6869 24 : return InvalidObjectAddress;
6870 : }
6871 : }
6872 :
6873 : /* skip if the name already exists and if_not_exists is true */
6874 2352 : if (!check_for_column_name_collision(rel, colDef->colname, if_not_exists))
6875 : {
6876 54 : table_close(attrdesc, RowExclusiveLock);
6877 54 : return InvalidObjectAddress;
6878 : }
6879 :
6880 : /*
6881 : * Okay, we need to add the column, so go ahead and do parse
6882 : * transformation. This can result in queueing up, or even immediately
6883 : * executing, subsidiary operations (such as creation of unique indexes);
6884 : * so we mustn't do it until we have made the if_not_exists check.
6885 : *
6886 : * When recursing, the command was already transformed and we needn't do
6887 : * so again. Also, if context isn't given we can't transform. (That
6888 : * currently happens only for AT_AddColumnToView; we expect that view.c
6889 : * passed us a ColumnDef that doesn't need work.)
6890 : */
6891 2268 : if (context != NULL && !recursing)
6892 : {
6893 1692 : *cmd = ATParseTransformCmd(wqueue, tab, rel, *cmd, recurse, lockmode,
6894 : cur_pass, context);
6895 : Assert(*cmd != NULL);
6896 1692 : colDef = castNode(ColumnDef, (*cmd)->def);
6897 : }
6898 :
6899 : /*
6900 : * Cannot add identity column if table has children, because identity does
6901 : * not inherit. (Adding column and identity separately will work.)
6902 : */
6903 2268 : if (colDef->identity &&
6904 30 : recurse &&
6905 30 : find_inheritance_children(myrelid, NoLock) != NIL)
6906 6 : ereport(ERROR,
6907 : (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
6908 : errmsg("cannot recursively add identity column to table that has child tables")));
6909 :
6910 2262 : pgclass = table_open(RelationRelationId, RowExclusiveLock);
6911 :
6912 2262 : reltup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(myrelid));
6913 2262 : if (!HeapTupleIsValid(reltup))
6914 0 : elog(ERROR, "cache lookup failed for relation %u", myrelid);
6915 2262 : relkind = ((Form_pg_class) GETSTRUCT(reltup))->relkind;
6916 :
6917 : /* Determine the new attribute's number */
6918 2262 : newattnum = ((Form_pg_class) GETSTRUCT(reltup))->relnatts + 1;
6919 2262 : if (newattnum > MaxHeapAttributeNumber)
6920 0 : ereport(ERROR,
6921 : (errcode(ERRCODE_TOO_MANY_COLUMNS),
6922 : errmsg("tables can have at most %d columns",
6923 : MaxHeapAttributeNumber)));
6924 :
6925 2262 : typeTuple = typenameType(NULL, colDef->typeName, &typmod);
6926 2262 : tform = (Form_pg_type) GETSTRUCT(typeTuple);
6927 2262 : typeOid = tform->oid;
6928 :
6929 2262 : aclresult = object_aclcheck(TypeRelationId, typeOid, GetUserId(), ACL_USAGE);
6930 2262 : if (aclresult != ACLCHECK_OK)
6931 12 : aclcheck_error_type(aclresult, typeOid);
6932 :
6933 2250 : collOid = GetColumnDefCollation(NULL, colDef, typeOid);
6934 :
6935 : /* make sure datatype is legal for a column */
6936 2250 : CheckAttributeType(colDef->colname, typeOid, collOid,
6937 2250 : list_make1_oid(rel->rd_rel->reltype),
6938 : 0);
6939 :
6940 : /*
6941 : * Construct new attribute's pg_attribute entry. (Variable-length fields
6942 : * are handled by InsertPgAttributeTuples().)
6943 : */
6944 2220 : attribute.attrelid = myrelid;
6945 2220 : namestrcpy(&(attribute.attname), colDef->colname);
6946 2220 : attribute.atttypid = typeOid;
6947 2220 : attribute.attstattarget = (newattnum > 0) ? -1 : 0;
6948 2220 : attribute.attlen = tform->typlen;
6949 2220 : attribute.attnum = newattnum;
6950 2220 : if (list_length(colDef->typeName->arrayBounds) > PG_INT16_MAX)
6951 0 : ereport(ERROR,
6952 : errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
6953 : errmsg("too many array dimensions"));
6954 2220 : attribute.attndims = list_length(colDef->typeName->arrayBounds);
6955 2220 : attribute.atttypmod = typmod;
6956 2220 : attribute.attbyval = tform->typbyval;
6957 2220 : attribute.attalign = tform->typalign;
6958 2220 : if (colDef->storage_name)
6959 0 : attribute.attstorage = GetAttributeStorage(typeOid, colDef->storage_name);
6960 : else
6961 2220 : attribute.attstorage = tform->typstorage;
6962 2220 : attribute.attcompression = GetAttributeCompression(typeOid,
6963 : colDef->compression);
6964 2220 : attribute.attnotnull = colDef->is_not_null;
6965 2220 : attribute.atthasdef = false;
6966 2220 : attribute.atthasmissing = false;
6967 2220 : attribute.attidentity = colDef->identity;
6968 2220 : attribute.attgenerated = colDef->generated;
6969 2220 : attribute.attisdropped = false;
6970 2220 : attribute.attislocal = colDef->is_local;
6971 2220 : attribute.attinhcount = colDef->inhcount;
6972 2220 : attribute.attcollation = collOid;
6973 :
6974 2220 : ReleaseSysCache(typeTuple);
6975 :
6976 2220 : tupdesc = CreateTupleDesc(lengthof(aattr), (FormData_pg_attribute **) &aattr);
6977 :
6978 2220 : InsertPgAttributeTuples(attrdesc, tupdesc, myrelid, NULL, NULL);
6979 :
6980 2220 : table_close(attrdesc, RowExclusiveLock);
6981 :
6982 : /*
6983 : * Update pg_class tuple as appropriate
6984 : */
6985 2220 : ((Form_pg_class) GETSTRUCT(reltup))->relnatts = newattnum;
6986 :
6987 2220 : CatalogTupleUpdate(pgclass, &reltup->t_self, reltup);
6988 :
6989 2220 : heap_freetuple(reltup);
6990 :
6991 : /* Post creation hook for new attribute */
6992 2220 : InvokeObjectPostCreateHook(RelationRelationId, myrelid, newattnum);
6993 :
6994 2220 : table_close(pgclass, RowExclusiveLock);
6995 :
6996 : /* Make the attribute's catalog entry visible */
6997 2220 : CommandCounterIncrement();
6998 :
6999 : /*
7000 : * Store the DEFAULT, if any, in the catalogs
7001 : */
7002 2220 : if (colDef->raw_default)
7003 : {
7004 : RawColumnDefault *rawEnt;
7005 :
7006 682 : rawEnt = (RawColumnDefault *) palloc(sizeof(RawColumnDefault));
7007 682 : rawEnt->attnum = attribute.attnum;
7008 682 : rawEnt->raw_default = copyObject(colDef->raw_default);
7009 :
7010 : /*
7011 : * Attempt to skip a complete table rewrite by storing the specified
7012 : * DEFAULT value outside of the heap. This may be disabled inside
7013 : * AddRelationNewConstraints if the optimization cannot be applied.
7014 : */
7015 682 : rawEnt->missingMode = (!colDef->generated);
7016 :
7017 682 : rawEnt->generated = colDef->generated;
7018 :
7019 : /*
7020 : * This function is intended for CREATE TABLE, so it processes a
7021 : * _list_ of defaults, but we just do one.
7022 : */
7023 682 : AddRelationNewConstraints(rel, list_make1(rawEnt), NIL,
7024 : false, true, false, NULL);
7025 :
7026 : /* Make the additional catalog changes visible */
7027 670 : CommandCounterIncrement();
7028 :
7029 : /*
7030 : * Did the request for a missing value work? If not we'll have to do a
7031 : * rewrite
7032 : */
7033 670 : if (!rawEnt->missingMode)
7034 96 : tab->rewrite |= AT_REWRITE_DEFAULT_VAL;
7035 : }
7036 :
7037 : /*
7038 : * Tell Phase 3 to fill in the default expression, if there is one.
7039 : *
7040 : * If there is no default, Phase 3 doesn't have to do anything, because
7041 : * that effectively means that the default is NULL. The heap tuple access
7042 : * routines always check for attnum > # of attributes in tuple, and return
7043 : * NULL if so, so without any modification of the tuple data we will get
7044 : * the effect of NULL values in the new column.
7045 : *
7046 : * An exception occurs when the new column is of a domain type: the domain
7047 : * might have a NOT NULL constraint, or a check constraint that indirectly
7048 : * rejects nulls. If there are any domain constraints then we construct
7049 : * an explicit NULL default value that will be passed through
7050 : * CoerceToDomain processing. (This is a tad inefficient, since it causes
7051 : * rewriting the table which we really don't have to do, but the present
7052 : * design of domain processing doesn't offer any simple way of checking
7053 : * the constraints more directly.)
7054 : *
7055 : * Note: we use build_column_default, and not just the cooked default
7056 : * returned by AddRelationNewConstraints, so that the right thing happens
7057 : * when a datatype's default applies.
7058 : *
7059 : * Note: it might seem that this should happen at the end of Phase 2, so
7060 : * that the effects of subsequent subcommands can be taken into account.
7061 : * It's intentional that we do it now, though. The new column should be
7062 : * filled according to what is said in the ADD COLUMN subcommand, so that
7063 : * the effects are the same as if this subcommand had been run by itself
7064 : * and the later subcommands had been issued in new ALTER TABLE commands.
7065 : *
7066 : * We can skip this entirely for relations without storage, since Phase 3
7067 : * is certainly not going to touch them. System attributes don't have
7068 : * interesting defaults, either.
7069 : */
7070 2208 : if (RELKIND_HAS_STORAGE(relkind) && attribute.attnum > 0)
7071 : {
7072 : /*
7073 : * For an identity column, we can't use build_column_default(),
7074 : * because the sequence ownership isn't set yet. So do it manually.
7075 : */
7076 1868 : if (colDef->identity)
7077 : {
7078 24 : NextValueExpr *nve = makeNode(NextValueExpr);
7079 :
7080 24 : nve->seqid = RangeVarGetRelid(colDef->identitySequence, NoLock, false);
7081 24 : nve->typeId = typeOid;
7082 :
7083 24 : defval = (Expr *) nve;
7084 :
7085 : /* must do a rewrite for identity columns */
7086 24 : tab->rewrite |= AT_REWRITE_DEFAULT_VAL;
7087 : }
7088 : else
7089 1844 : defval = (Expr *) build_column_default(rel, attribute.attnum);
7090 :
7091 1868 : if (!defval && DomainHasConstraints(typeOid))
7092 : {
7093 : Oid baseTypeId;
7094 : int32 baseTypeMod;
7095 : Oid baseTypeColl;
7096 :
7097 6 : baseTypeMod = typmod;
7098 6 : baseTypeId = getBaseTypeAndTypmod(typeOid, &baseTypeMod);
7099 6 : baseTypeColl = get_typcollation(baseTypeId);
7100 6 : defval = (Expr *) makeNullConst(baseTypeId, baseTypeMod, baseTypeColl);
7101 6 : defval = (Expr *) coerce_to_target_type(NULL,
7102 : (Node *) defval,
7103 : baseTypeId,
7104 : typeOid,
7105 : typmod,
7106 : COERCION_ASSIGNMENT,
7107 : COERCE_IMPLICIT_CAST,
7108 : -1);
7109 6 : if (defval == NULL) /* should not happen */
7110 0 : elog(ERROR, "failed to coerce base type to domain");
7111 : }
7112 :
7113 1868 : if (defval)
7114 : {
7115 : NewColumnValue *newval;
7116 :
7117 578 : newval = (NewColumnValue *) palloc0(sizeof(NewColumnValue));
7118 578 : newval->attnum = attribute.attnum;
7119 578 : newval->expr = expression_planner(defval);
7120 578 : newval->is_generated = (colDef->generated != '\0');
7121 :
7122 578 : tab->newvals = lappend(tab->newvals, newval);
7123 : }
7124 :
7125 1868 : if (DomainHasConstraints(typeOid))
7126 12 : tab->rewrite |= AT_REWRITE_DEFAULT_VAL;
7127 :
7128 1868 : if (!TupleDescAttr(rel->rd_att, attribute.attnum - 1)->atthasmissing)
7129 : {
7130 : /*
7131 : * If the new column is NOT NULL, and there is no missing value,
7132 : * tell Phase 3 it needs to check for NULLs.
7133 : */
7134 1422 : tab->verify_new_notnull |= colDef->is_not_null;
7135 : }
7136 : }
7137 :
7138 : /*
7139 : * Add needed dependency entries for the new column.
7140 : */
7141 2208 : add_column_datatype_dependency(myrelid, newattnum, attribute.atttypid);
7142 2208 : add_column_collation_dependency(myrelid, newattnum, attribute.attcollation);
7143 :
7144 : /*
7145 : * Propagate to children as appropriate. Unlike most other ALTER
7146 : * routines, we have to do this one level of recursion at a time; we can't
7147 : * use find_all_inheritors to do it in one pass.
7148 : */
7149 : children =
7150 2208 : find_inheritance_children(RelationGetRelid(rel), lockmode);
7151 :
7152 : /*
7153 : * If we are told not to recurse, there had better not be any child
7154 : * tables; else the addition would put them out of step.
7155 : */
7156 2208 : if (children && !recurse)
7157 12 : ereport(ERROR,
7158 : (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
7159 : errmsg("column must be added to child tables too")));
7160 :
7161 : /* Children should see column as singly inherited */
7162 2196 : if (!recursing)
7163 : {
7164 1644 : childcmd = copyObject(*cmd);
7165 1644 : colDef = castNode(ColumnDef, childcmd->def);
7166 1644 : colDef->inhcount = 1;
7167 1644 : colDef->is_local = false;
7168 : }
7169 : else
7170 552 : childcmd = *cmd; /* no need to copy again */
7171 :
7172 2772 : foreach(child, children)
7173 : {
7174 576 : Oid childrelid = lfirst_oid(child);
7175 : Relation childrel;
7176 : AlteredTableInfo *childtab;
7177 :
7178 : /* find_inheritance_children already got lock */
7179 576 : childrel = table_open(childrelid, NoLock);
7180 576 : CheckTableNotInUse(childrel, "ALTER TABLE");
7181 :
7182 : /* Find or create work queue entry for this table */
7183 576 : childtab = ATGetQueueEntry(wqueue, childrel);
7184 :
7185 : /* Recurse to child; return value is ignored */
7186 576 : ATExecAddColumn(wqueue, childtab, childrel,
7187 : &childcmd, recurse, true,
7188 : lockmode, cur_pass, context);
7189 :
7190 576 : table_close(childrel, NoLock);
7191 : }
7192 :
7193 2196 : ObjectAddressSubSet(address, RelationRelationId, myrelid, newattnum);
7194 2196 : return address;
7195 : }
7196 :
7197 : /*
7198 : * If a new or renamed column will collide with the name of an existing
7199 : * column and if_not_exists is false then error out, else do nothing.
7200 : */
7201 : static bool
7202 2784 : check_for_column_name_collision(Relation rel, const char *colname,
7203 : bool if_not_exists)
7204 : {
7205 : HeapTuple attTuple;
7206 : int attnum;
7207 :
7208 : /*
7209 : * this test is deliberately not attisdropped-aware, since if one tries to
7210 : * add a column matching a dropped column name, it's gonna fail anyway.
7211 : */
7212 2784 : attTuple = SearchSysCache2(ATTNAME,
7213 : ObjectIdGetDatum(RelationGetRelid(rel)),
7214 : PointerGetDatum(colname));
7215 2784 : if (!HeapTupleIsValid(attTuple))
7216 2688 : return true;
7217 :
7218 96 : attnum = ((Form_pg_attribute) GETSTRUCT(attTuple))->attnum;
7219 96 : ReleaseSysCache(attTuple);
7220 :
7221 : /*
7222 : * We throw a different error message for conflicts with system column
7223 : * names, since they are normally not shown and the user might otherwise
7224 : * be confused about the reason for the conflict.
7225 : */
7226 96 : if (attnum <= 0)
7227 12 : ereport(ERROR,
7228 : (errcode(ERRCODE_DUPLICATE_COLUMN),
7229 : errmsg("column name \"%s\" conflicts with a system column name",
7230 : colname)));
7231 : else
7232 : {
7233 84 : if (if_not_exists)
7234 : {
7235 54 : ereport(NOTICE,
7236 : (errcode(ERRCODE_DUPLICATE_COLUMN),
7237 : errmsg("column \"%s\" of relation \"%s\" already exists, skipping",
7238 : colname, RelationGetRelationName(rel))));
7239 54 : return false;
7240 : }
7241 :
7242 30 : ereport(ERROR,
7243 : (errcode(ERRCODE_DUPLICATE_COLUMN),
7244 : errmsg("column \"%s\" of relation \"%s\" already exists",
7245 : colname, RelationGetRelationName(rel))));
7246 : }
7247 :
7248 : return true;
7249 : }
7250 :
7251 : /*
7252 : * Install a column's dependency on its datatype.
7253 : */
7254 : static void
7255 3102 : add_column_datatype_dependency(Oid relid, int32 attnum, Oid typid)
7256 : {
7257 : ObjectAddress myself,
7258 : referenced;
7259 :
7260 3102 : myself.classId = RelationRelationId;
7261 3102 : myself.objectId = relid;
7262 3102 : myself.objectSubId = attnum;
7263 3102 : referenced.classId = TypeRelationId;
7264 3102 : referenced.objectId = typid;
7265 3102 : referenced.objectSubId = 0;
7266 3102 : recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
7267 3102 : }
7268 :
7269 : /*
7270 : * Install a column's dependency on its collation.
7271 : */
7272 : static void
7273 3102 : add_column_collation_dependency(Oid relid, int32 attnum, Oid collid)
7274 : {
7275 : ObjectAddress myself,
7276 : referenced;
7277 :
7278 : /* We know the default collation is pinned, so don't bother recording it */
7279 3102 : if (OidIsValid(collid) && collid != DEFAULT_COLLATION_OID)
7280 : {
7281 18 : myself.classId = RelationRelationId;
7282 18 : myself.objectId = relid;
7283 18 : myself.objectSubId = attnum;
7284 18 : referenced.classId = CollationRelationId;
7285 18 : referenced.objectId = collid;
7286 18 : referenced.objectSubId = 0;
7287 18 : recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
7288 : }
7289 3102 : }
7290 :
7291 : /*
7292 : * ALTER TABLE ALTER COLUMN DROP NOT NULL
7293 : */
7294 :
7295 : static void
7296 170 : ATPrepDropNotNull(Relation rel, bool recurse, bool recursing)
7297 : {
7298 : /*
7299 : * If the parent is a partitioned table, like check constraints, we do not
7300 : * support removing the NOT NULL while partitions exist.
7301 : */
7302 170 : if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
7303 : {
7304 12 : PartitionDesc partdesc = RelationGetPartitionDesc(rel, true);
7305 :
7306 : Assert(partdesc != NULL);
7307 12 : if (partdesc->nparts > 0 && !recurse && !recursing)
7308 6 : ereport(ERROR,
7309 : (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
7310 : errmsg("cannot remove constraint from only the partitioned table when partitions exist"),
7311 : errhint("Do not specify the ONLY keyword.")));
7312 : }
7313 164 : }
7314 :
7315 : /*
7316 : * Return the address of the modified column. If the column was already
7317 : * nullable, InvalidObjectAddress is returned.
7318 : */
7319 : static ObjectAddress
7320 164 : ATExecDropNotNull(Relation rel, const char *colName, LOCKMODE lockmode)
7321 : {
7322 : HeapTuple tuple;
7323 : Form_pg_attribute attTup;
7324 : AttrNumber attnum;
7325 : Relation attr_rel;
7326 : List *indexoidlist;
7327 : ListCell *indexoidscan;
7328 : ObjectAddress address;
7329 :
7330 : /*
7331 : * lookup the attribute
7332 : */
7333 164 : attr_rel = table_open(AttributeRelationId, RowExclusiveLock);
7334 :
7335 164 : tuple = SearchSysCacheCopyAttName(RelationGetRelid(rel), colName);
7336 164 : if (!HeapTupleIsValid(tuple))
7337 18 : ereport(ERROR,
7338 : (errcode(ERRCODE_UNDEFINED_COLUMN),
7339 : errmsg("column \"%s\" of relation \"%s\" does not exist",
7340 : colName, RelationGetRelationName(rel))));
7341 146 : attTup = (Form_pg_attribute) GETSTRUCT(tuple);
7342 146 : attnum = attTup->attnum;
7343 :
7344 : /* Prevent them from altering a system attribute */
7345 146 : if (attnum <= 0)
7346 0 : ereport(ERROR,
7347 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
7348 : errmsg("cannot alter system column \"%s\"",
7349 : colName)));
7350 :
7351 146 : if (attTup->attidentity)
7352 6 : ereport(ERROR,
7353 : (errcode(ERRCODE_SYNTAX_ERROR),
7354 : errmsg("column \"%s\" of relation \"%s\" is an identity column",
7355 : colName, RelationGetRelationName(rel))));
7356 :
7357 : /*
7358 : * Check that the attribute is not in a primary key or in an index used as
7359 : * a replica identity.
7360 : *
7361 : * Note: we'll throw error even if the pkey index is not valid.
7362 : */
7363 :
7364 : /* Loop over all indexes on the relation */
7365 140 : indexoidlist = RelationGetIndexList(rel);
7366 :
7367 152 : foreach(indexoidscan, indexoidlist)
7368 : {
7369 24 : Oid indexoid = lfirst_oid(indexoidscan);
7370 : HeapTuple indexTuple;
7371 : Form_pg_index indexStruct;
7372 : int i;
7373 :
7374 24 : indexTuple = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(indexoid));
7375 24 : if (!HeapTupleIsValid(indexTuple))
7376 0 : elog(ERROR, "cache lookup failed for index %u", indexoid);
7377 24 : indexStruct = (Form_pg_index) GETSTRUCT(indexTuple);
7378 :
7379 : /*
7380 : * If the index is not a primary key or an index used as replica
7381 : * identity, skip the check.
7382 : */
7383 24 : if (indexStruct->indisprimary || indexStruct->indisreplident)
7384 : {
7385 : /*
7386 : * Loop over each attribute in the primary key or the index used
7387 : * as replica identity and see if it matches the to-be-altered
7388 : * attribute.
7389 : */
7390 24 : for (i = 0; i < indexStruct->indnkeyatts; i++)
7391 : {
7392 18 : if (indexStruct->indkey.values[i] == attnum)
7393 : {
7394 12 : if (indexStruct->indisprimary)
7395 6 : ereport(ERROR,
7396 : (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
7397 : errmsg("column \"%s\" is in a primary key",
7398 : colName)));
7399 : else
7400 6 : ereport(ERROR,
7401 : (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
7402 : errmsg("column \"%s\" is in index used as replica identity",
7403 : colName)));
7404 : }
7405 : }
7406 : }
7407 :
7408 12 : ReleaseSysCache(indexTuple);
7409 : }
7410 :
7411 128 : list_free(indexoidlist);
7412 :
7413 : /* If rel is partition, shouldn't drop NOT NULL if parent has the same */
7414 128 : if (rel->rd_rel->relispartition)
7415 : {
7416 18 : Oid parentId = get_partition_parent(RelationGetRelid(rel), false);
7417 18 : Relation parent = table_open(parentId, AccessShareLock);
7418 18 : TupleDesc tupDesc = RelationGetDescr(parent);
7419 : AttrNumber parent_attnum;
7420 :
7421 18 : parent_attnum = get_attnum(parentId, colName);
7422 18 : if (TupleDescAttr(tupDesc, parent_attnum - 1)->attnotnull)
7423 18 : ereport(ERROR,
7424 : (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
7425 : errmsg("column \"%s\" is marked NOT NULL in parent table",
7426 : colName)));
7427 0 : table_close(parent, AccessShareLock);
7428 : }
7429 :
7430 : /*
7431 : * Okay, actually perform the catalog change ... if needed
7432 : */
7433 110 : if (attTup->attnotnull)
7434 : {
7435 110 : attTup->attnotnull = false;
7436 :
7437 110 : CatalogTupleUpdate(attr_rel, &tuple->t_self, tuple);
7438 :
7439 110 : ObjectAddressSubSet(address, RelationRelationId,
7440 : RelationGetRelid(rel), attnum);
7441 : }
7442 : else
7443 0 : address = InvalidObjectAddress;
7444 :
7445 110 : InvokeObjectPostAlterHook(RelationRelationId,
7446 : RelationGetRelid(rel), attnum);
7447 :
7448 110 : table_close(attr_rel, RowExclusiveLock);
7449 :
7450 110 : return address;
7451 : }
7452 :
7453 : /*
7454 : * ALTER TABLE ALTER COLUMN SET NOT NULL
7455 : */
7456 :
7457 : static void
7458 50650 : ATPrepSetNotNull(List **wqueue, Relation rel,
7459 : AlterTableCmd *cmd, bool recurse, bool recursing,
7460 : LOCKMODE lockmode, AlterTableUtilityContext *context)
7461 : {
7462 : /*
7463 : * If we're already recursing, there's nothing to do; the topmost
7464 : * invocation of ATSimpleRecursion already visited all children.
7465 : */
7466 50650 : if (recursing)
7467 162 : return;
7468 :
7469 : /*
7470 : * If the target column is already marked NOT NULL, we can skip recursing
7471 : * to children, because their columns should already be marked NOT NULL as
7472 : * well. But there's no point in checking here unless the relation has
7473 : * some children; else we can just wait till execution to check. (If it
7474 : * does have children, however, this can save taking per-child locks
7475 : * unnecessarily. This greatly improves concurrency in some parallel
7476 : * restore scenarios.)
7477 : *
7478 : * Unfortunately, we can only apply this optimization to partitioned
7479 : * tables, because traditional inheritance doesn't enforce that child
7480 : * columns be NOT NULL when their parent is. (That's a bug that should
7481 : * get fixed someday.)
7482 : */
7483 50488 : if (rel->rd_rel->relhassubclass &&
7484 188 : rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
7485 : {
7486 : HeapTuple tuple;
7487 : bool attnotnull;
7488 :
7489 150 : tuple = SearchSysCacheAttName(RelationGetRelid(rel), cmd->name);
7490 :
7491 : /* Might as well throw the error now, if name is bad */
7492 150 : if (!HeapTupleIsValid(tuple))
7493 0 : ereport(ERROR,
7494 : (errcode(ERRCODE_UNDEFINED_COLUMN),
7495 : errmsg("column \"%s\" of relation \"%s\" does not exist",
7496 : cmd->name, RelationGetRelationName(rel))));
7497 :
7498 150 : attnotnull = ((Form_pg_attribute) GETSTRUCT(tuple))->attnotnull;
7499 150 : ReleaseSysCache(tuple);
7500 150 : if (attnotnull)
7501 56 : return;
7502 : }
7503 :
7504 : /*
7505 : * If we have ALTER TABLE ONLY ... SET NOT NULL on a partitioned table,
7506 : * apply ALTER TABLE ... CHECK NOT NULL to every child. Otherwise, use
7507 : * normal recursion logic.
7508 : */
7509 50432 : if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE &&
7510 130 : !recurse)
7511 36 : {
7512 36 : AlterTableCmd *newcmd = makeNode(AlterTableCmd);
7513 :
7514 36 : newcmd->subtype = AT_CheckNotNull;
7515 36 : newcmd->name = pstrdup(cmd->name);
7516 36 : ATSimpleRecursion(wqueue, rel, newcmd, true, lockmode, context);
7517 : }
7518 : else
7519 50396 : ATSimpleRecursion(wqueue, rel, cmd, recurse, lockmode, context);
7520 : }
7521 :
7522 : /*
7523 : * Return the address of the modified column. If the column was already NOT
7524 : * NULL, InvalidObjectAddress is returned.
7525 : */
7526 : static ObjectAddress
7527 50650 : ATExecSetNotNull(AlteredTableInfo *tab, Relation rel,
7528 : const char *colName, LOCKMODE lockmode)
7529 : {
7530 : HeapTuple tuple;
7531 : AttrNumber attnum;
7532 : Relation attr_rel;
7533 : ObjectAddress address;
7534 :
7535 : /*
7536 : * lookup the attribute
7537 : */
7538 50650 : attr_rel = table_open(AttributeRelationId, RowExclusiveLock);
7539 :
7540 50650 : tuple = SearchSysCacheCopyAttName(RelationGetRelid(rel), colName);
7541 :
7542 50650 : if (!HeapTupleIsValid(tuple))
7543 36 : ereport(ERROR,
7544 : (errcode(ERRCODE_UNDEFINED_COLUMN),
7545 : errmsg("column \"%s\" of relation \"%s\" does not exist",
7546 : colName, RelationGetRelationName(rel))));
7547 :
7548 50614 : attnum = ((Form_pg_attribute) GETSTRUCT(tuple))->attnum;
7549 :
7550 : /* Prevent them from altering a system attribute */
7551 50614 : if (attnum <= 0)
7552 0 : ereport(ERROR,
7553 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
7554 : errmsg("cannot alter system column \"%s\"",
7555 : colName)));
7556 :
7557 : /*
7558 : * Okay, actually perform the catalog change ... if needed
7559 : */
7560 50614 : if (!((Form_pg_attribute) GETSTRUCT(tuple))->attnotnull)
7561 : {
7562 852 : ((Form_pg_attribute) GETSTRUCT(tuple))->attnotnull = true;
7563 :
7564 852 : CatalogTupleUpdate(attr_rel, &tuple->t_self, tuple);
7565 :
7566 : /*
7567 : * Ordinarily phase 3 must ensure that no NULLs exist in columns that
7568 : * are set NOT NULL; however, if we can find a constraint which proves
7569 : * this then we can skip that. We needn't bother looking if we've
7570 : * already found that we must verify some other NOT NULL constraint.
7571 : */
7572 852 : if (!tab->verify_new_notnull &&
7573 760 : !NotNullImpliedByRelConstraints(rel, (Form_pg_attribute) GETSTRUCT(tuple)))
7574 : {
7575 : /* Tell Phase 3 it needs to test the constraint */
7576 730 : tab->verify_new_notnull = true;
7577 : }
7578 :
7579 852 : ObjectAddressSubSet(address, RelationRelationId,
7580 : RelationGetRelid(rel), attnum);
7581 : }
7582 : else
7583 49762 : address = InvalidObjectAddress;
7584 :
7585 50614 : InvokeObjectPostAlterHook(RelationRelationId,
7586 : RelationGetRelid(rel), attnum);
7587 :
7588 50614 : table_close(attr_rel, RowExclusiveLock);
7589 :
7590 50614 : return address;
7591 : }
7592 :
7593 : /*
7594 : * ALTER TABLE ALTER COLUMN CHECK NOT NULL
7595 : *
7596 : * This doesn't exist in the grammar, but we generate AT_CheckNotNull
7597 : * commands against the partitions of a partitioned table if the user
7598 : * writes ALTER TABLE ONLY ... SET NOT NULL on the partitioned table,
7599 : * or tries to create a primary key on it (which internally creates
7600 : * AT_SetNotNull on the partitioned table). Such a command doesn't
7601 : * allow us to actually modify any partition, but we want to let it
7602 : * go through if the partitions are already properly marked.
7603 : *
7604 : * In future, this might need to adjust the child table's state, likely
7605 : * by incrementing an inheritance count for the attnotnull constraint.
7606 : * For now we need only check for the presence of the flag.
7607 : */
7608 : static void
7609 30 : ATExecCheckNotNull(AlteredTableInfo *tab, Relation rel,
7610 : const char *colName, LOCKMODE lockmode)
7611 : {
7612 : HeapTuple tuple;
7613 :
7614 30 : tuple = SearchSysCacheAttName(RelationGetRelid(rel), colName);
7615 :
7616 30 : if (!HeapTupleIsValid(tuple))
7617 0 : ereport(ERROR,
7618 : (errcode(ERRCODE_UNDEFINED_COLUMN),
7619 : errmsg("column \"%s\" of relation \"%s\" does not exist",
7620 : colName, RelationGetRelationName(rel))));
7621 :
7622 30 : if (!((Form_pg_attribute) GETSTRUCT(tuple))->attnotnull)
7623 12 : ereport(ERROR,
7624 : (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
7625 : errmsg("constraint must be added to child tables too"),
7626 : errdetail("Column \"%s\" of relation \"%s\" is not already NOT NULL.",
7627 : colName, RelationGetRelationName(rel)),
7628 : errhint("Do not specify the ONLY keyword.")));
7629 :
7630 18 : ReleaseSysCache(tuple);
7631 18 : }
7632 :
7633 : /*
7634 : * NotNullImpliedByRelConstraints
7635 : * Does rel's existing constraints imply NOT NULL for the given attribute?
7636 : */
7637 : static bool
7638 760 : NotNullImpliedByRelConstraints(Relation rel, Form_pg_attribute attr)
7639 : {
7640 760 : NullTest *nnulltest = makeNode(NullTest);
7641 :
7642 1520 : nnulltest->arg = (Expr *) makeVar(1,
7643 760 : attr->attnum,
7644 : attr->atttypid,
7645 : attr->atttypmod,
7646 : attr->attcollation,
7647 : 0);
7648 760 : nnulltest->nulltesttype = IS_NOT_NULL;
7649 :
7650 : /*
7651 : * argisrow = false is correct even for a composite column, because
7652 : * attnotnull does not represent a SQL-spec IS NOT NULL test in such a
7653 : * case, just IS DISTINCT FROM NULL.
7654 : */
7655 760 : nnulltest->argisrow = false;
7656 760 : nnulltest->location = -1;
7657 :
7658 760 : if (ConstraintImpliedByRelConstraint(rel, list_make1(nnulltest), NIL))
7659 : {
7660 30 : ereport(DEBUG1,
7661 : (errmsg_internal("existing constraints on column \"%s.%s\" are sufficient to prove that it does not contain nulls",
7662 : RelationGetRelationName(rel), NameStr(attr->attname))));
7663 30 : return true;
7664 : }
7665 :
7666 730 : return false;
7667 : }
7668 :
7669 : /*
7670 : * ALTER TABLE ALTER COLUMN SET/DROP DEFAULT
7671 : *
7672 : * Return the address of the affected column.
7673 : */
7674 : static ObjectAddress
7675 532 : ATExecColumnDefault(Relation rel, const char *colName,
7676 : Node *newDefault, LOCKMODE lockmode)
7677 : {
7678 532 : TupleDesc tupdesc = RelationGetDescr(rel);
7679 : AttrNumber attnum;
7680 : ObjectAddress address;
7681 :
7682 : /*
7683 : * get the number of the attribute
7684 : */
7685 532 : attnum = get_attnum(RelationGetRelid(rel), colName);
7686 532 : if (attnum == InvalidAttrNumber)
7687 30 : ereport(ERROR,
7688 : (errcode(ERRCODE_UNDEFINED_COLUMN),
7689 : errmsg("column \"%s\" of relation \"%s\" does not exist",
7690 : colName, RelationGetRelationName(rel))));
7691 :
7692 : /* Prevent them from altering a system attribute */
7693 502 : if (attnum <= 0)
7694 0 : ereport(ERROR,
7695 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
7696 : errmsg("cannot alter system column \"%s\"",
7697 : colName)));
7698 :
7699 502 : if (TupleDescAttr(tupdesc, attnum - 1)->attidentity)
7700 6 : ereport(ERROR,
7701 : (errcode(ERRCODE_SYNTAX_ERROR),
7702 : errmsg("column \"%s\" of relation \"%s\" is an identity column",
7703 : colName, RelationGetRelationName(rel)),
7704 : newDefault ? 0 : errhint("Use ALTER TABLE ... ALTER COLUMN ... DROP IDENTITY instead.")));
7705 :
7706 496 : if (TupleDescAttr(tupdesc, attnum - 1)->attgenerated)
7707 6 : ereport(ERROR,
7708 : (errcode(ERRCODE_SYNTAX_ERROR),
7709 : errmsg("column \"%s\" of relation \"%s\" is a generated column",
7710 : colName, RelationGetRelationName(rel)),
7711 : newDefault || TupleDescAttr(tupdesc, attnum - 1)->attgenerated != ATTRIBUTE_GENERATED_STORED ? 0 :
7712 : errhint("Use ALTER TABLE ... ALTER COLUMN ... DROP EXPRESSION instead.")));
7713 :
7714 : /*
7715 : * Remove any old default for the column. We use RESTRICT here for
7716 : * safety, but at present we do not expect anything to depend on the
7717 : * default.
7718 : *
7719 : * We treat removing the existing default as an internal operation when it
7720 : * is preparatory to adding a new default, but as a user-initiated
7721 : * operation when the user asked for a drop.
7722 : */
7723 490 : RemoveAttrDefault(RelationGetRelid(rel), attnum, DROP_RESTRICT, false,
7724 : newDefault != NULL);
7725 :
7726 490 : if (newDefault)
7727 : {
7728 : /* SET DEFAULT */
7729 : RawColumnDefault *rawEnt;
7730 :
7731 316 : rawEnt = (RawColumnDefault *) palloc(sizeof(RawColumnDefault));
7732 316 : rawEnt->attnum = attnum;
7733 316 : rawEnt->raw_default = newDefault;
7734 316 : rawEnt->missingMode = false;
7735 316 : rawEnt->generated = '\0';
7736 :
7737 : /*
7738 : * This function is intended for CREATE TABLE, so it processes a
7739 : * _list_ of defaults, but we just do one.
7740 : */
7741 316 : AddRelationNewConstraints(rel, list_make1(rawEnt), NIL,
7742 : false, true, false, NULL);
7743 : }
7744 :
7745 484 : ObjectAddressSubSet(address, RelationRelationId,
7746 : RelationGetRelid(rel), attnum);
7747 484 : return address;
7748 : }
7749 :
7750 : /*
7751 : * Add a pre-cooked default expression.
7752 : *
7753 : * Return the address of the affected column.
7754 : */
7755 : static ObjectAddress
7756 56 : ATExecCookedColumnDefault(Relation rel, AttrNumber attnum,
7757 : Node *newDefault)
7758 : {
7759 : ObjectAddress address;
7760 :
7761 : /* We assume no checking is required */
7762 :
7763 : /*
7764 : * Remove any old default for the column. We use RESTRICT here for
7765 : * safety, but at present we do not expect anything to depend on the
7766 : * default. (In ordinary cases, there could not be a default in place
7767 : * anyway, but it's possible when combining LIKE with inheritance.)
7768 : */
7769 56 : RemoveAttrDefault(RelationGetRelid(rel), attnum, DROP_RESTRICT, false,
7770 : true);
7771 :
7772 56 : (void) StoreAttrDefault(rel, attnum, newDefault, true, false);
7773 :
7774 56 : ObjectAddressSubSet(address, RelationRelationId,
7775 : RelationGetRelid(rel), attnum);
7776 56 : return address;
7777 : }
7778 :
7779 : /*
7780 : * ALTER TABLE ALTER COLUMN ADD IDENTITY
7781 : *
7782 : * Return the address of the affected column.
7783 : */
7784 : static ObjectAddress
7785 96 : ATExecAddIdentity(Relation rel, const char *colName,
7786 : Node *def, LOCKMODE lockmode)
7787 : {
7788 : Relation attrelation;
7789 : HeapTuple tuple;
7790 : Form_pg_attribute attTup;
7791 : AttrNumber attnum;
7792 : ObjectAddress address;
7793 96 : ColumnDef *cdef = castNode(ColumnDef, def);
7794 :
7795 96 : attrelation = table_open(AttributeRelationId, RowExclusiveLock);
7796 :
7797 96 : tuple = SearchSysCacheCopyAttName(RelationGetRelid(rel), colName);
7798 96 : if (!HeapTupleIsValid(tuple))
7799 0 : ereport(ERROR,
7800 : (errcode(ERRCODE_UNDEFINED_COLUMN),
7801 : errmsg("column \"%s\" of relation \"%s\" does not exist",
7802 : colName, RelationGetRelationName(rel))));
7803 96 : attTup = (Form_pg_attribute) GETSTRUCT(tuple);
7804 96 : attnum = attTup->attnum;
7805 :
7806 : /* Can't alter a system attribute */
7807 96 : if (attnum <= 0)
7808 0 : ereport(ERROR,
7809 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
7810 : errmsg("cannot alter system column \"%s\"",
7811 : colName)));
7812 :
7813 : /*
7814 : * Creating a column as identity implies NOT NULL, so adding the identity
7815 : * to an existing column that is not NOT NULL would create a state that
7816 : * cannot be reproduced without contortions.
7817 : */
7818 96 : if (!attTup->attnotnull)
7819 6 : ereport(ERROR,
7820 : (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
7821 : errmsg("column \"%s\" of relation \"%s\" must be declared NOT NULL before identity can be added",
7822 : colName, RelationGetRelationName(rel))));
7823 :
7824 90 : if (attTup->attidentity)
7825 12 : ereport(ERROR,
7826 : (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
7827 : errmsg("column \"%s\" of relation \"%s\" is already an identity column",
7828 : colName, RelationGetRelationName(rel))));
7829 :
7830 78 : if (attTup->atthasdef)
7831 6 : ereport(ERROR,
7832 : (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
7833 : errmsg("column \"%s\" of relation \"%s\" already has a default value",
7834 : colName, RelationGetRelationName(rel))));
7835 :
7836 72 : attTup->attidentity = cdef->identity;
7837 72 : CatalogTupleUpdate(attrelation, &tuple->t_self, tuple);
7838 :
7839 72 : InvokeObjectPostAlterHook(RelationRelationId,
7840 : RelationGetRelid(rel),
7841 : attTup->attnum);
7842 72 : ObjectAddressSubSet(address, RelationRelationId,
7843 : RelationGetRelid(rel), attnum);
7844 72 : heap_freetuple(tuple);
7845 :
7846 72 : table_close(attrelation, RowExclusiveLock);
7847 :
7848 72 : return address;
7849 : }
7850 :
7851 : /*
7852 : * ALTER TABLE ALTER COLUMN SET { GENERATED or sequence options }
7853 : *
7854 : * Return the address of the affected column.
7855 : */
7856 : static ObjectAddress
7857 38 : ATExecSetIdentity(Relation rel, const char *colName, Node *def, LOCKMODE lockmode)
7858 : {
7859 : ListCell *option;
7860 38 : DefElem *generatedEl = NULL;
7861 : HeapTuple tuple;
7862 : Form_pg_attribute attTup;
7863 : AttrNumber attnum;
7864 : Relation attrelation;
7865 : ObjectAddress address;
7866 :
7867 64 : foreach(option, castNode(List, def))
7868 : {
7869 26 : DefElem *defel = lfirst_node(DefElem, option);
7870 :
7871 26 : if (strcmp(defel->defname, "generated") == 0)
7872 : {
7873 26 : if (generatedEl)
7874 0 : ereport(ERROR,
7875 : (errcode(ERRCODE_SYNTAX_ERROR),
7876 : errmsg("conflicting or redundant options")));
7877 26 : generatedEl = defel;
7878 : }
7879 : else
7880 0 : elog(ERROR, "option \"%s\" not recognized",
7881 : defel->defname);
7882 : }
7883 :
7884 : /*
7885 : * Even if there is nothing to change here, we run all the checks. There
7886 : * will be a subsequent ALTER SEQUENCE that relies on everything being
7887 : * there.
7888 : */
7889 :
7890 38 : attrelation = table_open(AttributeRelationId, RowExclusiveLock);
7891 38 : tuple = SearchSysCacheCopyAttName(RelationGetRelid(rel), colName);
7892 38 : if (!HeapTupleIsValid(tuple))
7893 0 : ereport(ERROR,
7894 : (errcode(ERRCODE_UNDEFINED_COLUMN),
7895 : errmsg("column \"%s\" of relation \"%s\" does not exist",
7896 : colName, RelationGetRelationName(rel))));
7897 :
7898 38 : attTup = (Form_pg_attribute) GETSTRUCT(tuple);
7899 38 : attnum = attTup->attnum;
7900 :
7901 38 : if (attnum <= 0)
7902 0 : ereport(ERROR,
7903 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
7904 : errmsg("cannot alter system column \"%s\"",
7905 : colName)));
7906 :
7907 38 : if (!attTup->attidentity)
7908 6 : ereport(ERROR,
7909 : (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
7910 : errmsg("column \"%s\" of relation \"%s\" is not an identity column",
7911 : colName, RelationGetRelationName(rel))));
7912 :
7913 32 : if (generatedEl)
7914 : {
7915 26 : attTup->attidentity = defGetInt32(generatedEl);
7916 26 : CatalogTupleUpdate(attrelation, &tuple->t_self, tuple);
7917 :
7918 26 : InvokeObjectPostAlterHook(RelationRelationId,
7919 : RelationGetRelid(rel),
7920 : attTup->attnum);
7921 26 : ObjectAddressSubSet(address, RelationRelationId,
7922 : RelationGetRelid(rel), attnum);
7923 : }
7924 : else
7925 6 : address = InvalidObjectAddress;
7926 :
7927 32 : heap_freetuple(tuple);
7928 32 : table_close(attrelation, RowExclusiveLock);
7929 :
7930 32 : return address;
7931 : }
7932 :
7933 : /*
7934 : * ALTER TABLE ALTER COLUMN DROP IDENTITY
7935 : *
7936 : * Return the address of the affected column.
7937 : */
7938 : static ObjectAddress
7939 38 : ATExecDropIdentity(Relation rel, const char *colName, bool missing_ok, LOCKMODE lockmode)
7940 : {
7941 : HeapTuple tuple;
7942 : Form_pg_attribute attTup;
7943 : AttrNumber attnum;
7944 : Relation attrelation;
7945 : ObjectAddress address;
7946 : Oid seqid;
7947 : ObjectAddress seqaddress;
7948 :
7949 38 : attrelation = table_open(AttributeRelationId, RowExclusiveLock);
7950 38 : tuple = SearchSysCacheCopyAttName(RelationGetRelid(rel), colName);
7951 38 : if (!HeapTupleIsValid(tuple))
7952 0 : ereport(ERROR,
7953 : (errcode(ERRCODE_UNDEFINED_COLUMN),
7954 : errmsg("column \"%s\" of relation \"%s\" does not exist",
7955 : colName, RelationGetRelationName(rel))));
7956 :
7957 38 : attTup = (Form_pg_attribute) GETSTRUCT(tuple);
7958 38 : attnum = attTup->attnum;
7959 :
7960 38 : if (attnum <= 0)
7961 0 : ereport(ERROR,
7962 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
7963 : errmsg("cannot alter system column \"%s\"",
7964 : colName)));
7965 :
7966 38 : if (!attTup->attidentity)
7967 : {
7968 12 : if (!missing_ok)
7969 6 : ereport(ERROR,
7970 : (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
7971 : errmsg("column \"%s\" of relation \"%s\" is not an identity column",
7972 : colName, RelationGetRelationName(rel))));
7973 : else
7974 : {
7975 6 : ereport(NOTICE,
7976 : (errmsg("column \"%s\" of relation \"%s\" is not an identity column, skipping",
7977 : colName, RelationGetRelationName(rel))));
7978 6 : heap_freetuple(tuple);
7979 6 : table_close(attrelation, RowExclusiveLock);
7980 6 : return InvalidObjectAddress;
7981 : }
7982 : }
7983 :
7984 26 : attTup->attidentity = '\0';
7985 26 : CatalogTupleUpdate(attrelation, &tuple->t_self, tuple);
7986 :
7987 26 : InvokeObjectPostAlterHook(RelationRelationId,
7988 : RelationGetRelid(rel),
7989 : attTup->attnum);
7990 26 : ObjectAddressSubSet(address, RelationRelationId,
7991 : RelationGetRelid(rel), attnum);
7992 26 : heap_freetuple(tuple);
7993 :
7994 26 : table_close(attrelation, RowExclusiveLock);
7995 :
7996 : /* drop the internal sequence */
7997 26 : seqid = getIdentitySequence(RelationGetRelid(rel), attnum, false);
7998 26 : deleteDependencyRecordsForClass(RelationRelationId, seqid,
7999 : RelationRelationId, DEPENDENCY_INTERNAL);
8000 26 : CommandCounterIncrement();
8001 26 : seqaddress.classId = RelationRelationId;
8002 26 : seqaddress.objectId = seqid;
8003 26 : seqaddress.objectSubId = 0;
8004 26 : performDeletion(&seqaddress, DROP_RESTRICT, PERFORM_DELETION_INTERNAL);
8005 :
8006 26 : return address;
8007 : }
8008 :
8009 : /*
8010 : * ALTER TABLE ALTER COLUMN DROP EXPRESSION
8011 : */
8012 : static void
8013 44 : ATPrepDropExpression(Relation rel, AlterTableCmd *cmd, bool recurse, bool recursing, LOCKMODE lockmode)
8014 : {
8015 : /*
8016 : * Reject ONLY if there are child tables. We could implement this, but it
8017 : * is a bit complicated. GENERATED clauses must be attached to the column
8018 : * definition and cannot be added later like DEFAULT, so if a child table
8019 : * has a generation expression that the parent does not have, the child
8020 : * column will necessarily be an attislocal column. So to implement ONLY
8021 : * here, we'd need extra code to update attislocal of the direct child
8022 : * tables, somewhat similar to how DROP COLUMN does it, so that the
8023 : * resulting state can be properly dumped and restored.
8024 : */
8025 56 : if (!recurse &&
8026 12 : find_inheritance_children(RelationGetRelid(rel), lockmode))
8027 6 : ereport(ERROR,
8028 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
8029 : errmsg("ALTER TABLE / DROP EXPRESSION must be applied to child tables too")));
8030 :
8031 : /*
8032 : * Cannot drop generation expression from inherited columns.
8033 : */
8034 38 : if (!recursing)
8035 : {
8036 : HeapTuple tuple;
8037 : Form_pg_attribute attTup;
8038 :
8039 32 : tuple = SearchSysCacheCopyAttName(RelationGetRelid(rel), cmd->name);
8040 32 : if (!HeapTupleIsValid(tuple))
8041 0 : ereport(ERROR,
8042 : (errcode(ERRCODE_UNDEFINED_COLUMN),
8043 : errmsg("column \"%s\" of relation \"%s\" does not exist",
8044 : cmd->name, RelationGetRelationName(rel))));
8045 :
8046 32 : attTup = (Form_pg_attribute) GETSTRUCT(tuple);
8047 :
8048 32 : if (attTup->attinhcount > 0)
8049 6 : ereport(ERROR,
8050 : (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
8051 : errmsg("cannot drop generation expression from inherited column")));
8052 : }
8053 32 : }
8054 :
8055 : /*
8056 : * Return the address of the affected column.
8057 : */
8058 : static ObjectAddress
8059 32 : ATExecDropExpression(Relation rel, const char *colName, bool missing_ok, LOCKMODE lockmode)
8060 : {
8061 : HeapTuple tuple;
8062 : Form_pg_attribute attTup;
8063 : AttrNumber attnum;
8064 : Relation attrelation;
8065 : Oid attrdefoid;
8066 : ObjectAddress address;
8067 :
8068 32 : attrelation = table_open(AttributeRelationId, RowExclusiveLock);
8069 32 : tuple = SearchSysCacheCopyAttName(RelationGetRelid(rel), colName);
8070 32 : if (!HeapTupleIsValid(tuple))
8071 0 : ereport(ERROR,
8072 : (errcode(ERRCODE_UNDEFINED_COLUMN),
8073 : errmsg("column \"%s\" of relation \"%s\" does not exist",
8074 : colName, RelationGetRelationName(rel))));
8075 :
8076 32 : attTup = (Form_pg_attribute) GETSTRUCT(tuple);
8077 32 : attnum = attTup->attnum;
8078 :
8079 32 : if (attnum <= 0)
8080 0 : ereport(ERROR,
8081 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
8082 : errmsg("cannot alter system column \"%s\"",
8083 : colName)));
8084 :
8085 32 : if (attTup->attgenerated != ATTRIBUTE_GENERATED_STORED)
8086 : {
8087 12 : if (!missing_ok)
8088 6 : ereport(ERROR,
8089 : (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
8090 : errmsg("column \"%s\" of relation \"%s\" is not a stored generated column",
8091 : colName, RelationGetRelationName(rel))));
8092 : else
8093 : {
8094 6 : ereport(NOTICE,
8095 : (errmsg("column \"%s\" of relation \"%s\" is not a stored generated column, skipping",
8096 : colName, RelationGetRelationName(rel))));
8097 6 : heap_freetuple(tuple);
8098 6 : table_close(attrelation, RowExclusiveLock);
8099 6 : return InvalidObjectAddress;
8100 : }
8101 : }
8102 :
8103 : /*
8104 : * Mark the column as no longer generated. (The atthasdef flag needs to
8105 : * get cleared too, but RemoveAttrDefault will handle that.)
8106 : */
8107 20 : attTup->attgenerated = '\0';
8108 20 : CatalogTupleUpdate(attrelation, &tuple->t_self, tuple);
8109 :
8110 20 : InvokeObjectPostAlterHook(RelationRelationId,
8111 : RelationGetRelid(rel),
8112 : attnum);
8113 20 : heap_freetuple(tuple);
8114 :
8115 20 : table_close(attrelation, RowExclusiveLock);
8116 :
8117 : /*
8118 : * Drop the dependency records of the GENERATED expression, in particular
8119 : * its INTERNAL dependency on the column, which would otherwise cause
8120 : * dependency.c to refuse to perform the deletion.
8121 : */
8122 20 : attrdefoid = GetAttrDefaultOid(RelationGetRelid(rel), attnum);
8123 20 : if (!OidIsValid(attrdefoid))
8124 0 : elog(ERROR, "could not find attrdef tuple for relation %u attnum %d",
8125 : RelationGetRelid(rel), attnum);
8126 20 : (void) deleteDependencyRecordsFor(AttrDefaultRelationId, attrdefoid, false);
8127 :
8128 : /* Make above changes visible */
8129 20 : CommandCounterIncrement();
8130 :
8131 : /*
8132 : * Get rid of the GENERATED expression itself. We use RESTRICT here for
8133 : * safety, but at present we do not expect anything to depend on the
8134 : * default.
8135 : */
8136 20 : RemoveAttrDefault(RelationGetRelid(rel), attnum, DROP_RESTRICT,
8137 : false, false);
8138 :
8139 20 : ObjectAddressSubSet(address, RelationRelationId,
8140 : RelationGetRelid(rel), attnum);
8141 20 : return address;
8142 : }
8143 :
8144 : /*
8145 : * ALTER TABLE ALTER COLUMN SET STATISTICS
8146 : *
8147 : * Return value is the address of the modified column
8148 : */
8149 : static ObjectAddress
8150 164 : ATExecSetStatistics(Relation rel, const char *colName, int16 colNum, Node *newValue, LOCKMODE lockmode)
8151 : {
8152 : int newtarget;
8153 : Relation attrelation;
8154 : HeapTuple tuple;
8155 : Form_pg_attribute attrtuple;
8156 : AttrNumber attnum;
8157 : ObjectAddress address;
8158 :
8159 : /*
8160 : * We allow referencing columns by numbers only for indexes, since table
8161 : * column numbers could contain gaps if columns are later dropped.
8162 : */
8163 164 : if (rel->rd_rel->relkind != RELKIND_INDEX &&
8164 100 : rel->rd_rel->relkind != RELKIND_PARTITIONED_INDEX &&
8165 : !colName)
8166 0 : ereport(ERROR,
8167 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
8168 : errmsg("cannot refer to non-index column by number")));
8169 :
8170 : Assert(IsA(newValue, Integer));
8171 164 : newtarget = intVal(newValue);
8172 :
8173 : /*
8174 : * Limit target to a sane range
8175 : */
8176 164 : if (newtarget < -1)
8177 : {
8178 0 : ereport(ERROR,
8179 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
8180 : errmsg("statistics target %d is too low",
8181 : newtarget)));
8182 : }
8183 164 : else if (newtarget > 10000)
8184 : {
8185 0 : newtarget = 10000;
8186 0 : ereport(WARNING,
8187 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
8188 : errmsg("lowering statistics target to %d",
8189 : newtarget)));
8190 : }
8191 :
8192 164 : attrelation = table_open(AttributeRelationId, RowExclusiveLock);
8193 :
8194 164 : if (colName)
8195 : {
8196 100 : tuple = SearchSysCacheCopyAttName(RelationGetRelid(rel), colName);
8197 :
8198 100 : if (!HeapTupleIsValid(tuple))
8199 12 : ereport(ERROR,
8200 : (errcode(ERRCODE_UNDEFINED_COLUMN),
8201 : errmsg("column \"%s\" of relation \"%s\" does not exist",
8202 : colName, RelationGetRelationName(rel))));
8203 : }
8204 : else
8205 : {
8206 64 : tuple = SearchSysCacheCopyAttNum(RelationGetRelid(rel), colNum);
8207 :
8208 64 : if (!HeapTupleIsValid(tuple))
8209 12 : ereport(ERROR,
8210 : (errcode(ERRCODE_UNDEFINED_COLUMN),
8211 : errmsg("column number %d of relation \"%s\" does not exist",
8212 : colNum, RelationGetRelationName(rel))));
8213 : }
8214 :
8215 140 : attrtuple = (Form_pg_attribute) GETSTRUCT(tuple);
8216 :
8217 140 : attnum = attrtuple->attnum;
8218 140 : if (attnum <= 0)
8219 0 : ereport(ERROR,
8220 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
8221 : errmsg("cannot alter system column \"%s\"",
8222 : colName)));
8223 :
8224 140 : if (rel->rd_rel->relkind == RELKIND_INDEX ||
8225 88 : rel->rd_rel->relkind == RELKIND_PARTITIONED_INDEX)
8226 : {
8227 52 : if (attnum > rel->rd_index->indnkeyatts)
8228 6 : ereport(ERROR,
8229 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
8230 : errmsg("cannot alter statistics on included column \"%s\" of index \"%s\"",
8231 : NameStr(attrtuple->attname), RelationGetRelationName(rel))));
8232 46 : else if (rel->rd_index->indkey.values[attnum - 1] != 0)
8233 18 : ereport(ERROR,
8234 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
8235 : errmsg("cannot alter statistics on non-expression column \"%s\" of index \"%s\"",
8236 : NameStr(attrtuple->attname), RelationGetRelationName(rel)),
8237 : errhint("Alter statistics on table column instead.")));
8238 : }
8239 :
8240 116 : attrtuple->attstattarget = newtarget;
8241 :
8242 116 : CatalogTupleUpdate(attrelation, &tuple->t_self, tuple);
8243 :
8244 116 : InvokeObjectPostAlterHook(RelationRelationId,
8245 : RelationGetRelid(rel),
8246 : attrtuple->attnum);
8247 116 : ObjectAddressSubSet(address, RelationRelationId,
8248 : RelationGetRelid(rel), attnum);
8249 116 : heap_freetuple(tuple);
8250 :
8251 116 : table_close(attrelation, RowExclusiveLock);
8252 :
8253 116 : return address;
8254 : }
8255 :
8256 : /*
8257 : * Return value is the address of the modified column
8258 : */
8259 : static ObjectAddress
8260 32 : ATExecSetOptions(Relation rel, const char *colName, Node *options,
8261 : bool isReset, LOCKMODE lockmode)
8262 : {
8263 : Relation attrelation;
8264 : HeapTuple tuple,
8265 : newtuple;
8266 : Form_pg_attribute attrtuple;
8267 : AttrNumber attnum;
8268 : Datum datum,
8269 : newOptions;
8270 : bool isnull;
8271 : ObjectAddress address;
8272 : Datum repl_val[Natts_pg_attribute];
8273 : bool repl_null[Natts_pg_attribute];
8274 : bool repl_repl[Natts_pg_attribute];
8275 :
8276 32 : attrelation = table_open(AttributeRelationId, RowExclusiveLock);
8277 :
8278 32 : tuple = SearchSysCacheAttName(RelationGetRelid(rel), colName);
8279 :
8280 32 : if (!HeapTupleIsValid(tuple))
8281 0 : ereport(ERROR,
8282 : (errcode(ERRCODE_UNDEFINED_COLUMN),
8283 : errmsg("column \"%s\" of relation \"%s\" does not exist",
8284 : colName, RelationGetRelationName(rel))));
8285 32 : attrtuple = (Form_pg_attribute) GETSTRUCT(tuple);
8286 :
8287 32 : attnum = attrtuple->attnum;
8288 32 : if (attnum <= 0)
8289 0 : ereport(ERROR,
8290 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
8291 : errmsg("cannot alter system column \"%s\"",
8292 : colName)));
8293 :
8294 : /* Generate new proposed attoptions (text array) */
8295 32 : datum = SysCacheGetAttr(ATTNAME, tuple, Anum_pg_attribute_attoptions,
8296 : &isnull);
8297 32 : newOptions = transformRelOptions(isnull ? (Datum) 0 : datum,
8298 : castNode(List, options), NULL, NULL,
8299 : false, isReset);
8300 : /* Validate new options */
8301 32 : (void) attribute_reloptions(newOptions, true);
8302 :
8303 : /* Build new tuple. */
8304 32 : memset(repl_null, false, sizeof(repl_null));
8305 32 : memset(repl_repl, false, sizeof(repl_repl));
8306 32 : if (newOptions != (Datum) 0)
8307 32 : repl_val[Anum_pg_attribute_attoptions - 1] = newOptions;
8308 : else
8309 0 : repl_null[Anum_pg_attribute_attoptions - 1] = true;
8310 32 : repl_repl[Anum_pg_attribute_attoptions - 1] = true;
8311 32 : newtuple = heap_modify_tuple(tuple, RelationGetDescr(attrelation),
8312 : repl_val, repl_null, repl_repl);
8313 :
8314 : /* Update system catalog. */
8315 32 : CatalogTupleUpdate(attrelation, &newtuple->t_self, newtuple);
8316 :
8317 32 : InvokeObjectPostAlterHook(RelationRelationId,
8318 : RelationGetRelid(rel),
8319 : attrtuple->attnum);
8320 32 : ObjectAddressSubSet(address, RelationRelationId,
8321 : RelationGetRelid(rel), attnum);
8322 :
8323 32 : heap_freetuple(newtuple);
8324 :
8325 32 : ReleaseSysCache(tuple);
8326 :
8327 32 : table_close(attrelation, RowExclusiveLock);
8328 :
8329 32 : return address;
8330 : }
8331 :
8332 : /*
8333 : * Helper function for ATExecSetStorage and ATExecSetCompression
8334 : *
8335 : * Set the attstorage and/or attcompression fields for index columns
8336 : * associated with the specified table column.
8337 : */
8338 : static void
8339 278 : SetIndexStorageProperties(Relation rel, Relation attrelation,
8340 : AttrNumber attnum,
8341 : bool setstorage, char newstorage,
8342 : bool setcompression, char newcompression,
8343 : LOCKMODE lockmode)
8344 : {
8345 : ListCell *lc;
8346 :
8347 348 : foreach(lc, RelationGetIndexList(rel))
8348 : {
8349 70 : Oid indexoid = lfirst_oid(lc);
8350 : Relation indrel;
8351 70 : AttrNumber indattnum = 0;
8352 : HeapTuple tuple;
8353 :
8354 70 : indrel = index_open(indexoid, lockmode);
8355 :
8356 118 : for (int i = 0; i < indrel->rd_index->indnatts; i++)
8357 : {
8358 76 : if (indrel->rd_index->indkey.values[i] == attnum)
8359 : {
8360 28 : indattnum = i + 1;
8361 28 : break;
8362 : }
8363 : }
8364 :
8365 70 : if (indattnum == 0)
8366 : {
8367 42 : index_close(indrel, lockmode);
8368 42 : continue;
8369 : }
8370 :
8371 28 : tuple = SearchSysCacheCopyAttNum(RelationGetRelid(indrel), indattnum);
8372 :
8373 28 : if (HeapTupleIsValid(tuple))
8374 : {
8375 28 : Form_pg_attribute attrtuple = (Form_pg_attribute) GETSTRUCT(tuple);
8376 :
8377 28 : if (setstorage)
8378 22 : attrtuple->attstorage = newstorage;
8379 :
8380 28 : if (setcompression)
8381 6 : attrtuple->attcompression = newcompression;
8382 :
8383 28 : CatalogTupleUpdate(attrelation, &tuple->t_self, tuple);
8384 :
8385 28 : InvokeObjectPostAlterHook(RelationRelationId,
8386 : RelationGetRelid(rel),
8387 : attrtuple->attnum);
8388 :
8389 28 : heap_freetuple(tuple);
8390 : }
8391 :
8392 28 : index_close(indrel, lockmode);
8393 : }
8394 278 : }
8395 :
8396 : /*
8397 : * ALTER TABLE ALTER COLUMN SET STORAGE
8398 : *
8399 : * Return value is the address of the modified column
8400 : */
8401 : static ObjectAddress
8402 230 : ATExecSetStorage(Relation rel, const char *colName, Node *newValue, LOCKMODE lockmode)
8403 : {
8404 : Relation attrelation;
8405 : HeapTuple tuple;
8406 : Form_pg_attribute attrtuple;
8407 : AttrNumber attnum;
8408 : ObjectAddress address;
8409 :
8410 230 : attrelation = table_open(AttributeRelationId, RowExclusiveLock);
8411 :
8412 230 : tuple = SearchSysCacheCopyAttName(RelationGetRelid(rel), colName);
8413 :
8414 230 : if (!HeapTupleIsValid(tuple))
8415 12 : ereport(ERROR,
8416 : (errcode(ERRCODE_UNDEFINED_COLUMN),
8417 : errmsg("column \"%s\" of relation \"%s\" does not exist",
8418 : colName, RelationGetRelationName(rel))));
8419 218 : attrtuple = (Form_pg_attribute) GETSTRUCT(tuple);
8420 :
8421 218 : attnum = attrtuple->attnum;
8422 218 : if (attnum <= 0)
8423 0 : ereport(ERROR,
8424 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
8425 : errmsg("cannot alter system column \"%s\"",
8426 : colName)));
8427 :
8428 218 : attrtuple->attstorage = GetAttributeStorage(attrtuple->atttypid, strVal(newValue));
8429 :
8430 218 : CatalogTupleUpdate(attrelation, &tuple->t_self, tuple);
8431 :
8432 218 : InvokeObjectPostAlterHook(RelationRelationId,
8433 : RelationGetRelid(rel),
8434 : attrtuple->attnum);
8435 :
8436 : /*
8437 : * Apply the change to indexes as well (only for simple index columns,
8438 : * matching behavior of index.c ConstructTupleDescriptor()).
8439 : */
8440 218 : SetIndexStorageProperties(rel, attrelation, attnum,
8441 218 : true, attrtuple->attstorage,
8442 : false, 0,
8443 : lockmode);
8444 :
8445 218 : heap_freetuple(tuple);
8446 :
8447 218 : table_close(attrelation, RowExclusiveLock);
8448 :
8449 218 : ObjectAddressSubSet(address, RelationRelationId,
8450 : RelationGetRelid(rel), attnum);
8451 218 : return address;
8452 : }
8453 :
8454 :
8455 : /*
8456 : * ALTER TABLE DROP COLUMN
8457 : *
8458 : * DROP COLUMN cannot use the normal ALTER TABLE recursion mechanism,
8459 : * because we have to decide at runtime whether to recurse or not depending
8460 : * on whether attinhcount goes to zero or not. (We can't check this in a
8461 : * static pre-pass because it won't handle multiple inheritance situations
8462 : * correctly.)
8463 : */
8464 : static void
8465 1556 : ATPrepDropColumn(List **wqueue, Relation rel, bool recurse, bool recursing,
8466 : AlterTableCmd *cmd, LOCKMODE lockmode,
8467 : AlterTableUtilityContext *context)
8468 : {
8469 1556 : if (rel->rd_rel->reloftype && !recursing)
8470 6 : ereport(ERROR,
8471 : (errcode(ERRCODE_WRONG_OBJECT_TYPE),
8472 : errmsg("cannot drop column from typed table")));
8473 :
8474 1550 : if (rel->rd_rel->relkind == RELKIND_COMPOSITE_TYPE)
8475 82 : ATTypedTableRecursion(wqueue, rel, cmd, lockmode, context);
8476 :
8477 1544 : if (recurse)
8478 1276 : cmd->recurse = true;
8479 1544 : }
8480 :
8481 : /*
8482 : * Drops column 'colName' from relation 'rel' and returns the address of the
8483 : * dropped column. The column is also dropped (or marked as no longer
8484 : * inherited from relation) from the relation's inheritance children, if any.
8485 : *
8486 : * In the recursive invocations for inheritance child relations, instead of
8487 : * dropping the column directly (if to be dropped at all), its object address
8488 : * is added to 'addrs', which must be non-NULL in such invocations. All
8489 : * columns are dropped at the same time after all the children have been
8490 : * checked recursively.
8491 : */
8492 : static ObjectAddress
8493 2100 : ATExecDropColumn(List **wqueue, Relation rel, const char *colName,
8494 : DropBehavior behavior,
8495 : bool recurse, bool recursing,
8496 : bool missing_ok, LOCKMODE lockmode,
8497 : ObjectAddresses *addrs)
8498 : {
8499 : HeapTuple tuple;
8500 : Form_pg_attribute targetatt;
8501 : AttrNumber attnum;
8502 : List *children;
8503 : ObjectAddress object;
8504 : bool is_expr;
8505 :
8506 : /* At top level, permission check was done in ATPrepCmd, else do it */
8507 2100 : if (recursing)
8508 556 : ATSimplePermissions(AT_DropColumn, rel, ATT_TABLE | ATT_FOREIGN_TABLE);
8509 :
8510 : /* Initialize addrs on the first invocation */
8511 : Assert(!recursing || addrs != NULL);
8512 2100 : if (!recursing)
8513 1544 : addrs = new_object_addresses();
8514 :
8515 : /*
8516 : * get the number of the attribute
8517 : */
8518 2100 : tuple = SearchSysCacheAttName(RelationGetRelid(rel), colName);
8519 2100 : if (!HeapTupleIsValid(tuple))
8520 : {
8521 54 : if (!missing_ok)
8522 : {
8523 36 : ereport(ERROR,
8524 : (errcode(ERRCODE_UNDEFINED_COLUMN),
8525 : errmsg("column \"%s\" of relation \"%s\" does not exist",
8526 : colName, RelationGetRelationName(rel))));
8527 : }
8528 : else
8529 : {
8530 18 : ereport(NOTICE,
8531 : (errmsg("column \"%s\" of relation \"%s\" does not exist, skipping",
8532 : colName, RelationGetRelationName(rel))));
8533 18 : return InvalidObjectAddress;
8534 : }
8535 : }
8536 2046 : targetatt = (Form_pg_attribute) GETSTRUCT(tuple);
8537 :
8538 2046 : attnum = targetatt->attnum;
8539 :
8540 : /* Can't drop a system attribute */
8541 2046 : if (attnum <= 0)
8542 6 : ereport(ERROR,
8543 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
8544 : errmsg("cannot drop system column \"%s\"",
8545 : colName)));
8546 :
8547 : /*
8548 : * Don't drop inherited columns, unless recursing (presumably from a drop
8549 : * of the parent column)
8550 : */
8551 2040 : if (targetatt->attinhcount > 0 && !recursing)
8552 48 : ereport(ERROR,
8553 : (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
8554 : errmsg("cannot drop inherited column \"%s\"",
8555 : colName)));
8556 :
8557 : /*
8558 : * Don't drop columns used in the partition key, either. (If we let this
8559 : * go through, the key column's dependencies would cause a cascaded drop
8560 : * of the whole table, which is surely not what the user expected.)
8561 : */
8562 1992 : if (has_partition_attrs(rel,
8563 : bms_make_singleton(attnum - FirstLowInvalidHeapAttributeNumber),
8564 : &is_expr))
8565 30 : ereport(ERROR,
8566 : (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
8567 : errmsg("cannot drop column \"%s\" because it is part of the partition key of relation \"%s\"",
8568 : colName, RelationGetRelationName(rel))));
8569 :
8570 1962 : ReleaseSysCache(tuple);
8571 :
8572 : /*
8573 : * Propagate to children as appropriate. Unlike most other ALTER
8574 : * routines, we have to do this one level of recursion at a time; we can't
8575 : * use find_all_inheritors to do it in one pass.
8576 : */
8577 : children =
8578 1962 : find_inheritance_children(RelationGetRelid(rel), lockmode);
8579 :
8580 1962 : if (children)
8581 : {
8582 : Relation attr_rel;
8583 : ListCell *child;
8584 :
8585 : /*
8586 : * In case of a partitioned table, the column must be dropped from the
8587 : * partitions as well.
8588 : */
8589 302 : if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE && !recurse)
8590 6 : ereport(ERROR,
8591 : (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
8592 : errmsg("cannot drop column from only the partitioned table when partitions exist"),
8593 : errhint("Do not specify the ONLY keyword.")));
8594 :
8595 296 : attr_rel = table_open(AttributeRelationId, RowExclusiveLock);
8596 882 : foreach(child, children)
8597 : {
8598 592 : Oid childrelid = lfirst_oid(child);
8599 : Relation childrel;
8600 : Form_pg_attribute childatt;
8601 :
8602 : /* find_inheritance_children already got lock */
8603 592 : childrel = table_open(childrelid, NoLock);
8604 592 : CheckTableNotInUse(childrel, "ALTER TABLE");
8605 :
8606 592 : tuple = SearchSysCacheCopyAttName(childrelid, colName);
8607 592 : if (!HeapTupleIsValid(tuple)) /* shouldn't happen */
8608 0 : elog(ERROR, "cache lookup failed for attribute \"%s\" of relation %u",
8609 : colName, childrelid);
8610 592 : childatt = (Form_pg_attribute) GETSTRUCT(tuple);
8611 :
8612 592 : if (childatt->attinhcount <= 0) /* shouldn't happen */
8613 0 : elog(ERROR, "relation %u has non-inherited attribute \"%s\"",
8614 : childrelid, colName);
8615 :
8616 592 : if (recurse)
8617 : {
8618 : /*
8619 : * If the child column has other definition sources, just
8620 : * decrement its inheritance count; if not, recurse to delete
8621 : * it.
8622 : */
8623 568 : if (childatt->attinhcount == 1 && !childatt->attislocal)
8624 : {
8625 : /* Time to delete this child column, too */
8626 556 : ATExecDropColumn(wqueue, childrel, colName,
8627 : behavior, true, true,
8628 : false, lockmode, addrs);
8629 : }
8630 : else
8631 : {
8632 : /* Child column must survive my deletion */
8633 12 : childatt->attinhcount--;
8634 :
8635 12 : CatalogTupleUpdate(attr_rel, &tuple->t_self, tuple);
8636 :
8637 : /* Make update visible */
8638 12 : CommandCounterIncrement();
8639 : }
8640 : }
8641 : else
8642 : {
8643 : /*
8644 : * If we were told to drop ONLY in this table (no recursion),
8645 : * we need to mark the inheritors' attributes as locally
8646 : * defined rather than inherited.
8647 : */
8648 24 : childatt->attinhcount--;
8649 24 : childatt->attislocal = true;
8650 :
8651 24 : CatalogTupleUpdate(attr_rel, &tuple->t_self, tuple);
8652 :
8653 : /* Make update visible */
8654 24 : CommandCounterIncrement();
8655 : }
8656 :
8657 586 : heap_freetuple(tuple);
8658 :
8659 586 : table_close(childrel, NoLock);
8660 : }
8661 290 : table_close(attr_rel, RowExclusiveLock);
8662 : }
8663 :
8664 : /* Add object to delete */
8665 1950 : object.classId = RelationRelationId;
8666 1950 : object.objectId = RelationGetRelid(rel);
8667 1950 : object.objectSubId = attnum;
8668 1950 : add_exact_object_address(&object, addrs);
8669 :
8670 1950 : if (!recursing)
8671 : {
8672 : /* Recursion has ended, drop everything that was collected */
8673 1400 : performMultipleDeletions(addrs, behavior, 0);
8674 1358 : free_object_addresses(addrs);
8675 : }
8676 :
8677 1908 : return object;
8678 : }
8679 :
8680 : /*
8681 : * ALTER TABLE ADD INDEX
8682 : *
8683 |