1 | /*------------------------------------------------------------------------- |
2 | * |
3 | * pg_namespace.c |
4 | * routines to support manipulation of the pg_namespace relation |
5 | * |
6 | * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group |
7 | * Portions Copyright (c) 1994, Regents of the University of California |
8 | * |
9 | * |
10 | * IDENTIFICATION |
11 | * src/backend/catalog/pg_namespace.c |
12 | * |
13 | *------------------------------------------------------------------------- |
14 | */ |
15 | #include "postgres.h" |
16 | |
17 | #include "access/htup_details.h" |
18 | #include "access/table.h" |
19 | #include "catalog/catalog.h" |
20 | #include "catalog/dependency.h" |
21 | #include "catalog/indexing.h" |
22 | #include "catalog/objectaccess.h" |
23 | #include "catalog/pg_namespace.h" |
24 | #include "utils/builtins.h" |
25 | #include "utils/rel.h" |
26 | #include "utils/syscache.h" |
27 | |
28 | |
29 | /* ---------------- |
30 | * NamespaceCreate |
31 | * |
32 | * Create a namespace (schema) with the given name and owner OID. |
33 | * |
34 | * If isTemp is true, this schema is a per-backend schema for holding |
35 | * temporary tables. Currently, it is used to prevent it from being |
36 | * linked as a member of any active extension. (If someone does CREATE |
37 | * TEMP TABLE in an extension script, we don't want the temp schema to |
38 | * become part of the extension). And to avoid checking for default ACL |
39 | * for temp namespace (as it is not necessary). |
40 | * --------------- |
41 | */ |
42 | Oid |
43 | NamespaceCreate(const char *nspName, Oid ownerId, bool isTemp) |
44 | { |
45 | Relation nspdesc; |
46 | HeapTuple tup; |
47 | Oid nspoid; |
48 | bool nulls[Natts_pg_namespace]; |
49 | Datum values[Natts_pg_namespace]; |
50 | NameData nname; |
51 | TupleDesc tupDesc; |
52 | ObjectAddress myself; |
53 | int i; |
54 | Acl *nspacl; |
55 | |
56 | /* sanity checks */ |
57 | if (!nspName) |
58 | elog(ERROR, "no namespace name supplied" ); |
59 | |
60 | /* make sure there is no existing namespace of same name */ |
61 | if (SearchSysCacheExists1(NAMESPACENAME, PointerGetDatum(nspName))) |
62 | ereport(ERROR, |
63 | (errcode(ERRCODE_DUPLICATE_SCHEMA), |
64 | errmsg("schema \"%s\" already exists" , nspName))); |
65 | |
66 | if (!isTemp) |
67 | nspacl = get_user_default_acl(OBJECT_SCHEMA, ownerId, |
68 | InvalidOid); |
69 | else |
70 | nspacl = NULL; |
71 | |
72 | nspdesc = table_open(NamespaceRelationId, RowExclusiveLock); |
73 | tupDesc = nspdesc->rd_att; |
74 | |
75 | /* initialize nulls and values */ |
76 | for (i = 0; i < Natts_pg_namespace; i++) |
77 | { |
78 | nulls[i] = false; |
79 | values[i] = (Datum) NULL; |
80 | } |
81 | |
82 | nspoid = GetNewOidWithIndex(nspdesc, NamespaceOidIndexId, |
83 | Anum_pg_namespace_oid); |
84 | values[Anum_pg_namespace_oid - 1] = ObjectIdGetDatum(nspoid); |
85 | namestrcpy(&nname, nspName); |
86 | values[Anum_pg_namespace_nspname - 1] = NameGetDatum(&nname); |
87 | values[Anum_pg_namespace_nspowner - 1] = ObjectIdGetDatum(ownerId); |
88 | if (nspacl != NULL) |
89 | values[Anum_pg_namespace_nspacl - 1] = PointerGetDatum(nspacl); |
90 | else |
91 | nulls[Anum_pg_namespace_nspacl - 1] = true; |
92 | |
93 | |
94 | tup = heap_form_tuple(tupDesc, values, nulls); |
95 | |
96 | CatalogTupleInsert(nspdesc, tup); |
97 | Assert(OidIsValid(nspoid)); |
98 | |
99 | table_close(nspdesc, RowExclusiveLock); |
100 | |
101 | /* Record dependencies */ |
102 | myself.classId = NamespaceRelationId; |
103 | myself.objectId = nspoid; |
104 | myself.objectSubId = 0; |
105 | |
106 | /* dependency on owner */ |
107 | recordDependencyOnOwner(NamespaceRelationId, nspoid, ownerId); |
108 | |
109 | /* dependences on roles mentioned in default ACL */ |
110 | recordDependencyOnNewAcl(NamespaceRelationId, nspoid, 0, ownerId, nspacl); |
111 | |
112 | /* dependency on extension ... but not for magic temp schemas */ |
113 | if (!isTemp) |
114 | recordDependencyOnCurrentExtension(&myself, false); |
115 | |
116 | /* Post creation hook for new schema */ |
117 | InvokeObjectPostCreateHook(NamespaceRelationId, nspoid, 0); |
118 | |
119 | return nspoid; |
120 | } |
121 | |