PostgreSQL Source Code  git master
collationcmds.c File Reference
#include "postgres.h"
#include "access/htup_details.h"
#include "access/table.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 "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/acl.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 284 of file collationcmds.c.

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

Referenced by ProcessUtilitySlow().

285 {
286  Relation rel;
287  Oid collOid;
288  HeapTuple tup;
289  Form_pg_collation collForm;
290  Datum collversion;
291  bool isnull;
292  char *oldversion;
293  char *newversion;
294  ObjectAddress address;
295 
296  rel = table_open(CollationRelationId, RowExclusiveLock);
297  collOid = get_collation_oid(stmt->collname, false);
298 
299  if (!pg_collation_ownercheck(collOid, GetUserId()))
301  NameListToString(stmt->collname));
302 
304  if (!HeapTupleIsValid(tup))
305  elog(ERROR, "cache lookup failed for collation %u", collOid);
306 
307  collForm = (Form_pg_collation) GETSTRUCT(tup);
308  collversion = SysCacheGetAttr(COLLOID, tup, Anum_pg_collation_collversion,
309  &isnull);
310  oldversion = isnull ? NULL : TextDatumGetCString(collversion);
311 
312  newversion = get_collation_actual_version(collForm->collprovider, NameStr(collForm->collcollate));
313 
314  /* cannot change from NULL to non-NULL or vice versa */
315  if ((!oldversion && newversion) || (oldversion && !newversion))
316  elog(ERROR, "invalid collation version change");
317  else if (oldversion && newversion && strcmp(newversion, oldversion) != 0)
318  {
319  bool nulls[Natts_pg_collation];
320  bool replaces[Natts_pg_collation];
321  Datum values[Natts_pg_collation];
322 
323  ereport(NOTICE,
324  (errmsg("changing version from %s to %s",
325  oldversion, newversion)));
326 
327  memset(values, 0, sizeof(values));
328  memset(nulls, false, sizeof(nulls));
329  memset(replaces, false, sizeof(replaces));
330 
331  values[Anum_pg_collation_collversion - 1] = CStringGetTextDatum(newversion);
332  replaces[Anum_pg_collation_collversion - 1] = true;
333 
334  tup = heap_modify_tuple(tup, RelationGetDescr(rel),
335  values, nulls, replaces);
336  }
337  else
338  ereport(NOTICE,
339  (errmsg("version has not changed")));
340 
341  CatalogTupleUpdate(rel, &tup->t_self, tup);
342 
343  InvokeObjectPostAlterHook(CollationRelationId, collOid, 0);
344 
345  ObjectAddressSet(address, CollationRelationId, collOid);
346 
347  heap_freetuple(tup);
348  table_close(rel, NoLock);
349 
350  return address;
351 }
bool pg_collation_ownercheck(Oid coll_oid, Oid roleid)
Definition: aclchk.c:5164
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:133
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
#define RelationGetDescr(relation)
Definition: rel.h:482
Oid GetUserId(void)
Definition: miscinit.c:448
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1338
unsigned int Oid
Definition: postgres_ext.h:31
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:3327
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:43
ItemPointerData t_self
Definition: htup.h:65
#define NoLock
Definition: lockdefs.h:34
#define RowExclusiveLock
Definition: lockdefs.h:38
#define InvokeObjectPostAlterHook(classId, objectId, subId)
Definition: objectaccess.h:175
char * NameListToString(List *names)
Definition: namespace.c:3102
#define TextDatumGetCString(d)
Definition: builtins.h:88
uintptr_t Datum
Definition: postgres.h:367
Datum SysCacheGetAttr(int cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition: syscache.c:1377
#define ereport(elevel,...)
Definition: elog.h:144
#define NOTICE
Definition: elog.h:37
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:224
FormData_pg_collation * Form_pg_collation
Definition: pg_collation.h:51
#define ObjectAddressSet(addr, class_id, object_id)
Definition: objectaddress.h:40
static Datum values[MAXATTR]
Definition: bootstrap.c:167
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:174
int errmsg(const char *fmt,...)
Definition: elog.c:824
#define elog(elevel,...)
Definition: elog.h:214
#define NameStr(name)
Definition: c.h:615
#define CStringGetTextDatum(s)
Definition: builtins.h:87
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
HeapTuple heap_modify_tuple(HeapTuple tuple, TupleDesc tupleDesc, Datum *replValues, bool *replIsnull, bool *doReplace)
Definition: heaptuple.c:1113
Oid get_collation_oid(List *name, bool missing_ok)
Definition: namespace.c:3601
char * get_collation_actual_version(char collprovider, const char *collcollate)
Definition: pg_locale.c:1680

◆ DefineCollation()

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

Definition at line 52 of file collationcmds.c.

References ACL_CREATE, aclcheck_error(), ACLCHECK_OK, check_encoding_locale_matches(), CollationCreate(), COLLOID, CommandCounterIncrement(), defGetBoolean(), 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, OBJECT_SCHEMA, 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 *deterministicEl = NULL;
64  DefElem *versionEl = NULL;
65  char *collcollate = NULL;
66  char *collctype = NULL;
67  char *collproviderstr = NULL;
68  bool collisdeterministic = true;
69  int collencoding = 0;
70  char collprovider = 0;
71  char *collversion = NULL;
72  Oid newoid;
73  ObjectAddress address;
74 
75  collNamespace = QualifiedNameGetCreationNamespace(names, &collName);
76 
77  aclresult = pg_namespace_aclcheck(collNamespace, GetUserId(), ACL_CREATE);
78  if (aclresult != ACLCHECK_OK)
79  aclcheck_error(aclresult, OBJECT_SCHEMA,
80  get_namespace_name(collNamespace));
81 
82  foreach(pl, parameters)
83  {
84  DefElem *defel = lfirst_node(DefElem, pl);
85  DefElem **defelp;
86 
87  if (strcmp(defel->defname, "from") == 0)
88  defelp = &fromEl;
89  else if (strcmp(defel->defname, "locale") == 0)
90  defelp = &localeEl;
91  else if (strcmp(defel->defname, "lc_collate") == 0)
92  defelp = &lccollateEl;
93  else if (strcmp(defel->defname, "lc_ctype") == 0)
94  defelp = &lcctypeEl;
95  else if (strcmp(defel->defname, "provider") == 0)
96  defelp = &providerEl;
97  else if (strcmp(defel->defname, "deterministic") == 0)
98  defelp = &deterministicEl;
99  else if (strcmp(defel->defname, "version") == 0)
100  defelp = &versionEl;
101  else
102  {
103  ereport(ERROR,
104  (errcode(ERRCODE_SYNTAX_ERROR),
105  errmsg("collation attribute \"%s\" not recognized",
106  defel->defname),
107  parser_errposition(pstate, defel->location)));
108  break;
109  }
110 
111  *defelp = defel;
112  }
113 
114  if ((localeEl && (lccollateEl || lcctypeEl))
115  || (fromEl && list_length(parameters) != 1))
116  ereport(ERROR,
117  (errcode(ERRCODE_SYNTAX_ERROR),
118  errmsg("conflicting or redundant options")));
119 
120  if (fromEl)
121  {
122  Oid collid;
123  HeapTuple tp;
124 
125  collid = get_collation_oid(defGetQualifiedName(fromEl), false);
127  if (!HeapTupleIsValid(tp))
128  elog(ERROR, "cache lookup failed for collation %u", collid);
129 
130  collcollate = pstrdup(NameStr(((Form_pg_collation) GETSTRUCT(tp))->collcollate));
131  collctype = pstrdup(NameStr(((Form_pg_collation) GETSTRUCT(tp))->collctype));
132  collprovider = ((Form_pg_collation) GETSTRUCT(tp))->collprovider;
133  collisdeterministic = ((Form_pg_collation) GETSTRUCT(tp))->collisdeterministic;
134  collencoding = ((Form_pg_collation) GETSTRUCT(tp))->collencoding;
135 
136  ReleaseSysCache(tp);
137 
138  /*
139  * Copying the "default" collation is not allowed because most code
140  * checks for DEFAULT_COLLATION_OID instead of COLLPROVIDER_DEFAULT,
141  * and so having a second collation with COLLPROVIDER_DEFAULT would
142  * not work and potentially confuse or crash some code. This could be
143  * fixed with some legwork.
144  */
145  if (collprovider == COLLPROVIDER_DEFAULT)
146  ereport(ERROR,
147  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
148  errmsg("collation \"default\" cannot be copied")));
149  }
150 
151  if (localeEl)
152  {
153  collcollate = defGetString(localeEl);
154  collctype = defGetString(localeEl);
155  }
156 
157  if (lccollateEl)
158  collcollate = defGetString(lccollateEl);
159 
160  if (lcctypeEl)
161  collctype = defGetString(lcctypeEl);
162 
163  if (providerEl)
164  collproviderstr = defGetString(providerEl);
165 
166  if (deterministicEl)
167  collisdeterministic = defGetBoolean(deterministicEl);
168 
169  if (versionEl)
170  collversion = defGetString(versionEl);
171 
172  if (collproviderstr)
173  {
174  if (pg_strcasecmp(collproviderstr, "icu") == 0)
175  collprovider = COLLPROVIDER_ICU;
176  else if (pg_strcasecmp(collproviderstr, "libc") == 0)
177  collprovider = COLLPROVIDER_LIBC;
178  else
179  ereport(ERROR,
180  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
181  errmsg("unrecognized collation provider: %s",
182  collproviderstr)));
183  }
184  else if (!fromEl)
185  collprovider = COLLPROVIDER_LIBC;
186 
187  if (!collcollate)
188  ereport(ERROR,
189  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
190  errmsg("parameter \"lc_collate\" must be specified")));
191 
192  if (!collctype)
193  ereport(ERROR,
194  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
195  errmsg("parameter \"lc_ctype\" must be specified")));
196 
197  /*
198  * Nondeterministic collations are currently only supported with ICU
199  * because that's the only case where it can actually make a difference.
200  * So we can save writing the code for the other providers.
201  */
202  if (!collisdeterministic && collprovider != COLLPROVIDER_ICU)
203  ereport(ERROR,
204  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
205  errmsg("nondeterministic collations not supported with this provider")));
206 
207  if (!fromEl)
208  {
209  if (collprovider == COLLPROVIDER_ICU)
210  collencoding = -1;
211  else
212  {
213  collencoding = GetDatabaseEncoding();
214  check_encoding_locale_matches(collencoding, collcollate, collctype);
215  }
216  }
217 
218  if (!collversion)
219  collversion = get_collation_actual_version(collprovider, collcollate);
220 
221  newoid = CollationCreate(collName,
222  collNamespace,
223  GetUserId(),
224  collprovider,
225  collisdeterministic,
226  collencoding,
227  collcollate,
228  collctype,
229  collversion,
230  if_not_exists,
231  false); /* not quiet */
232 
233  if (!OidIsValid(newoid))
234  return InvalidObjectAddress;
235 
236  /*
237  * Check that the locales can be loaded. NB: pg_newlocale_from_collation
238  * is only supposed to be called on non-C-equivalent locales.
239  */
241  if (!lc_collate_is_c(newoid) || !lc_ctype_is_c(newoid))
242  (void) pg_newlocale_from_collation(newoid);
243 
244  ObjectAddressSet(address, CollationRelationId, newoid);
245 
246  return address;
247 }
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
void check_encoding_locale_matches(int encoding, const char *collate, const char *ctype)
Definition: dbcommands.c:755
Oid GetUserId(void)
Definition: miscinit.c:448
Oid QualifiedNameGetCreationNamespace(List *names, char **objname_p)
Definition: namespace.c:2995
char * pstrdup(const char *in)
Definition: mcxt.c:1186
int errcode(int sqlerrcode)
Definition: elog.c:610
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:644
AclResult pg_namespace_aclcheck(Oid nsp_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4658
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:3327
bool defGetBoolean(DefElem *def)
Definition: define.c:111
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:43
#define ACL_CREATE
Definition: parsenodes.h:84
bool lc_collate_is_c(Oid collation)
Definition: pg_locale.c:1356
char * defGetString(DefElem *def)
Definition: define.c:49
#define lfirst_node(type, lc)
Definition: pg_list.h:193
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3155
int location
Definition: parsenodes.h:735
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1116
pg_locale_t pg_newlocale_from_collation(Oid collid)
Definition: pg_locale.c:1503
AclResult
Definition: acl.h:177
void CommandCounterIncrement(void)
Definition: xact.c:1006
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1164
int GetDatabaseEncoding(void)
Definition: mbutils.c:1151
#define ereport(elevel,...)
Definition: elog.h:144
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
List * defGetQualifiedName(DefElem *def)
Definition: define.c:223
static int list_length(const List *l)
Definition: pg_list.h:169
int parser_errposition(ParseState *pstate, int location)
Definition: parse_node.c:110
Oid CollationCreate(const char *collname, Oid collnamespace, Oid collowner, char collprovider, bool collisdeterministic, int32 collencoding, const char *collcollate, const char *collctype, const char *collversion, bool if_not_exists, bool quiet)
Definition: pg_collation.c:46
FormData_pg_collation * Form_pg_collation
Definition: pg_collation.h:51
#define ObjectAddressSet(addr, class_id, object_id)
Definition: objectaddress.h:40
const ObjectAddress InvalidObjectAddress
int errmsg(const char *fmt,...)
Definition: elog.c:824
#define elog(elevel,...)
Definition: elog.h:214
#define NameStr(name)
Definition: c.h:615
char * defname
Definition: parsenodes.h:732
bool lc_ctype_is_c(Oid collation)
Definition: pg_locale.c:1406
Oid get_collation_oid(List *name, bool missing_ok)
Definition: namespace.c:3601
char * get_collation_actual_version(char collprovider, const char *collcollate)
Definition: pg_locale.c:1680

◆ IsThereCollationInNamespace()

void IsThereCollationInNamespace ( const char *  collname,
Oid  nspOid 
)

Definition at line 256 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().

257 {
258  /* make sure the name doesn't already exist in new schema */
260  CStringGetDatum(collname),
262  ObjectIdGetDatum(nspOid)))
263  ereport(ERROR,
265  errmsg("collation \"%s\" for encoding \"%s\" already exists in schema \"%s\"",
266  collname, GetDatabaseEncodingName(),
267  get_namespace_name(nspOid))));
268 
269  /* mustn't match an any-encoding entry, either */
271  CStringGetDatum(collname),
272  Int32GetDatum(-1),
273  ObjectIdGetDatum(nspOid)))
274  ereport(ERROR,
276  errmsg("collation \"%s\" already exists in schema \"%s\"",
277  collname, get_namespace_name(nspOid))));
278 }
int errcode(int sqlerrcode)
Definition: elog.c:610
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:43
#define SearchSysCacheExists3(cacheId, key1, key2, key3)
Definition: syscache.h:187
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3155
#define CStringGetDatum(X)
Definition: postgres.h:578
int GetDatabaseEncoding(void)
Definition: mbutils.c:1151
#define ereport(elevel,...)
Definition: elog.h:144
const char * GetDatabaseEncodingName(void)
Definition: mbutils.c:1157
#define Int32GetDatum(X)
Definition: postgres.h:479
int errmsg(const char *fmt,...)
Definition: elog.c:824
#define ERRCODE_DUPLICATE_OBJECT
Definition: streamutil.c:31

◆ pg_collation_actual_version()

Datum pg_collation_actual_version ( PG_FUNCTION_ARGS  )

Definition at line 355 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(), and generate_unaccent_rules::str.

356 {
357  Oid collid = PG_GETARG_OID(0);
358  HeapTuple tp;
359  char *collcollate;
360  char collprovider;
361  char *version;
362 
364  if (!HeapTupleIsValid(tp))
365  ereport(ERROR,
366  (errcode(ERRCODE_UNDEFINED_OBJECT),
367  errmsg("collation with OID %u does not exist", collid)));
368 
369  collcollate = pstrdup(NameStr(((Form_pg_collation) GETSTRUCT(tp))->collcollate));
370  collprovider = ((Form_pg_collation) GETSTRUCT(tp))->collprovider;
371 
372  ReleaseSysCache(tp);
373 
374  version = get_collation_actual_version(collprovider, collcollate);
375 
376  if (version)
378  else
379  PG_RETURN_NULL();
380 }
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
char * pstrdup(const char *in)
Definition: mcxt.c:1186
int errcode(int sqlerrcode)
Definition: elog.c:610
unsigned int Oid
Definition: postgres_ext.h:31
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:43
#define PG_GETARG_OID(n)
Definition: fmgr.h:275
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1116
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1164
#define ereport(elevel,...)
Definition: elog.h:144
#define PG_RETURN_TEXT_P(x)
Definition: fmgr.h:370
text * cstring_to_text(const char *s)
Definition: varlena.c:172
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
FormData_pg_collation * Form_pg_collation
Definition: pg_collation.h:51
int errmsg(const char *fmt,...)
Definition: elog.c:824
#define NameStr(name)
Definition: c.h:615
#define PG_RETURN_NULL()
Definition: fmgr.h:344
char * get_collation_actual_version(char collprovider, const char *collcollate)
Definition: pg_locale.c:1680

◆ pg_import_system_collations()

Datum pg_import_system_collations ( PG_FUNCTION_ARGS  )

Definition at line 520 of file collationcmds.c.

References CollAliasData::alias, ClosePipeStream(), CollationCreate(), 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.

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