PostgreSQL Source Code  git master
collationcmds.h File Reference
Include dependency graph for collationcmds.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Functions

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

Function Documentation

◆ AlterCollation()

ObjectAddress AlterCollation ( AlterCollationStmt stmt)

Definition at line 353 of file collationcmds.c.

354 {
355  Relation rel;
356  Oid collOid;
357  HeapTuple tup;
358  Form_pg_collation collForm;
359  Datum datum;
360  bool isnull;
361  char *oldversion;
362  char *newversion;
363  ObjectAddress address;
364 
365  rel = table_open(CollationRelationId, RowExclusiveLock);
366  collOid = get_collation_oid(stmt->collname, false);
367 
368  if (!pg_collation_ownercheck(collOid, GetUserId()))
370  NameListToString(stmt->collname));
371 
373  if (!HeapTupleIsValid(tup))
374  elog(ERROR, "cache lookup failed for collation %u", collOid);
375 
376  collForm = (Form_pg_collation) GETSTRUCT(tup);
377  datum = SysCacheGetAttr(COLLOID, tup, Anum_pg_collation_collversion, &isnull);
378  oldversion = isnull ? NULL : TextDatumGetCString(datum);
379 
380  datum = SysCacheGetAttr(COLLOID, tup, collForm->collprovider == COLLPROVIDER_ICU ? Anum_pg_collation_colliculocale : Anum_pg_collation_collcollate, &isnull);
381  if (isnull)
382  elog(ERROR, "unexpected null in pg_collation");
383  newversion = get_collation_actual_version(collForm->collprovider, TextDatumGetCString(datum));
384 
385  /* cannot change from NULL to non-NULL or vice versa */
386  if ((!oldversion && newversion) || (oldversion && !newversion))
387  elog(ERROR, "invalid collation version change");
388  else if (oldversion && newversion && strcmp(newversion, oldversion) != 0)
389  {
390  bool nulls[Natts_pg_collation];
391  bool replaces[Natts_pg_collation];
392  Datum values[Natts_pg_collation];
393 
394  ereport(NOTICE,
395  (errmsg("changing version from %s to %s",
396  oldversion, newversion)));
397 
398  memset(values, 0, sizeof(values));
399  memset(nulls, false, sizeof(nulls));
400  memset(replaces, false, sizeof(replaces));
401 
402  values[Anum_pg_collation_collversion - 1] = CStringGetTextDatum(newversion);
403  replaces[Anum_pg_collation_collversion - 1] = true;
404 
405  tup = heap_modify_tuple(tup, RelationGetDescr(rel),
406  values, nulls, replaces);
407  }
408  else
409  ereport(NOTICE,
410  (errmsg("version has not changed")));
411 
412  CatalogTupleUpdate(rel, &tup->t_self, tup);
413 
414  InvokeObjectPostAlterHook(CollationRelationId, collOid, 0);
415 
416  ObjectAddressSet(address, CollationRelationId, collOid);
417 
418  heap_freetuple(tup);
419  table_close(rel, NoLock);
420 
421  return address;
422 }
@ ACLCHECK_NOT_OWNER
Definition: acl.h:184
bool pg_collation_ownercheck(Oid coll_oid, Oid roleid)
Definition: aclchk.c:5615
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:3512
static Datum values[MAXATTR]
Definition: bootstrap.c:156
#define CStringGetTextDatum(s)
Definition: builtins.h:85
#define TextDatumGetCString(d)
Definition: builtins.h:86
int errmsg(const char *fmt,...)
Definition: elog.c:904
#define ERROR
Definition: elog.h:33
#define NOTICE
Definition: elog.h:29
#define ereport(elevel,...)
Definition: elog.h:143
HeapTuple heap_modify_tuple(HeapTuple tuple, TupleDesc tupleDesc, Datum *replValues, bool *replIsnull, bool *doReplace)
Definition: heaptuple.c:1113
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1338
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define GETSTRUCT(TUP)
Definition: htup_details.h:649
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:301
#define NoLock
Definition: lockdefs.h:34
#define RowExclusiveLock
Definition: lockdefs.h:38
Oid GetUserId(void)
Definition: miscinit.c:491
Oid get_collation_oid(List *name, bool missing_ok)
Definition: namespace.c:3647
char * NameListToString(List *names)
Definition: namespace.c:3148
#define InvokeObjectPostAlterHook(classId, objectId, subId)
Definition: objectaccess.h:195
#define ObjectAddressSet(addr, class_id, object_id)
Definition: objectaddress.h:40
@ OBJECT_COLLATION
Definition: parsenodes.h:2142
FormData_pg_collation * Form_pg_collation
Definition: pg_collation.h:57
char * get_collation_actual_version(char collprovider, const char *collcollate)
Definition: pg_locale.c:1674
uintptr_t Datum
Definition: postgres.h:411
#define ObjectIdGetDatum(X)
Definition: postgres.h:551
unsigned int Oid
Definition: postgres_ext.h:31
#define RelationGetDescr(relation)
Definition: rel.h:514
ItemPointerData t_self
Definition: htup.h:65
Datum SysCacheGetAttr(int cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition: syscache.c:1434
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:179
@ COLLOID
Definition: syscache.h:50
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:167
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39

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(), 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().

◆ DefineCollation()

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

Definition at line 53 of file collationcmds.c.

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;
67  char *collctype;
68  char *colliculocale;
69  bool collisdeterministic;
70  int collencoding;
71  char collprovider;
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  Datum datum;
133  bool isnull;
134 
135  collid = get_collation_oid(defGetQualifiedName(fromEl), false);
137  if (!HeapTupleIsValid(tp))
138  elog(ERROR, "cache lookup failed for collation %u", collid);
139 
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  datum = SysCacheGetAttr(COLLOID, tp, Anum_pg_collation_collcollate, &isnull);
145  if (!isnull)
146  collcollate = TextDatumGetCString(datum);
147  else
148  collcollate = NULL;
149 
150  datum = SysCacheGetAttr(COLLOID, tp, Anum_pg_collation_collctype, &isnull);
151  if (!isnull)
152  collctype = TextDatumGetCString(datum);
153  else
154  collctype = NULL;
155 
156  datum = SysCacheGetAttr(COLLOID, tp, Anum_pg_collation_colliculocale, &isnull);
157  if (!isnull)
158  colliculocale = TextDatumGetCString(datum);
159  else
160  colliculocale = NULL;
161 
162  ReleaseSysCache(tp);
163 
164  /*
165  * Copying the "default" collation is not allowed because most code
166  * checks for DEFAULT_COLLATION_OID instead of COLLPROVIDER_DEFAULT,
167  * and so having a second collation with COLLPROVIDER_DEFAULT would
168  * not work and potentially confuse or crash some code. This could be
169  * fixed with some legwork.
170  */
171  if (collprovider == COLLPROVIDER_DEFAULT)
172  ereport(ERROR,
173  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
174  errmsg("collation \"default\" cannot be copied")));
175  }
176  else
177  {
178  char *collproviderstr = NULL;
179 
180  collcollate = NULL;
181  collctype = NULL;
182  colliculocale = NULL;
183 
184  if (providerEl)
185  collproviderstr = defGetString(providerEl);
186 
187  if (deterministicEl)
188  collisdeterministic = defGetBoolean(deterministicEl);
189  else
190  collisdeterministic = true;
191 
192  if (versionEl)
193  collversion = defGetString(versionEl);
194 
195  if (collproviderstr)
196  {
197  if (pg_strcasecmp(collproviderstr, "icu") == 0)
198  collprovider = COLLPROVIDER_ICU;
199  else if (pg_strcasecmp(collproviderstr, "libc") == 0)
200  collprovider = COLLPROVIDER_LIBC;
201  else
202  ereport(ERROR,
203  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
204  errmsg("unrecognized collation provider: %s",
205  collproviderstr)));
206  }
207  else
208  collprovider = COLLPROVIDER_LIBC;
209 
210  if (localeEl)
211  {
212  if (collprovider == COLLPROVIDER_LIBC)
213  {
214  collcollate = defGetString(localeEl);
215  collctype = defGetString(localeEl);
216  }
217  else
218  colliculocale = defGetString(localeEl);
219  }
220 
221  if (lccollateEl)
222  collcollate = defGetString(lccollateEl);
223 
224  if (lcctypeEl)
225  collctype = defGetString(lcctypeEl);
226 
227  if (collprovider == COLLPROVIDER_LIBC)
228  {
229  if (!collcollate)
230  ereport(ERROR,
231  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
232  errmsg("parameter \"lc_collate\" must be specified")));
233 
234  if (!collctype)
235  ereport(ERROR,
236  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
237  errmsg("parameter \"lc_ctype\" must be specified")));
238  }
239  else if (collprovider == COLLPROVIDER_ICU)
240  {
241  if (!colliculocale)
242  ereport(ERROR,
243  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
244  errmsg("parameter \"locale\" must be specified")));
245  }
246 
247  /*
248  * Nondeterministic collations are currently only supported with ICU
249  * because that's the only case where it can actually make a
250  * difference. So we can save writing the code for the other
251  * providers.
252  */
253  if (!collisdeterministic && collprovider != COLLPROVIDER_ICU)
254  ereport(ERROR,
255  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
256  errmsg("nondeterministic collations not supported with this provider")));
257 
258  if (collprovider == COLLPROVIDER_ICU)
259  {
260 #ifdef USE_ICU
261  /*
262  * We could create ICU collations with collencoding == database
263  * encoding, but it seems better to use -1 so that it matches the
264  * way initdb would create ICU collations. However, only allow
265  * one to be created when the current database's encoding is
266  * supported. Otherwise the collation is useless, plus we get
267  * surprising behaviors like not being able to drop the collation.
268  *
269  * Skip this test when !USE_ICU, because the error we want to
270  * throw for that isn't thrown till later.
271  */
273  ereport(ERROR,
274  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
275  errmsg("current database's encoding is not supported with this provider")));
276 #endif
277  collencoding = -1;
278  }
279  else
280  {
281  collencoding = GetDatabaseEncoding();
282  check_encoding_locale_matches(collencoding, collcollate, collctype);
283  }
284  }
285 
286  if (!collversion)
287  collversion = get_collation_actual_version(collprovider, collprovider == COLLPROVIDER_ICU ? colliculocale : collcollate);
288 
289  newoid = CollationCreate(collName,
290  collNamespace,
291  GetUserId(),
292  collprovider,
293  collisdeterministic,
294  collencoding,
295  collcollate,
296  collctype,
297  colliculocale,
298  collversion,
299  if_not_exists,
300  false); /* not quiet */
301 
302  if (!OidIsValid(newoid))
303  return InvalidObjectAddress;
304 
305  /*
306  * Check that the locales can be loaded. NB: pg_newlocale_from_collation
307  * is only supposed to be called on non-C-equivalent locales.
308  */
310  if (!lc_collate_is_c(newoid) || !lc_ctype_is_c(newoid))
311  (void) pg_newlocale_from_collation(newoid);
312 
313  ObjectAddressSet(address, CollationRelationId, newoid);
314 
315  return address;
316 }
AclResult
Definition: acl.h:181
@ ACLCHECK_OK
Definition: acl.h:182
AclResult pg_namespace_aclcheck(Oid nsp_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:5109
#define OidIsValid(objectId)
Definition: c.h:721
void check_encoding_locale_matches(int encoding, const char *collate, const char *ctype)
Definition: dbcommands.c:1434
bool defGetBoolean(DefElem *def)
Definition: define.c:108
List * defGetQualifiedName(DefElem *def)
Definition: define.c:220
char * defGetString(DefElem *def)
Definition: define.c:49
void errorConflictingDefElem(DefElem *defel, ParseState *pstate)
Definition: define.c:352
int errdetail(const char *fmt,...)
Definition: elog.c:1037
int errcode(int sqlerrcode)
Definition: elog.c:693
bool is_encoding_supported_by_icu(int encoding)
Definition: encnames.c:459
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3326
int GetDatabaseEncoding(void)
Definition: mbutils.c:1210
Oid QualifiedNameGetCreationNamespace(List *names, char **objname_p)
Definition: namespace.c:3041
const ObjectAddress InvalidObjectAddress
int parser_errposition(ParseState *pstate, int location)
Definition: parse_node.c:110
@ OBJECT_SCHEMA
Definition: parsenodes.h:2171
#define ACL_CREATE
Definition: parsenodes.h:91
Oid CollationCreate(const char *collname, Oid collnamespace, Oid collowner, char collprovider, bool collisdeterministic, int32 collencoding, const char *collcollate, const char *collctype, const char *colliculocale, const char *collversion, bool if_not_exists, bool quiet)
Definition: pg_collation.c:46
#define lfirst_node(type, lc)
Definition: pg_list.h:174
static int list_length(const List *l)
Definition: pg_list.h:150
bool lc_collate_is_c(Oid collation)
Definition: pg_locale.c:1326
pg_locale_t pg_newlocale_from_collation(Oid collid)
Definition: pg_locale.c:1508
bool lc_ctype_is_c(Oid collation)
Definition: pg_locale.c:1379
int pg_strcasecmp(const char *s1, const char *s2)
Definition: pgstrcasecmp.c:36
char * defname
Definition: parsenodes.h:766
int location
Definition: parsenodes.h:770
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1221
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1173
void CommandCounterIncrement(void)
Definition: xact.c:1074

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, OBJECT_SCHEMA, ObjectAddressSet, ObjectIdGetDatum, OidIsValid, parser_errposition(), pg_namespace_aclcheck(), pg_newlocale_from_collation(), pg_strcasecmp(), QualifiedNameGetCreationNamespace(), ReleaseSysCache(), SearchSysCache1(), SysCacheGetAttr(), and TextDatumGetCString.

Referenced by ProcessUtilitySlow().

◆ IsThereCollationInNamespace()

void IsThereCollationInNamespace ( const char *  collname,
Oid  nspOid 
)

Definition at line 325 of file collationcmds.c.

326 {
327  /* make sure the name doesn't already exist in new schema */
329  CStringGetDatum(collname),
331  ObjectIdGetDatum(nspOid)))
332  ereport(ERROR,
334  errmsg("collation \"%s\" for encoding \"%s\" already exists in schema \"%s\"",
335  collname, GetDatabaseEncodingName(),
336  get_namespace_name(nspOid))));
337 
338  /* mustn't match an any-encoding entry, either */
340  CStringGetDatum(collname),
341  Int32GetDatum(-1),
342  ObjectIdGetDatum(nspOid)))
343  ereport(ERROR,
345  errmsg("collation \"%s\" already exists in schema \"%s\"",
346  collname, get_namespace_name(nspOid))));
347 }
const char * GetDatabaseEncodingName(void)
Definition: mbutils.c:1216
#define CStringGetDatum(X)
Definition: postgres.h:622
#define Int32GetDatum(X)
Definition: postgres.h:523
#define ERRCODE_DUPLICATE_OBJECT
Definition: streamutil.c:32
@ COLLNAMEENCNSP
Definition: syscache.h:49
#define SearchSysCacheExists3(cacheId, key1, key2, key3)
Definition: syscache.h:192

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().