00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #include "postgres.h"
00016
00017 #include "access/genam.h"
00018 #include "access/heapam.h"
00019 #include "access/heapam_xlog.h"
00020 #include "access/multixact.h"
00021 #include "access/reloptions.h"
00022 #include "access/relscan.h"
00023 #include "access/sysattr.h"
00024 #include "access/xact.h"
00025 #include "catalog/catalog.h"
00026 #include "catalog/dependency.h"
00027 #include "catalog/heap.h"
00028 #include "catalog/index.h"
00029 #include "catalog/indexing.h"
00030 #include "catalog/namespace.h"
00031 #include "catalog/objectaccess.h"
00032 #include "catalog/pg_collation.h"
00033 #include "catalog/pg_constraint.h"
00034 #include "catalog/pg_depend.h"
00035 #include "catalog/pg_foreign_table.h"
00036 #include "catalog/pg_inherits.h"
00037 #include "catalog/pg_inherits_fn.h"
00038 #include "catalog/pg_namespace.h"
00039 #include "catalog/pg_opclass.h"
00040 #include "catalog/pg_tablespace.h"
00041 #include "catalog/pg_trigger.h"
00042 #include "catalog/pg_type.h"
00043 #include "catalog/pg_type_fn.h"
00044 #include "catalog/storage.h"
00045 #include "catalog/toasting.h"
00046 #include "commands/cluster.h"
00047 #include "commands/comment.h"
00048 #include "commands/defrem.h"
00049 #include "commands/sequence.h"
00050 #include "commands/tablecmds.h"
00051 #include "commands/tablespace.h"
00052 #include "commands/trigger.h"
00053 #include "commands/typecmds.h"
00054 #include "common/relpath.h"
00055 #include "executor/executor.h"
00056 #include "foreign/foreign.h"
00057 #include "miscadmin.h"
00058 #include "nodes/makefuncs.h"
00059 #include "nodes/nodeFuncs.h"
00060 #include "nodes/parsenodes.h"
00061 #include "optimizer/clauses.h"
00062 #include "optimizer/planner.h"
00063 #include "parser/parse_clause.h"
00064 #include "parser/parse_coerce.h"
00065 #include "parser/parse_collate.h"
00066 #include "parser/parse_expr.h"
00067 #include "parser/parse_oper.h"
00068 #include "parser/parse_relation.h"
00069 #include "parser/parse_type.h"
00070 #include "parser/parse_utilcmd.h"
00071 #include "parser/parser.h"
00072 #include "rewrite/rewriteDefine.h"
00073 #include "rewrite/rewriteHandler.h"
00074 #include "rewrite/rewriteManip.h"
00075 #include "storage/bufmgr.h"
00076 #include "storage/lmgr.h"
00077 #include "storage/lock.h"
00078 #include "storage/predicate.h"
00079 #include "storage/smgr.h"
00080 #include "utils/acl.h"
00081 #include "utils/builtins.h"
00082 #include "utils/fmgroids.h"
00083 #include "utils/inval.h"
00084 #include "utils/lsyscache.h"
00085 #include "utils/memutils.h"
00086 #include "utils/relcache.h"
00087 #include "utils/snapmgr.h"
00088 #include "utils/syscache.h"
00089 #include "utils/tqual.h"
00090 #include "utils/typcache.h"
00091
00092
00093
00094
00095
00096 typedef struct OnCommitItem
00097 {
00098 Oid relid;
00099 OnCommitAction oncommit;
00100
00101
00102
00103
00104
00105
00106
00107
00108 SubTransactionId creating_subid;
00109 SubTransactionId deleting_subid;
00110 } OnCommitItem;
00111
00112 static List *on_commits = NIL;
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129 #define AT_PASS_DROP 0
00130 #define AT_PASS_ALTER_TYPE 1
00131 #define AT_PASS_OLD_INDEX 2
00132 #define AT_PASS_OLD_CONSTR 3
00133 #define AT_PASS_COL_ATTRS 4
00134
00135 #define AT_PASS_ADD_COL 5
00136 #define AT_PASS_ADD_INDEX 6
00137 #define AT_PASS_ADD_CONSTR 7
00138 #define AT_PASS_MISC 8
00139 #define AT_NUM_PASSES 9
00140
00141 typedef struct AlteredTableInfo
00142 {
00143
00144 Oid relid;
00145 char relkind;
00146 TupleDesc oldDesc;
00147
00148 List *subcmds[AT_NUM_PASSES];
00149
00150 List *constraints;
00151 List *newvals;
00152 bool new_notnull;
00153 bool rewrite;
00154 Oid newTableSpace;
00155
00156 List *changedConstraintOids;
00157 List *changedConstraintDefs;
00158 List *changedIndexOids;
00159 List *changedIndexDefs;
00160 } AlteredTableInfo;
00161
00162
00163
00164 typedef struct NewConstraint
00165 {
00166 char *name;
00167 ConstrType contype;
00168 Oid refrelid;
00169 Oid refindid;
00170 Oid conid;
00171 Node *qual;
00172 List *qualstate;
00173 } NewConstraint;
00174
00175
00176
00177
00178
00179
00180
00181
00182 typedef struct NewColumnValue
00183 {
00184 AttrNumber attnum;
00185 Expr *expr;
00186 ExprState *exprstate;
00187 } NewColumnValue;
00188
00189
00190
00191
00192 struct dropmsgstrings
00193 {
00194 char kind;
00195 int nonexistent_code;
00196 const char *nonexistent_msg;
00197 const char *skipping_msg;
00198 const char *nota_msg;
00199 const char *drophint_msg;
00200 };
00201
00202 static const struct dropmsgstrings dropmsgstringarray[] = {
00203 {RELKIND_RELATION,
00204 ERRCODE_UNDEFINED_TABLE,
00205 gettext_noop("table \"%s\" does not exist"),
00206 gettext_noop("table \"%s\" does not exist, skipping"),
00207 gettext_noop("\"%s\" is not a table"),
00208 gettext_noop("Use DROP TABLE to remove a table.")},
00209 {RELKIND_SEQUENCE,
00210 ERRCODE_UNDEFINED_TABLE,
00211 gettext_noop("sequence \"%s\" does not exist"),
00212 gettext_noop("sequence \"%s\" does not exist, skipping"),
00213 gettext_noop("\"%s\" is not a sequence"),
00214 gettext_noop("Use DROP SEQUENCE to remove a sequence.")},
00215 {RELKIND_VIEW,
00216 ERRCODE_UNDEFINED_TABLE,
00217 gettext_noop("view \"%s\" does not exist"),
00218 gettext_noop("view \"%s\" does not exist, skipping"),
00219 gettext_noop("\"%s\" is not a view"),
00220 gettext_noop("Use DROP VIEW to remove a view.")},
00221 {RELKIND_MATVIEW,
00222 ERRCODE_UNDEFINED_TABLE,
00223 gettext_noop("materialized view \"%s\" does not exist"),
00224 gettext_noop("materialized view \"%s\" does not exist, skipping"),
00225 gettext_noop("\"%s\" is not a materialized view"),
00226 gettext_noop("Use DROP MATERIALIZED VIEW to remove a materialized view.")},
00227 {RELKIND_INDEX,
00228 ERRCODE_UNDEFINED_OBJECT,
00229 gettext_noop("index \"%s\" does not exist"),
00230 gettext_noop("index \"%s\" does not exist, skipping"),
00231 gettext_noop("\"%s\" is not an index"),
00232 gettext_noop("Use DROP INDEX to remove an index.")},
00233 {RELKIND_COMPOSITE_TYPE,
00234 ERRCODE_UNDEFINED_OBJECT,
00235 gettext_noop("type \"%s\" does not exist"),
00236 gettext_noop("type \"%s\" does not exist, skipping"),
00237 gettext_noop("\"%s\" is not a type"),
00238 gettext_noop("Use DROP TYPE to remove a type.")},
00239 {RELKIND_FOREIGN_TABLE,
00240 ERRCODE_UNDEFINED_OBJECT,
00241 gettext_noop("foreign table \"%s\" does not exist"),
00242 gettext_noop("foreign table \"%s\" does not exist, skipping"),
00243 gettext_noop("\"%s\" is not a foreign table"),
00244 gettext_noop("Use DROP FOREIGN TABLE to remove a foreign table.")},
00245 {'\0', 0, NULL, NULL, NULL, NULL}
00246 };
00247
00248 struct DropRelationCallbackState
00249 {
00250 char relkind;
00251 Oid heapOid;
00252 bool concurrent;
00253 };
00254
00255
00256 #define ATT_TABLE 0x0001
00257 #define ATT_VIEW 0x0002
00258 #define ATT_MATVIEW 0x0004
00259 #define ATT_INDEX 0x0008
00260 #define ATT_COMPOSITE_TYPE 0x0010
00261 #define ATT_FOREIGN_TABLE 0x0020
00262
00263 static void truncate_check_rel(Relation rel);
00264 static List *MergeAttributes(List *schema, List *supers, char relpersistence,
00265 List **supOids, List **supconstr, int *supOidCount);
00266 static bool MergeCheckConstraint(List *constraints, char *name, Node *expr);
00267 static void MergeAttributesIntoExisting(Relation child_rel, Relation parent_rel);
00268 static void MergeConstraintsIntoExisting(Relation child_rel, Relation parent_rel);
00269 static void StoreCatalogInheritance(Oid relationId, List *supers);
00270 static void StoreCatalogInheritance1(Oid relationId, Oid parentOid,
00271 int16 seqNumber, Relation inhRelation);
00272 static int findAttrByName(const char *attributeName, List *schema);
00273 static void AlterIndexNamespaces(Relation classRel, Relation rel,
00274 Oid oldNspOid, Oid newNspOid, ObjectAddresses *objsMoved);
00275 static void AlterSeqNamespaces(Relation classRel, Relation rel,
00276 Oid oldNspOid, Oid newNspOid, ObjectAddresses *objsMoved,
00277 LOCKMODE lockmode);
00278 static void ATExecValidateConstraint(Relation rel, char *constrName,
00279 bool recurse, bool recursing, LOCKMODE lockmode);
00280 static int transformColumnNameList(Oid relId, List *colList,
00281 int16 *attnums, Oid *atttypids);
00282 static int transformFkeyGetPrimaryKey(Relation pkrel, Oid *indexOid,
00283 List **attnamelist,
00284 int16 *attnums, Oid *atttypids,
00285 Oid *opclasses);
00286 static Oid transformFkeyCheckAttrs(Relation pkrel,
00287 int numattrs, int16 *attnums,
00288 Oid *opclasses);
00289 static void checkFkeyPermissions(Relation rel, int16 *attnums, int natts);
00290 static CoercionPathType findFkeyCast(Oid targetTypeId, Oid sourceTypeId,
00291 Oid *funcid);
00292 static void validateCheckConstraint(Relation rel, HeapTuple constrtup);
00293 static void validateForeignKeyConstraint(char *conname,
00294 Relation rel, Relation pkrel,
00295 Oid pkindOid, Oid constraintOid);
00296 static void createForeignKeyTriggers(Relation rel, Constraint *fkconstraint,
00297 Oid constraintOid, Oid indexOid);
00298 static void ATController(Relation rel, List *cmds, bool recurse, LOCKMODE lockmode);
00299 static void ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd,
00300 bool recurse, bool recursing, LOCKMODE lockmode);
00301 static void ATRewriteCatalogs(List **wqueue, LOCKMODE lockmode);
00302 static void ATExecCmd(List **wqueue, AlteredTableInfo *tab, Relation rel,
00303 AlterTableCmd *cmd, LOCKMODE lockmode);
00304 static void ATRewriteTables(List **wqueue, LOCKMODE lockmode);
00305 static void ATRewriteTable(AlteredTableInfo *tab, Oid OIDNewHeap, LOCKMODE lockmode);
00306 static AlteredTableInfo *ATGetQueueEntry(List **wqueue, Relation rel);
00307 static void ATSimplePermissions(Relation rel, int allowed_targets);
00308 static void ATWrongRelkindError(Relation rel, int allowed_targets);
00309 static void ATSimpleRecursion(List **wqueue, Relation rel,
00310 AlterTableCmd *cmd, bool recurse, LOCKMODE lockmode);
00311 static void ATTypedTableRecursion(List **wqueue, Relation rel, AlterTableCmd *cmd,
00312 LOCKMODE lockmode);
00313 static List *find_typed_table_dependencies(Oid typeOid, const char *typeName,
00314 DropBehavior behavior);
00315 static void ATPrepAddColumn(List **wqueue, Relation rel, bool recurse, bool recursing,
00316 AlterTableCmd *cmd, LOCKMODE lockmode);
00317 static void ATExecAddColumn(List **wqueue, AlteredTableInfo *tab, Relation rel,
00318 ColumnDef *colDef, bool isOid,
00319 bool recurse, bool recursing, LOCKMODE lockmode);
00320 static void check_for_column_name_collision(Relation rel, const char *colname);
00321 static void add_column_datatype_dependency(Oid relid, int32 attnum, Oid typid);
00322 static void add_column_collation_dependency(Oid relid, int32 attnum, Oid collid);
00323 static void ATPrepAddOids(List **wqueue, Relation rel, bool recurse,
00324 AlterTableCmd *cmd, LOCKMODE lockmode);
00325 static void ATExecDropNotNull(Relation rel, const char *colName, LOCKMODE lockmode);
00326 static void ATExecSetNotNull(AlteredTableInfo *tab, Relation rel,
00327 const char *colName, LOCKMODE lockmode);
00328 static void ATExecColumnDefault(Relation rel, const char *colName,
00329 Node *newDefault, LOCKMODE lockmode);
00330 static void ATPrepSetStatistics(Relation rel, const char *colName,
00331 Node *newValue, LOCKMODE lockmode);
00332 static void ATExecSetStatistics(Relation rel, const char *colName,
00333 Node *newValue, LOCKMODE lockmode);
00334 static void ATExecSetOptions(Relation rel, const char *colName,
00335 Node *options, bool isReset, LOCKMODE lockmode);
00336 static void ATExecSetStorage(Relation rel, const char *colName,
00337 Node *newValue, LOCKMODE lockmode);
00338 static void ATPrepDropColumn(List **wqueue, Relation rel, bool recurse, bool recursing,
00339 AlterTableCmd *cmd, LOCKMODE lockmode);
00340 static void ATExecDropColumn(List **wqueue, Relation rel, const char *colName,
00341 DropBehavior behavior,
00342 bool recurse, bool recursing,
00343 bool missing_ok, LOCKMODE lockmode);
00344 static void ATExecAddIndex(AlteredTableInfo *tab, Relation rel,
00345 IndexStmt *stmt, bool is_rebuild, LOCKMODE lockmode);
00346 static void ATExecAddConstraint(List **wqueue,
00347 AlteredTableInfo *tab, Relation rel,
00348 Constraint *newConstraint, bool recurse, bool is_readd,
00349 LOCKMODE lockmode);
00350 static void ATExecAddIndexConstraint(AlteredTableInfo *tab, Relation rel,
00351 IndexStmt *stmt, LOCKMODE lockmode);
00352 static void ATAddCheckConstraint(List **wqueue,
00353 AlteredTableInfo *tab, Relation rel,
00354 Constraint *constr,
00355 bool recurse, bool recursing, bool is_readd,
00356 LOCKMODE lockmode);
00357 static void ATAddForeignKeyConstraint(AlteredTableInfo *tab, Relation rel,
00358 Constraint *fkconstraint, LOCKMODE lockmode);
00359 static void ATExecDropConstraint(Relation rel, const char *constrName,
00360 DropBehavior behavior,
00361 bool recurse, bool recursing,
00362 bool missing_ok, LOCKMODE lockmode);
00363 static void ATPrepAlterColumnType(List **wqueue,
00364 AlteredTableInfo *tab, Relation rel,
00365 bool recurse, bool recursing,
00366 AlterTableCmd *cmd, LOCKMODE lockmode);
00367 static bool ATColumnChangeRequiresRewrite(Node *expr, AttrNumber varattno);
00368 static void ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel,
00369 AlterTableCmd *cmd, LOCKMODE lockmode);
00370 static void ATExecAlterColumnGenericOptions(Relation rel, const char *colName,
00371 List *options, LOCKMODE lockmode);
00372 static void ATPostAlterTypeCleanup(List **wqueue, AlteredTableInfo *tab, LOCKMODE lockmode);
00373 static void ATPostAlterTypeParse(Oid oldId, char *cmd,
00374 List **wqueue, LOCKMODE lockmode, bool rewrite);
00375 static void TryReuseIndex(Oid oldId, IndexStmt *stmt);
00376 static void TryReuseForeignKey(Oid oldId, Constraint *con);
00377 static void change_owner_fix_column_acls(Oid relationOid,
00378 Oid oldOwnerId, Oid newOwnerId);
00379 static void change_owner_recurse_to_sequences(Oid relationOid,
00380 Oid newOwnerId, LOCKMODE lockmode);
00381 static void ATExecClusterOn(Relation rel, const char *indexName, LOCKMODE lockmode);
00382 static void ATExecDropCluster(Relation rel, LOCKMODE lockmode);
00383 static void ATPrepSetTableSpace(AlteredTableInfo *tab, Relation rel,
00384 char *tablespacename, LOCKMODE lockmode);
00385 static void ATExecSetTableSpace(Oid tableOid, Oid newTableSpace, LOCKMODE lockmode);
00386 static void ATExecSetRelOptions(Relation rel, List *defList,
00387 AlterTableType operation,
00388 LOCKMODE lockmode);
00389 static void ATExecEnableDisableTrigger(Relation rel, char *trigname,
00390 char fires_when, bool skip_system, LOCKMODE lockmode);
00391 static void ATExecEnableDisableRule(Relation rel, char *rulename,
00392 char fires_when, LOCKMODE lockmode);
00393 static void ATPrepAddInherit(Relation child_rel);
00394 static void ATExecAddInherit(Relation child_rel, RangeVar *parent, LOCKMODE lockmode);
00395 static void ATExecDropInherit(Relation rel, RangeVar *parent, LOCKMODE lockmode);
00396 static void drop_parent_dependency(Oid relid, Oid refclassid, Oid refobjid);
00397 static void ATExecAddOf(Relation rel, const TypeName *ofTypename, LOCKMODE lockmode);
00398 static void ATExecDropOf(Relation rel, LOCKMODE lockmode);
00399 static void ATExecGenericOptions(Relation rel, List *options);
00400
00401 static void copy_relation_data(SMgrRelation rel, SMgrRelation dst,
00402 ForkNumber forkNum, char relpersistence);
00403 static const char *storage_name(char c);
00404
00405 static void RangeVarCallbackForDropRelation(const RangeVar *rel, Oid relOid,
00406 Oid oldRelOid, void *arg);
00407 static void RangeVarCallbackForAlterRelation(const RangeVar *rv, Oid relid,
00408 Oid oldrelid, void *arg);
00409
00410
00411
00412
00413
00414
00415
00416
00417
00418
00419
00420
00421
00422
00423
00424
00425
00426
00427
00428 Oid
00429 DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId)
00430 {
00431 char relname[NAMEDATALEN];
00432 Oid namespaceId;
00433 List *schema = stmt->tableElts;
00434 Oid relationId;
00435 Oid tablespaceId;
00436 Relation rel;
00437 TupleDesc descriptor;
00438 List *inheritOids;
00439 List *old_constraints;
00440 bool localHasOids;
00441 int parentOidCount;
00442 List *rawDefaults;
00443 List *cookedDefaults;
00444 Datum reloptions;
00445 ListCell *listptr;
00446 AttrNumber attnum;
00447 static char *validnsps[] = HEAP_RELOPT_NAMESPACES;
00448 Oid ofTypeId;
00449
00450
00451
00452
00453
00454 StrNCpy(relname, stmt->relation->relname, NAMEDATALEN);
00455
00456
00457
00458
00459 if (stmt->oncommit != ONCOMMIT_NOOP
00460 && stmt->relation->relpersistence != RELPERSISTENCE_TEMP)
00461 ereport(ERROR,
00462 (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
00463 errmsg("ON COMMIT can only be used on temporary tables")));
00464 if (stmt->constraints != NIL && relkind == RELKIND_FOREIGN_TABLE)
00465 ereport(ERROR,
00466 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
00467 errmsg("constraints are not supported on foreign tables")));
00468
00469
00470
00471
00472
00473
00474
00475 namespaceId =
00476 RangeVarGetAndCheckCreationNamespace(stmt->relation, NoLock, NULL);
00477
00478
00479
00480
00481
00482
00483 if (stmt->relation->relpersistence == RELPERSISTENCE_TEMP
00484 && InSecurityRestrictedOperation())
00485 ereport(ERROR,
00486 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
00487 errmsg("cannot create temporary table within security-restricted operation")));
00488
00489
00490
00491
00492
00493 if (stmt->tablespacename)
00494 {
00495 tablespaceId = get_tablespace_oid(stmt->tablespacename, false);
00496 }
00497 else
00498 {
00499 tablespaceId = GetDefaultTablespace(stmt->relation->relpersistence);
00500
00501 }
00502
00503
00504 if (OidIsValid(tablespaceId) && tablespaceId != MyDatabaseTableSpace)
00505 {
00506 AclResult aclresult;
00507
00508 aclresult = pg_tablespace_aclcheck(tablespaceId, GetUserId(),
00509 ACL_CREATE);
00510 if (aclresult != ACLCHECK_OK)
00511 aclcheck_error(aclresult, ACL_KIND_TABLESPACE,
00512 get_tablespace_name(tablespaceId));
00513 }
00514
00515
00516 if (tablespaceId == GLOBALTABLESPACE_OID)
00517 ereport(ERROR,
00518 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
00519 errmsg("only shared relations can be placed in pg_global tablespace")));
00520
00521
00522 if (!OidIsValid(ownerId))
00523 ownerId = GetUserId();
00524
00525
00526
00527
00528 reloptions = transformRelOptions((Datum) 0, stmt->options, NULL, validnsps,
00529 true, false);
00530
00531 (void) heap_reloptions(relkind, reloptions, true);
00532
00533 if (stmt->ofTypename)
00534 {
00535 AclResult aclresult;
00536
00537 ofTypeId = typenameTypeId(NULL, stmt->ofTypename);
00538
00539 aclresult = pg_type_aclcheck(ofTypeId, GetUserId(), ACL_USAGE);
00540 if (aclresult != ACLCHECK_OK)
00541 aclcheck_error_type(aclresult, ofTypeId);
00542 }
00543 else
00544 ofTypeId = InvalidOid;
00545
00546
00547
00548
00549
00550 schema = MergeAttributes(schema, stmt->inhRelations,
00551 stmt->relation->relpersistence,
00552 &inheritOids, &old_constraints, &parentOidCount);
00553
00554
00555
00556
00557
00558
00559 descriptor = BuildDescForRelation(schema);
00560
00561 localHasOids = interpretOidsOption(stmt->options,
00562 (relkind == RELKIND_RELATION ||
00563 relkind == RELKIND_FOREIGN_TABLE));
00564 descriptor->tdhasoid = (localHasOids || parentOidCount > 0);
00565
00566
00567
00568
00569
00570
00571
00572
00573
00574
00575
00576
00577
00578 rawDefaults = NIL;
00579 cookedDefaults = NIL;
00580 attnum = 0;
00581
00582 foreach(listptr, schema)
00583 {
00584 ColumnDef *colDef = lfirst(listptr);
00585
00586 attnum++;
00587
00588 if (colDef->raw_default != NULL)
00589 {
00590 RawColumnDefault *rawEnt;
00591
00592 Assert(colDef->cooked_default == NULL);
00593
00594 rawEnt = (RawColumnDefault *) palloc(sizeof(RawColumnDefault));
00595 rawEnt->attnum = attnum;
00596 rawEnt->raw_default = colDef->raw_default;
00597 rawDefaults = lappend(rawDefaults, rawEnt);
00598 descriptor->attrs[attnum - 1]->atthasdef = true;
00599 }
00600 else if (colDef->cooked_default != NULL)
00601 {
00602 CookedConstraint *cooked;
00603
00604 cooked = (CookedConstraint *) palloc(sizeof(CookedConstraint));
00605 cooked->contype = CONSTR_DEFAULT;
00606 cooked->name = NULL;
00607 cooked->attnum = attnum;
00608 cooked->expr = colDef->cooked_default;
00609 cooked->skip_validation = false;
00610 cooked->is_local = true;
00611 cooked->inhcount = 0;
00612 cooked->is_no_inherit = false;
00613 cookedDefaults = lappend(cookedDefaults, cooked);
00614 descriptor->attrs[attnum - 1]->atthasdef = true;
00615 }
00616 }
00617
00618
00619
00620
00621
00622
00623 relationId = heap_create_with_catalog(relname,
00624 namespaceId,
00625 tablespaceId,
00626 InvalidOid,
00627 InvalidOid,
00628 ofTypeId,
00629 ownerId,
00630 descriptor,
00631 list_concat(cookedDefaults,
00632 old_constraints),
00633 relkind,
00634 stmt->relation->relpersistence,
00635 false,
00636 false,
00637 localHasOids,
00638 parentOidCount,
00639 stmt->oncommit,
00640 reloptions,
00641 true,
00642 allowSystemTableMods,
00643 false);
00644
00645
00646 StoreCatalogInheritance(relationId, inheritOids);
00647
00648
00649
00650
00651
00652 CommandCounterIncrement();
00653
00654
00655
00656
00657
00658
00659
00660 rel = relation_open(relationId, AccessExclusiveLock);
00661
00662
00663
00664
00665
00666
00667
00668
00669
00670
00671 if (rawDefaults || stmt->constraints)
00672 AddRelationNewConstraints(rel, rawDefaults, stmt->constraints,
00673 true, true, false);
00674
00675
00676
00677
00678
00679 relation_close(rel, NoLock);
00680
00681 return relationId;
00682 }
00683
00684
00685
00686
00687
00688 static void
00689 DropErrorMsgNonExistent(const char *relname, char rightkind, bool missing_ok)
00690 {
00691 const struct dropmsgstrings *rentry;
00692
00693 for (rentry = dropmsgstringarray; rentry->kind != '\0'; rentry++)
00694 {
00695 if (rentry->kind == rightkind)
00696 {
00697 if (!missing_ok)
00698 {
00699 ereport(ERROR,
00700 (errcode(rentry->nonexistent_code),
00701 errmsg(rentry->nonexistent_msg, relname)));
00702 }
00703 else
00704 {
00705 ereport(NOTICE, (errmsg(rentry->skipping_msg, relname)));
00706 break;
00707 }
00708 }
00709 }
00710
00711 Assert(rentry->kind != '\0');
00712 }
00713
00714
00715
00716
00717
00718 static void
00719 DropErrorMsgWrongType(const char *relname, char wrongkind, char rightkind)
00720 {
00721 const struct dropmsgstrings *rentry;
00722 const struct dropmsgstrings *wentry;
00723
00724 for (rentry = dropmsgstringarray; rentry->kind != '\0'; rentry++)
00725 if (rentry->kind == rightkind)
00726 break;
00727 Assert(rentry->kind != '\0');
00728
00729 for (wentry = dropmsgstringarray; wentry->kind != '\0'; wentry++)
00730 if (wentry->kind == wrongkind)
00731 break;
00732
00733
00734 ereport(ERROR,
00735 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
00736 errmsg(rentry->nota_msg, relname),
00737 (wentry->kind != '\0') ? errhint("%s", _(wentry->drophint_msg)) : 0));
00738 }
00739
00740
00741
00742
00743
00744
00745 void
00746 RemoveRelations(DropStmt *drop)
00747 {
00748 ObjectAddresses *objects;
00749 char relkind;
00750 ListCell *cell;
00751 int flags = 0;
00752 LOCKMODE lockmode = AccessExclusiveLock;
00753
00754
00755 if (drop->concurrent)
00756 {
00757 flags |= PERFORM_DELETION_CONCURRENTLY;
00758 lockmode = ShareUpdateExclusiveLock;
00759 Assert(drop->removeType == OBJECT_INDEX);
00760 if (list_length(drop->objects) != 1)
00761 ereport(ERROR,
00762 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
00763 errmsg("DROP INDEX CONCURRENTLY does not support dropping multiple objects")));
00764 if (drop->behavior == DROP_CASCADE)
00765 ereport(ERROR,
00766 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
00767 errmsg("DROP INDEX CONCURRENTLY does not support CASCADE")));
00768 }
00769
00770
00771
00772
00773
00774
00775
00776
00777 switch (drop->removeType)
00778 {
00779 case OBJECT_TABLE:
00780 relkind = RELKIND_RELATION;
00781 break;
00782
00783 case OBJECT_INDEX:
00784 relkind = RELKIND_INDEX;
00785 break;
00786
00787 case OBJECT_SEQUENCE:
00788 relkind = RELKIND_SEQUENCE;
00789 break;
00790
00791 case OBJECT_VIEW:
00792 relkind = RELKIND_VIEW;
00793 break;
00794
00795 case OBJECT_MATVIEW:
00796 relkind = RELKIND_MATVIEW;
00797 break;
00798
00799 case OBJECT_FOREIGN_TABLE:
00800 relkind = RELKIND_FOREIGN_TABLE;
00801 break;
00802
00803 default:
00804 elog(ERROR, "unrecognized drop object type: %d",
00805 (int) drop->removeType);
00806 relkind = 0;
00807 break;
00808 }
00809
00810
00811 objects = new_object_addresses();
00812
00813 foreach(cell, drop->objects)
00814 {
00815 RangeVar *rel = makeRangeVarFromNameList((List *) lfirst(cell));
00816 Oid relOid;
00817 ObjectAddress obj;
00818 struct DropRelationCallbackState state;
00819
00820
00821
00822
00823
00824
00825
00826
00827
00828
00829
00830 AcceptInvalidationMessages();
00831
00832
00833 state.relkind = relkind;
00834 state.heapOid = InvalidOid;
00835 state.concurrent = drop->concurrent;
00836 relOid = RangeVarGetRelidExtended(rel, lockmode, true,
00837 false,
00838 RangeVarCallbackForDropRelation,
00839 (void *) &state);
00840
00841
00842 if (!OidIsValid(relOid))
00843 {
00844 DropErrorMsgNonExistent(rel->relname, relkind, drop->missing_ok);
00845 continue;
00846 }
00847
00848
00849 obj.classId = RelationRelationId;
00850 obj.objectId = relOid;
00851 obj.objectSubId = 0;
00852
00853 add_exact_object_address(&obj, objects);
00854 }
00855
00856 performMultipleDeletions(objects, drop->behavior, flags);
00857
00858 free_object_addresses(objects);
00859 }
00860
00861
00862
00863
00864
00865 static void
00866 RangeVarCallbackForDropRelation(const RangeVar *rel, Oid relOid, Oid oldRelOid,
00867 void *arg)
00868 {
00869 HeapTuple tuple;
00870 struct DropRelationCallbackState *state;
00871 char relkind;
00872 Form_pg_class classform;
00873 LOCKMODE heap_lockmode;
00874
00875 state = (struct DropRelationCallbackState *) arg;
00876 relkind = state->relkind;
00877 heap_lockmode = state->concurrent ?
00878 ShareUpdateExclusiveLock : AccessExclusiveLock;
00879
00880
00881
00882
00883
00884
00885 if (relOid != oldRelOid && OidIsValid(state->heapOid))
00886 {
00887 UnlockRelationOid(state->heapOid, heap_lockmode);
00888 state->heapOid = InvalidOid;
00889 }
00890
00891
00892 if (!OidIsValid(relOid))
00893 return;
00894
00895 tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relOid));
00896 if (!HeapTupleIsValid(tuple))
00897 return;
00898 classform = (Form_pg_class) GETSTRUCT(tuple);
00899
00900 if (classform->relkind != relkind)
00901 DropErrorMsgWrongType(rel->relname, classform->relkind, relkind);
00902
00903
00904 if (!pg_class_ownercheck(relOid, GetUserId()) &&
00905 !pg_namespace_ownercheck(classform->relnamespace, GetUserId()))
00906 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS,
00907 rel->relname);
00908
00909 if (!allowSystemTableMods && IsSystemClass(classform))
00910 ereport(ERROR,
00911 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
00912 errmsg("permission denied: \"%s\" is a system catalog",
00913 rel->relname)));
00914
00915 ReleaseSysCache(tuple);
00916
00917
00918
00919
00920
00921
00922
00923
00924 if (relkind == RELKIND_INDEX && relOid != oldRelOid)
00925 {
00926 state->heapOid = IndexGetRelation(relOid, true);
00927 if (OidIsValid(state->heapOid))
00928 LockRelationOid(state->heapOid, heap_lockmode);
00929 }
00930 }
00931
00932
00933
00934
00935
00936
00937
00938
00939
00940
00941
00942
00943
00944 void
00945 ExecuteTruncate(TruncateStmt *stmt)
00946 {
00947 List *rels = NIL;
00948 List *relids = NIL;
00949 List *seq_relids = NIL;
00950 EState *estate;
00951 ResultRelInfo *resultRelInfos;
00952 ResultRelInfo *resultRelInfo;
00953 SubTransactionId mySubid;
00954 ListCell *cell;
00955
00956
00957
00958
00959 foreach(cell, stmt->relations)
00960 {
00961 RangeVar *rv = lfirst(cell);
00962 Relation rel;
00963 bool recurse = interpretInhOption(rv->inhOpt);
00964 Oid myrelid;
00965
00966 rel = heap_openrv(rv, AccessExclusiveLock);
00967 myrelid = RelationGetRelid(rel);
00968
00969 if (list_member_oid(relids, myrelid))
00970 {
00971 heap_close(rel, AccessExclusiveLock);
00972 continue;
00973 }
00974 truncate_check_rel(rel);
00975 rels = lappend(rels, rel);
00976 relids = lappend_oid(relids, myrelid);
00977
00978 if (recurse)
00979 {
00980 ListCell *child;
00981 List *children;
00982
00983 children = find_all_inheritors(myrelid, AccessExclusiveLock, NULL);
00984
00985 foreach(child, children)
00986 {
00987 Oid childrelid = lfirst_oid(child);
00988
00989 if (list_member_oid(relids, childrelid))
00990 continue;
00991
00992
00993 rel = heap_open(childrelid, NoLock);
00994 truncate_check_rel(rel);
00995 rels = lappend(rels, rel);
00996 relids = lappend_oid(relids, childrelid);
00997 }
00998 }
00999 }
01000
01001
01002
01003
01004
01005
01006
01007
01008
01009 if (stmt->behavior == DROP_CASCADE)
01010 {
01011 for (;;)
01012 {
01013 List *newrelids;
01014
01015 newrelids = heap_truncate_find_FKs(relids);
01016 if (newrelids == NIL)
01017 break;
01018
01019 foreach(cell, newrelids)
01020 {
01021 Oid relid = lfirst_oid(cell);
01022 Relation rel;
01023
01024 rel = heap_open(relid, AccessExclusiveLock);
01025 ereport(NOTICE,
01026 (errmsg("truncate cascades to table \"%s\"",
01027 RelationGetRelationName(rel))));
01028 truncate_check_rel(rel);
01029 rels = lappend(rels, rel);
01030 relids = lappend_oid(relids, relid);
01031 }
01032 }
01033 }
01034
01035
01036
01037
01038
01039
01040 #ifdef USE_ASSERT_CHECKING
01041 heap_truncate_check_FKs(rels, false);
01042 #else
01043 if (stmt->behavior == DROP_RESTRICT)
01044 heap_truncate_check_FKs(rels, false);
01045 #endif
01046
01047
01048
01049
01050
01051
01052
01053 if (stmt->restart_seqs)
01054 {
01055 foreach(cell, rels)
01056 {
01057 Relation rel = (Relation) lfirst(cell);
01058 List *seqlist = getOwnedSequences(RelationGetRelid(rel));
01059 ListCell *seqcell;
01060
01061 foreach(seqcell, seqlist)
01062 {
01063 Oid seq_relid = lfirst_oid(seqcell);
01064 Relation seq_rel;
01065
01066 seq_rel = relation_open(seq_relid, AccessExclusiveLock);
01067
01068
01069 if (!pg_class_ownercheck(seq_relid, GetUserId()))
01070 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS,
01071 RelationGetRelationName(seq_rel));
01072
01073 seq_relids = lappend_oid(seq_relids, seq_relid);
01074
01075 relation_close(seq_rel, NoLock);
01076 }
01077 }
01078 }
01079
01080
01081 AfterTriggerBeginQuery();
01082
01083
01084
01085
01086
01087 estate = CreateExecutorState();
01088 resultRelInfos = (ResultRelInfo *)
01089 palloc(list_length(rels) * sizeof(ResultRelInfo));
01090 resultRelInfo = resultRelInfos;
01091 foreach(cell, rels)
01092 {
01093 Relation rel = (Relation) lfirst(cell);
01094
01095 InitResultRelInfo(resultRelInfo,
01096 rel,
01097 0,
01098 0);
01099 resultRelInfo++;
01100 }
01101 estate->es_result_relations = resultRelInfos;
01102 estate->es_num_result_relations = list_length(rels);
01103
01104
01105
01106
01107
01108
01109
01110 resultRelInfo = resultRelInfos;
01111 foreach(cell, rels)
01112 {
01113 estate->es_result_relation_info = resultRelInfo;
01114 ExecBSTruncateTriggers(estate, resultRelInfo);
01115 resultRelInfo++;
01116 }
01117
01118
01119
01120
01121 mySubid = GetCurrentSubTransactionId();
01122
01123 foreach(cell, rels)
01124 {
01125 Relation rel = (Relation) lfirst(cell);
01126
01127
01128
01129
01130
01131
01132
01133
01134 if (rel->rd_createSubid == mySubid ||
01135 rel->rd_newRelfilenodeSubid == mySubid)
01136 {
01137
01138 heap_truncate_one_rel(rel);
01139 }
01140 else
01141 {
01142 Oid heap_relid;
01143 Oid toast_relid;
01144 MultiXactId minmulti;
01145
01146
01147
01148
01149
01150
01151
01152 CheckTableForSerializableConflictIn(rel);
01153
01154 minmulti = GetOldestMultiXactId();
01155
01156
01157
01158
01159
01160
01161
01162
01163 RelationSetNewRelfilenode(rel, RecentXmin, minmulti);
01164 if (rel->rd_rel->relpersistence == RELPERSISTENCE_UNLOGGED)
01165 heap_create_init_fork(rel);
01166
01167 heap_relid = RelationGetRelid(rel);
01168 toast_relid = rel->rd_rel->reltoastrelid;
01169
01170
01171
01172
01173 if (OidIsValid(toast_relid))
01174 {
01175 rel = relation_open(toast_relid, AccessExclusiveLock);
01176 RelationSetNewRelfilenode(rel, RecentXmin, minmulti);
01177 if (rel->rd_rel->relpersistence == RELPERSISTENCE_UNLOGGED)
01178 heap_create_init_fork(rel);
01179 heap_close(rel, NoLock);
01180 }
01181
01182
01183
01184
01185 reindex_relation(heap_relid, REINDEX_REL_PROCESS_TOAST);
01186 }
01187 }
01188
01189
01190
01191
01192 foreach(cell, seq_relids)
01193 {
01194 Oid seq_relid = lfirst_oid(cell);
01195
01196 ResetSequence(seq_relid);
01197 }
01198
01199
01200
01201
01202 resultRelInfo = resultRelInfos;
01203 foreach(cell, rels)
01204 {
01205 estate->es_result_relation_info = resultRelInfo;
01206 ExecASTruncateTriggers(estate, resultRelInfo);
01207 resultRelInfo++;
01208 }
01209
01210
01211 AfterTriggerEndQuery(estate);
01212
01213
01214 FreeExecutorState(estate);
01215
01216
01217 foreach(cell, rels)
01218 {
01219 Relation rel = (Relation) lfirst(cell);
01220
01221 heap_close(rel, NoLock);
01222 }
01223 }
01224
01225
01226
01227
01228 static void
01229 truncate_check_rel(Relation rel)
01230 {
01231 AclResult aclresult;
01232
01233
01234 if (rel->rd_rel->relkind != RELKIND_RELATION)
01235 ereport(ERROR,
01236 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
01237 errmsg("\"%s\" is not a table",
01238 RelationGetRelationName(rel))));
01239
01240
01241 aclresult = pg_class_aclcheck(RelationGetRelid(rel), GetUserId(),
01242 ACL_TRUNCATE);
01243 if (aclresult != ACLCHECK_OK)
01244 aclcheck_error(aclresult, ACL_KIND_CLASS,
01245 RelationGetRelationName(rel));
01246
01247 if (!allowSystemTableMods && IsSystemRelation(rel))
01248 ereport(ERROR,
01249 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
01250 errmsg("permission denied: \"%s\" is a system catalog",
01251 RelationGetRelationName(rel))));
01252
01253
01254
01255
01256
01257 if (RELATION_IS_OTHER_TEMP(rel))
01258 ereport(ERROR,
01259 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
01260 errmsg("cannot truncate temporary tables of other sessions")));
01261
01262
01263
01264
01265
01266 CheckTableNotInUse(rel, "TRUNCATE");
01267 }
01268
01269
01270
01271
01272
01273 static const char *
01274 storage_name(char c)
01275 {
01276 switch (c)
01277 {
01278 case 'p':
01279 return "PLAIN";
01280 case 'm':
01281 return "MAIN";
01282 case 'x':
01283 return "EXTENDED";
01284 case 'e':
01285 return "EXTERNAL";
01286 default:
01287 return "???";
01288 }
01289 }
01290
01291
01292
01293
01294
01295
01296
01297
01298
01299
01300
01301
01302
01303
01304
01305
01306
01307
01308
01309
01310
01311
01312
01313
01314
01315
01316
01317
01318
01319
01320
01321
01322
01323
01324
01325
01326
01327
01328
01329
01330
01331
01332
01333
01334
01335
01336
01337
01338
01339
01340
01341
01342
01343
01344
01345
01346
01347
01348
01349 static List *
01350 MergeAttributes(List *schema, List *supers, char relpersistence,
01351 List **supOids, List **supconstr, int *supOidCount)
01352 {
01353 ListCell *entry;
01354 List *inhSchema = NIL;
01355 List *parentOids = NIL;
01356 List *constraints = NIL;
01357 int parentsWithOids = 0;
01358 bool have_bogus_defaults = false;
01359 int child_attno;
01360 static Node bogus_marker = {0};
01361
01362
01363
01364
01365
01366
01367
01368
01369
01370
01371
01372
01373 if (list_length(schema) > MaxHeapAttributeNumber)
01374 ereport(ERROR,
01375 (errcode(ERRCODE_TOO_MANY_COLUMNS),
01376 errmsg("tables can have at most %d columns",
01377 MaxHeapAttributeNumber)));
01378
01379
01380
01381
01382
01383
01384
01385
01386 foreach(entry, schema)
01387 {
01388 ColumnDef *coldef = lfirst(entry);
01389 ListCell *rest = lnext(entry);
01390 ListCell *prev = entry;
01391
01392 if (coldef->typeName == NULL)
01393
01394
01395
01396
01397
01398
01399 ereport(ERROR,
01400 (errcode(ERRCODE_UNDEFINED_COLUMN),
01401 errmsg("column \"%s\" does not exist",
01402 coldef->colname)));
01403
01404 while (rest != NULL)
01405 {
01406 ColumnDef *restdef = lfirst(rest);
01407 ListCell *next = lnext(rest);
01408
01409
01410 if (strcmp(coldef->colname, restdef->colname) == 0)
01411 {
01412 if (coldef->is_from_type)
01413 {
01414
01415
01416
01417 coldef->is_not_null = restdef->is_not_null;
01418 coldef->raw_default = restdef->raw_default;
01419 coldef->cooked_default = restdef->cooked_default;
01420 coldef->constraints = restdef->constraints;
01421 coldef->is_from_type = false;
01422 list_delete_cell(schema, rest, prev);
01423 }
01424 else
01425 ereport(ERROR,
01426 (errcode(ERRCODE_DUPLICATE_COLUMN),
01427 errmsg("column \"%s\" specified more than once",
01428 coldef->colname)));
01429 }
01430 prev = rest;
01431 rest = next;
01432 }
01433 }
01434
01435
01436
01437
01438
01439
01440 child_attno = 0;
01441 foreach(entry, supers)
01442 {
01443 RangeVar *parent = (RangeVar *) lfirst(entry);
01444 Relation relation;
01445 TupleDesc tupleDesc;
01446 TupleConstr *constr;
01447 AttrNumber *newattno;
01448 AttrNumber parent_attno;
01449
01450
01451
01452
01453
01454
01455
01456
01457
01458
01459
01460 relation = heap_openrv(parent, ShareUpdateExclusiveLock);
01461
01462 if (relation->rd_rel->relkind != RELKIND_RELATION)
01463 ereport(ERROR,
01464 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
01465 errmsg("inherited relation \"%s\" is not a table",
01466 parent->relname)));
01467
01468 if (relpersistence != RELPERSISTENCE_TEMP &&
01469 relation->rd_rel->relpersistence == RELPERSISTENCE_TEMP)
01470 ereport(ERROR,
01471 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
01472 errmsg("cannot inherit from temporary relation \"%s\"",
01473 parent->relname)));
01474
01475
01476 if (relation->rd_rel->relpersistence == RELPERSISTENCE_TEMP &&
01477 !relation->rd_islocaltemp)
01478 ereport(ERROR,
01479 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
01480 errmsg("cannot inherit from temporary relation of another session")));
01481
01482
01483
01484
01485
01486 if (!pg_class_ownercheck(RelationGetRelid(relation), GetUserId()))
01487 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS,
01488 RelationGetRelationName(relation));
01489
01490
01491
01492
01493 if (list_member_oid(parentOids, RelationGetRelid(relation)))
01494 ereport(ERROR,
01495 (errcode(ERRCODE_DUPLICATE_TABLE),
01496 errmsg("relation \"%s\" would be inherited from more than once",
01497 parent->relname)));
01498
01499 parentOids = lappend_oid(parentOids, RelationGetRelid(relation));
01500
01501 if (relation->rd_rel->relhasoids)
01502 parentsWithOids++;
01503
01504 tupleDesc = RelationGetDescr(relation);
01505 constr = tupleDesc->constr;
01506
01507
01508
01509
01510
01511
01512 newattno = (AttrNumber *)
01513 palloc0(tupleDesc->natts * sizeof(AttrNumber));
01514
01515 for (parent_attno = 1; parent_attno <= tupleDesc->natts;
01516 parent_attno++)
01517 {
01518 Form_pg_attribute attribute = tupleDesc->attrs[parent_attno - 1];
01519 char *attributeName = NameStr(attribute->attname);
01520 int exist_attno;
01521 ColumnDef *def;
01522
01523
01524
01525
01526 if (attribute->attisdropped)
01527 continue;
01528
01529
01530
01531
01532 exist_attno = findAttrByName(attributeName, inhSchema);
01533 if (exist_attno > 0)
01534 {
01535 Oid defTypeId;
01536 int32 deftypmod;
01537 Oid defCollId;
01538
01539
01540
01541
01542
01543 ereport(NOTICE,
01544 (errmsg("merging multiple inherited definitions of column \"%s\"",
01545 attributeName)));
01546 def = (ColumnDef *) list_nth(inhSchema, exist_attno - 1);
01547 typenameTypeIdAndMod(NULL, def->typeName, &defTypeId, &deftypmod);
01548 if (defTypeId != attribute->atttypid ||
01549 deftypmod != attribute->atttypmod)
01550 ereport(ERROR,
01551 (errcode(ERRCODE_DATATYPE_MISMATCH),
01552 errmsg("inherited column \"%s\" has a type conflict",
01553 attributeName),
01554 errdetail("%s versus %s",
01555 TypeNameToString(def->typeName),
01556 format_type_be(attribute->atttypid))));
01557 defCollId = GetColumnDefCollation(NULL, def, defTypeId);
01558 if (defCollId != attribute->attcollation)
01559 ereport(ERROR,
01560 (errcode(ERRCODE_COLLATION_MISMATCH),
01561 errmsg("inherited column \"%s\" has a collation conflict",
01562 attributeName),
01563 errdetail("\"%s\" versus \"%s\"",
01564 get_collation_name(defCollId),
01565 get_collation_name(attribute->attcollation))));
01566
01567
01568 if (def->storage == 0)
01569 def->storage = attribute->attstorage;
01570 else if (def->storage != attribute->attstorage)
01571 ereport(ERROR,
01572 (errcode(ERRCODE_DATATYPE_MISMATCH),
01573 errmsg("inherited column \"%s\" has a storage parameter conflict",
01574 attributeName),
01575 errdetail("%s versus %s",
01576 storage_name(def->storage),
01577 storage_name(attribute->attstorage))));
01578
01579 def->inhcount++;
01580
01581 def->is_not_null |= attribute->attnotnull;
01582
01583 newattno[parent_attno - 1] = exist_attno;
01584 }
01585 else
01586 {
01587
01588
01589
01590 def = makeNode(ColumnDef);
01591 def->colname = pstrdup(attributeName);
01592 def->typeName = makeTypeNameFromOid(attribute->atttypid,
01593 attribute->atttypmod);
01594 def->inhcount = 1;
01595 def->is_local = false;
01596 def->is_not_null = attribute->attnotnull;
01597 def->is_from_type = false;
01598 def->storage = attribute->attstorage;
01599 def->raw_default = NULL;
01600 def->cooked_default = NULL;
01601 def->collClause = NULL;
01602 def->collOid = attribute->attcollation;
01603 def->constraints = NIL;
01604 inhSchema = lappend(inhSchema, def);
01605 newattno[parent_attno - 1] = ++child_attno;
01606 }
01607
01608
01609
01610
01611 if (attribute->atthasdef)
01612 {
01613 Node *this_default = NULL;
01614 AttrDefault *attrdef;
01615 int i;
01616
01617
01618 Assert(constr != NULL);
01619 attrdef = constr->defval;
01620 for (i = 0; i < constr->num_defval; i++)
01621 {
01622 if (attrdef[i].adnum == parent_attno)
01623 {
01624 this_default = stringToNode(attrdef[i].adbin);
01625 break;
01626 }
01627 }
01628 Assert(this_default != NULL);
01629
01630
01631
01632
01633
01634
01635
01636
01637
01638
01639
01640 Assert(def->raw_default == NULL);
01641 if (def->cooked_default == NULL)
01642 def->cooked_default = this_default;
01643 else if (!equal(def->cooked_default, this_default))
01644 {
01645 def->cooked_default = &bogus_marker;
01646 have_bogus_defaults = true;
01647 }
01648 }
01649 }
01650
01651
01652
01653
01654
01655
01656 if (constr && constr->num_check > 0)
01657 {
01658 ConstrCheck *check = constr->check;
01659 int i;
01660
01661 for (i = 0; i < constr->num_check; i++)
01662 {
01663 char *name = check[i].ccname;
01664 Node *expr;
01665 bool found_whole_row;
01666
01667
01668 if (check[i].ccnoinherit)
01669 continue;
01670
01671
01672 expr = map_variable_attnos(stringToNode(check[i].ccbin),
01673 1, 0,
01674 newattno, tupleDesc->natts,
01675 &found_whole_row);
01676
01677
01678
01679
01680
01681
01682 if (found_whole_row)
01683 ereport(ERROR,
01684 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
01685 errmsg("cannot convert whole-row table reference"),
01686 errdetail("Constraint \"%s\" contains a whole-row reference to table \"%s\".",
01687 name,
01688 RelationGetRelationName(relation))));
01689
01690
01691 if (!MergeCheckConstraint(constraints, name, expr))
01692 {
01693
01694 CookedConstraint *cooked;
01695
01696 cooked = (CookedConstraint *) palloc(sizeof(CookedConstraint));
01697 cooked->contype = CONSTR_CHECK;
01698 cooked->name = pstrdup(name);
01699 cooked->attnum = 0;
01700 cooked->expr = expr;
01701 cooked->skip_validation = false;
01702 cooked->is_local = false;
01703 cooked->inhcount = 1;
01704 cooked->is_no_inherit = false;
01705 constraints = lappend(constraints, cooked);
01706 }
01707 }
01708 }
01709
01710 pfree(newattno);
01711
01712
01713
01714
01715
01716
01717 heap_close(relation, NoLock);
01718 }
01719
01720
01721
01722
01723
01724
01725 if (inhSchema != NIL)
01726 {
01727 foreach(entry, schema)
01728 {
01729 ColumnDef *newdef = lfirst(entry);
01730 char *attributeName = newdef->colname;
01731 int exist_attno;
01732
01733
01734
01735
01736 exist_attno = findAttrByName(attributeName, inhSchema);
01737 if (exist_attno > 0)
01738 {
01739 ColumnDef *def;
01740 Oid defTypeId,
01741 newTypeId;
01742 int32 deftypmod,
01743 newtypmod;
01744 Oid defcollid,
01745 newcollid;
01746
01747
01748
01749
01750
01751 ereport(NOTICE,
01752 (errmsg("merging column \"%s\" with inherited definition",
01753 attributeName)));
01754 def = (ColumnDef *) list_nth(inhSchema, exist_attno - 1);
01755 typenameTypeIdAndMod(NULL, def->typeName, &defTypeId, &deftypmod);
01756 typenameTypeIdAndMod(NULL, newdef->typeName, &newTypeId, &newtypmod);
01757 if (defTypeId != newTypeId || deftypmod != newtypmod)
01758 ereport(ERROR,
01759 (errcode(ERRCODE_DATATYPE_MISMATCH),
01760 errmsg("column \"%s\" has a type conflict",
01761 attributeName),
01762 errdetail("%s versus %s",
01763 TypeNameToString(def->typeName),
01764 TypeNameToString(newdef->typeName))));
01765 defcollid = GetColumnDefCollation(NULL, def, defTypeId);
01766 newcollid = GetColumnDefCollation(NULL, newdef, newTypeId);
01767 if (defcollid != newcollid)
01768 ereport(ERROR,
01769 (errcode(ERRCODE_COLLATION_MISMATCH),
01770 errmsg("column \"%s\" has a collation conflict",
01771 attributeName),
01772 errdetail("\"%s\" versus \"%s\"",
01773 get_collation_name(defcollid),
01774 get_collation_name(newcollid))));
01775
01776
01777 if (def->storage == 0)
01778 def->storage = newdef->storage;
01779 else if (newdef->storage != 0 && def->storage != newdef->storage)
01780 ereport(ERROR,
01781 (errcode(ERRCODE_DATATYPE_MISMATCH),
01782 errmsg("column \"%s\" has a storage parameter conflict",
01783 attributeName),
01784 errdetail("%s versus %s",
01785 storage_name(def->storage),
01786 storage_name(newdef->storage))));
01787
01788
01789 def->is_local = true;
01790
01791 def->is_not_null |= newdef->is_not_null;
01792
01793 if (newdef->raw_default != NULL)
01794 {
01795 def->raw_default = newdef->raw_default;
01796 def->cooked_default = newdef->cooked_default;
01797 }
01798 }
01799 else
01800 {
01801
01802
01803
01804 inhSchema = lappend(inhSchema, newdef);
01805 }
01806 }
01807
01808 schema = inhSchema;
01809
01810
01811
01812
01813
01814 if (list_length(schema) > MaxHeapAttributeNumber)
01815 ereport(ERROR,
01816 (errcode(ERRCODE_TOO_MANY_COLUMNS),
01817 errmsg("tables can have at most %d columns",
01818 MaxHeapAttributeNumber)));
01819 }
01820
01821
01822
01823
01824
01825 if (have_bogus_defaults)
01826 {
01827 foreach(entry, schema)
01828 {
01829 ColumnDef *def = lfirst(entry);
01830
01831 if (def->cooked_default == &bogus_marker)
01832 ereport(ERROR,
01833 (errcode(ERRCODE_INVALID_COLUMN_DEFINITION),
01834 errmsg("column \"%s\" inherits conflicting default values",
01835 def->colname),
01836 errhint("To resolve the conflict, specify a default explicitly.")));
01837 }
01838 }
01839
01840 *supOids = parentOids;
01841 *supconstr = constraints;
01842 *supOidCount = parentsWithOids;
01843 return schema;
01844 }
01845
01846
01847
01848
01849
01850
01851
01852
01853
01854
01855
01856
01857
01858
01859 static bool
01860 MergeCheckConstraint(List *constraints, char *name, Node *expr)
01861 {
01862 ListCell *lc;
01863
01864 foreach(lc, constraints)
01865 {
01866 CookedConstraint *ccon = (CookedConstraint *) lfirst(lc);
01867
01868 Assert(ccon->contype == CONSTR_CHECK);
01869
01870
01871 if (strcmp(ccon->name, name) != 0)
01872 continue;
01873
01874 if (equal(expr, ccon->expr))
01875 {
01876
01877 ccon->inhcount++;
01878 return true;
01879 }
01880
01881 ereport(ERROR,
01882 (errcode(ERRCODE_DUPLICATE_OBJECT),
01883 errmsg("check constraint name \"%s\" appears multiple times but with different expressions",
01884 name)));
01885 }
01886
01887 return false;
01888 }
01889
01890
01891
01892
01893
01894
01895
01896
01897 static void
01898 StoreCatalogInheritance(Oid relationId, List *supers)
01899 {
01900 Relation relation;
01901 int16 seqNumber;
01902 ListCell *entry;
01903
01904
01905
01906
01907 AssertArg(OidIsValid(relationId));
01908
01909 if (supers == NIL)
01910 return;
01911
01912
01913
01914
01915
01916
01917
01918
01919
01920
01921 relation = heap_open(InheritsRelationId, RowExclusiveLock);
01922
01923 seqNumber = 1;
01924 foreach(entry, supers)
01925 {
01926 Oid parentOid = lfirst_oid(entry);
01927
01928 StoreCatalogInheritance1(relationId, parentOid, seqNumber, relation);
01929 seqNumber++;
01930 }
01931
01932 heap_close(relation, RowExclusiveLock);
01933 }
01934
01935
01936
01937
01938
01939 static void
01940 StoreCatalogInheritance1(Oid relationId, Oid parentOid,
01941 int16 seqNumber, Relation inhRelation)
01942 {
01943 TupleDesc desc = RelationGetDescr(inhRelation);
01944 Datum values[Natts_pg_inherits];
01945 bool nulls[Natts_pg_inherits];
01946 ObjectAddress childobject,
01947 parentobject;
01948 HeapTuple tuple;
01949
01950
01951
01952
01953 values[Anum_pg_inherits_inhrelid - 1] = ObjectIdGetDatum(relationId);
01954 values[Anum_pg_inherits_inhparent - 1] = ObjectIdGetDatum(parentOid);
01955 values[Anum_pg_inherits_inhseqno - 1] = Int16GetDatum(seqNumber);
01956
01957 memset(nulls, 0, sizeof(nulls));
01958
01959 tuple = heap_form_tuple(desc, values, nulls);
01960
01961 simple_heap_insert(inhRelation, tuple);
01962
01963 CatalogUpdateIndexes(inhRelation, tuple);
01964
01965 heap_freetuple(tuple);
01966
01967
01968
01969
01970 parentobject.classId = RelationRelationId;
01971 parentobject.objectId = parentOid;
01972 parentobject.objectSubId = 0;
01973 childobject.classId = RelationRelationId;
01974 childobject.objectId = relationId;
01975 childobject.objectSubId = 0;
01976
01977 recordDependencyOn(&childobject, &parentobject, DEPENDENCY_NORMAL);
01978
01979
01980
01981
01982
01983
01984 InvokeObjectPostAlterHookArg(InheritsRelationId,
01985 relationId, 0,
01986 parentOid, false);
01987
01988
01989
01990
01991 SetRelationHasSubclass(parentOid, true);
01992 }
01993
01994
01995
01996
01997
01998
01999
02000 static int
02001 findAttrByName(const char *attributeName, List *schema)
02002 {
02003 ListCell *s;
02004 int i = 1;
02005
02006 foreach(s, schema)
02007 {
02008 ColumnDef *def = lfirst(s);
02009
02010 if (strcmp(attributeName, def->colname) == 0)
02011 return i;
02012
02013 i++;
02014 }
02015 return 0;
02016 }
02017
02018
02019
02020
02021
02022
02023
02024
02025
02026
02027
02028
02029
02030
02031
02032 void
02033 SetRelationHasSubclass(Oid relationId, bool relhassubclass)
02034 {
02035 Relation relationRelation;
02036 HeapTuple tuple;
02037 Form_pg_class classtuple;
02038
02039
02040
02041
02042 relationRelation = heap_open(RelationRelationId, RowExclusiveLock);
02043 tuple = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relationId));
02044 if (!HeapTupleIsValid(tuple))
02045 elog(ERROR, "cache lookup failed for relation %u", relationId);
02046 classtuple = (Form_pg_class) GETSTRUCT(tuple);
02047
02048 if (classtuple->relhassubclass != relhassubclass)
02049 {
02050 classtuple->relhassubclass = relhassubclass;
02051 simple_heap_update(relationRelation, &tuple->t_self, tuple);
02052
02053
02054 CatalogUpdateIndexes(relationRelation, tuple);
02055 }
02056 else
02057 {
02058
02059 CacheInvalidateRelcacheByTuple(tuple);
02060 }
02061
02062 heap_freetuple(tuple);
02063 heap_close(relationRelation, RowExclusiveLock);
02064 }
02065
02066
02067
02068
02069 static void
02070 renameatt_check(Oid myrelid, Form_pg_class classform, bool recursing)
02071 {
02072 char relkind = classform->relkind;
02073
02074 if (classform->reloftype && !recursing)
02075 ereport(ERROR,
02076 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
02077 errmsg("cannot rename column of typed table")));
02078
02079
02080
02081
02082
02083
02084
02085
02086 if (relkind != RELKIND_RELATION &&
02087 relkind != RELKIND_VIEW &&
02088 relkind != RELKIND_MATVIEW &&
02089 relkind != RELKIND_COMPOSITE_TYPE &&
02090 relkind != RELKIND_INDEX &&
02091 relkind != RELKIND_FOREIGN_TABLE)
02092 ereport(ERROR,
02093 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
02094 errmsg("\"%s\" is not a table, view, materialized view, composite type, index, or foreign table",
02095 NameStr(classform->relname))));
02096
02097
02098
02099
02100 if (!pg_class_ownercheck(myrelid, GetUserId()))
02101 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS,
02102 NameStr(classform->relname));
02103 if (!allowSystemTableMods && IsSystemClass(classform))
02104 ereport(ERROR,
02105 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
02106 errmsg("permission denied: \"%s\" is a system catalog",
02107 NameStr(classform->relname))));
02108 }
02109
02110
02111
02112
02113 static void
02114 renameatt_internal(Oid myrelid,
02115 const char *oldattname,
02116 const char *newattname,
02117 bool recurse,
02118 bool recursing,
02119 int expected_parents,
02120 DropBehavior behavior)
02121 {
02122 Relation targetrelation;
02123 Relation attrelation;
02124 HeapTuple atttup;
02125 Form_pg_attribute attform;
02126 int attnum;
02127
02128
02129
02130
02131
02132 targetrelation = relation_open(myrelid, AccessExclusiveLock);
02133 renameatt_check(myrelid, RelationGetForm(targetrelation), recursing);
02134
02135
02136
02137
02138
02139
02140
02141
02142
02143 if (recurse)
02144 {
02145 List *child_oids,
02146 *child_numparents;
02147 ListCell *lo,
02148 *li;
02149
02150
02151
02152
02153
02154
02155 child_oids = find_all_inheritors(myrelid, AccessExclusiveLock,
02156 &child_numparents);
02157
02158
02159
02160
02161
02162
02163 forboth(lo, child_oids, li, child_numparents)
02164 {
02165 Oid childrelid = lfirst_oid(lo);
02166 int numparents = lfirst_int(li);
02167
02168 if (childrelid == myrelid)
02169 continue;
02170
02171 renameatt_internal(childrelid, oldattname, newattname, false, true, numparents, behavior);
02172 }
02173 }
02174 else
02175 {
02176
02177
02178
02179
02180
02181
02182 if (expected_parents == 0 &&
02183 find_inheritance_children(myrelid, NoLock) != NIL)
02184 ereport(ERROR,
02185 (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
02186 errmsg("inherited column \"%s\" must be renamed in child tables too",
02187 oldattname)));
02188 }
02189
02190
02191 if (targetrelation->rd_rel->relkind == RELKIND_COMPOSITE_TYPE)
02192 {
02193 List *child_oids;
02194 ListCell *lo;
02195
02196 child_oids = find_typed_table_dependencies(targetrelation->rd_rel->reltype,
02197 RelationGetRelationName(targetrelation),
02198 behavior);
02199
02200 foreach(lo, child_oids)
02201 renameatt_internal(lfirst_oid(lo), oldattname, newattname, true, true, 0, behavior);
02202 }
02203
02204 attrelation = heap_open(AttributeRelationId, RowExclusiveLock);
02205
02206 atttup = SearchSysCacheCopyAttName(myrelid, oldattname);
02207 if (!HeapTupleIsValid(atttup))
02208 ereport(ERROR,
02209 (errcode(ERRCODE_UNDEFINED_COLUMN),
02210 errmsg("column \"%s\" does not exist",
02211 oldattname)));
02212 attform = (Form_pg_attribute) GETSTRUCT(atttup);
02213
02214 attnum = attform->attnum;
02215 if (attnum <= 0)
02216 ereport(ERROR,
02217 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
02218 errmsg("cannot rename system column \"%s\"",
02219 oldattname)));
02220
02221
02222
02223
02224
02225
02226
02227
02228
02229
02230 if (attform->attinhcount > expected_parents)
02231 ereport(ERROR,
02232 (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
02233 errmsg("cannot rename inherited column \"%s\"",
02234 oldattname)));
02235
02236
02237 check_for_column_name_collision(targetrelation, newattname);
02238
02239
02240 namestrcpy(&(attform->attname), newattname);
02241
02242 simple_heap_update(attrelation, &atttup->t_self, atttup);
02243
02244
02245 CatalogUpdateIndexes(attrelation, atttup);
02246
02247 InvokeObjectPostAlterHook(RelationRelationId, myrelid, attnum);
02248
02249 heap_freetuple(atttup);
02250
02251 heap_close(attrelation, RowExclusiveLock);
02252
02253 relation_close(targetrelation, NoLock);
02254 }
02255
02256
02257
02258
02259 static void
02260 RangeVarCallbackForRenameAttribute(const RangeVar *rv, Oid relid, Oid oldrelid,
02261 void *arg)
02262 {
02263 HeapTuple tuple;
02264 Form_pg_class form;
02265
02266 tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
02267 if (!HeapTupleIsValid(tuple))
02268 return;
02269 form = (Form_pg_class) GETSTRUCT(tuple);
02270 renameatt_check(relid, form, false);
02271 ReleaseSysCache(tuple);
02272 }
02273
02274
02275
02276
02277 Oid
02278 renameatt(RenameStmt *stmt)
02279 {
02280 Oid relid;
02281
02282
02283 relid = RangeVarGetRelidExtended(stmt->relation, AccessExclusiveLock,
02284 stmt->missing_ok, false,
02285 RangeVarCallbackForRenameAttribute,
02286 NULL);
02287
02288 if (!OidIsValid(relid))
02289 {
02290 ereport(NOTICE,
02291 (errmsg("relation \"%s\" does not exist, skipping",
02292 stmt->relation->relname)));
02293 return InvalidOid;
02294 }
02295
02296 renameatt_internal(relid,
02297 stmt->subname,
02298 stmt->newname,
02299 interpretInhOption(stmt->relation->inhOpt),
02300 false,
02301 0,
02302 stmt->behavior);
02303
02304
02305 return relid;
02306 }
02307
02308
02309
02310
02311
02312 static Oid
02313 rename_constraint_internal(Oid myrelid,
02314 Oid mytypid,
02315 const char *oldconname,
02316 const char *newconname,
02317 bool recurse,
02318 bool recursing,
02319 int expected_parents)
02320 {
02321 Relation targetrelation = NULL;
02322 Oid constraintOid;
02323 HeapTuple tuple;
02324 Form_pg_constraint con;
02325
02326 AssertArg(!myrelid || !mytypid);
02327
02328 if (mytypid)
02329 {
02330 constraintOid = get_domain_constraint_oid(mytypid, oldconname, false);
02331 }
02332 else
02333 {
02334 targetrelation = relation_open(myrelid, AccessExclusiveLock);
02335
02336
02337
02338
02339
02340 renameatt_check(myrelid, RelationGetForm(targetrelation), false);
02341
02342 constraintOid = get_relation_constraint_oid(myrelid, oldconname, false);
02343 }
02344
02345 tuple = SearchSysCache1(CONSTROID, ObjectIdGetDatum(constraintOid));
02346 if (!HeapTupleIsValid(tuple))
02347 elog(ERROR, "cache lookup failed for constraint %u",
02348 constraintOid);
02349 con = (Form_pg_constraint) GETSTRUCT(tuple);
02350
02351 if (myrelid && con->contype == CONSTRAINT_CHECK && !con->connoinherit)
02352 {
02353 if (recurse)
02354 {
02355 List *child_oids,
02356 *child_numparents;
02357 ListCell *lo,
02358 *li;
02359
02360 child_oids = find_all_inheritors(myrelid, AccessExclusiveLock,
02361 &child_numparents);
02362
02363 forboth(lo, child_oids, li, child_numparents)
02364 {
02365 Oid childrelid = lfirst_oid(lo);
02366 int numparents = lfirst_int(li);
02367
02368 if (childrelid == myrelid)
02369 continue;
02370
02371 rename_constraint_internal(childrelid, InvalidOid, oldconname, newconname, false, true, numparents);
02372 }
02373 }
02374 else
02375 {
02376 if (expected_parents == 0 &&
02377 find_inheritance_children(myrelid, NoLock) != NIL)
02378 ereport(ERROR,
02379 (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
02380 errmsg("inherited constraint \"%s\" must be renamed in child tables too",
02381 oldconname)));
02382 }
02383
02384 if (con->coninhcount > expected_parents)
02385 ereport(ERROR,
02386 (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
02387 errmsg("cannot rename inherited constraint \"%s\"",
02388 oldconname)));
02389 }
02390
02391 if (con->conindid
02392 && (con->contype == CONSTRAINT_PRIMARY
02393 || con->contype == CONSTRAINT_UNIQUE
02394 || con->contype == CONSTRAINT_EXCLUSION))
02395
02396 RenameRelationInternal(con->conindid, newconname, false);
02397 else
02398 RenameConstraintById(constraintOid, newconname);
02399
02400 ReleaseSysCache(tuple);
02401
02402 if (targetrelation)
02403 relation_close(targetrelation, NoLock);
02404
02405 return constraintOid;
02406 }
02407
02408 Oid
02409 RenameConstraint(RenameStmt *stmt)
02410 {
02411 Oid relid = InvalidOid;
02412 Oid typid = InvalidOid;
02413
02414 if (stmt->relationType == OBJECT_DOMAIN)
02415 {
02416 Relation rel;
02417 HeapTuple tup;
02418
02419 typid = typenameTypeId(NULL, makeTypeNameFromNameList(stmt->object));
02420 rel = heap_open(TypeRelationId, RowExclusiveLock);
02421 tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
02422 if (!HeapTupleIsValid(tup))
02423 elog(ERROR, "cache lookup failed for type %u", typid);
02424 checkDomainOwner(tup);
02425 ReleaseSysCache(tup);
02426 heap_close(rel, NoLock);
02427 }
02428 else
02429 {
02430
02431 relid = RangeVarGetRelidExtended(stmt->relation, AccessExclusiveLock,
02432 false, false,
02433 RangeVarCallbackForRenameAttribute,
02434 NULL);
02435 }
02436
02437 return
02438 rename_constraint_internal(relid, typid,
02439 stmt->subname,
02440 stmt->newname,
02441 stmt->relation ? interpretInhOption(stmt->relation->inhOpt) : false,
02442 false,
02443 0 );
02444
02445 }
02446
02447
02448
02449
02450 Oid
02451 RenameRelation(RenameStmt *stmt)
02452 {
02453 Oid relid;
02454
02455
02456
02457
02458
02459
02460
02461
02462 relid = RangeVarGetRelidExtended(stmt->relation, AccessExclusiveLock,
02463 stmt->missing_ok, false,
02464 RangeVarCallbackForAlterRelation,
02465 (void *) stmt);
02466
02467 if (!OidIsValid(relid))
02468 {
02469 ereport(NOTICE,
02470 (errmsg("relation \"%s\" does not exist, skipping",
02471 stmt->relation->relname)));
02472 return InvalidOid;
02473 }
02474
02475
02476 RenameRelationInternal(relid, stmt->newname, false);
02477
02478 return relid;
02479 }
02480
02481
02482
02483
02484
02485
02486
02487
02488
02489
02490 void
02491 RenameRelationInternal(Oid myrelid, const char *newrelname, bool is_internal)
02492 {
02493 Relation targetrelation;
02494 Relation relrelation;
02495 HeapTuple reltup;
02496 Form_pg_class relform;
02497 Oid namespaceId;
02498
02499
02500
02501
02502
02503 targetrelation = relation_open(myrelid, AccessExclusiveLock);
02504 namespaceId = RelationGetNamespace(targetrelation);
02505
02506
02507
02508
02509 relrelation = heap_open(RelationRelationId, RowExclusiveLock);
02510
02511 reltup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(myrelid));
02512 if (!HeapTupleIsValid(reltup))
02513 elog(ERROR, "cache lookup failed for relation %u", myrelid);
02514 relform = (Form_pg_class) GETSTRUCT(reltup);
02515
02516 if (get_relname_relid(newrelname, namespaceId) != InvalidOid)
02517 ereport(ERROR,
02518 (errcode(ERRCODE_DUPLICATE_TABLE),
02519 errmsg("relation \"%s\" already exists",
02520 newrelname)));
02521
02522
02523
02524
02525
02526 namestrcpy(&(relform->relname), newrelname);
02527
02528 simple_heap_update(relrelation, &reltup->t_self, reltup);
02529
02530
02531 CatalogUpdateIndexes(relrelation, reltup);
02532
02533 InvokeObjectPostAlterHookArg(RelationRelationId, myrelid, 0,
02534 InvalidOid, is_internal);
02535
02536 heap_freetuple(reltup);
02537 heap_close(relrelation, RowExclusiveLock);
02538
02539
02540
02541
02542 if (OidIsValid(targetrelation->rd_rel->reltype))
02543 RenameTypeInternal(targetrelation->rd_rel->reltype,
02544 newrelname, namespaceId);
02545
02546
02547
02548
02549 if (targetrelation->rd_rel->relkind == RELKIND_INDEX)
02550 {
02551 Oid constraintId = get_index_constraint(myrelid);
02552
02553 if (OidIsValid(constraintId))
02554 RenameConstraintById(constraintId, newrelname);
02555 }
02556
02557
02558
02559
02560 relation_close(targetrelation, NoLock);
02561 }
02562
02563
02564
02565
02566
02567
02568
02569
02570
02571
02572
02573
02574
02575
02576
02577
02578
02579
02580
02581
02582
02583
02584
02585
02586
02587
02588 void
02589 CheckTableNotInUse(Relation rel, const char *stmt)
02590 {
02591 int expected_refcnt;
02592
02593 expected_refcnt = rel->rd_isnailed ? 2 : 1;
02594 if (rel->rd_refcnt != expected_refcnt)
02595 ereport(ERROR,
02596 (errcode(ERRCODE_OBJECT_IN_USE),
02597
02598 errmsg("cannot %s \"%s\" because "
02599 "it is being used by active queries in this session",
02600 stmt, RelationGetRelationName(rel))));
02601
02602 if (rel->rd_rel->relkind != RELKIND_INDEX &&
02603 AfterTriggerPendingOnRel(RelationGetRelid(rel)))
02604 ereport(ERROR,
02605 (errcode(ERRCODE_OBJECT_IN_USE),
02606
02607 errmsg("cannot %s \"%s\" because "
02608 "it has pending trigger events",
02609 stmt, RelationGetRelationName(rel))));
02610 }
02611
02612
02613
02614
02615
02616
02617 Oid
02618 AlterTableLookupRelation(AlterTableStmt *stmt, LOCKMODE lockmode)
02619 {
02620 return RangeVarGetRelidExtended(stmt->relation, lockmode, stmt->missing_ok, false,
02621 RangeVarCallbackForAlterRelation,
02622 (void *) stmt);
02623 }
02624
02625
02626
02627
02628
02629
02630
02631
02632
02633
02634
02635
02636
02637
02638
02639
02640
02641
02642
02643
02644
02645
02646
02647
02648
02649
02650
02651
02652
02653
02654
02655
02656
02657
02658
02659
02660
02661
02662
02663
02664
02665
02666
02667
02668
02669 void
02670 AlterTable(Oid relid, LOCKMODE lockmode, AlterTableStmt *stmt)
02671 {
02672 Relation rel;
02673
02674
02675 rel = relation_open(relid, NoLock);
02676
02677 CheckTableNotInUse(rel, "ALTER TABLE");
02678
02679 ATController(rel, stmt->cmds, interpretInhOption(stmt->relation->inhOpt),
02680 lockmode);
02681 }
02682
02683
02684
02685
02686
02687
02688
02689
02690
02691
02692
02693
02694 void
02695 AlterTableInternal(Oid relid, List *cmds, bool recurse)
02696 {
02697 Relation rel;
02698 LOCKMODE lockmode = AlterTableGetLockLevel(cmds);
02699
02700 rel = relation_open(relid, lockmode);
02701
02702 ATController(rel, cmds, recurse, lockmode);
02703 }
02704
02705
02706
02707
02708
02709
02710
02711
02712
02713
02714
02715
02716
02717
02718
02719
02720
02721
02722
02723
02724
02725
02726 LOCKMODE
02727 AlterTableGetLockLevel(List *cmds)
02728 {
02729
02730
02731
02732
02733
02734
02735
02736
02737
02738
02739
02740
02741
02742
02743
02744
02745
02746
02747
02748
02749
02750
02751
02752
02753 #ifdef REDUCED_ALTER_TABLE_LOCK_LEVELS
02754 ListCell *lcmd;
02755 LOCKMODE lockmode = ShareUpdateExclusiveLock;
02756
02757 foreach(lcmd, cmds)
02758 {
02759 AlterTableCmd *cmd = (AlterTableCmd *) lfirst(lcmd);
02760 LOCKMODE cmd_lockmode = AccessExclusiveLock;
02761
02762 switch (cmd->subtype)
02763 {
02764
02765
02766
02767
02768
02769
02770
02771 case AT_AddColumn:
02772
02773 case AT_DropColumn:
02774 case AT_AddColumnToView:
02775 case AT_AlterColumnType:
02776 case AT_DropConstraint:
02777 case AT_AddOids:
02778 case AT_DropOids:
02779 case AT_EnableAlwaysRule:
02780 case AT_EnableReplicaRule:
02781 case AT_EnableRule:
02782 case AT_DisableRule:
02783 case AT_ChangeOwner:
02784 case AT_SetTableSpace:
02785 case AT_DropNotNull:
02786 case AT_SetNotNull:
02787 case AT_GenericOptions:
02788 case AT_AlterColumnGenericOptions:
02789 cmd_lockmode = AccessExclusiveLock;
02790 break;
02791
02792
02793
02794
02795 case AT_ColumnDefault:
02796 case AT_ProcessedConstraint:
02797 case AT_AddConstraintRecurse:
02798 case AT_ReAddConstraint:
02799 case AT_EnableTrig:
02800 case AT_EnableAlwaysTrig:
02801 case AT_EnableReplicaTrig:
02802 case AT_EnableTrigAll:
02803 case AT_EnableTrigUser:
02804 case AT_DisableTrig:
02805 case AT_DisableTrigAll:
02806 case AT_DisableTrigUser:
02807 case AT_AddIndex:
02808 case AT_AddIndexConstraint:
02809 cmd_lockmode = ShareRowExclusiveLock;
02810 break;
02811
02812 case AT_AddConstraint:
02813 if (IsA(cmd->def, Constraint))
02814 {
02815 Constraint *con = (Constraint *) cmd->def;
02816
02817 switch (con->contype)
02818 {
02819 case CONSTR_EXCLUSION:
02820 case CONSTR_PRIMARY:
02821 case CONSTR_UNIQUE:
02822
02823
02824
02825
02826
02827
02828
02829 cmd_lockmode = ShareRowExclusiveLock;
02830 break;
02831 case CONSTR_FOREIGN:
02832
02833
02834
02835
02836
02837
02838 cmd_lockmode = ShareRowExclusiveLock;
02839 break;
02840
02841 default:
02842 cmd_lockmode = ShareRowExclusiveLock;
02843 }
02844 }
02845 break;
02846
02847
02848
02849
02850
02851
02852
02853
02854 case AT_AddInherit:
02855 case AT_DropInherit:
02856 cmd_lockmode = ShareUpdateExclusiveLock;
02857 break;
02858
02859
02860
02861
02862
02863
02864
02865
02866 case AT_AddOf:
02867 case AT_DropOf:
02868 cmd_lockmode = ShareUpdateExclusiveLock;
02869
02870
02871
02872
02873
02874
02875
02876
02877
02878
02879
02880 case AT_SetStatistics:
02881 case AT_ClusterOn:
02882 case AT_DropCluster:
02883 case AT_SetRelOptions:
02884 case AT_ResetRelOptions:
02885 case AT_ReplaceRelOptions:
02886 case AT_SetOptions:
02887 case AT_ResetOptions:
02888 case AT_SetStorage:
02889 case AT_ValidateConstraint:
02890 cmd_lockmode = ShareUpdateExclusiveLock;
02891 break;
02892
02893 default:
02894 elog(ERROR, "unrecognized alter table type: %d",
02895 (int) cmd->subtype);
02896 break;
02897 }
02898
02899
02900
02901
02902 if (cmd_lockmode > lockmode)
02903 lockmode = cmd_lockmode;
02904 }
02905 #else
02906 LOCKMODE lockmode = AccessExclusiveLock;
02907 #endif
02908
02909 return lockmode;
02910 }
02911
02912 static void
02913 ATController(Relation rel, List *cmds, bool recurse, LOCKMODE lockmode)
02914 {
02915 List *wqueue = NIL;
02916 ListCell *lcmd;
02917
02918
02919 foreach(lcmd, cmds)
02920 {
02921 AlterTableCmd *cmd = (AlterTableCmd *) lfirst(lcmd);
02922
02923 ATPrepCmd(&wqueue, rel, cmd, recurse, false, lockmode);
02924 }
02925
02926
02927 relation_close(rel, NoLock);
02928
02929
02930 ATRewriteCatalogs(&wqueue, lockmode);
02931
02932
02933 ATRewriteTables(&wqueue, lockmode);
02934 }
02935
02936
02937
02938
02939
02940
02941
02942
02943
02944
02945 static void
02946 ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd,
02947 bool recurse, bool recursing, LOCKMODE lockmode)
02948 {
02949 AlteredTableInfo *tab;
02950 int pass;
02951
02952
02953 tab = ATGetQueueEntry(wqueue, rel);
02954
02955
02956
02957
02958
02959
02960
02961 cmd = copyObject(cmd);
02962
02963
02964
02965
02966
02967 switch (cmd->subtype)
02968 {
02969 case AT_AddColumn:
02970 ATSimplePermissions(rel,
02971 ATT_TABLE | ATT_COMPOSITE_TYPE | ATT_FOREIGN_TABLE);
02972 ATPrepAddColumn(wqueue, rel, recurse, recursing, cmd, lockmode);
02973
02974 pass = AT_PASS_ADD_COL;
02975 break;
02976 case AT_AddColumnToView:
02977
02978 ATSimplePermissions(rel, ATT_VIEW);
02979 ATPrepAddColumn(wqueue, rel, recurse, recursing, cmd, lockmode);
02980
02981 pass = AT_PASS_ADD_COL;
02982 break;
02983 case AT_ColumnDefault:
02984
02985
02986
02987
02988
02989
02990
02991 ATSimplePermissions(rel, ATT_TABLE | ATT_VIEW | ATT_FOREIGN_TABLE);
02992 ATSimpleRecursion(wqueue, rel, cmd, recurse, lockmode);
02993
02994 pass = cmd->def ? AT_PASS_ADD_CONSTR : AT_PASS_DROP;
02995 break;
02996 case AT_DropNotNull:
02997 ATSimplePermissions(rel, ATT_TABLE | ATT_FOREIGN_TABLE);
02998 ATSimpleRecursion(wqueue, rel, cmd, recurse, lockmode);
02999
03000 pass = AT_PASS_DROP;
03001 break;
03002 case AT_SetNotNull:
03003 ATSimplePermissions(rel, ATT_TABLE | ATT_FOREIGN_TABLE);
03004 ATSimpleRecursion(wqueue, rel, cmd, recurse, lockmode);
03005
03006 pass = AT_PASS_ADD_CONSTR;
03007 break;
03008 case AT_SetStatistics:
03009 ATSimpleRecursion(wqueue, rel, cmd, recurse, lockmode);
03010
03011 ATPrepSetStatistics(rel, cmd->name, cmd->def, lockmode);
03012 pass = AT_PASS_MISC;
03013 break;
03014 case AT_SetOptions:
03015 case AT_ResetOptions:
03016 ATSimplePermissions(rel, ATT_TABLE | ATT_MATVIEW | ATT_INDEX | ATT_FOREIGN_TABLE);
03017
03018 pass = AT_PASS_MISC;
03019 break;
03020 case AT_SetStorage:
03021 ATSimplePermissions(rel, ATT_TABLE | ATT_MATVIEW);
03022 ATSimpleRecursion(wqueue, rel, cmd, recurse, lockmode);
03023
03024 pass = AT_PASS_MISC;
03025 break;
03026 case AT_DropColumn:
03027 ATSimplePermissions(rel,
03028 ATT_TABLE | ATT_COMPOSITE_TYPE | ATT_FOREIGN_TABLE);
03029 ATPrepDropColumn(wqueue, rel, recurse, recursing, cmd, lockmode);
03030
03031 pass = AT_PASS_DROP;
03032 break;
03033 case AT_AddIndex:
03034 ATSimplePermissions(rel, ATT_TABLE | ATT_MATVIEW);
03035
03036
03037 pass = AT_PASS_ADD_INDEX;
03038 break;
03039 case AT_AddConstraint:
03040 ATSimplePermissions(rel, ATT_TABLE);
03041
03042
03043 if (recurse)
03044 cmd->subtype = AT_AddConstraintRecurse;
03045 pass = AT_PASS_ADD_CONSTR;
03046 break;
03047 case AT_AddIndexConstraint:
03048 ATSimplePermissions(rel, ATT_TABLE);
03049
03050
03051 pass = AT_PASS_ADD_CONSTR;
03052 break;
03053 case AT_DropConstraint:
03054 ATSimplePermissions(rel, ATT_TABLE);
03055
03056
03057 if (recurse)
03058 cmd->subtype = AT_DropConstraintRecurse;
03059 pass = AT_PASS_DROP;
03060 break;
03061 case AT_AlterColumnType:
03062 ATSimplePermissions(rel,
03063 ATT_TABLE | ATT_COMPOSITE_TYPE | ATT_FOREIGN_TABLE);
03064
03065 ATPrepAlterColumnType(wqueue, tab, rel, recurse, recursing, cmd, lockmode);
03066 pass = AT_PASS_ALTER_TYPE;
03067 break;
03068 case AT_AlterColumnGenericOptions:
03069 ATSimplePermissions(rel, ATT_FOREIGN_TABLE);
03070
03071
03072 pass = AT_PASS_MISC;
03073 break;
03074 case AT_ChangeOwner:
03075
03076
03077 pass = AT_PASS_MISC;
03078 break;
03079 case AT_ClusterOn:
03080 case AT_DropCluster:
03081 ATSimplePermissions(rel, ATT_TABLE | ATT_MATVIEW);
03082
03083
03084 pass = AT_PASS_MISC;
03085 break;
03086 case AT_AddOids:
03087 ATSimplePermissions(rel, ATT_TABLE);
03088 if (!rel->rd_rel->relhasoids || recursing)
03089 ATPrepAddOids(wqueue, rel, recurse, cmd, lockmode);
03090
03091 pass = AT_PASS_ADD_COL;
03092 break;
03093 case AT_DropOids:
03094 ATSimplePermissions(rel, ATT_TABLE);
03095
03096 if (rel->rd_rel->relhasoids)
03097 {
03098 AlterTableCmd *dropCmd = makeNode(AlterTableCmd);
03099
03100 dropCmd->subtype = AT_DropColumn;
03101 dropCmd->name = pstrdup("oid");
03102 dropCmd->behavior = cmd->behavior;
03103 ATPrepCmd(wqueue, rel, dropCmd, recurse, false, lockmode);
03104 }
03105 pass = AT_PASS_DROP;
03106 break;
03107 case AT_SetTableSpace:
03108 ATSimplePermissions(rel, ATT_TABLE | ATT_MATVIEW | ATT_INDEX);
03109
03110 ATPrepSetTableSpace(tab, rel, cmd->name, lockmode);
03111 pass = AT_PASS_MISC;
03112 break;
03113 case AT_SetRelOptions:
03114 case AT_ResetRelOptions:
03115 case AT_ReplaceRelOptions:
03116 ATSimplePermissions(rel, ATT_TABLE | ATT_VIEW | ATT_MATVIEW | ATT_INDEX);
03117
03118
03119 pass = AT_PASS_MISC;
03120 break;
03121 case AT_AddInherit:
03122 ATSimplePermissions(rel, ATT_TABLE);
03123
03124 ATPrepAddInherit(rel);
03125 pass = AT_PASS_MISC;
03126 break;
03127 case AT_ValidateConstraint:
03128 ATSimplePermissions(rel, ATT_TABLE);
03129
03130
03131 if (recurse)
03132 cmd->subtype = AT_ValidateConstraintRecurse;
03133 pass = AT_PASS_MISC;
03134 break;
03135 case AT_EnableTrig:
03136 case AT_EnableAlwaysTrig:
03137 case AT_EnableReplicaTrig:
03138 case AT_EnableTrigAll:
03139 case AT_EnableTrigUser:
03140 case AT_DisableTrig:
03141 case AT_DisableTrigAll:
03142 case AT_DisableTrigUser:
03143 case AT_EnableRule:
03144 case AT_EnableAlwaysRule:
03145 case AT_EnableReplicaRule:
03146 case AT_DisableRule:
03147 case AT_DropInherit:
03148 case AT_AddOf:
03149 case AT_DropOf:
03150 ATSimplePermissions(rel, ATT_TABLE);
03151
03152
03153 pass = AT_PASS_MISC;
03154 break;
03155 case AT_GenericOptions:
03156 ATSimplePermissions(rel, ATT_FOREIGN_TABLE);
03157
03158 pass = AT_PASS_MISC;
03159 break;
03160 default:
03161 elog(ERROR, "unrecognized alter table type: %d",
03162 (int) cmd->subtype);
03163 pass = 0;
03164 break;
03165 }
03166
03167
03168 tab->subcmds[pass] = lappend(tab->subcmds[pass], cmd);
03169 }
03170
03171
03172
03173
03174
03175
03176
03177
03178 static void
03179 ATRewriteCatalogs(List **wqueue, LOCKMODE lockmode)
03180 {
03181 int pass;
03182 ListCell *ltab;
03183
03184
03185
03186
03187
03188
03189
03190
03191 for (pass = 0; pass < AT_NUM_PASSES; pass++)
03192 {
03193
03194 foreach(ltab, *wqueue)
03195 {
03196 AlteredTableInfo *tab = (AlteredTableInfo *) lfirst(ltab);
03197 List *subcmds = tab->subcmds[pass];
03198 Relation rel;
03199 ListCell *lcmd;
03200
03201 if (subcmds == NIL)
03202 continue;
03203
03204
03205
03206
03207 rel = relation_open(tab->relid, NoLock);
03208
03209 foreach(lcmd, subcmds)
03210 ATExecCmd(wqueue, tab, rel, (AlterTableCmd *) lfirst(lcmd), lockmode);
03211
03212
03213
03214
03215
03216
03217 if (pass == AT_PASS_ALTER_TYPE)
03218 ATPostAlterTypeCleanup(wqueue, tab, lockmode);
03219
03220 relation_close(rel, NoLock);
03221 }
03222 }
03223
03224
03225 foreach(ltab, *wqueue)
03226 {
03227 AlteredTableInfo *tab = (AlteredTableInfo *) lfirst(ltab);
03228
03229 if (tab->relkind == RELKIND_RELATION ||
03230 tab->relkind == RELKIND_MATVIEW)
03231 AlterTableCreateToastTable(tab->relid, (Datum) 0);
03232 }
03233 }
03234
03235
03236
03237
03238 static void
03239 ATExecCmd(List **wqueue, AlteredTableInfo *tab, Relation rel,
03240 AlterTableCmd *cmd, LOCKMODE lockmode)
03241 {
03242 switch (cmd->subtype)
03243 {
03244 case AT_AddColumn:
03245 case AT_AddColumnToView:
03246
03247 ATExecAddColumn(wqueue, tab, rel, (ColumnDef *) cmd->def,
03248 false, false, false, lockmode);
03249 break;
03250 case AT_AddColumnRecurse:
03251 ATExecAddColumn(wqueue, tab, rel, (ColumnDef *) cmd->def,
03252 false, true, false, lockmode);
03253 break;
03254 case AT_ColumnDefault:
03255 ATExecColumnDefault(rel, cmd->name, cmd->def, lockmode);
03256 break;
03257 case AT_DropNotNull:
03258 ATExecDropNotNull(rel, cmd->name, lockmode);
03259 break;
03260 case AT_SetNotNull:
03261 ATExecSetNotNull(tab, rel, cmd->name, lockmode);
03262 break;
03263 case AT_SetStatistics:
03264 ATExecSetStatistics(rel, cmd->name, cmd->def, lockmode);
03265 break;
03266 case AT_SetOptions:
03267 ATExecSetOptions(rel, cmd->name, cmd->def, false, lockmode);
03268 break;
03269 case AT_ResetOptions:
03270 ATExecSetOptions(rel, cmd->name, cmd->def, true, lockmode);
03271 break;
03272 case AT_SetStorage:
03273 ATExecSetStorage(rel, cmd->name, cmd->def, lockmode);
03274 break;
03275 case AT_DropColumn:
03276 ATExecDropColumn(wqueue, rel, cmd->name,
03277 cmd->behavior, false, false, cmd->missing_ok, lockmode);
03278 break;
03279 case AT_DropColumnRecurse:
03280 ATExecDropColumn(wqueue, rel, cmd->name,
03281 cmd->behavior, true, false, cmd->missing_ok, lockmode);
03282 break;
03283 case AT_AddIndex:
03284 ATExecAddIndex(tab, rel, (IndexStmt *) cmd->def, false, lockmode);
03285 break;
03286 case AT_ReAddIndex:
03287 ATExecAddIndex(tab, rel, (IndexStmt *) cmd->def, true, lockmode);
03288 break;
03289 case AT_AddConstraint:
03290 ATExecAddConstraint(wqueue, tab, rel, (Constraint *) cmd->def,
03291 false, false, lockmode);
03292 break;
03293 case AT_AddConstraintRecurse:
03294 ATExecAddConstraint(wqueue, tab, rel, (Constraint *) cmd->def,
03295 true, false, lockmode);
03296 break;
03297 case AT_ReAddConstraint:
03298 ATExecAddConstraint(wqueue, tab, rel, (Constraint *) cmd->def,
03299 false, true, lockmode);
03300 break;
03301 case AT_AddIndexConstraint:
03302 ATExecAddIndexConstraint(tab, rel, (IndexStmt *) cmd->def, lockmode);
03303 break;
03304 case AT_ValidateConstraint:
03305 ATExecValidateConstraint(rel, cmd->name, false, false, lockmode);
03306 break;
03307 case AT_ValidateConstraintRecurse:
03308
03309 ATExecValidateConstraint(rel, cmd->name, true, false, lockmode);
03310 break;
03311 case AT_DropConstraint:
03312 ATExecDropConstraint(rel, cmd->name, cmd->behavior,
03313 false, false,
03314 cmd->missing_ok, lockmode);
03315 break;
03316 case AT_DropConstraintRecurse:
03317 ATExecDropConstraint(rel, cmd->name, cmd->behavior,
03318 true, false,
03319 cmd->missing_ok, lockmode);
03320 break;
03321 case AT_AlterColumnType:
03322 ATExecAlterColumnType(tab, rel, cmd, lockmode);
03323 break;
03324 case AT_AlterColumnGenericOptions:
03325 ATExecAlterColumnGenericOptions(rel, cmd->name, (List *) cmd->def, lockmode);
03326 break;
03327 case AT_ChangeOwner:
03328 ATExecChangeOwner(RelationGetRelid(rel),
03329 get_role_oid(cmd->name, false),
03330 false, lockmode);
03331 break;
03332 case AT_ClusterOn:
03333 ATExecClusterOn(rel, cmd->name, lockmode);
03334 break;
03335 case AT_DropCluster:
03336 ATExecDropCluster(rel, lockmode);
03337 break;
03338 case AT_AddOids:
03339
03340 if (cmd->def != NULL)
03341 ATExecAddColumn(wqueue, tab, rel, (ColumnDef *) cmd->def,
03342 true, false, false, lockmode);
03343 break;
03344 case AT_AddOidsRecurse:
03345
03346 if (cmd->def != NULL)
03347 ATExecAddColumn(wqueue, tab, rel, (ColumnDef *) cmd->def,
03348 true, true, false, lockmode);
03349 break;
03350 case AT_DropOids:
03351
03352
03353
03354
03355
03356 break;
03357 case AT_SetTableSpace:
03358
03359
03360
03361
03362 break;
03363 case AT_SetRelOptions:
03364 case AT_ResetRelOptions:
03365 case AT_ReplaceRelOptions:
03366 ATExecSetRelOptions(rel, (List *) cmd->def, cmd->subtype, lockmode);
03367 break;
03368 case AT_EnableTrig:
03369 ATExecEnableDisableTrigger(rel, cmd->name,
03370 TRIGGER_FIRES_ON_ORIGIN, false, lockmode);
03371 break;
03372 case AT_EnableAlwaysTrig:
03373 ATExecEnableDisableTrigger(rel, cmd->name,
03374 TRIGGER_FIRES_ALWAYS, false, lockmode);
03375 break;
03376 case AT_EnableReplicaTrig:
03377 ATExecEnableDisableTrigger(rel, cmd->name,
03378 TRIGGER_FIRES_ON_REPLICA, false, lockmode);
03379 break;
03380 case AT_DisableTrig:
03381 ATExecEnableDisableTrigger(rel, cmd->name,
03382 TRIGGER_DISABLED, false, lockmode);
03383 break;
03384 case AT_EnableTrigAll:
03385 ATExecEnableDisableTrigger(rel, NULL,
03386 TRIGGER_FIRES_ON_ORIGIN, false, lockmode);
03387 break;
03388 case AT_DisableTrigAll:
03389 ATExecEnableDisableTrigger(rel, NULL,
03390 TRIGGER_DISABLED, false, lockmode);
03391 break;
03392 case AT_EnableTrigUser:
03393 ATExecEnableDisableTrigger(rel, NULL,
03394 TRIGGER_FIRES_ON_ORIGIN, true, lockmode);
03395 break;
03396 case AT_DisableTrigUser:
03397 ATExecEnableDisableTrigger(rel, NULL,
03398 TRIGGER_DISABLED, true, lockmode);
03399 break;
03400
03401 case AT_EnableRule:
03402 ATExecEnableDisableRule(rel, cmd->name,
03403 RULE_FIRES_ON_ORIGIN, lockmode);
03404 break;
03405 case AT_EnableAlwaysRule:
03406 ATExecEnableDisableRule(rel, cmd->name,
03407 RULE_FIRES_ALWAYS, lockmode);
03408 break;
03409 case AT_EnableReplicaRule:
03410 ATExecEnableDisableRule(rel, cmd->name,
03411 RULE_FIRES_ON_REPLICA, lockmode);
03412 break;
03413 case AT_DisableRule:
03414 ATExecEnableDisableRule(rel, cmd->name,
03415 RULE_DISABLED, lockmode);
03416 break;
03417
03418 case AT_AddInherit:
03419 ATExecAddInherit(rel, (RangeVar *) cmd->def, lockmode);
03420 break;
03421 case AT_DropInherit:
03422 ATExecDropInherit(rel, (RangeVar *) cmd->def, lockmode);
03423 break;
03424 case AT_AddOf:
03425 ATExecAddOf(rel, (TypeName *) cmd->def, lockmode);
03426 break;
03427 case AT_DropOf:
03428 ATExecDropOf(rel, lockmode);
03429 break;
03430 case AT_GenericOptions:
03431 ATExecGenericOptions(rel, (List *) cmd->def);
03432 break;
03433 default:
03434 elog(ERROR, "unrecognized alter table type: %d",
03435 (int) cmd->subtype);
03436 break;
03437 }
03438
03439
03440
03441
03442
03443 CommandCounterIncrement();
03444 }
03445
03446
03447
03448
03449 static void
03450 ATRewriteTables(List **wqueue, LOCKMODE lockmode)
03451 {
03452 ListCell *ltab;
03453
03454
03455 foreach(ltab, *wqueue)
03456 {
03457 AlteredTableInfo *tab = (AlteredTableInfo *) lfirst(ltab);
03458
03459
03460 if (tab->relkind == RELKIND_FOREIGN_TABLE)
03461 continue;
03462
03463
03464
03465
03466
03467
03468
03469
03470
03471
03472
03473
03474
03475
03476
03477 if (tab->newvals != NIL || tab->rewrite)
03478 {
03479 Relation rel;
03480
03481 rel = heap_open(tab->relid, NoLock);
03482 find_composite_type_dependencies(rel->rd_rel->reltype, rel, NULL);
03483 heap_close(rel, NoLock);
03484 }
03485
03486
03487
03488
03489
03490 if (tab->rewrite)
03491 {
03492
03493 Relation OldHeap;
03494 Oid OIDNewHeap;
03495 Oid NewTableSpace;
03496
03497 OldHeap = heap_open(tab->relid, NoLock);
03498
03499
03500
03501
03502
03503
03504 if (IsSystemRelation(OldHeap))
03505 ereport(ERROR,
03506 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
03507 errmsg("cannot rewrite system relation \"%s\"",
03508 RelationGetRelationName(OldHeap))));
03509
03510
03511
03512
03513
03514 if (RELATION_IS_OTHER_TEMP(OldHeap))
03515 ereport(ERROR,
03516 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
03517 errmsg("cannot rewrite temporary tables of other sessions")));
03518
03519
03520
03521
03522
03523 if (tab->newTableSpace)
03524 NewTableSpace = tab->newTableSpace;
03525 else
03526 NewTableSpace = OldHeap->rd_rel->reltablespace;
03527
03528 heap_close(OldHeap, NoLock);
03529
03530
03531 OIDNewHeap = make_new_heap(tab->relid, NewTableSpace);
03532
03533
03534
03535
03536
03537
03538 ATRewriteTable(tab, OIDNewHeap, lockmode);
03539
03540
03541
03542
03543
03544
03545
03546
03547
03548 finish_heap_swap(tab->relid, OIDNewHeap,
03549 false, false, true,
03550 !OidIsValid(tab->newTableSpace),
03551 RecentXmin,
03552 ReadNextMultiXactId());
03553 }
03554 else
03555 {
03556
03557
03558
03559
03560 if (tab->constraints != NIL || tab->new_notnull)
03561 ATRewriteTable(tab, InvalidOid, lockmode);
03562
03563
03564
03565
03566
03567 if (tab->newTableSpace)
03568 ATExecSetTableSpace(tab->relid, tab->newTableSpace, lockmode);
03569 }
03570 }
03571
03572
03573
03574
03575
03576
03577
03578
03579 foreach(ltab, *wqueue)
03580 {
03581 AlteredTableInfo *tab = (AlteredTableInfo *) lfirst(ltab);
03582 Relation rel = NULL;
03583 ListCell *lcon;
03584
03585 foreach(lcon, tab->constraints)
03586 {
03587 NewConstraint *con = lfirst(lcon);
03588
03589 if (con->contype == CONSTR_FOREIGN)
03590 {
03591 Constraint *fkconstraint = (Constraint *) con->qual;
03592 Relation refrel;
03593
03594 if (rel == NULL)
03595 {
03596
03597 rel = heap_open(tab->relid, NoLock);
03598 }
03599
03600 refrel = heap_open(con->refrelid, RowShareLock);
03601
03602 validateForeignKeyConstraint(fkconstraint->conname, rel, refrel,
03603 con->refindid,
03604 con->conid);
03605
03606
03607
03608
03609
03610
03611 heap_close(refrel, NoLock);
03612 }
03613 }
03614
03615 if (rel)
03616 heap_close(rel, NoLock);
03617 }
03618 }
03619
03620
03621
03622
03623
03624
03625 static void
03626 ATRewriteTable(AlteredTableInfo *tab, Oid OIDNewHeap, LOCKMODE lockmode)
03627 {
03628 Relation oldrel;
03629 Relation newrel;
03630 TupleDesc oldTupDesc;
03631 TupleDesc newTupDesc;
03632 bool needscan = false;
03633 List *notnull_attrs;
03634 int i;
03635 ListCell *l;
03636 EState *estate;
03637 CommandId mycid;
03638 BulkInsertState bistate;
03639 int hi_options;
03640
03641
03642
03643
03644
03645 oldrel = heap_open(tab->relid, NoLock);
03646 oldTupDesc = tab->oldDesc;
03647 newTupDesc = RelationGetDescr(oldrel);
03648
03649 if (OidIsValid(OIDNewHeap))
03650 newrel = heap_open(OIDNewHeap, lockmode);
03651 else
03652 newrel = NULL;
03653
03654
03655
03656
03657
03658
03659
03660 if (newrel)
03661 {
03662 mycid = GetCurrentCommandId(true);
03663 bistate = GetBulkInsertState();
03664
03665 hi_options = HEAP_INSERT_SKIP_FSM;
03666 if (!XLogIsNeeded())
03667 hi_options |= HEAP_INSERT_SKIP_WAL;
03668 }
03669 else
03670 {
03671
03672 mycid = 0;
03673 bistate = NULL;
03674 hi_options = 0;
03675 }
03676
03677
03678
03679
03680
03681 estate = CreateExecutorState();
03682
03683
03684 foreach(l, tab->constraints)
03685 {
03686 NewConstraint *con = lfirst(l);
03687
03688 switch (con->contype)
03689 {
03690 case CONSTR_CHECK:
03691 needscan = true;
03692 con->qualstate = (List *)
03693 ExecPrepareExpr((Expr *) con->qual, estate);
03694 break;
03695 case CONSTR_FOREIGN:
03696
03697 break;
03698 default:
03699 elog(ERROR, "unrecognized constraint type: %d",
03700 (int) con->contype);
03701 }
03702 }
03703
03704 foreach(l, tab->newvals)
03705 {
03706 NewColumnValue *ex = lfirst(l);
03707
03708
03709 ex->exprstate = ExecInitExpr((Expr *) ex->expr, NULL);
03710 }
03711
03712 notnull_attrs = NIL;
03713 if (newrel || tab->new_notnull)
03714 {
03715
03716
03717
03718
03719
03720
03721 for (i = 0; i < newTupDesc->natts; i++)
03722 {
03723 if (newTupDesc->attrs[i]->attnotnull &&
03724 !newTupDesc->attrs[i]->attisdropped)
03725 notnull_attrs = lappend_int(notnull_attrs, i);
03726 }
03727 if (notnull_attrs)
03728 needscan = true;
03729 }
03730
03731 if (newrel || needscan)
03732 {
03733 ExprContext *econtext;
03734 Datum *values;
03735 bool *isnull;
03736 TupleTableSlot *oldslot;
03737 TupleTableSlot *newslot;
03738 HeapScanDesc scan;
03739 HeapTuple tuple;
03740 MemoryContext oldCxt;
03741 List *dropped_attrs = NIL;
03742 ListCell *lc;
03743
03744 if (newrel)
03745 ereport(DEBUG1,
03746 (errmsg("rewriting table \"%s\"",
03747 RelationGetRelationName(oldrel))));
03748 else
03749 ereport(DEBUG1,
03750 (errmsg("verifying table \"%s\"",
03751 RelationGetRelationName(oldrel))));
03752
03753 if (newrel)
03754 {
03755
03756
03757
03758
03759
03760 TransferPredicateLocksToHeapRelation(oldrel);
03761 }
03762
03763 econtext = GetPerTupleExprContext(estate);
03764
03765
03766
03767
03768
03769
03770 oldslot = MakeSingleTupleTableSlot(oldTupDesc);
03771 newslot = MakeSingleTupleTableSlot(newTupDesc);
03772
03773
03774 i = Max(newTupDesc->natts, oldTupDesc->natts);
03775 values = (Datum *) palloc(i * sizeof(Datum));
03776 isnull = (bool *) palloc(i * sizeof(bool));
03777 memset(values, 0, i * sizeof(Datum));
03778 memset(isnull, true, i * sizeof(bool));
03779
03780
03781
03782
03783
03784
03785 for (i = 0; i < newTupDesc->natts; i++)
03786 {
03787 if (newTupDesc->attrs[i]->attisdropped)
03788 dropped_attrs = lappend_int(dropped_attrs, i);
03789 }
03790
03791
03792
03793
03794
03795 scan = heap_beginscan(oldrel, SnapshotNow, 0, NULL);
03796
03797
03798
03799
03800
03801 oldCxt = MemoryContextSwitchTo(GetPerTupleMemoryContext(estate));
03802
03803 while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
03804 {
03805 if (tab->rewrite)
03806 {
03807 Oid tupOid = InvalidOid;
03808
03809
03810 heap_deform_tuple(tuple, oldTupDesc, values, isnull);
03811 if (oldTupDesc->tdhasoid)
03812 tupOid = HeapTupleGetOid(tuple);
03813
03814
03815 foreach(lc, dropped_attrs)
03816 isnull[lfirst_int(lc)] = true;
03817
03818
03819
03820
03821
03822 ExecStoreTuple(tuple, oldslot, InvalidBuffer, false);
03823 econtext->ecxt_scantuple = oldslot;
03824
03825 foreach(l, tab->newvals)
03826 {
03827 NewColumnValue *ex = lfirst(l);
03828
03829 values[ex->attnum - 1] = ExecEvalExpr(ex->exprstate,
03830 econtext,
03831 &isnull[ex->attnum - 1],
03832 NULL);
03833 }
03834
03835
03836
03837
03838
03839 tuple = heap_form_tuple(newTupDesc, values, isnull);
03840
03841
03842 if (newTupDesc->tdhasoid)
03843 HeapTupleSetOid(tuple, tupOid);
03844 }
03845
03846
03847 ExecStoreTuple(tuple, newslot, InvalidBuffer, false);
03848 econtext->ecxt_scantuple = newslot;
03849
03850 foreach(l, notnull_attrs)
03851 {
03852 int attn = lfirst_int(l);
03853
03854 if (heap_attisnull(tuple, attn + 1))
03855 ereport(ERROR,
03856 (errcode(ERRCODE_NOT_NULL_VIOLATION),
03857 errmsg("column \"%s\" contains null values",
03858 NameStr(newTupDesc->attrs[attn]->attname)),
03859 errtablecol(oldrel, attn + 1)));
03860 }
03861
03862 foreach(l, tab->constraints)
03863 {
03864 NewConstraint *con = lfirst(l);
03865
03866 switch (con->contype)
03867 {
03868 case CONSTR_CHECK:
03869 if (!ExecQual(con->qualstate, econtext, true))
03870 ereport(ERROR,
03871 (errcode(ERRCODE_CHECK_VIOLATION),
03872 errmsg("check constraint \"%s\" is violated by some row",
03873 con->name),
03874 errtableconstraint(oldrel, con->name)));
03875 break;
03876 case CONSTR_FOREIGN:
03877
03878 break;
03879 default:
03880 elog(ERROR, "unrecognized constraint type: %d",
03881 (int) con->contype);
03882 }
03883 }
03884
03885
03886 if (newrel)
03887 heap_insert(newrel, tuple, mycid, hi_options, bistate);
03888
03889 ResetExprContext(econtext);
03890
03891 CHECK_FOR_INTERRUPTS();
03892 }
03893
03894 MemoryContextSwitchTo(oldCxt);
03895 heap_endscan(scan);
03896
03897 ExecDropSingleTupleTableSlot(oldslot);
03898 ExecDropSingleTupleTableSlot(newslot);
03899 }
03900
03901 FreeExecutorState(estate);
03902
03903 heap_close(oldrel, NoLock);
03904 if (newrel)
03905 {
03906 FreeBulkInsertState(bistate);
03907
03908
03909 if (hi_options & HEAP_INSERT_SKIP_WAL)
03910 heap_sync(newrel);
03911
03912 heap_close(newrel, NoLock);
03913 }
03914 }
03915
03916
03917
03918
03919 static AlteredTableInfo *
03920 ATGetQueueEntry(List **wqueue, Relation rel)
03921 {
03922 Oid relid = RelationGetRelid(rel);
03923 AlteredTableInfo *tab;
03924 ListCell *ltab;
03925
03926 foreach(ltab, *wqueue)
03927 {
03928 tab = (AlteredTableInfo *) lfirst(ltab);
03929 if (tab->relid == relid)
03930 return tab;
03931 }
03932
03933
03934
03935
03936
03937 tab = (AlteredTableInfo *) palloc0(sizeof(AlteredTableInfo));
03938 tab->relid = relid;
03939 tab->relkind = rel->rd_rel->relkind;
03940 tab->oldDesc = CreateTupleDescCopy(RelationGetDescr(rel));
03941
03942 *wqueue = lappend(*wqueue, tab);
03943
03944 return tab;
03945 }
03946
03947
03948
03949
03950
03951
03952
03953
03954 static void
03955 ATSimplePermissions(Relation rel, int allowed_targets)
03956 {
03957 int actual_target;
03958
03959 switch (rel->rd_rel->relkind)
03960 {
03961 case RELKIND_RELATION:
03962 actual_target = ATT_TABLE;
03963 break;
03964 case RELKIND_VIEW:
03965 actual_target = ATT_VIEW;
03966 break;
03967 case RELKIND_MATVIEW:
03968 actual_target = ATT_MATVIEW;
03969 break;
03970 case RELKIND_INDEX:
03971 actual_target = ATT_INDEX;
03972 break;
03973 case RELKIND_COMPOSITE_TYPE:
03974 actual_target = ATT_COMPOSITE_TYPE;
03975 break;
03976 case RELKIND_FOREIGN_TABLE:
03977 actual_target = ATT_FOREIGN_TABLE;
03978 break;
03979 default:
03980 actual_target = 0;
03981 break;
03982 }
03983
03984
03985 if ((actual_target & allowed_targets) == 0)
03986 ATWrongRelkindError(rel, allowed_targets);
03987
03988
03989 if (!pg_class_ownercheck(RelationGetRelid(rel), GetUserId()))
03990 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS,
03991 RelationGetRelationName(rel));
03992
03993 if (!allowSystemTableMods && IsSystemRelation(rel))
03994 ereport(ERROR,
03995 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
03996 errmsg("permission denied: \"%s\" is a system catalog",
03997 RelationGetRelationName(rel))));
03998 }
03999
04000
04001
04002
04003
04004
04005
04006 static void
04007 ATWrongRelkindError(Relation rel, int allowed_targets)
04008 {
04009 char *msg;
04010
04011 switch (allowed_targets)
04012 {
04013 case ATT_TABLE:
04014 msg = _("\"%s\" is not a table");
04015 break;
04016 case ATT_TABLE | ATT_VIEW:
04017 msg = _("\"%s\" is not a table or view");
04018 break;
04019 case ATT_TABLE | ATT_VIEW | ATT_MATVIEW | ATT_INDEX:
04020 msg = _("\"%s\" is not a table, view, materialized view, or index");
04021 break;
04022 case ATT_TABLE | ATT_MATVIEW:
04023 msg = _("\"%s\" is not a table or materialized view");
04024 break;
04025 case ATT_TABLE | ATT_MATVIEW | ATT_INDEX:
04026 msg = _("\"%s\" is not a table, materialized view, or index");
04027 break;
04028 case ATT_TABLE | ATT_FOREIGN_TABLE:
04029 msg = _("\"%s\" is not a table or foreign table");
04030 break;
04031 case ATT_TABLE | ATT_COMPOSITE_TYPE | ATT_FOREIGN_TABLE:
04032 msg = _("\"%s\" is not a table, composite type, or foreign table");
04033 break;
04034 case ATT_TABLE | ATT_MATVIEW | ATT_INDEX | ATT_FOREIGN_TABLE:
04035 msg = _("\"%s\" is not a table, materialized view, composite type, or foreign table");
04036 break;
04037 case ATT_VIEW:
04038 msg = _("\"%s\" is not a view");
04039 break;
04040 case ATT_FOREIGN_TABLE:
04041 msg = _("\"%s\" is not a foreign table");
04042 break;
04043 default:
04044
04045 msg = _("\"%s\" is of the wrong type");
04046 break;
04047 }
04048
04049 ereport(ERROR,
04050 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
04051 errmsg(msg, RelationGetRelationName(rel))));
04052 }
04053
04054
04055
04056
04057
04058
04059
04060
04061
04062 static void
04063 ATSimpleRecursion(List **wqueue, Relation rel,
04064 AlterTableCmd *cmd, bool recurse, LOCKMODE lockmode)
04065 {
04066
04067
04068
04069
04070 if (recurse && rel->rd_rel->relkind == RELKIND_RELATION)
04071 {
04072 Oid relid = RelationGetRelid(rel);
04073 ListCell *child;
04074 List *children;
04075
04076 children = find_all_inheritors(relid, lockmode, NULL);
04077
04078
04079
04080
04081
04082
04083 foreach(child, children)
04084 {
04085 Oid childrelid = lfirst_oid(child);
04086 Relation childrel;
04087
04088 if (childrelid == relid)
04089 continue;
04090
04091 childrel = relation_open(childrelid, NoLock);
04092 CheckTableNotInUse(childrel, "ALTER TABLE");
04093 ATPrepCmd(wqueue, childrel, cmd, false, true, lockmode);
04094 relation_close(childrel, NoLock);
04095 }
04096 }
04097 }
04098
04099
04100
04101
04102
04103
04104
04105
04106 static void
04107 ATTypedTableRecursion(List **wqueue, Relation rel, AlterTableCmd *cmd,
04108 LOCKMODE lockmode)
04109 {
04110 ListCell *child;
04111 List *children;
04112
04113 Assert(rel->rd_rel->relkind == RELKIND_COMPOSITE_TYPE);
04114
04115 children = find_typed_table_dependencies(rel->rd_rel->reltype,
04116 RelationGetRelationName(rel),
04117 cmd->behavior);
04118
04119 foreach(child, children)
04120 {
04121 Oid childrelid = lfirst_oid(child);
04122 Relation childrel;
04123
04124 childrel = relation_open(childrelid, lockmode);
04125 CheckTableNotInUse(childrel, "ALTER TABLE");
04126 ATPrepCmd(wqueue, childrel, cmd, true, true, lockmode);
04127 relation_close(childrel, NoLock);
04128 }
04129 }
04130
04131
04132
04133
04134
04135
04136
04137
04138
04139
04140
04141
04142
04143
04144
04145
04146 void
04147 find_composite_type_dependencies(Oid typeOid, Relation origRelation,
04148 const char *origTypeName)
04149 {
04150 Relation depRel;
04151 ScanKeyData key[2];
04152 SysScanDesc depScan;
04153 HeapTuple depTup;
04154 Oid arrayOid;
04155
04156
04157
04158
04159
04160 depRel = heap_open(DependRelationId, AccessShareLock);
04161
04162 ScanKeyInit(&key[0],
04163 Anum_pg_depend_refclassid,
04164 BTEqualStrategyNumber, F_OIDEQ,
04165 ObjectIdGetDatum(TypeRelationId));
04166 ScanKeyInit(&key[1],
04167 Anum_pg_depend_refobjid,
04168 BTEqualStrategyNumber, F_OIDEQ,
04169 ObjectIdGetDatum(typeOid));
04170
04171 depScan = systable_beginscan(depRel, DependReferenceIndexId, true,
04172 SnapshotNow, 2, key);
04173
04174 while (HeapTupleIsValid(depTup = systable_getnext(depScan)))
04175 {
04176 Form_pg_depend pg_depend = (Form_pg_depend) GETSTRUCT(depTup);
04177 Relation rel;
04178 Form_pg_attribute att;
04179
04180
04181
04182 if (pg_depend->classid != RelationRelationId ||
04183 pg_depend->objsubid <= 0)
04184 continue;
04185
04186 rel = relation_open(pg_depend->objid, AccessShareLock);
04187 att = rel->rd_att->attrs[pg_depend->objsubid - 1];
04188
04189 if (rel->rd_rel->relkind == RELKIND_RELATION ||
04190 rel->rd_rel->relkind == RELKIND_MATVIEW)
04191 {
04192 if (origTypeName)
04193 ereport(ERROR,
04194 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
04195 errmsg("cannot alter type \"%s\" because column \"%s.%s\" uses it",
04196 origTypeName,
04197 RelationGetRelationName(rel),
04198 NameStr(att->attname))));
04199 else if (origRelation->rd_rel->relkind == RELKIND_COMPOSITE_TYPE)
04200 ereport(ERROR,
04201 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
04202 errmsg("cannot alter type \"%s\" because column \"%s.%s\" uses it",
04203 RelationGetRelationName(origRelation),
04204 RelationGetRelationName(rel),
04205 NameStr(att->attname))));
04206 else if (origRelation->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
04207 ereport(ERROR,
04208 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
04209 errmsg("cannot alter foreign table \"%s\" because column \"%s.%s\" uses its row type",
04210 RelationGetRelationName(origRelation),
04211 RelationGetRelationName(rel),
04212 NameStr(att->attname))));
04213 else
04214 ereport(ERROR,
04215 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
04216 errmsg("cannot alter table \"%s\" because column \"%s.%s\" uses its row type",
04217 RelationGetRelationName(origRelation),
04218 RelationGetRelationName(rel),
04219 NameStr(att->attname))));
04220 }
04221 else if (OidIsValid(rel->rd_rel->reltype))
04222 {
04223
04224
04225
04226
04227 find_composite_type_dependencies(rel->rd_rel->reltype,
04228 origRelation, origTypeName);
04229 }
04230
04231 relation_close(rel, AccessShareLock);
04232 }
04233
04234 systable_endscan(depScan);
04235
04236 relation_close(depRel, AccessShareLock);
04237
04238
04239
04240
04241
04242 arrayOid = get_array_type(typeOid);
04243 if (OidIsValid(arrayOid))
04244 find_composite_type_dependencies(arrayOid, origRelation, origTypeName);
04245 }
04246
04247
04248
04249
04250
04251
04252
04253
04254
04255 static List *
04256 find_typed_table_dependencies(Oid typeOid, const char *typeName, DropBehavior behavior)
04257 {
04258 Relation classRel;
04259 ScanKeyData key[1];
04260 HeapScanDesc scan;
04261 HeapTuple tuple;
04262 List *result = NIL;
04263
04264 classRel = heap_open(RelationRelationId, AccessShareLock);
04265
04266 ScanKeyInit(&key[0],
04267 Anum_pg_class_reloftype,
04268 BTEqualStrategyNumber, F_OIDEQ,
04269 ObjectIdGetDatum(typeOid));
04270
04271 scan = heap_beginscan(classRel, SnapshotNow, 1, key);
04272
04273 while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
04274 {
04275 if (behavior == DROP_RESTRICT)
04276 ereport(ERROR,
04277 (errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
04278 errmsg("cannot alter type \"%s\" because it is the type of a typed table",
04279 typeName),
04280 errhint("Use ALTER ... CASCADE to alter the typed tables too.")));
04281 else
04282 result = lappend_oid(result, HeapTupleGetOid(tuple));
04283 }
04284
04285 heap_endscan(scan);
04286 heap_close(classRel, AccessShareLock);
04287
04288 return result;
04289 }
04290
04291
04292
04293
04294
04295
04296
04297
04298
04299
04300 void
04301 check_of_type(HeapTuple typetuple)
04302 {
04303 Form_pg_type typ = (Form_pg_type) GETSTRUCT(typetuple);
04304 bool typeOk = false;
04305
04306 if (typ->typtype == TYPTYPE_COMPOSITE)
04307 {
04308 Relation typeRelation;
04309
04310 Assert(OidIsValid(typ->typrelid));
04311 typeRelation = relation_open(typ->typrelid, AccessShareLock);
04312 typeOk = (typeRelation->rd_rel->relkind == RELKIND_COMPOSITE_TYPE);
04313
04314
04315
04316
04317
04318
04319 relation_close(typeRelation, NoLock);
04320 }
04321 if (!typeOk)
04322 ereport(ERROR,
04323 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
04324 errmsg("type %s is not a composite type",
04325 format_type_be(HeapTupleGetOid(typetuple)))));
04326 }
04327
04328
04329
04330
04331
04332
04333
04334
04335
04336
04337
04338
04339
04340
04341
04342
04343 static void
04344 ATPrepAddColumn(List **wqueue, Relation rel, bool recurse, bool recursing,
04345 AlterTableCmd *cmd, LOCKMODE lockmode)
04346 {
04347 if (rel->rd_rel->reloftype && !recursing)
04348 ereport(ERROR,
04349 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
04350 errmsg("cannot add column to typed table")));
04351
04352 if (rel->rd_rel->relkind == RELKIND_COMPOSITE_TYPE)
04353 ATTypedTableRecursion(wqueue, rel, cmd, lockmode);
04354
04355 if (recurse)
04356 cmd->subtype = AT_AddColumnRecurse;
04357 }
04358
04359 static void
04360 ATExecAddColumn(List **wqueue, AlteredTableInfo *tab, Relation rel,
04361 ColumnDef *colDef, bool isOid,
04362 bool recurse, bool recursing, LOCKMODE lockmode)
04363 {
04364 Oid myrelid = RelationGetRelid(rel);
04365 Relation pgclass,
04366 attrdesc;
04367 HeapTuple reltup;
04368 FormData_pg_attribute attribute;
04369 int newattnum;
04370 char relkind;
04371 HeapTuple typeTuple;
04372 Oid typeOid;
04373 int32 typmod;
04374 Oid collOid;
04375 Form_pg_type tform;
04376 Expr *defval;
04377 List *children;
04378 ListCell *child;
04379 AclResult aclresult;
04380
04381
04382 if (recursing)
04383 ATSimplePermissions(rel, ATT_TABLE);
04384
04385 attrdesc = heap_open(AttributeRelationId, RowExclusiveLock);
04386
04387
04388
04389
04390
04391
04392
04393 if (colDef->inhcount > 0)
04394 {
04395 HeapTuple tuple;
04396
04397
04398 tuple = SearchSysCacheCopyAttName(myrelid, colDef->colname);
04399 if (HeapTupleIsValid(tuple))
04400 {
04401 Form_pg_attribute childatt = (Form_pg_attribute) GETSTRUCT(tuple);
04402 Oid ctypeId;
04403 int32 ctypmod;
04404 Oid ccollid;
04405
04406
04407 typenameTypeIdAndMod(NULL, colDef->typeName, &ctypeId, &ctypmod);
04408 if (ctypeId != childatt->atttypid ||
04409 ctypmod != childatt->atttypmod)
04410 ereport(ERROR,
04411 (errcode(ERRCODE_DATATYPE_MISMATCH),
04412 errmsg("child table \"%s\" has different type for column \"%s\"",
04413 RelationGetRelationName(rel), colDef->colname)));
04414 ccollid = GetColumnDefCollation(NULL, colDef, ctypeId);
04415 if (ccollid != childatt->attcollation)
04416 ereport(ERROR,
04417 (errcode(ERRCODE_COLLATION_MISMATCH),
04418 errmsg("child table \"%s\" has different collation for column \"%s\"",
04419 RelationGetRelationName(rel), colDef->colname),
04420 errdetail("\"%s\" versus \"%s\"",
04421 get_collation_name(ccollid),
04422 get_collation_name(childatt->attcollation))));
04423
04424
04425 if (isOid && childatt->attnum != ObjectIdAttributeNumber)
04426 ereport(ERROR,
04427 (errcode(ERRCODE_DATATYPE_MISMATCH),
04428 errmsg("child table \"%s\" has a conflicting \"%s\" column",
04429 RelationGetRelationName(rel), colDef->colname)));
04430
04431
04432 childatt->attinhcount++;
04433 simple_heap_update(attrdesc, &tuple->t_self, tuple);
04434 CatalogUpdateIndexes(attrdesc, tuple);
04435
04436 heap_freetuple(tuple);
04437
04438
04439 ereport(NOTICE,
04440 (errmsg("merging definition of column \"%s\" for child \"%s\"",
04441 colDef->colname, RelationGetRelationName(rel))));
04442
04443 heap_close(attrdesc, RowExclusiveLock);
04444 return;
04445 }
04446 }
04447
04448 pgclass = heap_open(RelationRelationId, RowExclusiveLock);
04449
04450 reltup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(myrelid));
04451 if (!HeapTupleIsValid(reltup))
04452 elog(ERROR, "cache lookup failed for relation %u", myrelid);
04453 relkind = ((Form_pg_class) GETSTRUCT(reltup))->relkind;
04454
04455
04456 check_for_column_name_collision(rel, colDef->colname);
04457
04458
04459 if (isOid)
04460 newattnum = ObjectIdAttributeNumber;
04461 else
04462 {
04463 newattnum = ((Form_pg_class) GETSTRUCT(reltup))->relnatts + 1;
04464 if (newattnum > MaxHeapAttributeNumber)
04465 ereport(ERROR,
04466 (errcode(ERRCODE_TOO_MANY_COLUMNS),
04467 errmsg("tables can have at most %d columns",
04468 MaxHeapAttributeNumber)));
04469 }
04470
04471 typeTuple = typenameType(NULL, colDef->typeName, &typmod);
04472 tform = (Form_pg_type) GETSTRUCT(typeTuple);
04473 typeOid = HeapTupleGetOid(typeTuple);
04474
04475 aclresult = pg_type_aclcheck(typeOid, GetUserId(), ACL_USAGE);
04476 if (aclresult != ACLCHECK_OK)
04477 aclcheck_error_type(aclresult, typeOid);
04478
04479 collOid = GetColumnDefCollation(NULL, colDef, typeOid);
04480
04481
04482 CheckAttributeType(colDef->colname, typeOid, collOid,
04483 list_make1_oid(rel->rd_rel->reltype),
04484 false);
04485
04486
04487 attribute.attrelid = myrelid;
04488 namestrcpy(&(attribute.attname), colDef->colname);
04489 attribute.atttypid = typeOid;
04490 attribute.attstattarget = (newattnum > 0) ? -1 : 0;
04491 attribute.attlen = tform->typlen;
04492 attribute.attcacheoff = -1;
04493 attribute.atttypmod = typmod;
04494 attribute.attnum = newattnum;
04495 attribute.attbyval = tform->typbyval;
04496 attribute.attndims = list_length(colDef->typeName->arrayBounds);
04497 attribute.attstorage = tform->typstorage;
04498 attribute.attalign = tform->typalign;
04499 attribute.attnotnull = colDef->is_not_null;
04500 attribute.atthasdef = false;
04501 attribute.attisdropped = false;
04502 attribute.attislocal = colDef->is_local;
04503 attribute.attinhcount = colDef->inhcount;
04504 attribute.attcollation = collOid;
04505
04506
04507 ReleaseSysCache(typeTuple);
04508
04509 InsertPgAttributeTuple(attrdesc, &attribute, NULL);
04510
04511 heap_close(attrdesc, RowExclusiveLock);
04512
04513
04514
04515
04516 if (isOid)
04517 ((Form_pg_class) GETSTRUCT(reltup))->relhasoids = true;
04518 else
04519 ((Form_pg_class) GETSTRUCT(reltup))->relnatts = newattnum;
04520
04521 simple_heap_update(pgclass, &reltup->t_self, reltup);
04522
04523
04524 CatalogUpdateIndexes(pgclass, reltup);
04525
04526 heap_freetuple(reltup);
04527
04528
04529 InvokeObjectPostCreateHook(RelationRelationId, myrelid, newattnum);
04530
04531 heap_close(pgclass, RowExclusiveLock);
04532
04533
04534 CommandCounterIncrement();
04535
04536
04537
04538
04539 if (colDef->raw_default)
04540 {
04541 RawColumnDefault *rawEnt;
04542
04543 rawEnt = (RawColumnDefault *) palloc(sizeof(RawColumnDefault));
04544 rawEnt->attnum = attribute.attnum;
04545 rawEnt->raw_default = copyObject(colDef->raw_default);
04546
04547
04548
04549
04550
04551 AddRelationNewConstraints(rel, list_make1(rawEnt), NIL,
04552 false, true, false);
04553
04554
04555 CommandCounterIncrement();
04556 }
04557
04558
04559
04560
04561
04562
04563
04564
04565
04566
04567
04568
04569
04570
04571
04572
04573
04574
04575
04576
04577
04578
04579
04580
04581
04582
04583
04584
04585
04586 if (relkind != RELKIND_VIEW && relkind != RELKIND_COMPOSITE_TYPE
04587 && relkind != RELKIND_FOREIGN_TABLE && attribute.attnum > 0)
04588 {
04589 defval = (Expr *) build_column_default(rel, attribute.attnum);
04590
04591 if (!defval && GetDomainConstraints(typeOid) != NIL)
04592 {
04593 Oid baseTypeId;
04594 int32 baseTypeMod;
04595 Oid baseTypeColl;
04596
04597 baseTypeMod = typmod;
04598 baseTypeId = getBaseTypeAndTypmod(typeOid, &baseTypeMod);
04599 baseTypeColl = get_typcollation(baseTypeId);
04600 defval = (Expr *) makeNullConst(baseTypeId, baseTypeMod, baseTypeColl);
04601 defval = (Expr *) coerce_to_target_type(NULL,
04602 (Node *) defval,
04603 baseTypeId,
04604 typeOid,
04605 typmod,
04606 COERCION_ASSIGNMENT,
04607 COERCE_IMPLICIT_CAST,
04608 -1);
04609 if (defval == NULL)
04610 elog(ERROR, "failed to coerce base type to domain");
04611 }
04612
04613 if (defval)
04614 {
04615 NewColumnValue *newval;
04616
04617 newval = (NewColumnValue *) palloc0(sizeof(NewColumnValue));
04618 newval->attnum = attribute.attnum;
04619 newval->expr = expression_planner(defval);
04620
04621 tab->newvals = lappend(tab->newvals, newval);
04622 tab->rewrite = true;
04623 }
04624
04625
04626
04627
04628
04629
04630
04631 tab->new_notnull |= colDef->is_not_null;
04632 }
04633
04634
04635
04636
04637
04638 if (isOid)
04639 tab->rewrite = true;
04640
04641
04642
04643
04644 add_column_datatype_dependency(myrelid, newattnum, attribute.atttypid);
04645 add_column_collation_dependency(myrelid, newattnum, attribute.attcollation);
04646
04647
04648
04649
04650
04651
04652 children = find_inheritance_children(RelationGetRelid(rel), lockmode);
04653
04654
04655
04656
04657
04658 if (children && !recurse)
04659 ereport(ERROR,
04660 (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
04661 errmsg("column must be added to child tables too")));
04662
04663
04664 if (!recursing)
04665 {
04666 colDef = copyObject(colDef);
04667 colDef->inhcount = 1;
04668 colDef->is_local = false;
04669 }
04670
04671 foreach(child, children)
04672 {
04673 Oid childrelid = lfirst_oid(child);
04674 Relation childrel;
04675 AlteredTableInfo *childtab;
04676
04677
04678 childrel = heap_open(childrelid, NoLock);
04679 CheckTableNotInUse(childrel, "ALTER TABLE");
04680
04681
04682 childtab = ATGetQueueEntry(wqueue, childrel);
04683
04684
04685 ATExecAddColumn(wqueue, childtab, childrel,
04686 colDef, isOid, recurse, true, lockmode);
04687
04688 heap_close(childrel, NoLock);
04689 }
04690 }
04691
04692
04693
04694
04695
04696 static void
04697 check_for_column_name_collision(Relation rel, const char *colname)
04698 {
04699 HeapTuple attTuple;
04700 int attnum;
04701
04702
04703
04704
04705
04706 attTuple = SearchSysCache2(ATTNAME,
04707 ObjectIdGetDatum(RelationGetRelid(rel)),
04708 PointerGetDatum(colname));
04709 if (!HeapTupleIsValid(attTuple))
04710 return;
04711
04712 attnum = ((Form_pg_attribute) GETSTRUCT(attTuple))->attnum;
04713 ReleaseSysCache(attTuple);
04714
04715
04716
04717
04718
04719
04720 if (attnum <= 0)
04721 ereport(ERROR,
04722 (errcode(ERRCODE_DUPLICATE_COLUMN),
04723 errmsg("column name \"%s\" conflicts with a system column name",
04724 colname)));
04725 else
04726 ereport(ERROR,
04727 (errcode(ERRCODE_DUPLICATE_COLUMN),
04728 errmsg("column \"%s\" of relation \"%s\" already exists",
04729 colname, RelationGetRelationName(rel))));
04730 }
04731
04732
04733
04734
04735 static void
04736 add_column_datatype_dependency(Oid relid, int32 attnum, Oid typid)
04737 {
04738 ObjectAddress myself,
04739 referenced;
04740
04741 myself.classId = RelationRelationId;
04742 myself.objectId = relid;
04743 myself.objectSubId = attnum;
04744 referenced.classId = TypeRelationId;
04745 referenced.objectId = typid;
04746 referenced.objectSubId = 0;
04747 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
04748 }
04749
04750
04751
04752
04753 static void
04754 add_column_collation_dependency(Oid relid, int32 attnum, Oid collid)
04755 {
04756 ObjectAddress myself,
04757 referenced;
04758
04759
04760 if (OidIsValid(collid) && collid != DEFAULT_COLLATION_OID)
04761 {
04762 myself.classId = RelationRelationId;
04763 myself.objectId = relid;
04764 myself.objectSubId = attnum;
04765 referenced.classId = CollationRelationId;
04766 referenced.objectId = collid;
04767 referenced.objectSubId = 0;
04768 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
04769 }
04770 }
04771
04772
04773
04774
04775
04776
04777
04778 static void
04779 ATPrepAddOids(List **wqueue, Relation rel, bool recurse, AlterTableCmd *cmd, LOCKMODE lockmode)
04780 {
04781
04782 if (cmd->def == NULL)
04783 {
04784 ColumnDef *cdef = makeNode(ColumnDef);
04785
04786 cdef->colname = pstrdup("oid");
04787 cdef->typeName = makeTypeNameFromOid(OIDOID, -1);
04788 cdef->inhcount = 0;
04789 cdef->is_local = true;
04790 cdef->is_not_null = true;
04791 cdef->storage = 0;
04792 cmd->def = (Node *) cdef;
04793 }
04794 ATPrepAddColumn(wqueue, rel, recurse, false, cmd, lockmode);
04795
04796 if (recurse)
04797 cmd->subtype = AT_AddOidsRecurse;
04798 }
04799
04800
04801
04802
04803 static void
04804 ATExecDropNotNull(Relation rel, const char *colName, LOCKMODE lockmode)
04805 {
04806 HeapTuple tuple;
04807 AttrNumber attnum;
04808 Relation attr_rel;
04809 List *indexoidlist;
04810 ListCell *indexoidscan;
04811
04812
04813
04814
04815 attr_rel = heap_open(AttributeRelationId, RowExclusiveLock);
04816
04817 tuple = SearchSysCacheCopyAttName(RelationGetRelid(rel), colName);
04818
04819 if (!HeapTupleIsValid(tuple))
04820 ereport(ERROR,
04821 (errcode(ERRCODE_UNDEFINED_COLUMN),
04822 errmsg("column \"%s\" of relation \"%s\" does not exist",
04823 colName, RelationGetRelationName(rel))));
04824
04825 attnum = ((Form_pg_attribute) GETSTRUCT(tuple))->attnum;
04826
04827
04828 if (attnum <= 0)
04829 ereport(ERROR,
04830 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
04831 errmsg("cannot alter system column \"%s\"",
04832 colName)));
04833
04834
04835
04836
04837
04838
04839
04840
04841 indexoidlist = RelationGetIndexList(rel);
04842
04843 foreach(indexoidscan, indexoidlist)
04844 {
04845 Oid indexoid = lfirst_oid(indexoidscan);
04846 HeapTuple indexTuple;
04847 Form_pg_index indexStruct;
04848 int i;
04849
04850 indexTuple = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(indexoid));
04851 if (!HeapTupleIsValid(indexTuple))
04852 elog(ERROR, "cache lookup failed for index %u", indexoid);
04853 indexStruct = (Form_pg_index) GETSTRUCT(indexTuple);
04854
04855
04856 if (indexStruct->indisprimary)
04857 {
04858
04859
04860
04861
04862 for (i = 0; i < indexStruct->indnatts; i++)
04863 {
04864 if (indexStruct->indkey.values[i] == attnum)
04865 ereport(ERROR,
04866 (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
04867 errmsg("column \"%s\" is in a primary key",
04868 colName)));
04869 }
04870 }
04871
04872 ReleaseSysCache(indexTuple);
04873 }
04874
04875 list_free(indexoidlist);
04876
04877
04878
04879
04880 if (((Form_pg_attribute) GETSTRUCT(tuple))->attnotnull)
04881 {
04882 ((Form_pg_attribute) GETSTRUCT(tuple))->attnotnull = FALSE;
04883
04884 simple_heap_update(attr_rel, &tuple->t_self, tuple);
04885
04886
04887 CatalogUpdateIndexes(attr_rel, tuple);
04888 }
04889
04890 InvokeObjectPostAlterHook(RelationRelationId,
04891 RelationGetRelid(rel), attnum);
04892
04893 heap_close(attr_rel, RowExclusiveLock);
04894 }
04895
04896
04897
04898
04899 static void
04900 ATExecSetNotNull(AlteredTableInfo *tab, Relation rel,
04901 const char *colName, LOCKMODE lockmode)
04902 {
04903 HeapTuple tuple;
04904 AttrNumber attnum;
04905 Relation attr_rel;
04906
04907
04908
04909
04910 attr_rel = heap_open(AttributeRelationId, RowExclusiveLock);
04911
04912 tuple = SearchSysCacheCopyAttName(RelationGetRelid(rel), colName);
04913
04914 if (!HeapTupleIsValid(tuple))
04915 ereport(ERROR,
04916 (errcode(ERRCODE_UNDEFINED_COLUMN),
04917 errmsg("column \"%s\" of relation \"%s\" does not exist",
04918 colName, RelationGetRelationName(rel))));
04919
04920 attnum = ((Form_pg_attribute) GETSTRUCT(tuple))->attnum;
04921
04922
04923 if (attnum <= 0)
04924 ereport(ERROR,
04925 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
04926 errmsg("cannot alter system column \"%s\"",
04927 colName)));
04928
04929
04930
04931
04932 if (!((Form_pg_attribute) GETSTRUCT(tuple))->attnotnull)
04933 {
04934 ((Form_pg_attribute) GETSTRUCT(tuple))->attnotnull = TRUE;
04935
04936 simple_heap_update(attr_rel, &tuple->t_self, tuple);
04937
04938
04939 CatalogUpdateIndexes(attr_rel, tuple);
04940
04941
04942 tab->new_notnull = true;
04943 }
04944
04945 InvokeObjectPostAlterHook(RelationRelationId,
04946 RelationGetRelid(rel), attnum);
04947
04948 heap_close(attr_rel, RowExclusiveLock);
04949 }
04950
04951
04952
04953
04954 static void
04955 ATExecColumnDefault(Relation rel, const char *colName,
04956 Node *newDefault, LOCKMODE lockmode)
04957 {
04958 AttrNumber attnum;
04959
04960
04961
04962
04963 attnum = get_attnum(RelationGetRelid(rel), colName);
04964 if (attnum == InvalidAttrNumber)
04965 ereport(ERROR,
04966 (errcode(ERRCODE_UNDEFINED_COLUMN),
04967 errmsg("column \"%s\" of relation \"%s\" does not exist",
04968 colName, RelationGetRelationName(rel))));
04969
04970
04971 if (attnum <= 0)
04972 ereport(ERROR,
04973 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
04974 errmsg("cannot alter system column \"%s\"",
04975 colName)));
04976
04977
04978
04979
04980
04981
04982
04983
04984
04985
04986 RemoveAttrDefault(RelationGetRelid(rel), attnum, DROP_RESTRICT, false,
04987 newDefault == NULL ? false : true);
04988
04989 if (newDefault)
04990 {
04991
04992 RawColumnDefault *rawEnt;
04993
04994 rawEnt = (RawColumnDefault *) palloc(sizeof(RawColumnDefault));
04995 rawEnt->attnum = attnum;
04996 rawEnt->raw_default = newDefault;
04997
04998
04999
05000
05001
05002 AddRelationNewConstraints(rel, list_make1(rawEnt), NIL,
05003 false, true, false);
05004 }
05005 }
05006
05007
05008
05009
05010 static void
05011 ATPrepSetStatistics(Relation rel, const char *colName, Node *newValue, LOCKMODE lockmode)
05012 {
05013
05014
05015
05016
05017
05018
05019 if (rel->rd_rel->relkind != RELKIND_RELATION &&
05020 rel->rd_rel->relkind != RELKIND_MATVIEW &&
05021 rel->rd_rel->relkind != RELKIND_INDEX &&
05022 rel->rd_rel->relkind != RELKIND_FOREIGN_TABLE)
05023 ereport(ERROR,
05024 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
05025 errmsg("\"%s\" is not a table, materialized view, index, or foreign table",
05026 RelationGetRelationName(rel))));
05027
05028
05029 if (!pg_class_ownercheck(RelationGetRelid(rel), GetUserId()))
05030 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS,
05031 RelationGetRelationName(rel));
05032 }
05033
05034 static void
05035 ATExecSetStatistics(Relation rel, const char *colName, Node *newValue, LOCKMODE lockmode)
05036 {
05037 int newtarget;
05038 Relation attrelation;
05039 HeapTuple tuple;
05040 Form_pg_attribute attrtuple;
05041
05042 Assert(IsA(newValue, Integer));
05043 newtarget = intVal(newValue);
05044
05045
05046
05047
05048 if (newtarget < -1)
05049 {
05050 ereport(ERROR,
05051 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
05052 errmsg("statistics target %d is too low",
05053 newtarget)));
05054 }
05055 else if (newtarget > 10000)
05056 {
05057 newtarget = 10000;
05058 ereport(WARNING,
05059 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
05060 errmsg("lowering statistics target to %d",
05061 newtarget)));
05062 }
05063
05064 attrelation = heap_open(AttributeRelationId, RowExclusiveLock);
05065
05066 tuple = SearchSysCacheCopyAttName(RelationGetRelid(rel), colName);
05067
05068 if (!HeapTupleIsValid(tuple))
05069 ereport(ERROR,
05070 (errcode(ERRCODE_UNDEFINED_COLUMN),
05071 errmsg("column \"%s\" of relation \"%s\" does not exist",
05072 colName, RelationGetRelationName(rel))));
05073 attrtuple = (Form_pg_attribute) GETSTRUCT(tuple);
05074
05075 if (attrtuple->attnum <= 0)
05076 ereport(ERROR,
05077 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
05078 errmsg("cannot alter system column \"%s\"",
05079 colName)));
05080
05081 attrtuple->attstattarget = newtarget;
05082
05083 simple_heap_update(attrelation, &tuple->t_self, tuple);
05084
05085
05086 CatalogUpdateIndexes(attrelation, tuple);
05087
05088 InvokeObjectPostAlterHook(RelationRelationId,
05089 RelationGetRelid(rel),
05090 attrtuple->attnum);
05091 heap_freetuple(tuple);
05092
05093 heap_close(attrelation, RowExclusiveLock);
05094 }
05095
05096 static void
05097 ATExecSetOptions(Relation rel, const char *colName, Node *options,
05098 bool isReset, LOCKMODE lockmode)
05099 {
05100 Relation attrelation;
05101 HeapTuple tuple,
05102 newtuple;
05103 Form_pg_attribute attrtuple;
05104 Datum datum,
05105 newOptions;
05106 bool isnull;
05107 Datum repl_val[Natts_pg_attribute];
05108 bool repl_null[Natts_pg_attribute];
05109 bool repl_repl[Natts_pg_attribute];
05110
05111 attrelation = heap_open(AttributeRelationId, RowExclusiveLock);
05112
05113 tuple = SearchSysCacheAttName(RelationGetRelid(rel), colName);
05114
05115 if (!HeapTupleIsValid(tuple))
05116 ereport(ERROR,
05117 (errcode(ERRCODE_UNDEFINED_COLUMN),
05118 errmsg("column \"%s\" of relation \"%s\" does not exist",
05119 colName, RelationGetRelationName(rel))));
05120 attrtuple = (Form_pg_attribute) GETSTRUCT(tuple);
05121
05122 if (attrtuple->attnum <= 0)
05123 ereport(ERROR,
05124 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
05125 errmsg("cannot alter system column \"%s\"",
05126 colName)));
05127
05128
05129 Assert(IsA(options, List));
05130 datum = SysCacheGetAttr(ATTNAME, tuple, Anum_pg_attribute_attoptions,
05131 &isnull);
05132 newOptions = transformRelOptions(isnull ? (Datum) 0 : datum,
05133 (List *) options, NULL, NULL, false,
05134 isReset);
05135
05136 (void) attribute_reloptions(newOptions, true);
05137
05138
05139 memset(repl_null, false, sizeof(repl_null));
05140 memset(repl_repl, false, sizeof(repl_repl));
05141 if (newOptions != (Datum) 0)
05142 repl_val[Anum_pg_attribute_attoptions - 1] = newOptions;
05143 else
05144 repl_null[Anum_pg_attribute_attoptions - 1] = true;
05145 repl_repl[Anum_pg_attribute_attoptions - 1] = true;
05146 newtuple = heap_modify_tuple(tuple, RelationGetDescr(attrelation),
05147 repl_val, repl_null, repl_repl);
05148
05149
05150 simple_heap_update(attrelation, &newtuple->t_self, newtuple);
05151 CatalogUpdateIndexes(attrelation, newtuple);
05152
05153 InvokeObjectPostAlterHook(RelationRelationId,
05154 RelationGetRelid(rel),
05155 attrtuple->attnum);
05156 heap_freetuple(newtuple);
05157
05158 ReleaseSysCache(tuple);
05159
05160 heap_close(attrelation, RowExclusiveLock);
05161 }
05162
05163
05164
05165
05166 static void
05167 ATExecSetStorage(Relation rel, const char *colName, Node *newValue, LOCKMODE lockmode)
05168 {
05169 char *storagemode;
05170 char newstorage;
05171 Relation attrelation;
05172 HeapTuple tuple;
05173 Form_pg_attribute attrtuple;
05174
05175 Assert(IsA(newValue, String));
05176 storagemode = strVal(newValue);
05177
05178 if (pg_strcasecmp(storagemode, "plain") == 0)
05179 newstorage = 'p';
05180 else if (pg_strcasecmp(storagemode, "external") == 0)
05181 newstorage = 'e';
05182 else if (pg_strcasecmp(storagemode, "extended") == 0)
05183 newstorage = 'x';
05184 else if (pg_strcasecmp(storagemode, "main") == 0)
05185 newstorage = 'm';
05186 else
05187 {
05188 ereport(ERROR,
05189 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
05190 errmsg("invalid storage type \"%s\"",
05191 storagemode)));
05192 newstorage = 0;
05193 }
05194
05195 attrelation = heap_open(AttributeRelationId, RowExclusiveLock);
05196
05197 tuple = SearchSysCacheCopyAttName(RelationGetRelid(rel), colName);
05198
05199 if (!HeapTupleIsValid(tuple))
05200 ereport(ERROR,
05201 (errcode(ERRCODE_UNDEFINED_COLUMN),
05202 errmsg("column \"%s\" of relation \"%s\" does not exist",
05203 colName, RelationGetRelationName(rel))));
05204 attrtuple = (Form_pg_attribute) GETSTRUCT(tuple);
05205
05206 if (attrtuple->attnum <= 0)
05207 ereport(ERROR,
05208 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
05209 errmsg("cannot alter system column \"%s\"",
05210 colName)));
05211
05212
05213
05214
05215
05216 if (newstorage == 'p' || TypeIsToastable(attrtuple->atttypid))
05217 attrtuple->attstorage = newstorage;
05218 else
05219 ereport(ERROR,
05220 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
05221 errmsg("column data type %s can only have storage PLAIN",
05222 format_type_be(attrtuple->atttypid))));
05223
05224 simple_heap_update(attrelation, &tuple->t_self, tuple);
05225
05226
05227 CatalogUpdateIndexes(attrelation, tuple);
05228
05229 InvokeObjectPostAlterHook(RelationRelationId,
05230 RelationGetRelid(rel),
05231 attrtuple->attnum);
05232
05233 heap_freetuple(tuple);
05234
05235 heap_close(attrelation, RowExclusiveLock);
05236 }
05237
05238
05239
05240
05241
05242
05243
05244
05245
05246
05247
05248 static void
05249 ATPrepDropColumn(List **wqueue, Relation rel, bool recurse, bool recursing,
05250 AlterTableCmd *cmd, LOCKMODE lockmode)
05251 {
05252 if (rel->rd_rel->reloftype && !recursing)
05253 ereport(ERROR,
05254 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
05255 errmsg("cannot drop column from typed table")));
05256
05257 if (rel->rd_rel->relkind == RELKIND_COMPOSITE_TYPE)
05258 ATTypedTableRecursion(wqueue, rel, cmd, lockmode);
05259
05260 if (recurse)
05261 cmd->subtype = AT_DropColumnRecurse;
05262 }
05263
05264 static void
05265 ATExecDropColumn(List **wqueue, Relation rel, const char *colName,
05266 DropBehavior behavior,
05267 bool recurse, bool recursing,
05268 bool missing_ok, LOCKMODE lockmode)
05269 {
05270 HeapTuple tuple;
05271 Form_pg_attribute targetatt;
05272 AttrNumber attnum;
05273 List *children;
05274 ObjectAddress object;
05275
05276
05277 if (recursing)
05278 ATSimplePermissions(rel, ATT_TABLE);
05279
05280
05281
05282
05283 tuple = SearchSysCacheAttName(RelationGetRelid(rel), colName);
05284 if (!HeapTupleIsValid(tuple))
05285 {
05286 if (!missing_ok)
05287 {
05288 ereport(ERROR,
05289 (errcode(ERRCODE_UNDEFINED_COLUMN),
05290 errmsg("column \"%s\" of relation \"%s\" does not exist",
05291 colName, RelationGetRelationName(rel))));
05292 }
05293 else
05294 {
05295 ereport(NOTICE,
05296 (errmsg("column \"%s\" of relation \"%s\" does not exist, skipping",
05297 colName, RelationGetRelationName(rel))));
05298 return;
05299 }
05300 }
05301 targetatt = (Form_pg_attribute) GETSTRUCT(tuple);
05302
05303 attnum = targetatt->attnum;
05304
05305
05306 if (attnum <= 0 && attnum != ObjectIdAttributeNumber)
05307 ereport(ERROR,
05308 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
05309 errmsg("cannot drop system column \"%s\"",
05310 colName)));
05311
05312
05313 if (targetatt->attinhcount > 0 && !recursing)
05314 ereport(ERROR,
05315 (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
05316 errmsg("cannot drop inherited column \"%s\"",
05317 colName)));
05318
05319 ReleaseSysCache(tuple);
05320
05321
05322
05323
05324
05325
05326 children = find_inheritance_children(RelationGetRelid(rel), lockmode);
05327
05328 if (children)
05329 {
05330 Relation attr_rel;
05331 ListCell *child;
05332
05333 attr_rel = heap_open(AttributeRelationId, RowExclusiveLock);
05334 foreach(child, children)
05335 {
05336 Oid childrelid = lfirst_oid(child);
05337 Relation childrel;
05338 Form_pg_attribute childatt;
05339
05340
05341 childrel = heap_open(childrelid, NoLock);
05342 CheckTableNotInUse(childrel, "ALTER TABLE");
05343
05344 tuple = SearchSysCacheCopyAttName(childrelid, colName);
05345 if (!HeapTupleIsValid(tuple))
05346 elog(ERROR, "cache lookup failed for attribute \"%s\" of relation %u",
05347 colName, childrelid);
05348 childatt = (Form_pg_attribute) GETSTRUCT(tuple);
05349
05350 if (childatt->attinhcount <= 0)
05351 elog(ERROR, "relation %u has non-inherited attribute \"%s\"",
05352 childrelid, colName);
05353
05354 if (recurse)
05355 {
05356
05357
05358
05359
05360
05361 if (childatt->attinhcount == 1 && !childatt->attislocal)
05362 {
05363
05364 ATExecDropColumn(wqueue, childrel, colName,
05365 behavior, true, true,
05366 false, lockmode);
05367 }
05368 else
05369 {
05370
05371 childatt->attinhcount--;
05372
05373 simple_heap_update(attr_rel, &tuple->t_self, tuple);
05374
05375
05376 CatalogUpdateIndexes(attr_rel, tuple);
05377
05378
05379 CommandCounterIncrement();
05380 }
05381 }
05382 else
05383 {
05384
05385
05386
05387
05388
05389 childatt->attinhcount--;
05390 childatt->attislocal = true;
05391
05392 simple_heap_update(attr_rel, &tuple->t_self, tuple);
05393
05394
05395 CatalogUpdateIndexes(attr_rel, tuple);
05396
05397
05398 CommandCounterIncrement();
05399 }
05400
05401 heap_freetuple(tuple);
05402
05403 heap_close(childrel, NoLock);
05404 }
05405 heap_close(attr_rel, RowExclusiveLock);
05406 }
05407
05408
05409
05410
05411 object.classId = RelationRelationId;
05412 object.objectId = RelationGetRelid(rel);
05413 object.objectSubId = attnum;
05414
05415 performDeletion(&object, behavior, 0);
05416
05417
05418
05419
05420
05421
05422
05423 if (attnum == ObjectIdAttributeNumber)
05424 {
05425 Relation class_rel;
05426 Form_pg_class tuple_class;
05427 AlteredTableInfo *tab;
05428
05429 class_rel = heap_open(RelationRelationId, RowExclusiveLock);
05430
05431 tuple = SearchSysCacheCopy1(RELOID,
05432 ObjectIdGetDatum(RelationGetRelid(rel)));
05433 if (!HeapTupleIsValid(tuple))
05434 elog(ERROR, "cache lookup failed for relation %u",
05435 RelationGetRelid(rel));
05436 tuple_class = (Form_pg_class) GETSTRUCT(tuple);
05437
05438 tuple_class->relhasoids = false;
05439 simple_heap_update(class_rel, &tuple->t_self, tuple);
05440
05441
05442 CatalogUpdateIndexes(class_rel, tuple);
05443
05444 heap_close(class_rel, RowExclusiveLock);
05445
05446
05447 tab = ATGetQueueEntry(wqueue, rel);
05448
05449
05450 tab->rewrite = true;
05451 }
05452 }
05453
05454
05455
05456
05457
05458
05459
05460
05461 static void
05462 ATExecAddIndex(AlteredTableInfo *tab, Relation rel,
05463 IndexStmt *stmt, bool is_rebuild, LOCKMODE lockmode)
05464 {
05465 bool check_rights;
05466 bool skip_build;
05467 bool quiet;
05468 Oid new_index;
05469
05470 Assert(IsA(stmt, IndexStmt));
05471 Assert(!stmt->concurrent);
05472
05473
05474 check_rights = !is_rebuild;
05475
05476 skip_build = tab->rewrite || OidIsValid(stmt->oldNode);
05477
05478 quiet = is_rebuild;
05479
05480
05481
05482 new_index = DefineIndex(stmt,
05483 InvalidOid,
05484 true,
05485 check_rights,
05486 skip_build,
05487 quiet);
05488
05489
05490
05491
05492
05493
05494
05495 if (OidIsValid(stmt->oldNode))
05496 {
05497 Relation irel = index_open(new_index, NoLock);
05498
05499 RelationPreserveStorage(irel->rd_node, true);
05500 index_close(irel, NoLock);
05501 }
05502 }
05503
05504
05505
05506
05507 static void
05508 ATExecAddIndexConstraint(AlteredTableInfo *tab, Relation rel,
05509 IndexStmt *stmt, LOCKMODE lockmode)
05510 {
05511 Oid index_oid = stmt->indexOid;
05512 Relation indexRel;
05513 char *indexName;
05514 IndexInfo *indexInfo;
05515 char *constraintName;
05516 char constraintType;
05517
05518 Assert(IsA(stmt, IndexStmt));
05519 Assert(OidIsValid(index_oid));
05520 Assert(stmt->isconstraint);
05521
05522 indexRel = index_open(index_oid, AccessShareLock);
05523
05524 indexName = pstrdup(RelationGetRelationName(indexRel));
05525
05526 indexInfo = BuildIndexInfo(indexRel);
05527
05528
05529 if (!indexInfo->ii_Unique)
05530 elog(ERROR, "index \"%s\" is not unique", indexName);
05531
05532
05533
05534
05535
05536
05537
05538
05539 constraintName = stmt->idxname;
05540 if (constraintName == NULL)
05541 constraintName = indexName;
05542 else if (strcmp(constraintName, indexName) != 0)
05543 {
05544 ereport(NOTICE,
05545 (errmsg("ALTER TABLE / ADD CONSTRAINT USING INDEX will rename index \"%s\" to \"%s\"",
05546 indexName, constraintName)));
05547 RenameRelationInternal(index_oid, constraintName, false);
05548 }
05549
05550
05551 if (stmt->primary)
05552 index_check_primary_key(rel, indexInfo, true);
05553
05554
05555 if (stmt->primary)
05556 constraintType = CONSTRAINT_PRIMARY;
05557 else
05558 constraintType = CONSTRAINT_UNIQUE;
05559
05560
05561 index_constraint_create(rel,
05562 index_oid,
05563 indexInfo,
05564 constraintName,
05565 constraintType,
05566 stmt->deferrable,
05567 stmt->initdeferred,
05568 stmt->primary,
05569 true,
05570 true,
05571 allowSystemTableMods,
05572 false);
05573
05574 index_close(indexRel, NoLock);
05575 }
05576
05577
05578
05579
05580 static void
05581 ATExecAddConstraint(List **wqueue, AlteredTableInfo *tab, Relation rel,
05582 Constraint *newConstraint, bool recurse, bool is_readd,
05583 LOCKMODE lockmode)
05584 {
05585 Assert(IsA(newConstraint, Constraint));
05586
05587
05588
05589
05590
05591
05592 switch (newConstraint->contype)
05593 {
05594 case CONSTR_CHECK:
05595 ATAddCheckConstraint(wqueue, tab, rel,
05596 newConstraint, recurse, false, is_readd,
05597 lockmode);
05598 break;
05599
05600 case CONSTR_FOREIGN:
05601
05602
05603
05604
05605
05606
05607
05608 if (newConstraint->conname)
05609 {
05610 if (ConstraintNameIsUsed(CONSTRAINT_RELATION,
05611 RelationGetRelid(rel),
05612 RelationGetNamespace(rel),
05613 newConstraint->conname))
05614 ereport(ERROR,
05615 (errcode(ERRCODE_DUPLICATE_OBJECT),
05616 errmsg("constraint \"%s\" for relation \"%s\" already exists",
05617 newConstraint->conname,
05618 RelationGetRelationName(rel))));
05619 }
05620 else
05621 newConstraint->conname =
05622 ChooseConstraintName(RelationGetRelationName(rel),
05623 strVal(linitial(newConstraint->fk_attrs)),
05624 "fkey",
05625 RelationGetNamespace(rel),
05626 NIL);
05627
05628 ATAddForeignKeyConstraint(tab, rel, newConstraint, lockmode);
05629 break;
05630
05631 default:
05632 elog(ERROR, "unrecognized constraint type: %d",
05633 (int) newConstraint->contype);
05634 }
05635 }
05636
05637
05638
05639
05640
05641
05642
05643
05644
05645
05646
05647
05648
05649
05650
05651
05652
05653
05654
05655
05656
05657 static void
05658 ATAddCheckConstraint(List **wqueue, AlteredTableInfo *tab, Relation rel,
05659 Constraint *constr, bool recurse, bool recursing,
05660 bool is_readd, LOCKMODE lockmode)
05661 {
05662 List *newcons;
05663 ListCell *lcon;
05664 List *children;
05665 ListCell *child;
05666
05667
05668 if (recursing)
05669 ATSimplePermissions(rel, ATT_TABLE);
05670
05671
05672
05673
05674
05675
05676
05677
05678
05679
05680
05681 newcons = AddRelationNewConstraints(rel, NIL,
05682 list_make1(copyObject(constr)),
05683 recursing,
05684 !recursing,
05685 is_readd);
05686
05687
05688 foreach(lcon, newcons)
05689 {
05690 CookedConstraint *ccon = (CookedConstraint *) lfirst(lcon);
05691
05692 if (!ccon->skip_validation)
05693 {
05694 NewConstraint *newcon;
05695
05696 newcon = (NewConstraint *) palloc0(sizeof(NewConstraint));
05697 newcon->name = ccon->name;
05698 newcon->contype = ccon->contype;
05699
05700 newcon->qual = (Node *) make_ands_implicit((Expr *) ccon->expr);
05701
05702 tab->constraints = lappend(tab->constraints, newcon);
05703 }
05704
05705
05706 if (constr->conname == NULL)
05707 constr->conname = ccon->name;
05708 }
05709
05710
05711 Assert(constr->conname != NULL);
05712
05713
05714 CommandCounterIncrement();
05715
05716
05717
05718
05719
05720
05721
05722 if (newcons == NIL)
05723 return;
05724
05725
05726
05727
05728
05729
05730 if (constr->is_no_inherit || is_readd)
05731 return;
05732
05733
05734
05735
05736
05737
05738 children = find_inheritance_children(RelationGetRelid(rel), lockmode);
05739
05740
05741
05742
05743
05744
05745 if (!recurse && children != NIL)
05746 ereport(ERROR,
05747 (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
05748 errmsg("constraint must be added to child tables too")));
05749
05750 foreach(child, children)
05751 {
05752 Oid childrelid = lfirst_oid(child);
05753 Relation childrel;
05754 AlteredTableInfo *childtab;
05755
05756
05757 childrel = heap_open(childrelid, NoLock);
05758 CheckTableNotInUse(childrel, "ALTER TABLE");
05759
05760
05761 childtab = ATGetQueueEntry(wqueue, childrel);
05762
05763
05764 ATAddCheckConstraint(wqueue, childtab, childrel,
05765 constr, recurse, true, is_readd, lockmode);
05766
05767 heap_close(childrel, NoLock);
05768 }
05769 }
05770
05771
05772
05773
05774
05775
05776
05777
05778 static void
05779 ATAddForeignKeyConstraint(AlteredTableInfo *tab, Relation rel,
05780 Constraint *fkconstraint, LOCKMODE lockmode)
05781 {
05782 Relation pkrel;
05783 int16 pkattnum[INDEX_MAX_KEYS];
05784 int16 fkattnum[INDEX_MAX_KEYS];
05785 Oid pktypoid[INDEX_MAX_KEYS];
05786 Oid fktypoid[INDEX_MAX_KEYS];
05787 Oid opclasses[INDEX_MAX_KEYS];
05788 Oid pfeqoperators[INDEX_MAX_KEYS];
05789 Oid ppeqoperators[INDEX_MAX_KEYS];
05790 Oid ffeqoperators[INDEX_MAX_KEYS];
05791 int i;
05792 int numfks,
05793 numpks;
05794 Oid indexOid;
05795 Oid constrOid;
05796 bool old_check_ok;
05797 ListCell *old_pfeqop_item = list_head(fkconstraint->old_conpfeqop);
05798
05799
05800
05801
05802
05803
05804
05805
05806 pkrel = heap_openrv(fkconstraint->pktable, AccessExclusiveLock);
05807
05808
05809
05810
05811
05812 if (pkrel->rd_rel->relkind != RELKIND_RELATION)
05813 ereport(ERROR,
05814 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
05815 errmsg("referenced relation \"%s\" is not a table",
05816 RelationGetRelationName(pkrel))));
05817
05818 if (!allowSystemTableMods && IsSystemRelation(pkrel))
05819 ereport(ERROR,
05820 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
05821 errmsg("permission denied: \"%s\" is a system catalog",
05822 RelationGetRelationName(pkrel))));
05823
05824
05825
05826
05827
05828
05829
05830
05831
05832 switch (rel->rd_rel->relpersistence)
05833 {
05834 case RELPERSISTENCE_PERMANENT:
05835 if (pkrel->rd_rel->relpersistence != RELPERSISTENCE_PERMANENT)
05836 ereport(ERROR,
05837 (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
05838 errmsg("constraints on permanent tables may reference only permanent tables")));
05839 break;
05840 case RELPERSISTENCE_UNLOGGED:
05841 if (pkrel->rd_rel->relpersistence != RELPERSISTENCE_PERMANENT
05842 && pkrel->rd_rel->relpersistence != RELPERSISTENCE_UNLOGGED)
05843 ereport(ERROR,
05844 (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
05845 errmsg("constraints on unlogged tables may reference only permanent or unlogged tables")));
05846 break;
05847 case RELPERSISTENCE_TEMP:
05848 if (pkrel->rd_rel->relpersistence != RELPERSISTENCE_TEMP)
05849 ereport(ERROR,
05850 (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
05851 errmsg("constraints on temporary tables may reference only temporary tables")));
05852 if (!pkrel->rd_islocaltemp || !rel->rd_islocaltemp)
05853 ereport(ERROR,
05854 (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
05855 errmsg("constraints on temporary tables must involve temporary tables of this session")));
05856 break;
05857 }
05858
05859
05860
05861
05862
05863 MemSet(pkattnum, 0, sizeof(pkattnum));
05864 MemSet(fkattnum, 0, sizeof(fkattnum));
05865 MemSet(pktypoid, 0, sizeof(pktypoid));
05866 MemSet(fktypoid, 0, sizeof(fktypoid));
05867 MemSet(opclasses, 0, sizeof(opclasses));
05868 MemSet(pfeqoperators, 0, sizeof(pfeqoperators));
05869 MemSet(ppeqoperators, 0, sizeof(ppeqoperators));
05870 MemSet(ffeqoperators, 0, sizeof(ffeqoperators));
05871
05872 numfks = transformColumnNameList(RelationGetRelid(rel),
05873 fkconstraint->fk_attrs,
05874 fkattnum, fktypoid);
05875
05876
05877
05878
05879
05880
05881
05882 if (fkconstraint->pk_attrs == NIL)
05883 {
05884 numpks = transformFkeyGetPrimaryKey(pkrel, &indexOid,
05885 &fkconstraint->pk_attrs,
05886 pkattnum, pktypoid,
05887 opclasses);
05888 }
05889 else
05890 {
05891 numpks = transformColumnNameList(RelationGetRelid(pkrel),
05892 fkconstraint->pk_attrs,
05893 pkattnum, pktypoid);
05894
05895 indexOid = transformFkeyCheckAttrs(pkrel, numpks, pkattnum,
05896 opclasses);
05897 }
05898
05899
05900
05901
05902 checkFkeyPermissions(pkrel, pkattnum, numpks);
05903 checkFkeyPermissions(rel, fkattnum, numfks);
05904
05905
05906
05907
05908
05909
05910
05911
05912
05913 if (numfks != numpks)
05914 ereport(ERROR,
05915 (errcode(ERRCODE_INVALID_FOREIGN_KEY),
05916 errmsg("number of referencing and referenced columns for foreign key disagree")));
05917
05918
05919
05920
05921
05922 old_check_ok = (fkconstraint->old_conpfeqop != NIL);
05923 Assert(!old_check_ok || numfks == list_length(fkconstraint->old_conpfeqop));
05924
05925 for (i = 0; i < numpks; i++)
05926 {
05927 Oid pktype = pktypoid[i];
05928 Oid fktype = fktypoid[i];
05929 Oid fktyped;
05930 HeapTuple cla_ht;
05931 Form_pg_opclass cla_tup;
05932 Oid amid;
05933 Oid opfamily;
05934 Oid opcintype;
05935 Oid pfeqop;
05936 Oid ppeqop;
05937 Oid ffeqop;
05938 int16 eqstrategy;
05939 Oid pfeqop_right;
05940
05941
05942 cla_ht = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclasses[i]));
05943 if (!HeapTupleIsValid(cla_ht))
05944 elog(ERROR, "cache lookup failed for opclass %u", opclasses[i]);
05945 cla_tup = (Form_pg_opclass) GETSTRUCT(cla_ht);
05946 amid = cla_tup->opcmethod;
05947 opfamily = cla_tup->opcfamily;
05948 opcintype = cla_tup->opcintype;
05949 ReleaseSysCache(cla_ht);
05950
05951
05952
05953
05954
05955
05956
05957
05958 if (amid != BTREE_AM_OID)
05959 elog(ERROR, "only b-tree indexes are supported for foreign keys");
05960 eqstrategy = BTEqualStrategyNumber;
05961
05962
05963
05964
05965
05966 ppeqop = get_opfamily_member(opfamily, opcintype, opcintype,
05967 eqstrategy);
05968
05969 if (!OidIsValid(ppeqop))
05970 elog(ERROR, "missing operator %d(%u,%u) in opfamily %u",
05971 eqstrategy, opcintype, opcintype, opfamily);
05972
05973
05974
05975
05976
05977 fktyped = getBaseType(fktype);
05978
05979 pfeqop = get_opfamily_member(opfamily, opcintype, fktyped,
05980 eqstrategy);
05981 if (OidIsValid(pfeqop))
05982 {
05983 pfeqop_right = fktyped;
05984 ffeqop = get_opfamily_member(opfamily, fktyped, fktyped,
05985 eqstrategy);
05986 }
05987 else
05988 {
05989
05990 pfeqop_right = InvalidOid;
05991 ffeqop = InvalidOid;
05992 }
05993
05994 if (!(OidIsValid(pfeqop) && OidIsValid(ffeqop)))
05995 {
05996
05997
05998
05999
06000
06001
06002
06003
06004
06005 Oid input_typeids[2];
06006 Oid target_typeids[2];
06007
06008 input_typeids[0] = pktype;
06009 input_typeids[1] = fktype;
06010 target_typeids[0] = opcintype;
06011 target_typeids[1] = opcintype;
06012 if (can_coerce_type(2, input_typeids, target_typeids,
06013 COERCION_IMPLICIT))
06014 {
06015 pfeqop = ffeqop = ppeqop;
06016 pfeqop_right = opcintype;
06017 }
06018 }
06019
06020 if (!(OidIsValid(pfeqop) && OidIsValid(ffeqop)))
06021 ereport(ERROR,
06022 (errcode(ERRCODE_DATATYPE_MISMATCH),
06023 errmsg("foreign key constraint \"%s\" "
06024 "cannot be implemented",
06025 fkconstraint->conname),
06026 errdetail("Key columns \"%s\" and \"%s\" "
06027 "are of incompatible types: %s and %s.",
06028 strVal(list_nth(fkconstraint->fk_attrs, i)),
06029 strVal(list_nth(fkconstraint->pk_attrs, i)),
06030 format_type_be(fktype),
06031 format_type_be(pktype))));
06032
06033 if (old_check_ok)
06034 {
06035
06036
06037
06038
06039
06040
06041 old_check_ok = (pfeqop == lfirst_oid(old_pfeqop_item));
06042 old_pfeqop_item = lnext(old_pfeqop_item);
06043 }
06044 if (old_check_ok)
06045 {
06046 Oid old_fktype;
06047 Oid new_fktype;
06048 CoercionPathType old_pathtype;
06049 CoercionPathType new_pathtype;
06050 Oid old_castfunc;
06051 Oid new_castfunc;
06052
06053
06054
06055
06056
06057
06058 old_fktype = tab->oldDesc->attrs[fkattnum[i] - 1]->atttypid;
06059 new_fktype = fktype;
06060 old_pathtype = findFkeyCast(pfeqop_right, old_fktype,
06061 &old_castfunc);
06062 new_pathtype = findFkeyCast(pfeqop_right, new_fktype,
06063 &new_castfunc);
06064
06065
06066
06067
06068
06069
06070
06071
06072
06073
06074
06075
06076
06077
06078
06079
06080
06081
06082
06083
06084
06085
06086
06087
06088
06089
06090
06091
06092
06093
06094
06095
06096
06097 old_check_ok = (new_pathtype == old_pathtype &&
06098 new_castfunc == old_castfunc &&
06099 (!IsPolymorphicType(pfeqop_right) ||
06100 new_fktype == old_fktype));
06101
06102 }
06103
06104 pfeqoperators[i] = pfeqop;
06105 ppeqoperators[i] = ppeqop;
06106 ffeqoperators[i] = ffeqop;
06107 }
06108
06109
06110
06111
06112 constrOid = CreateConstraintEntry(fkconstraint->conname,
06113 RelationGetNamespace(rel),
06114 CONSTRAINT_FOREIGN,
06115 fkconstraint->deferrable,
06116 fkconstraint->initdeferred,
06117 fkconstraint->initially_valid,
06118 RelationGetRelid(rel),
06119 fkattnum,
06120 numfks,
06121 InvalidOid,
06122
06123 indexOid,
06124 RelationGetRelid(pkrel),
06125 pkattnum,
06126 pfeqoperators,
06127 ppeqoperators,
06128 ffeqoperators,
06129 numpks,
06130 fkconstraint->fk_upd_action,
06131 fkconstraint->fk_del_action,
06132 fkconstraint->fk_matchtype,
06133 NULL,
06134 NULL,
06135 NULL,
06136 NULL,
06137 true,
06138 0,
06139 true,
06140 false);
06141
06142
06143
06144
06145 createForeignKeyTriggers(rel, fkconstraint, constrOid, indexOid);
06146
06147
06148
06149
06150
06151
06152
06153
06154 if (!old_check_ok && !fkconstraint->skip_validation)
06155 {
06156 NewConstraint *newcon;
06157
06158 newcon = (NewConstraint *) palloc0(sizeof(NewConstraint));
06159 newcon->name = fkconstraint->conname;
06160 newcon->contype = CONSTR_FOREIGN;
06161 newcon->refrelid = RelationGetRelid(pkrel);
06162 newcon->refindid = indexOid;
06163 newcon->conid = constrOid;
06164 newcon->qual = (Node *) fkconstraint;
06165
06166 tab->constraints = lappend(tab->constraints, newcon);
06167 }
06168
06169
06170
06171
06172 heap_close(pkrel, NoLock);
06173 }
06174
06175
06176
06177
06178
06179
06180
06181
06182
06183 static void
06184 ATExecValidateConstraint(Relation rel, char *constrName, bool recurse,
06185 bool recursing, LOCKMODE lockmode)
06186 {
06187 Relation conrel;
06188 SysScanDesc scan;
06189 ScanKeyData key;
06190 HeapTuple tuple;
06191 Form_pg_constraint con = NULL;
06192 bool found = false;
06193
06194 conrel = heap_open(ConstraintRelationId, RowExclusiveLock);
06195
06196
06197
06198
06199 ScanKeyInit(&key,
06200 Anum_pg_constraint_conrelid,
06201 BTEqualStrategyNumber, F_OIDEQ,
06202 ObjectIdGetDatum(RelationGetRelid(rel)));
06203 scan = systable_beginscan(conrel, ConstraintRelidIndexId,
06204 true, SnapshotNow, 1, &key);
06205
06206 while (HeapTupleIsValid(tuple = systable_getnext(scan)))
06207 {
06208 con = (Form_pg_constraint) GETSTRUCT(tuple);
06209 if (strcmp(NameStr(con->conname), constrName) == 0)
06210 {
06211 found = true;
06212 break;
06213 }
06214 }
06215
06216 if (!found)
06217 ereport(ERROR,
06218 (errcode(ERRCODE_UNDEFINED_OBJECT),
06219 errmsg("constraint \"%s\" of relation \"%s\" does not exist",
06220 constrName, RelationGetRelationName(rel))));
06221
06222 if (con->contype != CONSTRAINT_FOREIGN &&
06223 con->contype != CONSTRAINT_CHECK)
06224 ereport(ERROR,
06225 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
06226 errmsg("constraint \"%s\" of relation \"%s\" is not a foreign key or check constraint",
06227 constrName, RelationGetRelationName(rel))));
06228
06229 if (!con->convalidated)
06230 {
06231 HeapTuple copyTuple;
06232 Form_pg_constraint copy_con;
06233
06234 if (con->contype == CONSTRAINT_FOREIGN)
06235 {
06236 Oid conid = HeapTupleGetOid(tuple);
06237 Relation refrel;
06238
06239
06240
06241
06242
06243
06244
06245
06246
06247 refrel = heap_open(con->confrelid, RowShareLock);
06248
06249 validateForeignKeyConstraint(constrName, rel, refrel,
06250 con->conindid,
06251 conid);
06252 heap_close(refrel, NoLock);
06253
06254
06255
06256
06257
06258 }
06259 else if (con->contype == CONSTRAINT_CHECK)
06260 {
06261 List *children = NIL;
06262 ListCell *child;
06263
06264
06265
06266
06267
06268 if (!recursing)
06269 children = find_all_inheritors(RelationGetRelid(rel),
06270 lockmode, NULL);
06271
06272
06273
06274
06275
06276
06277
06278
06279
06280 foreach(child, children)
06281 {
06282 Oid childoid = lfirst_oid(child);
06283 Relation childrel;
06284
06285 if (childoid == RelationGetRelid(rel))
06286 continue;
06287
06288
06289
06290
06291
06292 if (!recurse)
06293 ereport(ERROR,
06294 (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
06295 errmsg("constraint must be validated on child tables too")));
06296
06297
06298 childrel = heap_open(childoid, NoLock);
06299
06300 ATExecValidateConstraint(childrel, constrName, false,
06301 true, lockmode);
06302 heap_close(childrel, NoLock);
06303 }
06304
06305 validateCheckConstraint(rel, tuple);
06306
06307
06308
06309
06310
06311 CacheInvalidateRelcache(rel);
06312 }
06313
06314
06315
06316
06317 copyTuple = heap_copytuple(tuple);
06318 copy_con = (Form_pg_constraint) GETSTRUCT(copyTuple);
06319 copy_con->convalidated = true;
06320 simple_heap_update(conrel, ©Tuple->t_self, copyTuple);
06321 CatalogUpdateIndexes(conrel, copyTuple);
06322
06323 InvokeObjectPostAlterHook(ConstraintRelationId,
06324 HeapTupleGetOid(tuple), 0);
06325
06326 heap_freetuple(copyTuple);
06327 }
06328
06329 systable_endscan(scan);
06330
06331 heap_close(conrel, RowExclusiveLock);
06332 }
06333
06334
06335
06336
06337
06338
06339
06340 static int
06341 transformColumnNameList(Oid relId, List *colList,
06342 int16 *attnums, Oid *atttypids)
06343 {
06344 ListCell *l;
06345 int attnum;
06346
06347 attnum = 0;
06348 foreach(l, colList)
06349 {
06350 char *attname = strVal(lfirst(l));
06351 HeapTuple atttuple;
06352
06353 atttuple = SearchSysCacheAttName(relId, attname);
06354 if (!HeapTupleIsValid(atttuple))
06355 ereport(ERROR,
06356 (errcode(ERRCODE_UNDEFINED_COLUMN),
06357 errmsg("column \"%s\" referenced in foreign key constraint does not exist",
06358 attname)));
06359 if (attnum >= INDEX_MAX_KEYS)
06360 ereport(ERROR,
06361 (errcode(ERRCODE_TOO_MANY_COLUMNS),
06362 errmsg("cannot have more than %d keys in a foreign key",
06363 INDEX_MAX_KEYS)));
06364 attnums[attnum] = ((Form_pg_attribute) GETSTRUCT(atttuple))->attnum;
06365 atttypids[attnum] = ((Form_pg_attribute) GETSTRUCT(atttuple))->atttypid;
06366 ReleaseSysCache(atttuple);
06367 attnum++;
06368 }
06369
06370 return attnum;
06371 }
06372
06373
06374
06375
06376
06377
06378
06379
06380
06381
06382
06383
06384
06385 static int
06386 transformFkeyGetPrimaryKey(Relation pkrel, Oid *indexOid,
06387 List **attnamelist,
06388 int16 *attnums, Oid *atttypids,
06389 Oid *opclasses)
06390 {
06391 List *indexoidlist;
06392 ListCell *indexoidscan;
06393 HeapTuple indexTuple = NULL;
06394 Form_pg_index indexStruct = NULL;
06395 Datum indclassDatum;
06396 bool isnull;
06397 oidvector *indclass;
06398 int i;
06399
06400
06401
06402
06403
06404
06405 *indexOid = InvalidOid;
06406
06407 indexoidlist = RelationGetIndexList(pkrel);
06408
06409 foreach(indexoidscan, indexoidlist)
06410 {
06411 Oid indexoid = lfirst_oid(indexoidscan);
06412
06413 indexTuple = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(indexoid));
06414 if (!HeapTupleIsValid(indexTuple))
06415 elog(ERROR, "cache lookup failed for index %u", indexoid);
06416 indexStruct = (Form_pg_index) GETSTRUCT(indexTuple);
06417 if (indexStruct->indisprimary && IndexIsValid(indexStruct))
06418 {
06419
06420
06421
06422
06423
06424 if (!indexStruct->indimmediate)
06425 ereport(ERROR,
06426 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
06427 errmsg("cannot use a deferrable primary key for referenced table \"%s\"",
06428 RelationGetRelationName(pkrel))));
06429
06430 *indexOid = indexoid;
06431 break;
06432 }
06433 ReleaseSysCache(indexTuple);
06434 }
06435
06436 list_free(indexoidlist);
06437
06438
06439
06440
06441 if (!OidIsValid(*indexOid))
06442 ereport(ERROR,
06443 (errcode(ERRCODE_UNDEFINED_OBJECT),
06444 errmsg("there is no primary key for referenced table \"%s\"",
06445 RelationGetRelationName(pkrel))));
06446
06447
06448 indclassDatum = SysCacheGetAttr(INDEXRELID, indexTuple,
06449 Anum_pg_index_indclass, &isnull);
06450 Assert(!isnull);
06451 indclass = (oidvector *) DatumGetPointer(indclassDatum);
06452
06453
06454
06455
06456
06457 *attnamelist = NIL;
06458 for (i = 0; i < indexStruct->indnatts; i++)
06459 {
06460 int pkattno = indexStruct->indkey.values[i];
06461
06462 attnums[i] = pkattno;
06463 atttypids[i] = attnumTypeId(pkrel, pkattno);
06464 opclasses[i] = indclass->values[i];
06465 *attnamelist = lappend(*attnamelist,
06466 makeString(pstrdup(NameStr(*attnumAttName(pkrel, pkattno)))));
06467 }
06468
06469 ReleaseSysCache(indexTuple);
06470
06471 return i;
06472 }
06473
06474
06475
06476
06477
06478
06479
06480
06481
06482 static Oid
06483 transformFkeyCheckAttrs(Relation pkrel,
06484 int numattrs, int16 *attnums,
06485 Oid *opclasses)
06486 {
06487 Oid indexoid = InvalidOid;
06488 bool found = false;
06489 bool found_deferrable = false;
06490 List *indexoidlist;
06491 ListCell *indexoidscan;
06492
06493
06494
06495
06496
06497
06498 indexoidlist = RelationGetIndexList(pkrel);
06499
06500 foreach(indexoidscan, indexoidlist)
06501 {
06502 HeapTuple indexTuple;
06503 Form_pg_index indexStruct;
06504 int i,
06505 j;
06506
06507 indexoid = lfirst_oid(indexoidscan);
06508 indexTuple = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(indexoid));
06509 if (!HeapTupleIsValid(indexTuple))
06510 elog(ERROR, "cache lookup failed for index %u", indexoid);
06511 indexStruct = (Form_pg_index) GETSTRUCT(indexTuple);
06512
06513
06514
06515
06516
06517
06518 if (indexStruct->indnatts == numattrs &&
06519 indexStruct->indisunique &&
06520 IndexIsValid(indexStruct) &&
06521 heap_attisnull(indexTuple, Anum_pg_index_indpred) &&
06522 heap_attisnull(indexTuple, Anum_pg_index_indexprs))
06523 {
06524
06525 Datum indclassDatum;
06526 bool isnull;
06527 oidvector *indclass;
06528
06529 indclassDatum = SysCacheGetAttr(INDEXRELID, indexTuple,
06530 Anum_pg_index_indclass, &isnull);
06531 Assert(!isnull);
06532 indclass = (oidvector *) DatumGetPointer(indclassDatum);
06533
06534
06535
06536
06537
06538 for (i = 0; i < numattrs; i++)
06539 {
06540 found = false;
06541 for (j = 0; j < numattrs; j++)
06542 {
06543 if (attnums[i] == indexStruct->indkey.values[j])
06544 {
06545 found = true;
06546 break;
06547 }
06548 }
06549 if (!found)
06550 break;
06551 }
06552 if (found)
06553 {
06554 for (i = 0; i < numattrs; i++)
06555 {
06556 found = false;
06557 for (j = 0; j < numattrs; j++)
06558 {
06559 if (attnums[j] == indexStruct->indkey.values[i])
06560 {
06561 opclasses[j] = indclass->values[i];
06562 found = true;
06563 break;
06564 }
06565 }
06566 if (!found)
06567 break;
06568 }
06569 }
06570
06571
06572
06573
06574
06575
06576 if (found && !indexStruct->indimmediate)
06577 {
06578
06579
06580
06581
06582 found_deferrable = true;
06583 found = false;
06584 }
06585 }
06586 ReleaseSysCache(indexTuple);
06587 if (found)
06588 break;
06589 }
06590
06591 if (!found)
06592 {
06593 if (found_deferrable)
06594 ereport(ERROR,
06595 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
06596 errmsg("cannot use a deferrable unique constraint for referenced table \"%s\"",
06597 RelationGetRelationName(pkrel))));
06598 else
06599 ereport(ERROR,
06600 (errcode(ERRCODE_INVALID_FOREIGN_KEY),
06601 errmsg("there is no unique constraint matching given keys for referenced table \"%s\"",
06602 RelationGetRelationName(pkrel))));
06603 }
06604
06605 list_free(indexoidlist);
06606
06607 return indexoid;
06608 }
06609
06610
06611
06612
06613
06614
06615
06616 static CoercionPathType
06617 findFkeyCast(Oid targetTypeId, Oid sourceTypeId, Oid *funcid)
06618 {
06619 CoercionPathType ret;
06620
06621 if (targetTypeId == sourceTypeId)
06622 {
06623 ret = COERCION_PATH_RELABELTYPE;
06624 *funcid = InvalidOid;
06625 }
06626 else
06627 {
06628 ret = find_coercion_pathway(targetTypeId, sourceTypeId,
06629 COERCION_IMPLICIT, funcid);
06630 if (ret == COERCION_PATH_NONE)
06631
06632 elog(ERROR, "could not find cast from %u to %u",
06633 sourceTypeId, targetTypeId);
06634 }
06635
06636 return ret;
06637 }
06638
06639
06640 static void
06641 checkFkeyPermissions(Relation rel, int16 *attnums, int natts)
06642 {
06643 Oid roleid = GetUserId();
06644 AclResult aclresult;
06645 int i;
06646
06647
06648 aclresult = pg_class_aclcheck(RelationGetRelid(rel), roleid,
06649 ACL_REFERENCES);
06650 if (aclresult == ACLCHECK_OK)
06651 return;
06652
06653 for (i = 0; i < natts; i++)
06654 {
06655 aclresult = pg_attribute_aclcheck(RelationGetRelid(rel), attnums[i],
06656 roleid, ACL_REFERENCES);
06657 if (aclresult != ACLCHECK_OK)
06658 aclcheck_error(aclresult, ACL_KIND_CLASS,
06659 RelationGetRelationName(rel));
06660 }
06661 }
06662
06663
06664
06665
06666
06667
06668
06669 static void
06670 validateCheckConstraint(Relation rel, HeapTuple constrtup)
06671 {
06672 EState *estate;
06673 Datum val;
06674 char *conbin;
06675 Expr *origexpr;
06676 List *exprstate;
06677 TupleDesc tupdesc;
06678 HeapScanDesc scan;
06679 HeapTuple tuple;
06680 ExprContext *econtext;
06681 MemoryContext oldcxt;
06682 TupleTableSlot *slot;
06683 Form_pg_constraint constrForm;
06684 bool isnull;
06685
06686 constrForm = (Form_pg_constraint) GETSTRUCT(constrtup);
06687
06688 estate = CreateExecutorState();
06689
06690
06691
06692
06693
06694
06695 val = SysCacheGetAttr(CONSTROID, constrtup, Anum_pg_constraint_conbin,
06696 &isnull);
06697 if (isnull)
06698 elog(ERROR, "null conbin for constraint %u",
06699 HeapTupleGetOid(constrtup));
06700 conbin = TextDatumGetCString(val);
06701 origexpr = (Expr *) stringToNode(conbin);
06702 exprstate = (List *)
06703 ExecPrepareExpr((Expr *) make_ands_implicit(origexpr), estate);
06704
06705 econtext = GetPerTupleExprContext(estate);
06706 tupdesc = RelationGetDescr(rel);
06707 slot = MakeSingleTupleTableSlot(tupdesc);
06708 econtext->ecxt_scantuple = slot;
06709
06710 scan = heap_beginscan(rel, SnapshotNow, 0, NULL);
06711
06712
06713
06714
06715
06716 oldcxt = MemoryContextSwitchTo(GetPerTupleMemoryContext(estate));
06717
06718 while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
06719 {
06720 ExecStoreTuple(tuple, slot, InvalidBuffer, false);
06721
06722 if (!ExecQual(exprstate, econtext, true))
06723 ereport(ERROR,
06724 (errcode(ERRCODE_CHECK_VIOLATION),
06725 errmsg("check constraint \"%s\" is violated by some row",
06726 NameStr(constrForm->conname)),
06727 errtableconstraint(rel, NameStr(constrForm->conname))));
06728
06729 ResetExprContext(econtext);
06730 }
06731
06732 MemoryContextSwitchTo(oldcxt);
06733 heap_endscan(scan);
06734 ExecDropSingleTupleTableSlot(slot);
06735 FreeExecutorState(estate);
06736 }
06737
06738
06739
06740
06741
06742
06743
06744 static void
06745 validateForeignKeyConstraint(char *conname,
06746 Relation rel,
06747 Relation pkrel,
06748 Oid pkindOid,
06749 Oid constraintOid)
06750 {
06751 HeapScanDesc scan;
06752 HeapTuple tuple;
06753 Trigger trig;
06754
06755 ereport(DEBUG1,
06756 (errmsg("validating foreign key constraint \"%s\"", conname)));
06757
06758
06759
06760
06761 MemSet(&trig, 0, sizeof(trig));
06762 trig.tgoid = InvalidOid;
06763 trig.tgname = conname;
06764 trig.tgenabled = TRIGGER_FIRES_ON_ORIGIN;
06765 trig.tgisinternal = TRUE;
06766 trig.tgconstrrelid = RelationGetRelid(pkrel);
06767 trig.tgconstrindid = pkindOid;
06768 trig.tgconstraint = constraintOid;
06769 trig.tgdeferrable = FALSE;
06770 trig.tginitdeferred = FALSE;
06771
06772
06773
06774
06775
06776
06777 if (RI_Initial_Check(&trig, rel, pkrel))
06778 return;
06779
06780
06781
06782
06783
06784
06785 scan = heap_beginscan(rel, SnapshotNow, 0, NULL);
06786
06787 while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
06788 {
06789 FunctionCallInfoData fcinfo;
06790 TriggerData trigdata;
06791
06792
06793
06794
06795
06796
06797 MemSet(&fcinfo, 0, sizeof(fcinfo));
06798
06799
06800
06801
06802 trigdata.type = T_TriggerData;
06803 trigdata.tg_event = TRIGGER_EVENT_INSERT | TRIGGER_EVENT_ROW;
06804 trigdata.tg_relation = rel;
06805 trigdata.tg_trigtuple = tuple;
06806 trigdata.tg_newtuple = NULL;
06807 trigdata.tg_trigger = &trig;
06808 trigdata.tg_trigtuplebuf = scan->rs_cbuf;
06809 trigdata.tg_newtuplebuf = InvalidBuffer;
06810
06811 fcinfo.context = (Node *) &trigdata;
06812
06813 RI_FKey_check_ins(&fcinfo);
06814 }
06815
06816 heap_endscan(scan);
06817 }
06818
06819 static void
06820 CreateFKCheckTrigger(RangeVar *myRel, Constraint *fkconstraint,
06821 Oid constraintOid, Oid indexOid, bool on_insert)
06822 {
06823 CreateTrigStmt *fk_trigger;
06824
06825
06826
06827
06828
06829
06830
06831
06832
06833
06834 fk_trigger = makeNode(CreateTrigStmt);
06835 fk_trigger->trigname = "RI_ConstraintTrigger_c";
06836 fk_trigger->relation = myRel;
06837 fk_trigger->row = true;
06838 fk_trigger->timing = TRIGGER_TYPE_AFTER;
06839
06840
06841 if (on_insert)
06842 {
06843 fk_trigger->funcname = SystemFuncName("RI_FKey_check_ins");
06844 fk_trigger->events = TRIGGER_TYPE_INSERT;
06845 }
06846 else
06847 {
06848 fk_trigger->funcname = SystemFuncName("RI_FKey_check_upd");
06849 fk_trigger->events = TRIGGER_TYPE_UPDATE;
06850 }
06851
06852 fk_trigger->columns = NIL;
06853 fk_trigger->whenClause = NULL;
06854 fk_trigger->isconstraint = true;
06855 fk_trigger->deferrable = fkconstraint->deferrable;
06856 fk_trigger->initdeferred = fkconstraint->initdeferred;
06857 fk_trigger->constrrel = fkconstraint->pktable;
06858 fk_trigger->args = NIL;
06859
06860 (void) CreateTrigger(fk_trigger, NULL, constraintOid, indexOid, true);
06861
06862
06863 CommandCounterIncrement();
06864 }
06865
06866
06867
06868
06869 static void
06870 createForeignKeyTriggers(Relation rel, Constraint *fkconstraint,
06871 Oid constraintOid, Oid indexOid)
06872 {
06873 RangeVar *myRel;
06874 CreateTrigStmt *fk_trigger;
06875
06876
06877
06878
06879 myRel = makeRangeVar(get_namespace_name(RelationGetNamespace(rel)),
06880 pstrdup(RelationGetRelationName(rel)),
06881 -1);
06882
06883
06884 CommandCounterIncrement();
06885
06886
06887
06888
06889
06890 fk_trigger = makeNode(CreateTrigStmt);
06891 fk_trigger->trigname = "RI_ConstraintTrigger_a";
06892 fk_trigger->relation = fkconstraint->pktable;
06893 fk_trigger->row = true;
06894 fk_trigger->timing = TRIGGER_TYPE_AFTER;
06895 fk_trigger->events = TRIGGER_TYPE_DELETE;
06896 fk_trigger->columns = NIL;
06897 fk_trigger->whenClause = NULL;
06898 fk_trigger->isconstraint = true;
06899 fk_trigger->constrrel = myRel;
06900 switch (fkconstraint->fk_del_action)
06901 {
06902 case FKCONSTR_ACTION_NOACTION:
06903 fk_trigger->deferrable = fkconstraint->deferrable;
06904 fk_trigger->initdeferred = fkconstraint->initdeferred;
06905 fk_trigger->funcname = SystemFuncName("RI_FKey_noaction_del");
06906 break;
06907 case FKCONSTR_ACTION_RESTRICT:
06908 fk_trigger->deferrable = false;
06909 fk_trigger->initdeferred = false;
06910 fk_trigger->funcname = SystemFuncName("RI_FKey_restrict_del");
06911 break;
06912 case FKCONSTR_ACTION_CASCADE:
06913 fk_trigger->deferrable = false;
06914 fk_trigger->initdeferred = false;
06915 fk_trigger->funcname = SystemFuncName("RI_FKey_cascade_del");
06916 break;
06917 case FKCONSTR_ACTION_SETNULL:
06918 fk_trigger->deferrable = false;
06919 fk_trigger->initdeferred = false;
06920 fk_trigger->funcname = SystemFuncName("RI_FKey_setnull_del");
06921 break;
06922 case FKCONSTR_ACTION_SETDEFAULT:
06923 fk_trigger->deferrable = false;
06924 fk_trigger->initdeferred = false;
06925 fk_trigger->funcname = SystemFuncName("RI_FKey_setdefault_del");
06926 break;
06927 default:
06928 elog(ERROR, "unrecognized FK action type: %d",
06929 (int) fkconstraint->fk_del_action);
06930 break;
06931 }
06932 fk_trigger->args = NIL;
06933
06934 (void) CreateTrigger(fk_trigger, NULL, constraintOid, indexOid, true);
06935
06936
06937 CommandCounterIncrement();
06938
06939
06940
06941
06942
06943 fk_trigger = makeNode(CreateTrigStmt);
06944 fk_trigger->trigname = "RI_ConstraintTrigger_a";
06945 fk_trigger->relation = fkconstraint->pktable;
06946 fk_trigger->row = true;
06947 fk_trigger->timing = TRIGGER_TYPE_AFTER;
06948 fk_trigger->events = TRIGGER_TYPE_UPDATE;
06949 fk_trigger->columns = NIL;
06950 fk_trigger->whenClause = NULL;
06951 fk_trigger->isconstraint = true;
06952 fk_trigger->constrrel = myRel;
06953 switch (fkconstraint->fk_upd_action)
06954 {
06955 case FKCONSTR_ACTION_NOACTION:
06956 fk_trigger->deferrable = fkconstraint->deferrable;
06957 fk_trigger->initdeferred = fkconstraint->initdeferred;
06958 fk_trigger->funcname = SystemFuncName("RI_FKey_noaction_upd");
06959 break;
06960 case FKCONSTR_ACTION_RESTRICT:
06961 fk_trigger->deferrable = false;
06962 fk_trigger->initdeferred = false;
06963 fk_trigger->funcname = SystemFuncName("RI_FKey_restrict_upd");
06964 break;
06965 case FKCONSTR_ACTION_CASCADE:
06966 fk_trigger->deferrable = false;
06967 fk_trigger->initdeferred = false;
06968 fk_trigger->funcname = SystemFuncName("RI_FKey_cascade_upd");
06969 break;
06970 case FKCONSTR_ACTION_SETNULL:
06971 fk_trigger->deferrable = false;
06972 fk_trigger->initdeferred = false;
06973 fk_trigger->funcname = SystemFuncName("RI_FKey_setnull_upd");
06974 break;
06975 case FKCONSTR_ACTION_SETDEFAULT:
06976 fk_trigger->deferrable = false;
06977 fk_trigger->initdeferred = false;
06978 fk_trigger->funcname = SystemFuncName("RI_FKey_setdefault_upd");
06979 break;
06980 default:
06981 elog(ERROR, "unrecognized FK action type: %d",
06982 (int) fkconstraint->fk_upd_action);
06983 break;
06984 }
06985 fk_trigger->args = NIL;
06986
06987 (void) CreateTrigger(fk_trigger, NULL, constraintOid, indexOid, true);
06988
06989
06990 CommandCounterIncrement();
06991
06992
06993
06994
06995
06996 CreateFKCheckTrigger(myRel, fkconstraint, constraintOid, indexOid, true);
06997 CreateFKCheckTrigger(myRel, fkconstraint, constraintOid, indexOid, false);
06998 }
06999
07000
07001
07002
07003
07004
07005 static void
07006 ATExecDropConstraint(Relation rel, const char *constrName,
07007 DropBehavior behavior,
07008 bool recurse, bool recursing,
07009 bool missing_ok, LOCKMODE lockmode)
07010 {
07011 List *children;
07012 ListCell *child;
07013 Relation conrel;
07014 Form_pg_constraint con;
07015 SysScanDesc scan;
07016 ScanKeyData key;
07017 HeapTuple tuple;
07018 bool found = false;
07019 bool is_no_inherit_constraint = false;
07020
07021
07022 if (recursing)
07023 ATSimplePermissions(rel, ATT_TABLE);
07024
07025 conrel = heap_open(ConstraintRelationId, RowExclusiveLock);
07026
07027
07028
07029
07030 ScanKeyInit(&key,
07031 Anum_pg_constraint_conrelid,
07032 BTEqualStrategyNumber, F_OIDEQ,
07033 ObjectIdGetDatum(RelationGetRelid(rel)));
07034 scan = systable_beginscan(conrel, ConstraintRelidIndexId,
07035 true, SnapshotNow, 1, &key);
07036
07037 while (HeapTupleIsValid(tuple = systable_getnext(scan)))
07038 {
07039 ObjectAddress conobj;
07040
07041 con = (Form_pg_constraint) GETSTRUCT(tuple);
07042
07043 if (strcmp(NameStr(con->conname), constrName) != 0)
07044 continue;
07045
07046
07047 if (con->coninhcount > 0 && !recursing)
07048 ereport(ERROR,
07049 (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
07050 errmsg("cannot drop inherited constraint \"%s\" of relation \"%s\"",
07051 constrName, RelationGetRelationName(rel))));
07052
07053 is_no_inherit_constraint = con->connoinherit;
07054
07055
07056
07057
07058 conobj.classId = ConstraintRelationId;
07059 conobj.objectId = HeapTupleGetOid(tuple);
07060 conobj.objectSubId = 0;
07061
07062 performDeletion(&conobj, behavior, 0);
07063
07064 found = true;
07065
07066
07067 break;
07068 }
07069
07070 systable_endscan(scan);
07071
07072 if (!found)
07073 {
07074 if (!missing_ok)
07075 {
07076 ereport(ERROR,
07077 (errcode(ERRCODE_UNDEFINED_OBJECT),
07078 errmsg("constraint \"%s\" of relation \"%s\" does not exist",
07079 constrName, RelationGetRelationName(rel))));
07080 }
07081 else
07082 {
07083 ereport(NOTICE,
07084 (errmsg("constraint \"%s\" of relation \"%s\" does not exist, skipping",
07085 constrName, RelationGetRelationName(rel))));
07086 heap_close(conrel, RowExclusiveLock);
07087 return;
07088 }
07089 }
07090
07091
07092
07093
07094
07095
07096 if (!is_no_inherit_constraint)
07097 children = find_inheritance_children(RelationGetRelid(rel), lockmode);
07098 else
07099 children = NIL;
07100
07101 foreach(child, children)
07102 {
07103 Oid childrelid = lfirst_oid(child);
07104 Relation childrel;
07105 HeapTuple copy_tuple;
07106
07107
07108 childrel = heap_open(childrelid, NoLock);
07109 CheckTableNotInUse(childrel, "ALTER TABLE");
07110
07111 ScanKeyInit(&key,
07112 Anum_pg_constraint_conrelid,
07113 BTEqualStrategyNumber, F_OIDEQ,
07114 ObjectIdGetDatum(childrelid));
07115 scan = systable_beginscan(conrel, ConstraintRelidIndexId,
07116 true, SnapshotNow, 1, &key);
07117
07118
07119 while (HeapTupleIsValid(tuple = systable_getnext(scan)))
07120 {
07121 con = (Form_pg_constraint) GETSTRUCT(tuple);
07122
07123
07124 if (con->contype != CONSTRAINT_CHECK)
07125 continue;
07126
07127 if (strcmp(NameStr(con->conname), constrName) == 0)
07128 break;
07129 }
07130
07131 if (!HeapTupleIsValid(tuple))
07132 ereport(ERROR,
07133 (errcode(ERRCODE_UNDEFINED_OBJECT),
07134 errmsg("constraint \"%s\" of relation \"%s\" does not exist",
07135 constrName,
07136 RelationGetRelationName(childrel))));
07137
07138 copy_tuple = heap_copytuple(tuple);
07139
07140 systable_endscan(scan);
07141
07142 con = (Form_pg_constraint) GETSTRUCT(copy_tuple);
07143
07144 if (con->coninhcount <= 0)
07145 elog(ERROR, "relation %u has non-inherited constraint \"%s\"",
07146 childrelid, constrName);
07147
07148 if (recurse)
07149 {
07150
07151
07152
07153
07154 if (con->coninhcount == 1 && !con->conislocal)
07155 {
07156
07157 ATExecDropConstraint(childrel, constrName, behavior,
07158 true, true,
07159 false, lockmode);
07160 }
07161 else
07162 {
07163
07164 con->coninhcount--;
07165 simple_heap_update(conrel, ©_tuple->t_self, copy_tuple);
07166 CatalogUpdateIndexes(conrel, copy_tuple);
07167
07168
07169 CommandCounterIncrement();
07170 }
07171 }
07172 else
07173 {
07174
07175
07176
07177
07178
07179 con->coninhcount--;
07180 con->conislocal = true;
07181
07182 simple_heap_update(conrel, ©_tuple->t_self, copy_tuple);
07183 CatalogUpdateIndexes(conrel, copy_tuple);
07184
07185
07186 CommandCounterIncrement();
07187 }
07188
07189 heap_freetuple(copy_tuple);
07190
07191 heap_close(childrel, NoLock);
07192 }
07193
07194 heap_close(conrel, RowExclusiveLock);
07195 }
07196
07197
07198
07199
07200 static void
07201 ATPrepAlterColumnType(List **wqueue,
07202 AlteredTableInfo *tab, Relation rel,
07203 bool recurse, bool recursing,
07204 AlterTableCmd *cmd, LOCKMODE lockmode)
07205 {
07206 char *colName = cmd->name;
07207 ColumnDef *def = (ColumnDef *) cmd->def;
07208 TypeName *typeName = def->typeName;
07209 Node *transform = def->raw_default;
07210 HeapTuple tuple;
07211 Form_pg_attribute attTup;
07212 AttrNumber attnum;
07213 Oid targettype;
07214 int32 targettypmod;
07215 Oid targetcollid;
07216 NewColumnValue *newval;
07217 ParseState *pstate = make_parsestate(NULL);
07218 AclResult aclresult;
07219
07220 if (rel->rd_rel->reloftype && !recursing)
07221 ereport(ERROR,
07222 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
07223 errmsg("cannot alter column type of typed table")));
07224
07225
07226 tuple = SearchSysCacheAttName(RelationGetRelid(rel), colName);
07227 if (!HeapTupleIsValid(tuple))
07228 ereport(ERROR,
07229 (errcode(ERRCODE_UNDEFINED_COLUMN),
07230 errmsg("column \"%s\" of relation \"%s\" does not exist",
07231 colName, RelationGetRelationName(rel))));
07232 attTup = (Form_pg_attribute) GETSTRUCT(tuple);
07233 attnum = attTup->attnum;
07234
07235
07236 if (attnum <= 0)
07237 ereport(ERROR,
07238 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
07239 errmsg("cannot alter system column \"%s\"",
07240 colName)));
07241
07242
07243 if (attTup->attinhcount > 0 && !recursing)
07244 ereport(ERROR,
07245 (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
07246 errmsg("cannot alter inherited column \"%s\"",
07247 colName)));
07248
07249
07250 typenameTypeIdAndMod(NULL, typeName, &targettype, &targettypmod);
07251
07252 aclresult = pg_type_aclcheck(targettype, GetUserId(), ACL_USAGE);
07253 if (aclresult != ACLCHECK_OK)
07254 aclcheck_error_type(aclresult, targettype);
07255
07256
07257 targetcollid = GetColumnDefCollation(NULL, def, targettype);
07258
07259
07260 CheckAttributeType(colName, targettype, targetcollid,
07261 list_make1_oid(rel->rd_rel->reltype),
07262 false);
07263
07264 if (tab->relkind == RELKIND_RELATION)
07265 {
07266
07267
07268
07269
07270
07271
07272
07273
07274 if (transform)
07275 {
07276 RangeTblEntry *rte;
07277
07278
07279 rte = addRangeTableEntryForRelation(pstate,
07280 rel,
07281 NULL,
07282 false,
07283 true);
07284 addRTEtoQuery(pstate, rte, false, true, true);
07285
07286 transform = transformExpr(pstate, transform,
07287 EXPR_KIND_ALTER_COL_TRANSFORM);
07288
07289
07290 if (expression_returns_set(transform))
07291 ereport(ERROR,
07292 (errcode(ERRCODE_DATATYPE_MISMATCH),
07293 errmsg("transform expression must not return a set")));
07294 }
07295 else
07296 {
07297 transform = (Node *) makeVar(1, attnum,
07298 attTup->atttypid, attTup->atttypmod,
07299 attTup->attcollation,
07300 0);
07301 }
07302
07303 transform = coerce_to_target_type(pstate,
07304 transform, exprType(transform),
07305 targettype, targettypmod,
07306 COERCION_ASSIGNMENT,
07307 COERCE_IMPLICIT_CAST,
07308 -1);
07309 if (transform == NULL)
07310 ereport(ERROR,
07311 (errcode(ERRCODE_DATATYPE_MISMATCH),
07312 errmsg("column \"%s\" cannot be cast automatically to type %s",
07313 colName, format_type_be(targettype)),
07314 errhint("Specify a USING expression to perform the conversion.")));
07315
07316
07317 assign_expr_collations(pstate, transform);
07318
07319
07320 transform = (Node *) expression_planner((Expr *) transform);
07321
07322
07323
07324
07325
07326 newval = (NewColumnValue *) palloc0(sizeof(NewColumnValue));
07327 newval->attnum = attnum;
07328 newval->expr = (Expr *) transform;
07329
07330 tab->newvals = lappend(tab->newvals, newval);
07331 if (ATColumnChangeRequiresRewrite(transform, attnum))
07332 tab->rewrite = true;
07333 }
07334 else if (transform)
07335 ereport(ERROR,
07336 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
07337 errmsg("\"%s\" is not a table",
07338 RelationGetRelationName(rel))));
07339
07340 if (tab->relkind == RELKIND_COMPOSITE_TYPE ||
07341 tab->relkind == RELKIND_FOREIGN_TABLE)
07342 {
07343
07344
07345
07346
07347 find_composite_type_dependencies(rel->rd_rel->reltype, rel, NULL);
07348 }
07349
07350 ReleaseSysCache(tuple);
07351
07352
07353
07354
07355
07356
07357 if (recurse)
07358 ATSimpleRecursion(wqueue, rel, cmd, recurse, lockmode);
07359 else if (!recursing &&
07360 find_inheritance_children(RelationGetRelid(rel), NoLock) != NIL)
07361 ereport(ERROR,
07362 (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
07363 errmsg("type of inherited column \"%s\" must be changed in child tables too",
07364 colName)));
07365
07366 if (tab->relkind == RELKIND_COMPOSITE_TYPE)
07367 ATTypedTableRecursion(wqueue, rel, cmd, lockmode);
07368 }
07369
07370
07371
07372
07373
07374
07375
07376
07377
07378
07379
07380 static bool
07381 ATColumnChangeRequiresRewrite(Node *expr, AttrNumber varattno)
07382 {
07383 Assert(expr != NULL);
07384
07385 for (;;)
07386 {
07387
07388 if (IsA(expr, Var) &&((Var *) expr)->varattno == varattno)
07389 return false;
07390 else if (IsA(expr, RelabelType))
07391 expr = (Node *) ((RelabelType *) expr)->arg;
07392 else if (IsA(expr, CoerceToDomain))
07393 {
07394 CoerceToDomain *d = (CoerceToDomain *) expr;
07395
07396 if (GetDomainConstraints(d->resulttype) != NIL)
07397 return true;
07398 expr = (Node *) d->arg;
07399 }
07400 else
07401 return true;
07402 }
07403 }
07404
07405 static void
07406 ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel,
07407 AlterTableCmd *cmd, LOCKMODE lockmode)
07408 {
07409 char *colName = cmd->name;
07410 ColumnDef *def = (ColumnDef *) cmd->def;
07411 TypeName *typeName = def->typeName;
07412 HeapTuple heapTup;
07413 Form_pg_attribute attTup;
07414 AttrNumber attnum;
07415 HeapTuple typeTuple;
07416 Form_pg_type tform;
07417 Oid targettype;
07418 int32 targettypmod;
07419 Oid targetcollid;
07420 Node *defaultexpr;
07421 Relation attrelation;
07422 Relation depRel;
07423 ScanKeyData key[3];
07424 SysScanDesc scan;
07425 HeapTuple depTup;
07426
07427 attrelation = heap_open(AttributeRelationId, RowExclusiveLock);
07428
07429
07430 heapTup = SearchSysCacheCopyAttName(RelationGetRelid(rel), colName);
07431 if (!HeapTupleIsValid(heapTup))
07432 ereport(ERROR,
07433 (errcode(ERRCODE_UNDEFINED_COLUMN),
07434 errmsg("column \"%s\" of relation \"%s\" does not exist",
07435 colName, RelationGetRelationName(rel))));
07436 attTup = (Form_pg_attribute) GETSTRUCT(heapTup);
07437 attnum = attTup->attnum;
07438
07439
07440 if (attTup->atttypid != tab->oldDesc->attrs[attnum - 1]->atttypid ||
07441 attTup->atttypmod != tab->oldDesc->attrs[attnum - 1]->atttypmod)
07442 ereport(ERROR,
07443 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
07444 errmsg("cannot alter type of column \"%s\" twice",
07445 colName)));
07446
07447
07448 typeTuple = typenameType(NULL, typeName, &targettypmod);
07449 tform = (Form_pg_type) GETSTRUCT(typeTuple);
07450 targettype = HeapTupleGetOid(typeTuple);
07451
07452 targetcollid = GetColumnDefCollation(NULL, def, targettype);
07453
07454
07455
07456
07457
07458
07459
07460
07461
07462
07463
07464
07465
07466 if (attTup->atthasdef)
07467 {
07468 defaultexpr = build_column_default(rel, attnum);
07469 Assert(defaultexpr);
07470 defaultexpr = strip_implicit_coercions(defaultexpr);
07471 defaultexpr = coerce_to_target_type(NULL,
07472 defaultexpr, exprType(defaultexpr),
07473 targettype, targettypmod,
07474 COERCION_ASSIGNMENT,
07475 COERCE_IMPLICIT_CAST,
07476 -1);
07477 if (defaultexpr == NULL)
07478 ereport(ERROR,
07479 (errcode(ERRCODE_DATATYPE_MISMATCH),
07480 errmsg("default for column \"%s\" cannot be cast automatically to type %s",
07481 colName, format_type_be(targettype))));
07482 }
07483 else
07484 defaultexpr = NULL;
07485
07486
07487
07488
07489
07490
07491
07492
07493
07494
07495
07496
07497
07498
07499
07500 depRel = heap_open(DependRelationId, RowExclusiveLock);
07501
07502 ScanKeyInit(&key[0],
07503 Anum_pg_depend_refclassid,
07504 BTEqualStrategyNumber, F_OIDEQ,
07505 ObjectIdGetDatum(RelationRelationId));
07506 ScanKeyInit(&key[1],
07507 Anum_pg_depend_refobjid,
07508 BTEqualStrategyNumber, F_OIDEQ,
07509 ObjectIdGetDatum(RelationGetRelid(rel)));
07510 ScanKeyInit(&key[2],
07511 Anum_pg_depend_refobjsubid,
07512 BTEqualStrategyNumber, F_INT4EQ,
07513 Int32GetDatum((int32) attnum));
07514
07515 scan = systable_beginscan(depRel, DependReferenceIndexId, true,
07516 SnapshotNow, 3, key);
07517
07518 while (HeapTupleIsValid(depTup = systable_getnext(scan)))
07519 {
07520 Form_pg_depend foundDep = (Form_pg_depend) GETSTRUCT(depTup);
07521 ObjectAddress foundObject;
07522
07523
07524 if (foundDep->deptype == DEPENDENCY_PIN)
07525 elog(ERROR, "cannot alter type of a pinned column");
07526
07527 foundObject.classId = foundDep->classid;
07528 foundObject.objectId = foundDep->objid;
07529 foundObject.objectSubId = foundDep->objsubid;
07530
07531 switch (getObjectClass(&foundObject))
07532 {
07533 case OCLASS_CLASS:
07534 {
07535 char relKind = get_rel_relkind(foundObject.objectId);
07536
07537 if (relKind == RELKIND_INDEX)
07538 {
07539 Assert(foundObject.objectSubId == 0);
07540 if (!list_member_oid(tab->changedIndexOids, foundObject.objectId))
07541 {
07542 tab->changedIndexOids = lappend_oid(tab->changedIndexOids,
07543 foundObject.objectId);
07544 tab->changedIndexDefs = lappend(tab->changedIndexDefs,
07545 pg_get_indexdef_string(foundObject.objectId));
07546 }
07547 }
07548 else if (relKind == RELKIND_SEQUENCE)
07549 {
07550
07551
07552
07553
07554 Assert(foundObject.objectSubId == 0);
07555 }
07556 else
07557 {
07558
07559 elog(ERROR, "unexpected object depending on column: %s",
07560 getObjectDescription(&foundObject));
07561 }
07562 break;
07563 }
07564
07565 case OCLASS_CONSTRAINT:
07566 Assert(foundObject.objectSubId == 0);
07567 if (!list_member_oid(tab->changedConstraintOids,
07568 foundObject.objectId))
07569 {
07570 char *defstring = pg_get_constraintdef_string(foundObject.objectId);
07571
07572
07573
07574
07575
07576
07577
07578
07579
07580
07581 if (foundDep->deptype == DEPENDENCY_NORMAL)
07582 {
07583 tab->changedConstraintOids =
07584 lcons_oid(foundObject.objectId,
07585 tab->changedConstraintOids);
07586 tab->changedConstraintDefs =
07587 lcons(defstring,
07588 tab->changedConstraintDefs);
07589 }
07590 else
07591 {
07592 tab->changedConstraintOids =
07593 lappend_oid(tab->changedConstraintOids,
07594 foundObject.objectId);
07595 tab->changedConstraintDefs =
07596 lappend(tab->changedConstraintDefs,
07597 defstring);
07598 }
07599 }
07600 break;
07601
07602 case OCLASS_REWRITE:
07603
07604 ereport(ERROR,
07605 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
07606 errmsg("cannot alter type of a column used by a view or rule"),
07607 errdetail("%s depends on column \"%s\"",
07608 getObjectDescription(&foundObject),
07609 colName)));
07610 break;
07611
07612 case OCLASS_TRIGGER:
07613
07614
07615
07616
07617
07618
07619
07620
07621
07622
07623 ereport(ERROR,
07624 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
07625 errmsg("cannot alter type of a column used in a trigger definition"),
07626 errdetail("%s depends on column \"%s\"",
07627 getObjectDescription(&foundObject),
07628 colName)));
07629 break;
07630
07631 case OCLASS_DEFAULT:
07632
07633
07634
07635
07636
07637 Assert(defaultexpr);
07638 break;
07639
07640 case OCLASS_PROC:
07641 case OCLASS_TYPE:
07642 case OCLASS_CAST:
07643 case OCLASS_COLLATION:
07644 case OCLASS_CONVERSION:
07645 case OCLASS_LANGUAGE:
07646 case OCLASS_LARGEOBJECT:
07647 case OCLASS_OPERATOR:
07648 case OCLASS_OPCLASS:
07649 case OCLASS_OPFAMILY:
07650 case OCLASS_AMOP:
07651 case OCLASS_AMPROC:
07652 case OCLASS_SCHEMA:
07653 case OCLASS_TSPARSER:
07654 case OCLASS_TSDICT:
07655 case OCLASS_TSTEMPLATE:
07656 case OCLASS_TSCONFIG:
07657 case OCLASS_ROLE:
07658 case OCLASS_DATABASE:
07659 case OCLASS_TBLSPACE:
07660 case OCLASS_FDW:
07661 case OCLASS_FOREIGN_SERVER:
07662 case OCLASS_USER_MAPPING:
07663 case OCLASS_DEFACL:
07664 case OCLASS_EXTENSION:
07665
07666
07667
07668
07669
07670 elog(ERROR, "unexpected object depending on column: %s",
07671 getObjectDescription(&foundObject));
07672 break;
07673
07674 default:
07675 elog(ERROR, "unrecognized object class: %u",
07676 foundObject.classId);
07677 }
07678 }
07679
07680 systable_endscan(scan);
07681
07682
07683
07684
07685
07686
07687 ScanKeyInit(&key[0],
07688 Anum_pg_depend_classid,
07689 BTEqualStrategyNumber, F_OIDEQ,
07690 ObjectIdGetDatum(RelationRelationId));
07691 ScanKeyInit(&key[1],
07692 Anum_pg_depend_objid,
07693 BTEqualStrategyNumber, F_OIDEQ,
07694 ObjectIdGetDatum(RelationGetRelid(rel)));
07695 ScanKeyInit(&key[2],
07696 Anum_pg_depend_objsubid,
07697 BTEqualStrategyNumber, F_INT4EQ,
07698 Int32GetDatum((int32) attnum));
07699
07700 scan = systable_beginscan(depRel, DependDependerIndexId, true,
07701 SnapshotNow, 3, key);
07702
07703 while (HeapTupleIsValid(depTup = systable_getnext(scan)))
07704 {
07705 Form_pg_depend foundDep = (Form_pg_depend) GETSTRUCT(depTup);
07706
07707 if (foundDep->deptype != DEPENDENCY_NORMAL)
07708 elog(ERROR, "found unexpected dependency type '%c'",
07709 foundDep->deptype);
07710 if (!(foundDep->refclassid == TypeRelationId &&
07711 foundDep->refobjid == attTup->atttypid) &&
07712 !(foundDep->refclassid == CollationRelationId &&
07713 foundDep->refobjid == attTup->attcollation))
07714 elog(ERROR, "found unexpected dependency for column");
07715
07716 simple_heap_delete(depRel, &depTup->t_self);
07717 }
07718
07719 systable_endscan(scan);
07720
07721 heap_close(depRel, RowExclusiveLock);
07722
07723
07724
07725
07726
07727 attTup->atttypid = targettype;
07728 attTup->atttypmod = targettypmod;
07729 attTup->attcollation = targetcollid;
07730 attTup->attndims = list_length(typeName->arrayBounds);
07731 attTup->attlen = tform->typlen;
07732 attTup->attbyval = tform->typbyval;
07733 attTup->attalign = tform->typalign;
07734 attTup->attstorage = tform->typstorage;
07735
07736 ReleaseSysCache(typeTuple);
07737
07738 simple_heap_update(attrelation, &heapTup->t_self, heapTup);
07739
07740
07741 CatalogUpdateIndexes(attrelation, heapTup);
07742
07743 heap_close(attrelation, RowExclusiveLock);
07744
07745
07746 add_column_datatype_dependency(RelationGetRelid(rel), attnum, targettype);
07747 add_column_collation_dependency(RelationGetRelid(rel), attnum, targetcollid);
07748
07749
07750
07751
07752 RemoveStatistics(RelationGetRelid(rel), attnum);
07753
07754 InvokeObjectPostAlterHook(RelationRelationId,
07755 RelationGetRelid(rel), attnum);
07756
07757
07758
07759
07760
07761
07762
07763
07764 if (defaultexpr)
07765 {
07766
07767 CommandCounterIncrement();
07768
07769
07770
07771
07772
07773 RemoveAttrDefault(RelationGetRelid(rel), attnum, DROP_RESTRICT, true,
07774 true);
07775
07776 StoreAttrDefault(rel, attnum, defaultexpr, true);
07777 }
07778
07779
07780 heap_freetuple(heapTup);
07781 }
07782
07783 static void
07784 ATExecAlterColumnGenericOptions(Relation rel,
07785 const char *colName,
07786 List *options,
07787 LOCKMODE lockmode)
07788 {
07789 Relation ftrel;
07790 Relation attrel;
07791 ForeignServer *server;
07792 ForeignDataWrapper *fdw;
07793 HeapTuple tuple;
07794 HeapTuple newtuple;
07795 bool isnull;
07796 Datum repl_val[Natts_pg_attribute];
07797 bool repl_null[Natts_pg_attribute];
07798 bool repl_repl[Natts_pg_attribute];
07799 Datum datum;
07800 Form_pg_foreign_table fttableform;
07801 Form_pg_attribute atttableform;
07802
07803 if (options == NIL)
07804 return;
07805
07806
07807 ftrel = heap_open(ForeignTableRelationId, AccessShareLock);
07808 tuple = SearchSysCache1(FOREIGNTABLEREL, rel->rd_id);
07809 if (!HeapTupleIsValid(tuple))
07810 ereport(ERROR,
07811 (errcode(ERRCODE_UNDEFINED_OBJECT),
07812 errmsg("foreign table \"%s\" does not exist",
07813 RelationGetRelationName(rel))));
07814 fttableform = (Form_pg_foreign_table) GETSTRUCT(tuple);
07815 server = GetForeignServer(fttableform->ftserver);
07816 fdw = GetForeignDataWrapper(server->fdwid);
07817
07818 heap_close(ftrel, AccessShareLock);
07819 ReleaseSysCache(tuple);
07820
07821 attrel = heap_open(AttributeRelationId, RowExclusiveLock);
07822 tuple = SearchSysCacheAttName(RelationGetRelid(rel), colName);
07823 if (!HeapTupleIsValid(tuple))
07824 ereport(ERROR,
07825 (errcode(ERRCODE_UNDEFINED_COLUMN),
07826 errmsg("column \"%s\" of relation \"%s\" does not exist",
07827 colName, RelationGetRelationName(rel))));
07828
07829
07830 atttableform = (Form_pg_attribute) GETSTRUCT(tuple);
07831 if (atttableform->attnum <= 0)
07832 ereport(ERROR,
07833 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
07834 errmsg("cannot alter system column \"%s\"", colName)));
07835
07836
07837
07838 memset(repl_val, 0, sizeof(repl_val));
07839 memset(repl_null, false, sizeof(repl_null));
07840 memset(repl_repl, false, sizeof(repl_repl));
07841
07842
07843 datum = SysCacheGetAttr(ATTNAME,
07844 tuple,
07845 Anum_pg_attribute_attfdwoptions,
07846 &isnull);
07847 if (isnull)
07848 datum = PointerGetDatum(NULL);
07849
07850
07851 datum = transformGenericOptions(AttributeRelationId,
07852 datum,
07853 options,
07854 fdw->fdwvalidator);
07855
07856 if (PointerIsValid(DatumGetPointer(datum)))
07857 repl_val[Anum_pg_attribute_attfdwoptions - 1] = datum;
07858 else
07859 repl_null[Anum_pg_attribute_attfdwoptions - 1] = true;
07860
07861 repl_repl[Anum_pg_attribute_attfdwoptions - 1] = true;
07862
07863
07864
07865 newtuple = heap_modify_tuple(tuple, RelationGetDescr(attrel),
07866 repl_val, repl_null, repl_repl);
07867
07868 simple_heap_update(attrel, &newtuple->t_self, newtuple);
07869 CatalogUpdateIndexes(attrel, newtuple);
07870
07871 InvokeObjectPostAlterHook(RelationRelationId,
07872 RelationGetRelid(rel),
07873 atttableform->attnum);
07874
07875 ReleaseSysCache(tuple);
07876
07877 heap_close(attrel, RowExclusiveLock);
07878
07879 heap_freetuple(newtuple);
07880 }
07881
07882
07883
07884
07885
07886
07887 static void
07888 ATPostAlterTypeCleanup(List **wqueue, AlteredTableInfo *tab, LOCKMODE lockmode)
07889 {
07890 ObjectAddress obj;
07891 ListCell *def_item;
07892 ListCell *oid_item;
07893
07894
07895
07896
07897
07898
07899
07900
07901
07902 forboth(oid_item, tab->changedConstraintOids,
07903 def_item, tab->changedConstraintDefs)
07904 ATPostAlterTypeParse(lfirst_oid(oid_item), (char *) lfirst(def_item),
07905 wqueue, lockmode, tab->rewrite);
07906 forboth(oid_item, tab->changedIndexOids,
07907 def_item, tab->changedIndexDefs)
07908 ATPostAlterTypeParse(lfirst_oid(oid_item), (char *) lfirst(def_item),
07909 wqueue, lockmode, tab->rewrite);
07910
07911
07912
07913
07914
07915
07916
07917
07918
07919 foreach(oid_item, tab->changedConstraintOids)
07920 {
07921 obj.classId = ConstraintRelationId;
07922 obj.objectId = lfirst_oid(oid_item);
07923 obj.objectSubId = 0;
07924 performDeletion(&obj, DROP_RESTRICT, PERFORM_DELETION_INTERNAL);
07925 }
07926
07927 foreach(oid_item, tab->changedIndexOids)
07928 {
07929 obj.classId = RelationRelationId;
07930 obj.objectId = lfirst_oid(oid_item);
07931 obj.objectSubId = 0;
07932 performDeletion(&obj, DROP_RESTRICT, PERFORM_DELETION_INTERNAL);
07933 }
07934
07935
07936
07937
07938
07939 }
07940
07941 static void
07942 ATPostAlterTypeParse(Oid oldId, char *cmd,
07943 List **wqueue, LOCKMODE lockmode, bool rewrite)
07944 {
07945 List *raw_parsetree_list;
07946 List *querytree_list;
07947 ListCell *list_item;
07948
07949
07950
07951
07952
07953
07954
07955 raw_parsetree_list = raw_parser(cmd);
07956 querytree_list = NIL;
07957 foreach(list_item, raw_parsetree_list)
07958 {
07959 Node *stmt = (Node *) lfirst(list_item);
07960
07961 if (IsA(stmt, IndexStmt))
07962 querytree_list = lappend(querytree_list,
07963 transformIndexStmt((IndexStmt *) stmt,
07964 cmd));
07965 else if (IsA(stmt, AlterTableStmt))
07966 querytree_list = list_concat(querytree_list,
07967 transformAlterTableStmt((AlterTableStmt *) stmt,
07968 cmd));
07969 else
07970 querytree_list = lappend(querytree_list, stmt);
07971 }
07972
07973
07974
07975
07976
07977
07978
07979
07980
07981 foreach(list_item, querytree_list)
07982 {
07983 Node *stm = (Node *) lfirst(list_item);
07984 Relation rel;
07985 AlteredTableInfo *tab;
07986
07987 switch (nodeTag(stm))
07988 {
07989 case T_IndexStmt:
07990 {
07991 IndexStmt *stmt = (IndexStmt *) stm;
07992 AlterTableCmd *newcmd;
07993
07994 if (!rewrite)
07995 TryReuseIndex(oldId, stmt);
07996
07997 rel = relation_openrv(stmt->relation, lockmode);
07998 tab = ATGetQueueEntry(wqueue, rel);
07999 newcmd = makeNode(AlterTableCmd);
08000 newcmd->subtype = AT_ReAddIndex;
08001 newcmd->def = (Node *) stmt;
08002 tab->subcmds[AT_PASS_OLD_INDEX] =
08003 lappend(tab->subcmds[AT_PASS_OLD_INDEX], newcmd);
08004 relation_close(rel, NoLock);
08005 break;
08006 }
08007 case T_AlterTableStmt:
08008 {
08009 AlterTableStmt *stmt = (AlterTableStmt *) stm;
08010 ListCell *lcmd;
08011
08012 rel = relation_openrv(stmt->relation, lockmode);
08013 tab = ATGetQueueEntry(wqueue, rel);
08014 foreach(lcmd, stmt->cmds)
08015 {
08016 AlterTableCmd *cmd = (AlterTableCmd *) lfirst(lcmd);
08017 Constraint *con;
08018
08019 switch (cmd->subtype)
08020 {
08021 case AT_AddIndex:
08022 Assert(IsA(cmd->def, IndexStmt));
08023 if (!rewrite)
08024 TryReuseIndex(get_constraint_index(oldId),
08025 (IndexStmt *) cmd->def);
08026 cmd->subtype = AT_ReAddIndex;
08027 tab->subcmds[AT_PASS_OLD_INDEX] =
08028 lappend(tab->subcmds[AT_PASS_OLD_INDEX], cmd);
08029 break;
08030 case AT_AddConstraint:
08031 Assert(IsA(cmd->def, Constraint));
08032 con = (Constraint *) cmd->def;
08033
08034 if (con->contype == CONSTR_FOREIGN &&
08035 !rewrite && !tab->rewrite)
08036 TryReuseForeignKey(oldId, con);
08037 cmd->subtype = AT_ReAddConstraint;
08038 tab->subcmds[AT_PASS_OLD_CONSTR] =
08039 lappend(tab->subcmds[AT_PASS_OLD_CONSTR], cmd);
08040 break;
08041 default:
08042 elog(ERROR, "unexpected statement type: %d",
08043 (int) cmd->subtype);
08044 }
08045 }
08046 relation_close(rel, NoLock);
08047 break;
08048 }
08049 default:
08050 elog(ERROR, "unexpected statement type: %d",
08051 (int) nodeTag(stm));
08052 }
08053 }
08054 }
08055
08056
08057
08058
08059
08060 static void
08061 TryReuseIndex(Oid oldId, IndexStmt *stmt)
08062 {
08063 if (CheckIndexCompatible(oldId,
08064 stmt->relation,
08065 stmt->accessMethod,
08066 stmt->indexParams,
08067 stmt->excludeOpNames))
08068 {
08069 Relation irel = index_open(oldId, NoLock);
08070
08071 stmt->oldNode = irel->rd_node.relNode;
08072 index_close(irel, NoLock);
08073 }
08074 }
08075
08076
08077
08078
08079
08080
08081
08082
08083 static void
08084 TryReuseForeignKey(Oid oldId, Constraint *con)
08085 {
08086 HeapTuple tup;
08087 Datum adatum;
08088 bool isNull;
08089 ArrayType *arr;
08090 Oid *rawarr;
08091 int numkeys;
08092 int i;
08093
08094 Assert(con->contype == CONSTR_FOREIGN);
08095 Assert(con->old_conpfeqop == NIL);
08096
08097 tup = SearchSysCache1(CONSTROID, ObjectIdGetDatum(oldId));
08098 if (!HeapTupleIsValid(tup))
08099 elog(ERROR, "cache lookup failed for constraint %u", oldId);
08100
08101 adatum = SysCacheGetAttr(CONSTROID, tup,
08102 Anum_pg_constraint_conpfeqop, &isNull);
08103 if (isNull)
08104 elog(ERROR, "null conpfeqop for constraint %u", oldId);
08105 arr = DatumGetArrayTypeP(adatum);
08106 numkeys = ARR_DIMS(arr)[0];
08107
08108 if (ARR_NDIM(arr) != 1 ||
08109 ARR_HASNULL(arr) ||
08110 ARR_ELEMTYPE(arr) != OIDOID)
08111 elog(ERROR, "conpfeqop is not a 1-D Oid array");
08112 rawarr = (Oid *) ARR_DATA_PTR(arr);
08113
08114
08115 for (i = 0; i < numkeys; i++)
08116 con->old_conpfeqop = lcons_oid(rawarr[i], con->old_conpfeqop);
08117
08118 ReleaseSysCache(tup);
08119 }
08120
08121
08122
08123
08124
08125
08126
08127
08128
08129
08130
08131
08132
08133 void
08134 ATExecChangeOwner(Oid relationOid, Oid newOwnerId, bool recursing, LOCKMODE lockmode)
08135 {
08136 Relation target_rel;
08137 Relation class_rel;
08138 HeapTuple tuple;
08139 Form_pg_class tuple_class;
08140
08141
08142
08143
08144
08145 target_rel = relation_open(relationOid, lockmode);
08146
08147
08148 class_rel = heap_open(RelationRelationId, RowExclusiveLock);
08149
08150 tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relationOid));
08151 if (!HeapTupleIsValid(tuple))
08152 elog(ERROR, "cache lookup failed for relation %u", relationOid);
08153 tuple_class = (Form_pg_class) GETSTRUCT(tuple);
08154
08155
08156 switch (tuple_class->relkind)
08157 {
08158 case RELKIND_RELATION:
08159 case RELKIND_VIEW:
08160 case RELKIND_MATVIEW:
08161 case RELKIND_FOREIGN_TABLE:
08162
08163 break;
08164 case RELKIND_INDEX:
08165 if (!recursing)
08166 {
08167
08168
08169
08170
08171
08172
08173
08174 if (tuple_class->relowner != newOwnerId)
08175 ereport(WARNING,
08176 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
08177 errmsg("cannot change owner of index \"%s\"",
08178 NameStr(tuple_class->relname)),
08179 errhint("Change the ownership of the index's table, instead.")));
08180
08181 newOwnerId = tuple_class->relowner;
08182 }
08183 break;
08184 case RELKIND_SEQUENCE:
08185 if (!recursing &&
08186 tuple_class->relowner != newOwnerId)
08187 {
08188
08189 Oid tableId;
08190 int32 colId;
08191
08192 if (sequenceIsOwned(relationOid, &tableId, &colId))
08193 ereport(ERROR,
08194 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
08195 errmsg("cannot change owner of sequence \"%s\"",
08196 NameStr(tuple_class->relname)),
08197 errdetail("Sequence \"%s\" is linked to table \"%s\".",
08198 NameStr(tuple_class->relname),
08199 get_rel_name(tableId))));
08200 }
08201 break;
08202 case RELKIND_COMPOSITE_TYPE:
08203 if (recursing)
08204 break;
08205 ereport(ERROR,
08206 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
08207 errmsg("\"%s\" is a composite type",
08208 NameStr(tuple_class->relname)),
08209 errhint("Use ALTER TYPE instead.")));
08210 break;
08211 case RELKIND_TOASTVALUE:
08212 if (recursing)
08213 break;
08214
08215 default:
08216 ereport(ERROR,
08217 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
08218 errmsg("\"%s\" is not a table, view, sequence, or foreign table",
08219 NameStr(tuple_class->relname))));
08220 }
08221
08222
08223
08224
08225
08226 if (tuple_class->relowner != newOwnerId)
08227 {
08228 Datum repl_val[Natts_pg_class];
08229 bool repl_null[Natts_pg_class];
08230 bool repl_repl[Natts_pg_class];
08231 Acl *newAcl;
08232 Datum aclDatum;
08233 bool isNull;
08234 HeapTuple newtuple;
08235
08236
08237 if (!recursing)
08238 {
08239
08240 if (!superuser())
08241 {
08242 Oid namespaceOid = tuple_class->relnamespace;
08243 AclResult aclresult;
08244
08245
08246 if (!pg_class_ownercheck(relationOid, GetUserId()))
08247 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS,
08248 RelationGetRelationName(target_rel));
08249
08250
08251 check_is_member_of_role(GetUserId(), newOwnerId);
08252
08253
08254 aclresult = pg_namespace_aclcheck(namespaceOid, newOwnerId,
08255 ACL_CREATE);
08256 if (aclresult != ACLCHECK_OK)
08257 aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
08258 get_namespace_name(namespaceOid));
08259 }
08260 }
08261
08262 memset(repl_null, false, sizeof(repl_null));
08263 memset(repl_repl, false, sizeof(repl_repl));
08264
08265 repl_repl[Anum_pg_class_relowner - 1] = true;
08266 repl_val[Anum_pg_class_relowner - 1] = ObjectIdGetDatum(newOwnerId);
08267
08268
08269
08270
08271
08272 aclDatum = SysCacheGetAttr(RELOID, tuple,
08273 Anum_pg_class_relacl,
08274 &isNull);
08275 if (!isNull)
08276 {
08277 newAcl = aclnewowner(DatumGetAclP(aclDatum),
08278 tuple_class->relowner, newOwnerId);
08279 repl_repl[Anum_pg_class_relacl - 1] = true;
08280 repl_val[Anum_pg_class_relacl - 1] = PointerGetDatum(newAcl);
08281 }
08282
08283 newtuple = heap_modify_tuple(tuple, RelationGetDescr(class_rel), repl_val, repl_null, repl_repl);
08284
08285 simple_heap_update(class_rel, &newtuple->t_self, newtuple);
08286 CatalogUpdateIndexes(class_rel, newtuple);
08287
08288 heap_freetuple(newtuple);
08289
08290
08291
08292
08293
08294 change_owner_fix_column_acls(relationOid,
08295 tuple_class->relowner,
08296 newOwnerId);
08297
08298
08299
08300
08301
08302
08303 if (tuple_class->relkind != RELKIND_COMPOSITE_TYPE &&
08304 tuple_class->relkind != RELKIND_INDEX &&
08305 tuple_class->relkind != RELKIND_TOASTVALUE)
08306 changeDependencyOnOwner(RelationRelationId, relationOid,
08307 newOwnerId);
08308
08309
08310
08311
08312 if (tuple_class->relkind != RELKIND_INDEX)
08313 AlterTypeOwnerInternal(tuple_class->reltype, newOwnerId,
08314 tuple_class->relkind == RELKIND_COMPOSITE_TYPE);
08315
08316
08317
08318
08319
08320
08321 if (tuple_class->relkind == RELKIND_RELATION ||
08322 tuple_class->relkind == RELKIND_MATVIEW ||
08323 tuple_class->relkind == RELKIND_TOASTVALUE)
08324 {
08325 List *index_oid_list;
08326 ListCell *i;
08327
08328
08329 index_oid_list = RelationGetIndexList(target_rel);
08330
08331
08332 foreach(i, index_oid_list)
08333 ATExecChangeOwner(lfirst_oid(i), newOwnerId, true, lockmode);
08334
08335 list_free(index_oid_list);
08336 }
08337
08338 if (tuple_class->relkind == RELKIND_RELATION ||
08339 tuple_class->relkind == RELKIND_MATVIEW)
08340 {
08341
08342 if (tuple_class->reltoastrelid != InvalidOid)
08343 ATExecChangeOwner(tuple_class->reltoastrelid, newOwnerId,
08344 true, lockmode);
08345
08346
08347 change_owner_recurse_to_sequences(relationOid, newOwnerId, lockmode);
08348 }
08349 }
08350
08351 InvokeObjectPostAlterHook(RelationRelationId, relationOid, 0);
08352
08353 ReleaseSysCache(tuple);
08354 heap_close(class_rel, RowExclusiveLock);
08355 relation_close(target_rel, NoLock);
08356 }
08357
08358
08359
08360
08361
08362
08363
08364 static void
08365 change_owner_fix_column_acls(Oid relationOid, Oid oldOwnerId, Oid newOwnerId)
08366 {
08367 Relation attRelation;
08368 SysScanDesc scan;
08369 ScanKeyData key[1];
08370 HeapTuple attributeTuple;
08371
08372 attRelation = heap_open(AttributeRelationId, RowExclusiveLock);
08373 ScanKeyInit(&key[0],
08374 Anum_pg_attribute_attrelid,
08375 BTEqualStrategyNumber, F_OIDEQ,
08376 ObjectIdGetDatum(relationOid));
08377 scan = systable_beginscan(attRelation, AttributeRelidNumIndexId,
08378 true, SnapshotNow, 1, key);
08379 while (HeapTupleIsValid(attributeTuple = systable_getnext(scan)))
08380 {
08381 Form_pg_attribute att = (Form_pg_attribute) GETSTRUCT(attributeTuple);
08382 Datum repl_val[Natts_pg_attribute];
08383 bool repl_null[Natts_pg_attribute];
08384 bool repl_repl[Natts_pg_attribute];
08385 Acl *newAcl;
08386 Datum aclDatum;
08387 bool isNull;
08388 HeapTuple newtuple;
08389
08390
08391 if (att->attisdropped)
08392 continue;
08393
08394 aclDatum = heap_getattr(attributeTuple,
08395 Anum_pg_attribute_attacl,
08396 RelationGetDescr(attRelation),
08397 &isNull);
08398
08399 if (isNull)
08400 continue;
08401
08402 memset(repl_null, false, sizeof(repl_null));
08403 memset(repl_repl, false, sizeof(repl_repl));
08404
08405 newAcl = aclnewowner(DatumGetAclP(aclDatum),
08406 oldOwnerId, newOwnerId);
08407 repl_repl[Anum_pg_attribute_attacl - 1] = true;
08408 repl_val[Anum_pg_attribute_attacl - 1] = PointerGetDatum(newAcl);
08409
08410 newtuple = heap_modify_tuple(attributeTuple,
08411 RelationGetDescr(attRelation),
08412 repl_val, repl_null, repl_repl);
08413
08414 simple_heap_update(attRelation, &newtuple->t_self, newtuple);
08415 CatalogUpdateIndexes(attRelation, newtuple);
08416
08417 heap_freetuple(newtuple);
08418 }
08419 systable_endscan(scan);
08420 heap_close(attRelation, RowExclusiveLock);
08421 }
08422
08423
08424
08425
08426
08427
08428
08429
08430 static void
08431 change_owner_recurse_to_sequences(Oid relationOid, Oid newOwnerId, LOCKMODE lockmode)
08432 {
08433 Relation depRel;
08434 SysScanDesc scan;
08435 ScanKeyData key[2];
08436 HeapTuple tup;
08437
08438
08439
08440
08441
08442 depRel = heap_open(DependRelationId, AccessShareLock);
08443
08444 ScanKeyInit(&key[0],
08445 Anum_pg_depend_refclassid,
08446 BTEqualStrategyNumber, F_OIDEQ,
08447 ObjectIdGetDatum(RelationRelationId));
08448 ScanKeyInit(&key[1],
08449 Anum_pg_depend_refobjid,
08450 BTEqualStrategyNumber, F_OIDEQ,
08451 ObjectIdGetDatum(relationOid));
08452
08453
08454 scan = systable_beginscan(depRel, DependReferenceIndexId, true,
08455 SnapshotNow, 2, key);
08456
08457 while (HeapTupleIsValid(tup = systable_getnext(scan)))
08458 {
08459 Form_pg_depend depForm = (Form_pg_depend) GETSTRUCT(tup);
08460 Relation seqRel;
08461
08462
08463 if (depForm->refobjsubid == 0 ||
08464 depForm->classid != RelationRelationId ||
08465 depForm->objsubid != 0 ||
08466 depForm->deptype != DEPENDENCY_AUTO)
08467 continue;
08468
08469
08470 seqRel = relation_open(depForm->objid, lockmode);
08471
08472
08473 if (RelationGetForm(seqRel)->relkind != RELKIND_SEQUENCE)
08474 {
08475
08476 relation_close(seqRel, lockmode);
08477 continue;
08478 }
08479
08480
08481 ATExecChangeOwner(depForm->objid, newOwnerId, true, lockmode);
08482
08483
08484 relation_close(seqRel, NoLock);
08485 }
08486
08487 systable_endscan(scan);
08488
08489 relation_close(depRel, AccessShareLock);
08490 }
08491
08492
08493
08494
08495
08496
08497 static void
08498 ATExecClusterOn(Relation rel, const char *indexName, LOCKMODE lockmode)
08499 {
08500 Oid indexOid;
08501
08502 indexOid = get_relname_relid(indexName, rel->rd_rel->relnamespace);
08503
08504 if (!OidIsValid(indexOid))
08505 ereport(ERROR,
08506 (errcode(ERRCODE_UNDEFINED_OBJECT),
08507 errmsg("index \"%s\" for table \"%s\" does not exist",
08508 indexName, RelationGetRelationName(rel))));
08509
08510
08511 check_index_is_clusterable(rel, indexOid, false, lockmode);
08512
08513
08514 mark_index_clustered(rel, indexOid, false);
08515 }
08516
08517
08518
08519
08520
08521
08522
08523 static void
08524 ATExecDropCluster(Relation rel, LOCKMODE lockmode)
08525 {
08526 mark_index_clustered(rel, InvalidOid, false);
08527 }
08528
08529
08530
08531
08532 static void
08533 ATPrepSetTableSpace(AlteredTableInfo *tab, Relation rel, char *tablespacename, LOCKMODE lockmode)
08534 {
08535 Oid tablespaceId;
08536 AclResult aclresult;
08537
08538
08539 tablespaceId = get_tablespace_oid(tablespacename, false);
08540
08541
08542 aclresult = pg_tablespace_aclcheck(tablespaceId, GetUserId(), ACL_CREATE);
08543 if (aclresult != ACLCHECK_OK)
08544 aclcheck_error(aclresult, ACL_KIND_TABLESPACE, tablespacename);
08545
08546
08547 if (OidIsValid(tab->newTableSpace))
08548 ereport(ERROR,
08549 (errcode(ERRCODE_SYNTAX_ERROR),
08550 errmsg("cannot have multiple SET TABLESPACE subcommands")));
08551 tab->newTableSpace = tablespaceId;
08552 }
08553
08554
08555
08556
08557 static void
08558 ATExecSetRelOptions(Relation rel, List *defList, AlterTableType operation,
08559 LOCKMODE lockmode)
08560 {
08561 Oid relid;
08562 Relation pgclass;
08563 HeapTuple tuple;
08564 HeapTuple newtuple;
08565 Datum datum;
08566 bool isnull;
08567 Datum newOptions;
08568 Datum repl_val[Natts_pg_class];
08569 bool repl_null[Natts_pg_class];
08570 bool repl_repl[Natts_pg_class];
08571 static char *validnsps[] = HEAP_RELOPT_NAMESPACES;
08572
08573 if (defList == NIL && operation != AT_ReplaceRelOptions)
08574 return;
08575
08576 pgclass = heap_open(RelationRelationId, RowExclusiveLock);
08577
08578
08579 relid = RelationGetRelid(rel);
08580 tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
08581 if (!HeapTupleIsValid(tuple))
08582 elog(ERROR, "cache lookup failed for relation %u", relid);
08583
08584 if (operation == AT_ReplaceRelOptions)
08585 {
08586
08587
08588
08589
08590 datum = (Datum) 0;
08591 isnull = true;
08592 }
08593 else
08594 {
08595
08596 datum = SysCacheGetAttr(RELOID, tuple, Anum_pg_class_reloptions,
08597 &isnull);
08598 }
08599
08600
08601 newOptions = transformRelOptions(isnull ? (Datum) 0 : datum,
08602 defList, NULL, validnsps, false,
08603 operation == AT_ResetRelOptions);
08604
08605
08606 switch (rel->rd_rel->relkind)
08607 {
08608 case RELKIND_RELATION:
08609 case RELKIND_TOASTVALUE:
08610 case RELKIND_VIEW:
08611 case RELKIND_MATVIEW:
08612 (void) heap_reloptions(rel->rd_rel->relkind, newOptions, true);
08613 break;
08614 case RELKIND_INDEX:
08615 (void) index_reloptions(rel->rd_am->amoptions, newOptions, true);
08616 break;
08617 default:
08618 ereport(ERROR,
08619 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
08620 errmsg("\"%s\" is not a table, view, materialized view, index, or TOAST table",
08621 RelationGetRelationName(rel))));
08622 break;
08623 }
08624
08625
08626
08627
08628
08629 memset(repl_val, 0, sizeof(repl_val));
08630 memset(repl_null, false, sizeof(repl_null));
08631 memset(repl_repl, false, sizeof(repl_repl));
08632
08633 if (newOptions != (Datum) 0)
08634 repl_val[Anum_pg_class_reloptions - 1] = newOptions;
08635 else
08636 repl_null[Anum_pg_class_reloptions - 1] = true;
08637
08638 repl_repl[Anum_pg_class_reloptions - 1] = true;
08639
08640 newtuple = heap_modify_tuple(tuple, RelationGetDescr(pgclass),
08641 repl_val, repl_null, repl_repl);
08642
08643 simple_heap_update(pgclass, &newtuple->t_self, newtuple);
08644
08645 CatalogUpdateIndexes(pgclass, newtuple);
08646
08647 InvokeObjectPostAlterHook(RelationRelationId, RelationGetRelid(rel), 0);
08648
08649 heap_freetuple(newtuple);
08650
08651 ReleaseSysCache(tuple);
08652
08653
08654 if (OidIsValid(rel->rd_rel->reltoastrelid))
08655 {
08656 Relation toastrel;
08657 Oid toastid = rel->rd_rel->reltoastrelid;
08658
08659 toastrel = heap_open(toastid, lockmode);
08660
08661
08662 tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(toastid));
08663 if (!HeapTupleIsValid(tuple))
08664 elog(ERROR, "cache lookup failed for relation %u", toastid);
08665
08666 if (operation == AT_ReplaceRelOptions)
08667 {
08668
08669
08670
08671
08672 datum = (Datum) 0;
08673 isnull = true;
08674 }
08675 else
08676 {
08677
08678 datum = SysCacheGetAttr(RELOID, tuple, Anum_pg_class_reloptions,
08679 &isnull);
08680 }
08681
08682 newOptions = transformRelOptions(isnull ? (Datum) 0 : datum,
08683 defList, "toast", validnsps, false,
08684 operation == AT_ResetRelOptions);
08685
08686 (void) heap_reloptions(RELKIND_TOASTVALUE, newOptions, true);
08687
08688 memset(repl_val, 0, sizeof(repl_val));
08689 memset(repl_null, false, sizeof(repl_null));
08690 memset(repl_repl, false, sizeof(repl_repl));
08691
08692 if (newOptions != (Datum) 0)
08693 repl_val[Anum_pg_class_reloptions - 1] = newOptions;
08694 else
08695 repl_null[Anum_pg_class_reloptions - 1] = true;
08696
08697 repl_repl[Anum_pg_class_reloptions - 1] = true;
08698
08699 newtuple = heap_modify_tuple(tuple, RelationGetDescr(pgclass),
08700 repl_val, repl_null, repl_repl);
08701
08702 simple_heap_update(pgclass, &newtuple->t_self, newtuple);
08703
08704 CatalogUpdateIndexes(pgclass, newtuple);
08705
08706 InvokeObjectPostAlterHookArg(RelationRelationId,
08707 RelationGetRelid(toastrel), 0,
08708 InvalidOid, true);
08709
08710 heap_freetuple(newtuple);
08711
08712 ReleaseSysCache(tuple);
08713
08714 heap_close(toastrel, NoLock);
08715 }
08716
08717 heap_close(pgclass, RowExclusiveLock);
08718 }
08719
08720
08721
08722
08723
08724 static void
08725 ATExecSetTableSpace(Oid tableOid, Oid newTableSpace, LOCKMODE lockmode)
08726 {
08727 Relation rel;
08728 Oid oldTableSpace;
08729 Oid reltoastrelid;
08730 Oid reltoastidxid;
08731 Oid newrelfilenode;
08732 RelFileNode newrnode;
08733 SMgrRelation dstrel;
08734 Relation pg_class;
08735 HeapTuple tuple;
08736 Form_pg_class rd_rel;
08737 ForkNumber forkNum;
08738
08739
08740
08741
08742 rel = relation_open(tableOid, lockmode);
08743
08744
08745
08746
08747 oldTableSpace = rel->rd_rel->reltablespace;
08748 if (newTableSpace == oldTableSpace ||
08749 (newTableSpace == MyDatabaseTableSpace && oldTableSpace == 0))
08750 {
08751 InvokeObjectPostAlterHook(RelationRelationId,
08752 RelationGetRelid(rel), 0);
08753
08754 relation_close(rel, NoLock);
08755 return;
08756 }
08757
08758
08759
08760
08761
08762 if (RelationIsMapped(rel))
08763 ereport(ERROR,
08764 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
08765 errmsg("cannot move system relation \"%s\"",
08766 RelationGetRelationName(rel))));
08767
08768
08769 if (newTableSpace == GLOBALTABLESPACE_OID)
08770 ereport(ERROR,
08771 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
08772 errmsg("only shared relations can be placed in pg_global tablespace")));
08773
08774
08775
08776
08777
08778 if (RELATION_IS_OTHER_TEMP(rel))
08779 ereport(ERROR,
08780 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
08781 errmsg("cannot move temporary tables of other sessions")));
08782
08783 reltoastrelid = rel->rd_rel->reltoastrelid;
08784 reltoastidxid = rel->rd_rel->reltoastidxid;
08785
08786
08787 pg_class = heap_open(RelationRelationId, RowExclusiveLock);
08788
08789 tuple = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(tableOid));
08790 if (!HeapTupleIsValid(tuple))
08791 elog(ERROR, "cache lookup failed for relation %u", tableOid);
08792 rd_rel = (Form_pg_class) GETSTRUCT(tuple);
08793
08794
08795
08796
08797
08798
08799
08800 FlushRelationBuffers(rel);
08801
08802
08803
08804
08805
08806 newrelfilenode = GetNewRelFileNode(newTableSpace, NULL,
08807 rel->rd_rel->relpersistence);
08808
08809
08810 newrnode = rel->rd_node;
08811 newrnode.relNode = newrelfilenode;
08812 newrnode.spcNode = newTableSpace;
08813 dstrel = smgropen(newrnode, rel->rd_backend);
08814
08815 RelationOpenSmgr(rel);
08816
08817
08818
08819
08820
08821
08822
08823
08824 RelationCreateStorage(newrnode, rel->rd_rel->relpersistence);
08825
08826
08827 copy_relation_data(rel->rd_smgr, dstrel, MAIN_FORKNUM,
08828 rel->rd_rel->relpersistence);
08829
08830
08831 for (forkNum = MAIN_FORKNUM + 1; forkNum <= MAX_FORKNUM; forkNum++)
08832 {
08833 if (smgrexists(rel->rd_smgr, forkNum))
08834 {
08835 smgrcreate(dstrel, forkNum, false);
08836 copy_relation_data(rel->rd_smgr, dstrel, forkNum,
08837 rel->rd_rel->relpersistence);
08838 }
08839 }
08840
08841
08842 RelationDropStorage(rel);
08843 smgrclose(dstrel);
08844
08845
08846 rd_rel->reltablespace = (newTableSpace == MyDatabaseTableSpace) ? InvalidOid : newTableSpace;
08847 rd_rel->relfilenode = newrelfilenode;
08848 simple_heap_update(pg_class, &tuple->t_self, tuple);
08849 CatalogUpdateIndexes(pg_class, tuple);
08850
08851 InvokeObjectPostAlterHook(RelationRelationId, RelationGetRelid(rel), 0);
08852
08853 heap_freetuple(tuple);
08854
08855 heap_close(pg_class, RowExclusiveLock);
08856
08857 relation_close(rel, NoLock);
08858
08859
08860 CommandCounterIncrement();
08861
08862
08863 if (OidIsValid(reltoastrelid))
08864 ATExecSetTableSpace(reltoastrelid, newTableSpace, lockmode);
08865 if (OidIsValid(reltoastidxid))
08866 ATExecSetTableSpace(reltoastidxid, newTableSpace, lockmode);
08867 }
08868
08869
08870
08871
08872 static void
08873 copy_relation_data(SMgrRelation src, SMgrRelation dst,
08874 ForkNumber forkNum, char relpersistence)
08875 {
08876 char *buf;
08877 Page page;
08878 bool use_wal;
08879 BlockNumber nblocks;
08880 BlockNumber blkno;
08881
08882
08883
08884
08885
08886
08887
08888 buf = (char *) palloc(BLCKSZ);
08889 page = (Page) buf;
08890
08891
08892
08893
08894
08895 use_wal = XLogIsNeeded() && relpersistence == RELPERSISTENCE_PERMANENT;
08896
08897 nblocks = smgrnblocks(src, forkNum);
08898
08899 for (blkno = 0; blkno < nblocks; blkno++)
08900 {
08901
08902 CHECK_FOR_INTERRUPTS();
08903
08904 smgrread(src, forkNum, blkno, buf);
08905
08906 if (!PageIsVerified(page, blkno))
08907 ereport(ERROR,
08908 (errcode(ERRCODE_DATA_CORRUPTED),
08909 errmsg("invalid page in block %u of relation %s",
08910 blkno,
08911 relpathbackend(src->smgr_rnode.node,
08912 src->smgr_rnode.backend,
08913 forkNum))));
08914
08915
08916 if (use_wal)
08917 log_newpage(&dst->smgr_rnode.node, forkNum, blkno, page);
08918
08919 PageSetChecksumInplace(page, blkno);
08920
08921
08922
08923
08924
08925
08926 smgrextend(dst, forkNum, blkno, buf, true);
08927 }
08928
08929 pfree(buf);
08930
08931
08932
08933
08934
08935
08936
08937
08938
08939
08940
08941
08942
08943
08944
08945
08946 if (relpersistence == RELPERSISTENCE_PERMANENT)
08947 smgrimmedsync(dst, forkNum);
08948 }
08949
08950
08951
08952
08953
08954
08955 static void
08956 ATExecEnableDisableTrigger(Relation rel, char *trigname,
08957 char fires_when, bool skip_system, LOCKMODE lockmode)
08958 {
08959 EnableDisableTrigger(rel, trigname, fires_when, skip_system);
08960 }
08961
08962
08963
08964
08965
08966
08967 static void
08968 ATExecEnableDisableRule(Relation rel, char *trigname,
08969 char fires_when, LOCKMODE lockmode)
08970 {
08971 EnableDisableRule(rel, trigname, fires_when);
08972 }
08973
08974
08975
08976
08977
08978
08979
08980
08981 static void
08982 ATPrepAddInherit(Relation child_rel)
08983 {
08984 if (child_rel->rd_rel->reloftype)
08985 ereport(ERROR,
08986 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
08987 errmsg("cannot change inheritance of typed table")));
08988 }
08989
08990 static void
08991 ATExecAddInherit(Relation child_rel, RangeVar *parent, LOCKMODE lockmode)
08992 {
08993 Relation parent_rel,
08994 catalogRelation;
08995 SysScanDesc scan;
08996 ScanKeyData key;
08997 HeapTuple inheritsTuple;
08998 int32 inhseqno;
08999 List *children;
09000
09001
09002
09003
09004
09005 parent_rel = heap_openrv(parent, ShareUpdateExclusiveLock);
09006
09007
09008
09009
09010
09011 ATSimplePermissions(parent_rel, ATT_TABLE);
09012
09013
09014 if (parent_rel->rd_rel->relpersistence == RELPERSISTENCE_TEMP &&
09015 child_rel->rd_rel->relpersistence != RELPERSISTENCE_TEMP)
09016 ereport(ERROR,
09017 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
09018 errmsg("cannot inherit from temporary relation \"%s\"",
09019 RelationGetRelationName(parent_rel))));
09020
09021
09022 if (parent_rel->rd_rel->relpersistence == RELPERSISTENCE_TEMP &&
09023 !parent_rel->rd_islocaltemp)
09024 ereport(ERROR,
09025 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
09026 errmsg("cannot inherit from temporary relation of another session")));
09027
09028
09029 if (child_rel->rd_rel->relpersistence == RELPERSISTENCE_TEMP &&
09030 !child_rel->rd_islocaltemp)
09031 ereport(ERROR,
09032 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
09033 errmsg("cannot inherit to temporary relation of another session")));
09034
09035
09036
09037
09038
09039
09040
09041
09042
09043 catalogRelation = heap_open(InheritsRelationId, RowExclusiveLock);
09044 ScanKeyInit(&key,
09045 Anum_pg_inherits_inhrelid,
09046 BTEqualStrategyNumber, F_OIDEQ,
09047 ObjectIdGetDatum(RelationGetRelid(child_rel)));
09048 scan = systable_beginscan(catalogRelation, InheritsRelidSeqnoIndexId,
09049 true, SnapshotNow, 1, &key);
09050
09051
09052 inhseqno = 0;
09053 while (HeapTupleIsValid(inheritsTuple = systable_getnext(scan)))
09054 {
09055 Form_pg_inherits inh = (Form_pg_inherits) GETSTRUCT(inheritsTuple);
09056
09057 if (inh->inhparent == RelationGetRelid(parent_rel))
09058 ereport(ERROR,
09059 (errcode(ERRCODE_DUPLICATE_TABLE),
09060 errmsg("relation \"%s\" would be inherited from more than once",
09061 RelationGetRelationName(parent_rel))));
09062 if (inh->inhseqno > inhseqno)
09063 inhseqno = inh->inhseqno;
09064 }
09065 systable_endscan(scan);
09066
09067
09068
09069
09070
09071
09072
09073
09074
09075
09076
09077
09078
09079
09080
09081 children = find_all_inheritors(RelationGetRelid(child_rel),
09082 AccessShareLock, NULL);
09083
09084 if (list_member_oid(children, RelationGetRelid(parent_rel)))
09085 ereport(ERROR,
09086 (errcode(ERRCODE_DUPLICATE_TABLE),
09087 errmsg("circular inheritance not allowed"),
09088 errdetail("\"%s\" is already a child of \"%s\".",
09089 parent->relname,
09090 RelationGetRelationName(child_rel))));
09091
09092
09093 if (parent_rel->rd_rel->relhasoids && !child_rel->rd_rel->relhasoids)
09094 ereport(ERROR,
09095 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
09096 errmsg("table \"%s\" without OIDs cannot inherit from table \"%s\" with OIDs",
09097 RelationGetRelationName(child_rel),
09098 RelationGetRelationName(parent_rel))));
09099
09100
09101 MergeAttributesIntoExisting(child_rel, parent_rel);
09102
09103
09104 MergeConstraintsIntoExisting(child_rel, parent_rel);
09105
09106
09107
09108
09109 StoreCatalogInheritance1(RelationGetRelid(child_rel),
09110 RelationGetRelid(parent_rel),
09111 inhseqno + 1,
09112 catalogRelation);
09113
09114
09115 heap_close(catalogRelation, RowExclusiveLock);
09116
09117
09118 heap_close(parent_rel, NoLock);
09119 }
09120
09121
09122
09123
09124
09125 static char *
09126 decompile_conbin(HeapTuple contup, TupleDesc tupdesc)
09127 {
09128 Form_pg_constraint con;
09129 bool isnull;
09130 Datum attr;
09131 Datum expr;
09132
09133 con = (Form_pg_constraint) GETSTRUCT(contup);
09134 attr = heap_getattr(contup, Anum_pg_constraint_conbin, tupdesc, &isnull);
09135 if (isnull)
09136 elog(ERROR, "null conbin for constraint %u", HeapTupleGetOid(contup));
09137
09138 expr = DirectFunctionCall2(pg_get_expr, attr,
09139 ObjectIdGetDatum(con->conrelid));
09140 return TextDatumGetCString(expr);
09141 }
09142
09143
09144
09145
09146
09147
09148
09149
09150 static bool
09151 constraints_equivalent(HeapTuple a, HeapTuple b, TupleDesc tupleDesc)
09152 {
09153 Form_pg_constraint acon = (Form_pg_constraint) GETSTRUCT(a);
09154 Form_pg_constraint bcon = (Form_pg_constraint) GETSTRUCT(b);
09155
09156 if (acon->condeferrable != bcon->condeferrable ||
09157 acon->condeferred != bcon->condeferred ||
09158 strcmp(decompile_conbin(a, tupleDesc),
09159 decompile_conbin(b, tupleDesc)) != 0)
09160 return false;
09161 else
09162 return true;
09163 }
09164
09165
09166
09167
09168
09169
09170
09171
09172
09173
09174
09175
09176
09177
09178
09179 static void
09180 MergeAttributesIntoExisting(Relation child_rel, Relation parent_rel)
09181 {
09182 Relation attrrel;
09183 AttrNumber parent_attno;
09184 int parent_natts;
09185 TupleDesc tupleDesc;
09186 HeapTuple tuple;
09187
09188 attrrel = heap_open(AttributeRelationId, RowExclusiveLock);
09189
09190 tupleDesc = RelationGetDescr(parent_rel);
09191 parent_natts = tupleDesc->natts;
09192
09193 for (parent_attno = 1; parent_attno <= parent_natts; parent_attno++)
09194 {
09195 Form_pg_attribute attribute = tupleDesc->attrs[parent_attno - 1];
09196 char *attributeName = NameStr(attribute->attname);
09197
09198
09199 if (attribute->attisdropped)
09200 continue;
09201
09202
09203 tuple = SearchSysCacheCopyAttName(RelationGetRelid(child_rel),
09204 attributeName);
09205 if (HeapTupleIsValid(tuple))
09206 {
09207
09208 Form_pg_attribute childatt = (Form_pg_attribute) GETSTRUCT(tuple);
09209
09210 if (attribute->atttypid != childatt->atttypid ||
09211 attribute->atttypmod != childatt->atttypmod)
09212 ereport(ERROR,
09213 (errcode(ERRCODE_DATATYPE_MISMATCH),
09214 errmsg("child table \"%s\" has different type for column \"%s\"",
09215 RelationGetRelationName(child_rel),
09216 attributeName)));
09217
09218 if (attribute->attcollation != childatt->attcollation)
09219 ereport(ERROR,
09220 (errcode(ERRCODE_COLLATION_MISMATCH),
09221 errmsg("child table \"%s\" has different collation for column \"%s\"",
09222 RelationGetRelationName(child_rel),
09223 attributeName)));
09224
09225
09226
09227
09228
09229 if (attribute->attnotnull && !childatt->attnotnull)
09230 ereport(ERROR,
09231 (errcode(ERRCODE_DATATYPE_MISMATCH),
09232 errmsg("column \"%s\" in child table must be marked NOT NULL",
09233 attributeName)));
09234
09235
09236
09237
09238
09239 childatt->attinhcount++;
09240 simple_heap_update(attrrel, &tuple->t_self, tuple);
09241 CatalogUpdateIndexes(attrrel, tuple);
09242 heap_freetuple(tuple);
09243 }
09244 else
09245 {
09246 ereport(ERROR,
09247 (errcode(ERRCODE_DATATYPE_MISMATCH),
09248 errmsg("child table is missing column \"%s\"",
09249 attributeName)));
09250 }
09251 }
09252
09253 heap_close(attrrel, RowExclusiveLock);
09254 }
09255
09256
09257
09258
09259
09260
09261
09262
09263
09264
09265
09266
09267
09268
09269
09270
09271
09272
09273 static void
09274 MergeConstraintsIntoExisting(Relation child_rel, Relation parent_rel)
09275 {
09276 Relation catalog_relation;
09277 TupleDesc tuple_desc;
09278 SysScanDesc parent_scan;
09279 ScanKeyData parent_key;
09280 HeapTuple parent_tuple;
09281
09282 catalog_relation = heap_open(ConstraintRelationId, RowExclusiveLock);
09283 tuple_desc = RelationGetDescr(catalog_relation);
09284
09285
09286 ScanKeyInit(&parent_key,
09287 Anum_pg_constraint_conrelid,
09288 BTEqualStrategyNumber, F_OIDEQ,
09289 ObjectIdGetDatum(RelationGetRelid(parent_rel)));
09290 parent_scan = systable_beginscan(catalog_relation, ConstraintRelidIndexId,
09291 true, SnapshotNow, 1, &parent_key);
09292
09293 while (HeapTupleIsValid(parent_tuple = systable_getnext(parent_scan)))
09294 {
09295 Form_pg_constraint parent_con = (Form_pg_constraint) GETSTRUCT(parent_tuple);
09296 SysScanDesc child_scan;
09297 ScanKeyData child_key;
09298 HeapTuple child_tuple;
09299 bool found = false;
09300
09301 if (parent_con->contype != CONSTRAINT_CHECK)
09302 continue;
09303
09304
09305 if (parent_con->connoinherit)
09306 continue;
09307
09308
09309 ScanKeyInit(&child_key,
09310 Anum_pg_constraint_conrelid,
09311 BTEqualStrategyNumber, F_OIDEQ,
09312 ObjectIdGetDatum(RelationGetRelid(child_rel)));
09313 child_scan = systable_beginscan(catalog_relation, ConstraintRelidIndexId,
09314 true, SnapshotNow, 1, &child_key);
09315
09316 while (HeapTupleIsValid(child_tuple = systable_getnext(child_scan)))
09317 {
09318 Form_pg_constraint child_con = (Form_pg_constraint) GETSTRUCT(child_tuple);
09319 HeapTuple child_copy;
09320
09321 if (child_con->contype != CONSTRAINT_CHECK)
09322 continue;
09323
09324 if (strcmp(NameStr(parent_con->conname),
09325 NameStr(child_con->conname)) != 0)
09326 continue;
09327
09328 if (!constraints_equivalent(parent_tuple, child_tuple, tuple_desc))
09329 ereport(ERROR,
09330 (errcode(ERRCODE_DATATYPE_MISMATCH),
09331 errmsg("child table \"%s\" has different definition for check constraint \"%s\"",
09332 RelationGetRelationName(child_rel),
09333 NameStr(parent_con->conname))));
09334
09335
09336 if (child_con->connoinherit)
09337 ereport(ERROR,
09338 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
09339 errmsg("constraint \"%s\" conflicts with non-inherited constraint on child table \"%s\"",
09340 NameStr(child_con->conname),
09341 RelationGetRelationName(child_rel))));
09342
09343
09344
09345
09346
09347 child_copy = heap_copytuple(child_tuple);
09348 child_con = (Form_pg_constraint) GETSTRUCT(child_copy);
09349 child_con->coninhcount++;
09350 simple_heap_update(catalog_relation, &child_copy->t_self, child_copy);
09351 CatalogUpdateIndexes(catalog_relation, child_copy);
09352 heap_freetuple(child_copy);
09353
09354 found = true;
09355 break;
09356 }
09357
09358 systable_endscan(child_scan);
09359
09360 if (!found)
09361 ereport(ERROR,
09362 (errcode(ERRCODE_DATATYPE_MISMATCH),
09363 errmsg("child table is missing constraint \"%s\"",
09364 NameStr(parent_con->conname))));
09365 }
09366
09367 systable_endscan(parent_scan);
09368 heap_close(catalog_relation, RowExclusiveLock);
09369 }
09370
09371
09372
09373
09374
09375
09376
09377
09378
09379
09380
09381
09382
09383
09384
09385
09386
09387 static void
09388 ATExecDropInherit(Relation rel, RangeVar *parent, LOCKMODE lockmode)
09389 {
09390 Relation parent_rel;
09391 Relation catalogRelation;
09392 SysScanDesc scan;
09393 ScanKeyData key[3];
09394 HeapTuple inheritsTuple,
09395 attributeTuple,
09396 constraintTuple;
09397 List *connames;
09398 bool found = false;
09399
09400
09401
09402
09403
09404
09405 parent_rel = heap_openrv(parent, AccessShareLock);
09406
09407
09408
09409
09410
09411
09412
09413
09414
09415
09416 catalogRelation = heap_open(InheritsRelationId, RowExclusiveLock);
09417 ScanKeyInit(&key[0],
09418 Anum_pg_inherits_inhrelid,
09419 BTEqualStrategyNumber, F_OIDEQ,
09420 ObjectIdGetDatum(RelationGetRelid(rel)));
09421 scan = systable_beginscan(catalogRelation, InheritsRelidSeqnoIndexId,
09422 true, SnapshotNow, 1, key);
09423
09424 while (HeapTupleIsValid(inheritsTuple = systable_getnext(scan)))
09425 {
09426 Oid inhparent;
09427
09428 inhparent = ((Form_pg_inherits) GETSTRUCT(inheritsTuple))->inhparent;
09429 if (inhparent == RelationGetRelid(parent_rel))
09430 {
09431 simple_heap_delete(catalogRelation, &inheritsTuple->t_self);
09432 found = true;
09433 break;
09434 }
09435 }
09436
09437 systable_endscan(scan);
09438 heap_close(catalogRelation, RowExclusiveLock);
09439
09440 if (!found)
09441 ereport(ERROR,
09442 (errcode(ERRCODE_UNDEFINED_TABLE),
09443 errmsg("relation \"%s\" is not a parent of relation \"%s\"",
09444 RelationGetRelationName(parent_rel),
09445 RelationGetRelationName(rel))));
09446
09447
09448
09449
09450 catalogRelation = heap_open(AttributeRelationId, RowExclusiveLock);
09451 ScanKeyInit(&key[0],
09452 Anum_pg_attribute_attrelid,
09453 BTEqualStrategyNumber, F_OIDEQ,
09454 ObjectIdGetDatum(RelationGetRelid(rel)));
09455 scan = systable_beginscan(catalogRelation, AttributeRelidNumIndexId,
09456 true, SnapshotNow, 1, key);
09457 while (HeapTupleIsValid(attributeTuple = systable_getnext(scan)))
09458 {
09459 Form_pg_attribute att = (Form_pg_attribute) GETSTRUCT(attributeTuple);
09460
09461
09462 if (att->attisdropped)
09463 continue;
09464 if (att->attinhcount <= 0)
09465 continue;
09466
09467 if (SearchSysCacheExistsAttName(RelationGetRelid(parent_rel),
09468 NameStr(att->attname)))
09469 {
09470
09471 HeapTuple copyTuple = heap_copytuple(attributeTuple);
09472 Form_pg_attribute copy_att = (Form_pg_attribute) GETSTRUCT(copyTuple);
09473
09474 copy_att->attinhcount--;
09475 if (copy_att->attinhcount == 0)
09476 copy_att->attislocal = true;
09477
09478 simple_heap_update(catalogRelation, ©Tuple->t_self, copyTuple);
09479 CatalogUpdateIndexes(catalogRelation, copyTuple);
09480 heap_freetuple(copyTuple);
09481 }
09482 }
09483 systable_endscan(scan);
09484 heap_close(catalogRelation, RowExclusiveLock);
09485
09486
09487
09488
09489
09490
09491
09492 catalogRelation = heap_open(ConstraintRelationId, RowExclusiveLock);
09493 ScanKeyInit(&key[0],
09494 Anum_pg_constraint_conrelid,
09495 BTEqualStrategyNumber, F_OIDEQ,
09496 ObjectIdGetDatum(RelationGetRelid(parent_rel)));
09497 scan = systable_beginscan(catalogRelation, ConstraintRelidIndexId,
09498 true, SnapshotNow, 1, key);
09499
09500 connames = NIL;
09501
09502 while (HeapTupleIsValid(constraintTuple = systable_getnext(scan)))
09503 {
09504 Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(constraintTuple);
09505
09506 if (con->contype == CONSTRAINT_CHECK)
09507 connames = lappend(connames, pstrdup(NameStr(con->conname)));
09508 }
09509
09510 systable_endscan(scan);
09511
09512
09513 ScanKeyInit(&key[0],
09514 Anum_pg_constraint_conrelid,
09515 BTEqualStrategyNumber, F_OIDEQ,
09516 ObjectIdGetDatum(RelationGetRelid(rel)));
09517 scan = systable_beginscan(catalogRelation, ConstraintRelidIndexId,
09518 true, SnapshotNow, 1, key);
09519
09520 while (HeapTupleIsValid(constraintTuple = systable_getnext(scan)))
09521 {
09522 Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(constraintTuple);
09523 bool match;
09524 ListCell *lc;
09525
09526 if (con->contype != CONSTRAINT_CHECK)
09527 continue;
09528
09529 match = false;
09530 foreach(lc, connames)
09531 {
09532 if (strcmp(NameStr(con->conname), (char *) lfirst(lc)) == 0)
09533 {
09534 match = true;
09535 break;
09536 }
09537 }
09538
09539 if (match)
09540 {
09541
09542 HeapTuple copyTuple = heap_copytuple(constraintTuple);
09543 Form_pg_constraint copy_con = (Form_pg_constraint) GETSTRUCT(copyTuple);
09544
09545 if (copy_con->coninhcount <= 0)
09546 elog(ERROR, "relation %u has non-inherited constraint \"%s\"",
09547 RelationGetRelid(rel), NameStr(copy_con->conname));
09548
09549 copy_con->coninhcount--;
09550 if (copy_con->coninhcount == 0)
09551 copy_con->conislocal = true;
09552
09553 simple_heap_update(catalogRelation, ©Tuple->t_self, copyTuple);
09554 CatalogUpdateIndexes(catalogRelation, copyTuple);
09555 heap_freetuple(copyTuple);
09556 }
09557 }
09558
09559 systable_endscan(scan);
09560 heap_close(catalogRelation, RowExclusiveLock);
09561
09562 drop_parent_dependency(RelationGetRelid(rel),
09563 RelationRelationId,
09564 RelationGetRelid(parent_rel));
09565
09566
09567
09568
09569
09570
09571 InvokeObjectPostAlterHookArg(InheritsRelationId,
09572 RelationGetRelid(rel), 0,
09573 RelationGetRelid(parent_rel), false);
09574
09575
09576 heap_close(parent_rel, NoLock);
09577 }
09578
09579
09580
09581
09582
09583
09584
09585
09586 static void
09587 drop_parent_dependency(Oid relid, Oid refclassid, Oid refobjid)
09588 {
09589 Relation catalogRelation;
09590 SysScanDesc scan;
09591 ScanKeyData key[3];
09592 HeapTuple depTuple;
09593
09594 catalogRelation = heap_open(DependRelationId, RowExclusiveLock);
09595
09596 ScanKeyInit(&key[0],
09597 Anum_pg_depend_classid,
09598 BTEqualStrategyNumber, F_OIDEQ,
09599 ObjectIdGetDatum(RelationRelationId));
09600 ScanKeyInit(&key[1],
09601 Anum_pg_depend_objid,
09602 BTEqualStrategyNumber, F_OIDEQ,
09603 ObjectIdGetDatum(relid));
09604 ScanKeyInit(&key[2],
09605 Anum_pg_depend_objsubid,
09606 BTEqualStrategyNumber, F_INT4EQ,
09607 Int32GetDatum(0));
09608
09609 scan = systable_beginscan(catalogRelation, DependDependerIndexId, true,
09610 SnapshotNow, 3, key);
09611
09612 while (HeapTupleIsValid(depTuple = systable_getnext(scan)))
09613 {
09614 Form_pg_depend dep = (Form_pg_depend) GETSTRUCT(depTuple);
09615
09616 if (dep->refclassid == refclassid &&
09617 dep->refobjid == refobjid &&
09618 dep->refobjsubid == 0 &&
09619 dep->deptype == DEPENDENCY_NORMAL)
09620 simple_heap_delete(catalogRelation, &depTuple->t_self);
09621 }
09622
09623 systable_endscan(scan);
09624 heap_close(catalogRelation, RowExclusiveLock);
09625 }
09626
09627
09628
09629
09630
09631
09632
09633
09634
09635 static void
09636 ATExecAddOf(Relation rel, const TypeName *ofTypename, LOCKMODE lockmode)
09637 {
09638 Oid relid = RelationGetRelid(rel);
09639 Type typetuple;
09640 Oid typeid;
09641 Relation inheritsRelation,
09642 relationRelation;
09643 SysScanDesc scan;
09644 ScanKeyData key;
09645 AttrNumber table_attno,
09646 type_attno;
09647 TupleDesc typeTupleDesc,
09648 tableTupleDesc;
09649 ObjectAddress tableobj,
09650 typeobj;
09651 HeapTuple classtuple;
09652
09653
09654 typetuple = typenameType(NULL, ofTypename, NULL);
09655 check_of_type(typetuple);
09656 typeid = HeapTupleGetOid(typetuple);
09657
09658
09659 inheritsRelation = heap_open(InheritsRelationId, AccessShareLock);
09660 ScanKeyInit(&key,
09661 Anum_pg_inherits_inhrelid,
09662 BTEqualStrategyNumber, F_OIDEQ,
09663 ObjectIdGetDatum(relid));
09664 scan = systable_beginscan(inheritsRelation, InheritsRelidSeqnoIndexId,
09665 true, SnapshotNow, 1, &key);
09666 if (HeapTupleIsValid(systable_getnext(scan)))
09667 ereport(ERROR,
09668 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
09669 errmsg("typed tables cannot inherit")));
09670 systable_endscan(scan);
09671 heap_close(inheritsRelation, AccessShareLock);
09672
09673
09674
09675
09676
09677
09678 typeTupleDesc = lookup_rowtype_tupdesc(typeid, -1);
09679 tableTupleDesc = RelationGetDescr(rel);
09680 table_attno = 1;
09681 for (type_attno = 1; type_attno <= typeTupleDesc->natts; type_attno++)
09682 {
09683 Form_pg_attribute type_attr,
09684 table_attr;
09685 const char *type_attname,
09686 *table_attname;
09687
09688
09689 type_attr = typeTupleDesc->attrs[type_attno - 1];
09690 if (type_attr->attisdropped)
09691 continue;
09692 type_attname = NameStr(type_attr->attname);
09693
09694
09695 do
09696 {
09697 if (table_attno > tableTupleDesc->natts)
09698 ereport(ERROR,
09699 (errcode(ERRCODE_DATATYPE_MISMATCH),
09700 errmsg("table is missing column \"%s\"",
09701 type_attname)));
09702 table_attr = tableTupleDesc->attrs[table_attno++ - 1];
09703 } while (table_attr->attisdropped);
09704 table_attname = NameStr(table_attr->attname);
09705
09706
09707 if (strncmp(table_attname, type_attname, NAMEDATALEN) != 0)
09708 ereport(ERROR,
09709 (errcode(ERRCODE_DATATYPE_MISMATCH),
09710 errmsg("table has column \"%s\" where type requires \"%s\"",
09711 table_attname, type_attname)));
09712
09713
09714 if (table_attr->atttypid != type_attr->atttypid ||
09715 table_attr->atttypmod != type_attr->atttypmod ||
09716 table_attr->attcollation != type_attr->attcollation)
09717 ereport(ERROR,
09718 (errcode(ERRCODE_DATATYPE_MISMATCH),
09719 errmsg("table \"%s\" has different type for column \"%s\"",
09720 RelationGetRelationName(rel), type_attname)));
09721 }
09722 DecrTupleDescRefCount(typeTupleDesc);
09723
09724
09725 for (; table_attno <= tableTupleDesc->natts; table_attno++)
09726 {
09727 Form_pg_attribute table_attr = tableTupleDesc->attrs[table_attno - 1];
09728
09729 if (!table_attr->attisdropped)
09730 ereport(ERROR,
09731 (errcode(ERRCODE_DATATYPE_MISMATCH),
09732 errmsg("table has extra column \"%s\"",
09733 NameStr(table_attr->attname))));
09734 }
09735
09736
09737 if (rel->rd_rel->reloftype)
09738 drop_parent_dependency(relid, TypeRelationId, rel->rd_rel->reloftype);
09739
09740
09741 tableobj.classId = RelationRelationId;
09742 tableobj.objectId = relid;
09743 tableobj.objectSubId = 0;
09744 typeobj.classId = TypeRelationId;
09745 typeobj.objectId = typeid;
09746 typeobj.objectSubId = 0;
09747 recordDependencyOn(&tableobj, &typeobj, DEPENDENCY_NORMAL);
09748
09749
09750 relationRelation = heap_open(RelationRelationId, RowExclusiveLock);
09751 classtuple = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
09752 if (!HeapTupleIsValid(classtuple))
09753 elog(ERROR, "cache lookup failed for relation %u", relid);
09754 ((Form_pg_class) GETSTRUCT(classtuple))->reloftype = typeid;
09755 simple_heap_update(relationRelation, &classtuple->t_self, classtuple);
09756 CatalogUpdateIndexes(relationRelation, classtuple);
09757
09758 InvokeObjectPostAlterHook(RelationRelationId, relid, 0);
09759
09760 heap_freetuple(classtuple);
09761 heap_close(relationRelation, RowExclusiveLock);
09762
09763 ReleaseSysCache(typetuple);
09764 }
09765
09766
09767
09768
09769
09770
09771
09772 static void
09773 ATExecDropOf(Relation rel, LOCKMODE lockmode)
09774 {
09775 Oid relid = RelationGetRelid(rel);
09776 Relation relationRelation;
09777 HeapTuple tuple;
09778
09779 if (!OidIsValid(rel->rd_rel->reloftype))
09780 ereport(ERROR,
09781 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
09782 errmsg("\"%s\" is not a typed table",
09783 RelationGetRelationName(rel))));
09784
09785
09786
09787
09788
09789
09790 drop_parent_dependency(relid, TypeRelationId, rel->rd_rel->reloftype);
09791
09792
09793 relationRelation = heap_open(RelationRelationId, RowExclusiveLock);
09794 tuple = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
09795 if (!HeapTupleIsValid(tuple))
09796 elog(ERROR, "cache lookup failed for relation %u", relid);
09797 ((Form_pg_class) GETSTRUCT(tuple))->reloftype = InvalidOid;
09798 simple_heap_update(relationRelation, &tuple->t_self, tuple);
09799 CatalogUpdateIndexes(relationRelation, tuple);
09800
09801 InvokeObjectPostAlterHook(RelationRelationId, relid, 0);
09802
09803 heap_freetuple(tuple);
09804 heap_close(relationRelation, RowExclusiveLock);
09805 }
09806
09807
09808
09809
09810 static void
09811 ATExecGenericOptions(Relation rel, List *options)
09812 {
09813 Relation ftrel;
09814 ForeignServer *server;
09815 ForeignDataWrapper *fdw;
09816 HeapTuple tuple;
09817 bool isnull;
09818 Datum repl_val[Natts_pg_foreign_table];
09819 bool repl_null[Natts_pg_foreign_table];
09820 bool repl_repl[Natts_pg_foreign_table];
09821 Datum datum;
09822 Form_pg_foreign_table tableform;
09823
09824 if (options == NIL)
09825 return;
09826
09827 ftrel = heap_open(ForeignTableRelationId, RowExclusiveLock);
09828
09829 tuple = SearchSysCacheCopy1(FOREIGNTABLEREL, rel->rd_id);
09830 if (!HeapTupleIsValid(tuple))
09831 ereport(ERROR,
09832 (errcode(ERRCODE_UNDEFINED_OBJECT),
09833 errmsg("foreign table \"%s\" does not exist",
09834 RelationGetRelationName(rel))));
09835 tableform = (Form_pg_foreign_table) GETSTRUCT(tuple);
09836 server = GetForeignServer(tableform->ftserver);
09837 fdw = GetForeignDataWrapper(server->fdwid);
09838
09839 memset(repl_val, 0, sizeof(repl_val));
09840 memset(repl_null, false, sizeof(repl_null));
09841 memset(repl_repl, false, sizeof(repl_repl));
09842
09843
09844 datum = SysCacheGetAttr(FOREIGNTABLEREL,
09845 tuple,
09846 Anum_pg_foreign_table_ftoptions,
09847 &isnull);
09848 if (isnull)
09849 datum = PointerGetDatum(NULL);
09850
09851
09852 datum = transformGenericOptions(ForeignTableRelationId,
09853 datum,
09854 options,
09855 fdw->fdwvalidator);
09856
09857 if (PointerIsValid(DatumGetPointer(datum)))
09858 repl_val[Anum_pg_foreign_table_ftoptions - 1] = datum;
09859 else
09860 repl_null[Anum_pg_foreign_table_ftoptions - 1] = true;
09861
09862 repl_repl[Anum_pg_foreign_table_ftoptions - 1] = true;
09863
09864
09865
09866 tuple = heap_modify_tuple(tuple, RelationGetDescr(ftrel),
09867 repl_val, repl_null, repl_repl);
09868
09869 simple_heap_update(ftrel, &tuple->t_self, tuple);
09870 CatalogUpdateIndexes(ftrel, tuple);
09871
09872 InvokeObjectPostAlterHook(ForeignTableRelationId,
09873 RelationGetRelid(rel), 0);
09874
09875 heap_close(ftrel, RowExclusiveLock);
09876
09877 heap_freetuple(tuple);
09878 }
09879
09880
09881
09882
09883 Oid
09884 AlterTableNamespace(AlterObjectSchemaStmt *stmt)
09885 {
09886 Relation rel;
09887 Oid relid;
09888 Oid oldNspOid;
09889 Oid nspOid;
09890 RangeVar *newrv;
09891 ObjectAddresses *objsMoved;
09892
09893 relid = RangeVarGetRelidExtended(stmt->relation, AccessExclusiveLock,
09894 stmt->missing_ok, false,
09895 RangeVarCallbackForAlterRelation,
09896 (void *) stmt);
09897
09898 if (!OidIsValid(relid))
09899 {
09900 ereport(NOTICE,
09901 (errmsg("relation \"%s\" does not exist, skipping",
09902 stmt->relation->relname)));
09903 return InvalidOid;
09904 }
09905
09906 rel = relation_open(relid, NoLock);
09907
09908 oldNspOid = RelationGetNamespace(rel);
09909
09910
09911 if (rel->rd_rel->relkind == RELKIND_SEQUENCE)
09912 {
09913 Oid tableId;
09914 int32 colId;
09915
09916 if (sequenceIsOwned(relid, &tableId, &colId))
09917 ereport(ERROR,
09918 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
09919 errmsg("cannot move an owned sequence into another schema"),
09920 errdetail("Sequence \"%s\" is linked to table \"%s\".",
09921 RelationGetRelationName(rel),
09922 get_rel_name(tableId))));
09923 }
09924
09925
09926 newrv = makeRangeVar(stmt->newschema, RelationGetRelationName(rel), -1);
09927 nspOid = RangeVarGetAndCheckCreationNamespace(newrv, NoLock, NULL);
09928
09929
09930 CheckSetNamespace(oldNspOid, nspOid, RelationRelationId, relid);
09931
09932 objsMoved = new_object_addresses();
09933 AlterTableNamespaceInternal(rel, oldNspOid, nspOid, objsMoved);
09934 free_object_addresses(objsMoved);
09935
09936
09937 relation_close(rel, NoLock);
09938
09939 return relid;
09940 }
09941
09942
09943
09944
09945
09946
09947 void
09948 AlterTableNamespaceInternal(Relation rel, Oid oldNspOid, Oid nspOid,
09949 ObjectAddresses *objsMoved)
09950 {
09951 Relation classRel;
09952
09953 Assert(objsMoved != NULL);
09954
09955
09956 classRel = heap_open(RelationRelationId, RowExclusiveLock);
09957
09958 AlterRelationNamespaceInternal(classRel, RelationGetRelid(rel), oldNspOid,
09959 nspOid, true, objsMoved);
09960
09961
09962 AlterTypeNamespaceInternal(rel->rd_rel->reltype,
09963 nspOid, false, false, objsMoved);
09964
09965
09966 if (rel->rd_rel->relkind == RELKIND_RELATION ||
09967 rel->rd_rel->relkind == RELKIND_MATVIEW)
09968 {
09969 AlterIndexNamespaces(classRel, rel, oldNspOid, nspOid, objsMoved);
09970 AlterSeqNamespaces(classRel, rel, oldNspOid, nspOid,
09971 objsMoved, AccessExclusiveLock);
09972 AlterConstraintNamespaces(RelationGetRelid(rel), oldNspOid, nspOid,
09973 false, objsMoved);
09974 }
09975
09976 heap_close(classRel, RowExclusiveLock);
09977 }
09978
09979
09980
09981
09982
09983
09984 void
09985 AlterRelationNamespaceInternal(Relation classRel, Oid relOid,
09986 Oid oldNspOid, Oid newNspOid,
09987 bool hasDependEntry, ObjectAddresses *objsMoved)
09988 {
09989 HeapTuple classTup;
09990 Form_pg_class classForm;
09991 ObjectAddress thisobj;
09992
09993 classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relOid));
09994 if (!HeapTupleIsValid(classTup))
09995 elog(ERROR, "cache lookup failed for relation %u", relOid);
09996 classForm = (Form_pg_class) GETSTRUCT(classTup);
09997
09998 Assert(classForm->relnamespace == oldNspOid);
09999
10000 thisobj.classId = RelationRelationId;
10001 thisobj.objectId = relOid;
10002 thisobj.objectSubId = 0;
10003
10004
10005
10006
10007 if (!object_address_present(&thisobj, objsMoved))
10008 {
10009
10010 if (get_relname_relid(NameStr(classForm->relname),
10011 newNspOid) != InvalidOid)
10012 ereport(ERROR,
10013 (errcode(ERRCODE_DUPLICATE_TABLE),
10014 errmsg("relation \"%s\" already exists in schema \"%s\"",
10015 NameStr(classForm->relname),
10016 get_namespace_name(newNspOid))));
10017
10018
10019 classForm->relnamespace = newNspOid;
10020
10021 simple_heap_update(classRel, &classTup->t_self, classTup);
10022 CatalogUpdateIndexes(classRel, classTup);
10023
10024
10025 if (hasDependEntry &&
10026 changeDependencyFor(RelationRelationId, relOid,
10027 NamespaceRelationId, oldNspOid, newNspOid) != 1)
10028 elog(ERROR, "failed to change schema dependency for relation \"%s\"",
10029 NameStr(classForm->relname));
10030
10031 add_exact_object_address(&thisobj, objsMoved);
10032
10033 InvokeObjectPostAlterHook(RelationRelationId, relOid, 0);
10034 }
10035
10036 heap_freetuple(classTup);
10037 }
10038
10039
10040
10041
10042
10043
10044
10045 static void
10046 AlterIndexNamespaces(Relation classRel, Relation rel,
10047 Oid oldNspOid, Oid newNspOid, ObjectAddresses *objsMoved)
10048 {
10049 List *indexList;
10050 ListCell *l;
10051
10052 indexList = RelationGetIndexList(rel);
10053
10054 foreach(l, indexList)
10055 {
10056 Oid indexOid = lfirst_oid(l);
10057 ObjectAddress thisobj;
10058
10059 thisobj.classId = RelationRelationId;
10060 thisobj.objectId = indexOid;
10061 thisobj.objectSubId = 0;
10062
10063
10064
10065
10066
10067
10068
10069
10070
10071 if (!object_address_present(&thisobj, objsMoved))
10072 {
10073 AlterRelationNamespaceInternal(classRel, indexOid,
10074 oldNspOid, newNspOid,
10075 false, objsMoved);
10076 add_exact_object_address(&thisobj, objsMoved);
10077 }
10078 }
10079
10080 list_free(indexList);
10081 }
10082
10083
10084
10085
10086
10087
10088
10089
10090 static void
10091 AlterSeqNamespaces(Relation classRel, Relation rel,
10092 Oid oldNspOid, Oid newNspOid, ObjectAddresses *objsMoved,
10093 LOCKMODE lockmode)
10094 {
10095 Relation depRel;
10096 SysScanDesc scan;
10097 ScanKeyData key[2];
10098 HeapTuple tup;
10099
10100
10101
10102
10103
10104 depRel = heap_open(DependRelationId, AccessShareLock);
10105
10106 ScanKeyInit(&key[0],
10107 Anum_pg_depend_refclassid,
10108 BTEqualStrategyNumber, F_OIDEQ,
10109 ObjectIdGetDatum(RelationRelationId));
10110 ScanKeyInit(&key[1],
10111 Anum_pg_depend_refobjid,
10112 BTEqualStrategyNumber, F_OIDEQ,
10113 ObjectIdGetDatum(RelationGetRelid(rel)));
10114
10115
10116 scan = systable_beginscan(depRel, DependReferenceIndexId, true,
10117 SnapshotNow, 2, key);
10118
10119 while (HeapTupleIsValid(tup = systable_getnext(scan)))
10120 {
10121 Form_pg_depend depForm = (Form_pg_depend) GETSTRUCT(tup);
10122 Relation seqRel;
10123
10124
10125 if (depForm->refobjsubid == 0 ||
10126 depForm->classid != RelationRelationId ||
10127 depForm->objsubid != 0 ||
10128 depForm->deptype != DEPENDENCY_AUTO)
10129 continue;
10130
10131
10132 seqRel = relation_open(depForm->objid, lockmode);
10133
10134
10135 if (RelationGetForm(seqRel)->relkind != RELKIND_SEQUENCE)
10136 {
10137
10138 relation_close(seqRel, lockmode);
10139 continue;
10140 }
10141
10142
10143 AlterRelationNamespaceInternal(classRel, depForm->objid,
10144 oldNspOid, newNspOid,
10145 true, objsMoved);
10146
10147
10148
10149
10150
10151 AlterTypeNamespaceInternal(RelationGetForm(seqRel)->reltype,
10152 newNspOid, false, false, objsMoved);
10153
10154
10155 relation_close(seqRel, NoLock);
10156 }
10157
10158 systable_endscan(scan);
10159
10160 relation_close(depRel, AccessShareLock);
10161 }
10162
10163
10164
10165
10166
10167
10168
10169
10170
10171
10172
10173
10174
10175 void
10176 register_on_commit_action(Oid relid, OnCommitAction action)
10177 {
10178 OnCommitItem *oc;
10179 MemoryContext oldcxt;
10180
10181
10182
10183
10184
10185 if (action == ONCOMMIT_NOOP || action == ONCOMMIT_PRESERVE_ROWS)
10186 return;
10187
10188 oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
10189
10190 oc = (OnCommitItem *) palloc(sizeof(OnCommitItem));
10191 oc->relid = relid;
10192 oc->oncommit = action;
10193 oc->creating_subid = GetCurrentSubTransactionId();
10194 oc->deleting_subid = InvalidSubTransactionId;
10195
10196 on_commits = lcons(oc, on_commits);
10197
10198 MemoryContextSwitchTo(oldcxt);
10199 }
10200
10201
10202
10203
10204
10205
10206 void
10207 remove_on_commit_action(Oid relid)
10208 {
10209 ListCell *l;
10210
10211 foreach(l, on_commits)
10212 {
10213 OnCommitItem *oc = (OnCommitItem *) lfirst(l);
10214
10215 if (oc->relid == relid)
10216 {
10217 oc->deleting_subid = GetCurrentSubTransactionId();
10218 break;
10219 }
10220 }
10221 }
10222
10223
10224
10225
10226
10227
10228
10229 void
10230 PreCommit_on_commit_actions(void)
10231 {
10232 ListCell *l;
10233 List *oids_to_truncate = NIL;
10234
10235 foreach(l, on_commits)
10236 {
10237 OnCommitItem *oc = (OnCommitItem *) lfirst(l);
10238
10239
10240 if (oc->deleting_subid != InvalidSubTransactionId)
10241 continue;
10242
10243 switch (oc->oncommit)
10244 {
10245 case ONCOMMIT_NOOP:
10246 case ONCOMMIT_PRESERVE_ROWS:
10247
10248 break;
10249 case ONCOMMIT_DELETE_ROWS:
10250
10251
10252
10253
10254
10255 if (MyXactAccessedTempRel)
10256 oids_to_truncate = lappend_oid(oids_to_truncate, oc->relid);
10257 break;
10258 case ONCOMMIT_DROP:
10259 {
10260 ObjectAddress object;
10261
10262 object.classId = RelationRelationId;
10263 object.objectId = oc->relid;
10264 object.objectSubId = 0;
10265
10266
10267
10268
10269
10270
10271 performDeletion(&object,
10272 DROP_CASCADE, PERFORM_DELETION_INTERNAL);
10273
10274
10275
10276
10277
10278
10279 Assert(oc->deleting_subid != InvalidSubTransactionId);
10280 break;
10281 }
10282 }
10283 }
10284 if (oids_to_truncate != NIL)
10285 {
10286 heap_truncate(oids_to_truncate);
10287 CommandCounterIncrement();
10288 }
10289 }
10290
10291
10292
10293
10294
10295
10296
10297
10298
10299 void
10300 AtEOXact_on_commit_actions(bool isCommit)
10301 {
10302 ListCell *cur_item;
10303 ListCell *prev_item;
10304
10305 prev_item = NULL;
10306 cur_item = list_head(on_commits);
10307
10308 while (cur_item != NULL)
10309 {
10310 OnCommitItem *oc = (OnCommitItem *) lfirst(cur_item);
10311
10312 if (isCommit ? oc->deleting_subid != InvalidSubTransactionId :
10313 oc->creating_subid != InvalidSubTransactionId)
10314 {
10315
10316 on_commits = list_delete_cell(on_commits, cur_item, prev_item);
10317 pfree(oc);
10318 if (prev_item)
10319 cur_item = lnext(prev_item);
10320 else
10321 cur_item = list_head(on_commits);
10322 }
10323 else
10324 {
10325
10326 oc->creating_subid = InvalidSubTransactionId;
10327 oc->deleting_subid = InvalidSubTransactionId;
10328 prev_item = cur_item;
10329 cur_item = lnext(prev_item);
10330 }
10331 }
10332 }
10333
10334
10335
10336
10337
10338
10339
10340
10341 void
10342 AtEOSubXact_on_commit_actions(bool isCommit, SubTransactionId mySubid,
10343 SubTransactionId parentSubid)
10344 {
10345 ListCell *cur_item;
10346 ListCell *prev_item;
10347
10348 prev_item = NULL;
10349 cur_item = list_head(on_commits);
10350
10351 while (cur_item != NULL)
10352 {
10353 OnCommitItem *oc = (OnCommitItem *) lfirst(cur_item);
10354
10355 if (!isCommit && oc->creating_subid == mySubid)
10356 {
10357
10358 on_commits = list_delete_cell(on_commits, cur_item, prev_item);
10359 pfree(oc);
10360 if (prev_item)
10361 cur_item = lnext(prev_item);
10362 else
10363 cur_item = list_head(on_commits);
10364 }
10365 else
10366 {
10367
10368 if (oc->creating_subid == mySubid)
10369 oc->creating_subid = parentSubid;
10370 if (oc->deleting_subid == mySubid)
10371 oc->deleting_subid = isCommit ? parentSubid : InvalidSubTransactionId;
10372 prev_item = cur_item;
10373 cur_item = lnext(prev_item);
10374 }
10375 }
10376 }
10377
10378
10379
10380
10381
10382
10383
10384
10385
10386 void
10387 RangeVarCallbackOwnsTable(const RangeVar *relation,
10388 Oid relId, Oid oldRelId, void *arg)
10389 {
10390 char relkind;
10391
10392
10393 if (!OidIsValid(relId))
10394 return;
10395
10396
10397
10398
10399
10400
10401 relkind = get_rel_relkind(relId);
10402 if (!relkind)
10403 return;
10404 if (relkind != RELKIND_RELATION && relkind != RELKIND_TOASTVALUE &&
10405 relkind != RELKIND_MATVIEW)
10406 ereport(ERROR,
10407 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
10408 errmsg("\"%s\" is not a table or materialized view", relation->relname)));
10409
10410
10411 if (!pg_class_ownercheck(relId, GetUserId()))
10412 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS, relation->relname);
10413 }
10414
10415
10416
10417
10418
10419 static void
10420 RangeVarCallbackForAlterRelation(const RangeVar *rv, Oid relid, Oid oldrelid,
10421 void *arg)
10422 {
10423 Node *stmt = (Node *) arg;
10424 ObjectType reltype;
10425 HeapTuple tuple;
10426 Form_pg_class classform;
10427 AclResult aclresult;
10428 char relkind;
10429
10430 tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
10431 if (!HeapTupleIsValid(tuple))
10432 return;
10433 classform = (Form_pg_class) GETSTRUCT(tuple);
10434 relkind = classform->relkind;
10435
10436
10437 if (!pg_class_ownercheck(relid, GetUserId()))
10438 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS, rv->relname);
10439
10440
10441 if (!allowSystemTableMods && IsSystemClass(classform))
10442 ereport(ERROR,
10443 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
10444 errmsg("permission denied: \"%s\" is a system catalog",
10445 rv->relname)));
10446
10447
10448
10449
10450
10451
10452
10453 if (IsA(stmt, RenameStmt))
10454 {
10455 aclresult = pg_namespace_aclcheck(classform->relnamespace,
10456 GetUserId(), ACL_CREATE);
10457 if (aclresult != ACLCHECK_OK)
10458 aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
10459 get_namespace_name(classform->relnamespace));
10460 reltype = ((RenameStmt *) stmt)->renameType;
10461 }
10462 else if (IsA(stmt, AlterObjectSchemaStmt))
10463 reltype = ((AlterObjectSchemaStmt *) stmt)->objectType;
10464
10465 else if (IsA(stmt, AlterTableStmt))
10466 reltype = ((AlterTableStmt *) stmt)->relkind;
10467 else
10468 {
10469 reltype = OBJECT_TABLE;
10470 elog(ERROR, "unrecognized node type: %d", (int) nodeTag(stmt));
10471 }
10472
10473
10474
10475
10476
10477
10478
10479
10480 if (reltype == OBJECT_SEQUENCE && relkind != RELKIND_SEQUENCE)
10481 ereport(ERROR,
10482 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
10483 errmsg("\"%s\" is not a sequence", rv->relname)));
10484
10485 if (reltype == OBJECT_VIEW && relkind != RELKIND_VIEW)
10486 ereport(ERROR,
10487 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
10488 errmsg("\"%s\" is not a view", rv->relname)));
10489
10490 if (reltype == OBJECT_MATVIEW && relkind != RELKIND_MATVIEW)
10491 ereport(ERROR,
10492 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
10493 errmsg("\"%s\" is not a materialized view", rv->relname)));
10494
10495 if (reltype == OBJECT_FOREIGN_TABLE && relkind != RELKIND_FOREIGN_TABLE)
10496 ereport(ERROR,
10497 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
10498 errmsg("\"%s\" is not a foreign table", rv->relname)));
10499
10500 if (reltype == OBJECT_TYPE && relkind != RELKIND_COMPOSITE_TYPE)
10501 ereport(ERROR,
10502 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
10503 errmsg("\"%s\" is not a composite type", rv->relname)));
10504
10505 if (reltype == OBJECT_INDEX && relkind != RELKIND_INDEX
10506 && !IsA(stmt, RenameStmt))
10507 ereport(ERROR,
10508 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
10509 errmsg("\"%s\" is not an index", rv->relname)));
10510
10511
10512
10513
10514
10515 if (reltype != OBJECT_TYPE && relkind == RELKIND_COMPOSITE_TYPE)
10516 ereport(ERROR,
10517 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
10518 errmsg("\"%s\" is a composite type", rv->relname),
10519 errhint("Use ALTER TYPE instead.")));
10520
10521 if (reltype != OBJECT_FOREIGN_TABLE && relkind == RELKIND_FOREIGN_TABLE)
10522 ereport(ERROR,
10523 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
10524 errmsg("\"%s\" is a foreign table", rv->relname),
10525 errhint("Use ALTER FOREIGN TABLE instead.")));
10526
10527
10528
10529
10530
10531 if (IsA(stmt, AlterObjectSchemaStmt) && relkind != RELKIND_RELATION
10532 && relkind != RELKIND_VIEW && relkind != RELKIND_MATVIEW
10533 && relkind != RELKIND_SEQUENCE && relkind != RELKIND_FOREIGN_TABLE)
10534 ereport(ERROR,
10535 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
10536 errmsg("\"%s\" is not a table, view, sequence, or foreign table",
10537 rv->relname)));
10538
10539 ReleaseSysCache(tuple);
10540 }