postgresql/src/backend/catalog/pg_namespace.c

121 lines
3.4 KiB
C

/*-------------------------------------------------------------------------
*
* pg_namespace.c
* routines to support manipulation of the pg_namespace relation
*
* Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* src/backend/catalog/pg_namespace.c
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include "access/htup_details.h"
#include "access/table.h"
#include "catalog/catalog.h"
#include "catalog/dependency.h"
#include "catalog/indexing.h"
#include "catalog/objectaccess.h"
#include "catalog/pg_namespace.h"
#include "utils/builtins.h"
#include "utils/rel.h"
#include "utils/syscache.h"
/* ----------------
* NamespaceCreate
*
* Create a namespace (schema) with the given name and owner OID.
*
* If isTemp is true, this schema is a per-backend schema for holding
* temporary tables. Currently, it is used to prevent it from being
* linked as a member of any active extension. (If someone does CREATE
* TEMP TABLE in an extension script, we don't want the temp schema to
* become part of the extension). And to avoid checking for default ACL
* for temp namespace (as it is not necessary).
* ---------------
*/
Oid
NamespaceCreate(const char *nspName, Oid ownerId, bool isTemp)
{
Relation nspdesc;
HeapTuple tup;
Oid nspoid;
bool nulls[Natts_pg_namespace];
Datum values[Natts_pg_namespace];
NameData nname;
TupleDesc tupDesc;
ObjectAddress myself;
int i;
Acl *nspacl;
/* sanity checks */
if (!nspName)
elog(ERROR, "no namespace name supplied");
/* make sure there is no existing namespace of same name */
if (SearchSysCacheExists1(NAMESPACENAME, PointerGetDatum(nspName)))
ereport(ERROR,
(errcode(ERRCODE_DUPLICATE_SCHEMA),
errmsg("schema \"%s\" already exists", nspName)));
if (!isTemp)
nspacl = get_user_default_acl(OBJECT_SCHEMA, ownerId,
InvalidOid);
else
nspacl = NULL;
nspdesc = table_open(NamespaceRelationId, RowExclusiveLock);
tupDesc = nspdesc->rd_att;
/* initialize nulls and values */
for (i = 0; i < Natts_pg_namespace; i++)
{
nulls[i] = false;
values[i] = (Datum) NULL;
}
nspoid = GetNewOidWithIndex(nspdesc, NamespaceOidIndexId,
Anum_pg_namespace_oid);
values[Anum_pg_namespace_oid - 1] = ObjectIdGetDatum(nspoid);
namestrcpy(&nname, nspName);
values[Anum_pg_namespace_nspname - 1] = NameGetDatum(&nname);
values[Anum_pg_namespace_nspowner - 1] = ObjectIdGetDatum(ownerId);
if (nspacl != NULL)
values[Anum_pg_namespace_nspacl - 1] = PointerGetDatum(nspacl);
else
nulls[Anum_pg_namespace_nspacl - 1] = true;
tup = heap_form_tuple(tupDesc, values, nulls);
CatalogTupleInsert(nspdesc, tup);
Assert(OidIsValid(nspoid));
table_close(nspdesc, RowExclusiveLock);
/* Record dependencies */
myself.classId = NamespaceRelationId;
myself.objectId = nspoid;
myself.objectSubId = 0;
/* dependency on owner */
recordDependencyOnOwner(NamespaceRelationId, nspoid, ownerId);
/* dependencies on roles mentioned in default ACL */
recordDependencyOnNewAcl(NamespaceRelationId, nspoid, 0, ownerId, nspacl);
/* dependency on extension ... but not for magic temp schemas */
if (!isTemp)
recordDependencyOnCurrentExtension(&myself, false);
/* Post creation hook for new schema */
InvokeObjectPostCreateHook(NamespaceRelationId, nspoid, 0);
return nspoid;
}