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

284 {
285  Relation rel;
286  Oid collOid;
287  HeapTuple tup;
288  Form_pg_collation collForm;
289  Datum collversion;
290  bool isnull;
291  char *oldversion;
292  char *newversion;
293  ObjectAddress address;
294 
295  rel = table_open(CollationRelationId, RowExclusiveLock);
296  collOid = get_collation_oid(stmt->collname, false);
297 
298  if (!pg_collation_ownercheck(collOid, GetUserId()))
300  NameListToString(stmt->collname));
301 
303  if (!HeapTupleIsValid(tup))
304  elog(ERROR, "cache lookup failed for collation %u", collOid);
305 
306  collForm = (Form_pg_collation) GETSTRUCT(tup);
307  collversion = SysCacheGetAttr(COLLOID, tup, Anum_pg_collation_collversion,
308  &isnull);
309  oldversion = isnull ? NULL : TextDatumGetCString(collversion);
310 
311  newversion = get_collation_actual_version(collForm->collprovider, NameStr(collForm->collcollate));
312 
313  /* cannot change from NULL to non-NULL or vice versa */
314  if ((!oldversion && newversion) || (oldversion && !newversion))
315  elog(ERROR, "invalid collation version change");
316  else if (oldversion && newversion && strcmp(newversion, oldversion) != 0)
317  {
318  bool nulls[Natts_pg_collation];
319  bool replaces[Natts_pg_collation];
320  Datum values[Natts_pg_collation];
321 
322  ereport(NOTICE,
323  (errmsg("changing version from %s to %s",
324  oldversion, newversion)));
325 
326  memset(values, 0, sizeof(values));
327  memset(nulls, false, sizeof(nulls));
328  memset(replaces, false, sizeof(replaces));
329 
330  values[Anum_pg_collation_collversion - 1] = CStringGetTextDatum(newversion);
331  replaces[Anum_pg_collation_collversion - 1] = true;
332 
333  tup = heap_modify_tuple(tup, RelationGetDescr(rel),
334  values, nulls, replaces);
335  }
336  else
337  ereport(NOTICE,
338  (errmsg("version has not changed")));
339 
340  CatalogTupleUpdate(rel, &tup->t_self, tup);
341 
342  InvokeObjectPostAlterHook(CollationRelationId, collOid, 0);
343 
344  ObjectAddressSet(address, CollationRelationId, collOid);
345 
346  heap_freetuple(tup);
347  table_close(rel, NoLock);
348 
349  return address;
350 }
bool pg_collation_ownercheck(Oid coll_oid, Oid roleid)
Definition: aclchk.c:5199
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:442
Oid GetUserId(void)
Definition: miscinit.c:380
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:3353
#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 ereport(elevel, rest)
Definition: elog.h:141
#define InvokeObjectPostAlterHook(classId, objectId, subId)
Definition: objectaccess.h:163
char * NameListToString(List *names)
Definition: namespace.c:3094
#define TextDatumGetCString(d)
Definition: builtins.h:84
uintptr_t Datum
Definition: postgres.h:367
Datum SysCacheGetAttr(int cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition: syscache.c:1385
#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:784
#define elog(elevel,...)
Definition: elog.h:226
#define NameStr(name)
Definition: c.h:609
#define CStringGetTextDatum(s)
Definition: builtins.h:83
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:3564
char * get_collation_actual_version(char collprovider, const char *collcollate)
Definition: pg_locale.c:1519

◆ DefineCollation()

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

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

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

◆ IsThereCollationInNamespace()

void IsThereCollationInNamespace ( const char *  collname,
Oid  nspOid 
)

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

256 {
257  /* make sure the name doesn't already exist in new schema */
259  CStringGetDatum(collname),
261  ObjectIdGetDatum(nspOid)))
262  ereport(ERROR,
264  errmsg("collation \"%s\" for encoding \"%s\" already exists in schema \"%s\"",
265  collname, GetDatabaseEncodingName(),
266  get_namespace_name(nspOid))));
267 
268  /* mustn't match an any-encoding entry, either */
270  CStringGetDatum(collname),
271  Int32GetDatum(-1),
272  ObjectIdGetDatum(nspOid)))
273  ereport(ERROR,
275  errmsg("collation \"%s\" already exists in schema \"%s\"",
276  collname, get_namespace_name(nspOid))));
277 }
int errcode(int sqlerrcode)
Definition: elog.c:570
#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:3094
#define CStringGetDatum(X)
Definition: postgres.h:578
#define ereport(elevel, rest)
Definition: elog.h:141
int GetDatabaseEncoding(void)
Definition: mbutils.c:996
const char * GetDatabaseEncodingName(void)
Definition: mbutils.c:1002
#define Int32GetDatum(X)
Definition: postgres.h:479
int errmsg(const char *fmt,...)
Definition: elog.c:784
#define ERRCODE_DUPLICATE_OBJECT
Definition: streamutil.c:33