Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * pg_collation.c
4 : * routines to support manipulation of the pg_collation relation
5 : *
6 : * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
7 : * Portions Copyright (c) 1994, Regents of the University of California
8 : *
9 : *
10 : * IDENTIFICATION
11 : * src/backend/catalog/pg_collation.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_collation.h"
24 : #include "catalog/pg_namespace.h"
25 : #include "mb/pg_wchar.h"
26 : #include "utils/builtins.h"
27 : #include "utils/rel.h"
28 : #include "utils/syscache.h"
29 :
30 :
31 : /*
32 : * CollationCreate
33 : *
34 : * Add a new tuple to pg_collation.
35 : *
36 : * if_not_exists: if true, don't fail on duplicate name, just print a notice
37 : * and return InvalidOid.
38 : * quiet: if true, don't fail on duplicate name, just silently return
39 : * InvalidOid (overrides if_not_exists).
40 : */
41 : Oid
42 67906 : CollationCreate(const char *collname, Oid collnamespace,
43 : Oid collowner,
44 : char collprovider,
45 : bool collisdeterministic,
46 : int32 collencoding,
47 : const char *collcollate, const char *collctype,
48 : const char *colllocale,
49 : const char *collicurules,
50 : const char *collversion,
51 : bool if_not_exists,
52 : bool quiet)
53 : {
54 : Relation rel;
55 : TupleDesc tupDesc;
56 : HeapTuple tup;
57 : Datum values[Natts_pg_collation];
58 : bool nulls[Natts_pg_collation];
59 : NameData name_name;
60 : Oid oid;
61 : ObjectAddress myself,
62 : referenced;
63 :
64 : Assert(collname);
65 : Assert(collnamespace);
66 : Assert(collowner);
67 : Assert((collprovider == COLLPROVIDER_LIBC &&
68 : collcollate && collctype && !colllocale) ||
69 : (collprovider != COLLPROVIDER_LIBC &&
70 : !collcollate && !collctype && colllocale));
71 :
72 : /*
73 : * Make sure there is no existing collation of same name & encoding.
74 : *
75 : * This would be caught by the unique index anyway; we're just giving a
76 : * friendlier error message. The unique index provides a backstop against
77 : * race conditions.
78 : */
79 67906 : oid = GetSysCacheOid3(COLLNAMEENCNSP,
80 : Anum_pg_collation_oid,
81 : PointerGetDatum(collname),
82 : Int32GetDatum(collencoding),
83 : ObjectIdGetDatum(collnamespace));
84 67906 : if (OidIsValid(oid))
85 : {
86 10 : if (quiet)
87 0 : return InvalidOid;
88 10 : else if (if_not_exists)
89 : {
90 : /*
91 : * If we are in an extension script, insist that the pre-existing
92 : * object be a member of the extension, to avoid security risks.
93 : */
94 4 : ObjectAddressSet(myself, CollationRelationId, oid);
95 4 : checkMembershipInCurrentExtension(&myself);
96 :
97 : /* OK to skip */
98 2 : ereport(NOTICE,
99 : (errcode(ERRCODE_DUPLICATE_OBJECT),
100 : collencoding == -1
101 : ? errmsg("collation \"%s\" already exists, skipping",
102 : collname)
103 : : errmsg("collation \"%s\" for encoding \"%s\" already exists, skipping",
104 : collname, pg_encoding_to_char(collencoding))));
105 2 : return InvalidOid;
106 : }
107 : else
108 6 : ereport(ERROR,
109 : (errcode(ERRCODE_DUPLICATE_OBJECT),
110 : collencoding == -1
111 : ? errmsg("collation \"%s\" already exists",
112 : collname)
113 : : errmsg("collation \"%s\" for encoding \"%s\" already exists",
114 : collname, pg_encoding_to_char(collencoding))));
115 : }
116 :
117 : /* open pg_collation; see below about the lock level */
118 67896 : rel = table_open(CollationRelationId, ShareRowExclusiveLock);
119 :
120 : /*
121 : * Also forbid a specific-encoding collation shadowing an any-encoding
122 : * collation, or an any-encoding collation being shadowed (see
123 : * get_collation_name()). This test is not backed up by the unique index,
124 : * so we take a ShareRowExclusiveLock earlier, to protect against
125 : * concurrent changes fooling this check.
126 : */
127 67896 : if (collencoding == -1)
128 67514 : oid = GetSysCacheOid3(COLLNAMEENCNSP,
129 : Anum_pg_collation_oid,
130 : PointerGetDatum(collname),
131 : Int32GetDatum(GetDatabaseEncoding()),
132 : ObjectIdGetDatum(collnamespace));
133 : else
134 382 : oid = GetSysCacheOid3(COLLNAMEENCNSP,
135 : Anum_pg_collation_oid,
136 : PointerGetDatum(collname),
137 : Int32GetDatum(-1),
138 : ObjectIdGetDatum(collnamespace));
139 67896 : if (OidIsValid(oid))
140 : {
141 86 : if (quiet)
142 : {
143 86 : table_close(rel, NoLock);
144 86 : return InvalidOid;
145 : }
146 0 : else if (if_not_exists)
147 : {
148 : /*
149 : * If we are in an extension script, insist that the pre-existing
150 : * object be a member of the extension, to avoid security risks.
151 : */
152 0 : ObjectAddressSet(myself, CollationRelationId, oid);
153 0 : checkMembershipInCurrentExtension(&myself);
154 :
155 : /* OK to skip */
156 0 : table_close(rel, NoLock);
157 0 : ereport(NOTICE,
158 : (errcode(ERRCODE_DUPLICATE_OBJECT),
159 : errmsg("collation \"%s\" already exists, skipping",
160 : collname)));
161 0 : return InvalidOid;
162 : }
163 : else
164 0 : ereport(ERROR,
165 : (errcode(ERRCODE_DUPLICATE_OBJECT),
166 : errmsg("collation \"%s\" already exists",
167 : collname)));
168 : }
169 :
170 67810 : tupDesc = RelationGetDescr(rel);
171 :
172 : /* form a tuple */
173 67810 : memset(nulls, 0, sizeof(nulls));
174 :
175 67810 : namestrcpy(&name_name, collname);
176 67810 : oid = GetNewOidWithIndex(rel, CollationOidIndexId,
177 : Anum_pg_collation_oid);
178 67810 : values[Anum_pg_collation_oid - 1] = ObjectIdGetDatum(oid);
179 67810 : values[Anum_pg_collation_collname - 1] = NameGetDatum(&name_name);
180 67810 : values[Anum_pg_collation_collnamespace - 1] = ObjectIdGetDatum(collnamespace);
181 67810 : values[Anum_pg_collation_collowner - 1] = ObjectIdGetDatum(collowner);
182 67810 : values[Anum_pg_collation_collprovider - 1] = CharGetDatum(collprovider);
183 67810 : values[Anum_pg_collation_collisdeterministic - 1] = BoolGetDatum(collisdeterministic);
184 67810 : values[Anum_pg_collation_collencoding - 1] = Int32GetDatum(collencoding);
185 67810 : if (collcollate)
186 306 : values[Anum_pg_collation_collcollate - 1] = CStringGetTextDatum(collcollate);
187 : else
188 67504 : nulls[Anum_pg_collation_collcollate - 1] = true;
189 67810 : if (collctype)
190 306 : values[Anum_pg_collation_collctype - 1] = CStringGetTextDatum(collctype);
191 : else
192 67504 : nulls[Anum_pg_collation_collctype - 1] = true;
193 67810 : if (colllocale)
194 67504 : values[Anum_pg_collation_colllocale - 1] = CStringGetTextDatum(colllocale);
195 : else
196 306 : nulls[Anum_pg_collation_colllocale - 1] = true;
197 67810 : if (collicurules)
198 12 : values[Anum_pg_collation_collicurules - 1] = CStringGetTextDatum(collicurules);
199 : else
200 67798 : nulls[Anum_pg_collation_collicurules - 1] = true;
201 67810 : if (collversion)
202 67676 : values[Anum_pg_collation_collversion - 1] = CStringGetTextDatum(collversion);
203 : else
204 134 : nulls[Anum_pg_collation_collversion - 1] = true;
205 :
206 67810 : tup = heap_form_tuple(tupDesc, values, nulls);
207 :
208 : /* insert a new tuple */
209 67810 : CatalogTupleInsert(rel, tup);
210 : Assert(OidIsValid(oid));
211 :
212 : /* set up dependencies for the new collation */
213 67810 : myself.classId = CollationRelationId;
214 67810 : myself.objectId = oid;
215 67810 : myself.objectSubId = 0;
216 :
217 : /* create dependency on namespace */
218 67810 : referenced.classId = NamespaceRelationId;
219 67810 : referenced.objectId = collnamespace;
220 67810 : referenced.objectSubId = 0;
221 67810 : recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
222 :
223 : /* create dependency on owner */
224 67810 : recordDependencyOnOwner(CollationRelationId, oid, collowner);
225 :
226 : /* dependency on extension */
227 67810 : recordDependencyOnCurrentExtension(&myself, false);
228 :
229 : /* Post creation hook for new collation */
230 67810 : InvokeObjectPostCreateHook(CollationRelationId, oid, 0);
231 :
232 67810 : heap_freetuple(tup);
233 67810 : table_close(rel, NoLock);
234 :
235 67810 : return oid;
236 : }
|