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 "common/string.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 311 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().

312 {
313  Relation rel;
314  Oid collOid;
315  HeapTuple tup;
316  Form_pg_collation collForm;
317  Datum collversion;
318  bool isnull;
319  char *oldversion;
320  char *newversion;
321  ObjectAddress address;
322 
323  rel = table_open(CollationRelationId, RowExclusiveLock);
324  collOid = get_collation_oid(stmt->collname, false);
325 
326  if (!pg_collation_ownercheck(collOid, GetUserId()))
328  NameListToString(stmt->collname));
329 
331  if (!HeapTupleIsValid(tup))
332  elog(ERROR, "cache lookup failed for collation %u", collOid);
333 
334  collForm = (Form_pg_collation) GETSTRUCT(tup);
335  collversion = SysCacheGetAttr(COLLOID, tup, Anum_pg_collation_collversion,
336  &isnull);
337  oldversion = isnull ? NULL : TextDatumGetCString(collversion);
338 
339  newversion = get_collation_actual_version(collForm->collprovider, NameStr(collForm->collcollate));
340 
341  /* cannot change from NULL to non-NULL or vice versa */
342  if ((!oldversion && newversion) || (oldversion && !newversion))
343  elog(ERROR, "invalid collation version change");
344  else if (oldversion && newversion && strcmp(newversion, oldversion) != 0)
345  {
346  bool nulls[Natts_pg_collation];
347  bool replaces[Natts_pg_collation];
348  Datum values[Natts_pg_collation];
349 
350  ereport(NOTICE,
351  (errmsg("changing version from %s to %s",
352  oldversion, newversion)));
353 
354  memset(values, 0, sizeof(values));
355  memset(nulls, false, sizeof(nulls));
356  memset(replaces, false, sizeof(replaces));
357 
358  values[Anum_pg_collation_collversion - 1] = CStringGetTextDatum(newversion);
359  replaces[Anum_pg_collation_collversion - 1] = true;
360 
361  tup = heap_modify_tuple(tup, RelationGetDescr(rel),
362  values, nulls, replaces);
363  }
364  else
365  ereport(NOTICE,
366  (errmsg("version has not changed")));
367 
368  CatalogTupleUpdate(rel, &tup->t_self, tup);
369 
370  InvokeObjectPostAlterHook(CollationRelationId, collOid, 0);
371 
372  ObjectAddressSet(address, CollationRelationId, collOid);
373 
374  heap_freetuple(tup);
375  table_close(rel, NoLock);
376 
377  return address;
378 }
bool pg_collation_ownercheck(Oid coll_oid, Oid roleid)
Definition: aclchk.c:5264
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:167
#define GETSTRUCT(TUP)
Definition: htup_details.h:654
#define RelationGetDescr(relation)
Definition: rel.h:503
Oid GetUserId(void)
Definition: miscinit.c:495
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:3308
#define ObjectIdGetDatum(X)
Definition: postgres.h:551
#define ERROR
Definition: elog.h:46
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:3147
#define TextDatumGetCString(d)
Definition: builtins.h:87
uintptr_t Datum
Definition: postgres.h:411
Datum SysCacheGetAttr(int cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition: syscache.c:1411
#define ereport(elevel,...)
Definition: elog.h:157
#define NOTICE
Definition: elog.h:37
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:301
FormData_pg_collation * Form_pg_collation
Definition: pg_collation.h:56
#define ObjectAddressSet(addr, class_id, object_id)
Definition: objectaddress.h:40
static Datum values[MAXATTR]
Definition: bootstrap.c:156
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:177
int errmsg(const char *fmt,...)
Definition: elog.c:909
#define elog(elevel,...)
Definition: elog.h:232
#define NameStr(name)
Definition: c.h:681
#define CStringGetTextDatum(s)
Definition: builtins.h:86
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:3646
char * get_collation_actual_version(char collprovider, const char *collcollate)
Definition: pg_locale.c:1645

◆ DefineCollation()

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

Definition at line 53 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(), errdetail(), errmsg(), ERROR, errorConflictingDefElem(), get_collation_actual_version(), get_collation_oid(), get_namespace_name(), GetDatabaseEncoding(), GETSTRUCT, GetUserId(), HeapTupleIsValid, InvalidObjectAddress, is_encoding_supported_by_icu(), 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().

54 {
55  char *collName;
56  Oid collNamespace;
57  AclResult aclresult;
58  ListCell *pl;
59  DefElem *fromEl = NULL;
60  DefElem *localeEl = NULL;
61  DefElem *lccollateEl = NULL;
62  DefElem *lcctypeEl = NULL;
63  DefElem *providerEl = NULL;
64  DefElem *deterministicEl = NULL;
65  DefElem *versionEl = NULL;
66  char *collcollate = NULL;
67  char *collctype = NULL;
68  char *collproviderstr = NULL;
69  bool collisdeterministic = true;
70  int collencoding = 0;
71  char collprovider = 0;
72  char *collversion = NULL;
73  Oid newoid;
74  ObjectAddress address;
75 
76  collNamespace = QualifiedNameGetCreationNamespace(names, &collName);
77 
78  aclresult = pg_namespace_aclcheck(collNamespace, GetUserId(), ACL_CREATE);
79  if (aclresult != ACLCHECK_OK)
80  aclcheck_error(aclresult, OBJECT_SCHEMA,
81  get_namespace_name(collNamespace));
82 
83  foreach(pl, parameters)
84  {
85  DefElem *defel = lfirst_node(DefElem, pl);
86  DefElem **defelp;
87 
88  if (strcmp(defel->defname, "from") == 0)
89  defelp = &fromEl;
90  else if (strcmp(defel->defname, "locale") == 0)
91  defelp = &localeEl;
92  else if (strcmp(defel->defname, "lc_collate") == 0)
93  defelp = &lccollateEl;
94  else if (strcmp(defel->defname, "lc_ctype") == 0)
95  defelp = &lcctypeEl;
96  else if (strcmp(defel->defname, "provider") == 0)
97  defelp = &providerEl;
98  else if (strcmp(defel->defname, "deterministic") == 0)
99  defelp = &deterministicEl;
100  else if (strcmp(defel->defname, "version") == 0)
101  defelp = &versionEl;
102  else
103  {
104  ereport(ERROR,
105  (errcode(ERRCODE_SYNTAX_ERROR),
106  errmsg("collation attribute \"%s\" not recognized",
107  defel->defname),
108  parser_errposition(pstate, defel->location)));
109  break;
110  }
111  if (*defelp != NULL)
112  errorConflictingDefElem(defel, pstate);
113  *defelp = defel;
114  }
115 
116  if (localeEl && (lccollateEl || lcctypeEl))
117  ereport(ERROR,
118  errcode(ERRCODE_SYNTAX_ERROR),
119  errmsg("conflicting or redundant options"),
120  errdetail("LOCALE cannot be specified together with LC_COLLATE or LC_CTYPE."));
121 
122  if (fromEl && list_length(parameters) != 1)
123  ereport(ERROR,
124  errcode(ERRCODE_SYNTAX_ERROR),
125  errmsg("conflicting or redundant options"),
126  errdetail("FROM cannot be specified together with any other options."));
127 
128  if (fromEl)
129  {
130  Oid collid;
131  HeapTuple tp;
132 
133  collid = get_collation_oid(defGetQualifiedName(fromEl), false);
135  if (!HeapTupleIsValid(tp))
136  elog(ERROR, "cache lookup failed for collation %u", collid);
137 
138  collcollate = pstrdup(NameStr(((Form_pg_collation) GETSTRUCT(tp))->collcollate));
139  collctype = pstrdup(NameStr(((Form_pg_collation) GETSTRUCT(tp))->collctype));
140  collprovider = ((Form_pg_collation) GETSTRUCT(tp))->collprovider;
141  collisdeterministic = ((Form_pg_collation) GETSTRUCT(tp))->collisdeterministic;
142  collencoding = ((Form_pg_collation) GETSTRUCT(tp))->collencoding;
143 
144  ReleaseSysCache(tp);
145 
146  /*
147  * Copying the "default" collation is not allowed because most code
148  * checks for DEFAULT_COLLATION_OID instead of COLLPROVIDER_DEFAULT,
149  * and so having a second collation with COLLPROVIDER_DEFAULT would
150  * not work and potentially confuse or crash some code. This could be
151  * fixed with some legwork.
152  */
153  if (collprovider == COLLPROVIDER_DEFAULT)
154  ereport(ERROR,
155  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
156  errmsg("collation \"default\" cannot be copied")));
157  }
158 
159  if (localeEl)
160  {
161  collcollate = defGetString(localeEl);
162  collctype = defGetString(localeEl);
163  }
164 
165  if (lccollateEl)
166  collcollate = defGetString(lccollateEl);
167 
168  if (lcctypeEl)
169  collctype = defGetString(lcctypeEl);
170 
171  if (providerEl)
172  collproviderstr = defGetString(providerEl);
173 
174  if (deterministicEl)
175  collisdeterministic = defGetBoolean(deterministicEl);
176 
177  if (versionEl)
178  collversion = defGetString(versionEl);
179 
180  if (collproviderstr)
181  {
182  if (pg_strcasecmp(collproviderstr, "icu") == 0)
183  collprovider = COLLPROVIDER_ICU;
184  else if (pg_strcasecmp(collproviderstr, "libc") == 0)
185  collprovider = COLLPROVIDER_LIBC;
186  else
187  ereport(ERROR,
188  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
189  errmsg("unrecognized collation provider: %s",
190  collproviderstr)));
191  }
192  else if (!fromEl)
193  collprovider = COLLPROVIDER_LIBC;
194 
195  if (!collcollate)
196  ereport(ERROR,
197  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
198  errmsg("parameter \"lc_collate\" must be specified")));
199 
200  if (!collctype)
201  ereport(ERROR,
202  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
203  errmsg("parameter \"lc_ctype\" must be specified")));
204 
205  /*
206  * Nondeterministic collations are currently only supported with ICU
207  * because that's the only case where it can actually make a difference.
208  * So we can save writing the code for the other providers.
209  */
210  if (!collisdeterministic && collprovider != COLLPROVIDER_ICU)
211  ereport(ERROR,
212  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
213  errmsg("nondeterministic collations not supported with this provider")));
214 
215  if (!fromEl)
216  {
217  if (collprovider == COLLPROVIDER_ICU)
218  {
219 #ifdef USE_ICU
220  /*
221  * We could create ICU collations with collencoding == database
222  * encoding, but it seems better to use -1 so that it matches the
223  * way initdb would create ICU collations. However, only allow
224  * one to be created when the current database's encoding is
225  * supported. Otherwise the collation is useless, plus we get
226  * surprising behaviors like not being able to drop the collation.
227  *
228  * Skip this test when !USE_ICU, because the error we want to
229  * throw for that isn't thrown till later.
230  */
232  ereport(ERROR,
233  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
234  errmsg("current database's encoding is not supported with this provider")));
235 #endif
236  collencoding = -1;
237  }
238  else
239  {
240  collencoding = GetDatabaseEncoding();
241  check_encoding_locale_matches(collencoding, collcollate, collctype);
242  }
243  }
244 
245  if (!collversion)
246  collversion = get_collation_actual_version(collprovider, collcollate);
247 
248  newoid = CollationCreate(collName,
249  collNamespace,
250  GetUserId(),
251  collprovider,
252  collisdeterministic,
253  collencoding,
254  collcollate,
255  collctype,
256  collversion,
257  if_not_exists,
258  false); /* not quiet */
259 
260  if (!OidIsValid(newoid))
261  return InvalidObjectAddress;
262 
263  /*
264  * Check that the locales can be loaded. NB: pg_newlocale_from_collation
265  * is only supposed to be called on non-C-equivalent locales.
266  */
268  if (!lc_collate_is_c(newoid) || !lc_ctype_is_c(newoid))
269  (void) pg_newlocale_from_collation(newoid);
270 
271  ObjectAddressSet(address, CollationRelationId, newoid);
272 
273  return address;
274 }
#define GETSTRUCT(TUP)
Definition: htup_details.h:654
void check_encoding_locale_matches(int encoding, const char *collate, const char *ctype)
Definition: dbcommands.c:725
Oid GetUserId(void)
Definition: miscinit.c:495
Oid QualifiedNameGetCreationNamespace(List *names, char **objname_p)
Definition: namespace.c:3040
char * pstrdup(const char *in)
Definition: mcxt.c:1299
bool is_encoding_supported_by_icu(int encoding)
Definition: encnames.c:459
int errcode(int sqlerrcode)
Definition: elog.c:698
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:710
AclResult pg_namespace_aclcheck(Oid nsp_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4758
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:3308
bool defGetBoolean(DefElem *def)
Definition: define.c:106
#define ObjectIdGetDatum(X)
Definition: postgres.h:551
#define ERROR
Definition: elog.h:46
#define ACL_CREATE
Definition: parsenodes.h:92
bool lc_collate_is_c(Oid collation)
Definition: pg_locale.c:1321
char * defGetString(DefElem *def)
Definition: define.c:49
#define lfirst_node(type, lc)
Definition: pg_list.h:172
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3316
int location
Definition: parsenodes.h:761
int errdetail(const char *fmt,...)
Definition: elog.c:1042
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1150
pg_locale_t pg_newlocale_from_collation(Oid collid)
Definition: pg_locale.c:1468
AclResult
Definition: acl.h:177
void CommandCounterIncrement(void)
Definition: xact.c:1022
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1198
int GetDatabaseEncoding(void)
Definition: mbutils.c:1210
#define ereport(elevel,...)
Definition: elog.h:157
void errorConflictingDefElem(DefElem *defel, ParseState *pstate)
Definition: define.c:350
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
List * defGetQualifiedName(DefElem *def)
Definition: define.c:218
static int list_length(const List *l)
Definition: pg_list.h:149
int parser_errposition(ParseState *pstate, int location)
Definition: parse_node.c:111
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:56
#define ObjectAddressSet(addr, class_id, object_id)
Definition: objectaddress.h:40
const ObjectAddress InvalidObjectAddress
int errmsg(const char *fmt,...)
Definition: elog.c:909
#define elog(elevel,...)
Definition: elog.h:232
#define NameStr(name)
Definition: c.h:681
char * defname
Definition: parsenodes.h:758
bool lc_ctype_is_c(Oid collation)
Definition: pg_locale.c:1371
Oid get_collation_oid(List *name, bool missing_ok)
Definition: namespace.c:3646
char * get_collation_actual_version(char collprovider, const char *collcollate)
Definition: pg_locale.c:1645

◆ IsThereCollationInNamespace()

void IsThereCollationInNamespace ( const char *  collname,
Oid  nspOid 
)

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

284 {
285  /* make sure the name doesn't already exist in new schema */
287  CStringGetDatum(collname),
289  ObjectIdGetDatum(nspOid)))
290  ereport(ERROR,
292  errmsg("collation \"%s\" for encoding \"%s\" already exists in schema \"%s\"",
293  collname, GetDatabaseEncodingName(),
294  get_namespace_name(nspOid))));
295 
296  /* mustn't match an any-encoding entry, either */
298  CStringGetDatum(collname),
299  Int32GetDatum(-1),
300  ObjectIdGetDatum(nspOid)))
301  ereport(ERROR,
303  errmsg("collation \"%s\" already exists in schema \"%s\"",
304  collname, get_namespace_name(nspOid))));
305 }
int errcode(int sqlerrcode)
Definition: elog.c:698
#define ObjectIdGetDatum(X)
Definition: postgres.h:551
#define ERROR
Definition: elog.h:46
#define SearchSysCacheExists3(cacheId, key1, key2, key3)
Definition: syscache.h:190
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3316
#define CStringGetDatum(X)
Definition: postgres.h:622
int GetDatabaseEncoding(void)
Definition: mbutils.c:1210
#define ereport(elevel,...)
Definition: elog.h:157
const char * GetDatabaseEncodingName(void)
Definition: mbutils.c:1216
#define Int32GetDatum(X)
Definition: postgres.h:523
int errmsg(const char *fmt,...)
Definition: elog.c:909
#define ERRCODE_DUPLICATE_OBJECT
Definition: streamutil.c:32

◆ pg_collation_actual_version()

Datum pg_collation_actual_version ( PG_FUNCTION_ARGS  )

Definition at line 382 of file collationcmds.c.

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

383 {
384  Oid collid = PG_GETARG_OID(0);
385  HeapTuple tp;
386  char *collcollate;
387  char collprovider;
388  char *version;
389 
391  if (!HeapTupleIsValid(tp))
392  ereport(ERROR,
393  (errcode(ERRCODE_UNDEFINED_OBJECT),
394  errmsg("collation with OID %u does not exist", collid)));
395 
396  collcollate = pstrdup(NameStr(((Form_pg_collation) GETSTRUCT(tp))->collcollate));
397  collprovider = ((Form_pg_collation) GETSTRUCT(tp))->collprovider;
398 
399  ReleaseSysCache(tp);
400 
401  version = get_collation_actual_version(collprovider, collcollate);
402 
403  if (version)
405  else
406  PG_RETURN_NULL();
407 }
#define GETSTRUCT(TUP)
Definition: htup_details.h:654
char * pstrdup(const char *in)
Definition: mcxt.c:1299
int errcode(int sqlerrcode)
Definition: elog.c:698
unsigned int Oid
Definition: postgres_ext.h:31
#define ObjectIdGetDatum(X)
Definition: postgres.h:551
#define ERROR
Definition: elog.h:46
#define PG_GETARG_OID(n)
Definition: fmgr.h:275
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1150
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1198
#define ereport(elevel,...)
Definition: elog.h:157
#define PG_RETURN_TEXT_P(x)
Definition: fmgr.h:372
text * cstring_to_text(const char *s)
Definition: varlena.c:189
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
FormData_pg_collation * Form_pg_collation
Definition: pg_collation.h:56
int errmsg(const char *fmt,...)
Definition: elog.c:909
#define NameStr(name)
Definition: c.h:681
#define PG_RETURN_NULL()
Definition: fmgr.h:345
char * get_collation_actual_version(char collprovider, const char *collcollate)
Definition: pg_locale.c:1645

◆ pg_import_system_collations()

Datum pg_import_system_collations ( PG_FUNCTION_ARGS  )

Definition at line 530 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, NAMESPACEOID, ObjectIdGetDatum, OidIsValid, OpenPipeStream(), palloc(), pg_get_encoding_from_locale(), PG_GETARG_OID, pg_is_ascii(), PG_RETURN_INT32, PG_SQL_ASCII, PG_VALID_BE_ENCODING, psprintf(), pstrdup(), qsort, repalloc(), SearchSysCacheExists1, superuser(), and WARNING.

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