1 /*-------------------------------------------------------------------------
4 * routines to support manipulation of the pg_collation relation
6 * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
11 * src/backend/catalog/pg_collation.c
13 *-------------------------------------------------------------------------
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"
34 * Add a new tuple to pg_collation.
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).
42 CollationCreate(const char *collname
, Oid collnamespace
,
45 bool collisdeterministic
,
47 const char *collcollate
, const char *collctype
,
48 const char *colllocale
,
49 const char *collicurules
,
50 const char *collversion
,
57 Datum values
[Natts_pg_collation
];
58 bool nulls
[Natts_pg_collation
];
65 Assert(collnamespace
);
67 Assert((collprovider
== COLLPROVIDER_LIBC
&&
68 collcollate
&& collctype
&& !colllocale
) ||
69 (collprovider
!= COLLPROVIDER_LIBC
&&
70 !collcollate
&& !collctype
&& colllocale
));
73 * Make sure there is no existing collation of same name & encoding.
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
79 oid
= GetSysCacheOid3(COLLNAMEENCNSP
,
80 Anum_pg_collation_oid
,
81 PointerGetDatum(collname
),
82 Int32GetDatum(collencoding
),
83 ObjectIdGetDatum(collnamespace
));
88 else if (if_not_exists
)
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.
94 ObjectAddressSet(myself
, CollationRelationId
, oid
);
95 checkMembershipInCurrentExtension(&myself
);
99 (errcode(ERRCODE_DUPLICATE_OBJECT
),
101 ? errmsg("collation \"%s\" already exists, skipping",
103 : errmsg("collation \"%s\" for encoding \"%s\" already exists, skipping",
104 collname
, pg_encoding_to_char(collencoding
))));
109 (errcode(ERRCODE_DUPLICATE_OBJECT
),
111 ? errmsg("collation \"%s\" already exists",
113 : errmsg("collation \"%s\" for encoding \"%s\" already exists",
114 collname
, pg_encoding_to_char(collencoding
))));
117 /* open pg_collation; see below about the lock level */
118 rel
= table_open(CollationRelationId
, ShareRowExclusiveLock
);
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.
127 if (collencoding
== -1)
128 oid
= GetSysCacheOid3(COLLNAMEENCNSP
,
129 Anum_pg_collation_oid
,
130 PointerGetDatum(collname
),
131 Int32GetDatum(GetDatabaseEncoding()),
132 ObjectIdGetDatum(collnamespace
));
134 oid
= GetSysCacheOid3(COLLNAMEENCNSP
,
135 Anum_pg_collation_oid
,
136 PointerGetDatum(collname
),
138 ObjectIdGetDatum(collnamespace
));
143 table_close(rel
, NoLock
);
146 else if (if_not_exists
)
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.
152 ObjectAddressSet(myself
, CollationRelationId
, oid
);
153 checkMembershipInCurrentExtension(&myself
);
156 table_close(rel
, NoLock
);
158 (errcode(ERRCODE_DUPLICATE_OBJECT
),
159 errmsg("collation \"%s\" already exists, skipping",
165 (errcode(ERRCODE_DUPLICATE_OBJECT
),
166 errmsg("collation \"%s\" already exists",
170 tupDesc
= RelationGetDescr(rel
);
173 memset(nulls
, 0, sizeof(nulls
));
175 namestrcpy(&name_name
, collname
);
176 oid
= GetNewOidWithIndex(rel
, CollationOidIndexId
,
177 Anum_pg_collation_oid
);
178 values
[Anum_pg_collation_oid
- 1] = ObjectIdGetDatum(oid
);
179 values
[Anum_pg_collation_collname
- 1] = NameGetDatum(&name_name
);
180 values
[Anum_pg_collation_collnamespace
- 1] = ObjectIdGetDatum(collnamespace
);
181 values
[Anum_pg_collation_collowner
- 1] = ObjectIdGetDatum(collowner
);
182 values
[Anum_pg_collation_collprovider
- 1] = CharGetDatum(collprovider
);
183 values
[Anum_pg_collation_collisdeterministic
- 1] = BoolGetDatum(collisdeterministic
);
184 values
[Anum_pg_collation_collencoding
- 1] = Int32GetDatum(collencoding
);
186 values
[Anum_pg_collation_collcollate
- 1] = CStringGetTextDatum(collcollate
);
188 nulls
[Anum_pg_collation_collcollate
- 1] = true;
190 values
[Anum_pg_collation_collctype
- 1] = CStringGetTextDatum(collctype
);
192 nulls
[Anum_pg_collation_collctype
- 1] = true;
194 values
[Anum_pg_collation_colllocale
- 1] = CStringGetTextDatum(colllocale
);
196 nulls
[Anum_pg_collation_colllocale
- 1] = true;
198 values
[Anum_pg_collation_collicurules
- 1] = CStringGetTextDatum(collicurules
);
200 nulls
[Anum_pg_collation_collicurules
- 1] = true;
202 values
[Anum_pg_collation_collversion
- 1] = CStringGetTextDatum(collversion
);
204 nulls
[Anum_pg_collation_collversion
- 1] = true;
206 tup
= heap_form_tuple(tupDesc
, values
, nulls
);
208 /* insert a new tuple */
209 CatalogTupleInsert(rel
, tup
);
210 Assert(OidIsValid(oid
));
212 /* set up dependencies for the new collation */
213 myself
.classId
= CollationRelationId
;
214 myself
.objectId
= oid
;
215 myself
.objectSubId
= 0;
217 /* create dependency on namespace */
218 referenced
.classId
= NamespaceRelationId
;
219 referenced
.objectId
= collnamespace
;
220 referenced
.objectSubId
= 0;
221 recordDependencyOn(&myself
, &referenced
, DEPENDENCY_NORMAL
);
223 /* create dependency on owner */
224 recordDependencyOnOwner(CollationRelationId
, oid
, collowner
);
226 /* dependency on extension */
227 recordDependencyOnCurrentExtension(&myself
, false);
229 /* Post creation hook for new collation */
230 InvokeObjectPostCreateHook(CollationRelationId
, oid
, 0);
233 table_close(rel
, NoLock
);