PostgreSQL Source Code  git master
collationcmds.c File Reference
#include "postgres.h"
#include "access/heapam.h"
#include "access/htup_details.h"
#include "access/xact.h"
#include "catalog/dependency.h"
#include "catalog/indexing.h"
#include "catalog/namespace.h"
#include "catalog/objectaccess.h"
#include "catalog/pg_collation.h"
#include "catalog/pg_collation_fn.h"
#include "commands/alter.h"
#include "commands/collationcmds.h"
#include "commands/comment.h"
#include "commands/dbcommands.h"
#include "commands/defrem.h"
#include "mb/pg_wchar.h"
#include "miscadmin.h"
#include "utils/builtins.h"
#include "utils/lsyscache.h"
#include "utils/pg_locale.h"
#include "utils/rel.h"
#include "utils/syscache.h"
Include dependency graph for collationcmds.c:

Go to the source code of this file.

Data Structures

struct  CollAliasData
 

Functions

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

Function Documentation

◆ AlterCollation()

ObjectAddress AlterCollation ( AlterCollationStmt stmt)

Definition at line 265 of file collationcmds.c.

References ACL_KIND_COLLATION, aclcheck_error(), ACLCHECK_NOT_OWNER, Anum_pg_collation_collversion, CatalogTupleUpdate(), CollationRelationId, AlterCollationStmt::collname, COLLOID, CStringGetTextDatum, elog, ereport, errmsg(), ERROR, get_collation_actual_version(), get_collation_oid(), GETSTRUCT, GetUserId(), heap_close, heap_freetuple(), heap_modify_tuple(), heap_open(), HeapTupleIsValid, InvokeObjectPostAlterHook, NameListToString(), NameStr, Natts_pg_collation, NoLock, NOTICE, ObjectAddressSet, ObjectIdGetDatum, pg_collation_ownercheck(), RelationGetDescr, RowExclusiveLock, SearchSysCacheCopy1, SysCacheGetAttr(), HeapTupleData::t_self, TextDatumGetCString, and values.

Referenced by ProcessUtilitySlow().

266 {
267  Relation rel;
268  Oid collOid;
269  HeapTuple tup;
270  Form_pg_collation collForm;
271  Datum collversion;
272  bool isnull;
273  char *oldversion;
274  char *newversion;
275  ObjectAddress address;
276 
278  collOid = get_collation_oid(stmt->collname, false);
279 
280  if (!pg_collation_ownercheck(collOid, GetUserId()))
282  NameListToString(stmt->collname));
283 
285  if (!HeapTupleIsValid(tup))
286  elog(ERROR, "cache lookup failed for collation %u", collOid);
287 
288  collForm = (Form_pg_collation) GETSTRUCT(tup);
290  &isnull);
291  oldversion = isnull ? NULL : TextDatumGetCString(collversion);
292 
293  newversion = get_collation_actual_version(collForm->collprovider, NameStr(collForm->collcollate));
294 
295  /* cannot change from NULL to non-NULL or vice versa */
296  if ((!oldversion && newversion) || (oldversion && !newversion))
297  elog(ERROR, "invalid collation version change");
298  else if (oldversion && newversion && strcmp(newversion, oldversion) != 0)
299  {
300  bool nulls[Natts_pg_collation];
301  bool replaces[Natts_pg_collation];
303 
304  ereport(NOTICE,
305  (errmsg("changing version from %s to %s",
306  oldversion, newversion)));
307 
308  memset(values, 0, sizeof(values));
309  memset(nulls, false, sizeof(nulls));
310  memset(replaces, false, sizeof(replaces));
311 
312  values[Anum_pg_collation_collversion - 1] = CStringGetTextDatum(newversion);
313  replaces[Anum_pg_collation_collversion - 1] = true;
314 
315  tup = heap_modify_tuple(tup, RelationGetDescr(rel),
316  values, nulls, replaces);
317  }
318  else
319  ereport(NOTICE,
320  (errmsg("version has not changed")));
321 
322  CatalogTupleUpdate(rel, &tup->t_self, tup);
323 
325 
326  ObjectAddressSet(address, CollationRelationId, collOid);
327 
328  heap_freetuple(tup);
329  heap_close(rel, NoLock);
330 
331  return address;
332 }
bool pg_collation_ownercheck(Oid coll_oid, Oid roleid)
Definition: aclchk.c:4990
#define Anum_pg_collation_collversion
Definition: pg_collation.h:66
#define GETSTRUCT(TUP)
Definition: htup_details.h:661
#define RelationGetDescr(relation)
Definition: rel.h:437
Oid GetUserId(void)
Definition: miscinit.c:284
#define Natts_pg_collation
Definition: pg_collation.h:58
#define heap_close(r, l)
Definition: heapam.h:97
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1373
unsigned int Oid
Definition: postgres_ext.h:31
#define ObjectIdGetDatum(X)
Definition: postgres.h:513
#define ERROR
Definition: elog.h:43
ItemPointerData t_self
Definition: htup.h:65
#define NoLock
Definition: lockdefs.h:34
void aclcheck_error(AclResult aclerr, AclObjectKind objectkind, const char *objectname)
Definition: aclchk.c:3399
#define RowExclusiveLock
Definition: lockdefs.h:38
#define ereport(elevel, rest)
Definition: elog.h:122
#define InvokeObjectPostAlterHook(classId, objectId, subId)
Definition: objectaccess.h:163
char * NameListToString(List *names)
Definition: namespace.c:3063
#define TextDatumGetCString(d)
Definition: builtins.h:92
uintptr_t Datum
Definition: postgres.h:372
Datum SysCacheGetAttr(int cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition: syscache.c:1368
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1290
#define CollationRelationId
Definition: pg_collation.h:30
#define NOTICE
Definition: elog.h:37
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:210
FormData_pg_collation * Form_pg_collation
Definition: pg_collation.h:52
#define ObjectAddressSet(addr, class_id, object_id)
Definition: objectaddress.h:40
static Datum values[MAXATTR]
Definition: bootstrap.c:164
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:173
int errmsg(const char *fmt,...)
Definition: elog.c:797
#define NameStr(name)
Definition: c.h:547
#define CStringGetTextDatum(s)
Definition: builtins.h:91
#define elog
Definition: elog.h:219
HeapTuple heap_modify_tuple(HeapTuple tuple, TupleDesc tupleDesc, Datum *replValues, bool *replIsnull, bool *doReplace)
Definition: heaptuple.c:794
Oid get_collation_oid(List *name, bool missing_ok)
Definition: namespace.c:3493
char * get_collation_actual_version(char collprovider, const char *collcollate)
Definition: pg_locale.c:1452

◆ DefineCollation()

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

Definition at line 52 of file collationcmds.c.

References ACL_CREATE, ACL_KIND_NAMESPACE, aclcheck_error(), ACLCHECK_OK, check_encoding_locale_matches(), CollationCreate(), CollationRelationId, COLLOID, COLLPROVIDER_DEFAULT, COLLPROVIDER_ICU, COLLPROVIDER_LIBC, CommandCounterIncrement(), defGetQualifiedName(), defGetString(), DefElem::defname, elog, ereport, errcode(), errmsg(), ERROR, get_collation_actual_version(), get_collation_oid(), get_namespace_name(), GetDatabaseEncoding(), GETSTRUCT, GetUserId(), HeapTupleIsValid, InvalidObjectAddress, lc_collate_is_c(), lc_ctype_is_c(), lfirst_node, list_length(), DefElem::location, NameStr, ObjectAddressSet, ObjectIdGetDatum, OidIsValid, parser_errposition(), pg_namespace_aclcheck(), pg_newlocale_from_collation(), pg_strcasecmp(), pstrdup(), QualifiedNameGetCreationNamespace(), ReleaseSysCache(), and SearchSysCache1().

Referenced by ProcessUtilitySlow().

53 {
54  char *collName;
55  Oid collNamespace;
56  AclResult aclresult;
57  ListCell *pl;
58  DefElem *fromEl = NULL;
59  DefElem *localeEl = NULL;
60  DefElem *lccollateEl = NULL;
61  DefElem *lcctypeEl = NULL;
62  DefElem *providerEl = NULL;
63  DefElem *versionEl = NULL;
64  char *collcollate = NULL;
65  char *collctype = NULL;
66  char *collproviderstr = NULL;
67  int collencoding = 0;
68  char collprovider = 0;
69  char *collversion = NULL;
70  Oid newoid;
71  ObjectAddress address;
72 
73  collNamespace = QualifiedNameGetCreationNamespace(names, &collName);
74 
75  aclresult = pg_namespace_aclcheck(collNamespace, GetUserId(), ACL_CREATE);
76  if (aclresult != ACLCHECK_OK)
78  get_namespace_name(collNamespace));
79 
80  foreach(pl, parameters)
81  {
82  DefElem *defel = lfirst_node(DefElem, pl);
83  DefElem **defelp;
84 
85  if (pg_strcasecmp(defel->defname, "from") == 0)
86  defelp = &fromEl;
87  else if (pg_strcasecmp(defel->defname, "locale") == 0)
88  defelp = &localeEl;
89  else if (pg_strcasecmp(defel->defname, "lc_collate") == 0)
90  defelp = &lccollateEl;
91  else if (pg_strcasecmp(defel->defname, "lc_ctype") == 0)
92  defelp = &lcctypeEl;
93  else if (pg_strcasecmp(defel->defname, "provider") == 0)
94  defelp = &providerEl;
95  else if (pg_strcasecmp(defel->defname, "version") == 0)
96  defelp = &versionEl;
97  else
98  {
99  ereport(ERROR,
100  (errcode(ERRCODE_SYNTAX_ERROR),
101  errmsg("collation attribute \"%s\" not recognized",
102  defel->defname),
103  parser_errposition(pstate, defel->location)));
104  break;
105  }
106 
107  *defelp = defel;
108  }
109 
110  if ((localeEl && (lccollateEl || lcctypeEl))
111  || (fromEl && list_length(parameters) != 1))
112  ereport(ERROR,
113  (errcode(ERRCODE_SYNTAX_ERROR),
114  errmsg("conflicting or redundant options")));
115 
116  if (fromEl)
117  {
118  Oid collid;
119  HeapTuple tp;
120 
121  collid = get_collation_oid(defGetQualifiedName(fromEl), false);
123  if (!HeapTupleIsValid(tp))
124  elog(ERROR, "cache lookup failed for collation %u", collid);
125 
126  collcollate = pstrdup(NameStr(((Form_pg_collation) GETSTRUCT(tp))->collcollate));
127  collctype = pstrdup(NameStr(((Form_pg_collation) GETSTRUCT(tp))->collctype));
128  collprovider = ((Form_pg_collation) GETSTRUCT(tp))->collprovider;
129  collencoding = ((Form_pg_collation) GETSTRUCT(tp))->collencoding;
130 
131  ReleaseSysCache(tp);
132 
133  /*
134  * Copying the "default" collation is not allowed because most code
135  * checks for DEFAULT_COLLATION_OID instead of COLLPROVIDER_DEFAULT,
136  * and so having a second collation with COLLPROVIDER_DEFAULT would
137  * not work and potentially confuse or crash some code. This could be
138  * fixed with some legwork.
139  */
140  if (collprovider == COLLPROVIDER_DEFAULT)
141  ereport(ERROR,
142  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
143  errmsg("collation \"default\" cannot be copied")));
144  }
145 
146  if (localeEl)
147  {
148  collcollate = defGetString(localeEl);
149  collctype = defGetString(localeEl);
150  }
151 
152  if (lccollateEl)
153  collcollate = defGetString(lccollateEl);
154 
155  if (lcctypeEl)
156  collctype = defGetString(lcctypeEl);
157 
158  if (providerEl)
159  collproviderstr = defGetString(providerEl);
160 
161  if (versionEl)
162  collversion = defGetString(versionEl);
163 
164  if (collproviderstr)
165  {
166  if (pg_strcasecmp(collproviderstr, "icu") == 0)
167  collprovider = COLLPROVIDER_ICU;
168  else if (pg_strcasecmp(collproviderstr, "libc") == 0)
169  collprovider = COLLPROVIDER_LIBC;
170  else
171  ereport(ERROR,
172  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
173  errmsg("unrecognized collation provider: %s",
174  collproviderstr)));
175  }
176  else if (!fromEl)
177  collprovider = COLLPROVIDER_LIBC;
178 
179  if (!collcollate)
180  ereport(ERROR,
181  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
182  errmsg("parameter \"lc_collate\" must be specified")));
183 
184  if (!collctype)
185  ereport(ERROR,
186  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
187  errmsg("parameter \"lc_ctype\" must be specified")));
188 
189  if (!fromEl)
190  {
191  if (collprovider == COLLPROVIDER_ICU)
192  collencoding = -1;
193  else
194  {
195  collencoding = GetDatabaseEncoding();
196  check_encoding_locale_matches(collencoding, collcollate, collctype);
197  }
198  }
199 
200  if (!collversion)
201  collversion = get_collation_actual_version(collprovider, collcollate);
202 
203  newoid = CollationCreate(collName,
204  collNamespace,
205  GetUserId(),
206  collprovider,
207  collencoding,
208  collcollate,
209  collctype,
210  collversion,
211  if_not_exists,
212  false); /* not quiet */
213 
214  if (!OidIsValid(newoid))
215  return InvalidObjectAddress;
216 
217  /*
218  * Check that the locales can be loaded. NB: pg_newlocale_from_collation
219  * is only supposed to be called on non-C-equivalent locales.
220  */
222  if (!lc_collate_is_c(newoid) || !lc_ctype_is_c(newoid))
223  (void) pg_newlocale_from_collation(newoid);
224 
225  ObjectAddressSet(address, CollationRelationId, newoid);
226 
227  return address;
228 }
#define COLLPROVIDER_ICU
Definition: pg_collation.h:85
#define COLLPROVIDER_DEFAULT
Definition: pg_collation.h:84
#define GETSTRUCT(TUP)
Definition: htup_details.h:661
void check_encoding_locale_matches(int encoding, const char *collate, const char *ctype)
Definition: dbcommands.c:722
Oid GetUserId(void)
Definition: miscinit.c:284
Oid QualifiedNameGetCreationNamespace(List *names, char **objname_p)
Definition: namespace.c:2956
char * pstrdup(const char *in)
Definition: mcxt.c:1076
int errcode(int sqlerrcode)
Definition: elog.c:575
int pg_strcasecmp(const char *s1, const char *s2)
Definition: pgstrcasecmp.c:36
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:576
AclResult pg_namespace_aclcheck(Oid nsp_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4484
#define ObjectIdGetDatum(X)
Definition: postgres.h:513
#define ERROR
Definition: elog.h:43
#define ACL_CREATE
Definition: parsenodes.h:82
bool lc_collate_is_c(Oid collation)
Definition: pg_locale.c:1128
char * defGetString(DefElem *def)
Definition: define.c:49
#define lfirst_node(type, lc)
Definition: pg_list.h:109
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3047
void aclcheck_error(AclResult aclerr, AclObjectKind objectkind, const char *objectname)
Definition: aclchk.c:3399
int location
Definition: parsenodes.h:722
#define ereport(elevel, rest)
Definition: elog.h:122
Oid CollationCreate(const char *collname, Oid collnamespace, Oid collowner, char collprovider, int32 collencoding, const char *collcollate, const char *collctype, const char *collversion, bool if_not_exists, bool quiet)
Definition: pg_collation.c:47
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1112
pg_locale_t pg_newlocale_from_collation(Oid collid)
Definition: pg_locale.c:1275
AclResult
Definition: acl.h:178
void CommandCounterIncrement(void)
Definition: xact.c:915
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1160
int GetDatabaseEncoding(void)
Definition: mbutils.c:1004
#define CollationRelationId
Definition: pg_collation.h:30
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
List * defGetQualifiedName(DefElem *def)
Definition: define.c:223
static int list_length(const List *l)
Definition: pg_list.h:89
int parser_errposition(ParseState *pstate, int location)
Definition: parse_node.c:111
FormData_pg_collation * Form_pg_collation
Definition: pg_collation.h:52
#define ObjectAddressSet(addr, class_id, object_id)
Definition: objectaddress.h:40
const ObjectAddress InvalidObjectAddress
int errmsg(const char *fmt,...)
Definition: elog.c:797
#define NameStr(name)
Definition: c.h:547
char * defname
Definition: parsenodes.h:719
#define elog
Definition: elog.h:219
bool lc_ctype_is_c(Oid collation)
Definition: pg_locale.c:1178
Oid get_collation_oid(List *name, bool missing_ok)
Definition: namespace.c:3493
#define COLLPROVIDER_LIBC
Definition: pg_collation.h:86
char * get_collation_actual_version(char collprovider, const char *collcollate)
Definition: pg_locale.c:1452

◆ IsThereCollationInNamespace()

void IsThereCollationInNamespace ( const char *  collname,
Oid  nspOid 
)

Definition at line 237 of file collationcmds.c.

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

Referenced by AlterObjectNamespace_internal(), and AlterObjectRename_internal().

238 {
239  /* make sure the name doesn't already exist in new schema */
241  CStringGetDatum(collname),
243  ObjectIdGetDatum(nspOid)))
244  ereport(ERROR,
246  errmsg("collation \"%s\" for encoding \"%s\" already exists in schema \"%s\"",
247  collname, GetDatabaseEncodingName(),
248  get_namespace_name(nspOid))));
249 
250  /* mustn't match an any-encoding entry, either */
252  CStringGetDatum(collname),
253  Int32GetDatum(-1),
254  ObjectIdGetDatum(nspOid)))
255  ereport(ERROR,
257  errmsg("collation \"%s\" already exists in schema \"%s\"",
258  collname, get_namespace_name(nspOid))));
259 }
int errcode(int sqlerrcode)
Definition: elog.c:575
#define ObjectIdGetDatum(X)
Definition: postgres.h:513
#define ERROR
Definition: elog.h:43
#define SearchSysCacheExists3(cacheId, key1, key2, key3)
Definition: syscache.h:186
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3047
#define CStringGetDatum(X)
Definition: postgres.h:584
#define ereport(elevel, rest)
Definition: elog.h:122
int GetDatabaseEncoding(void)
Definition: mbutils.c:1004
const char * GetDatabaseEncodingName(void)
Definition: mbutils.c:1010
#define Int32GetDatum(X)
Definition: postgres.h:485
int errmsg(const char *fmt,...)
Definition: elog.c:797
#define ERRCODE_DUPLICATE_OBJECT
Definition: streamutil.c:30

◆ pg_collation_actual_version()

Datum pg_collation_actual_version ( PG_FUNCTION_ARGS  )

Definition at line 336 of file collationcmds.c.

References buf, COLLOID, cstring_to_text(), ereport, errcode(), errmsg(), ERROR, get_collation_actual_version(), GETSTRUCT, HeapTupleIsValid, i, IS_HIGHBIT_SET, lengthof, CollAliasData::localename, NameStr, ObjectIdGetDatum, palloc(), PG_GETARG_OID, PG_RETURN_NULL, PG_RETURN_TEXT_P, pstrdup(), ReleaseSysCache(), SearchSysCache1(), status(), generate_unaccent_rules::str, and TRUE.

337 {
338  Oid collid = PG_GETARG_OID(0);
339  HeapTuple tp;
340  char *collcollate;
341  char collprovider;
342  char *version;
343 
345  if (!HeapTupleIsValid(tp))
346  ereport(ERROR,
347  (errcode(ERRCODE_UNDEFINED_OBJECT),
348  errmsg("collation with OID %u does not exist", collid)));
349 
350  collcollate = pstrdup(NameStr(((Form_pg_collation) GETSTRUCT(tp))->collcollate));
351  collprovider = ((Form_pg_collation) GETSTRUCT(tp))->collprovider;
352 
353  ReleaseSysCache(tp);
354 
355  version = get_collation_actual_version(collprovider, collcollate);
356 
357  if (version)
359  else
360  PG_RETURN_NULL();
361 }
#define GETSTRUCT(TUP)
Definition: htup_details.h:661
char * pstrdup(const char *in)
Definition: mcxt.c:1076
int errcode(int sqlerrcode)
Definition: elog.c:575
unsigned int Oid
Definition: postgres_ext.h:31
#define ObjectIdGetDatum(X)
Definition: postgres.h:513
#define ERROR
Definition: elog.h:43
#define PG_GETARG_OID(n)
Definition: fmgr.h:240
#define ereport(elevel, rest)
Definition: elog.h:122
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1112
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1160
#define PG_RETURN_TEXT_P(x)
Definition: fmgr.h:331
text * cstring_to_text(const char *s)
Definition: varlena.c:149
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
FormData_pg_collation * Form_pg_collation
Definition: pg_collation.h:52
int errmsg(const char *fmt,...)
Definition: elog.c:797
#define NameStr(name)
Definition: c.h:547
#define PG_RETURN_NULL()
Definition: fmgr.h:305
char * get_collation_actual_version(char collprovider, const char *collcollate)
Definition: pg_locale.c:1452

◆ pg_import_system_collations()

Datum pg_import_system_collations ( PG_FUNCTION_ARGS  )

Definition at line 501 of file collationcmds.c.

References CollAliasData::alias, ClosePipeStream(), CollationCreate(), CollationRelationId, COLLPROVIDER_ICU, COLLPROVIDER_LIBC, CommandCounterIncrement(), CreateComments(), DEBUG1, elog, CollAliasData::enc, enc, ereport, errcode(), errcode_for_file_access(), errmsg(), ERROR, get_collation_actual_version(), GetUserId(), i, locale, CollAliasData::localename, name, NAMEDATALEN, OidIsValid, OpenPipeStream(), palloc(), pg_get_encoding_from_locale(), PG_GETARG_OID, PG_RETURN_INT32, PG_SQL_ASCII, PG_VALID_BE_ENCODING, psprintf(), pstrdup(), qsort, repalloc(), superuser(), and WARNING.

502 {
503  Oid nspid = PG_GETARG_OID(0);
504  int ncreated = 0;
505 
506  /* silence compiler warning if we have no locale implementation at all */
507  (void) nspid;
508 
509  if (!superuser())
510  ereport(ERROR,
511  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
512  (errmsg("must be superuser to import system collations"))));
513 
514  /* Load collations known to libc, using "locale -a" to enumerate them */
515 #ifdef READ_LOCALE_A_OUTPUT
516  {
517  FILE *locale_a_handle;
518  char localebuf[NAMEDATALEN]; /* we assume ASCII so this is fine */
519  int nvalid = 0;
520  Oid collid;
521  CollAliasData *aliases;
522  int naliases,
523  maxaliases,
524  i;
525 
526  /* expansible array of aliases */
527  maxaliases = 100;
528  aliases = (CollAliasData *) palloc(maxaliases * sizeof(CollAliasData));
529  naliases = 0;
530 
531  locale_a_handle = OpenPipeStream("locale -a", "r");
532  if (locale_a_handle == NULL)
533  ereport(ERROR,
535  errmsg("could not execute command \"%s\": %m",
536  "locale -a")));
537 
538  while (fgets(localebuf, sizeof(localebuf), locale_a_handle))
539  {
540  size_t len;
541  int enc;
542  char alias[NAMEDATALEN];
543 
544  len = strlen(localebuf);
545 
546  if (len == 0 || localebuf[len - 1] != '\n')
547  {
548  elog(DEBUG1, "locale name too long, skipped: \"%s\"", localebuf);
549  continue;
550  }
551  localebuf[len - 1] = '\0';
552 
553  /*
554  * Some systems have locale names that don't consist entirely of
555  * ASCII letters (such as "bokmål" or "français").
556  * This is pretty silly, since we need the locale itself to
557  * interpret the non-ASCII characters. We can't do much with
558  * those, so we filter them out.
559  */
560  if (!is_all_ascii(localebuf))
561  {
562  elog(DEBUG1, "locale name has non-ASCII characters, skipped: \"%s\"", localebuf);
563  continue;
564  }
565 
566  enc = pg_get_encoding_from_locale(localebuf, false);
567  if (enc < 0)
568  {
569  /* error message printed by pg_get_encoding_from_locale() */
570  continue;
571  }
572  if (!PG_VALID_BE_ENCODING(enc))
573  continue; /* ignore locales for client-only encodings */
574  if (enc == PG_SQL_ASCII)
575  continue; /* C/POSIX are already in the catalog */
576 
577  /* count valid locales found in operating system */
578  nvalid++;
579 
580  /*
581  * Create a collation named the same as the locale, but quietly
582  * doing nothing if it already exists. This is the behavior we
583  * need even at initdb time, because some versions of "locale -a"
584  * can report the same locale name more than once. And it's
585  * convenient for later import runs, too, since you just about
586  * always want to add on new locales without a lot of chatter
587  * about existing ones.
588  */
589  collid = CollationCreate(localebuf, nspid, GetUserId(),
590  COLLPROVIDER_LIBC, enc,
591  localebuf, localebuf,
593  true, true);
594  if (OidIsValid(collid))
595  {
596  ncreated++;
597 
598  /* Must do CCI between inserts to handle duplicates correctly */
600  }
601 
602  /*
603  * Generate aliases such as "en_US" in addition to "en_US.utf8"
604  * for ease of use. Note that collation names are unique per
605  * encoding only, so this doesn't clash with "en_US" for LATIN1,
606  * say.
607  *
608  * However, it might conflict with a name we'll see later in the
609  * "locale -a" output. So save up the aliases and try to add them
610  * after we've read all the output.
611  */
612  if (normalize_libc_locale_name(alias, localebuf))
613  {
614  if (naliases >= maxaliases)
615  {
616  maxaliases *= 2;
617  aliases = (CollAliasData *)
618  repalloc(aliases, maxaliases * sizeof(CollAliasData));
619  }
620  aliases[naliases].localename = pstrdup(localebuf);
621  aliases[naliases].alias = pstrdup(alias);
622  aliases[naliases].enc = enc;
623  naliases++;
624  }
625  }
626 
627  ClosePipeStream(locale_a_handle);
628 
629  /*
630  * Before processing the aliases, sort them by locale name. The point
631  * here is that if "locale -a" gives us multiple locale names with the
632  * same encoding and base name, say "en_US.utf8" and "en_US.utf-8", we
633  * want to pick a deterministic one of them. First in ASCII sort
634  * order is a good enough rule. (Before PG 10, the code corresponding
635  * to this logic in initdb.c had an additional ordering rule, to
636  * prefer the locale name exactly matching the alias, if any. We
637  * don't need to consider that here, because we would have already
638  * created such a pg_collation entry above, and that one will win.)
639  */
640  if (naliases > 1)
641  qsort((void *) aliases, naliases, sizeof(CollAliasData), cmpaliases);
642 
643  /* Now add aliases, ignoring any that match pre-existing entries */
644  for (i = 0; i < naliases; i++)
645  {
646  char *locale = aliases[i].localename;
647  char *alias = aliases[i].alias;
648  int enc = aliases[i].enc;
649 
650  collid = CollationCreate(alias, nspid, GetUserId(),
651  COLLPROVIDER_LIBC, enc,
652  locale, locale,
654  true, true);
655  if (OidIsValid(collid))
656  {
657  ncreated++;
658 
660  }
661  }
662 
663  /* Give a warning if "locale -a" seems to be malfunctioning */
664  if (nvalid == 0)
666  (errmsg("no usable system locales were found")));
667  }
668 #endif /* READ_LOCALE_A_OUTPUT */
669 
670  /*
671  * Load collations known to ICU
672  *
673  * We use uloc_countAvailable()/uloc_getAvailable() rather than
674  * ucol_countAvailable()/ucol_getAvailable(). The former returns a full
675  * set of language+region combinations, whereas the latter only returns
676  * language+region combinations of they are distinct from the language's
677  * base collation. So there might not be a de-DE or en-GB, which would be
678  * confusing.
679  */
680 #ifdef USE_ICU
681  {
682  int i;
683 
684  /*
685  * Start the loop at -1 to sneak in the root locale without too much
686  * code duplication.
687  */
688  for (i = -1; i < uloc_countAvailable(); i++)
689  {
690  const char *name;
691  char *langtag;
692  char *icucomment;
693  const char *collcollate;
694  Oid collid;
695 
696  if (i == -1)
697  name = ""; /* ICU root locale */
698  else
699  name = uloc_getAvailable(i);
700 
701  langtag = get_icu_language_tag(name);
702  collcollate = U_ICU_VERSION_MAJOR_NUM >= 54 ? langtag : name;
703 
704  /*
705  * Be paranoid about not allowing any non-ASCII strings into
706  * pg_collation
707  */
708  if (!is_all_ascii(langtag) || !is_all_ascii(collcollate))
709  continue;
710 
711  collid = CollationCreate(psprintf("%s-x-icu", langtag),
712  nspid, GetUserId(),
713  COLLPROVIDER_ICU, -1,
714  collcollate, collcollate,
716  true, true);
717  if (OidIsValid(collid))
718  {
719  ncreated++;
720 
722 
723  icucomment = get_icu_locale_comment(name);
724  if (icucomment)
726  icucomment);
727  }
728  }
729  }
730 #endif /* USE_ICU */
731 
732  PG_RETURN_INT32(ncreated);
733 }
#define COLLPROVIDER_ICU
Definition: pg_collation.h:85
void CreateComments(Oid oid, Oid classoid, int32 subid, const char *comment)
Definition: comment.c:142
#define DEBUG1
Definition: elog.h:25
Oid GetUserId(void)
Definition: miscinit.c:284
char * localename
Definition: collationcmds.c:42
char * pstrdup(const char *in)
Definition: mcxt.c:1076
char * psprintf(const char *fmt,...)
Definition: psprintf.c:46
#define PG_RETURN_INT32(x)
Definition: fmgr.h:314
int errcode(int sqlerrcode)
Definition: elog.c:575
bool superuser(void)
Definition: superuser.c:47
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:576
int ClosePipeStream(FILE *file)
Definition: fd.c:2508
#define NAMEDATALEN
#define ERROR
Definition: elog.h:43
struct pg_encoding enc
Definition: encode.c:522
#define PG_GETARG_OID(n)
Definition: fmgr.h:240
int errcode_for_file_access(void)
Definition: elog.c:598
FILE * OpenPipeStream(const char *command, const char *mode)
Definition: fd.c:2222
#define ereport(elevel, rest)
Definition: elog.h:122
Oid CollationCreate(const char *collname, Oid collnamespace, Oid collowner, char collprovider, int32 collencoding, const char *collcollate, const char *collctype, const char *collversion, bool if_not_exists, bool quiet)
Definition: pg_collation.c:47
#define WARNING
Definition: elog.h:40
void CommandCounterIncrement(void)
Definition: xact.c:915
#define CollationRelationId
Definition: pg_collation.h:30
int pg_get_encoding_from_locale(const char *ctype, bool write_message)
Definition: chklocale.c:433
#define PG_VALID_BE_ENCODING(_enc)
Definition: pg_wchar.h:295
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:962
const char * name
Definition: encode.c:521
void * palloc(Size size)
Definition: mcxt.c:848
int errmsg(const char *fmt,...)
Definition: elog.c:797
int i
static char * locale
Definition: initdb.c:124
#define elog
Definition: elog.h:219
#define qsort(a, b, c, d)
Definition: port.h:408
#define COLLPROVIDER_LIBC
Definition: pg_collation.h:86
char * get_collation_actual_version(char collprovider, const char *collcollate)
Definition: pg_locale.c:1452