summaryrefslogtreecommitdiffstats
path: root/meta-oe/recipes-support/postgresql/files
diff options
context:
space:
mode:
Diffstat (limited to 'meta-oe/recipes-support/postgresql/files')
-rw-r--r--meta-oe/recipes-support/postgresql/files/0005-Avoid-repeated-name-lookups-during-table-and-index-D.patch1082
1 files changed, 1082 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 000000000..f1aa21250
--- /dev/null
+++ b/meta-oe/recipes-support/postgresql/files/0005-Avoid-repeated-name-lookups-during-table-and-index-D.patch
@@ -0,0 +1,1082 @@
1From 820ab11fbfd508fc75a39c43ad2c1b3e79c4982b Mon Sep 17 00:00:00 2001
2From: Robert Haas <rhaas@postgresql.org>
3Date: Mon, 17 Feb 2014 09:33:31 -0500
4Subject: [PATCH] Avoid repeated name lookups during table and index DDL.
5
6commit 820ab11fbfd508fc75a39c43ad2c1b3e79c4982b REL9_2_STABLE
7
8If the name lookups come to different conclusions due to concurrent
9activity, we might perform some parts of the DDL on a different table
10than other parts. At least in the case of CREATE INDEX, this can be
11used to cause the permissions checks to be performed against a
12different table than the index creation, allowing for a privilege
13escalation attack.
14
15This changes the calling convention for DefineIndex, CreateTrigger,
16transformIndexStmt, transformAlterTableStmt, CheckIndexCompatible
17(in 9.2 and newer), and AlterTable (in 9.1 and older). In addition,
18CheckRelationOwnership is removed in 9.2 and newer and the calling
19convention is changed in older branches. A field has also been added
20to the Constraint node (FkConstraint in 8.4). Third-party code calling
21these functions or using the Constraint node will require updating.
22
23Report by Andres Freund. Patch by Robert Haas and Andres Freund,
24reviewed by Tom Lane.
25
26Security: CVE-2014-0062
27
28Upstream-Status: Backport
29
30Signed-off-by: Kai Kang <kai.kang@windriver.com>
31---
32 src/backend/bootstrap/bootparse.y | 17 ++++-
33 src/backend/catalog/index.c | 10 +--
34 src/backend/catalog/pg_constraint.c | 19 +++++
35 src/backend/commands/indexcmds.c | 22 ++++--
36 src/backend/commands/tablecmds.c | 137 +++++++++++++++++++++++++----------
37 src/backend/commands/trigger.c | 28 ++++++--
38 src/backend/nodes/copyfuncs.c | 1 +
39 src/backend/nodes/equalfuncs.c | 1 +
40 src/backend/nodes/outfuncs.c | 1 +
41 src/backend/parser/parse_utilcmd.c | 64 ++++++-----------
42 src/backend/tcop/utility.c | 73 +++++++------------
43 src/include/catalog/pg_constraint.h | 1 +
44 src/include/commands/defrem.h | 4 +-
45 src/include/commands/tablecmds.h | 2 +
46 src/include/commands/trigger.h | 2 +-
47 src/include/nodes/parsenodes.h | 2 +
48 src/include/parser/parse_utilcmd.h | 5 +-
49 src/include/tcop/utility.h | 2 -
50 18 files changed, 234 insertions(+), 157 deletions(-)
51
52diff --git a/src/backend/bootstrap/bootparse.y b/src/backend/bootstrap/bootparse.y
53index f4a1b8f..eeffb0f 100644
54--- a/src/backend/bootstrap/bootparse.y
55+++ b/src/backend/bootstrap/bootparse.y
56@@ -27,6 +27,7 @@
57 #include "bootstrap/bootstrap.h"
58 #include "catalog/catalog.h"
59 #include "catalog/heap.h"
60+#include "catalog/namespace.h"
61 #include "catalog/pg_am.h"
62 #include "catalog/pg_attribute.h"
63 #include "catalog/pg_authid.h"
64@@ -281,6 +282,7 @@ Boot_DeclareIndexStmt:
65 XDECLARE INDEX boot_ident oidspec ON boot_ident USING boot_ident LPAREN boot_index_params RPAREN
66 {
67 IndexStmt *stmt = makeNode(IndexStmt);
68+ Oid relationId;
69
70 do_start();
71
72@@ -302,7 +304,12 @@ Boot_DeclareIndexStmt:
73 stmt->initdeferred = false;
74 stmt->concurrent = false;
75
76- DefineIndex(stmt,
77+ /* locks and races need not concern us in bootstrap mode */
78+ relationId = RangeVarGetRelid(stmt->relation, NoLock,
79+ false);
80+
81+ DefineIndex(relationId,
82+ stmt,
83 $4,
84 false,
85 false,
86@@ -316,6 +323,7 @@ Boot_DeclareUniqueIndexStmt:
87 XDECLARE UNIQUE INDEX boot_ident oidspec ON boot_ident USING boot_ident LPAREN boot_index_params RPAREN
88 {
89 IndexStmt *stmt = makeNode(IndexStmt);
90+ Oid relationId;
91
92 do_start();
93
94@@ -337,7 +345,12 @@ Boot_DeclareUniqueIndexStmt:
95 stmt->initdeferred = false;
96 stmt->concurrent = false;
97
98- DefineIndex(stmt,
99+ /* locks and races need not concern us in bootstrap mode */
100+ relationId = RangeVarGetRelid(stmt->relation, NoLock,
101+ false);
102+
103+ DefineIndex(relationId,
104+ stmt,
105 $5,
106 false,
107 false,
108diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
109index 7d6346a..ca8acf3 100644
110--- a/src/backend/catalog/index.c
111+++ b/src/backend/catalog/index.c
112@@ -1202,18 +1202,13 @@ index_constraint_create(Relation heapRelation,
113 */
114 if (deferrable)
115 {
116- RangeVar *heapRel;
117 CreateTrigStmt *trigger;
118
119- heapRel = makeRangeVar(get_namespace_name(namespaceId),
120- pstrdup(RelationGetRelationName(heapRelation)),
121- -1);
122-
123 trigger = makeNode(CreateTrigStmt);
124 trigger->trigname = (constraintType == CONSTRAINT_PRIMARY) ?
125 "PK_ConstraintTrigger" :
126 "Unique_ConstraintTrigger";
127- trigger->relation = heapRel;
128+ trigger->relation = NULL;
129 trigger->funcname = SystemFuncName("unique_key_recheck");
130 trigger->args = NIL;
131 trigger->row = true;
132@@ -1226,7 +1221,8 @@ index_constraint_create(Relation heapRelation,
133 trigger->initdeferred = initdeferred;
134 trigger->constrrel = NULL;
135
136- (void) CreateTrigger(trigger, NULL, conOid, indexRelationId, true);
137+ (void) CreateTrigger(trigger, NULL, RelationGetRelid(heapRelation),
138+ InvalidOid, conOid, indexRelationId, true);
139 }
140
141 /*
142diff --git a/src/backend/catalog/pg_constraint.c b/src/backend/catalog/pg_constraint.c
143index 107a780..08a94cf 100644
144--- a/src/backend/catalog/pg_constraint.c
145+++ b/src/backend/catalog/pg_constraint.c
146@@ -746,6 +746,25 @@ AlterConstraintNamespaces(Oid ownerId, Oid oldNspId,
147 }
148
149 /*
150+ * get_constraint_relation_oids
151+ * Find the IDs of the relations to which a constraint refers.
152+ */
153+void
154+get_constraint_relation_oids(Oid constraint_oid, Oid *conrelid, Oid *confrelid)
155+{
156+ HeapTuple tup;
157+ Form_pg_constraint con;
158+
159+ tup = SearchSysCache1(CONSTROID, ObjectIdGetDatum(constraint_oid));
160+ if (!HeapTupleIsValid(tup)) /* should not happen */
161+ elog(ERROR, "cache lookup failed for constraint %u", constraint_oid);
162+ con = (Form_pg_constraint) GETSTRUCT(tup);
163+ *conrelid = con->conrelid;
164+ *confrelid = con->confrelid;
165+ ReleaseSysCache(tup);
166+}
167+
168+/*
169 * get_relation_constraint_oid
170 * Find a constraint on the specified relation with the specified name.
171 * Returns constraint's OID.
172diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
173index f3ee278..ec5fb0d 100644
174--- a/src/backend/commands/indexcmds.c
175+++ b/src/backend/commands/indexcmds.c
176@@ -111,7 +111,6 @@ static void RangeVarCallbackForReindexIndex(const RangeVar *relation,
177 */
178 bool
179 CheckIndexCompatible(Oid oldId,
180- RangeVar *heapRelation,
181 char *accessMethodName,
182 List *attributeList,
183 List *exclusionOpNames)
184@@ -139,7 +138,7 @@ CheckIndexCompatible(Oid oldId,
185 Datum d;
186
187 /* Caller should already have the relation locked in some way. */
188- relationId = RangeVarGetRelid(heapRelation, NoLock, false);
189+ relationId = IndexGetRelation(oldId, false);
190
191 /*
192 * We can pretend isconstraint = false unconditionally. It only serves to
193@@ -279,6 +278,8 @@ CheckIndexCompatible(Oid oldId,
194 * DefineIndex
195 * Creates a new index.
196 *
197+ * 'relationId': the OID of the heap relation on which the index is to be
198+ * created
199 * 'stmt': IndexStmt describing the properties of the new index.
200 * 'indexRelationId': normally InvalidOid, but during bootstrap can be
201 * nonzero to specify a preselected OID for the index.
202@@ -292,7 +293,8 @@ CheckIndexCompatible(Oid oldId,
203 * Returns the OID of the created index.
204 */
205 Oid
206-DefineIndex(IndexStmt *stmt,
207+DefineIndex(Oid relationId,
208+ IndexStmt *stmt,
209 Oid indexRelationId,
210 bool is_alter_table,
211 bool check_rights,
212@@ -305,7 +307,6 @@ DefineIndex(IndexStmt *stmt,
213 Oid *collationObjectId;
214 Oid *classObjectId;
215 Oid accessMethodId;
216- Oid relationId;
217 Oid namespaceId;
218 Oid tablespaceId;
219 List *indexColNames;
220@@ -325,6 +326,7 @@ DefineIndex(IndexStmt *stmt,
221 int n_old_snapshots;
222 LockRelId heaprelid;
223 LOCKTAG heaplocktag;
224+ LOCKMODE lockmode;
225 Snapshot snapshot;
226 int i;
227
228@@ -343,14 +345,18 @@ DefineIndex(IndexStmt *stmt,
229 INDEX_MAX_KEYS)));
230
231 /*
232- * Open heap relation, acquire a suitable lock on it, remember its OID
233- *
234 * Only SELECT ... FOR UPDATE/SHARE are allowed while doing a standard
235 * index build; but for concurrent builds we allow INSERT/UPDATE/DELETE
236 * (but not VACUUM).
237+ *
238+ * NB: Caller is responsible for making sure that relationId refers
239+ * to the relation on which the index should be built; except in bootstrap
240+ * mode, this will typically require the caller to have already locked
241+ * the relation. To avoid lock upgrade hazards, that lock should be at
242+ * least as strong as the one we take here.
243 */
244- rel = heap_openrv(stmt->relation,
245- (stmt->concurrent ? ShareUpdateExclusiveLock : ShareLock));
246+ lockmode = stmt->concurrent ? ShareUpdateExclusiveLock : ShareLock;
247+ rel = heap_open(relationId, lockmode);
248
249 relationId = RelationGetRelid(rel);
250 namespaceId = RelationGetNamespace(rel);
251diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
252index 7c1f779..bcb81ea 100644
253--- a/src/backend/commands/tablecmds.c
254+++ b/src/backend/commands/tablecmds.c
255@@ -283,7 +283,8 @@ static void validateCheckConstraint(Relation rel, HeapTuple constrtup);
256 static void validateForeignKeyConstraint(char *conname,
257 Relation rel, Relation pkrel,
258 Oid pkindOid, Oid constraintOid);
259-static void createForeignKeyTriggers(Relation rel, Constraint *fkconstraint,
260+static void createForeignKeyTriggers(Relation rel, Oid refRelOid,
261+ Constraint *fkconstraint,
262 Oid constraintOid, Oid indexOid);
263 static void ATController(Relation rel, List *cmds, bool recurse, LOCKMODE lockmode);
264 static void ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd,
265@@ -360,8 +361,9 @@ static void ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel,
266 static void ATExecAlterColumnGenericOptions(Relation rel, const char *colName,
267 List *options, LOCKMODE lockmode);
268 static void ATPostAlterTypeCleanup(List **wqueue, AlteredTableInfo *tab, LOCKMODE lockmode);
269-static void ATPostAlterTypeParse(Oid oldId, char *cmd,
270- List **wqueue, LOCKMODE lockmode, bool rewrite);
271+static void ATPostAlterTypeParse(Oid oldId, Oid oldRelId, Oid refRelId,
272+ char *cmd, List **wqueue, LOCKMODE lockmode,
273+ bool rewrite);
274 static void TryReuseIndex(Oid oldId, IndexStmt *stmt);
275 static void TryReuseForeignKey(Oid oldId, Constraint *con);
276 static void change_owner_fix_column_acls(Oid relationOid,
277@@ -5406,7 +5408,8 @@ ATExecAddIndex(AlteredTableInfo *tab, Relation rel,
278
279 /* The IndexStmt has already been through transformIndexStmt */
280
281- new_index = DefineIndex(stmt,
282+ new_index = DefineIndex(RelationGetRelid(rel),
283+ stmt,
284 InvalidOid, /* no predefined OID */
285 true, /* is_alter_table */
286 check_rights,
287@@ -5728,7 +5731,10 @@ ATAddForeignKeyConstraint(AlteredTableInfo *tab, Relation rel,
288 * table; trying to start with a lesser lock will just create a risk of
289 * deadlock.)
290 */
291- pkrel = heap_openrv(fkconstraint->pktable, AccessExclusiveLock);
292+ if (OidIsValid(fkconstraint->old_pktable_oid))
293+ pkrel = heap_open(fkconstraint->old_pktable_oid, AccessExclusiveLock);
294+ else
295+ pkrel = heap_openrv(fkconstraint->pktable, AccessExclusiveLock);
296
297 /*
298 * Validity checks (permission checks wait till we have the column
299@@ -6066,7 +6072,8 @@ ATAddForeignKeyConstraint(AlteredTableInfo *tab, Relation rel,
300 /*
301 * Create the triggers that will enforce the constraint.
302 */
303- createForeignKeyTriggers(rel, fkconstraint, constrOid, indexOid);
304+ createForeignKeyTriggers(rel, RelationGetRelid(pkrel), fkconstraint,
305+ constrOid, indexOid);
306
307 /*
308 * Tell Phase 3 to check that the constraint is satisfied by existing
309@@ -6736,7 +6743,7 @@ validateForeignKeyConstraint(char *conname,
310 }
311
312 static void
313-CreateFKCheckTrigger(RangeVar *myRel, Constraint *fkconstraint,
314+CreateFKCheckTrigger(Oid myRelOid, Oid refRelOid, Constraint *fkconstraint,
315 Oid constraintOid, Oid indexOid, bool on_insert)
316 {
317 CreateTrigStmt *fk_trigger;
318@@ -6752,7 +6759,7 @@ CreateFKCheckTrigger(RangeVar *myRel, Constraint *fkconstraint,
319 */
320 fk_trigger = makeNode(CreateTrigStmt);
321 fk_trigger->trigname = "RI_ConstraintTrigger_c";
322- fk_trigger->relation = myRel;
323+ fk_trigger->relation = NULL;
324 fk_trigger->row = true;
325 fk_trigger->timing = TRIGGER_TYPE_AFTER;
326
327@@ -6773,10 +6780,11 @@ CreateFKCheckTrigger(RangeVar *myRel, Constraint *fkconstraint,
328 fk_trigger->isconstraint = true;
329 fk_trigger->deferrable = fkconstraint->deferrable;
330 fk_trigger->initdeferred = fkconstraint->initdeferred;
331- fk_trigger->constrrel = fkconstraint->pktable;
332+ fk_trigger->constrrel = NULL;
333 fk_trigger->args = NIL;
334
335- (void) CreateTrigger(fk_trigger, NULL, constraintOid, indexOid, true);
336+ (void) CreateTrigger(fk_trigger, NULL, myRelOid, refRelOid, constraintOid,
337+ indexOid, true);
338
339 /* Make changes-so-far visible */
340 CommandCounterIncrement();
341@@ -6786,18 +6794,13 @@ CreateFKCheckTrigger(RangeVar *myRel, Constraint *fkconstraint,
342 * Create the triggers that implement an FK constraint.
343 */
344 static void
345-createForeignKeyTriggers(Relation rel, Constraint *fkconstraint,
346+createForeignKeyTriggers(Relation rel, Oid refRelOid, Constraint *fkconstraint,
347 Oid constraintOid, Oid indexOid)
348 {
349- RangeVar *myRel;
350+ Oid myRelOid;
351 CreateTrigStmt *fk_trigger;
352
353- /*
354- * Reconstruct a RangeVar for my relation (not passed in, unfortunately).
355- */
356- myRel = makeRangeVar(get_namespace_name(RelationGetNamespace(rel)),
357- pstrdup(RelationGetRelationName(rel)),
358- -1);
359+ myRelOid = RelationGetRelid(rel);
360
361 /* Make changes-so-far visible */
362 CommandCounterIncrement();
363@@ -6808,14 +6811,14 @@ createForeignKeyTriggers(Relation rel, Constraint *fkconstraint,
364 */
365 fk_trigger = makeNode(CreateTrigStmt);
366 fk_trigger->trigname = "RI_ConstraintTrigger_a";
367- fk_trigger->relation = fkconstraint->pktable;
368+ fk_trigger->relation = NULL;
369 fk_trigger->row = true;
370 fk_trigger->timing = TRIGGER_TYPE_AFTER;
371 fk_trigger->events = TRIGGER_TYPE_DELETE;
372 fk_trigger->columns = NIL;
373 fk_trigger->whenClause = NULL;
374 fk_trigger->isconstraint = true;
375- fk_trigger->constrrel = myRel;
376+ fk_trigger->constrrel = NULL;
377 switch (fkconstraint->fk_del_action)
378 {
379 case FKCONSTR_ACTION_NOACTION:
380@@ -6850,7 +6853,8 @@ createForeignKeyTriggers(Relation rel, Constraint *fkconstraint,
381 }
382 fk_trigger->args = NIL;
383
384- (void) CreateTrigger(fk_trigger, NULL, constraintOid, indexOid, true);
385+ (void) CreateTrigger(fk_trigger, NULL, refRelOid, myRelOid, constraintOid,
386+ indexOid, true);
387
388 /* Make changes-so-far visible */
389 CommandCounterIncrement();
390@@ -6861,14 +6865,14 @@ createForeignKeyTriggers(Relation rel, Constraint *fkconstraint,
391 */
392 fk_trigger = makeNode(CreateTrigStmt);
393 fk_trigger->trigname = "RI_ConstraintTrigger_a";
394- fk_trigger->relation = fkconstraint->pktable;
395+ fk_trigger->relation = NULL;
396 fk_trigger->row = true;
397 fk_trigger->timing = TRIGGER_TYPE_AFTER;
398 fk_trigger->events = TRIGGER_TYPE_UPDATE;
399 fk_trigger->columns = NIL;
400 fk_trigger->whenClause = NULL;
401 fk_trigger->isconstraint = true;
402- fk_trigger->constrrel = myRel;
403+ fk_trigger->constrrel = NULL;
404 switch (fkconstraint->fk_upd_action)
405 {
406 case FKCONSTR_ACTION_NOACTION:
407@@ -6903,7 +6907,8 @@ createForeignKeyTriggers(Relation rel, Constraint *fkconstraint,
408 }
409 fk_trigger->args = NIL;
410
411- (void) CreateTrigger(fk_trigger, NULL, constraintOid, indexOid, true);
412+ (void) CreateTrigger(fk_trigger, NULL, refRelOid, myRelOid, constraintOid,
413+ indexOid, true);
414
415 /* Make changes-so-far visible */
416 CommandCounterIncrement();
417@@ -6912,8 +6917,10 @@ createForeignKeyTriggers(Relation rel, Constraint *fkconstraint,
418 * Build and execute CREATE CONSTRAINT TRIGGER statements for the CHECK
419 * action for both INSERTs and UPDATEs on the referencing table.
420 */
421- CreateFKCheckTrigger(myRel, fkconstraint, constraintOid, indexOid, true);
422- CreateFKCheckTrigger(myRel, fkconstraint, constraintOid, indexOid, false);
423+ CreateFKCheckTrigger(myRelOid, refRelOid, fkconstraint, constraintOid,
424+ indexOid, true);
425+ CreateFKCheckTrigger(myRelOid, refRelOid, fkconstraint, constraintOid,
426+ indexOid, false);
427 }
428
429 /*
430@@ -7832,15 +7839,36 @@ ATPostAlterTypeCleanup(List **wqueue, AlteredTableInfo *tab, LOCKMODE lockmode)
431 * lock on the table the constraint is attached to, and we need to get
432 * that before dropping. It's safe because the parser won't actually look
433 * at the catalogs to detect the existing entry.
434+ *
435+ * We can't rely on the output of deparsing to tell us which relation
436+ * to operate on, because concurrent activity might have made the name
437+ * resolve differently. Instead, we've got to use the OID of the
438+ * constraint or index we're processing to figure out which relation
439+ * to operate on.
440 */
441 forboth(oid_item, tab->changedConstraintOids,
442 def_item, tab->changedConstraintDefs)
443- ATPostAlterTypeParse(lfirst_oid(oid_item), (char *) lfirst(def_item),
444+ {
445+ Oid oldId = lfirst_oid(oid_item);
446+ Oid relid;
447+ Oid confrelid;
448+
449+ get_constraint_relation_oids(oldId, &relid, &confrelid);
450+ ATPostAlterTypeParse(oldId, relid, confrelid,
451+ (char *) lfirst(def_item),
452 wqueue, lockmode, tab->rewrite);
453+ }
454 forboth(oid_item, tab->changedIndexOids,
455 def_item, tab->changedIndexDefs)
456- ATPostAlterTypeParse(lfirst_oid(oid_item), (char *) lfirst(def_item),
457+ {
458+ Oid oldId = lfirst_oid(oid_item);
459+ Oid relid;
460+
461+ relid = IndexGetRelation(oldId, false);
462+ ATPostAlterTypeParse(oldId, relid, InvalidOid,
463+ (char *) lfirst(def_item),
464 wqueue, lockmode, tab->rewrite);
465+ }
466
467 /*
468 * Now we can drop the existing constraints and indexes --- constraints
469@@ -7873,12 +7901,13 @@ ATPostAlterTypeCleanup(List **wqueue, AlteredTableInfo *tab, LOCKMODE lockmode)
470 }
471
472 static void
473-ATPostAlterTypeParse(Oid oldId, char *cmd,
474+ATPostAlterTypeParse(Oid oldId, Oid oldRelId, Oid refRelId, char *cmd,
475 List **wqueue, LOCKMODE lockmode, bool rewrite)
476 {
477 List *raw_parsetree_list;
478 List *querytree_list;
479 ListCell *list_item;
480+ Relation rel;
481
482 /*
483 * We expect that we will get only ALTER TABLE and CREATE INDEX
484@@ -7894,16 +7923,21 @@ ATPostAlterTypeParse(Oid oldId, char *cmd,
485
486 if (IsA(stmt, IndexStmt))
487 querytree_list = lappend(querytree_list,
488- transformIndexStmt((IndexStmt *) stmt,
489+ transformIndexStmt(oldRelId,
490+ (IndexStmt *) stmt,
491 cmd));
492 else if (IsA(stmt, AlterTableStmt))
493 querytree_list = list_concat(querytree_list,
494- transformAlterTableStmt((AlterTableStmt *) stmt,
495+ transformAlterTableStmt(oldRelId,
496+ (AlterTableStmt *) stmt,
497 cmd));
498 else
499 querytree_list = lappend(querytree_list, stmt);
500 }
501
502+ /* Caller should already have acquired whatever lock we need. */
503+ rel = relation_open(oldRelId, NoLock);
504+
505 /*
506 * Attach each generated command to the proper place in the work queue.
507 * Note this could result in creation of entirely new work-queue entries.
508@@ -7915,7 +7949,6 @@ ATPostAlterTypeParse(Oid oldId, char *cmd,
509 foreach(list_item, querytree_list)
510 {
511 Node *stm = (Node *) lfirst(list_item);
512- Relation rel;
513 AlteredTableInfo *tab;
514
515 switch (nodeTag(stm))
516@@ -7928,14 +7961,12 @@ ATPostAlterTypeParse(Oid oldId, char *cmd,
517 if (!rewrite)
518 TryReuseIndex(oldId, stmt);
519
520- rel = relation_openrv(stmt->relation, lockmode);
521 tab = ATGetQueueEntry(wqueue, rel);
522 newcmd = makeNode(AlterTableCmd);
523 newcmd->subtype = AT_ReAddIndex;
524 newcmd->def = (Node *) stmt;
525 tab->subcmds[AT_PASS_OLD_INDEX] =
526 lappend(tab->subcmds[AT_PASS_OLD_INDEX], newcmd);
527- relation_close(rel, NoLock);
528 break;
529 }
530 case T_AlterTableStmt:
531@@ -7943,7 +7974,6 @@ ATPostAlterTypeParse(Oid oldId, char *cmd,
532 AlterTableStmt *stmt = (AlterTableStmt *) stm;
533 ListCell *lcmd;
534
535- rel = relation_openrv(stmt->relation, lockmode);
536 tab = ATGetQueueEntry(wqueue, rel);
537 foreach(lcmd, stmt->cmds)
538 {
539@@ -7964,6 +7994,7 @@ ATPostAlterTypeParse(Oid oldId, char *cmd,
540 case AT_AddConstraint:
541 Assert(IsA(cmd->def, Constraint));
542 con = (Constraint *) cmd->def;
543+ con->old_pktable_oid = refRelId;
544 /* rewriting neither side of a FK */
545 if (con->contype == CONSTR_FOREIGN &&
546 !rewrite && !tab->rewrite)
547@@ -7977,7 +8008,6 @@ ATPostAlterTypeParse(Oid oldId, char *cmd,
548 (int) cmd->subtype);
549 }
550 }
551- relation_close(rel, NoLock);
552 break;
553 }
554 default:
555@@ -7985,6 +8015,8 @@ ATPostAlterTypeParse(Oid oldId, char *cmd,
556 (int) nodeTag(stm));
557 }
558 }
559+
560+ relation_close(rel, NoLock);
561 }
562
563 /*
564@@ -7995,7 +8027,6 @@ static void
565 TryReuseIndex(Oid oldId, IndexStmt *stmt)
566 {
567 if (CheckIndexCompatible(oldId,
568- stmt->relation,
569 stmt->accessMethod,
570 stmt->indexParams,
571 stmt->excludeOpNames))
572@@ -10291,6 +10322,38 @@ RangeVarCallbackOwnsTable(const RangeVar *relation,
573 }
574
575 /*
576+ * Callback to RangeVarGetRelidExtended(), similar to
577+ * RangeVarCallbackOwnsTable() but without checks on the type of the relation.
578+ */
579+void
580+RangeVarCallbackOwnsRelation(const RangeVar *relation,
581+ Oid relId, Oid oldRelId, void *arg)
582+{
583+ HeapTuple tuple;
584+
585+ /* Nothing to do if the relation was not found. */
586+ if (!OidIsValid(relId))
587+ return;
588+
589+ tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relId));
590+ if (!HeapTupleIsValid(tuple)) /* should not happen */
591+ elog(ERROR, "cache lookup failed for relation %u", relId);
592+
593+ if (!pg_class_ownercheck(relId, GetUserId()))
594+ aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS,
595+ relation->relname);
596+
597+ if (!allowSystemTableMods &&
598+ IsSystemClass((Form_pg_class) GETSTRUCT(tuple)))
599+ ereport(ERROR,
600+ (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
601+ errmsg("permission denied: \"%s\" is a system catalog",
602+ relation->relname)));
603+
604+ ReleaseSysCache(tuple);
605+}
606+
607+/*
608 * Common RangeVarGetRelid callback for rename, set schema, and alter table
609 * processing.
610 */
611diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c
612index f546d94..9e6c954 100644
613--- a/src/backend/commands/trigger.c
614+++ b/src/backend/commands/trigger.c
615@@ -42,6 +42,7 @@
616 #include "pgstat.h"
617 #include "rewrite/rewriteManip.h"
618 #include "storage/bufmgr.h"
619+#include "storage/lmgr.h"
620 #include "tcop/utility.h"
621 #include "utils/acl.h"
622 #include "utils/builtins.h"
623@@ -94,6 +95,13 @@ static void AfterTriggerSaveEvent(EState *estate, ResultRelInfo *relinfo,
624 * queryString is the source text of the CREATE TRIGGER command.
625 * This must be supplied if a whenClause is specified, else it can be NULL.
626 *
627+ * relOid, if nonzero, is the relation on which the trigger should be
628+ * created. If zero, the name provided in the statement will be looked up.
629+ *
630+ * refRelOid, if nonzero, is the relation to which the constraint trigger
631+ * refers. If zero, the constraint relation name provided in the statement
632+ * will be looked up as needed.
633+ *
634 * constraintOid, if nonzero, says that this trigger is being created
635 * internally to implement that constraint. A suitable pg_depend entry will
636 * be made to link the trigger to that constraint. constraintOid is zero when
637@@ -116,7 +124,7 @@ static void AfterTriggerSaveEvent(EState *estate, ResultRelInfo *relinfo,
638 */
639 Oid
640 CreateTrigger(CreateTrigStmt *stmt, const char *queryString,
641- Oid constraintOid, Oid indexOid,
642+ Oid relOid, Oid refRelOid, Oid constraintOid, Oid indexOid,
643 bool isInternal)
644 {
645 int16 tgtype;
646@@ -145,7 +153,10 @@ CreateTrigger(CreateTrigStmt *stmt, const char *queryString,
647 ObjectAddress myself,
648 referenced;
649
650- rel = heap_openrv(stmt->relation, AccessExclusiveLock);
651+ if (OidIsValid(relOid))
652+ rel = heap_open(relOid, AccessExclusiveLock);
653+ else
654+ rel = heap_openrv(stmt->relation, AccessExclusiveLock);
655
656 /*
657 * Triggers must be on tables or views, and there are additional
658@@ -194,7 +205,7 @@ CreateTrigger(CreateTrigStmt *stmt, const char *queryString,
659 errmsg("permission denied: \"%s\" is a system catalog",
660 RelationGetRelationName(rel))));
661
662- if (stmt->isconstraint && stmt->constrrel != NULL)
663+ if (stmt->isconstraint)
664 {
665 /*
666 * We must take a lock on the target relation to protect against
667@@ -203,7 +214,14 @@ CreateTrigger(CreateTrigStmt *stmt, const char *queryString,
668 * might end up creating a pg_constraint entry referencing a
669 * nonexistent table.
670 */
671- constrrelid = RangeVarGetRelid(stmt->constrrel, AccessShareLock, false);
672+ if (OidIsValid(refRelOid))
673+ {
674+ LockRelationOid(refRelOid, AccessShareLock);
675+ constrrelid = refRelOid;
676+ }
677+ else if (stmt->constrrel != NULL)
678+ constrrelid = RangeVarGetRelid(stmt->constrrel, AccessShareLock,
679+ false);
680 }
681
682 /* permission checks */
683@@ -513,7 +531,7 @@ CreateTrigger(CreateTrigStmt *stmt, const char *queryString,
684 ereport(ERROR,
685 (errcode(ERRCODE_DUPLICATE_OBJECT),
686 errmsg("trigger \"%s\" for relation \"%s\" already exists",
687- trigname, stmt->relation->relname)));
688+ trigname, RelationGetRelationName(rel))));
689 }
690 systable_endscan(tgscan);
691 }
692diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
693index 9bac994..dbe0f6a 100644
694--- a/src/backend/nodes/copyfuncs.c
695+++ b/src/backend/nodes/copyfuncs.c
696@@ -2357,6 +2357,7 @@ _copyConstraint(const Constraint *from)
697 COPY_SCALAR_FIELD(fk_upd_action);
698 COPY_SCALAR_FIELD(fk_del_action);
699 COPY_NODE_FIELD(old_conpfeqop);
700+ COPY_SCALAR_FIELD(old_pktable_oid);
701 COPY_SCALAR_FIELD(skip_validation);
702 COPY_SCALAR_FIELD(initially_valid);
703
704diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c
705index d185654..f8770b0 100644
706--- a/src/backend/nodes/equalfuncs.c
707+++ b/src/backend/nodes/equalfuncs.c
708@@ -2143,6 +2143,7 @@ _equalConstraint(const Constraint *a, const Constraint *b)
709 COMPARE_SCALAR_FIELD(fk_upd_action);
710 COMPARE_SCALAR_FIELD(fk_del_action);
711 COMPARE_NODE_FIELD(old_conpfeqop);
712+ COMPARE_SCALAR_FIELD(old_pktable_oid);
713 COMPARE_SCALAR_FIELD(skip_validation);
714 COMPARE_SCALAR_FIELD(initially_valid);
715
716diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c
717index 1df71f6..888ffd2 100644
718--- a/src/backend/nodes/outfuncs.c
719+++ b/src/backend/nodes/outfuncs.c
720@@ -2653,6 +2653,7 @@ _outConstraint(StringInfo str, const Constraint *node)
721 WRITE_CHAR_FIELD(fk_upd_action);
722 WRITE_CHAR_FIELD(fk_del_action);
723 WRITE_NODE_FIELD(old_conpfeqop);
724+ WRITE_OID_FIELD(old_pktable_oid);
725 WRITE_BOOL_FIELD(skip_validation);
726 WRITE_BOOL_FIELD(initially_valid);
727 break;
728diff --git a/src/backend/parser/parse_utilcmd.c b/src/backend/parser/parse_utilcmd.c
729index e3f9c62..5df939a 100644
730--- a/src/backend/parser/parse_utilcmd.c
731+++ b/src/backend/parser/parse_utilcmd.c
732@@ -1867,14 +1867,18 @@ transformFKConstraints(CreateStmtContext *cxt,
733 * a predicate expression. There are several code paths that create indexes
734 * without bothering to call this, because they know they don't have any
735 * such expressions to deal with.
736+ *
737+ * To avoid race conditions, it's important that this function rely only on
738+ * the passed-in relid (and not on stmt->relation) to determine the target
739+ * relation.
740 */
741 IndexStmt *
742-transformIndexStmt(IndexStmt *stmt, const char *queryString)
743+transformIndexStmt(Oid relid, IndexStmt *stmt, const char *queryString)
744 {
745- Relation rel;
746 ParseState *pstate;
747 RangeTblEntry *rte;
748 ListCell *l;
749+ Relation rel;
750
751 /*
752 * We must not scribble on the passed-in IndexStmt, so copy it. (This is
753@@ -1882,26 +1886,17 @@ transformIndexStmt(IndexStmt *stmt, const char *queryString)
754 */
755 stmt = (IndexStmt *) copyObject(stmt);
756
757- /*
758- * Open the parent table with appropriate locking. We must do this
759- * because addRangeTableEntry() would acquire only AccessShareLock,
760- * leaving DefineIndex() needing to do a lock upgrade with consequent risk
761- * of deadlock. Make sure this stays in sync with the type of lock
762- * DefineIndex() wants. If we are being called by ALTER TABLE, we will
763- * already hold a higher lock.
764- */
765- rel = heap_openrv(stmt->relation,
766- (stmt->concurrent ? ShareUpdateExclusiveLock : ShareLock));
767-
768 /* Set up pstate */
769 pstate = make_parsestate(NULL);
770 pstate->p_sourcetext = queryString;
771
772 /*
773 * Put the parent table into the rtable so that the expressions can refer
774- * to its fields without qualification.
775+ * to its fields without qualification. Caller is responsible for locking
776+ * relation, but we still need to open it.
777 */
778- rte = addRangeTableEntry(pstate, stmt->relation, NULL, false, true);
779+ rel = relation_open(relid, NoLock);
780+ rte = addRangeTableEntryForRelation(pstate, rel, NULL, false, true);
781
782 /* no to join list, yes to namespaces */
783 addRTEtoQuery(pstate, rte, false, true, true);
784@@ -1955,7 +1950,7 @@ transformIndexStmt(IndexStmt *stmt, const char *queryString)
785
786 free_parsestate(pstate);
787
788- /* Close relation, but keep the lock */
789+ /* Close relation */
790 heap_close(rel, NoLock);
791
792 return stmt;
793@@ -2277,9 +2272,14 @@ transformRuleStmt(RuleStmt *stmt, const char *queryString,
794 * Returns a List of utility commands to be done in sequence. One of these
795 * will be the transformed AlterTableStmt, but there may be additional actions
796 * to be done before and after the actual AlterTable() call.
797+ *
798+ * To avoid race conditions, it's important that this function rely only on
799+ * the passed-in relid (and not on stmt->relation) to determine the target
800+ * relation.
801 */
802 List *
803-transformAlterTableStmt(AlterTableStmt *stmt, const char *queryString)
804+transformAlterTableStmt(Oid relid, AlterTableStmt *stmt,
805+ const char *queryString)
806 {
807 Relation rel;
808 ParseState *pstate;
809@@ -2291,7 +2291,6 @@ transformAlterTableStmt(AlterTableStmt *stmt, const char *queryString)
810 List *newcmds = NIL;
811 bool skipValidation = true;
812 AlterTableCmd *newcmd;
813- LOCKMODE lockmode;
814
815 /*
816 * We must not scribble on the passed-in AlterTableStmt, so copy it. (This
817@@ -2299,29 +2298,8 @@ transformAlterTableStmt(AlterTableStmt *stmt, const char *queryString)
818 */
819 stmt = (AlterTableStmt *) copyObject(stmt);
820
821- /*
822- * Determine the appropriate lock level for this list of subcommands.
823- */
824- lockmode = AlterTableGetLockLevel(stmt->cmds);
825-
826- /*
827- * Acquire appropriate lock on the target relation, which will be held
828- * until end of transaction. This ensures any decisions we make here
829- * based on the state of the relation will still be good at execution. We
830- * must get lock now because execution will later require it; taking a
831- * lower grade lock now and trying to upgrade later risks deadlock. Any
832- * new commands we add after this must not upgrade the lock level
833- * requested here.
834- */
835- rel = relation_openrv_extended(stmt->relation, lockmode, stmt->missing_ok);
836- if (rel == NULL)
837- {
838- /* this message is consistent with relation_openrv */
839- ereport(NOTICE,
840- (errmsg("relation \"%s\" does not exist, skipping",
841- stmt->relation->relname)));
842- return NIL;
843- }
844+ /* Caller is responsible for locking the relation */
845+ rel = relation_open(relid, NoLock);
846
847 /* Set up pstate and CreateStmtContext */
848 pstate = make_parsestate(NULL);
849@@ -2434,7 +2412,7 @@ transformAlterTableStmt(AlterTableStmt *stmt, const char *queryString)
850 IndexStmt *idxstmt = (IndexStmt *) lfirst(l);
851
852 Assert(IsA(idxstmt, IndexStmt));
853- idxstmt = transformIndexStmt(idxstmt, queryString);
854+ idxstmt = transformIndexStmt(relid, idxstmt, queryString);
855 newcmd = makeNode(AlterTableCmd);
856 newcmd->subtype = OidIsValid(idxstmt->indexOid) ? AT_AddIndexConstraint : AT_AddIndex;
857 newcmd->def = (Node *) idxstmt;
858@@ -2458,7 +2436,7 @@ transformAlterTableStmt(AlterTableStmt *stmt, const char *queryString)
859 newcmds = lappend(newcmds, newcmd);
860 }
861
862- /* Close rel but keep lock */
863+ /* Close rel */
864 relation_close(rel, NoLock);
865
866 /*
867diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c
868index 509bf4d..7903e03 100644
869--- a/src/backend/tcop/utility.c
870+++ b/src/backend/tcop/utility.c
871@@ -67,49 +67,6 @@ ProcessUtility_hook_type ProcessUtility_hook = NULL;
872
873
874 /*
875- * Verify user has ownership of specified relation, else ereport.
876- *
877- * If noCatalogs is true then we also deny access to system catalogs,
878- * except when allowSystemTableMods is true.
879- */
880-void
881-CheckRelationOwnership(RangeVar *rel, bool noCatalogs)
882-{
883- Oid relOid;
884- HeapTuple tuple;
885-
886- /*
887- * XXX: This is unsafe in the presence of concurrent DDL, since it is
888- * called before acquiring any lock on the target relation. However,
889- * locking the target relation (especially using something like
890- * AccessExclusiveLock) before verifying that the user has permissions is
891- * not appealing either.
892- */
893- relOid = RangeVarGetRelid(rel, NoLock, false);
894-
895- tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relOid));
896- if (!HeapTupleIsValid(tuple)) /* should not happen */
897- elog(ERROR, "cache lookup failed for relation %u", relOid);
898-
899- if (!pg_class_ownercheck(relOid, GetUserId()))
900- aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS,
901- rel->relname);
902-
903- if (noCatalogs)
904- {
905- if (!allowSystemTableMods &&
906- IsSystemClass((Form_pg_class) GETSTRUCT(tuple)))
907- ereport(ERROR,
908- (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
909- errmsg("permission denied: \"%s\" is a system catalog",
910- rel->relname)));
911- }
912-
913- ReleaseSysCache(tuple);
914-}
915-
916-
917-/*
918 * CommandIsReadOnly: is an executable query read-only?
919 *
920 * This is a much stricter test than we apply for XactReadOnly mode;
921@@ -723,7 +680,8 @@ standard_ProcessUtility(Node *parsetree,
922 if (OidIsValid(relid))
923 {
924 /* Run parse analysis ... */
925- stmts = transformAlterTableStmt(atstmt, queryString);
926+ stmts = transformAlterTableStmt(relid, atstmt,
927+ queryString);
928
929 /* ... and do it */
930 foreach(l, stmts)
931@@ -910,18 +868,36 @@ standard_ProcessUtility(Node *parsetree,
932 case T_IndexStmt: /* CREATE INDEX */
933 {
934 IndexStmt *stmt = (IndexStmt *) parsetree;
935+ Oid relid;
936+ LOCKMODE lockmode;
937
938 if (stmt->concurrent)
939 PreventTransactionChain(isTopLevel,
940 "CREATE INDEX CONCURRENTLY");
941
942- CheckRelationOwnership(stmt->relation, true);
943+ /*
944+ * Look up the relation OID just once, right here at the
945+ * beginning, so that we don't end up repeating the name
946+ * lookup later and latching onto a different relation
947+ * partway through. To avoid lock upgrade hazards, it's
948+ * important that we take the strongest lock that will
949+ * eventually be needed here, so the lockmode calculation
950+ * needs to match what DefineIndex() does.
951+ */
952+ lockmode = stmt->concurrent ? ShareUpdateExclusiveLock
953+ : ShareLock;
954+ relid =
955+ RangeVarGetRelidExtended(stmt->relation, lockmode,
956+ false, false,
957+ RangeVarCallbackOwnsRelation,
958+ NULL);
959
960 /* Run parse analysis ... */
961- stmt = transformIndexStmt(stmt, queryString);
962+ stmt = transformIndexStmt(relid, stmt, queryString);
963
964 /* ... and do it */
965- DefineIndex(stmt,
966+ DefineIndex(relid, /* OID of heap relation */
967+ stmt,
968 InvalidOid, /* no predefined OID */
969 false, /* is_alter_table */
970 true, /* check_rights */
971@@ -1057,7 +1033,8 @@ standard_ProcessUtility(Node *parsetree,
972
973 case T_CreateTrigStmt:
974 (void) CreateTrigger((CreateTrigStmt *) parsetree, queryString,
975- InvalidOid, InvalidOid, false);
976+ InvalidOid, InvalidOid, InvalidOid,
977+ InvalidOid, false);
978 break;
979
980 case T_CreatePLangStmt:
981diff --git a/src/include/catalog/pg_constraint.h b/src/include/catalog/pg_constraint.h
982index d9d40b2..d8f8da4 100644
983--- a/src/include/catalog/pg_constraint.h
984+++ b/src/include/catalog/pg_constraint.h
985@@ -246,6 +246,7 @@ extern char *ChooseConstraintName(const char *name1, const char *name2,
986
987 extern void AlterConstraintNamespaces(Oid ownerId, Oid oldNspId,
988 Oid newNspId, bool isType, ObjectAddresses *objsMoved);
989+extern void get_constraint_relation_oids(Oid constraint_oid, Oid *conrelid, Oid *confrelid);
990 extern Oid get_relation_constraint_oid(Oid relid, const char *conname, bool missing_ok);
991 extern Oid get_domain_constraint_oid(Oid typid, const char *conname, bool missing_ok);
992
993diff --git a/src/include/commands/defrem.h b/src/include/commands/defrem.h
994index 9b6d57a..a00fd37 100644
995--- a/src/include/commands/defrem.h
996+++ b/src/include/commands/defrem.h
997@@ -20,7 +20,8 @@
998 extern void RemoveObjects(DropStmt *stmt);
999
1000 /* commands/indexcmds.c */
1001-extern Oid DefineIndex(IndexStmt *stmt,
1002+extern Oid DefineIndex(Oid relationId,
1003+ IndexStmt *stmt,
1004 Oid indexRelationId,
1005 bool is_alter_table,
1006 bool check_rights,
1007@@ -35,7 +36,6 @@ extern char *makeObjectName(const char *name1, const char *name2,
1008 extern char *ChooseRelationName(const char *name1, const char *name2,
1009 const char *label, Oid namespaceid);
1010 extern bool CheckIndexCompatible(Oid oldId,
1011- RangeVar *heapRelation,
1012 char *accessMethodName,
1013 List *attributeList,
1014 List *exclusionOpNames);
1015diff --git a/src/include/commands/tablecmds.h b/src/include/commands/tablecmds.h
1016index 4f32062..d41f8a1 100644
1017--- a/src/include/commands/tablecmds.h
1018+++ b/src/include/commands/tablecmds.h
1019@@ -78,4 +78,6 @@ extern void AtEOSubXact_on_commit_actions(bool isCommit,
1020 extern void RangeVarCallbackOwnsTable(const RangeVar *relation,
1021 Oid relId, Oid oldRelId, void *arg);
1022
1023+extern void RangeVarCallbackOwnsRelation(const RangeVar *relation,
1024+ Oid relId, Oid oldRelId, void *noCatalogs);
1025 #endif /* TABLECMDS_H */
1026diff --git a/src/include/commands/trigger.h b/src/include/commands/trigger.h
1027index 9303341..0869c0b 100644
1028--- a/src/include/commands/trigger.h
1029+++ b/src/include/commands/trigger.h
1030@@ -109,7 +109,7 @@ extern PGDLLIMPORT int SessionReplicationRole;
1031 #define TRIGGER_DISABLED 'D'
1032
1033 extern Oid CreateTrigger(CreateTrigStmt *stmt, const char *queryString,
1034- Oid constraintOid, Oid indexOid,
1035+ Oid relOid, Oid refRelOid, Oid constraintOid, Oid indexOid,
1036 bool isInternal);
1037
1038 extern void RemoveTriggerById(Oid trigOid);
1039diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
1040index 327f7cf..31f5479 100644
1041--- a/src/include/nodes/parsenodes.h
1042+++ b/src/include/nodes/parsenodes.h
1043@@ -1566,6 +1566,8 @@ typedef struct Constraint
1044 /* Fields used for constraints that allow a NOT VALID specification */
1045 bool skip_validation; /* skip validation of existing rows? */
1046 bool initially_valid; /* mark the new constraint as valid? */
1047+
1048+ Oid old_pktable_oid; /* pg_constraint.confrelid of my former self */
1049 } Constraint;
1050
1051 /* ----------------------
1052diff --git a/src/include/parser/parse_utilcmd.h b/src/include/parser/parse_utilcmd.h
1053index 4ad793a..d8b340e 100644
1054--- a/src/include/parser/parse_utilcmd.h
1055+++ b/src/include/parser/parse_utilcmd.h
1056@@ -18,9 +18,10 @@
1057
1058
1059 extern List *transformCreateStmt(CreateStmt *stmt, const char *queryString);
1060-extern List *transformAlterTableStmt(AlterTableStmt *stmt,
1061+extern List *transformAlterTableStmt(Oid relid, AlterTableStmt *stmt,
1062 const char *queryString);
1063-extern IndexStmt *transformIndexStmt(IndexStmt *stmt, const char *queryString);
1064+extern IndexStmt *transformIndexStmt(Oid relid, IndexStmt *stmt,
1065+ const char *queryString);
1066 extern void transformRuleStmt(RuleStmt *stmt, const char *queryString,
1067 List **actions, Node **whereClause);
1068 extern List *transformCreateSchemaStmt(CreateSchemaStmt *stmt);
1069diff --git a/src/include/tcop/utility.h b/src/include/tcop/utility.h
1070index 54190b2..ae871ca 100644
1071--- a/src/include/tcop/utility.h
1072+++ b/src/include/tcop/utility.h
1073@@ -42,6 +42,4 @@ extern LogStmtLevel GetCommandLogLevel(Node *parsetree);
1074
1075 extern bool CommandIsReadOnly(Node *parsetree);
1076
1077-extern void CheckRelationOwnership(RangeVar *rel, bool noCatalogs);
1078-
1079 #endif /* UTILITY_H */
1080--
10811.7.5.4
1082