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-2024, 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 *rulesEl = NULL;
68  DefElem *versionEl = NULL;
69  char *collcollate;
70  char *collctype;
71  char *colliculocale;
72  char *collicurules;
73  bool collisdeterministic;
74  int collencoding;
75  char collprovider;
76  char *collversion = NULL;
77  Oid newoid;
78  ObjectAddress address;
79 
80  collNamespace = QualifiedNameGetCreationNamespace(names, &collName);
81 
82  aclresult = object_aclcheck(NamespaceRelationId, collNamespace, GetUserId(), ACL_CREATE);
83  if (aclresult != ACLCHECK_OK)
84  aclcheck_error(aclresult, OBJECT_SCHEMA,
85  get_namespace_name(collNamespace));
86 
87  foreach(pl, parameters)
88  {
89  DefElem *defel = lfirst_node(DefElem, pl);
90  DefElem **defelp;
91 
92  if (strcmp(defel->defname, "from") == 0)
93  defelp = &fromEl;
94  else if (strcmp(defel->defname, "locale") == 0)
95  defelp = &localeEl;
96  else if (strcmp(defel->defname, "lc_collate") == 0)
97  defelp = &lccollateEl;
98  else if (strcmp(defel->defname, "lc_ctype") == 0)
99  defelp = &lcctypeEl;
100  else if (strcmp(defel->defname, "provider") == 0)
101  defelp = &providerEl;
102  else if (strcmp(defel->defname, "deterministic") == 0)
103  defelp = &deterministicEl;
104  else if (strcmp(defel->defname, "rules") == 0)
105  defelp = &rulesEl;
106  else if (strcmp(defel->defname, "version") == 0)
107  defelp = &versionEl;
108  else
109  {
110  ereport(ERROR,
111  (errcode(ERRCODE_SYNTAX_ERROR),
112  errmsg("collation attribute \"%s\" not recognized",
113  defel->defname),
114  parser_errposition(pstate, defel->location)));
115  break;
116  }
117  if (*defelp != NULL)
118  errorConflictingDefElem(defel, pstate);
119  *defelp = defel;
120  }
121 
122  if (localeEl && (lccollateEl || lcctypeEl))
123  ereport(ERROR,
124  errcode(ERRCODE_SYNTAX_ERROR),
125  errmsg("conflicting or redundant options"),
126  errdetail("LOCALE cannot be specified together with LC_COLLATE or LC_CTYPE."));
127 
128  if (fromEl && list_length(parameters) != 1)
129  ereport(ERROR,
130  errcode(ERRCODE_SYNTAX_ERROR),
131  errmsg("conflicting or redundant options"),
132  errdetail("FROM cannot be specified together with any other options."));
133 
134  if (fromEl)
135  {
136  Oid collid;
137  HeapTuple tp;
138  Datum datum;
139  bool isnull;
140 
141  collid = get_collation_oid(defGetQualifiedName(fromEl), false);
142  tp = SearchSysCache1(COLLOID, ObjectIdGetDatum(collid));
143  if (!HeapTupleIsValid(tp))
144  elog(ERROR, "cache lookup failed for collation %u", collid);
145 
146  collprovider = ((Form_pg_collation) GETSTRUCT(tp))->collprovider;
147  collisdeterministic = ((Form_pg_collation) GETSTRUCT(tp))->collisdeterministic;
148  collencoding = ((Form_pg_collation) GETSTRUCT(tp))->collencoding;
149 
150  datum = SysCacheGetAttr(COLLOID, tp, Anum_pg_collation_collcollate, &isnull);
151  if (!isnull)
152  collcollate = TextDatumGetCString(datum);
153  else
154  collcollate = NULL;
155 
156  datum = SysCacheGetAttr(COLLOID, tp, Anum_pg_collation_collctype, &isnull);
157  if (!isnull)
158  collctype = TextDatumGetCString(datum);
159  else
160  collctype = NULL;
161 
162  datum = SysCacheGetAttr(COLLOID, tp, Anum_pg_collation_colliculocale, &isnull);
163  if (!isnull)
164  colliculocale = TextDatumGetCString(datum);
165  else
166  colliculocale = NULL;
167 
168  /*
169  * When the ICU locale comes from an existing collation, do not
170  * canonicalize to a language tag.
171  */
172 
173  datum = SysCacheGetAttr(COLLOID, tp, Anum_pg_collation_collicurules, &isnull);
174  if (!isnull)
175  collicurules = TextDatumGetCString(datum);
176  else
177  collicurules = NULL;
178 
179  ReleaseSysCache(tp);
180 
181  /*
182  * Copying the "default" collation is not allowed because most code
183  * checks for DEFAULT_COLLATION_OID instead of COLLPROVIDER_DEFAULT,
184  * and so having a second collation with COLLPROVIDER_DEFAULT would
185  * not work and potentially confuse or crash some code. This could be
186  * fixed with some legwork.
187  */
188  if (collprovider == COLLPROVIDER_DEFAULT)
189  ereport(ERROR,
190  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
191  errmsg("collation \"default\" cannot be copied")));
192  }
193  else
194  {
195  char *collproviderstr = NULL;
196 
197  collcollate = NULL;
198  collctype = NULL;
199  colliculocale = NULL;
200  collicurules = NULL;
201 
202  if (providerEl)
203  collproviderstr = defGetString(providerEl);
204 
205  if (deterministicEl)
206  collisdeterministic = defGetBoolean(deterministicEl);
207  else
208  collisdeterministic = true;
209 
210  if (rulesEl)
211  collicurules = defGetString(rulesEl);
212 
213  if (versionEl)
214  collversion = defGetString(versionEl);
215 
216  if (collproviderstr)
217  {
218  if (pg_strcasecmp(collproviderstr, "icu") == 0)
219  collprovider = COLLPROVIDER_ICU;
220  else if (pg_strcasecmp(collproviderstr, "libc") == 0)
221  collprovider = COLLPROVIDER_LIBC;
222  else
223  ereport(ERROR,
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  colliculocale = defGetString(localeEl);
240  }
241 
242  if (lccollateEl)
243  collcollate = defGetString(lccollateEl);
244 
245  if (lcctypeEl)
246  collctype = defGetString(lcctypeEl);
247 
248  if (collprovider == COLLPROVIDER_LIBC)
249  {
250  if (!collcollate)
251  ereport(ERROR,
252  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
253  errmsg("parameter \"%s\" must be specified",
254  "lc_collate")));
255 
256  if (!collctype)
257  ereport(ERROR,
258  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
259  errmsg("parameter \"%s\" must be specified",
260  "lc_ctype")));
261  }
262  else if (collprovider == COLLPROVIDER_ICU)
263  {
264  if (!colliculocale)
265  ereport(ERROR,
266  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
267  errmsg("parameter \"%s\" must be specified",
268  "locale")));
269 
270  /*
271  * During binary upgrade, preserve the locale string. Otherwise,
272  * canonicalize to a language tag.
273  */
274  if (!IsBinaryUpgrade)
275  {
276  char *langtag = icu_language_tag(colliculocale,
278 
279  if (langtag && strcmp(colliculocale, langtag) != 0)
280  {
281  ereport(NOTICE,
282  (errmsg("using standard form \"%s\" for ICU locale \"%s\"",
283  langtag, colliculocale)));
284 
285  colliculocale = langtag;
286  }
287  }
288 
289  icu_validate_locale(colliculocale);
290  }
291 
292  /*
293  * Nondeterministic collations are currently only supported with ICU
294  * because that's the only case where it can actually make a
295  * difference. So we can save writing the code for the other
296  * providers.
297  */
298  if (!collisdeterministic && collprovider != COLLPROVIDER_ICU)
299  ereport(ERROR,
300  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
301  errmsg("nondeterministic collations not supported with this provider")));
302 
303  if (collicurules && collprovider != COLLPROVIDER_ICU)
304  ereport(ERROR,
305  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
306  errmsg("ICU rules cannot be specified unless locale provider is ICU")));
307 
308  if (collprovider == COLLPROVIDER_ICU)
309  {
310 #ifdef USE_ICU
311  /*
312  * We could create ICU collations with collencoding == database
313  * encoding, but it seems better to use -1 so that it matches the
314  * way initdb would create ICU collations. However, only allow
315  * one to be created when the current database's encoding is
316  * supported. Otherwise the collation is useless, plus we get
317  * surprising behaviors like not being able to drop the collation.
318  *
319  * Skip this test when !USE_ICU, because the error we want to
320  * throw for that isn't thrown till later.
321  */
323  ereport(ERROR,
324  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
325  errmsg("current database's encoding is not supported with this provider")));
326 #endif
327  collencoding = -1;
328  }
329  else
330  {
331  collencoding = GetDatabaseEncoding();
332  check_encoding_locale_matches(collencoding, collcollate, collctype);
333  }
334  }
335 
336  if (!collversion)
337  collversion = get_collation_actual_version(collprovider, collprovider == COLLPROVIDER_ICU ? colliculocale : collcollate);
338 
339  newoid = CollationCreate(collName,
340  collNamespace,
341  GetUserId(),
342  collprovider,
343  collisdeterministic,
344  collencoding,
345  collcollate,
346  collctype,
347  colliculocale,
348  collicurules,
349  collversion,
350  if_not_exists,
351  false); /* not quiet */
352 
353  if (!OidIsValid(newoid))
354  return InvalidObjectAddress;
355 
356  /*
357  * Check that the locales can be loaded. NB: pg_newlocale_from_collation
358  * is only supposed to be called on non-C-equivalent locales.
359  */
361  if (!lc_collate_is_c(newoid) || !lc_ctype_is_c(newoid))
362  (void) pg_newlocale_from_collation(newoid);
363 
364  ObjectAddressSet(address, CollationRelationId, newoid);
365 
366  return address;
367 }
368 
369 /*
370  * Subroutine for ALTER COLLATION SET SCHEMA and RENAME
371  *
372  * Is there a collation with the same name of the given collation already in
373  * the given namespace? If so, raise an appropriate error message.
374  */
375 void
376 IsThereCollationInNamespace(const char *collname, Oid nspOid)
377 {
378  /* make sure the name doesn't already exist in new schema */
379  if (SearchSysCacheExists3(COLLNAMEENCNSP,
380  CStringGetDatum(collname),
382  ObjectIdGetDatum(nspOid)))
383  ereport(ERROR,
385  errmsg("collation \"%s\" for encoding \"%s\" already exists in schema \"%s\"",
386  collname, GetDatabaseEncodingName(),
387  get_namespace_name(nspOid))));
388 
389  /* mustn't match an any-encoding entry, either */
390  if (SearchSysCacheExists3(COLLNAMEENCNSP,
391  CStringGetDatum(collname),
392  Int32GetDatum(-1),
393  ObjectIdGetDatum(nspOid)))
394  ereport(ERROR,
396  errmsg("collation \"%s\" already exists in schema \"%s\"",
397  collname, get_namespace_name(nspOid))));
398 }
399 
400 /*
401  * ALTER COLLATION
402  */
405 {
406  Relation rel;
407  Oid collOid;
408  HeapTuple tup;
409  Form_pg_collation collForm;
410  Datum datum;
411  bool isnull;
412  char *oldversion;
413  char *newversion;
414  ObjectAddress address;
415 
416  rel = table_open(CollationRelationId, RowExclusiveLock);
417  collOid = get_collation_oid(stmt->collname, false);
418 
419  if (collOid == DEFAULT_COLLATION_OID)
420  ereport(ERROR,
421  (errmsg("cannot refresh version of default collation"),
422  /* translator: %s is an SQL command */
423  errhint("Use %s instead.",
424  "ALTER DATABASE ... REFRESH COLLATION VERSION")));
425 
426  if (!object_ownercheck(CollationRelationId, collOid, GetUserId()))
428  NameListToString(stmt->collname));
429 
430  tup = SearchSysCacheCopy1(COLLOID, ObjectIdGetDatum(collOid));
431  if (!HeapTupleIsValid(tup))
432  elog(ERROR, "cache lookup failed for collation %u", collOid);
433 
434  collForm = (Form_pg_collation) GETSTRUCT(tup);
435  datum = SysCacheGetAttr(COLLOID, tup, Anum_pg_collation_collversion, &isnull);
436  oldversion = isnull ? NULL : TextDatumGetCString(datum);
437 
438  datum = SysCacheGetAttrNotNull(COLLOID, tup, collForm->collprovider == COLLPROVIDER_ICU ? Anum_pg_collation_colliculocale : Anum_pg_collation_collcollate);
439  newversion = get_collation_actual_version(collForm->collprovider, TextDatumGetCString(datum));
440 
441  /* cannot change from NULL to non-NULL or vice versa */
442  if ((!oldversion && newversion) || (oldversion && !newversion))
443  elog(ERROR, "invalid collation version change");
444  else if (oldversion && newversion && strcmp(newversion, oldversion) != 0)
445  {
446  bool nulls[Natts_pg_collation];
447  bool replaces[Natts_pg_collation];
448  Datum values[Natts_pg_collation];
449 
450  ereport(NOTICE,
451  (errmsg("changing version from %s to %s",
452  oldversion, newversion)));
453 
454  memset(values, 0, sizeof(values));
455  memset(nulls, false, sizeof(nulls));
456  memset(replaces, false, sizeof(replaces));
457 
458  values[Anum_pg_collation_collversion - 1] = CStringGetTextDatum(newversion);
459  replaces[Anum_pg_collation_collversion - 1] = true;
460 
461  tup = heap_modify_tuple(tup, RelationGetDescr(rel),
462  values, nulls, replaces);
463  }
464  else
465  ereport(NOTICE,
466  (errmsg("version has not changed")));
467 
468  CatalogTupleUpdate(rel, &tup->t_self, tup);
469 
470  InvokeObjectPostAlterHook(CollationRelationId, collOid, 0);
471 
472  ObjectAddressSet(address, CollationRelationId, collOid);
473 
474  heap_freetuple(tup);
475  table_close(rel, NoLock);
476 
477  return address;
478 }
479 
480 
481 Datum
483 {
484  Oid collid = PG_GETARG_OID(0);
485  char provider;
486  char *locale;
487  char *version;
488  Datum datum;
489 
490  if (collid == DEFAULT_COLLATION_OID)
491  {
492  /* retrieve from pg_database */
493 
495 
496  if (!HeapTupleIsValid(dbtup))
497  ereport(ERROR,
498  (errcode(ERRCODE_UNDEFINED_OBJECT),
499  errmsg("database with OID %u does not exist", MyDatabaseId)));
500 
502 
503  datum = SysCacheGetAttrNotNull(DATABASEOID, dbtup,
504  provider == COLLPROVIDER_ICU ?
505  Anum_pg_database_daticulocale : Anum_pg_database_datcollate);
506 
507  locale = TextDatumGetCString(datum);
508 
509  ReleaseSysCache(dbtup);
510  }
511  else
512  {
513  /* retrieve from pg_collation */
514 
515  HeapTuple colltp = SearchSysCache1(COLLOID, ObjectIdGetDatum(collid));
516 
517  if (!HeapTupleIsValid(colltp))
518  ereport(ERROR,
519  (errcode(ERRCODE_UNDEFINED_OBJECT),
520  errmsg("collation with OID %u does not exist", collid)));
521 
522  provider = ((Form_pg_collation) GETSTRUCT(colltp))->collprovider;
523  Assert(provider != COLLPROVIDER_DEFAULT);
524  datum = SysCacheGetAttrNotNull(COLLOID, colltp,
525  provider == COLLPROVIDER_ICU ?
526  Anum_pg_collation_colliculocale : Anum_pg_collation_collcollate);
527 
528  locale = TextDatumGetCString(datum);
529 
530  ReleaseSysCache(colltp);
531  }
532 
534  if (version)
536  else
537  PG_RETURN_NULL();
538 }
539 
540 
541 /* will we use "locale -a" in pg_import_system_collations? */
542 #if !defined(WIN32)
543 #define READ_LOCALE_A_OUTPUT
544 #endif
545 
546 /* will we use EnumSystemLocalesEx in pg_import_system_collations? */
547 #ifdef WIN32
548 #define ENUM_SYSTEM_LOCALE
549 #endif
550 
551 
552 #ifdef READ_LOCALE_A_OUTPUT
553 /*
554  * "Normalize" a libc locale name, stripping off encoding tags such as
555  * ".utf8" (e.g., "en_US.utf8" -> "en_US", but "br_FR.iso885915@euro"
556  * -> "br_FR@euro"). Return true if a new, different name was
557  * generated.
558  */
559 static bool
560 normalize_libc_locale_name(char *new, const char *old)
561 {
562  char *n = new;
563  const char *o = old;
564  bool changed = false;
565 
566  while (*o)
567  {
568  if (*o == '.')
569  {
570  /* skip over encoding tag such as ".utf8" or ".UTF-8" */
571  o++;
572  while ((*o >= 'A' && *o <= 'Z')
573  || (*o >= 'a' && *o <= 'z')
574  || (*o >= '0' && *o <= '9')
575  || (*o == '-'))
576  o++;
577  changed = true;
578  }
579  else
580  *n++ = *o++;
581  }
582  *n = '\0';
583 
584  return changed;
585 }
586 
587 /*
588  * qsort comparator for CollAliasData items
589  */
590 static int
591 cmpaliases(const void *a, const void *b)
592 {
593  const CollAliasData *ca = (const CollAliasData *) a;
594  const CollAliasData *cb = (const CollAliasData *) b;
595 
596  /* comparing localename is enough because other fields are derived */
597  return strcmp(ca->localename, cb->localename);
598 }
599 #endif /* READ_LOCALE_A_OUTPUT */
600 
601 
602 #ifdef USE_ICU
603 /*
604  * Get a comment (specifically, the display name) for an ICU locale.
605  * The result is a palloc'd string, or NULL if we can't get a comment
606  * or find that it's not all ASCII. (We can *not* accept non-ASCII
607  * comments, because the contents of template0 must be encoding-agnostic.)
608  */
609 static char *
610 get_icu_locale_comment(const char *localename)
611 {
612  UErrorCode status;
613  UChar displayname[128];
614  int32 len_uchar;
615  int32 i;
616  char *result;
617 
618  status = U_ZERO_ERROR;
619  len_uchar = uloc_getDisplayName(localename, "en",
620  displayname, lengthof(displayname),
621  &status);
622  if (U_FAILURE(status))
623  return NULL; /* no good reason to raise an error */
624 
625  /* Check for non-ASCII comment (can't use pg_is_ascii for this) */
626  for (i = 0; i < len_uchar; i++)
627  {
628  if (displayname[i] > 127)
629  return NULL;
630  }
631 
632  /* OK, transcribe */
633  result = palloc(len_uchar + 1);
634  for (i = 0; i < len_uchar; i++)
635  result[i] = displayname[i];
636  result[len_uchar] = '\0';
637 
638  return result;
639 }
640 #endif /* USE_ICU */
641 
642 
643 /*
644  * Create a new collation using the input locale 'locale'. (subroutine for
645  * pg_import_system_collations())
646  *
647  * 'nspid' is the namespace id where the collation will be created.
648  *
649  * 'nvalidp' is incremented if the locale has a valid encoding.
650  *
651  * 'ncreatedp' is incremented if the collation is actually created. If the
652  * collation already exists it will quietly do nothing.
653  *
654  * The returned value is the encoding of the locale, -1 if the locale is not
655  * valid for creating a collation.
656  *
657  */
659 static int
660 create_collation_from_locale(const char *locale, int nspid,
661  int *nvalidp, int *ncreatedp)
662 {
663  int enc;
665 
666  /*
667  * Some systems have locale names that don't consist entirely of ASCII
668  * letters (such as "bokm&aring;l" or "fran&ccedil;ais"). This is pretty
669  * silly, since we need the locale itself to interpret the non-ASCII
670  * characters. We can't do much with those, so we filter them out.
671  */
673  {
674  elog(DEBUG1, "skipping locale with non-ASCII name: \"%s\"", locale);
675  return -1;
676  }
677 
679  if (enc < 0)
680  {
681  elog(DEBUG1, "skipping locale with unrecognized encoding: \"%s\"", locale);
682  return -1;
683  }
685  {
686  elog(DEBUG1, "skipping locale with client-only encoding: \"%s\"", locale);
687  return -1;
688  }
690  return -1; /* C/POSIX are already in the catalog */
691 
692  /* count valid locales found in operating system */
693  (*nvalidp)++;
694 
695  /*
696  * Create a collation named the same as the locale, but quietly doing
697  * nothing if it already exists. This is the behavior we need even at
698  * initdb time, because some versions of "locale -a" can report the same
699  * locale name more than once. And it's convenient for later import runs,
700  * too, since you just about always want to add on new locales without a
701  * lot of chatter about existing ones.
702  */
704  COLLPROVIDER_LIBC, true, enc,
705  locale, locale, NULL, NULL,
706  get_collation_actual_version(COLLPROVIDER_LIBC, locale),
707  true, true);
708  if (OidIsValid(collid))
709  {
710  (*ncreatedp)++;
711 
712  /* Must do CCI between inserts to handle duplicates correctly */
714  }
715 
716  return enc;
717 }
718 
719 
720 #ifdef ENUM_SYSTEM_LOCALE
721 /* parameter to be passed to the callback function win32_read_locale() */
722 typedef struct
723 {
724  Oid nspid;
725  int *ncreatedp;
726  int *nvalidp;
727 } CollParam;
728 
729 /*
730  * Callback function for EnumSystemLocalesEx() in
731  * pg_import_system_collations(). Creates a collation for every valid locale
732  * and a POSIX alias collation.
733  *
734  * The callback contract is to return TRUE to continue enumerating and FALSE
735  * to stop enumerating. We always want to continue.
736  */
737 static BOOL CALLBACK
738 win32_read_locale(LPWSTR pStr, DWORD dwFlags, LPARAM lparam)
739 {
740  CollParam *param = (CollParam *) lparam;
741  char localebuf[NAMEDATALEN];
742  int result;
743  int enc;
744 
745  (void) dwFlags;
746 
747  result = WideCharToMultiByte(CP_ACP, 0, pStr, -1, localebuf, NAMEDATALEN,
748  NULL, NULL);
749 
750  if (result == 0)
751  {
752  if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
753  elog(DEBUG1, "skipping locale with too-long name: \"%s\"", localebuf);
754  return TRUE;
755  }
756  if (localebuf[0] == '\0')
757  return TRUE;
758 
759  enc = create_collation_from_locale(localebuf, param->nspid,
760  param->nvalidp, param->ncreatedp);
761  if (enc < 0)
762  return TRUE;
763 
764  /*
765  * Windows will use hyphens between language and territory, where POSIX
766  * uses an underscore. Simply create a POSIX alias.
767  */
768  if (strchr(localebuf, '-'))
769  {
770  char alias[NAMEDATALEN];
771  Oid collid;
772 
773  strcpy(alias, localebuf);
774  for (char *p = alias; *p; p++)
775  if (*p == '-')
776  *p = '_';
777 
778  collid = CollationCreate(alias, param->nspid, GetUserId(),
779  COLLPROVIDER_LIBC, true, enc,
780  localebuf, localebuf, NULL, NULL,
781  get_collation_actual_version(COLLPROVIDER_LIBC, localebuf),
782  true, true);
783  if (OidIsValid(collid))
784  {
785  (*param->ncreatedp)++;
786 
788  }
789  }
790 
791  return TRUE;
792 }
793 #endif /* ENUM_SYSTEM_LOCALE */
794 
795 
796 /*
797  * pg_import_system_collations: add known system collations to pg_collation
798  */
799 Datum
801 {
802  Oid nspid = PG_GETARG_OID(0);
803  int ncreated = 0;
804 
805  if (!superuser())
806  ereport(ERROR,
807  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
808  errmsg("must be superuser to import system collations")));
809 
810  if (!SearchSysCacheExists1(NAMESPACEOID, ObjectIdGetDatum(nspid)))
811  ereport(ERROR,
812  (errcode(ERRCODE_UNDEFINED_SCHEMA),
813  errmsg("schema with OID %u does not exist", nspid)));
814 
815  /* Load collations known to libc, using "locale -a" to enumerate them */
816 #ifdef READ_LOCALE_A_OUTPUT
817  {
818  FILE *locale_a_handle;
819  char localebuf[LOCALE_NAME_BUFLEN];
820  int nvalid = 0;
821  Oid collid;
822  CollAliasData *aliases;
823  int naliases,
824  maxaliases,
825  i;
826 
827  /* expansible array of aliases */
828  maxaliases = 100;
829  aliases = (CollAliasData *) palloc(maxaliases * sizeof(CollAliasData));
830  naliases = 0;
831 
832  locale_a_handle = OpenPipeStream("locale -a", "r");
833  if (locale_a_handle == NULL)
834  ereport(ERROR,
836  errmsg("could not execute command \"%s\": %m",
837  "locale -a")));
838 
839  while (fgets(localebuf, sizeof(localebuf), locale_a_handle))
840  {
841  size_t len;
842  int enc;
843  char alias[LOCALE_NAME_BUFLEN];
844 
845  len = strlen(localebuf);
846 
847  if (len == 0 || localebuf[len - 1] != '\n')
848  {
849  elog(DEBUG1, "skipping locale with too-long name: \"%s\"", localebuf);
850  continue;
851  }
852  localebuf[len - 1] = '\0';
853 
854  enc = create_collation_from_locale(localebuf, nspid, &nvalid, &ncreated);
855  if (enc < 0)
856  continue;
857 
858  /*
859  * Generate aliases such as "en_US" in addition to "en_US.utf8"
860  * for ease of use. Note that collation names are unique per
861  * encoding only, so this doesn't clash with "en_US" for LATIN1,
862  * say.
863  *
864  * However, it might conflict with a name we'll see later in the
865  * "locale -a" output. So save up the aliases and try to add them
866  * after we've read all the output.
867  */
868  if (normalize_libc_locale_name(alias, localebuf))
869  {
870  if (naliases >= maxaliases)
871  {
872  maxaliases *= 2;
873  aliases = (CollAliasData *)
874  repalloc(aliases, maxaliases * sizeof(CollAliasData));
875  }
876  aliases[naliases].localename = pstrdup(localebuf);
877  aliases[naliases].alias = pstrdup(alias);
878  aliases[naliases].enc = enc;
879  naliases++;
880  }
881  }
882 
883  /*
884  * We don't check the return value of this, because we want to support
885  * the case where there "locale" command does not exist. (This is
886  * unusual but can happen on minimalized Linux distributions, for
887  * example.) We will warn below if no locales could be found.
888  */
889  ClosePipeStream(locale_a_handle);
890 
891  /*
892  * Before processing the aliases, sort them by locale name. The point
893  * here is that if "locale -a" gives us multiple locale names with the
894  * same encoding and base name, say "en_US.utf8" and "en_US.utf-8", we
895  * want to pick a deterministic one of them. First in ASCII sort
896  * order is a good enough rule. (Before PG 10, the code corresponding
897  * to this logic in initdb.c had an additional ordering rule, to
898  * prefer the locale name exactly matching the alias, if any. We
899  * don't need to consider that here, because we would have already
900  * created such a pg_collation entry above, and that one will win.)
901  */
902  if (naliases > 1)
903  qsort(aliases, naliases, sizeof(CollAliasData), cmpaliases);
904 
905  /* Now add aliases, ignoring any that match pre-existing entries */
906  for (i = 0; i < naliases; i++)
907  {
908  char *locale = aliases[i].localename;
909  char *alias = aliases[i].alias;
910  int enc = aliases[i].enc;
911 
913  COLLPROVIDER_LIBC, true, enc,
914  locale, locale, NULL, NULL,
915  get_collation_actual_version(COLLPROVIDER_LIBC, locale),
916  true, true);
917  if (OidIsValid(collid))
918  {
919  ncreated++;
920 
922  }
923  }
924 
925  /* Give a warning if "locale -a" seems to be malfunctioning */
926  if (nvalid == 0)
928  (errmsg("no usable system locales were found")));
929  }
930 #endif /* READ_LOCALE_A_OUTPUT */
931 
932  /*
933  * Load collations known to ICU
934  *
935  * We use uloc_countAvailable()/uloc_getAvailable() rather than
936  * ucol_countAvailable()/ucol_getAvailable(). The former returns a full
937  * set of language+region combinations, whereas the latter only returns
938  * language+region combinations if they are distinct from the language's
939  * base collation. So there might not be a de-DE or en-GB, which would be
940  * confusing.
941  */
942 #ifdef USE_ICU
943  {
944  int i;
945 
946  /*
947  * Start the loop at -1 to sneak in the root locale without too much
948  * code duplication.
949  */
950  for (i = -1; i < uloc_countAvailable(); i++)
951  {
952  const char *name;
953  char *langtag;
954  char *icucomment;
955  Oid collid;
956 
957  if (i == -1)
958  name = ""; /* ICU root locale */
959  else
960  name = uloc_getAvailable(i);
961 
962  langtag = icu_language_tag(name, ERROR);
963 
964  /*
965  * Be paranoid about not allowing any non-ASCII strings into
966  * pg_collation
967  */
968  if (!pg_is_ascii(langtag))
969  continue;
970 
971  collid = CollationCreate(psprintf("%s-x-icu", langtag),
972  nspid, GetUserId(),
973  COLLPROVIDER_ICU, true, -1,
974  NULL, NULL, langtag, NULL,
975  get_collation_actual_version(COLLPROVIDER_ICU, langtag),
976  true, true);
977  if (OidIsValid(collid))
978  {
979  ncreated++;
980 
982 
983  icucomment = get_icu_locale_comment(name);
984  if (icucomment)
985  CreateComments(collid, CollationRelationId, 0,
986  icucomment);
987  }
988  }
989  }
990 #endif /* USE_ICU */
991 
992  /* Load collations known to WIN32 */
993 #ifdef ENUM_SYSTEM_LOCALE
994  {
995  int nvalid = 0;
996  CollParam param;
997 
998  param.nspid = nspid;
999  param.ncreatedp = &ncreated;
1000  param.nvalidp = &nvalid;
1001 
1002  /*
1003  * Enumerate the locales that are either installed on or supported by
1004  * the OS.
1005  */
1006  if (!EnumSystemLocalesEx(win32_read_locale, LOCALE_ALL,
1007  (LPARAM) &param, NULL))
1008  _dosmaperr(GetLastError());
1009 
1010  /* Give a warning if EnumSystemLocalesEx seems to be malfunctioning */
1011  if (nvalid == 0)
1012  ereport(WARNING,
1013  (errmsg("no usable system locales were found")));
1014  }
1015 #endif /* ENUM_SYSTEM_LOCALE */
1016 
1017  PG_RETURN_INT32(ncreated);
1018 }
AclResult
Definition: acl.h:181
@ ACLCHECK_OK
Definition: acl.h:182
@ ACLCHECK_NOT_OWNER
Definition: acl.h:184
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:2701
AclResult object_aclcheck(Oid classid, Oid objectid, Oid roleid, AclMode mode)
Definition: aclchk.c:3878
bool object_ownercheck(Oid classid, Oid objectid, Oid roleid)
Definition: aclchk.c:4132
static Datum values[MAXATTR]
Definition: bootstrap.c:156
#define CStringGetTextDatum(s)
Definition: builtins.h:97
#define TextDatumGetCString(d)
Definition: builtins.h:98
signed int int32
Definition: c.h:481
#define lengthof(array)
Definition: c.h:775
#define OidIsValid(objectId)
Definition: c.h:762
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: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:1508
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:883
int errdetail(const char *fmt,...)
Definition: elog.c:1206
int errhint(const char *fmt,...)
Definition: elog.c:1320
int errcode(int sqlerrcode)
Definition: elog.c:860
int errmsg(const char *fmt,...)
Definition: elog.c:1073
#define WARNING
Definition: elog.h:36
#define DEBUG1
Definition: elog.h:30
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:224
#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
int ClosePipeStream(FILE *file)
Definition: fd.c:2991
FILE * OpenPipeStream(const char *command, const char *mode)
Definition: fd.c:2686
#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:117
Oid MyDatabaseId
Definition: globals.c:90
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
static char * locale
Definition: initdb.c:140
int b
Definition: isn.c:70
int a
Definition: isn.c:69
int i
Definition: isn.c:73
static JitProviderCallbacks provider
Definition: jit.c:42
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:3321
int GetDatabaseEncoding(void)
Definition: mbutils.c:1262
const char * GetDatabaseEncodingName(void)
Definition: mbutils.c:1268
char * pstrdup(const char *in)
Definition: mcxt.c:1580
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:1425
void * palloc(Size size)
Definition: mcxt.c:1201
Oid GetUserId(void)
Definition: miscinit.c:515
Oid QualifiedNameGetCreationNamespace(const List *names, char **objname_p)
Definition: namespace.c:3472
Oid get_collation_oid(List *collname, bool missing_ok)
Definition: namespace.c:3956
char * NameListToString(const List *names)
Definition: namespace.c:3579
#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:111
@ OBJECT_COLLATION
Definition: parsenodes.h:2111
@ OBJECT_SCHEMA
Definition: parsenodes.h:2140
#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 *colliculocale, const char *collicurules, const char *collversion, bool if_not_exists, bool quiet)
Definition: pg_collation.c:46
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:103
bool lc_collate_is_c(Oid collation)
Definition: pg_locale.c:1307
void icu_validate_locale(const char *loc_str)
Definition: pg_locale.c:2853
pg_locale_t pg_newlocale_from_collation(Oid collid)
Definition: pg_locale.c:1514
bool lc_ctype_is_c(Oid collation)
Definition: pg_locale.c:1360
char * get_collation_actual_version(char collprovider, const char *collcollate)
Definition: pg_locale.c:1677
char * icu_language_tag(const char *loc_str, int elevel)
Definition: pg_locale.c:2796
#define LOCALE_NAME_BUFLEN
Definition: pg_locale.h:36
@ 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:449
uintptr_t Datum
Definition: postgres.h:64
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:252
static Datum CStringGetDatum(const char *X)
Definition: postgres.h:350
static Datum Int32GetDatum(int32 X)
Definition: postgres.h:212
unsigned int Oid
Definition: postgres_ext.h:31
char * psprintf(const char *fmt,...)
Definition: psprintf.c:46
#define RelationGetDescr(relation)
Definition: rel.h:530
#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:810
int location
Definition: parsenodes.h:814
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:267
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:219
Datum SysCacheGetAttr(int cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition: syscache.c:480
Datum SysCacheGetAttrNotNull(int cacheId, HeapTuple tup, AttrNumber attributeNumber)
Definition: syscache.c:511
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:86
#define SearchSysCacheExists1(cacheId, key1)
Definition: syscache.h:95
#define SearchSysCacheExists3(cacheId, key1, key2, key3)
Definition: syscache.h:99
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:1078