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-2022, 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/dependency.h"
21 #include "catalog/indexing.h"
22 #include "catalog/namespace.h"
23 #include "catalog/objectaccess.h"
24 #include "catalog/pg_collation.h"
25 #include "catalog/pg_database.h"
26 #include "catalog/pg_namespace.h"
27 #include "commands/alter.h"
28 #include "commands/collationcmds.h"
29 #include "commands/comment.h"
30 #include "commands/dbcommands.h"
31 #include "commands/defrem.h"
32 #include "common/string.h"
33 #include "mb/pg_wchar.h"
34 #include "miscadmin.h"
35 #include "utils/acl.h"
36 #include "utils/builtins.h"
37 #include "utils/lsyscache.h"
38 #include "utils/pg_locale.h"
39 #include "utils/rel.h"
40 #include "utils/syscache.h"
41 
42 
43 typedef struct
44 {
45  char *localename; /* name of locale, as per "locale -a" */
46  char *alias; /* shortened alias for same */
47  int enc; /* encoding */
49 
50 
51 /*
52  * CREATE COLLATION
53  */
55 DefineCollation(ParseState *pstate, List *names, List *parameters, bool if_not_exists)
56 {
57  char *collName;
58  Oid collNamespace;
59  AclResult aclresult;
60  ListCell *pl;
61  DefElem *fromEl = NULL;
62  DefElem *localeEl = NULL;
63  DefElem *lccollateEl = NULL;
64  DefElem *lcctypeEl = NULL;
65  DefElem *providerEl = NULL;
66  DefElem *deterministicEl = NULL;
67  DefElem *versionEl = NULL;
68  char *collcollate;
69  char *collctype;
70  char *colliculocale;
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)
82  aclcheck_error(aclresult, OBJECT_SCHEMA,
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, "version") == 0)
103  defelp = &versionEl;
104  else
105  {
106  ereport(ERROR,
107  (errcode(ERRCODE_SYNTAX_ERROR),
108  errmsg("collation attribute \"%s\" not recognized",
109  defel->defname),
110  parser_errposition(pstate, defel->location)));
111  break;
112  }
113  if (*defelp != NULL)
114  errorConflictingDefElem(defel, pstate);
115  *defelp = defel;
116  }
117 
118  if (localeEl && (lccollateEl || lcctypeEl))
119  ereport(ERROR,
120  errcode(ERRCODE_SYNTAX_ERROR),
121  errmsg("conflicting or redundant options"),
122  errdetail("LOCALE cannot be specified together with LC_COLLATE or LC_CTYPE."));
123 
124  if (fromEl && list_length(parameters) != 1)
125  ereport(ERROR,
126  errcode(ERRCODE_SYNTAX_ERROR),
127  errmsg("conflicting or redundant options"),
128  errdetail("FROM cannot be specified together with any other options."));
129 
130  if (fromEl)
131  {
132  Oid collid;
133  HeapTuple tp;
134  Datum datum;
135  bool isnull;
136 
137  collid = get_collation_oid(defGetQualifiedName(fromEl), false);
139  if (!HeapTupleIsValid(tp))
140  elog(ERROR, "cache lookup failed for collation %u", collid);
141 
142  collprovider = ((Form_pg_collation) GETSTRUCT(tp))->collprovider;
143  collisdeterministic = ((Form_pg_collation) GETSTRUCT(tp))->collisdeterministic;
144  collencoding = ((Form_pg_collation) GETSTRUCT(tp))->collencoding;
145 
146  datum = SysCacheGetAttr(COLLOID, tp, Anum_pg_collation_collcollate, &isnull);
147  if (!isnull)
148  collcollate = TextDatumGetCString(datum);
149  else
150  collcollate = NULL;
151 
152  datum = SysCacheGetAttr(COLLOID, tp, Anum_pg_collation_collctype, &isnull);
153  if (!isnull)
154  collctype = TextDatumGetCString(datum);
155  else
156  collctype = NULL;
157 
158  datum = SysCacheGetAttr(COLLOID, tp, Anum_pg_collation_colliculocale, &isnull);
159  if (!isnull)
160  colliculocale = TextDatumGetCString(datum);
161  else
162  colliculocale = NULL;
163 
164  ReleaseSysCache(tp);
165 
166  /*
167  * Copying the "default" collation is not allowed because most code
168  * checks for DEFAULT_COLLATION_OID instead of COLLPROVIDER_DEFAULT,
169  * and so having a second collation with COLLPROVIDER_DEFAULT would
170  * not work and potentially confuse or crash some code. This could be
171  * fixed with some legwork.
172  */
173  if (collprovider == COLLPROVIDER_DEFAULT)
174  ereport(ERROR,
175  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
176  errmsg("collation \"default\" cannot be copied")));
177  }
178  else
179  {
180  char *collproviderstr = NULL;
181 
182  collcollate = NULL;
183  collctype = NULL;
184  colliculocale = NULL;
185 
186  if (providerEl)
187  collproviderstr = defGetString(providerEl);
188 
189  if (deterministicEl)
190  collisdeterministic = defGetBoolean(deterministicEl);
191  else
192  collisdeterministic = true;
193 
194  if (versionEl)
195  collversion = defGetString(versionEl);
196 
197  if (collproviderstr)
198  {
199  if (pg_strcasecmp(collproviderstr, "icu") == 0)
200  collprovider = COLLPROVIDER_ICU;
201  else if (pg_strcasecmp(collproviderstr, "libc") == 0)
202  collprovider = COLLPROVIDER_LIBC;
203  else
204  ereport(ERROR,
205  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
206  errmsg("unrecognized collation provider: %s",
207  collproviderstr)));
208  }
209  else
210  collprovider = COLLPROVIDER_LIBC;
211 
212  if (localeEl)
213  {
214  if (collprovider == COLLPROVIDER_LIBC)
215  {
216  collcollate = defGetString(localeEl);
217  collctype = defGetString(localeEl);
218  }
219  else
220  colliculocale = defGetString(localeEl);
221  }
222 
223  if (lccollateEl)
224  collcollate = defGetString(lccollateEl);
225 
226  if (lcctypeEl)
227  collctype = defGetString(lcctypeEl);
228 
229  if (collprovider == COLLPROVIDER_LIBC)
230  {
231  if (!collcollate)
232  ereport(ERROR,
233  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
234  errmsg("parameter \"lc_collate\" must be specified")));
235 
236  if (!collctype)
237  ereport(ERROR,
238  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
239  errmsg("parameter \"lc_ctype\" must be specified")));
240  }
241  else if (collprovider == COLLPROVIDER_ICU)
242  {
243  if (!colliculocale)
244  ereport(ERROR,
245  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
246  errmsg("parameter \"locale\" must be specified")));
247  }
248 
249  /*
250  * Nondeterministic collations are currently only supported with ICU
251  * because that's the only case where it can actually make a
252  * difference. So we can save writing the code for the other
253  * providers.
254  */
255  if (!collisdeterministic && collprovider != COLLPROVIDER_ICU)
256  ereport(ERROR,
257  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
258  errmsg("nondeterministic collations not supported with this provider")));
259 
260  if (collprovider == COLLPROVIDER_ICU)
261  {
262 #ifdef USE_ICU
263  /*
264  * We could create ICU collations with collencoding == database
265  * encoding, but it seems better to use -1 so that it matches the
266  * way initdb would create ICU collations. However, only allow
267  * one to be created when the current database's encoding is
268  * supported. Otherwise the collation is useless, plus we get
269  * surprising behaviors like not being able to drop the collation.
270  *
271  * Skip this test when !USE_ICU, because the error we want to
272  * throw for that isn't thrown till later.
273  */
275  ereport(ERROR,
276  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
277  errmsg("current database's encoding is not supported with this provider")));
278 #endif
279  collencoding = -1;
280  }
281  else
282  {
283  collencoding = GetDatabaseEncoding();
284  check_encoding_locale_matches(collencoding, collcollate, collctype);
285  }
286  }
287 
288  if (!collversion)
289  collversion = get_collation_actual_version(collprovider, collprovider == COLLPROVIDER_ICU ? colliculocale : collcollate);
290 
291  newoid = CollationCreate(collName,
292  collNamespace,
293  GetUserId(),
294  collprovider,
295  collisdeterministic,
296  collencoding,
297  collcollate,
298  collctype,
299  colliculocale,
300  collversion,
301  if_not_exists,
302  false); /* not quiet */
303 
304  if (!OidIsValid(newoid))
305  return InvalidObjectAddress;
306 
307  /*
308  * Check that the locales can be loaded. NB: pg_newlocale_from_collation
309  * is only supposed to be called on non-C-equivalent locales.
310  */
312  if (!lc_collate_is_c(newoid) || !lc_ctype_is_c(newoid))
313  (void) pg_newlocale_from_collation(newoid);
314 
315  ObjectAddressSet(address, CollationRelationId, newoid);
316 
317  return address;
318 }
319 
320 /*
321  * Subroutine for ALTER COLLATION SET SCHEMA and RENAME
322  *
323  * Is there a collation with the same name of the given collation already in
324  * the given namespace? If so, raise an appropriate error message.
325  */
326 void
327 IsThereCollationInNamespace(const char *collname, Oid nspOid)
328 {
329  /* make sure the name doesn't already exist in new schema */
331  CStringGetDatum(collname),
333  ObjectIdGetDatum(nspOid)))
334  ereport(ERROR,
336  errmsg("collation \"%s\" for encoding \"%s\" already exists in schema \"%s\"",
337  collname, GetDatabaseEncodingName(),
338  get_namespace_name(nspOid))));
339 
340  /* mustn't match an any-encoding entry, either */
342  CStringGetDatum(collname),
343  Int32GetDatum(-1),
344  ObjectIdGetDatum(nspOid)))
345  ereport(ERROR,
347  errmsg("collation \"%s\" already exists in schema \"%s\"",
348  collname, get_namespace_name(nspOid))));
349 }
350 
351 /*
352  * ALTER COLLATION
353  */
356 {
357  Relation rel;
358  Oid collOid;
359  HeapTuple tup;
360  Form_pg_collation collForm;
361  Datum datum;
362  bool isnull;
363  char *oldversion;
364  char *newversion;
365  ObjectAddress address;
366 
367  rel = table_open(CollationRelationId, RowExclusiveLock);
368  collOid = get_collation_oid(stmt->collname, false);
369 
370  if (collOid == DEFAULT_COLLATION_OID)
371  ereport(ERROR,
372  (errmsg("cannot refresh version of default collation"),
373  errhint("Use ALTER DATABASE ... REFRESH COLLATION VERSION instead.")));
374 
375  if (!object_ownercheck(CollationRelationId, collOid, GetUserId()))
377  NameListToString(stmt->collname));
378 
380  if (!HeapTupleIsValid(tup))
381  elog(ERROR, "cache lookup failed for collation %u", collOid);
382 
383  collForm = (Form_pg_collation) GETSTRUCT(tup);
384  datum = SysCacheGetAttr(COLLOID, tup, Anum_pg_collation_collversion, &isnull);
385  oldversion = isnull ? NULL : TextDatumGetCString(datum);
386 
387  datum = SysCacheGetAttr(COLLOID, tup, collForm->collprovider == COLLPROVIDER_ICU ? Anum_pg_collation_colliculocale : Anum_pg_collation_collcollate, &isnull);
388  if (isnull)
389  elog(ERROR, "unexpected null in pg_collation");
390  newversion = get_collation_actual_version(collForm->collprovider, TextDatumGetCString(datum));
391 
392  /* cannot change from NULL to non-NULL or vice versa */
393  if ((!oldversion && newversion) || (oldversion && !newversion))
394  elog(ERROR, "invalid collation version change");
395  else if (oldversion && newversion && strcmp(newversion, oldversion) != 0)
396  {
397  bool nulls[Natts_pg_collation];
398  bool replaces[Natts_pg_collation];
399  Datum values[Natts_pg_collation];
400 
401  ereport(NOTICE,
402  (errmsg("changing version from %s to %s",
403  oldversion, newversion)));
404 
405  memset(values, 0, sizeof(values));
406  memset(nulls, false, sizeof(nulls));
407  memset(replaces, false, sizeof(replaces));
408 
409  values[Anum_pg_collation_collversion - 1] = CStringGetTextDatum(newversion);
410  replaces[Anum_pg_collation_collversion - 1] = true;
411 
412  tup = heap_modify_tuple(tup, RelationGetDescr(rel),
413  values, nulls, replaces);
414  }
415  else
416  ereport(NOTICE,
417  (errmsg("version has not changed")));
418 
419  CatalogTupleUpdate(rel, &tup->t_self, tup);
420 
421  InvokeObjectPostAlterHook(CollationRelationId, collOid, 0);
422 
423  ObjectAddressSet(address, CollationRelationId, collOid);
424 
425  heap_freetuple(tup);
426  table_close(rel, NoLock);
427 
428  return address;
429 }
430 
431 
432 Datum
434 {
435  Oid collid = PG_GETARG_OID(0);
436  char provider;
437  char *locale;
438  char *version;
439  Datum datum;
440  bool isnull;
441 
442  if (collid == DEFAULT_COLLATION_OID)
443  {
444  /* retrieve from pg_database */
445 
447  if (!HeapTupleIsValid(dbtup))
448  ereport(ERROR,
449  (errcode(ERRCODE_UNDEFINED_OBJECT),
450  errmsg("database with OID %u does not exist", MyDatabaseId)));
451 
453 
454  datum = SysCacheGetAttr(DATABASEOID, dbtup,
455  provider == COLLPROVIDER_ICU ?
456  Anum_pg_database_daticulocale : Anum_pg_database_datcollate,
457  &isnull);
458  if (isnull)
459  elog(ERROR, "unexpected null in pg_database");
460 
461  locale = TextDatumGetCString(datum);
462 
463  ReleaseSysCache(dbtup);
464  }
465  else
466  {
467  /* retrieve from pg_collation */
468 
470  if (!HeapTupleIsValid(colltp))
471  ereport(ERROR,
472  (errcode(ERRCODE_UNDEFINED_OBJECT),
473  errmsg("collation with OID %u does not exist", collid)));
474 
475  provider = ((Form_pg_collation) GETSTRUCT(colltp))->collprovider;
476  Assert(provider != COLLPROVIDER_DEFAULT);
477  datum = SysCacheGetAttr(COLLOID, colltp,
478  provider == COLLPROVIDER_ICU ?
479  Anum_pg_collation_colliculocale : Anum_pg_collation_collcollate,
480  &isnull);
481  if (isnull)
482  elog(ERROR, "unexpected null in pg_collation");
483 
484  locale = TextDatumGetCString(datum);
485 
486  ReleaseSysCache(colltp);
487  }
488 
490  if (version)
492  else
493  PG_RETURN_NULL();
494 }
495 
496 
497 /* will we use "locale -a" in pg_import_system_collations? */
498 #if defined(HAVE_LOCALE_T) && !defined(WIN32)
499 #define READ_LOCALE_A_OUTPUT
500 #endif
501 
502 #ifdef READ_LOCALE_A_OUTPUT
503 /*
504  * "Normalize" a libc locale name, stripping off encoding tags such as
505  * ".utf8" (e.g., "en_US.utf8" -> "en_US", but "br_FR.iso885915@euro"
506  * -> "br_FR@euro"). Return true if a new, different name was
507  * generated.
508  */
509 static bool
510 normalize_libc_locale_name(char *new, const char *old)
511 {
512  char *n = new;
513  const char *o = old;
514  bool changed = false;
515 
516  while (*o)
517  {
518  if (*o == '.')
519  {
520  /* skip over encoding tag such as ".utf8" or ".UTF-8" */
521  o++;
522  while ((*o >= 'A' && *o <= 'Z')
523  || (*o >= 'a' && *o <= 'z')
524  || (*o >= '0' && *o <= '9')
525  || (*o == '-'))
526  o++;
527  changed = true;
528  }
529  else
530  *n++ = *o++;
531  }
532  *n = '\0';
533 
534  return changed;
535 }
536 
537 /*
538  * qsort comparator for CollAliasData items
539  */
540 static int
541 cmpaliases(const void *a, const void *b)
542 {
543  const CollAliasData *ca = (const CollAliasData *) a;
544  const CollAliasData *cb = (const CollAliasData *) b;
545 
546  /* comparing localename is enough because other fields are derived */
547  return strcmp(ca->localename, cb->localename);
548 }
549 #endif /* READ_LOCALE_A_OUTPUT */
550 
551 
552 #ifdef USE_ICU
553 /*
554  * Get the ICU language tag for a locale name.
555  * The result is a palloc'd string.
556  */
557 static char *
558 get_icu_language_tag(const char *localename)
559 {
560  char buf[ULOC_FULLNAME_CAPACITY];
561  UErrorCode status;
562 
563  status = U_ZERO_ERROR;
564  uloc_toLanguageTag(localename, buf, sizeof(buf), true, &status);
565  if (U_FAILURE(status))
566  ereport(ERROR,
567  (errmsg("could not convert locale name \"%s\" to language tag: %s",
568  localename, u_errorName(status))));
569 
570  return pstrdup(buf);
571 }
572 
573 /*
574  * Get a comment (specifically, the display name) for an ICU locale.
575  * The result is a palloc'd string, or NULL if we can't get a comment
576  * or find that it's not all ASCII. (We can *not* accept non-ASCII
577  * comments, because the contents of template0 must be encoding-agnostic.)
578  */
579 static char *
580 get_icu_locale_comment(const char *localename)
581 {
582  UErrorCode status;
583  UChar displayname[128];
584  int32 len_uchar;
585  int32 i;
586  char *result;
587 
588  status = U_ZERO_ERROR;
589  len_uchar = uloc_getDisplayName(localename, "en",
590  displayname, lengthof(displayname),
591  &status);
592  if (U_FAILURE(status))
593  return NULL; /* no good reason to raise an error */
594 
595  /* Check for non-ASCII comment (can't use pg_is_ascii for this) */
596  for (i = 0; i < len_uchar; i++)
597  {
598  if (displayname[i] > 127)
599  return NULL;
600  }
601 
602  /* OK, transcribe */
603  result = palloc(len_uchar + 1);
604  for (i = 0; i < len_uchar; i++)
605  result[i] = displayname[i];
606  result[len_uchar] = '\0';
607 
608  return result;
609 }
610 #endif /* USE_ICU */
611 
612 
613 /*
614  * pg_import_system_collations: add known system collations to pg_collation
615  */
616 Datum
618 {
619  Oid nspid = PG_GETARG_OID(0);
620  int ncreated = 0;
621 
622  if (!superuser())
623  ereport(ERROR,
624  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
625  errmsg("must be superuser to import system collations")));
626 
628  ereport(ERROR,
629  (errcode(ERRCODE_UNDEFINED_SCHEMA),
630  errmsg("schema with OID %u does not exist", nspid)));
631 
632  /* Load collations known to libc, using "locale -a" to enumerate them */
633 #ifdef READ_LOCALE_A_OUTPUT
634  {
635  FILE *locale_a_handle;
636  char localebuf[LOCALE_NAME_BUFLEN];
637  int nvalid = 0;
638  Oid collid;
639  CollAliasData *aliases;
640  int naliases,
641  maxaliases,
642  i;
643 
644  /* expansible array of aliases */
645  maxaliases = 100;
646  aliases = (CollAliasData *) palloc(maxaliases * sizeof(CollAliasData));
647  naliases = 0;
648 
649  locale_a_handle = OpenPipeStream("locale -a", "r");
650  if (locale_a_handle == NULL)
651  ereport(ERROR,
653  errmsg("could not execute command \"%s\": %m",
654  "locale -a")));
655 
656  while (fgets(localebuf, sizeof(localebuf), locale_a_handle))
657  {
658  size_t len;
659  int enc;
660  char alias[LOCALE_NAME_BUFLEN];
661 
662  len = strlen(localebuf);
663 
664  if (len == 0 || localebuf[len - 1] != '\n')
665  {
666  elog(DEBUG1, "skipping locale with too-long name: \"%s\"", localebuf);
667  continue;
668  }
669  localebuf[len - 1] = '\0';
670 
671  /*
672  * Some systems have locale names that don't consist entirely of
673  * ASCII letters (such as "bokm&aring;l" or "fran&ccedil;ais").
674  * This is pretty silly, since we need the locale itself to
675  * interpret the non-ASCII characters. We can't do much with
676  * those, so we filter them out.
677  */
678  if (!pg_is_ascii(localebuf))
679  {
680  elog(DEBUG1, "skipping locale with non-ASCII name: \"%s\"", localebuf);
681  continue;
682  }
683 
684  enc = pg_get_encoding_from_locale(localebuf, false);
685  if (enc < 0)
686  {
687  elog(DEBUG1, "skipping locale with unrecognized encoding: \"%s\"",
688  localebuf);
689  continue;
690  }
692  {
693  elog(DEBUG1, "skipping locale with client-only encoding: \"%s\"", localebuf);
694  continue;
695  }
696  if (enc == PG_SQL_ASCII)
697  continue; /* C/POSIX are already in the catalog */
698 
699  /* count valid locales found in operating system */
700  nvalid++;
701 
702  /*
703  * Create a collation named the same as the locale, but quietly
704  * doing nothing if it already exists. This is the behavior we
705  * need even at initdb time, because some versions of "locale -a"
706  * can report the same locale name more than once. And it's
707  * convenient for later import runs, too, since you just about
708  * always want to add on new locales without a lot of chatter
709  * about existing ones.
710  */
711  collid = CollationCreate(localebuf, nspid, GetUserId(),
712  COLLPROVIDER_LIBC, true, enc,
713  localebuf, localebuf, NULL,
714  get_collation_actual_version(COLLPROVIDER_LIBC, localebuf),
715  true, true);
716  if (OidIsValid(collid))
717  {
718  ncreated++;
719 
720  /* Must do CCI between inserts to handle duplicates correctly */
722  }
723 
724  /*
725  * Generate aliases such as "en_US" in addition to "en_US.utf8"
726  * for ease of use. Note that collation names are unique per
727  * encoding only, so this doesn't clash with "en_US" for LATIN1,
728  * say.
729  *
730  * However, it might conflict with a name we'll see later in the
731  * "locale -a" output. So save up the aliases and try to add them
732  * after we've read all the output.
733  */
734  if (normalize_libc_locale_name(alias, localebuf))
735  {
736  if (naliases >= maxaliases)
737  {
738  maxaliases *= 2;
739  aliases = (CollAliasData *)
740  repalloc(aliases, maxaliases * sizeof(CollAliasData));
741  }
742  aliases[naliases].localename = pstrdup(localebuf);
743  aliases[naliases].alias = pstrdup(alias);
744  aliases[naliases].enc = enc;
745  naliases++;
746  }
747  }
748 
749  /*
750  * We don't check the return value of this, because we want to support
751  * the case where there "locale" command does not exist. (This is
752  * unusual but can happen on minimalized Linux distributions, for
753  * example.) We will warn below if no locales could be found.
754  */
755  ClosePipeStream(locale_a_handle);
756 
757  /*
758  * Before processing the aliases, sort them by locale name. The point
759  * here is that if "locale -a" gives us multiple locale names with the
760  * same encoding and base name, say "en_US.utf8" and "en_US.utf-8", we
761  * want to pick a deterministic one of them. First in ASCII sort
762  * order is a good enough rule. (Before PG 10, the code corresponding
763  * to this logic in initdb.c had an additional ordering rule, to
764  * prefer the locale name exactly matching the alias, if any. We
765  * don't need to consider that here, because we would have already
766  * created such a pg_collation entry above, and that one will win.)
767  */
768  if (naliases > 1)
769  qsort((void *) aliases, naliases, sizeof(CollAliasData), cmpaliases);
770 
771  /* Now add aliases, ignoring any that match pre-existing entries */
772  for (i = 0; i < naliases; i++)
773  {
774  char *locale = aliases[i].localename;
775  char *alias = aliases[i].alias;
776  int enc = aliases[i].enc;
777 
778  collid = CollationCreate(alias, nspid, GetUserId(),
779  COLLPROVIDER_LIBC, true, enc,
780  locale, locale, NULL,
781  get_collation_actual_version(COLLPROVIDER_LIBC, locale),
782  true, true);
783  if (OidIsValid(collid))
784  {
785  ncreated++;
786 
788  }
789  }
790 
791  /* Give a warning if "locale -a" seems to be malfunctioning */
792  if (nvalid == 0)
794  (errmsg("no usable system locales were found")));
795  }
796 #endif /* READ_LOCALE_A_OUTPUT */
797 
798  /*
799  * Load collations known to ICU
800  *
801  * We use uloc_countAvailable()/uloc_getAvailable() rather than
802  * ucol_countAvailable()/ucol_getAvailable(). The former returns a full
803  * set of language+region combinations, whereas the latter only returns
804  * language+region combinations if they are distinct from the language's
805  * base collation. So there might not be a de-DE or en-GB, which would be
806  * confusing.
807  */
808 #ifdef USE_ICU
809  {
810  int i;
811 
812  /*
813  * Start the loop at -1 to sneak in the root locale without too much
814  * code duplication.
815  */
816  for (i = -1; i < uloc_countAvailable(); i++)
817  {
818  const char *name;
819  char *langtag;
820  char *icucomment;
821  const char *iculocstr;
822  Oid collid;
823 
824  if (i == -1)
825  name = ""; /* ICU root locale */
826  else
827  name = uloc_getAvailable(i);
828 
829  langtag = get_icu_language_tag(name);
830  iculocstr = U_ICU_VERSION_MAJOR_NUM >= 54 ? langtag : name;
831 
832  /*
833  * Be paranoid about not allowing any non-ASCII strings into
834  * pg_collation
835  */
836  if (!pg_is_ascii(langtag) || !pg_is_ascii(iculocstr))
837  continue;
838 
839  collid = CollationCreate(psprintf("%s-x-icu", langtag),
840  nspid, GetUserId(),
841  COLLPROVIDER_ICU, true, -1,
842  NULL, NULL, iculocstr,
843  get_collation_actual_version(COLLPROVIDER_ICU, iculocstr),
844  true, true);
845  if (OidIsValid(collid))
846  {
847  ncreated++;
848 
850 
851  icucomment = get_icu_locale_comment(name);
852  if (icucomment)
853  CreateComments(collid, CollationRelationId, 0,
854  icucomment);
855  }
856  }
857  }
858 #endif /* USE_ICU */
859 
860  PG_RETURN_INT32(ncreated);
861 }
AclResult
Definition: acl.h:183
@ ACLCHECK_OK
Definition: acl.h:184
@ ACLCHECK_NOT_OWNER
Definition: acl.h:186
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:3485
AclResult object_aclcheck(Oid classid, Oid objectid, Oid roleid, AclMode mode)
Definition: aclchk.c:4598
bool object_ownercheck(Oid classid, Oid objectid, Oid roleid)
Definition: aclchk.c:4799
static Datum values[MAXATTR]
Definition: bootstrap.c:156
#define CStringGetTextDatum(s)
Definition: builtins.h:88
#define TextDatumGetCString(d)
Definition: builtins.h:89
signed int int32
Definition: c.h:430
#define lengthof(array)
Definition: c.h:724
#define OidIsValid(objectId)
Definition: c.h:711
Datum pg_collation_actual_version(PG_FUNCTION_ARGS)
ObjectAddress AlterCollation(AlterCollationStmt *stmt)
void IsThereCollationInNamespace(const char *collname, Oid nspOid)
Datum pg_import_system_collations(PG_FUNCTION_ARGS)
ObjectAddress DefineCollation(ParseState *pstate, List *names, List *parameters, bool if_not_exists)
Definition: collationcmds.c:55
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:1431
bool defGetBoolean(DefElem *def)
Definition: define.c:108
List * defGetQualifiedName(DefElem *def)
Definition: define.c:253
char * defGetString(DefElem *def)
Definition: define.c:49
void errorConflictingDefElem(DefElem *defel, ParseState *pstate)
Definition: define.c:385
int errcode_for_file_access(void)
Definition: elog.c:881
int errdetail(const char *fmt,...)
Definition: elog.c:1202
int errhint(const char *fmt,...)
Definition: elog.c:1316
int errcode(int sqlerrcode)
Definition: elog.c:858
int errmsg(const char *fmt,...)
Definition: elog.c:1069
#define WARNING
Definition: elog.h:36
#define DEBUG1
Definition: elog.h:30
#define ERROR
Definition: elog.h:39
#define NOTICE
Definition: elog.h:35
#define ereport(elevel,...)
Definition: elog.h:149
bool is_encoding_supported_by_icu(int encoding)
Definition: encnames.c:459
const char * name
Definition: encode.c:561
struct pg_encoding enc
Definition: encode.c:562
int ClosePipeStream(FILE *file)
Definition: fd.c:2791
FILE * OpenPipeStream(const char *command, const char *mode)
Definition: fd.c:2486
#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
Oid MyDatabaseId
Definition: globals.c:89
HeapTuple heap_modify_tuple(HeapTuple tuple, TupleDesc tupleDesc, Datum *replValues, bool *replIsnull, bool *doReplace)
Definition: heaptuple.c:1113
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1338
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define GETSTRUCT(TUP)
Definition: htup_details.h:649
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:301
static char * locale
Definition: initdb.c:129
int b
Definition: isn.c:70
int a
Definition: isn.c:69
int i
Definition: isn.c:73
static JitProviderCallbacks provider
Definition: jit.c:43
Assert(fmt[strlen(fmt) - 1] !='\n')
#define NoLock
Definition: lockdefs.h:34
#define RowExclusiveLock
Definition: lockdefs.h:38
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3331
int GetDatabaseEncoding(void)
Definition: mbutils.c:1210
const char * GetDatabaseEncodingName(void)
Definition: mbutils.c:1216
char * pstrdup(const char *in)
Definition: mcxt.c:1483
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:1321
void * palloc(Size size)
Definition: mcxt.c:1199
Oid GetUserId(void)
Definition: miscinit.c:497
Oid QualifiedNameGetCreationNamespace(List *names, char **objname_p)
Definition: namespace.c:3038
Oid get_collation_oid(List *collname, bool missing_ok)
Definition: namespace.c:3644
char * NameListToString(List *names)
Definition: namespace.c:3145
#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:110
@ OBJECT_COLLATION
Definition: parsenodes.h:1895
@ OBJECT_SCHEMA
Definition: parsenodes.h:1924
#define ACL_CREATE
Definition: parsenodes.h:92
Oid CollationCreate(const char *collname, Oid collnamespace, Oid collowner, char collprovider, bool collisdeterministic, int32 collencoding, const char *collcollate, const char *collctype, const char *colliculocale, const char *collversion, bool if_not_exists, bool quiet)
Definition: pg_collation.c:46
FormData_pg_collation * Form_pg_collation
Definition: pg_collation.h:57
const void size_t len
char datlocprovider
Definition: pg_database.h:44
FormData_pg_database * Form_pg_database
Definition: pg_database.h:87
#define lfirst_node(type, lc)
Definition: pg_list.h:174
static int list_length(const List *l)
Definition: pg_list.h:150
bool lc_collate_is_c(Oid collation)
Definition: pg_locale.c:1299
pg_locale_t pg_newlocale_from_collation(Oid collid)
Definition: pg_locale.c:1481
bool lc_ctype_is_c(Oid collation)
Definition: pg_locale.c:1352
char * get_collation_actual_version(char collprovider, const char *collcollate)
Definition: pg_locale.c:1647
#define LOCALE_NAME_BUFLEN
Definition: pg_locale.h:36
static void static void status(const char *fmt,...) pg_attribute_printf(1
Definition: pg_regress.c:225
static char * buf
Definition: pg_test_fsync.c:67
@ 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:428
#define qsort(a, b, c, d)
Definition: port.h:445
uintptr_t Datum
Definition: postgres.h:412
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:600
static Datum CStringGetDatum(const char *X)
Definition: postgres.h:698
static Datum Int32GetDatum(int32 X)
Definition: postgres.h:560
unsigned int Oid
Definition: postgres_ext.h:31
char * psprintf(const char *fmt,...)
Definition: psprintf.c:46
#define RelationGetDescr(relation)
Definition: rel.h:527
#define ERRCODE_DUPLICATE_OBJECT
Definition: streamutil.c:32
bool pg_is_ascii(const char *str)
Definition: string.c:133
char * localename
Definition: collationcmds.c:45
char * defname
Definition: parsenodes.h:779
int location
Definition: parsenodes.h:783
ItemPointerData t_self
Definition: htup.h:65
Definition: pg_list.h:52
bool superuser(void)
Definition: superuser.c:46
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1221
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1173
Datum SysCacheGetAttr(int cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition: syscache.c:1434
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:179
@ COLLOID
Definition: syscache.h:50
@ COLLNAMEENCNSP
Definition: syscache.h:49
@ DATABASEOID
Definition: syscache.h:55
@ NAMESPACEOID
Definition: syscache.h:70
#define SearchSysCacheExists1(cacheId, key1)
Definition: syscache.h:188
#define SearchSysCacheExists3(cacheId, key1, key2, key3)
Definition: syscache.h:192
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:189
void CommandCounterIncrement(void)
Definition: xact.c:1077