diff options
Diffstat (limited to 'meta-oe/recipes-support/postgresql/files/0005-Avoid-repeated-name-lookups-during-table-and-index-D.patch')
-rw-r--r-- | meta-oe/recipes-support/postgresql/files/0005-Avoid-repeated-name-lookups-during-table-and-index-D.patch | 1082 |
1 files changed, 0 insertions, 1082 deletions
diff --git a/meta-oe/recipes-support/postgresql/files/0005-Avoid-repeated-name-lookups-during-table-and-index-D.patch b/meta-oe/recipes-support/postgresql/files/0005-Avoid-repeated-name-lookups-during-table-and-index-D.patch deleted file mode 100644 index f1aa212502..0000000000 --- a/meta-oe/recipes-support/postgresql/files/0005-Avoid-repeated-name-lookups-during-table-and-index-D.patch +++ /dev/null @@ -1,1082 +0,0 @@ -From 820ab11fbfd508fc75a39c43ad2c1b3e79c4982b Mon Sep 17 00:00:00 2001 -From: Robert Haas <rhaas@postgresql.org> -Date: Mon, 17 Feb 2014 09:33:31 -0500 -Subject: [PATCH] Avoid repeated name lookups during table and index DDL. - -commit 820ab11fbfd508fc75a39c43ad2c1b3e79c4982b REL9_2_STABLE - -If the name lookups come to different conclusions due to concurrent -activity, we might perform some parts of the DDL on a different table -than other parts. At least in the case of CREATE INDEX, this can be -used to cause the permissions checks to be performed against a -different table than the index creation, allowing for a privilege -escalation attack. - -This changes the calling convention for DefineIndex, CreateTrigger, -transformIndexStmt, transformAlterTableStmt, CheckIndexCompatible -(in 9.2 and newer), and AlterTable (in 9.1 and older). In addition, -CheckRelationOwnership is removed in 9.2 and newer and the calling -convention is changed in older branches. A field has also been added -to the Constraint node (FkConstraint in 8.4). Third-party code calling -these functions or using the Constraint node will require updating. - -Report by Andres Freund. Patch by Robert Haas and Andres Freund, -reviewed by Tom Lane. - -Security: CVE-2014-0062 - -Upstream-Status: Backport - -Signed-off-by: Kai Kang <kai.kang@windriver.com> ---- - src/backend/bootstrap/bootparse.y | 17 ++++- - src/backend/catalog/index.c | 10 +-- - src/backend/catalog/pg_constraint.c | 19 +++++ - src/backend/commands/indexcmds.c | 22 ++++-- - src/backend/commands/tablecmds.c | 137 +++++++++++++++++++++++++---------- - src/backend/commands/trigger.c | 28 ++++++-- - src/backend/nodes/copyfuncs.c | 1 + - src/backend/nodes/equalfuncs.c | 1 + - src/backend/nodes/outfuncs.c | 1 + - src/backend/parser/parse_utilcmd.c | 64 ++++++----------- - src/backend/tcop/utility.c | 73 +++++++------------ - src/include/catalog/pg_constraint.h | 1 + - src/include/commands/defrem.h | 4 +- - src/include/commands/tablecmds.h | 2 + - src/include/commands/trigger.h | 2 +- - src/include/nodes/parsenodes.h | 2 + - src/include/parser/parse_utilcmd.h | 5 +- - src/include/tcop/utility.h | 2 - - 18 files changed, 234 insertions(+), 157 deletions(-) - -diff --git a/src/backend/bootstrap/bootparse.y b/src/backend/bootstrap/bootparse.y -index f4a1b8f..eeffb0f 100644 ---- a/src/backend/bootstrap/bootparse.y -+++ b/src/backend/bootstrap/bootparse.y -@@ -27,6 +27,7 @@ - #include "bootstrap/bootstrap.h" - #include "catalog/catalog.h" - #include "catalog/heap.h" -+#include "catalog/namespace.h" - #include "catalog/pg_am.h" - #include "catalog/pg_attribute.h" - #include "catalog/pg_authid.h" -@@ -281,6 +282,7 @@ Boot_DeclareIndexStmt: - XDECLARE INDEX boot_ident oidspec ON boot_ident USING boot_ident LPAREN boot_index_params RPAREN - { - IndexStmt *stmt = makeNode(IndexStmt); -+ Oid relationId; - - do_start(); - -@@ -302,7 +304,12 @@ Boot_DeclareIndexStmt: - stmt->initdeferred = false; - stmt->concurrent = false; - -- DefineIndex(stmt, -+ /* locks and races need not concern us in bootstrap mode */ -+ relationId = RangeVarGetRelid(stmt->relation, NoLock, -+ false); -+ -+ DefineIndex(relationId, -+ stmt, - $4, - false, - false, -@@ -316,6 +323,7 @@ Boot_DeclareUniqueIndexStmt: - XDECLARE UNIQUE INDEX boot_ident oidspec ON boot_ident USING boot_ident LPAREN boot_index_params RPAREN - { - IndexStmt *stmt = makeNode(IndexStmt); -+ Oid relationId; - - do_start(); - -@@ -337,7 +345,12 @@ Boot_DeclareUniqueIndexStmt: - stmt->initdeferred = false; - stmt->concurrent = false; - -- DefineIndex(stmt, -+ /* locks and races need not concern us in bootstrap mode */ -+ relationId = RangeVarGetRelid(stmt->relation, NoLock, -+ false); -+ -+ DefineIndex(relationId, -+ stmt, - $5, - false, - false, -diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c -index 7d6346a..ca8acf3 100644 ---- a/src/backend/catalog/index.c -+++ b/src/backend/catalog/index.c -@@ -1202,18 +1202,13 @@ index_constraint_create(Relation heapRelation, - */ - if (deferrable) - { -- RangeVar *heapRel; - CreateTrigStmt *trigger; - -- heapRel = makeRangeVar(get_namespace_name(namespaceId), -- pstrdup(RelationGetRelationName(heapRelation)), -- -1); -- - trigger = makeNode(CreateTrigStmt); - trigger->trigname = (constraintType == CONSTRAINT_PRIMARY) ? - "PK_ConstraintTrigger" : - "Unique_ConstraintTrigger"; -- trigger->relation = heapRel; -+ trigger->relation = NULL; - trigger->funcname = SystemFuncName("unique_key_recheck"); - trigger->args = NIL; - trigger->row = true; -@@ -1226,7 +1221,8 @@ index_constraint_create(Relation heapRelation, - trigger->initdeferred = initdeferred; - trigger->constrrel = NULL; - -- (void) CreateTrigger(trigger, NULL, conOid, indexRelationId, true); -+ (void) CreateTrigger(trigger, NULL, RelationGetRelid(heapRelation), -+ InvalidOid, conOid, indexRelationId, true); - } - - /* -diff --git a/src/backend/catalog/pg_constraint.c b/src/backend/catalog/pg_constraint.c -index 107a780..08a94cf 100644 ---- a/src/backend/catalog/pg_constraint.c -+++ b/src/backend/catalog/pg_constraint.c -@@ -746,6 +746,25 @@ AlterConstraintNamespaces(Oid ownerId, Oid oldNspId, - } - - /* -+ * get_constraint_relation_oids -+ * Find the IDs of the relations to which a constraint refers. -+ */ -+void -+get_constraint_relation_oids(Oid constraint_oid, Oid *conrelid, Oid *confrelid) -+{ -+ HeapTuple tup; -+ Form_pg_constraint con; -+ -+ tup = SearchSysCache1(CONSTROID, ObjectIdGetDatum(constraint_oid)); -+ if (!HeapTupleIsValid(tup)) /* should not happen */ -+ elog(ERROR, "cache lookup failed for constraint %u", constraint_oid); -+ con = (Form_pg_constraint) GETSTRUCT(tup); -+ *conrelid = con->conrelid; -+ *confrelid = con->confrelid; -+ ReleaseSysCache(tup); -+} -+ -+/* - * get_relation_constraint_oid - * Find a constraint on the specified relation with the specified name. - * Returns constraint's OID. -diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c -index f3ee278..ec5fb0d 100644 ---- a/src/backend/commands/indexcmds.c -+++ b/src/backend/commands/indexcmds.c -@@ -111,7 +111,6 @@ static void RangeVarCallbackForReindexIndex(const RangeVar *relation, - */ - bool - CheckIndexCompatible(Oid oldId, -- RangeVar *heapRelation, - char *accessMethodName, - List *attributeList, - List *exclusionOpNames) -@@ -139,7 +138,7 @@ CheckIndexCompatible(Oid oldId, - Datum d; - - /* Caller should already have the relation locked in some way. */ -- relationId = RangeVarGetRelid(heapRelation, NoLock, false); -+ relationId = IndexGetRelation(oldId, false); - - /* - * We can pretend isconstraint = false unconditionally. It only serves to -@@ -279,6 +278,8 @@ CheckIndexCompatible(Oid oldId, - * DefineIndex - * Creates a new index. - * -+ * 'relationId': the OID of the heap relation on which the index is to be -+ * created - * 'stmt': IndexStmt describing the properties of the new index. - * 'indexRelationId': normally InvalidOid, but during bootstrap can be - * nonzero to specify a preselected OID for the index. -@@ -292,7 +293,8 @@ CheckIndexCompatible(Oid oldId, - * Returns the OID of the created index. - */ - Oid --DefineIndex(IndexStmt *stmt, -+DefineIndex(Oid relationId, -+ IndexStmt *stmt, - Oid indexRelationId, - bool is_alter_table, - bool check_rights, -@@ -305,7 +307,6 @@ DefineIndex(IndexStmt *stmt, - Oid *collationObjectId; - Oid *classObjectId; - Oid accessMethodId; -- Oid relationId; - Oid namespaceId; - Oid tablespaceId; - List *indexColNames; -@@ -325,6 +326,7 @@ DefineIndex(IndexStmt *stmt, - int n_old_snapshots; - LockRelId heaprelid; - LOCKTAG heaplocktag; -+ LOCKMODE lockmode; - Snapshot snapshot; - int i; - -@@ -343,14 +345,18 @@ DefineIndex(IndexStmt *stmt, - INDEX_MAX_KEYS))); - - /* -- * Open heap relation, acquire a suitable lock on it, remember its OID -- * - * Only SELECT ... FOR UPDATE/SHARE are allowed while doing a standard - * index build; but for concurrent builds we allow INSERT/UPDATE/DELETE - * (but not VACUUM). -+ * -+ * NB: Caller is responsible for making sure that relationId refers -+ * to the relation on which the index should be built; except in bootstrap -+ * mode, this will typically require the caller to have already locked -+ * the relation. To avoid lock upgrade hazards, that lock should be at -+ * least as strong as the one we take here. - */ -- rel = heap_openrv(stmt->relation, -- (stmt->concurrent ? ShareUpdateExclusiveLock : ShareLock)); -+ lockmode = stmt->concurrent ? ShareUpdateExclusiveLock : ShareLock; -+ rel = heap_open(relationId, lockmode); - - relationId = RelationGetRelid(rel); - namespaceId = RelationGetNamespace(rel); -diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c -index 7c1f779..bcb81ea 100644 ---- a/src/backend/commands/tablecmds.c -+++ b/src/backend/commands/tablecmds.c -@@ -283,7 +283,8 @@ static void validateCheckConstraint(Relation rel, HeapTuple constrtup); - static void validateForeignKeyConstraint(char *conname, - Relation rel, Relation pkrel, - Oid pkindOid, Oid constraintOid); --static void createForeignKeyTriggers(Relation rel, Constraint *fkconstraint, -+static void createForeignKeyTriggers(Relation rel, Oid refRelOid, -+ Constraint *fkconstraint, - Oid constraintOid, Oid indexOid); - static void ATController(Relation rel, List *cmds, bool recurse, LOCKMODE lockmode); - static void ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd, -@@ -360,8 +361,9 @@ static void ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel, - static void ATExecAlterColumnGenericOptions(Relation rel, const char *colName, - List *options, LOCKMODE lockmode); - static void ATPostAlterTypeCleanup(List **wqueue, AlteredTableInfo *tab, LOCKMODE lockmode); --static void ATPostAlterTypeParse(Oid oldId, char *cmd, -- List **wqueue, LOCKMODE lockmode, bool rewrite); -+static void ATPostAlterTypeParse(Oid oldId, Oid oldRelId, Oid refRelId, -+ char *cmd, List **wqueue, LOCKMODE lockmode, -+ bool rewrite); - static void TryReuseIndex(Oid oldId, IndexStmt *stmt); - static void TryReuseForeignKey(Oid oldId, Constraint *con); - static void change_owner_fix_column_acls(Oid relationOid, -@@ -5406,7 +5408,8 @@ ATExecAddIndex(AlteredTableInfo *tab, Relation rel, - - /* The IndexStmt has already been through transformIndexStmt */ - -- new_index = DefineIndex(stmt, -+ new_index = DefineIndex(RelationGetRelid(rel), -+ stmt, - InvalidOid, /* no predefined OID */ - true, /* is_alter_table */ - check_rights, -@@ -5728,7 +5731,10 @@ ATAddForeignKeyConstraint(AlteredTableInfo *tab, Relation rel, - * table; trying to start with a lesser lock will just create a risk of - * deadlock.) - */ -- pkrel = heap_openrv(fkconstraint->pktable, AccessExclusiveLock); -+ if (OidIsValid(fkconstraint->old_pktable_oid)) -+ pkrel = heap_open(fkconstraint->old_pktable_oid, AccessExclusiveLock); -+ else -+ pkrel = heap_openrv(fkconstraint->pktable, AccessExclusiveLock); - - /* - * Validity checks (permission checks wait till we have the column -@@ -6066,7 +6072,8 @@ ATAddForeignKeyConstraint(AlteredTableInfo *tab, Relation rel, - /* - * Create the triggers that will enforce the constraint. - */ -- createForeignKeyTriggers(rel, fkconstraint, constrOid, indexOid); -+ createForeignKeyTriggers(rel, RelationGetRelid(pkrel), fkconstraint, -+ constrOid, indexOid); - - /* - * Tell Phase 3 to check that the constraint is satisfied by existing -@@ -6736,7 +6743,7 @@ validateForeignKeyConstraint(char *conname, - } - - static void --CreateFKCheckTrigger(RangeVar *myRel, Constraint *fkconstraint, -+CreateFKCheckTrigger(Oid myRelOid, Oid refRelOid, Constraint *fkconstraint, - Oid constraintOid, Oid indexOid, bool on_insert) - { - CreateTrigStmt *fk_trigger; -@@ -6752,7 +6759,7 @@ CreateFKCheckTrigger(RangeVar *myRel, Constraint *fkconstraint, - */ - fk_trigger = makeNode(CreateTrigStmt); - fk_trigger->trigname = "RI_ConstraintTrigger_c"; -- fk_trigger->relation = myRel; -+ fk_trigger->relation = NULL; - fk_trigger->row = true; - fk_trigger->timing = TRIGGER_TYPE_AFTER; - -@@ -6773,10 +6780,11 @@ CreateFKCheckTrigger(RangeVar *myRel, Constraint *fkconstraint, - fk_trigger->isconstraint = true; - fk_trigger->deferrable = fkconstraint->deferrable; - fk_trigger->initdeferred = fkconstraint->initdeferred; -- fk_trigger->constrrel = fkconstraint->pktable; -+ fk_trigger->constrrel = NULL; - fk_trigger->args = NIL; - -- (void) CreateTrigger(fk_trigger, NULL, constraintOid, indexOid, true); -+ (void) CreateTrigger(fk_trigger, NULL, myRelOid, refRelOid, constraintOid, -+ indexOid, true); - - /* Make changes-so-far visible */ - CommandCounterIncrement(); -@@ -6786,18 +6794,13 @@ CreateFKCheckTrigger(RangeVar *myRel, Constraint *fkconstraint, - * Create the triggers that implement an FK constraint. - */ - static void --createForeignKeyTriggers(Relation rel, Constraint *fkconstraint, -+createForeignKeyTriggers(Relation rel, Oid refRelOid, Constraint *fkconstraint, - Oid constraintOid, Oid indexOid) - { -- RangeVar *myRel; -+ Oid myRelOid; - CreateTrigStmt *fk_trigger; - -- /* -- * Reconstruct a RangeVar for my relation (not passed in, unfortunately). -- */ -- myRel = makeRangeVar(get_namespace_name(RelationGetNamespace(rel)), -- pstrdup(RelationGetRelationName(rel)), -- -1); -+ myRelOid = RelationGetRelid(rel); - - /* Make changes-so-far visible */ - CommandCounterIncrement(); -@@ -6808,14 +6811,14 @@ createForeignKeyTriggers(Relation rel, Constraint *fkconstraint, - */ - fk_trigger = makeNode(CreateTrigStmt); - fk_trigger->trigname = "RI_ConstraintTrigger_a"; -- fk_trigger->relation = fkconstraint->pktable; -+ fk_trigger->relation = NULL; - fk_trigger->row = true; - fk_trigger->timing = TRIGGER_TYPE_AFTER; - fk_trigger->events = TRIGGER_TYPE_DELETE; - fk_trigger->columns = NIL; - fk_trigger->whenClause = NULL; - fk_trigger->isconstraint = true; -- fk_trigger->constrrel = myRel; -+ fk_trigger->constrrel = NULL; - switch (fkconstraint->fk_del_action) - { - case FKCONSTR_ACTION_NOACTION: -@@ -6850,7 +6853,8 @@ createForeignKeyTriggers(Relation rel, Constraint *fkconstraint, - } - fk_trigger->args = NIL; - -- (void) CreateTrigger(fk_trigger, NULL, constraintOid, indexOid, true); -+ (void) CreateTrigger(fk_trigger, NULL, refRelOid, myRelOid, constraintOid, -+ indexOid, true); - - /* Make changes-so-far visible */ - CommandCounterIncrement(); -@@ -6861,14 +6865,14 @@ createForeignKeyTriggers(Relation rel, Constraint *fkconstraint, - */ - fk_trigger = makeNode(CreateTrigStmt); - fk_trigger->trigname = "RI_ConstraintTrigger_a"; -- fk_trigger->relation = fkconstraint->pktable; -+ fk_trigger->relation = NULL; - fk_trigger->row = true; - fk_trigger->timing = TRIGGER_TYPE_AFTER; - fk_trigger->events = TRIGGER_TYPE_UPDATE; - fk_trigger->columns = NIL; - fk_trigger->whenClause = NULL; - fk_trigger->isconstraint = true; -- fk_trigger->constrrel = myRel; -+ fk_trigger->constrrel = NULL; - switch (fkconstraint->fk_upd_action) - { - case FKCONSTR_ACTION_NOACTION: -@@ -6903,7 +6907,8 @@ createForeignKeyTriggers(Relation rel, Constraint *fkconstraint, - } - fk_trigger->args = NIL; - -- (void) CreateTrigger(fk_trigger, NULL, constraintOid, indexOid, true); -+ (void) CreateTrigger(fk_trigger, NULL, refRelOid, myRelOid, constraintOid, -+ indexOid, true); - - /* Make changes-so-far visible */ - CommandCounterIncrement(); -@@ -6912,8 +6917,10 @@ createForeignKeyTriggers(Relation rel, Constraint *fkconstraint, - * Build and execute CREATE CONSTRAINT TRIGGER statements for the CHECK - * action for both INSERTs and UPDATEs on the referencing table. - */ -- CreateFKCheckTrigger(myRel, fkconstraint, constraintOid, indexOid, true); -- CreateFKCheckTrigger(myRel, fkconstraint, constraintOid, indexOid, false); -+ CreateFKCheckTrigger(myRelOid, refRelOid, fkconstraint, constraintOid, -+ indexOid, true); -+ CreateFKCheckTrigger(myRelOid, refRelOid, fkconstraint, constraintOid, -+ indexOid, false); - } - - /* -@@ -7832,15 +7839,36 @@ ATPostAlterTypeCleanup(List **wqueue, AlteredTableInfo *tab, LOCKMODE lockmode) - * lock on the table the constraint is attached to, and we need to get - * that before dropping. It's safe because the parser won't actually look - * at the catalogs to detect the existing entry. -+ * -+ * We can't rely on the output of deparsing to tell us which relation -+ * to operate on, because concurrent activity might have made the name -+ * resolve differently. Instead, we've got to use the OID of the -+ * constraint or index we're processing to figure out which relation -+ * to operate on. - */ - forboth(oid_item, tab->changedConstraintOids, - def_item, tab->changedConstraintDefs) -- ATPostAlterTypeParse(lfirst_oid(oid_item), (char *) lfirst(def_item), -+ { -+ Oid oldId = lfirst_oid(oid_item); -+ Oid relid; -+ Oid confrelid; -+ -+ get_constraint_relation_oids(oldId, &relid, &confrelid); -+ ATPostAlterTypeParse(oldId, relid, confrelid, -+ (char *) lfirst(def_item), - wqueue, lockmode, tab->rewrite); -+ } - forboth(oid_item, tab->changedIndexOids, - def_item, tab->changedIndexDefs) -- ATPostAlterTypeParse(lfirst_oid(oid_item), (char *) lfirst(def_item), -+ { -+ Oid oldId = lfirst_oid(oid_item); -+ Oid relid; -+ -+ relid = IndexGetRelation(oldId, false); -+ ATPostAlterTypeParse(oldId, relid, InvalidOid, -+ (char *) lfirst(def_item), - wqueue, lockmode, tab->rewrite); -+ } - - /* - * Now we can drop the existing constraints and indexes --- constraints -@@ -7873,12 +7901,13 @@ ATPostAlterTypeCleanup(List **wqueue, AlteredTableInfo *tab, LOCKMODE lockmode) - } - - static void --ATPostAlterTypeParse(Oid oldId, char *cmd, -+ATPostAlterTypeParse(Oid oldId, Oid oldRelId, Oid refRelId, char *cmd, - List **wqueue, LOCKMODE lockmode, bool rewrite) - { - List *raw_parsetree_list; - List *querytree_list; - ListCell *list_item; -+ Relation rel; - - /* - * We expect that we will get only ALTER TABLE and CREATE INDEX -@@ -7894,16 +7923,21 @@ ATPostAlterTypeParse(Oid oldId, char *cmd, - - if (IsA(stmt, IndexStmt)) - querytree_list = lappend(querytree_list, -- transformIndexStmt((IndexStmt *) stmt, -+ transformIndexStmt(oldRelId, -+ (IndexStmt *) stmt, - cmd)); - else if (IsA(stmt, AlterTableStmt)) - querytree_list = list_concat(querytree_list, -- transformAlterTableStmt((AlterTableStmt *) stmt, -+ transformAlterTableStmt(oldRelId, -+ (AlterTableStmt *) stmt, - cmd)); - else - querytree_list = lappend(querytree_list, stmt); - } - -+ /* Caller should already have acquired whatever lock we need. */ -+ rel = relation_open(oldRelId, NoLock); -+ - /* - * Attach each generated command to the proper place in the work queue. - * Note this could result in creation of entirely new work-queue entries. -@@ -7915,7 +7949,6 @@ ATPostAlterTypeParse(Oid oldId, char *cmd, - foreach(list_item, querytree_list) - { - Node *stm = (Node *) lfirst(list_item); -- Relation rel; - AlteredTableInfo *tab; - - switch (nodeTag(stm)) -@@ -7928,14 +7961,12 @@ ATPostAlterTypeParse(Oid oldId, char *cmd, - if (!rewrite) - TryReuseIndex(oldId, stmt); - -- rel = relation_openrv(stmt->relation, lockmode); - tab = ATGetQueueEntry(wqueue, rel); - newcmd = makeNode(AlterTableCmd); - newcmd->subtype = AT_ReAddIndex; - newcmd->def = (Node *) stmt; - tab->subcmds[AT_PASS_OLD_INDEX] = - lappend(tab->subcmds[AT_PASS_OLD_INDEX], newcmd); -- relation_close(rel, NoLock); - break; - } - case T_AlterTableStmt: -@@ -7943,7 +7974,6 @@ ATPostAlterTypeParse(Oid oldId, char *cmd, - AlterTableStmt *stmt = (AlterTableStmt *) stm; - ListCell *lcmd; - -- rel = relation_openrv(stmt->relation, lockmode); - tab = ATGetQueueEntry(wqueue, rel); - foreach(lcmd, stmt->cmds) - { -@@ -7964,6 +7994,7 @@ ATPostAlterTypeParse(Oid oldId, char *cmd, - case AT_AddConstraint: - Assert(IsA(cmd->def, Constraint)); - con = (Constraint *) cmd->def; -+ con->old_pktable_oid = refRelId; - /* rewriting neither side of a FK */ - if (con->contype == CONSTR_FOREIGN && - !rewrite && !tab->rewrite) -@@ -7977,7 +8008,6 @@ ATPostAlterTypeParse(Oid oldId, char *cmd, - (int) cmd->subtype); - } - } -- relation_close(rel, NoLock); - break; - } - default: -@@ -7985,6 +8015,8 @@ ATPostAlterTypeParse(Oid oldId, char *cmd, - (int) nodeTag(stm)); - } - } -+ -+ relation_close(rel, NoLock); - } - - /* -@@ -7995,7 +8027,6 @@ static void - TryReuseIndex(Oid oldId, IndexStmt *stmt) - { - if (CheckIndexCompatible(oldId, -- stmt->relation, - stmt->accessMethod, - stmt->indexParams, - stmt->excludeOpNames)) -@@ -10291,6 +10322,38 @@ RangeVarCallbackOwnsTable(const RangeVar *relation, - } - - /* -+ * Callback to RangeVarGetRelidExtended(), similar to -+ * RangeVarCallbackOwnsTable() but without checks on the type of the relation. -+ */ -+void -+RangeVarCallbackOwnsRelation(const RangeVar *relation, -+ Oid relId, Oid oldRelId, void *arg) -+{ -+ HeapTuple tuple; -+ -+ /* Nothing to do if the relation was not found. */ -+ if (!OidIsValid(relId)) -+ return; -+ -+ tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relId)); -+ if (!HeapTupleIsValid(tuple)) /* should not happen */ -+ elog(ERROR, "cache lookup failed for relation %u", relId); -+ -+ if (!pg_class_ownercheck(relId, GetUserId())) -+ aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS, -+ relation->relname); -+ -+ if (!allowSystemTableMods && -+ IsSystemClass((Form_pg_class) GETSTRUCT(tuple))) -+ ereport(ERROR, -+ (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), -+ errmsg("permission denied: \"%s\" is a system catalog", -+ relation->relname))); -+ -+ ReleaseSysCache(tuple); -+} -+ -+/* - * Common RangeVarGetRelid callback for rename, set schema, and alter table - * processing. - */ -diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c -index f546d94..9e6c954 100644 ---- a/src/backend/commands/trigger.c -+++ b/src/backend/commands/trigger.c -@@ -42,6 +42,7 @@ - #include "pgstat.h" - #include "rewrite/rewriteManip.h" - #include "storage/bufmgr.h" -+#include "storage/lmgr.h" - #include "tcop/utility.h" - #include "utils/acl.h" - #include "utils/builtins.h" -@@ -94,6 +95,13 @@ static void AfterTriggerSaveEvent(EState *estate, ResultRelInfo *relinfo, - * queryString is the source text of the CREATE TRIGGER command. - * This must be supplied if a whenClause is specified, else it can be NULL. - * -+ * relOid, if nonzero, is the relation on which the trigger should be -+ * created. If zero, the name provided in the statement will be looked up. -+ * -+ * refRelOid, if nonzero, is the relation to which the constraint trigger -+ * refers. If zero, the constraint relation name provided in the statement -+ * will be looked up as needed. -+ * - * constraintOid, if nonzero, says that this trigger is being created - * internally to implement that constraint. A suitable pg_depend entry will - * be made to link the trigger to that constraint. constraintOid is zero when -@@ -116,7 +124,7 @@ static void AfterTriggerSaveEvent(EState *estate, ResultRelInfo *relinfo, - */ - Oid - CreateTrigger(CreateTrigStmt *stmt, const char *queryString, -- Oid constraintOid, Oid indexOid, -+ Oid relOid, Oid refRelOid, Oid constraintOid, Oid indexOid, - bool isInternal) - { - int16 tgtype; -@@ -145,7 +153,10 @@ CreateTrigger(CreateTrigStmt *stmt, const char *queryString, - ObjectAddress myself, - referenced; - -- rel = heap_openrv(stmt->relation, AccessExclusiveLock); -+ if (OidIsValid(relOid)) -+ rel = heap_open(relOid, AccessExclusiveLock); -+ else -+ rel = heap_openrv(stmt->relation, AccessExclusiveLock); - - /* - * Triggers must be on tables or views, and there are additional -@@ -194,7 +205,7 @@ CreateTrigger(CreateTrigStmt *stmt, const char *queryString, - errmsg("permission denied: \"%s\" is a system catalog", - RelationGetRelationName(rel)))); - -- if (stmt->isconstraint && stmt->constrrel != NULL) -+ if (stmt->isconstraint) - { - /* - * We must take a lock on the target relation to protect against -@@ -203,7 +214,14 @@ CreateTrigger(CreateTrigStmt *stmt, const char *queryString, - * might end up creating a pg_constraint entry referencing a - * nonexistent table. - */ -- constrrelid = RangeVarGetRelid(stmt->constrrel, AccessShareLock, false); -+ if (OidIsValid(refRelOid)) -+ { -+ LockRelationOid(refRelOid, AccessShareLock); -+ constrrelid = refRelOid; -+ } -+ else if (stmt->constrrel != NULL) -+ constrrelid = RangeVarGetRelid(stmt->constrrel, AccessShareLock, -+ false); - } - - /* permission checks */ -@@ -513,7 +531,7 @@ CreateTrigger(CreateTrigStmt *stmt, const char *queryString, - ereport(ERROR, - (errcode(ERRCODE_DUPLICATE_OBJECT), - errmsg("trigger \"%s\" for relation \"%s\" already exists", -- trigname, stmt->relation->relname))); -+ trigname, RelationGetRelationName(rel)))); - } - systable_endscan(tgscan); - } -diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c -index 9bac994..dbe0f6a 100644 ---- a/src/backend/nodes/copyfuncs.c -+++ b/src/backend/nodes/copyfuncs.c -@@ -2357,6 +2357,7 @@ _copyConstraint(const Constraint *from) - COPY_SCALAR_FIELD(fk_upd_action); - COPY_SCALAR_FIELD(fk_del_action); - COPY_NODE_FIELD(old_conpfeqop); -+ COPY_SCALAR_FIELD(old_pktable_oid); - COPY_SCALAR_FIELD(skip_validation); - COPY_SCALAR_FIELD(initially_valid); - -diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c -index d185654..f8770b0 100644 ---- a/src/backend/nodes/equalfuncs.c -+++ b/src/backend/nodes/equalfuncs.c -@@ -2143,6 +2143,7 @@ _equalConstraint(const Constraint *a, const Constraint *b) - COMPARE_SCALAR_FIELD(fk_upd_action); - COMPARE_SCALAR_FIELD(fk_del_action); - COMPARE_NODE_FIELD(old_conpfeqop); -+ COMPARE_SCALAR_FIELD(old_pktable_oid); - COMPARE_SCALAR_FIELD(skip_validation); - COMPARE_SCALAR_FIELD(initially_valid); - -diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c -index 1df71f6..888ffd2 100644 ---- a/src/backend/nodes/outfuncs.c -+++ b/src/backend/nodes/outfuncs.c -@@ -2653,6 +2653,7 @@ _outConstraint(StringInfo str, const Constraint *node) - WRITE_CHAR_FIELD(fk_upd_action); - WRITE_CHAR_FIELD(fk_del_action); - WRITE_NODE_FIELD(old_conpfeqop); -+ WRITE_OID_FIELD(old_pktable_oid); - WRITE_BOOL_FIELD(skip_validation); - WRITE_BOOL_FIELD(initially_valid); - break; -diff --git a/src/backend/parser/parse_utilcmd.c b/src/backend/parser/parse_utilcmd.c -index e3f9c62..5df939a 100644 ---- a/src/backend/parser/parse_utilcmd.c -+++ b/src/backend/parser/parse_utilcmd.c -@@ -1867,14 +1867,18 @@ transformFKConstraints(CreateStmtContext *cxt, - * a predicate expression. There are several code paths that create indexes - * without bothering to call this, because they know they don't have any - * such expressions to deal with. -+ * -+ * To avoid race conditions, it's important that this function rely only on -+ * the passed-in relid (and not on stmt->relation) to determine the target -+ * relation. - */ - IndexStmt * --transformIndexStmt(IndexStmt *stmt, const char *queryString) -+transformIndexStmt(Oid relid, IndexStmt *stmt, const char *queryString) - { -- Relation rel; - ParseState *pstate; - RangeTblEntry *rte; - ListCell *l; -+ Relation rel; - - /* - * We must not scribble on the passed-in IndexStmt, so copy it. (This is -@@ -1882,26 +1886,17 @@ transformIndexStmt(IndexStmt *stmt, const char *queryString) - */ - stmt = (IndexStmt *) copyObject(stmt); - -- /* -- * Open the parent table with appropriate locking. We must do this -- * because addRangeTableEntry() would acquire only AccessShareLock, -- * leaving DefineIndex() needing to do a lock upgrade with consequent risk -- * of deadlock. Make sure this stays in sync with the type of lock -- * DefineIndex() wants. If we are being called by ALTER TABLE, we will -- * already hold a higher lock. -- */ -- rel = heap_openrv(stmt->relation, -- (stmt->concurrent ? ShareUpdateExclusiveLock : ShareLock)); -- - /* Set up pstate */ - pstate = make_parsestate(NULL); - pstate->p_sourcetext = queryString; - - /* - * Put the parent table into the rtable so that the expressions can refer -- * to its fields without qualification. -+ * to its fields without qualification. Caller is responsible for locking -+ * relation, but we still need to open it. - */ -- rte = addRangeTableEntry(pstate, stmt->relation, NULL, false, true); -+ rel = relation_open(relid, NoLock); -+ rte = addRangeTableEntryForRelation(pstate, rel, NULL, false, true); - - /* no to join list, yes to namespaces */ - addRTEtoQuery(pstate, rte, false, true, true); -@@ -1955,7 +1950,7 @@ transformIndexStmt(IndexStmt *stmt, const char *queryString) - - free_parsestate(pstate); - -- /* Close relation, but keep the lock */ -+ /* Close relation */ - heap_close(rel, NoLock); - - return stmt; -@@ -2277,9 +2272,14 @@ transformRuleStmt(RuleStmt *stmt, const char *queryString, - * Returns a List of utility commands to be done in sequence. One of these - * will be the transformed AlterTableStmt, but there may be additional actions - * to be done before and after the actual AlterTable() call. -+ * -+ * To avoid race conditions, it's important that this function rely only on -+ * the passed-in relid (and not on stmt->relation) to determine the target -+ * relation. - */ - List * --transformAlterTableStmt(AlterTableStmt *stmt, const char *queryString) -+transformAlterTableStmt(Oid relid, AlterTableStmt *stmt, -+ const char *queryString) - { - Relation rel; - ParseState *pstate; -@@ -2291,7 +2291,6 @@ transformAlterTableStmt(AlterTableStmt *stmt, const char *queryString) - List *newcmds = NIL; - bool skipValidation = true; - AlterTableCmd *newcmd; -- LOCKMODE lockmode; - - /* - * We must not scribble on the passed-in AlterTableStmt, so copy it. (This -@@ -2299,29 +2298,8 @@ transformAlterTableStmt(AlterTableStmt *stmt, const char *queryString) - */ - stmt = (AlterTableStmt *) copyObject(stmt); - -- /* -- * Determine the appropriate lock level for this list of subcommands. -- */ -- lockmode = AlterTableGetLockLevel(stmt->cmds); -- -- /* -- * Acquire appropriate lock on the target relation, which will be held -- * until end of transaction. This ensures any decisions we make here -- * based on the state of the relation will still be good at execution. We -- * must get lock now because execution will later require it; taking a -- * lower grade lock now and trying to upgrade later risks deadlock. Any -- * new commands we add after this must not upgrade the lock level -- * requested here. -- */ -- rel = relation_openrv_extended(stmt->relation, lockmode, stmt->missing_ok); -- if (rel == NULL) -- { -- /* this message is consistent with relation_openrv */ -- ereport(NOTICE, -- (errmsg("relation \"%s\" does not exist, skipping", -- stmt->relation->relname))); -- return NIL; -- } -+ /* Caller is responsible for locking the relation */ -+ rel = relation_open(relid, NoLock); - - /* Set up pstate and CreateStmtContext */ - pstate = make_parsestate(NULL); -@@ -2434,7 +2412,7 @@ transformAlterTableStmt(AlterTableStmt *stmt, const char *queryString) - IndexStmt *idxstmt = (IndexStmt *) lfirst(l); - - Assert(IsA(idxstmt, IndexStmt)); -- idxstmt = transformIndexStmt(idxstmt, queryString); -+ idxstmt = transformIndexStmt(relid, idxstmt, queryString); - newcmd = makeNode(AlterTableCmd); - newcmd->subtype = OidIsValid(idxstmt->indexOid) ? AT_AddIndexConstraint : AT_AddIndex; - newcmd->def = (Node *) idxstmt; -@@ -2458,7 +2436,7 @@ transformAlterTableStmt(AlterTableStmt *stmt, const char *queryString) - newcmds = lappend(newcmds, newcmd); - } - -- /* Close rel but keep lock */ -+ /* Close rel */ - relation_close(rel, NoLock); - - /* -diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c -index 509bf4d..7903e03 100644 ---- a/src/backend/tcop/utility.c -+++ b/src/backend/tcop/utility.c -@@ -67,49 +67,6 @@ ProcessUtility_hook_type ProcessUtility_hook = NULL; - - - /* -- * Verify user has ownership of specified relation, else ereport. -- * -- * If noCatalogs is true then we also deny access to system catalogs, -- * except when allowSystemTableMods is true. -- */ --void --CheckRelationOwnership(RangeVar *rel, bool noCatalogs) --{ -- Oid relOid; -- HeapTuple tuple; -- -- /* -- * XXX: This is unsafe in the presence of concurrent DDL, since it is -- * called before acquiring any lock on the target relation. However, -- * locking the target relation (especially using something like -- * AccessExclusiveLock) before verifying that the user has permissions is -- * not appealing either. -- */ -- relOid = RangeVarGetRelid(rel, NoLock, false); -- -- tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relOid)); -- if (!HeapTupleIsValid(tuple)) /* should not happen */ -- elog(ERROR, "cache lookup failed for relation %u", relOid); -- -- if (!pg_class_ownercheck(relOid, GetUserId())) -- aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS, -- rel->relname); -- -- if (noCatalogs) -- { -- if (!allowSystemTableMods && -- IsSystemClass((Form_pg_class) GETSTRUCT(tuple))) -- ereport(ERROR, -- (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), -- errmsg("permission denied: \"%s\" is a system catalog", -- rel->relname))); -- } -- -- ReleaseSysCache(tuple); --} -- -- --/* - * CommandIsReadOnly: is an executable query read-only? - * - * This is a much stricter test than we apply for XactReadOnly mode; -@@ -723,7 +680,8 @@ standard_ProcessUtility(Node *parsetree, - if (OidIsValid(relid)) - { - /* Run parse analysis ... */ -- stmts = transformAlterTableStmt(atstmt, queryString); -+ stmts = transformAlterTableStmt(relid, atstmt, -+ queryString); - - /* ... and do it */ - foreach(l, stmts) -@@ -910,18 +868,36 @@ standard_ProcessUtility(Node *parsetree, - case T_IndexStmt: /* CREATE INDEX */ - { - IndexStmt *stmt = (IndexStmt *) parsetree; -+ Oid relid; -+ LOCKMODE lockmode; - - if (stmt->concurrent) - PreventTransactionChain(isTopLevel, - "CREATE INDEX CONCURRENTLY"); - -- CheckRelationOwnership(stmt->relation, true); -+ /* -+ * Look up the relation OID just once, right here at the -+ * beginning, so that we don't end up repeating the name -+ * lookup later and latching onto a different relation -+ * partway through. To avoid lock upgrade hazards, it's -+ * important that we take the strongest lock that will -+ * eventually be needed here, so the lockmode calculation -+ * needs to match what DefineIndex() does. -+ */ -+ lockmode = stmt->concurrent ? ShareUpdateExclusiveLock -+ : ShareLock; -+ relid = -+ RangeVarGetRelidExtended(stmt->relation, lockmode, -+ false, false, -+ RangeVarCallbackOwnsRelation, -+ NULL); - - /* Run parse analysis ... */ -- stmt = transformIndexStmt(stmt, queryString); -+ stmt = transformIndexStmt(relid, stmt, queryString); - - /* ... and do it */ -- DefineIndex(stmt, -+ DefineIndex(relid, /* OID of heap relation */ -+ stmt, - InvalidOid, /* no predefined OID */ - false, /* is_alter_table */ - true, /* check_rights */ -@@ -1057,7 +1033,8 @@ standard_ProcessUtility(Node *parsetree, - - case T_CreateTrigStmt: - (void) CreateTrigger((CreateTrigStmt *) parsetree, queryString, -- InvalidOid, InvalidOid, false); -+ InvalidOid, InvalidOid, InvalidOid, -+ InvalidOid, false); - break; - - case T_CreatePLangStmt: -diff --git a/src/include/catalog/pg_constraint.h b/src/include/catalog/pg_constraint.h -index d9d40b2..d8f8da4 100644 ---- a/src/include/catalog/pg_constraint.h -+++ b/src/include/catalog/pg_constraint.h -@@ -246,6 +246,7 @@ extern char *ChooseConstraintName(const char *name1, const char *name2, - - extern void AlterConstraintNamespaces(Oid ownerId, Oid oldNspId, - Oid newNspId, bool isType, ObjectAddresses *objsMoved); -+extern void get_constraint_relation_oids(Oid constraint_oid, Oid *conrelid, Oid *confrelid); - extern Oid get_relation_constraint_oid(Oid relid, const char *conname, bool missing_ok); - extern Oid get_domain_constraint_oid(Oid typid, const char *conname, bool missing_ok); - -diff --git a/src/include/commands/defrem.h b/src/include/commands/defrem.h -index 9b6d57a..a00fd37 100644 ---- a/src/include/commands/defrem.h -+++ b/src/include/commands/defrem.h -@@ -20,7 +20,8 @@ - extern void RemoveObjects(DropStmt *stmt); - - /* commands/indexcmds.c */ --extern Oid DefineIndex(IndexStmt *stmt, -+extern Oid DefineIndex(Oid relationId, -+ IndexStmt *stmt, - Oid indexRelationId, - bool is_alter_table, - bool check_rights, -@@ -35,7 +36,6 @@ extern char *makeObjectName(const char *name1, const char *name2, - extern char *ChooseRelationName(const char *name1, const char *name2, - const char *label, Oid namespaceid); - extern bool CheckIndexCompatible(Oid oldId, -- RangeVar *heapRelation, - char *accessMethodName, - List *attributeList, - List *exclusionOpNames); -diff --git a/src/include/commands/tablecmds.h b/src/include/commands/tablecmds.h -index 4f32062..d41f8a1 100644 ---- a/src/include/commands/tablecmds.h -+++ b/src/include/commands/tablecmds.h -@@ -78,4 +78,6 @@ extern void AtEOSubXact_on_commit_actions(bool isCommit, - extern void RangeVarCallbackOwnsTable(const RangeVar *relation, - Oid relId, Oid oldRelId, void *arg); - -+extern void RangeVarCallbackOwnsRelation(const RangeVar *relation, -+ Oid relId, Oid oldRelId, void *noCatalogs); - #endif /* TABLECMDS_H */ -diff --git a/src/include/commands/trigger.h b/src/include/commands/trigger.h -index 9303341..0869c0b 100644 ---- a/src/include/commands/trigger.h -+++ b/src/include/commands/trigger.h -@@ -109,7 +109,7 @@ extern PGDLLIMPORT int SessionReplicationRole; - #define TRIGGER_DISABLED 'D' - - extern Oid CreateTrigger(CreateTrigStmt *stmt, const char *queryString, -- Oid constraintOid, Oid indexOid, -+ Oid relOid, Oid refRelOid, Oid constraintOid, Oid indexOid, - bool isInternal); - - extern void RemoveTriggerById(Oid trigOid); -diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h -index 327f7cf..31f5479 100644 ---- a/src/include/nodes/parsenodes.h -+++ b/src/include/nodes/parsenodes.h -@@ -1566,6 +1566,8 @@ typedef struct Constraint - /* Fields used for constraints that allow a NOT VALID specification */ - bool skip_validation; /* skip validation of existing rows? */ - bool initially_valid; /* mark the new constraint as valid? */ -+ -+ Oid old_pktable_oid; /* pg_constraint.confrelid of my former self */ - } Constraint; - - /* ---------------------- -diff --git a/src/include/parser/parse_utilcmd.h b/src/include/parser/parse_utilcmd.h -index 4ad793a..d8b340e 100644 ---- a/src/include/parser/parse_utilcmd.h -+++ b/src/include/parser/parse_utilcmd.h -@@ -18,9 +18,10 @@ - - - extern List *transformCreateStmt(CreateStmt *stmt, const char *queryString); --extern List *transformAlterTableStmt(AlterTableStmt *stmt, -+extern List *transformAlterTableStmt(Oid relid, AlterTableStmt *stmt, - const char *queryString); --extern IndexStmt *transformIndexStmt(IndexStmt *stmt, const char *queryString); -+extern IndexStmt *transformIndexStmt(Oid relid, IndexStmt *stmt, -+ const char *queryString); - extern void transformRuleStmt(RuleStmt *stmt, const char *queryString, - List **actions, Node **whereClause); - extern List *transformCreateSchemaStmt(CreateSchemaStmt *stmt); -diff --git a/src/include/tcop/utility.h b/src/include/tcop/utility.h -index 54190b2..ae871ca 100644 ---- a/src/include/tcop/utility.h -+++ b/src/include/tcop/utility.h -@@ -42,6 +42,4 @@ extern LogStmtLevel GetCommandLogLevel(Node *parsetree); - - extern bool CommandIsReadOnly(Node *parsetree); - --extern void CheckRelationOwnership(RangeVar *rel, bool noCatalogs); -- - #endif /* UTILITY_H */ --- -1.7.5.4 - |