PostgreSQL Source Code git master
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
collationcmds.h File Reference
Include dependency graph for collationcmds.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Functions

ObjectAddress DefineCollation (ParseState *pstate, List *names, List *parameters, bool if_not_exists)
 
void IsThereCollationInNamespace (const char *collname, Oid nspOid)
 
ObjectAddress AlterCollation (AlterCollationStmt *stmt)
 

Function Documentation

◆ AlterCollation()

ObjectAddress AlterCollation ( AlterCollationStmt stmt)

Definition at line 424 of file collationcmds.c.

425{
426 Relation rel;
427 Oid collOid;
428 HeapTuple tup;
429 Form_pg_collation collForm;
430 Datum datum;
431 bool isnull;
432 char *oldversion;
433 char *newversion;
434 ObjectAddress address;
435
436 rel = table_open(CollationRelationId, RowExclusiveLock);
437 collOid = get_collation_oid(stmt->collname, false);
438
439 if (collOid == DEFAULT_COLLATION_OID)
441 (errmsg("cannot refresh version of default collation"),
442 /* translator: %s is an SQL command */
443 errhint("Use %s instead.",
444 "ALTER DATABASE ... REFRESH COLLATION VERSION")));
445
446 if (!object_ownercheck(CollationRelationId, collOid, GetUserId()))
448 NameListToString(stmt->collname));
449
450 tup = SearchSysCacheCopy1(COLLOID, ObjectIdGetDatum(collOid));
451 if (!HeapTupleIsValid(tup))
452 elog(ERROR, "cache lookup failed for collation %u", collOid);
453
454 collForm = (Form_pg_collation) GETSTRUCT(tup);
455 datum = SysCacheGetAttr(COLLOID, tup, Anum_pg_collation_collversion, &isnull);
456 oldversion = isnull ? NULL : TextDatumGetCString(datum);
457
458 if (collForm->collprovider == COLLPROVIDER_LIBC)
459 datum = SysCacheGetAttrNotNull(COLLOID, tup, Anum_pg_collation_collcollate);
460 else
461 datum = SysCacheGetAttrNotNull(COLLOID, tup, Anum_pg_collation_colllocale);
462
463 newversion = get_collation_actual_version(collForm->collprovider,
464 TextDatumGetCString(datum));
465
466 /* cannot change from NULL to non-NULL or vice versa */
467 if ((!oldversion && newversion) || (oldversion && !newversion))
468 elog(ERROR, "invalid collation version change");
469 else if (oldversion && newversion && strcmp(newversion, oldversion) != 0)
470 {
471 bool nulls[Natts_pg_collation];
472 bool replaces[Natts_pg_collation];
473 Datum values[Natts_pg_collation];
474
476 (errmsg("changing version from %s to %s",
477 oldversion, newversion)));
478
479 memset(values, 0, sizeof(values));
480 memset(nulls, false, sizeof(nulls));
481 memset(replaces, false, sizeof(replaces));
482
483 values[Anum_pg_collation_collversion - 1] = CStringGetTextDatum(newversion);
484 replaces[Anum_pg_collation_collversion - 1] = true;
485
486 tup = heap_modify_tuple(tup, RelationGetDescr(rel),
487 values, nulls, replaces);
488 }
489 else
491 (errmsg("version has not changed")));
492
493 CatalogTupleUpdate(rel, &tup->t_self, tup);
494
495 InvokeObjectPostAlterHook(CollationRelationId, collOid, 0);
496
497 ObjectAddressSet(address, CollationRelationId, collOid);
498
499 heap_freetuple(tup);
500 table_close(rel, NoLock);
501
502 return address;
503}
@ ACLCHECK_NOT_OWNER
Definition: acl.h:185
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:2622
bool object_ownercheck(Oid classid, Oid objectid, Oid roleid)
Definition: aclchk.c:4064
static Datum values[MAXATTR]
Definition: bootstrap.c:151
#define CStringGetTextDatum(s)
Definition: builtins.h:97
#define TextDatumGetCString(d)
Definition: builtins.h:98
int errhint(const char *fmt,...)
Definition: elog.c:1317
int errmsg(const char *fmt,...)
Definition: elog.c:1070
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:225
#define NOTICE
Definition: elog.h:35
#define ereport(elevel,...)
Definition: elog.h:149
HeapTuple heap_modify_tuple(HeapTuple tuple, TupleDesc tupleDesc, const Datum *replValues, const bool *replIsnull, const bool *doReplace)
Definition: heaptuple.c:1210
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1435
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define GETSTRUCT(TUP)
Definition: htup_details.h:653
#define stmt
Definition: indent_codes.h:59
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:313
#define NoLock
Definition: lockdefs.h:34
#define RowExclusiveLock
Definition: lockdefs.h:38
Oid GetUserId(void)
Definition: miscinit.c:517
char * NameListToString(const List *names)
Definition: namespace.c:3594
Oid get_collation_oid(List *collname, bool missing_ok)
Definition: namespace.c:3971
#define InvokeObjectPostAlterHook(classId, objectId, subId)
Definition: objectaccess.h:197
#define ObjectAddressSet(addr, class_id, object_id)
Definition: objectaddress.h:40
@ OBJECT_COLLATION
Definition: parsenodes.h:2275
FormData_pg_collation * Form_pg_collation
Definition: pg_collation.h:58
char * get_collation_actual_version(char collprovider, const char *collcollate)
Definition: pg_locale.c:1390
uintptr_t Datum
Definition: postgres.h:64
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:252
unsigned int Oid
Definition: postgres_ext.h:31
#define RelationGetDescr(relation)
Definition: rel.h:531
ItemPointerData t_self
Definition: htup.h:65
Datum SysCacheGetAttr(int cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition: syscache.c:600
Datum SysCacheGetAttrNotNull(int cacheId, HeapTuple tup, AttrNumber attributeNumber)
Definition: syscache.c:631
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:91
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:126
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:40

References aclcheck_error(), ACLCHECK_NOT_OWNER, CatalogTupleUpdate(), CStringGetTextDatum, elog, ereport, errhint(), errmsg(), ERROR, get_collation_actual_version(), get_collation_oid(), GETSTRUCT, GetUserId(), heap_freetuple(), heap_modify_tuple(), HeapTupleIsValid, InvokeObjectPostAlterHook, NameListToString(), NoLock, NOTICE, OBJECT_COLLATION, object_ownercheck(), ObjectAddressSet, ObjectIdGetDatum(), RelationGetDescr, RowExclusiveLock, SearchSysCacheCopy1, stmt, SysCacheGetAttr(), SysCacheGetAttrNotNull(), HeapTupleData::t_self, table_close(), table_open(), TextDatumGetCString, and values.

Referenced by ProcessUtilitySlow().

◆ DefineCollation()

ObjectAddress DefineCollation ( ParseState pstate,
List names,
List parameters,
bool  if_not_exists 
)

Definition at line 53 of file collationcmds.c.

54{
55 char *collName;
56 Oid collNamespace;
57 AclResult aclresult;
58 ListCell *pl;
59 DefElem *fromEl = NULL;
60 DefElem *localeEl = NULL;
61 DefElem *lccollateEl = NULL;
62 DefElem *lcctypeEl = NULL;
63 DefElem *providerEl = NULL;
64 DefElem *deterministicEl = NULL;
65 DefElem *rulesEl = NULL;
66 DefElem *versionEl = NULL;
67 char *collcollate;
68 char *collctype;
69 const char *colllocale;
70 char *collicurules;
71 bool collisdeterministic;
72 int collencoding;
73 char collprovider;
74 char *collversion = NULL;
75 Oid newoid;
76 ObjectAddress address;
77
78 collNamespace = QualifiedNameGetCreationNamespace(names, &collName);
79
80 aclresult = object_aclcheck(NamespaceRelationId, collNamespace, GetUserId(), ACL_CREATE);
81 if (aclresult != ACLCHECK_OK)
83 get_namespace_name(collNamespace));
84
85 foreach(pl, parameters)
86 {
87 DefElem *defel = lfirst_node(DefElem, pl);
88 DefElem **defelp;
89
90 if (strcmp(defel->defname, "from") == 0)
91 defelp = &fromEl;
92 else if (strcmp(defel->defname, "locale") == 0)
93 defelp = &localeEl;
94 else if (strcmp(defel->defname, "lc_collate") == 0)
95 defelp = &lccollateEl;
96 else if (strcmp(defel->defname, "lc_ctype") == 0)
97 defelp = &lcctypeEl;
98 else if (strcmp(defel->defname, "provider") == 0)
99 defelp = &providerEl;
100 else if (strcmp(defel->defname, "deterministic") == 0)
101 defelp = &deterministicEl;
102 else if (strcmp(defel->defname, "rules") == 0)
103 defelp = &rulesEl;
104 else if (strcmp(defel->defname, "version") == 0)
105 defelp = &versionEl;
106 else
107 {
109 (errcode(ERRCODE_SYNTAX_ERROR),
110 errmsg("collation attribute \"%s\" not recognized",
111 defel->defname),
112 parser_errposition(pstate, defel->location)));
113 break;
114 }
115 if (*defelp != NULL)
116 errorConflictingDefElem(defel, pstate);
117 *defelp = defel;
118 }
119
120 if (localeEl && (lccollateEl || lcctypeEl))
122 errcode(ERRCODE_SYNTAX_ERROR),
123 errmsg("conflicting or redundant options"),
124 errdetail("LOCALE cannot be specified together with LC_COLLATE or LC_CTYPE."));
125
126 if (fromEl && list_length(parameters) != 1)
128 errcode(ERRCODE_SYNTAX_ERROR),
129 errmsg("conflicting or redundant options"),
130 errdetail("FROM cannot be specified together with any other options."));
131
132 if (fromEl)
133 {
134 Oid collid;
135 HeapTuple tp;
136 Datum datum;
137 bool isnull;
138
141 if (!HeapTupleIsValid(tp))
142 elog(ERROR, "cache lookup failed for collation %u", collid);
143
144 collprovider = ((Form_pg_collation) GETSTRUCT(tp))->collprovider;
145 collisdeterministic = ((Form_pg_collation) GETSTRUCT(tp))->collisdeterministic;
146 collencoding = ((Form_pg_collation) GETSTRUCT(tp))->collencoding;
147
148 datum = SysCacheGetAttr(COLLOID, tp, Anum_pg_collation_collcollate, &isnull);
149 if (!isnull)
150 collcollate = TextDatumGetCString(datum);
151 else
152 collcollate = NULL;
153
154 datum = SysCacheGetAttr(COLLOID, tp, Anum_pg_collation_collctype, &isnull);
155 if (!isnull)
156 collctype = TextDatumGetCString(datum);
157 else
158 collctype = NULL;
159
160 datum = SysCacheGetAttr(COLLOID, tp, Anum_pg_collation_colllocale, &isnull);
161 if (!isnull)
162 colllocale = TextDatumGetCString(datum);
163 else
164 colllocale = NULL;
165
166 /*
167 * When the ICU locale comes from an existing collation, do not
168 * canonicalize to a language tag.
169 */
170
171 datum = SysCacheGetAttr(COLLOID, tp, Anum_pg_collation_collicurules, &isnull);
172 if (!isnull)
173 collicurules = TextDatumGetCString(datum);
174 else
175 collicurules = NULL;
176
177 ReleaseSysCache(tp);
178
179 /*
180 * Copying the "default" collation is not allowed because most code
181 * checks for DEFAULT_COLLATION_OID instead of COLLPROVIDER_DEFAULT,
182 * and so having a second collation with COLLPROVIDER_DEFAULT would
183 * not work and potentially confuse or crash some code. This could be
184 * fixed with some legwork.
185 */
186 if (collprovider == COLLPROVIDER_DEFAULT)
188 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
189 errmsg("collation \"default\" cannot be copied")));
190 }
191 else
192 {
193 char *collproviderstr = NULL;
194
195 collcollate = NULL;
196 collctype = NULL;
197 colllocale = NULL;
198 collicurules = NULL;
199
200 if (providerEl)
201 collproviderstr = defGetString(providerEl);
202
203 if (deterministicEl)
204 collisdeterministic = defGetBoolean(deterministicEl);
205 else
206 collisdeterministic = true;
207
208 if (rulesEl)
209 collicurules = defGetString(rulesEl);
210
211 if (versionEl)
212 collversion = defGetString(versionEl);
213
214 if (collproviderstr)
215 {
216 if (pg_strcasecmp(collproviderstr, "builtin") == 0)
217 collprovider = COLLPROVIDER_BUILTIN;
218 else if (pg_strcasecmp(collproviderstr, "icu") == 0)
219 collprovider = COLLPROVIDER_ICU;
220 else if (pg_strcasecmp(collproviderstr, "libc") == 0)
221 collprovider = COLLPROVIDER_LIBC;
222 else
224 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
225 errmsg("unrecognized collation provider: %s",
226 collproviderstr)));
227 }
228 else
229 collprovider = COLLPROVIDER_LIBC;
230
231 if (localeEl)
232 {
233 if (collprovider == COLLPROVIDER_LIBC)
234 {
235 collcollate = defGetString(localeEl);
236 collctype = defGetString(localeEl);
237 }
238 else
239 colllocale = defGetString(localeEl);
240 }
241
242 if (lccollateEl)
243 collcollate = defGetString(lccollateEl);
244
245 if (lcctypeEl)
246 collctype = defGetString(lcctypeEl);
247
248 if (collprovider == COLLPROVIDER_BUILTIN)
249 {
250 if (!colllocale)
252 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
253 errmsg("parameter \"%s\" must be specified",
254 "locale")));
255
257 colllocale);
258 }
259 else if (collprovider == COLLPROVIDER_LIBC)
260 {
261 if (!collcollate)
263 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
264 errmsg("parameter \"%s\" must be specified",
265 "lc_collate")));
266
267 if (!collctype)
269 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
270 errmsg("parameter \"%s\" must be specified",
271 "lc_ctype")));
272 }
273 else if (collprovider == COLLPROVIDER_ICU)
274 {
275 if (!colllocale)
277 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
278 errmsg("parameter \"%s\" must be specified",
279 "locale")));
280
281 /*
282 * During binary upgrade, preserve the locale string. Otherwise,
283 * canonicalize to a language tag.
284 */
285 if (!IsBinaryUpgrade)
286 {
287 char *langtag = icu_language_tag(colllocale,
289
290 if (langtag && strcmp(colllocale, langtag) != 0)
291 {
293 (errmsg("using standard form \"%s\" for ICU locale \"%s\"",
294 langtag, colllocale)));
295
296 colllocale = langtag;
297 }
298 }
299
300 icu_validate_locale(colllocale);
301 }
302
303 /*
304 * Nondeterministic collations are currently only supported with ICU
305 * because that's the only case where it can actually make a
306 * difference. So we can save writing the code for the other
307 * providers.
308 */
309 if (!collisdeterministic && collprovider != COLLPROVIDER_ICU)
311 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
312 errmsg("nondeterministic collations not supported with this provider")));
313
314 if (collicurules && collprovider != COLLPROVIDER_ICU)
316 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
317 errmsg("ICU rules cannot be specified unless locale provider is ICU")));
318
319 if (collprovider == COLLPROVIDER_BUILTIN)
320 {
321 collencoding = builtin_locale_encoding(colllocale);
322 }
323 else if (collprovider == COLLPROVIDER_ICU)
324 {
325#ifdef USE_ICU
326 /*
327 * We could create ICU collations with collencoding == database
328 * encoding, but it seems better to use -1 so that it matches the
329 * way initdb would create ICU collations. However, only allow
330 * one to be created when the current database's encoding is
331 * supported. Otherwise the collation is useless, plus we get
332 * surprising behaviors like not being able to drop the collation.
333 *
334 * Skip this test when !USE_ICU, because the error we want to
335 * throw for that isn't thrown till later.
336 */
339 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
340 errmsg("current database's encoding is not supported with this provider")));
341#endif
342 collencoding = -1;
343 }
344 else
345 {
346 collencoding = GetDatabaseEncoding();
347 check_encoding_locale_matches(collencoding, collcollate, collctype);
348 }
349 }
350
351 if (!collversion)
352 {
353 const char *locale;
354
355 if (collprovider == COLLPROVIDER_LIBC)
356 locale = collcollate;
357 else
358 locale = colllocale;
359
360 collversion = get_collation_actual_version(collprovider, locale);
361 }
362
363 newoid = CollationCreate(collName,
364 collNamespace,
365 GetUserId(),
366 collprovider,
367 collisdeterministic,
368 collencoding,
369 collcollate,
370 collctype,
371 colllocale,
372 collicurules,
373 collversion,
374 if_not_exists,
375 false); /* not quiet */
376
377 if (!OidIsValid(newoid))
379
380 /* Check that the locales can be loaded. */
382 (void) pg_newlocale_from_collation(newoid);
383
384 ObjectAddressSet(address, CollationRelationId, newoid);
385
386 return address;
387}
AclResult
Definition: acl.h:182
@ ACLCHECK_OK
Definition: acl.h:183
AclResult object_aclcheck(Oid classid, Oid objectid, Oid roleid, AclMode mode)
Definition: aclchk.c:3810
#define OidIsValid(objectId)
Definition: c.h:729
Oid collid
void check_encoding_locale_matches(int encoding, const char *collate, const char *ctype)
Definition: dbcommands.c:1570
char * defGetString(DefElem *def)
Definition: define.c:35
bool defGetBoolean(DefElem *def)
Definition: define.c:94
List * defGetQualifiedName(DefElem *def)
Definition: define.c:239
void errorConflictingDefElem(DefElem *defel, ParseState *pstate)
Definition: define.c:371
int errdetail(const char *fmt,...)
Definition: elog.c:1203
int errcode(int sqlerrcode)
Definition: elog.c:853
bool is_encoding_supported_by_icu(int encoding)
Definition: encnames.c:461
bool IsBinaryUpgrade
Definition: globals.c:120
static char * locale
Definition: initdb.c:140
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3366
int GetDatabaseEncoding(void)
Definition: mbutils.c:1261
Oid QualifiedNameGetCreationNamespace(const List *names, char **objname_p)
Definition: namespace.c:3487
const ObjectAddress InvalidObjectAddress
int parser_errposition(ParseState *pstate, int location)
Definition: parse_node.c:106
@ OBJECT_SCHEMA
Definition: parsenodes.h:2304
#define ACL_CREATE
Definition: parsenodes.h:85
Oid CollationCreate(const char *collname, Oid collnamespace, Oid collowner, char collprovider, bool collisdeterministic, int32 collencoding, const char *collcollate, const char *collctype, const char *colllocale, const char *collicurules, const char *collversion, bool if_not_exists, bool quiet)
Definition: pg_collation.c:42
#define lfirst_node(type, lc)
Definition: pg_list.h:176
static int list_length(const List *l)
Definition: pg_list.h:152
int icu_validation_level
Definition: pg_locale.c:146
void icu_validate_locale(const char *loc_str)
Definition: pg_locale.c:1884
pg_locale_t pg_newlocale_from_collation(Oid collid)
Definition: pg_locale.c:1341
int builtin_locale_encoding(const char *locale)
Definition: pg_locale.c:1767
char * icu_language_tag(const char *loc_str, int elevel)
Definition: pg_locale.c:1826
const char * builtin_validate_locale(int encoding, const char *locale)
Definition: pg_locale.c:1788
int pg_strcasecmp(const char *s1, const char *s2)
Definition: pgstrcasecmp.c:36
char * defname
Definition: parsenodes.h:817
ParseLoc location
Definition: parsenodes.h:821
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:269
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:221
void CommandCounterIncrement(void)
Definition: xact.c:1099

References ACL_CREATE, aclcheck_error(), ACLCHECK_OK, builtin_locale_encoding(), builtin_validate_locale(), check_encoding_locale_matches(), CollationCreate(), collid, CommandCounterIncrement(), defGetBoolean(), defGetQualifiedName(), defGetString(), DefElem::defname, elog, ereport, errcode(), errdetail(), errmsg(), ERROR, errorConflictingDefElem(), get_collation_actual_version(), get_collation_oid(), get_namespace_name(), GetDatabaseEncoding(), GETSTRUCT, GetUserId(), HeapTupleIsValid, icu_language_tag(), icu_validate_locale(), icu_validation_level, InvalidObjectAddress, is_encoding_supported_by_icu(), IsBinaryUpgrade, lfirst_node, list_length(), locale, DefElem::location, NOTICE, object_aclcheck(), OBJECT_SCHEMA, ObjectAddressSet, ObjectIdGetDatum(), OidIsValid, parser_errposition(), pg_newlocale_from_collation(), pg_strcasecmp(), QualifiedNameGetCreationNamespace(), ReleaseSysCache(), SearchSysCache1(), SysCacheGetAttr(), and TextDatumGetCString.

Referenced by ProcessUtilitySlow().

◆ IsThereCollationInNamespace()

void IsThereCollationInNamespace ( const char *  collname,
Oid  nspOid 
)

Definition at line 396 of file collationcmds.c.

397{
398 /* make sure the name doesn't already exist in new schema */
399 if (SearchSysCacheExists3(COLLNAMEENCNSP,
400 CStringGetDatum(collname),
402 ObjectIdGetDatum(nspOid)))
405 errmsg("collation \"%s\" for encoding \"%s\" already exists in schema \"%s\"",
406 collname, GetDatabaseEncodingName(),
407 get_namespace_name(nspOid))));
408
409 /* mustn't match an any-encoding entry, either */
410 if (SearchSysCacheExists3(COLLNAMEENCNSP,
411 CStringGetDatum(collname),
412 Int32GetDatum(-1),
413 ObjectIdGetDatum(nspOid)))
416 errmsg("collation \"%s\" already exists in schema \"%s\"",
417 collname, get_namespace_name(nspOid))));
418}
const char * GetDatabaseEncodingName(void)
Definition: mbutils.c:1267
static Datum CStringGetDatum(const char *X)
Definition: postgres.h:350
static Datum Int32GetDatum(int32 X)
Definition: postgres.h:212
#define ERRCODE_DUPLICATE_OBJECT
Definition: streamutil.c:30
#define SearchSysCacheExists3(cacheId, key1, key2, key3)
Definition: syscache.h:104

References CStringGetDatum(), ereport, errcode(), ERRCODE_DUPLICATE_OBJECT, errmsg(), ERROR, get_namespace_name(), GetDatabaseEncoding(), GetDatabaseEncodingName(), Int32GetDatum(), ObjectIdGetDatum(), and SearchSysCacheExists3.

Referenced by AlterObjectNamespace_internal(), and AlterObjectRename_internal().