Age Owner Branch data 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-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
4810 peter_e@gmx.net 42 :CBC 53980 : 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 : :
534 peter@eisentraut.org 64 [ - + ]: 53980 : Assert(collname);
65 [ - + ]: 53980 : Assert(collnamespace);
66 [ - + ]: 53980 : Assert(collowner);
32 jdavis@postgresql.or 67 [ + + + - :GNC 53980 : 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 : : */
615 tgl@sss.pgh.pa.us 79 :CBC 53980 : oid = GetSysCacheOid3(COLLNAMEENCNSP,
80 : : Anum_pg_collation_oid,
81 : : PointerGetDatum(collname),
82 : : Int32GetDatum(collencoding),
83 : : ObjectIdGetDatum(collnamespace));
84 [ + + ]: 53980 : if (OidIsValid(oid))
85 : : {
2487 86 [ - + ]: 5 : if (quiet)
2487 tgl@sss.pgh.pa.us 87 :UBC 0 : return InvalidOid;
2487 tgl@sss.pgh.pa.us 88 [ + + ]:CBC 5 : 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 : : */
615 94 : 2 : ObjectAddressSet(myself, CollationRelationId, oid);
95 : 2 : checkMembershipInCurrentExtension(&myself);
96 : :
97 : : /* OK to skip */
2643 peter_e@gmx.net 98 [ - + - - ]: 1 : 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 : 1 : return InvalidOid;
106 : : }
107 : : else
108 [ + - + - ]: 3 : 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 */
1910 andres@anarazel.de 118 : 53975 : 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 : : */
615 tgl@sss.pgh.pa.us 127 [ + + ]: 53975 : if (collencoding == -1)
128 : 29906 : oid = GetSysCacheOid3(COLLNAMEENCNSP,
129 : : Anum_pg_collation_oid,
130 : : PointerGetDatum(collname),
131 : : Int32GetDatum(GetDatabaseEncoding()),
132 : : ObjectIdGetDatum(collnamespace));
133 : : else
134 : 24069 : oid = GetSysCacheOid3(COLLNAMEENCNSP,
135 : : Anum_pg_collation_oid,
136 : : PointerGetDatum(collname),
137 : : Int32GetDatum(-1),
138 : : ObjectIdGetDatum(collnamespace));
139 [ + + ]: 53975 : if (OidIsValid(oid))
140 : : {
2487 141 [ + - ]: 37 : if (quiet)
142 : : {
1910 andres@anarazel.de 143 : 37 : table_close(rel, NoLock);
2487 tgl@sss.pgh.pa.us 144 : 37 : return InvalidOid;
145 : : }
2487 tgl@sss.pgh.pa.us 146 [ # # ]:UBC 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 : : */
615 152 : 0 : ObjectAddressSet(myself, CollationRelationId, oid);
153 : 0 : checkMembershipInCurrentExtension(&myself);
154 : :
155 : : /* OK to skip */
1910 andres@anarazel.de 156 : 0 : table_close(rel, NoLock);
2643 peter_e@gmx.net 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 : :
4783 tgl@sss.pgh.pa.us 170 :CBC 53938 : tupDesc = RelationGetDescr(rel);
171 : :
172 : : /* form a tuple */
173 : 53938 : memset(nulls, 0, sizeof(nulls));
174 : :
4810 peter_e@gmx.net 175 : 53938 : namestrcpy(&name_name, collname);
1972 andres@anarazel.de 176 : 53938 : oid = GetNewOidWithIndex(rel, CollationOidIndexId,
177 : : Anum_pg_collation_oid);
178 : 53938 : values[Anum_pg_collation_oid - 1] = ObjectIdGetDatum(oid);
4810 peter_e@gmx.net 179 : 53938 : values[Anum_pg_collation_collname - 1] = NameGetDatum(&name_name);
180 : 53938 : values[Anum_pg_collation_collnamespace - 1] = ObjectIdGetDatum(collnamespace);
181 : 53938 : values[Anum_pg_collation_collowner - 1] = ObjectIdGetDatum(collowner);
2579 182 : 53938 : values[Anum_pg_collation_collprovider - 1] = CharGetDatum(collprovider);
1850 peter@eisentraut.org 183 : 53938 : values[Anum_pg_collation_collisdeterministic - 1] = BoolGetDatum(collisdeterministic);
4810 peter_e@gmx.net 184 : 53938 : values[Anum_pg_collation_collencoding - 1] = Int32GetDatum(collencoding);
759 peter@eisentraut.org 185 [ + + ]: 53938 : if (collcollate)
186 : 24036 : values[Anum_pg_collation_collcollate - 1] = CStringGetTextDatum(collcollate);
187 : : else
188 : 29902 : nulls[Anum_pg_collation_collcollate - 1] = true;
189 [ + + ]: 53938 : if (collctype)
190 : 24036 : values[Anum_pg_collation_collctype - 1] = CStringGetTextDatum(collctype);
191 : : else
192 : 29902 : nulls[Anum_pg_collation_collctype - 1] = true;
36 jdavis@postgresql.or 193 [ + + ]:GNC 53938 : if (colllocale)
194 : 29902 : values[Anum_pg_collation_colllocale - 1] = CStringGetTextDatum(colllocale);
195 : : else
196 : 24036 : nulls[Anum_pg_collation_colllocale - 1] = true;
403 peter@eisentraut.org 197 [ + + ]:CBC 53938 : if (collicurules)
198 : 6 : values[Anum_pg_collation_collicurules - 1] = CStringGetTextDatum(collicurules);
199 : : else
200 : 53932 : nulls[Anum_pg_collation_collicurules - 1] = true;
1073 tmunro@postgresql.or 201 [ + + ]: 53938 : if (collversion)
202 : 53878 : values[Anum_pg_collation_collversion - 1] = CStringGetTextDatum(collversion);
203 : : else
204 : 60 : nulls[Anum_pg_collation_collversion - 1] = true;
205 : :
4810 peter_e@gmx.net 206 : 53938 : tup = heap_form_tuple(tupDesc, values, nulls);
207 : :
208 : : /* insert a new tuple */
1972 andres@anarazel.de 209 : 53938 : CatalogTupleInsert(rel, tup);
4810 peter_e@gmx.net 210 [ - + ]: 53938 : Assert(OidIsValid(oid));
211 : :
212 : : /* set up dependencies for the new collation */
213 : 53938 : myself.classId = CollationRelationId;
4783 tgl@sss.pgh.pa.us 214 : 53938 : myself.objectId = oid;
4810 peter_e@gmx.net 215 : 53938 : myself.objectSubId = 0;
216 : :
217 : : /* create dependency on namespace */
218 : 53938 : referenced.classId = NamespaceRelationId;
219 : 53938 : referenced.objectId = collnamespace;
220 : 53938 : referenced.objectSubId = 0;
221 : 53938 : recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
222 : :
223 : : /* create dependency on owner */
1972 andres@anarazel.de 224 : 53938 : recordDependencyOnOwner(CollationRelationId, oid, collowner);
225 : :
226 : : /* dependency on extension */
4649 tgl@sss.pgh.pa.us 227 : 53938 : recordDependencyOnCurrentExtension(&myself, false);
228 : :
229 : : /* Post creation hook for new collation */
4057 rhaas@postgresql.org 230 [ - + ]: 53938 : InvokeObjectPostCreateHook(CollationRelationId, oid, 0);
231 : :
4810 peter_e@gmx.net 232 : 53938 : heap_freetuple(tup);
1910 andres@anarazel.de 233 : 53938 : table_close(rel, NoLock);
234 : :
4810 peter_e@gmx.net 235 : 53938 : return oid;
236 : : }
|