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 355 of file collationcmds.c.

356 {
357  Relation rel;
358  Oid collOid;
359  HeapTuple tup;
360  Form_pg_collation collForm;
361  Datum datum;
362  bool isnull;
363  char *oldversion;
364  char *newversion;
365  ObjectAddress address;
366 
367  rel = table_open(CollationRelationId, RowExclusiveLock);
368  collOid = get_collation_oid(stmt->collname, false);
369 
370  if (collOid == DEFAULT_COLLATION_OID)
371  ereport(ERROR,
372  (errmsg("cannot refresh version of default collation"),
373  errhint("Use ALTER DATABASE ... REFRESH COLLATION VERSION instead.")));
374 
375  if (!object_ownercheck(CollationRelationId, collOid, GetUserId()))
377  NameListToString(stmt->collname));
378 
380  if (!HeapTupleIsValid(tup))
381  elog(ERROR, "cache lookup failed for collation %u", collOid);
382 
383  collForm = (Form_pg_collation) GETSTRUCT(tup);
384  datum = SysCacheGetAttr(COLLOID, tup, Anum_pg_collation_collversion, &isnull);
385  oldversion = isnull ? NULL : TextDatumGetCString(datum);
386 
387  datum = SysCacheGetAttr(COLLOID, tup, collForm->collprovider == COLLPROVIDER_ICU ? Anum_pg_collation_colliculocale : Anum_pg_collation_collcollate, &isnull);
388  if (isnull)
389  elog(ERROR, "unexpected null in pg_collation");
390  newversion = get_collation_actual_version(collForm->collprovider, TextDatumGetCString(datum));
391 
392  /* cannot change from NULL to non-NULL or vice versa */
393  if ((!oldversion && newversion) || (oldversion && !newversion))
394  elog(ERROR, "invalid collation version change");
395  else if (oldversion && newversion && strcmp(newversion, oldversion) != 0)
396  {
397  bool nulls[Natts_pg_collation];
398  bool replaces[Natts_pg_collation];
399  Datum values[Natts_pg_collation];
400 
401  ereport(NOTICE,
402  (errmsg("changing version from %s to %s",
403  oldversion, newversion)));
404 
405  memset(values, 0, sizeof(values));
406  memset(nulls, false, sizeof(nulls));
407  memset(replaces, false, sizeof(replaces));
408 
409  values[Anum_pg_collation_collversion - 1] = CStringGetTextDatum(newversion);
410  replaces[Anum_pg_collation_collversion - 1] = true;
411 
412  tup = heap_modify_tuple(tup, RelationGetDescr(rel),
413  values, nulls, replaces);
414  }
415  else
416  ereport(NOTICE,
417  (errmsg("version has not changed")));
418 
419  CatalogTupleUpdate(rel, &tup->t_self, tup);
420 
421  InvokeObjectPostAlterHook(CollationRelationId, collOid, 0);
422 
423  ObjectAddressSet(address, CollationRelationId, collOid);
424 
425  heap_freetuple(tup);
426  table_close(rel, NoLock);
427 
428  return address;
429 }
@ ACLCHECK_NOT_OWNER
Definition: acl.h:185
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:2679
bool object_ownercheck(Oid classid, Oid objectid, Oid roleid)
Definition: aclchk.c:3984
static Datum values[MAXATTR]
Definition: bootstrap.c:156
#define CStringGetTextDatum(s)
Definition: builtins.h:94
#define TextDatumGetCString(d)
Definition: builtins.h:95
int errhint(const char *fmt,...)
Definition: elog.c:1316
int errmsg(const char *fmt,...)
Definition: elog.c:1069
#define ERROR
Definition: elog.h:39
#define NOTICE
Definition: elog.h:35
#define ereport(elevel,...)
Definition: elog.h:149
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:653
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:502
Oid get_collation_oid(List *collname, bool missing_ok)
Definition: namespace.c:3644
char * NameListToString(List *names)
Definition: namespace.c:3145
#define InvokeObjectPostAlterHook(classId, objectId, subId)
Definition: objectaccess.h:197
#define ObjectAddressSet(addr, class_id, object_id)
Definition: objectaddress.h:40
@ OBJECT_COLLATION
Definition: parsenodes.h:1976
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:1647
uintptr_t Datum
Definition: postgres.h:64
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:252
unsigned int Oid
Definition: postgres_ext.h:31
#define RelationGetDescr(relation)
Definition: rel.h:527
ItemPointerData t_self
Definition: htup.h:65
Datum SysCacheGetAttr(int cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition: syscache.c:1078
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:179
@ COLLOID
Definition: syscache.h:50
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:126
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:40

References aclcheck_error(), ACLCHECK_NOT_OWNER, CatalogTupleUpdate(), AlterCollationStmt::collname, COLLOID, CStringGetTextDatum, elog(), ereport, errhint(), errmsg(), ERROR, get_collation_actual_version(), get_collation_oid(), GETSTRUCT, GetUserId(), heap_freetuple(), heap_modify_tuple(), HeapTupleIsValid, InvokeObjectPostAlterHook, NameListToString(), NoLock, NOTICE, OBJECT_COLLATION, object_ownercheck(), ObjectAddressSet, ObjectIdGetDatum(), 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 55 of file collationcmds.c.

56 {
57  char *collName;
58  Oid collNamespace;
59  AclResult aclresult;
60  ListCell *pl;
61  DefElem *fromEl = NULL;
62  DefElem *localeEl = NULL;
63  DefElem *lccollateEl = NULL;
64  DefElem *lcctypeEl = NULL;
65  DefElem *providerEl = NULL;
66  DefElem *deterministicEl = NULL;
67  DefElem *versionEl = NULL;
68  char *collcollate;
69  char *collctype;
70  char *colliculocale;
71  bool collisdeterministic;
72  int collencoding;
73  char collprovider;
74  char *collversion = NULL;
75  Oid newoid;
76  ObjectAddress address;
77 
78  collNamespace = QualifiedNameGetCreationNamespace(names, &collName);
79 
80  aclresult = object_aclcheck(NamespaceRelationId, collNamespace, GetUserId(), ACL_CREATE);
81  if (aclresult != ACLCHECK_OK)
82  aclcheck_error(aclresult, OBJECT_SCHEMA,
83  get_namespace_name(collNamespace));
84 
85  foreach(pl, parameters)
86  {
87  DefElem *defel = lfirst_node(DefElem, pl);
88  DefElem **defelp;
89 
90  if (strcmp(defel->defname, "from") == 0)
91  defelp = &fromEl;
92  else if (strcmp(defel->defname, "locale") == 0)
93  defelp = &localeEl;
94  else if (strcmp(defel->defname, "lc_collate") == 0)
95  defelp = &lccollateEl;
96  else if (strcmp(defel->defname, "lc_ctype") == 0)
97  defelp = &lcctypeEl;
98  else if (strcmp(defel->defname, "provider") == 0)
99  defelp = &providerEl;
100  else if (strcmp(defel->defname, "deterministic") == 0)
101  defelp = &deterministicEl;
102  else if (strcmp(defel->defname, "version") == 0)
103  defelp = &versionEl;
104  else
105  {
106  ereport(ERROR,
107  (errcode(ERRCODE_SYNTAX_ERROR),
108  errmsg("collation attribute \"%s\" not recognized",
109  defel->defname),
110  parser_errposition(pstate, defel->location)));
111  break;
112  }
113  if (*defelp != NULL)
114  errorConflictingDefElem(defel, pstate);
115  *defelp = defel;
116  }
117 
118  if (localeEl && (lccollateEl || lcctypeEl))
119  ereport(ERROR,
120  errcode(ERRCODE_SYNTAX_ERROR),
121  errmsg("conflicting or redundant options"),
122  errdetail("LOCALE cannot be specified together with LC_COLLATE or LC_CTYPE."));
123 
124  if (fromEl && list_length(parameters) != 1)
125  ereport(ERROR,
126  errcode(ERRCODE_SYNTAX_ERROR),
127  errmsg("conflicting or redundant options"),
128  errdetail("FROM cannot be specified together with any other options."));
129 
130  if (fromEl)
131  {
132  Oid collid;
133  HeapTuple tp;
134  Datum datum;
135  bool isnull;
136 
137  collid = get_collation_oid(defGetQualifiedName(fromEl), false);
139  if (!HeapTupleIsValid(tp))
140  elog(ERROR, "cache lookup failed for collation %u", collid);
141 
142  collprovider = ((Form_pg_collation) GETSTRUCT(tp))->collprovider;
143  collisdeterministic = ((Form_pg_collation) GETSTRUCT(tp))->collisdeterministic;
144  collencoding = ((Form_pg_collation) GETSTRUCT(tp))->collencoding;
145 
146  datum = SysCacheGetAttr(COLLOID, tp, Anum_pg_collation_collcollate, &isnull);
147  if (!isnull)
148  collcollate = TextDatumGetCString(datum);
149  else
150  collcollate = NULL;
151 
152  datum = SysCacheGetAttr(COLLOID, tp, Anum_pg_collation_collctype, &isnull);
153  if (!isnull)
154  collctype = TextDatumGetCString(datum);
155  else
156  collctype = NULL;
157 
158  datum = SysCacheGetAttr(COLLOID, tp, Anum_pg_collation_colliculocale, &isnull);
159  if (!isnull)
160  colliculocale = TextDatumGetCString(datum);
161  else
162  colliculocale = NULL;
163 
164  ReleaseSysCache(tp);
165 
166  /*
167  * Copying the "default" collation is not allowed because most code
168  * checks for DEFAULT_COLLATION_OID instead of COLLPROVIDER_DEFAULT,
169  * and so having a second collation with COLLPROVIDER_DEFAULT would
170  * not work and potentially confuse or crash some code. This could be
171  * fixed with some legwork.
172  */
173  if (collprovider == COLLPROVIDER_DEFAULT)
174  ereport(ERROR,
175  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
176  errmsg("collation \"default\" cannot be copied")));
177  }
178  else
179  {
180  char *collproviderstr = NULL;
181 
182  collcollate = NULL;
183  collctype = NULL;
184  colliculocale = NULL;
185 
186  if (providerEl)
187  collproviderstr = defGetString(providerEl);
188 
189  if (deterministicEl)
190  collisdeterministic = defGetBoolean(deterministicEl);
191  else
192  collisdeterministic = true;
193 
194  if (versionEl)
195  collversion = defGetString(versionEl);
196 
197  if (collproviderstr)
198  {
199  if (pg_strcasecmp(collproviderstr, "icu") == 0)
200  collprovider = COLLPROVIDER_ICU;
201  else if (pg_strcasecmp(collproviderstr, "libc") == 0)
202  collprovider = COLLPROVIDER_LIBC;
203  else
204  ereport(ERROR,
205  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
206  errmsg("unrecognized collation provider: %s",
207  collproviderstr)));
208  }
209  else
210  collprovider = COLLPROVIDER_LIBC;
211 
212  if (localeEl)
213  {
214  if (collprovider == COLLPROVIDER_LIBC)
215  {
216  collcollate = defGetString(localeEl);
217  collctype = defGetString(localeEl);
218  }
219  else
220  colliculocale = defGetString(localeEl);
221  }
222 
223  if (lccollateEl)
224  collcollate = defGetString(lccollateEl);
225 
226  if (lcctypeEl)
227  collctype = defGetString(lcctypeEl);
228 
229  if (collprovider == COLLPROVIDER_LIBC)
230  {
231  if (!collcollate)
232  ereport(ERROR,
233  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
234  errmsg("parameter \"lc_collate\" must be specified")));
235 
236  if (!collctype)
237  ereport(ERROR,
238  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
239  errmsg("parameter \"lc_ctype\" must be specified")));
240  }
241  else if (collprovider == COLLPROVIDER_ICU)
242  {
243  if (!colliculocale)
244  ereport(ERROR,
245  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
246  errmsg("parameter \"locale\" must be specified")));
247  }
248 
249  /*
250  * Nondeterministic collations are currently only supported with ICU
251  * because that's the only case where it can actually make a
252  * difference. So we can save writing the code for the other
253  * providers.
254  */
255  if (!collisdeterministic && collprovider != COLLPROVIDER_ICU)
256  ereport(ERROR,
257  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
258  errmsg("nondeterministic collations not supported with this provider")));
259 
260  if (collprovider == COLLPROVIDER_ICU)
261  {
262 #ifdef USE_ICU
263  /*
264  * We could create ICU collations with collencoding == database
265  * encoding, but it seems better to use -1 so that it matches the
266  * way initdb would create ICU collations. However, only allow
267  * one to be created when the current database's encoding is
268  * supported. Otherwise the collation is useless, plus we get
269  * surprising behaviors like not being able to drop the collation.
270  *
271  * Skip this test when !USE_ICU, because the error we want to
272  * throw for that isn't thrown till later.
273  */
275  ereport(ERROR,
276  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
277  errmsg("current database's encoding is not supported with this provider")));
278 #endif
279  collencoding = -1;
280  }
281  else
282  {
283  collencoding = GetDatabaseEncoding();
284  check_encoding_locale_matches(collencoding, collcollate, collctype);
285  }
286  }
287 
288  if (!collversion)
289  collversion = get_collation_actual_version(collprovider, collprovider == COLLPROVIDER_ICU ? colliculocale : collcollate);
290 
291  newoid = CollationCreate(collName,
292  collNamespace,
293  GetUserId(),
294  collprovider,
295  collisdeterministic,
296  collencoding,
297  collcollate,
298  collctype,
299  colliculocale,
300  collversion,
301  if_not_exists,
302  false); /* not quiet */
303 
304  if (!OidIsValid(newoid))
305  return InvalidObjectAddress;
306 
307  /*
308  * Check that the locales can be loaded. NB: pg_newlocale_from_collation
309  * is only supposed to be called on non-C-equivalent locales.
310  */
312  if (!lc_collate_is_c(newoid) || !lc_ctype_is_c(newoid))
313  (void) pg_newlocale_from_collation(newoid);
314 
315  ObjectAddressSet(address, CollationRelationId, newoid);
316 
317  return address;
318 }
AclResult
Definition: acl.h:182
@ ACLCHECK_OK
Definition: acl.h:183
AclResult object_aclcheck(Oid classid, Oid objectid, Oid roleid, AclMode mode)
Definition: aclchk.c:3783
#define OidIsValid(objectId)
Definition: c.h:759
Oid collid
void check_encoding_locale_matches(int encoding, const char *collate, const char *ctype)
Definition: dbcommands.c:1430
bool defGetBoolean(DefElem *def)
Definition: define.c:108
List * defGetQualifiedName(DefElem *def)
Definition: define.c:253
char * defGetString(DefElem *def)
Definition: define.c:49
void errorConflictingDefElem(DefElem *defel, ParseState *pstate)
Definition: define.c:385
int errdetail(const char *fmt,...)
Definition: elog.c:1202
int errcode(int sqlerrcode)
Definition: elog.c:858
bool is_encoding_supported_by_icu(int encoding)
Definition: encnames.c:462
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3331
int GetDatabaseEncoding(void)
Definition: mbutils.c:1268
Oid QualifiedNameGetCreationNamespace(List *names, char **objname_p)
Definition: namespace.c:3038
const ObjectAddress InvalidObjectAddress
int parser_errposition(ParseState *pstate, int location)
Definition: parse_node.c:111
@ OBJECT_SCHEMA
Definition: parsenodes.h:2005
#define ACL_CREATE
Definition: parsenodes.h:92
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:176
static int list_length(const List *l)
Definition: pg_list.h:152
bool lc_collate_is_c(Oid collation)
Definition: pg_locale.c:1299
pg_locale_t pg_newlocale_from_collation(Oid collid)
Definition: pg_locale.c:1481
bool lc_ctype_is_c(Oid collation)
Definition: pg_locale.c:1352
int pg_strcasecmp(const char *s1, const char *s2)
Definition: pgstrcasecmp.c:36
char * defname
Definition: parsenodes.h:810
int location
Definition: parsenodes.h:814
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:865
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:817
void CommandCounterIncrement(void)
Definition: xact.c:1078

References ACL_CREATE, aclcheck_error(), ACLCHECK_OK, check_encoding_locale_matches(), CollationCreate(), collid, 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_aclcheck(), OBJECT_SCHEMA, ObjectAddressSet, ObjectIdGetDatum(), OidIsValid, parser_errposition(), 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 327 of file collationcmds.c.

328 {
329  /* make sure the name doesn't already exist in new schema */
331  CStringGetDatum(collname),
333  ObjectIdGetDatum(nspOid)))
334  ereport(ERROR,
336  errmsg("collation \"%s\" for encoding \"%s\" already exists in schema \"%s\"",
337  collname, GetDatabaseEncodingName(),
338  get_namespace_name(nspOid))));
339 
340  /* mustn't match an any-encoding entry, either */
342  CStringGetDatum(collname),
343  Int32GetDatum(-1),
344  ObjectIdGetDatum(nspOid)))
345  ereport(ERROR,
347  errmsg("collation \"%s\" already exists in schema \"%s\"",
348  collname, get_namespace_name(nspOid))));
349 }
const char * GetDatabaseEncodingName(void)
Definition: mbutils.c:1274
static Datum CStringGetDatum(const char *X)
Definition: postgres.h:350
static Datum Int32GetDatum(int32 X)
Definition: postgres.h:212
#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().