Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
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

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)