PostgreSQL Source Code git master
collationcmds.c
Go to the documentation of this file.
1/*-------------------------------------------------------------------------
2 *
3 * collationcmds.c
4 * collation-related commands support code
5 *
6 * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
8 *
9 *
10 * IDENTIFICATION
11 * src/backend/commands/collationcmds.c
12 *
13 *-------------------------------------------------------------------------
14 */
15#include "postgres.h"
16
17#include "access/htup_details.h"
18#include "access/table.h"
19#include "access/xact.h"
20#include "catalog/indexing.h"
21#include "catalog/namespace.h"
24#include "catalog/pg_database.h"
27#include "commands/comment.h"
28#include "commands/dbcommands.h"
29#include "commands/defrem.h"
30#include "common/string.h"
31#include "mb/pg_wchar.h"
32#include "miscadmin.h"
33#include "utils/acl.h"
34#include "utils/builtins.h"
35#include "utils/lsyscache.h"
36#include "utils/pg_locale.h"
37#include "utils/rel.h"
38#include "utils/syscache.h"
39
40
41typedef struct
42{
43 char *localename; /* name of locale, as per "locale -a" */
44 char *alias; /* shortened alias for same */
45 int enc; /* encoding */
47
48
49/*
50 * CREATE COLLATION
51 */
53DefineCollation(ParseState *pstate, List *names, List *parameters, bool if_not_exists)
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}
388
389/*
390 * Subroutine for ALTER COLLATION SET SCHEMA and RENAME
391 *
392 * Is there a collation with the same name of the given collation already in
393 * the given namespace? If so, raise an appropriate error message.
394 */
395void
396IsThereCollationInNamespace(const char *collname, Oid nspOid)
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}
419
420/*
421 * ALTER COLLATION
422 */
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}
504
505
506Datum
508{
510 char provider;
511 char *locale;
512 char *version;
513 Datum datum;
514
515 if (collid == DEFAULT_COLLATION_OID)
516 {
517 /* retrieve from pg_database */
518
520
521 if (!HeapTupleIsValid(dbtup))
523 (errcode(ERRCODE_UNDEFINED_OBJECT),
524 errmsg("database with OID %u does not exist", MyDatabaseId)));
525
527
528 if (provider == COLLPROVIDER_LIBC)
529 {
530 datum = SysCacheGetAttrNotNull(DATABASEOID, dbtup, Anum_pg_database_datcollate);
532 }
533 else
534 {
535 datum = SysCacheGetAttrNotNull(DATABASEOID, dbtup, Anum_pg_database_datlocale);
537 }
538
539 ReleaseSysCache(dbtup);
540 }
541 else
542 {
543 /* retrieve from pg_collation */
544
546
547 if (!HeapTupleIsValid(colltp))
549 (errcode(ERRCODE_UNDEFINED_OBJECT),
550 errmsg("collation with OID %u does not exist", collid)));
551
552 provider = ((Form_pg_collation) GETSTRUCT(colltp))->collprovider;
553 Assert(provider != COLLPROVIDER_DEFAULT);
554
555 if (provider == COLLPROVIDER_LIBC)
556 {
557 datum = SysCacheGetAttrNotNull(COLLOID, colltp, Anum_pg_collation_collcollate);
559 }
560 else
561 {
562 datum = SysCacheGetAttrNotNull(COLLOID, colltp, Anum_pg_collation_colllocale);
564 }
565
566 ReleaseSysCache(colltp);
567 }
568
570 if (version)
572 else
574}
575
576
577/* will we use "locale -a" in pg_import_system_collations? */
578#if !defined(WIN32)
579#define READ_LOCALE_A_OUTPUT
580#endif
581
582/* will we use EnumSystemLocalesEx in pg_import_system_collations? */
583#ifdef WIN32
584#define ENUM_SYSTEM_LOCALE
585#endif
586
587
588#ifdef READ_LOCALE_A_OUTPUT
589/*
590 * "Normalize" a libc locale name, stripping off encoding tags such as
591 * ".utf8" (e.g., "en_US.utf8" -> "en_US", but "br_FR.iso885915@euro"
592 * -> "br_FR@euro"). Return true if a new, different name was
593 * generated.
594 */
595static bool
596normalize_libc_locale_name(char *new, const char *old)
597{
598 char *n = new;
599 const char *o = old;
600 bool changed = false;
601
602 while (*o)
603 {
604 if (*o == '.')
605 {
606 /* skip over encoding tag such as ".utf8" or ".UTF-8" */
607 o++;
608 while ((*o >= 'A' && *o <= 'Z')
609 || (*o >= 'a' && *o <= 'z')
610 || (*o >= '0' && *o <= '9')
611 || (*o == '-'))
612 o++;
613 changed = true;
614 }
615 else
616 *n++ = *o++;
617 }
618 *n = '\0';
619
620 return changed;
621}
622
623/*
624 * qsort comparator for CollAliasData items
625 */
626static int
627cmpaliases(const void *a, const void *b)
628{
629 const CollAliasData *ca = (const CollAliasData *) a;
630 const CollAliasData *cb = (const CollAliasData *) b;
631
632 /* comparing localename is enough because other fields are derived */
633 return strcmp(ca->localename, cb->localename);
634}
635#endif /* READ_LOCALE_A_OUTPUT */
636
637
638#ifdef USE_ICU
639/*
640 * Get a comment (specifically, the display name) for an ICU locale.
641 * The result is a palloc'd string, or NULL if we can't get a comment
642 * or find that it's not all ASCII. (We can *not* accept non-ASCII
643 * comments, because the contents of template0 must be encoding-agnostic.)
644 */
645static char *
646get_icu_locale_comment(const char *localename)
647{
648 UErrorCode status;
649 UChar displayname[128];
650 int32 len_uchar;
651 int32 i;
652 char *result;
653
654 status = U_ZERO_ERROR;
655 len_uchar = uloc_getDisplayName(localename, "en",
656 displayname, lengthof(displayname),
657 &status);
658 if (U_FAILURE(status))
659 return NULL; /* no good reason to raise an error */
660
661 /* Check for non-ASCII comment (can't use pg_is_ascii for this) */
662 for (i = 0; i < len_uchar; i++)
663 {
664 if (displayname[i] > 127)
665 return NULL;
666 }
667
668 /* OK, transcribe */
669 result = palloc(len_uchar + 1);
670 for (i = 0; i < len_uchar; i++)
671 result[i] = displayname[i];
672 result[len_uchar] = '\0';
673
674 return result;
675}
676#endif /* USE_ICU */
677
678
679/*
680 * Create a new collation using the input locale 'locale'. (subroutine for
681 * pg_import_system_collations())
682 *
683 * 'nspid' is the namespace id where the collation will be created.
684 *
685 * 'nvalidp' is incremented if the locale has a valid encoding.
686 *
687 * 'ncreatedp' is incremented if the collation is actually created. If the
688 * collation already exists it will quietly do nothing.
689 *
690 * The returned value is the encoding of the locale, -1 if the locale is not
691 * valid for creating a collation.
692 *
693 */
695static int
696create_collation_from_locale(const char *locale, int nspid,
697 int *nvalidp, int *ncreatedp)
698{
699 int enc;
701
702 /*
703 * Some systems have locale names that don't consist entirely of ASCII
704 * letters (such as "bokm&aring;l" or "fran&ccedil;ais"). This is pretty
705 * silly, since we need the locale itself to interpret the non-ASCII
706 * characters. We can't do much with those, so we filter them out.
707 */
709 {
710 elog(DEBUG1, "skipping locale with non-ASCII name: \"%s\"", locale);
711 return -1;
712 }
713
715 if (enc < 0)
716 {
717 elog(DEBUG1, "skipping locale with unrecognized encoding: \"%s\"", locale);
718 return -1;
719 }
721 {
722 elog(DEBUG1, "skipping locale with client-only encoding: \"%s\"", locale);
723 return -1;
724 }
726 return -1; /* C/POSIX are already in the catalog */
727
728 /* count valid locales found in operating system */
729 (*nvalidp)++;
730
731 /*
732 * Create a collation named the same as the locale, but quietly doing
733 * nothing if it already exists. This is the behavior we need even at
734 * initdb time, because some versions of "locale -a" can report the same
735 * locale name more than once. And it's convenient for later import runs,
736 * too, since you just about always want to add on new locales without a
737 * lot of chatter about existing ones.
738 */
740 COLLPROVIDER_LIBC, true, enc,
741 locale, locale, NULL, NULL,
742 get_collation_actual_version(COLLPROVIDER_LIBC, locale),
743 true, true);
744 if (OidIsValid(collid))
745 {
746 (*ncreatedp)++;
747
748 /* Must do CCI between inserts to handle duplicates correctly */
750 }
751
752 return enc;
753}
754
755
756#ifdef ENUM_SYSTEM_LOCALE
757/* parameter to be passed to the callback function win32_read_locale() */
758typedef struct
759{
760 Oid nspid;
761 int *ncreatedp;
762 int *nvalidp;
763} CollParam;
764
765/*
766 * Callback function for EnumSystemLocalesEx() in
767 * pg_import_system_collations(). Creates a collation for every valid locale
768 * and a POSIX alias collation.
769 *
770 * The callback contract is to return TRUE to continue enumerating and FALSE
771 * to stop enumerating. We always want to continue.
772 */
773static BOOL CALLBACK
774win32_read_locale(LPWSTR pStr, DWORD dwFlags, LPARAM lparam)
775{
776 CollParam *param = (CollParam *) lparam;
777 char localebuf[NAMEDATALEN];
778 int result;
779 int enc;
780
781 (void) dwFlags;
782
783 result = WideCharToMultiByte(CP_ACP, 0, pStr, -1, localebuf, NAMEDATALEN,
784 NULL, NULL);
785
786 if (result == 0)
787 {
788 if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
789 elog(DEBUG1, "skipping locale with too-long name: \"%s\"", localebuf);
790 return TRUE;
791 }
792 if (localebuf[0] == '\0')
793 return TRUE;
794
795 enc = create_collation_from_locale(localebuf, param->nspid,
796 param->nvalidp, param->ncreatedp);
797 if (enc < 0)
798 return TRUE;
799
800 /*
801 * Windows will use hyphens between language and territory, where POSIX
802 * uses an underscore. Simply create a POSIX alias.
803 */
804 if (strchr(localebuf, '-'))
805 {
806 char alias[NAMEDATALEN];
807 Oid collid;
808
809 strcpy(alias, localebuf);
810 for (char *p = alias; *p; p++)
811 if (*p == '-')
812 *p = '_';
813
814 collid = CollationCreate(alias, param->nspid, GetUserId(),
815 COLLPROVIDER_LIBC, true, enc,
816 localebuf, localebuf, NULL, NULL,
817 get_collation_actual_version(COLLPROVIDER_LIBC, localebuf),
818 true, true);
819 if (OidIsValid(collid))
820 {
821 (*param->ncreatedp)++;
822
824 }
825 }
826
827 return TRUE;
828}
829#endif /* ENUM_SYSTEM_LOCALE */
830
831
832/*
833 * pg_import_system_collations: add known system collations to pg_collation
834 */
835Datum
837{
839 int ncreated = 0;
840
841 if (!superuser())
843 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
844 errmsg("must be superuser to import system collations")));
845
846 if (!SearchSysCacheExists1(NAMESPACEOID, ObjectIdGetDatum(nspid)))
848 (errcode(ERRCODE_UNDEFINED_SCHEMA),
849 errmsg("schema with OID %u does not exist", nspid)));
850
851 /* Load collations known to libc, using "locale -a" to enumerate them */
852#ifdef READ_LOCALE_A_OUTPUT
853 {
854 FILE *locale_a_handle;
855 char localebuf[LOCALE_NAME_BUFLEN];
856 int nvalid = 0;
857 Oid collid;
858 CollAliasData *aliases;
859 int naliases,
860 maxaliases,
861 i;
862
863 /* expansible array of aliases */
864 maxaliases = 100;
865 aliases = (CollAliasData *) palloc(maxaliases * sizeof(CollAliasData));
866 naliases = 0;
867
868 locale_a_handle = OpenPipeStream("locale -a", "r");
869 if (locale_a_handle == NULL)
872 errmsg("could not execute command \"%s\": %m",
873 "locale -a")));
874
875 while (fgets(localebuf, sizeof(localebuf), locale_a_handle))
876 {
877 size_t len;
878 int enc;
879 char alias[LOCALE_NAME_BUFLEN];
880
881 len = strlen(localebuf);
882
883 if (len == 0 || localebuf[len - 1] != '\n')
884 {
885 elog(DEBUG1, "skipping locale with too-long name: \"%s\"", localebuf);
886 continue;
887 }
888 localebuf[len - 1] = '\0';
889
890 enc = create_collation_from_locale(localebuf, nspid, &nvalid, &ncreated);
891 if (enc < 0)
892 continue;
893
894 /*
895 * Generate aliases such as "en_US" in addition to "en_US.utf8"
896 * for ease of use. Note that collation names are unique per
897 * encoding only, so this doesn't clash with "en_US" for LATIN1,
898 * say.
899 *
900 * However, it might conflict with a name we'll see later in the
901 * "locale -a" output. So save up the aliases and try to add them
902 * after we've read all the output.
903 */
904 if (normalize_libc_locale_name(alias, localebuf))
905 {
906 if (naliases >= maxaliases)
907 {
908 maxaliases *= 2;
909 aliases = (CollAliasData *)
910 repalloc(aliases, maxaliases * sizeof(CollAliasData));
911 }
912 aliases[naliases].localename = pstrdup(localebuf);
913 aliases[naliases].alias = pstrdup(alias);
914 aliases[naliases].enc = enc;
915 naliases++;
916 }
917 }
918
919 /*
920 * We don't check the return value of this, because we want to support
921 * the case where there "locale" command does not exist. (This is
922 * unusual but can happen on minimalized Linux distributions, for
923 * example.) We will warn below if no locales could be found.
924 */
925 ClosePipeStream(locale_a_handle);
926
927 /*
928 * Before processing the aliases, sort them by locale name. The point
929 * here is that if "locale -a" gives us multiple locale names with the
930 * same encoding and base name, say "en_US.utf8" and "en_US.utf-8", we
931 * want to pick a deterministic one of them. First in ASCII sort
932 * order is a good enough rule. (Before PG 10, the code corresponding
933 * to this logic in initdb.c had an additional ordering rule, to
934 * prefer the locale name exactly matching the alias, if any. We
935 * don't need to consider that here, because we would have already
936 * created such a pg_collation entry above, and that one will win.)
937 */
938 if (naliases > 1)
939 qsort(aliases, naliases, sizeof(CollAliasData), cmpaliases);
940
941 /* Now add aliases, ignoring any that match pre-existing entries */
942 for (i = 0; i < naliases; i++)
943 {
944 char *locale = aliases[i].localename;
945 char *alias = aliases[i].alias;
946 int enc = aliases[i].enc;
947
949 COLLPROVIDER_LIBC, true, enc,
950 locale, locale, NULL, NULL,
951 get_collation_actual_version(COLLPROVIDER_LIBC, locale),
952 true, true);
953 if (OidIsValid(collid))
954 {
955 ncreated++;
956
958 }
959 }
960
961 /* Give a warning if "locale -a" seems to be malfunctioning */
962 if (nvalid == 0)
964 (errmsg("no usable system locales were found")));
965 }
966#endif /* READ_LOCALE_A_OUTPUT */
967
968 /*
969 * Load collations known to ICU
970 *
971 * We use uloc_countAvailable()/uloc_getAvailable() rather than
972 * ucol_countAvailable()/ucol_getAvailable(). The former returns a full
973 * set of language+region combinations, whereas the latter only returns
974 * language+region combinations if they are distinct from the language's
975 * base collation. So there might not be a de-DE or en-GB, which would be
976 * confusing.
977 */
978#ifdef USE_ICU
979 {
980 int i;
981
982 /*
983 * Start the loop at -1 to sneak in the root locale without too much
984 * code duplication.
985 */
986 for (i = -1; i < uloc_countAvailable(); i++)
987 {
988 const char *name;
989 char *langtag;
990 char *icucomment;
991 Oid collid;
992
993 if (i == -1)
994 name = ""; /* ICU root locale */
995 else
996 name = uloc_getAvailable(i);
997
998 langtag = icu_language_tag(name, ERROR);
999
1000 /*
1001 * Be paranoid about not allowing any non-ASCII strings into
1002 * pg_collation
1003 */
1004 if (!pg_is_ascii(langtag))
1005 continue;
1006
1007 collid = CollationCreate(psprintf("%s-x-icu", langtag),
1008 nspid, GetUserId(),
1009 COLLPROVIDER_ICU, true, -1,
1010 NULL, NULL, langtag, NULL,
1011 get_collation_actual_version(COLLPROVIDER_ICU, langtag),
1012 true, true);
1013 if (OidIsValid(collid))
1014 {
1015 ncreated++;
1016
1018
1019 icucomment = get_icu_locale_comment(name);
1020 if (icucomment)
1021 CreateComments(collid, CollationRelationId, 0,
1022 icucomment);
1023 }
1024 }
1025 }
1026#endif /* USE_ICU */
1027
1028 /* Load collations known to WIN32 */
1029#ifdef ENUM_SYSTEM_LOCALE
1030 {
1031 int nvalid = 0;
1032 CollParam param;
1033
1034 param.nspid = nspid;
1035 param.ncreatedp = &ncreated;
1036 param.nvalidp = &nvalid;
1037
1038 /*
1039 * Enumerate the locales that are either installed on or supported by
1040 * the OS.
1041 */
1042 if (!EnumSystemLocalesEx(win32_read_locale, LOCALE_ALL,
1043 (LPARAM) &param, NULL))
1044 _dosmaperr(GetLastError());
1045
1046 /* Give a warning if EnumSystemLocalesEx seems to be malfunctioning */
1047 if (nvalid == 0)
1049 (errmsg("no usable system locales were found")));
1050 }
1051#endif /* ENUM_SYSTEM_LOCALE */
1052
1053 PG_RETURN_INT32(ncreated);
1054}
AclResult
Definition: acl.h:182
@ ACLCHECK_OK
Definition: acl.h:183
@ ACLCHECK_NOT_OWNER
Definition: acl.h:185
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:2622
AclResult object_aclcheck(Oid classid, Oid objectid, Oid roleid, AclMode mode)
Definition: aclchk.c:3804
bool object_ownercheck(Oid classid, Oid objectid, Oid roleid)
Definition: aclchk.c:4058
static Datum values[MAXATTR]
Definition: bootstrap.c:151
#define CStringGetTextDatum(s)
Definition: builtins.h:97
#define TextDatumGetCString(d)
Definition: builtins.h:98
#define Assert(condition)
Definition: c.h:815
int32_t int32
Definition: c.h:484
#define lengthof(array)
Definition: c.h:745
#define OidIsValid(objectId)
Definition: c.h:732
Datum pg_collation_actual_version(PG_FUNCTION_ARGS)
static bool normalize_libc_locale_name(char *new, const char *old)
int nspid
int int * nvalidp
static int cmpaliases(const void *a, const void *b)
enc
pg_attribute_unused() static int create_collation_from_locale(const char *locale
ObjectAddress AlterCollation(AlterCollationStmt *stmt)
void IsThereCollationInNamespace(const char *collname, Oid nspOid)
Datum pg_import_system_collations(PG_FUNCTION_ARGS)
int int int * ncreatedp
Oid collid
ObjectAddress DefineCollation(ParseState *pstate, List *names, List *parameters, bool if_not_exists)
Definition: collationcmds.c:53
void CreateComments(Oid oid, Oid classoid, int32 subid, const char *comment)
Definition: comment.c:143
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 errcode_for_file_access(void)
Definition: elog.c:876
int errdetail(const char *fmt,...)
Definition: elog.c:1203
int errhint(const char *fmt,...)
Definition: elog.c:1317
int errcode(int sqlerrcode)
Definition: elog.c:853
int errmsg(const char *fmt,...)
Definition: elog.c:1070
#define WARNING
Definition: elog.h:36
#define DEBUG1
Definition: elog.h:30
#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
bool is_encoding_supported_by_icu(int encoding)
Definition: encnames.c:461
FILE * OpenPipeStream(const char *command, const char *mode)
Definition: fd.c:2708
int ClosePipeStream(FILE *file)
Definition: fd.c:3013
#define PG_GETARG_OID(n)
Definition: fmgr.h:275
#define PG_RETURN_NULL()
Definition: fmgr.h:345
#define PG_RETURN_TEXT_P(x)
Definition: fmgr.h:372
#define PG_RETURN_INT32(x)
Definition: fmgr.h:354
#define PG_FUNCTION_ARGS
Definition: fmgr.h:193
bool IsBinaryUpgrade
Definition: globals.c:120
Oid MyDatabaseId
Definition: globals.c:93
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
static void * GETSTRUCT(const HeapTupleData *tuple)
Definition: htup_details.h:728
#define stmt
Definition: indent_codes.h:59
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:313
static char * locale
Definition: initdb.c:140
int b
Definition: isn.c:69
int a
Definition: isn.c:68
int i
Definition: isn.c:72
static JitProviderCallbacks provider
Definition: jit.c:43
#define NoLock
Definition: lockdefs.h:34
#define RowExclusiveLock
Definition: lockdefs.h:38
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3393
int GetDatabaseEncoding(void)
Definition: mbutils.c:1261
const char * GetDatabaseEncodingName(void)
Definition: mbutils.c:1267
char * pstrdup(const char *in)
Definition: mcxt.c:1696
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:1541
void * palloc(Size size)
Definition: mcxt.c:1317
Oid GetUserId(void)
Definition: miscinit.c:517
char * NameListToString(const List *names)
Definition: namespace.c:3594
Oid QualifiedNameGetCreationNamespace(const List *names, char **objname_p)
Definition: namespace.c:3487
Oid get_collation_oid(List *collname, bool missing_ok)
Definition: namespace.c:3971
#define InvokeObjectPostAlterHook(classId, objectId, subId)
Definition: objectaccess.h:197
const ObjectAddress InvalidObjectAddress
#define ObjectAddressSet(addr, class_id, object_id)
Definition: objectaddress.h:40
int parser_errposition(ParseState *pstate, int location)
Definition: parse_node.c:106
@ OBJECT_COLLATION
Definition: parsenodes.h:2319
@ OBJECT_SCHEMA
Definition: parsenodes.h:2348
#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
FormData_pg_collation * Form_pg_collation
Definition: pg_collation.h:58
#define NAMEDATALEN
const void size_t len
char datlocprovider
Definition: pg_database.h:44
FormData_pg_database * Form_pg_database
Definition: pg_database.h:96
#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:134
void icu_validate_locale(const char *loc_str)
Definition: pg_locale.c:1735
char * get_collation_actual_version(char collprovider, const char *collcollate)
Definition: pg_locale.c:1381
pg_locale_t pg_newlocale_from_collation(Oid collid)
Definition: pg_locale.c:1332
int builtin_locale_encoding(const char *locale)
Definition: pg_locale.c:1613
char * icu_language_tag(const char *loc_str, int elevel)
Definition: pg_locale.c:1677
const char * builtin_validate_locale(int encoding, const char *locale)
Definition: pg_locale.c:1637
#define LOCALE_NAME_BUFLEN
Definition: pg_locale.h:20
@ PG_SQL_ASCII
Definition: pg_wchar.h:226
#define PG_VALID_BE_ENCODING(_enc)
Definition: pg_wchar.h:281
int pg_strcasecmp(const char *s1, const char *s2)
Definition: pgstrcasecmp.c:36
int pg_get_encoding_from_locale(const char *ctype, bool write_message)
Definition: chklocale.c:301
#define qsort(a, b, c, d)
Definition: port.h:475
uintptr_t Datum
Definition: postgres.h:69
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:257
static Datum CStringGetDatum(const char *X)
Definition: postgres.h:355
static Datum Int32GetDatum(int32 X)
Definition: postgres.h:217
unsigned int Oid
Definition: postgres_ext.h:32
char * psprintf(const char *fmt,...)
Definition: psprintf.c:43
#define RelationGetDescr(relation)
Definition: rel.h:538
#define ERRCODE_DUPLICATE_OBJECT
Definition: streamutil.c:30
bool pg_is_ascii(const char *str)
Definition: string.c:132
char * localename
Definition: collationcmds.c:43
char * defname
Definition: parsenodes.h:826
ParseLoc location
Definition: parsenodes.h:830
ItemPointerData t_self
Definition: htup.h:65
Definition: pg_list.h:54
bool superuser(void)
Definition: superuser.c:46
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:269
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:221
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
#define SearchSysCacheExists1(cacheId, key1)
Definition: syscache.h:100
#define SearchSysCacheExists3(cacheId, key1, key2, key3)
Definition: syscache.h:104
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:126
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:40
text * cstring_to_text(const char *s)
Definition: varlena.c:184
const char * name
void _dosmaperr(unsigned long)
Definition: win32error.c:177
void CommandCounterIncrement(void)
Definition: xact.c:1099