Skip to content

Commit 35508d1

Browse files
committed
Add ALTER object SET SCHEMA capability for a limited but useful set of
object kinds (tables, functions, types). Documentation is not here yet. Original code by Bernd Helmle, extensive rework by Bruce Momjian and Tom Lane.
1 parent a85e5d1 commit 35508d1

File tree

22 files changed

+1095
-41
lines changed

22 files changed

+1095
-41
lines changed

src/backend/catalog/namespace.c

Lines changed: 50 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
* Portions Copyright (c) 1994, Regents of the University of California
1414
*
1515
* IDENTIFICATION
16-
* $PostgreSQL: pgsql/src/backend/catalog/namespace.c,v 1.76 2005/06/28 05:08:52 tgl Exp $
16+
* $PostgreSQL: pgsql/src/backend/catalog/namespace.c,v 1.77 2005/08/01 04:03:54 tgl Exp $
1717
*
1818
*-------------------------------------------------------------------------
1919
*/
@@ -1235,12 +1235,43 @@ LookupExplicitNamespace(const char *nspname)
12351235
return namespaceId;
12361236
}
12371237

1238+
/*
1239+
* LookupCreationNamespace
1240+
* Look up the schema and verify we have CREATE rights on it.
1241+
*
1242+
* This is just like LookupExplicitNamespace except for the permission check.
1243+
*/
1244+
Oid
1245+
LookupCreationNamespace(const char *nspname)
1246+
{
1247+
Oid namespaceId;
1248+
AclResult aclresult;
1249+
1250+
namespaceId = GetSysCacheOid(NAMESPACENAME,
1251+
CStringGetDatum(nspname),
1252+
0, 0, 0);
1253+
if (!OidIsValid(namespaceId))
1254+
ereport(ERROR,
1255+
(errcode(ERRCODE_UNDEFINED_SCHEMA),
1256+
errmsg("schema \"%s\" does not exist", nspname)));
1257+
1258+
aclresult = pg_namespace_aclcheck(namespaceId, GetUserId(), ACL_CREATE);
1259+
if (aclresult != ACLCHECK_OK)
1260+
aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
1261+
nspname);
1262+
1263+
return namespaceId;
1264+
}
1265+
12381266
/*
12391267
* QualifiedNameGetCreationNamespace
12401268
* Given a possibly-qualified name for an object (in List-of-Values
12411269
* format), determine what namespace the object should be created in.
12421270
* Also extract and return the object name (last component of list).
12431271
*
1272+
* Note: this does not apply any permissions check. Callers must check
1273+
* for CREATE rights on the selected namespace when appropriate.
1274+
*
12441275
* This is *not* used for tables. Hence, the TEMP table namespace is
12451276
* never selected as the creation target.
12461277
*/
@@ -1277,8 +1308,6 @@ QualifiedNameGetCreationNamespace(List *names, char **objname_p)
12771308
errmsg("no schema has been selected to create in")));
12781309
}
12791310

1280-
/* Note: callers will check for CREATE rights when appropriate */
1281-
12821311
*objname_p = objname;
12831312
return namespaceId;
12841313
}
@@ -1379,19 +1408,16 @@ isTempNamespace(Oid namespaceId)
13791408
}
13801409

13811410
/*
1382-
* isOtherTempNamespace - is the given namespace some other backend's
1383-
* temporary-table namespace?
1411+
* isAnyTempNamespace - is the given namespace a temporary-table namespace
1412+
* (either my own, or another backend's)?
13841413
*/
13851414
bool
1386-
isOtherTempNamespace(Oid namespaceId)
1415+
isAnyTempNamespace(Oid namespaceId)
13871416
{
13881417
bool result;
13891418
char *nspname;
13901419

1391-
/* If it's my own temp namespace, say "false" */
1392-
if (isTempNamespace(namespaceId))
1393-
return false;
1394-
/* Else, if the namespace name starts with "pg_temp_", say "true" */
1420+
/* If the namespace name starts with "pg_temp_", say "true" */
13951421
nspname = get_namespace_name(namespaceId);
13961422
if (!nspname)
13971423
return false; /* no such namespace? */
@@ -1400,6 +1426,20 @@ isOtherTempNamespace(Oid namespaceId)
14001426
return result;
14011427
}
14021428

1429+
/*
1430+
* isOtherTempNamespace - is the given namespace some other backend's
1431+
* temporary-table namespace?
1432+
*/
1433+
bool
1434+
isOtherTempNamespace(Oid namespaceId)
1435+
{
1436+
/* If it's my own temp namespace, say "false" */
1437+
if (isTempNamespace(namespaceId))
1438+
return false;
1439+
/* Else, if the namespace name starts with "pg_temp_", say "true" */
1440+
return isAnyTempNamespace(namespaceId);
1441+
}
1442+
14031443
/*
14041444
* PushSpecialNamespace - push a "special" namespace onto the front of the
14051445
* search path.

src/backend/catalog/pg_constraint.c

Lines changed: 67 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/catalog/pg_constraint.c,v 1.25 2005/04/14 20:03:23 tgl Exp $
11+
* $PostgreSQL: pgsql/src/backend/catalog/pg_constraint.c,v 1.26 2005/08/01 04:03:54 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -599,3 +599,69 @@ GetConstraintNameForTrigger(Oid triggerId)
599599

600600
return result;
601601
}
602+
603+
/*
604+
* AlterConstraintNamespaces
605+
* Find any constraints belonging to the specified object,
606+
* and move them to the specified new namespace.
607+
*
608+
* isType indicates whether the owning object is a type or a relation.
609+
*/
610+
void
611+
AlterConstraintNamespaces(Oid ownerId, Oid oldNspId,
612+
Oid newNspId, bool isType)
613+
{
614+
Relation conRel;
615+
ScanKeyData key[1];
616+
SysScanDesc scan;
617+
HeapTuple tup;
618+
619+
conRel = heap_open(ConstraintRelationId, RowExclusiveLock);
620+
621+
if (isType)
622+
{
623+
ScanKeyInit(&key[0],
624+
Anum_pg_constraint_contypid,
625+
BTEqualStrategyNumber, F_OIDEQ,
626+
ObjectIdGetDatum(ownerId));
627+
628+
scan = systable_beginscan(conRel, ConstraintTypidIndexId, true,
629+
SnapshotNow, 1, key);
630+
}
631+
else
632+
{
633+
ScanKeyInit(&key[0],
634+
Anum_pg_constraint_conrelid,
635+
BTEqualStrategyNumber, F_OIDEQ,
636+
ObjectIdGetDatum(ownerId));
637+
638+
scan = systable_beginscan(conRel, ConstraintRelidIndexId, true,
639+
SnapshotNow, 1, key);
640+
}
641+
642+
while (HeapTupleIsValid((tup = systable_getnext(scan))))
643+
{
644+
Form_pg_constraint conform = (Form_pg_constraint) GETSTRUCT(tup);
645+
646+
if (conform->connamespace == oldNspId)
647+
{
648+
tup = heap_copytuple(tup);
649+
conform = (Form_pg_constraint) GETSTRUCT(tup);
650+
651+
conform->connamespace = newNspId;
652+
653+
simple_heap_update(conRel, &tup->t_self, tup);
654+
CatalogUpdateIndexes(conRel, tup);
655+
656+
/*
657+
* Note: currently, the constraint will not have its own
658+
* dependency on the namespace, so we don't need to do
659+
* changeDependencyFor().
660+
*/
661+
}
662+
}
663+
664+
systable_endscan(scan);
665+
666+
heap_close(conRel, RowExclusiveLock);
667+
}

src/backend/catalog/pg_depend.c

Lines changed: 100 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/catalog/pg_depend.c,v 1.13 2005/04/14 20:03:23 tgl Exp $
11+
* $PostgreSQL: pgsql/src/backend/catalog/pg_depend.c,v 1.14 2005/08/01 04:03:54 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -162,6 +162,105 @@ deleteDependencyRecordsFor(Oid classId, Oid objectId)
162162
return count;
163163
}
164164

165+
/*
166+
* Adjust dependency record(s) to point to a different object of the same type
167+
*
168+
* classId/objectId specify the referencing object.
169+
* refClassId/oldRefObjectId specify the old referenced object.
170+
* newRefObjectId is the new referenced object (must be of class refClassId).
171+
*
172+
* Note the lack of objsubid parameters. If there are subobject references
173+
* they will all be readjusted.
174+
*
175+
* Returns the number of records updated.
176+
*/
177+
long
178+
changeDependencyFor(Oid classId, Oid objectId,
179+
Oid refClassId, Oid oldRefObjectId,
180+
Oid newRefObjectId)
181+
{
182+
long count = 0;
183+
Relation depRel;
184+
ScanKeyData key[2];
185+
SysScanDesc scan;
186+
HeapTuple tup;
187+
ObjectAddress objAddr;
188+
bool newIsPinned;
189+
190+
depRel = heap_open(DependRelationId, RowExclusiveLock);
191+
192+
/*
193+
* If oldRefObjectId is pinned, there won't be any dependency entries
194+
* on it --- we can't cope in that case. (This isn't really worth
195+
* expending code to fix, in current usage; it just means you can't
196+
* rename stuff out of pg_catalog, which would likely be a bad move
197+
* anyway.)
198+
*/
199+
objAddr.classId = refClassId;
200+
objAddr.objectId = oldRefObjectId;
201+
objAddr.objectSubId = 0;
202+
203+
if (isObjectPinned(&objAddr, depRel))
204+
ereport(ERROR,
205+
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
206+
errmsg("cannot remove dependency on %s because it is a system object",
207+
getObjectDescription(&objAddr))));
208+
209+
/*
210+
* We can handle adding a dependency on something pinned, though,
211+
* since that just means deleting the dependency entry.
212+
*/
213+
objAddr.objectId = newRefObjectId;
214+
215+
newIsPinned = isObjectPinned(&objAddr, depRel);
216+
217+
/* Now search for dependency records */
218+
ScanKeyInit(&key[0],
219+
Anum_pg_depend_classid,
220+
BTEqualStrategyNumber, F_OIDEQ,
221+
ObjectIdGetDatum(classId));
222+
ScanKeyInit(&key[1],
223+
Anum_pg_depend_objid,
224+
BTEqualStrategyNumber, F_OIDEQ,
225+
ObjectIdGetDatum(objectId));
226+
227+
scan = systable_beginscan(depRel, DependDependerIndexId, true,
228+
SnapshotNow, 2, key);
229+
230+
while (HeapTupleIsValid((tup = systable_getnext(scan))))
231+
{
232+
Form_pg_depend depform = (Form_pg_depend) GETSTRUCT(tup);
233+
234+
if (depform->refclassid == refClassId &&
235+
depform->refobjid == oldRefObjectId)
236+
{
237+
if (newIsPinned)
238+
simple_heap_delete(depRel, &tup->t_self);
239+
else
240+
{
241+
/* make a modifiable copy */
242+
tup = heap_copytuple(tup);
243+
depform = (Form_pg_depend) GETSTRUCT(tup);
244+
245+
depform->refobjid = newRefObjectId;
246+
247+
simple_heap_update(depRel, &tup->t_self, tup);
248+
CatalogUpdateIndexes(depRel, tup);
249+
250+
heap_freetuple(tup);
251+
}
252+
253+
count++;
254+
}
255+
}
256+
257+
systable_endscan(scan);
258+
259+
heap_close(depRel, RowExclusiveLock);
260+
261+
return count;
262+
}
263+
165264
/*
166265
* isObjectPinned()
167266
*

src/backend/commands/alter.c

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/commands/alter.c,v 1.13 2005/06/28 05:08:53 tgl Exp $
11+
* $PostgreSQL: pgsql/src/backend/commands/alter.c,v 1.14 2005/08/01 04:03:55 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -142,6 +142,38 @@ ExecRenameStmt(RenameStmt *stmt)
142142
}
143143
}
144144

145+
/*
146+
* Executes an ALTER OBJECT / SET SCHEMA statement. Based on the object
147+
* type, the function appropriate to that type is executed.
148+
*/
149+
void
150+
ExecAlterObjectSchemaStmt(AlterObjectSchemaStmt *stmt)
151+
{
152+
switch (stmt->objectType)
153+
{
154+
case OBJECT_AGGREGATE:
155+
case OBJECT_FUNCTION:
156+
AlterFunctionNamespace(stmt->object, stmt->objarg,
157+
stmt->newschema);
158+
break;
159+
160+
case OBJECT_SEQUENCE:
161+
case OBJECT_TABLE:
162+
CheckRelationOwnership(stmt->relation, true);
163+
AlterTableNamespace(stmt->relation, stmt->newschema);
164+
break;
165+
166+
case OBJECT_TYPE:
167+
case OBJECT_DOMAIN:
168+
AlterTypeNamespace(stmt->object, stmt->newschema);
169+
break;
170+
171+
default:
172+
elog(ERROR, "unrecognized AlterObjectSchemaStmt type: %d",
173+
(int) stmt->objectType);
174+
}
175+
}
176+
145177
/*
146178
* Executes an ALTER OBJECT / OWNER TO statement. Based on the object
147179
* type, the function appropriate to that type is executed.

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy