aboutsummaryrefslogtreecommitdiffstats
path: root/meta-oe/recipes-support/postgresql/files/0005-Avoid-repeated-name-lookups-during-table-and-index-D.patch
diff options
context:
space:
mode:
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.patch1082
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
-