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