00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #include "postgres.h"
00016
00017 #include "access/htup_details.h"
00018 #include "access/heapam.h"
00019 #include "access/xact.h"
00020 #include "catalog/catalog.h"
00021 #include "catalog/dependency.h"
00022 #include "catalog/indexing.h"
00023 #include "catalog/namespace.h"
00024 #include "catalog/objectaccess.h"
00025 #include "catalog/pg_namespace.h"
00026 #include "commands/dbcommands.h"
00027 #include "commands/schemacmds.h"
00028 #include "miscadmin.h"
00029 #include "parser/parse_utilcmd.h"
00030 #include "tcop/utility.h"
00031 #include "utils/acl.h"
00032 #include "utils/builtins.h"
00033 #include "utils/rel.h"
00034 #include "utils/syscache.h"
00035
00036
00037 static void AlterSchemaOwner_internal(HeapTuple tup, Relation rel, Oid newOwnerId);
00038
00039
00040
00041
00042 Oid
00043 CreateSchemaCommand(CreateSchemaStmt *stmt, const char *queryString)
00044 {
00045 const char *schemaName = stmt->schemaname;
00046 const char *authId = stmt->authid;
00047 Oid namespaceId;
00048 OverrideSearchPath *overridePath;
00049 List *parsetree_list;
00050 ListCell *parsetree_item;
00051 Oid owner_uid;
00052 Oid saved_uid;
00053 int save_sec_context;
00054 AclResult aclresult;
00055
00056 GetUserIdAndSecContext(&saved_uid, &save_sec_context);
00057
00058
00059
00060
00061 if (authId)
00062 owner_uid = get_role_oid(authId, false);
00063 else
00064 owner_uid = saved_uid;
00065
00066
00067
00068
00069
00070
00071
00072
00073 aclresult = pg_database_aclcheck(MyDatabaseId, saved_uid, ACL_CREATE);
00074 if (aclresult != ACLCHECK_OK)
00075 aclcheck_error(aclresult, ACL_KIND_DATABASE,
00076 get_database_name(MyDatabaseId));
00077
00078 check_is_member_of_role(saved_uid, owner_uid);
00079
00080
00081 if (!allowSystemTableMods && IsReservedName(schemaName))
00082 ereport(ERROR,
00083 (errcode(ERRCODE_RESERVED_NAME),
00084 errmsg("unacceptable schema name \"%s\"", schemaName),
00085 errdetail("The prefix \"pg_\" is reserved for system schemas.")));
00086
00087
00088
00089
00090
00091
00092
00093
00094 if (stmt->if_not_exists &&
00095 SearchSysCacheExists1(NAMESPACENAME, PointerGetDatum(schemaName)))
00096 {
00097 ereport(NOTICE,
00098 (errcode(ERRCODE_DUPLICATE_SCHEMA),
00099 errmsg("schema \"%s\" already exists, skipping",
00100 schemaName)));
00101 return InvalidOid;
00102 }
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112 if (saved_uid != owner_uid)
00113 SetUserIdAndSecContext(owner_uid,
00114 save_sec_context | SECURITY_LOCAL_USERID_CHANGE);
00115
00116
00117 namespaceId = NamespaceCreate(schemaName, owner_uid, false);
00118
00119
00120 CommandCounterIncrement();
00121
00122
00123
00124
00125
00126
00127 overridePath = GetOverrideSearchPath(CurrentMemoryContext);
00128 overridePath->schemas = lcons_oid(namespaceId, overridePath->schemas);
00129
00130 PushOverrideSearchPath(overridePath);
00131
00132
00133
00134
00135
00136
00137
00138
00139 parsetree_list = transformCreateSchemaStmt(stmt);
00140
00141
00142
00143
00144
00145
00146
00147 foreach(parsetree_item, parsetree_list)
00148 {
00149 Node *stmt = (Node *) lfirst(parsetree_item);
00150
00151
00152 ProcessUtility(stmt,
00153 queryString,
00154 PROCESS_UTILITY_SUBCOMMAND,
00155 NULL,
00156 None_Receiver,
00157 NULL);
00158
00159 CommandCounterIncrement();
00160 }
00161
00162
00163 PopOverrideSearchPath();
00164
00165
00166 SetUserIdAndSecContext(saved_uid, save_sec_context);
00167
00168 return namespaceId;
00169 }
00170
00171
00172
00173
00174 void
00175 RemoveSchemaById(Oid schemaOid)
00176 {
00177 Relation relation;
00178 HeapTuple tup;
00179
00180 relation = heap_open(NamespaceRelationId, RowExclusiveLock);
00181
00182 tup = SearchSysCache1(NAMESPACEOID,
00183 ObjectIdGetDatum(schemaOid));
00184 if (!HeapTupleIsValid(tup))
00185 elog(ERROR, "cache lookup failed for namespace %u", schemaOid);
00186
00187 simple_heap_delete(relation, &tup->t_self);
00188
00189 ReleaseSysCache(tup);
00190
00191 heap_close(relation, RowExclusiveLock);
00192 }
00193
00194
00195
00196
00197
00198 Oid
00199 RenameSchema(const char *oldname, const char *newname)
00200 {
00201 Oid nspOid;
00202 HeapTuple tup;
00203 Relation rel;
00204 AclResult aclresult;
00205
00206 rel = heap_open(NamespaceRelationId, RowExclusiveLock);
00207
00208 tup = SearchSysCacheCopy1(NAMESPACENAME, CStringGetDatum(oldname));
00209 if (!HeapTupleIsValid(tup))
00210 ereport(ERROR,
00211 (errcode(ERRCODE_UNDEFINED_SCHEMA),
00212 errmsg("schema \"%s\" does not exist", oldname)));
00213
00214 nspOid = HeapTupleGetOid(tup);
00215
00216
00217 if (OidIsValid(get_namespace_oid(newname, true)))
00218 ereport(ERROR,
00219 (errcode(ERRCODE_DUPLICATE_SCHEMA),
00220 errmsg("schema \"%s\" already exists", newname)));
00221
00222
00223 if (!pg_namespace_ownercheck(HeapTupleGetOid(tup), GetUserId()))
00224 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_NAMESPACE,
00225 oldname);
00226
00227
00228 aclresult = pg_database_aclcheck(MyDatabaseId, GetUserId(), ACL_CREATE);
00229 if (aclresult != ACLCHECK_OK)
00230 aclcheck_error(aclresult, ACL_KIND_DATABASE,
00231 get_database_name(MyDatabaseId));
00232
00233 if (!allowSystemTableMods && IsReservedName(newname))
00234 ereport(ERROR,
00235 (errcode(ERRCODE_RESERVED_NAME),
00236 errmsg("unacceptable schema name \"%s\"", newname),
00237 errdetail("The prefix \"pg_\" is reserved for system schemas.")));
00238
00239
00240 namestrcpy(&(((Form_pg_namespace) GETSTRUCT(tup))->nspname), newname);
00241 simple_heap_update(rel, &tup->t_self, tup);
00242 CatalogUpdateIndexes(rel, tup);
00243
00244 InvokeObjectPostAlterHook(NamespaceRelationId, HeapTupleGetOid(tup), 0);
00245
00246 heap_close(rel, NoLock);
00247 heap_freetuple(tup);
00248
00249 return nspOid;
00250 }
00251
00252 void
00253 AlterSchemaOwner_oid(Oid oid, Oid newOwnerId)
00254 {
00255 HeapTuple tup;
00256 Relation rel;
00257
00258 rel = heap_open(NamespaceRelationId, RowExclusiveLock);
00259
00260 tup = SearchSysCache1(NAMESPACEOID, ObjectIdGetDatum(oid));
00261 if (!HeapTupleIsValid(tup))
00262 elog(ERROR, "cache lookup failed for schema %u", oid);
00263
00264 AlterSchemaOwner_internal(tup, rel, newOwnerId);
00265
00266 ReleaseSysCache(tup);
00267
00268 heap_close(rel, RowExclusiveLock);
00269 }
00270
00271
00272
00273
00274
00275 Oid
00276 AlterSchemaOwner(const char *name, Oid newOwnerId)
00277 {
00278 Oid nspOid;
00279 HeapTuple tup;
00280 Relation rel;
00281
00282 rel = heap_open(NamespaceRelationId, RowExclusiveLock);
00283
00284 tup = SearchSysCache1(NAMESPACENAME, CStringGetDatum(name));
00285 if (!HeapTupleIsValid(tup))
00286 ereport(ERROR,
00287 (errcode(ERRCODE_UNDEFINED_SCHEMA),
00288 errmsg("schema \"%s\" does not exist", name)));
00289
00290 nspOid = HeapTupleGetOid(tup);
00291
00292 AlterSchemaOwner_internal(tup, rel, newOwnerId);
00293
00294 ReleaseSysCache(tup);
00295
00296 heap_close(rel, RowExclusiveLock);
00297
00298 return nspOid;
00299 }
00300
00301 static void
00302 AlterSchemaOwner_internal(HeapTuple tup, Relation rel, Oid newOwnerId)
00303 {
00304 Form_pg_namespace nspForm;
00305
00306 Assert(tup->t_tableOid == NamespaceRelationId);
00307 Assert(RelationGetRelid(rel) == NamespaceRelationId);
00308
00309 nspForm = (Form_pg_namespace) GETSTRUCT(tup);
00310
00311
00312
00313
00314
00315 if (nspForm->nspowner != newOwnerId)
00316 {
00317 Datum repl_val[Natts_pg_namespace];
00318 bool repl_null[Natts_pg_namespace];
00319 bool repl_repl[Natts_pg_namespace];
00320 Acl *newAcl;
00321 Datum aclDatum;
00322 bool isNull;
00323 HeapTuple newtuple;
00324 AclResult aclresult;
00325
00326
00327 if (!pg_namespace_ownercheck(HeapTupleGetOid(tup), GetUserId()))
00328 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_NAMESPACE,
00329 NameStr(nspForm->nspname));
00330
00331
00332 check_is_member_of_role(GetUserId(), newOwnerId);
00333
00334
00335
00336
00337
00338
00339
00340
00341
00342
00343 aclresult = pg_database_aclcheck(MyDatabaseId, GetUserId(),
00344 ACL_CREATE);
00345 if (aclresult != ACLCHECK_OK)
00346 aclcheck_error(aclresult, ACL_KIND_DATABASE,
00347 get_database_name(MyDatabaseId));
00348
00349 memset(repl_null, false, sizeof(repl_null));
00350 memset(repl_repl, false, sizeof(repl_repl));
00351
00352 repl_repl[Anum_pg_namespace_nspowner - 1] = true;
00353 repl_val[Anum_pg_namespace_nspowner - 1] = ObjectIdGetDatum(newOwnerId);
00354
00355
00356
00357
00358
00359 aclDatum = SysCacheGetAttr(NAMESPACENAME, tup,
00360 Anum_pg_namespace_nspacl,
00361 &isNull);
00362 if (!isNull)
00363 {
00364 newAcl = aclnewowner(DatumGetAclP(aclDatum),
00365 nspForm->nspowner, newOwnerId);
00366 repl_repl[Anum_pg_namespace_nspacl - 1] = true;
00367 repl_val[Anum_pg_namespace_nspacl - 1] = PointerGetDatum(newAcl);
00368 }
00369
00370 newtuple = heap_modify_tuple(tup, RelationGetDescr(rel), repl_val, repl_null, repl_repl);
00371
00372 simple_heap_update(rel, &newtuple->t_self, newtuple);
00373 CatalogUpdateIndexes(rel, newtuple);
00374
00375 heap_freetuple(newtuple);
00376
00377
00378 changeDependencyOnOwner(NamespaceRelationId, HeapTupleGetOid(tup),
00379 newOwnerId);
00380 }
00381
00382 InvokeObjectPostAlterHook(NamespaceRelationId,
00383 HeapTupleGetOid(tup), 0);
00384 }