aboutsummaryrefslogtreecommitdiffstats
path: root/meta-oe/recipes-support
diff options
context:
space:
mode:
Diffstat (limited to 'meta-oe/recipes-support')
-rw-r--r--meta-oe/recipes-support/postgresql/files/0005-Avoid-repeated-name-lookups-during-table-and-index-D.patch1082
-rw-r--r--meta-oe/recipes-support/postgresql/postgresql.inc1
2 files changed, 1083 insertions, 0 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
new file mode 100644
index 0000000000..f1aa212502
--- /dev/null
+++ b/meta-oe/recipes-support/postgresql/files/0005-Avoid-repeated-name-lookups-during-table-and-index-D.patch
@@ -0,0 +1,1082 @@
+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
+
diff --git a/meta-oe/recipes-support/postgresql/postgresql.inc b/meta-oe/recipes-support/postgresql/postgresql.inc
index e2e5947b7c..9cfb2b6d87 100644
--- a/meta-oe/recipes-support/postgresql/postgresql.inc
+++ b/meta-oe/recipes-support/postgresql/postgresql.inc
@@ -34,6 +34,7 @@ SRC_URI = "http://ftp.postgresql.org/pub/source/v${PV}/${BP}.tar.bz2 \
file://0002-Predict-integer-overflow-to-avoid-buffer-overruns.patch \
file://0003-Shore-up-ADMIN-OPTION-restrictions.patch \
file://0004-Prevent-privilege-escalation-in-explicit-calls-to-PL.patch \
+ file://0005-Avoid-repeated-name-lookups-during-table-and-index-D.patch \
"
LEAD_SONAME = "libpq.so"