mirror of
https://github.com/postgres/postgres.git
synced 2025-06-14 18:42:34 +03:00
Allow tailoring of ICU locales with custom rules
This exposes the ICU facility to add custom collation rules to a standard collation. New options are added to CREATE COLLATION, CREATE DATABASE, createdb, and initdb to set the rules. Reviewed-by: Laurenz Albe <laurenz.albe@cybertec.at> Reviewed-by: Daniel Verite <daniel@manitou-mail.org> Discussion: https://www.postgresql.org/message-id/flat/821c71a4-6ef0-d366-9acf-bb8e367f739f@enterprisedb.com
This commit is contained in:
@ -119,6 +119,7 @@ static bool get_db_info(const char *name, LOCKMODE lockmode,
|
||||
int *encodingP, bool *dbIsTemplateP, bool *dbAllowConnP,
|
||||
TransactionId *dbFrozenXidP, MultiXactId *dbMinMultiP,
|
||||
Oid *dbTablespace, char **dbCollate, char **dbCtype, char **dbIculocale,
|
||||
char **dbIcurules,
|
||||
char *dbLocProvider,
|
||||
char **dbCollversion);
|
||||
static void remove_dbtablespaces(Oid db_id);
|
||||
@ -675,6 +676,7 @@ createdb(ParseState *pstate, const CreatedbStmt *stmt)
|
||||
char *src_collate = NULL;
|
||||
char *src_ctype = NULL;
|
||||
char *src_iculocale = NULL;
|
||||
char *src_icurules = NULL;
|
||||
char src_locprovider = '\0';
|
||||
char *src_collversion = NULL;
|
||||
bool src_istemplate;
|
||||
@ -698,6 +700,7 @@ createdb(ParseState *pstate, const CreatedbStmt *stmt)
|
||||
DefElem *dcollate = NULL;
|
||||
DefElem *dctype = NULL;
|
||||
DefElem *diculocale = NULL;
|
||||
DefElem *dicurules = NULL;
|
||||
DefElem *dlocprovider = NULL;
|
||||
DefElem *distemplate = NULL;
|
||||
DefElem *dallowconnections = NULL;
|
||||
@ -710,6 +713,7 @@ createdb(ParseState *pstate, const CreatedbStmt *stmt)
|
||||
char *dbcollate = NULL;
|
||||
char *dbctype = NULL;
|
||||
char *dbiculocale = NULL;
|
||||
char *dbicurules = NULL;
|
||||
char dblocprovider = '\0';
|
||||
char *canonname;
|
||||
int encoding = -1;
|
||||
@ -775,6 +779,12 @@ createdb(ParseState *pstate, const CreatedbStmt *stmt)
|
||||
errorConflictingDefElem(defel, pstate);
|
||||
diculocale = defel;
|
||||
}
|
||||
else if (strcmp(defel->defname, "icu_rules") == 0)
|
||||
{
|
||||
if (dicurules)
|
||||
errorConflictingDefElem(defel, pstate);
|
||||
dicurules = defel;
|
||||
}
|
||||
else if (strcmp(defel->defname, "locale_provider") == 0)
|
||||
{
|
||||
if (dlocprovider)
|
||||
@ -893,6 +903,8 @@ createdb(ParseState *pstate, const CreatedbStmt *stmt)
|
||||
dbctype = defGetString(dctype);
|
||||
if (diculocale && diculocale->arg)
|
||||
dbiculocale = defGetString(diculocale);
|
||||
if (dicurules && dicurules->arg)
|
||||
dbicurules = defGetString(dicurules);
|
||||
if (dlocprovider && dlocprovider->arg)
|
||||
{
|
||||
char *locproviderstr = defGetString(dlocprovider);
|
||||
@ -958,7 +970,7 @@ createdb(ParseState *pstate, const CreatedbStmt *stmt)
|
||||
&src_dboid, &src_owner, &src_encoding,
|
||||
&src_istemplate, &src_allowconn,
|
||||
&src_frozenxid, &src_minmxid, &src_deftablespace,
|
||||
&src_collate, &src_ctype, &src_iculocale, &src_locprovider,
|
||||
&src_collate, &src_ctype, &src_iculocale, &src_icurules, &src_locprovider,
|
||||
&src_collversion))
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_UNDEFINED_DATABASE),
|
||||
@ -1006,6 +1018,8 @@ createdb(ParseState *pstate, const CreatedbStmt *stmt)
|
||||
dblocprovider = src_locprovider;
|
||||
if (dbiculocale == NULL && dblocprovider == COLLPROVIDER_ICU)
|
||||
dbiculocale = src_iculocale;
|
||||
if (dbicurules == NULL && dblocprovider == COLLPROVIDER_ICU)
|
||||
dbicurules = src_icurules;
|
||||
|
||||
/* Some encodings are client only */
|
||||
if (!PG_VALID_BE_ENCODING(encoding))
|
||||
@ -1097,6 +1111,9 @@ createdb(ParseState *pstate, const CreatedbStmt *stmt)
|
||||
|
||||
if (dblocprovider == COLLPROVIDER_ICU)
|
||||
{
|
||||
char *val1;
|
||||
char *val2;
|
||||
|
||||
Assert(dbiculocale);
|
||||
Assert(src_iculocale);
|
||||
if (strcmp(dbiculocale, src_iculocale) != 0)
|
||||
@ -1105,6 +1122,19 @@ createdb(ParseState *pstate, const CreatedbStmt *stmt)
|
||||
errmsg("new ICU locale (%s) is incompatible with the ICU locale of the template database (%s)",
|
||||
dbiculocale, src_iculocale),
|
||||
errhint("Use the same ICU locale as in the template database, or use template0 as template.")));
|
||||
|
||||
val1 = dbicurules;
|
||||
if (!val1)
|
||||
val1 = "";
|
||||
val2 = src_icurules;
|
||||
if (!val2)
|
||||
val2 = "";
|
||||
if (strcmp(val1, val2) != 0)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
||||
errmsg("new ICU collation rules (%s) are incompatible with the ICU collation rules of the template database (%s)",
|
||||
val1, val2),
|
||||
errhint("Use the same ICU collation rules as in the template database, or use template0 as template.")));
|
||||
}
|
||||
}
|
||||
|
||||
@ -1313,6 +1343,10 @@ createdb(ParseState *pstate, const CreatedbStmt *stmt)
|
||||
new_record[Anum_pg_database_daticulocale - 1] = CStringGetTextDatum(dbiculocale);
|
||||
else
|
||||
new_record_nulls[Anum_pg_database_daticulocale - 1] = true;
|
||||
if (dbicurules)
|
||||
new_record[Anum_pg_database_daticurules - 1] = CStringGetTextDatum(dbicurules);
|
||||
else
|
||||
new_record_nulls[Anum_pg_database_daticurules - 1] = true;
|
||||
if (dbcollversion)
|
||||
new_record[Anum_pg_database_datcollversion - 1] = CStringGetTextDatum(dbcollversion);
|
||||
else
|
||||
@ -1526,7 +1560,7 @@ dropdb(const char *dbname, bool missing_ok, bool force)
|
||||
pgdbrel = table_open(DatabaseRelationId, RowExclusiveLock);
|
||||
|
||||
if (!get_db_info(dbname, AccessExclusiveLock, &db_id, NULL, NULL,
|
||||
&db_istemplate, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL))
|
||||
&db_istemplate, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL))
|
||||
{
|
||||
if (!missing_ok)
|
||||
{
|
||||
@ -1726,7 +1760,7 @@ RenameDatabase(const char *oldname, const char *newname)
|
||||
rel = table_open(DatabaseRelationId, RowExclusiveLock);
|
||||
|
||||
if (!get_db_info(oldname, AccessExclusiveLock, &db_id, NULL, NULL,
|
||||
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL))
|
||||
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL))
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_UNDEFINED_DATABASE),
|
||||
errmsg("database \"%s\" does not exist", oldname)));
|
||||
@ -1836,7 +1870,7 @@ movedb(const char *dbname, const char *tblspcname)
|
||||
pgdbrel = table_open(DatabaseRelationId, RowExclusiveLock);
|
||||
|
||||
if (!get_db_info(dbname, AccessExclusiveLock, &db_id, NULL, NULL,
|
||||
NULL, NULL, NULL, NULL, &src_tblspcoid, NULL, NULL, NULL, NULL, NULL))
|
||||
NULL, NULL, NULL, NULL, &src_tblspcoid, NULL, NULL, NULL, NULL, NULL, NULL))
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_UNDEFINED_DATABASE),
|
||||
errmsg("database \"%s\" does not exist", dbname)));
|
||||
@ -2599,6 +2633,7 @@ get_db_info(const char *name, LOCKMODE lockmode,
|
||||
int *encodingP, bool *dbIsTemplateP, bool *dbAllowConnP,
|
||||
TransactionId *dbFrozenXidP, MultiXactId *dbMinMultiP,
|
||||
Oid *dbTablespace, char **dbCollate, char **dbCtype, char **dbIculocale,
|
||||
char **dbIcurules,
|
||||
char *dbLocProvider,
|
||||
char **dbCollversion)
|
||||
{
|
||||
@ -2715,6 +2750,14 @@ get_db_info(const char *name, LOCKMODE lockmode,
|
||||
else
|
||||
*dbIculocale = TextDatumGetCString(datum);
|
||||
}
|
||||
if (dbIcurules)
|
||||
{
|
||||
datum = SysCacheGetAttr(DATABASEOID, tuple, Anum_pg_database_daticurules, &isnull);
|
||||
if (isnull)
|
||||
*dbIcurules = NULL;
|
||||
else
|
||||
*dbIcurules = TextDatumGetCString(datum);
|
||||
}
|
||||
if (dbCollversion)
|
||||
{
|
||||
datum = SysCacheGetAttr(DATABASEOID, tuple, Anum_pg_database_datcollversion, &isnull);
|
||||
|
Reference in New Issue
Block a user