Catalog changes preparing for builtin collation provider.

Rename pg_collation.colliculocale to colllocale, and
pg_database.daticulocale to datlocale. These names reflects that the
fields will be useful for the upcoming builtin provider as well, not
just for ICU.

This is purely a rename; no changes to the meaning of the fields.

Discussion: https://postgr.es/m/ff4c2f2f9c8fc7ca27c1c24ae37ecaeaeaff6b53.camel%40j-davis.com
Reviewed-by: Peter Eisentraut
This commit is contained in:
Jeff Davis 2024-03-09 14:48:18 -08:00
parent 81d13a8dc0
commit f696c0cd5f
22 changed files with 231 additions and 169 deletions

View File

@ -186,7 +186,7 @@
datlocprovider => 'LOCALE_PROVIDER', datistemplate => 't', datlocprovider => 'LOCALE_PROVIDER', datistemplate => 't',
datallowconn => 't', dathasloginevt => 'f', datconnlimit => '-1', datfrozenxid => '0', datallowconn => 't', dathasloginevt => 'f', datconnlimit => '-1', datfrozenxid => '0',
datminmxid => '1', dattablespace => 'pg_default', datcollate => 'LC_COLLATE', datminmxid => '1', dattablespace => 'pg_default', datcollate => 'LC_COLLATE',
datctype => 'LC_CTYPE', daticulocale => 'ICU_LOCALE', datacl => '_null_' }, datctype => 'LC_CTYPE', datlocale => 'DATLOCALE', datacl => '_null_' },
] ]
]]></programlisting> ]]></programlisting>

View File

@ -2407,7 +2407,10 @@ SCRAM-SHA-256$<replaceable>&lt;iteration count&gt;</replaceable>:<replaceable>&l
<structfield>collcollate</structfield> <type>text</type> <structfield>collcollate</structfield> <type>text</type>
</para> </para>
<para> <para>
<symbol>LC_COLLATE</symbol> for this collation object <symbol>LC_COLLATE</symbol> for this collation object. If the provider is
not <literal>libc</literal>, <structfield>collcollate</structfield> is
<literal>NULL</literal> and <structfield>colllocale</structfield> is
used instead.
</para></entry> </para></entry>
</row> </row>
@ -2416,16 +2419,23 @@ SCRAM-SHA-256$<replaceable>&lt;iteration count&gt;</replaceable>:<replaceable>&l
<structfield>collctype</structfield> <type>text</type> <structfield>collctype</structfield> <type>text</type>
</para> </para>
<para> <para>
<symbol>LC_CTYPE</symbol> for this collation object <symbol>LC_CTYPE</symbol> for this collation object. If the provider is
not <literal>libc</literal>, <structfield>collctype</structfield> is
<literal>NULL</literal> and <structfield>colllocale</structfield> is
used instead.
</para></entry> </para></entry>
</row> </row>
<row> <row>
<entry role="catalog_table_entry"><para role="column_definition"> <entry role="catalog_table_entry"><para role="column_definition">
<structfield>colliculocale</structfield> <type>text</type> <structfield>colllocale</structfield> <type>text</type>
</para> </para>
<para> <para>
ICU locale ID for this collation object Collation provider locale name for this collation object. If the
provider is <literal>libc</literal>,
<structfield>colllocale</structfield> is <literal>NULL</literal>;
<structfield>collcollate</structfield> and
<structfield>collctype</structfield> are used instead.
</para></entry> </para></entry>
</row> </row>
@ -3131,10 +3141,14 @@ SCRAM-SHA-256$<replaceable>&lt;iteration count&gt;</replaceable>:<replaceable>&l
<row> <row>
<entry role="catalog_table_entry"><para role="column_definition"> <entry role="catalog_table_entry"><para role="column_definition">
<structfield>daticulocale</structfield> <type>text</type> <structfield>datlocale</structfield> <type>text</type>
</para> </para>
<para> <para>
ICU locale ID for this database Collation provider locale name for this database. If the
provider is <literal>libc</literal>,
<structfield>datlocale</structfield> is <literal>NULL</literal>;
<structfield>datcollate</structfield> and
<structfield>datctype</structfield> are used instead.
</para></entry> </para></entry>
</row> </row>

View File

@ -45,7 +45,7 @@ CollationCreate(const char *collname, Oid collnamespace,
bool collisdeterministic, bool collisdeterministic,
int32 collencoding, int32 collencoding,
const char *collcollate, const char *collctype, const char *collcollate, const char *collctype,
const char *colliculocale, const char *colllocale,
const char *collicurules, const char *collicurules,
const char *collversion, const char *collversion,
bool if_not_exists, bool if_not_exists,
@ -64,7 +64,7 @@ CollationCreate(const char *collname, Oid collnamespace,
Assert(collname); Assert(collname);
Assert(collnamespace); Assert(collnamespace);
Assert(collowner); Assert(collowner);
Assert((collcollate && collctype) || colliculocale); Assert((collcollate && collctype) || colllocale);
/* /*
* Make sure there is no existing collation of same name & encoding. * Make sure there is no existing collation of same name & encoding.
@ -187,10 +187,10 @@ CollationCreate(const char *collname, Oid collnamespace,
values[Anum_pg_collation_collctype - 1] = CStringGetTextDatum(collctype); values[Anum_pg_collation_collctype - 1] = CStringGetTextDatum(collctype);
else else
nulls[Anum_pg_collation_collctype - 1] = true; nulls[Anum_pg_collation_collctype - 1] = true;
if (colliculocale) if (colllocale)
values[Anum_pg_collation_colliculocale - 1] = CStringGetTextDatum(colliculocale); values[Anum_pg_collation_colllocale - 1] = CStringGetTextDatum(colllocale);
else else
nulls[Anum_pg_collation_colliculocale - 1] = true; nulls[Anum_pg_collation_colllocale - 1] = true;
if (collicurules) if (collicurules)
values[Anum_pg_collation_collicurules - 1] = CStringGetTextDatum(collicurules); values[Anum_pg_collation_collicurules - 1] = CStringGetTextDatum(collicurules);
else else

View File

@ -66,7 +66,7 @@ DefineCollation(ParseState *pstate, List *names, List *parameters, bool if_not_e
DefElem *versionEl = NULL; DefElem *versionEl = NULL;
char *collcollate; char *collcollate;
char *collctype; char *collctype;
char *colliculocale; char *colllocale;
char *collicurules; char *collicurules;
bool collisdeterministic; bool collisdeterministic;
int collencoding; int collencoding;
@ -157,11 +157,11 @@ DefineCollation(ParseState *pstate, List *names, List *parameters, bool if_not_e
else else
collctype = NULL; collctype = NULL;
datum = SysCacheGetAttr(COLLOID, tp, Anum_pg_collation_colliculocale, &isnull); datum = SysCacheGetAttr(COLLOID, tp, Anum_pg_collation_colllocale, &isnull);
if (!isnull) if (!isnull)
colliculocale = TextDatumGetCString(datum); colllocale = TextDatumGetCString(datum);
else else
colliculocale = NULL; colllocale = NULL;
/* /*
* When the ICU locale comes from an existing collation, do not * When the ICU locale comes from an existing collation, do not
@ -194,7 +194,7 @@ DefineCollation(ParseState *pstate, List *names, List *parameters, bool if_not_e
collcollate = NULL; collcollate = NULL;
collctype = NULL; collctype = NULL;
colliculocale = NULL; colllocale = NULL;
collicurules = NULL; collicurules = NULL;
if (providerEl) if (providerEl)
@ -234,7 +234,7 @@ DefineCollation(ParseState *pstate, List *names, List *parameters, bool if_not_e
collctype = defGetString(localeEl); collctype = defGetString(localeEl);
} }
else else
colliculocale = defGetString(localeEl); colllocale = defGetString(localeEl);
} }
if (lccollateEl) if (lccollateEl)
@ -259,7 +259,7 @@ DefineCollation(ParseState *pstate, List *names, List *parameters, bool if_not_e
} }
else if (collprovider == COLLPROVIDER_ICU) else if (collprovider == COLLPROVIDER_ICU)
{ {
if (!colliculocale) if (!colllocale)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION), (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("parameter \"%s\" must be specified", errmsg("parameter \"%s\" must be specified",
@ -271,20 +271,20 @@ DefineCollation(ParseState *pstate, List *names, List *parameters, bool if_not_e
*/ */
if (!IsBinaryUpgrade) if (!IsBinaryUpgrade)
{ {
char *langtag = icu_language_tag(colliculocale, char *langtag = icu_language_tag(colllocale,
icu_validation_level); icu_validation_level);
if (langtag && strcmp(colliculocale, langtag) != 0) if (langtag && strcmp(colllocale, langtag) != 0)
{ {
ereport(NOTICE, ereport(NOTICE,
(errmsg("using standard form \"%s\" for ICU locale \"%s\"", (errmsg("using standard form \"%s\" for ICU locale \"%s\"",
langtag, colliculocale))); langtag, colllocale)));
colliculocale = langtag; colllocale = langtag;
} }
} }
icu_validate_locale(colliculocale); icu_validate_locale(colllocale);
} }
/* /*
@ -332,7 +332,7 @@ DefineCollation(ParseState *pstate, List *names, List *parameters, bool if_not_e
} }
if (!collversion) if (!collversion)
collversion = get_collation_actual_version(collprovider, collprovider == COLLPROVIDER_ICU ? colliculocale : collcollate); collversion = get_collation_actual_version(collprovider, collprovider == COLLPROVIDER_ICU ? colllocale : collcollate);
newoid = CollationCreate(collName, newoid = CollationCreate(collName,
collNamespace, collNamespace,
@ -342,7 +342,7 @@ DefineCollation(ParseState *pstate, List *names, List *parameters, bool if_not_e
collencoding, collencoding,
collcollate, collcollate,
collctype, collctype,
colliculocale, colllocale,
collicurules, collicurules,
collversion, collversion,
if_not_exists, if_not_exists,
@ -433,7 +433,7 @@ AlterCollation(AlterCollationStmt *stmt)
datum = SysCacheGetAttr(COLLOID, tup, Anum_pg_collation_collversion, &isnull); datum = SysCacheGetAttr(COLLOID, tup, Anum_pg_collation_collversion, &isnull);
oldversion = isnull ? NULL : TextDatumGetCString(datum); oldversion = isnull ? NULL : TextDatumGetCString(datum);
datum = SysCacheGetAttrNotNull(COLLOID, tup, collForm->collprovider == COLLPROVIDER_ICU ? Anum_pg_collation_colliculocale : Anum_pg_collation_collcollate); datum = SysCacheGetAttrNotNull(COLLOID, tup, collForm->collprovider == COLLPROVIDER_ICU ? Anum_pg_collation_colllocale : Anum_pg_collation_collcollate);
newversion = get_collation_actual_version(collForm->collprovider, TextDatumGetCString(datum)); newversion = get_collation_actual_version(collForm->collprovider, TextDatumGetCString(datum));
/* cannot change from NULL to non-NULL or vice versa */ /* cannot change from NULL to non-NULL or vice versa */
@ -500,7 +500,7 @@ pg_collation_actual_version(PG_FUNCTION_ARGS)
datum = SysCacheGetAttrNotNull(DATABASEOID, dbtup, datum = SysCacheGetAttrNotNull(DATABASEOID, dbtup,
provider == COLLPROVIDER_ICU ? provider == COLLPROVIDER_ICU ?
Anum_pg_database_daticulocale : Anum_pg_database_datcollate); Anum_pg_database_datlocale : Anum_pg_database_datcollate);
locale = TextDatumGetCString(datum); locale = TextDatumGetCString(datum);
@ -521,7 +521,7 @@ pg_collation_actual_version(PG_FUNCTION_ARGS)
Assert(provider != COLLPROVIDER_DEFAULT); Assert(provider != COLLPROVIDER_DEFAULT);
datum = SysCacheGetAttrNotNull(COLLOID, colltp, datum = SysCacheGetAttrNotNull(COLLOID, colltp,
provider == COLLPROVIDER_ICU ? provider == COLLPROVIDER_ICU ?
Anum_pg_collation_colliculocale : Anum_pg_collation_collcollate); Anum_pg_collation_colllocale : Anum_pg_collation_collcollate);
locale = TextDatumGetCString(datum); locale = TextDatumGetCString(datum);

View File

@ -117,7 +117,7 @@ static bool get_db_info(const char *name, LOCKMODE lockmode,
Oid *dbIdP, Oid *ownerIdP, Oid *dbIdP, Oid *ownerIdP,
int *encodingP, bool *dbIsTemplateP, bool *dbAllowConnP, bool *dbHasLoginEvtP, int *encodingP, bool *dbIsTemplateP, bool *dbAllowConnP, bool *dbHasLoginEvtP,
TransactionId *dbFrozenXidP, MultiXactId *dbMinMultiP, TransactionId *dbFrozenXidP, MultiXactId *dbMinMultiP,
Oid *dbTablespace, char **dbCollate, char **dbCtype, char **dbIculocale, Oid *dbTablespace, char **dbCollate, char **dbCtype, char **dbLocale,
char **dbIcurules, char **dbIcurules,
char *dbLocProvider, char *dbLocProvider,
char **dbCollversion); char **dbCollversion);
@ -674,7 +674,7 @@ createdb(ParseState *pstate, const CreatedbStmt *stmt)
int src_encoding = -1; int src_encoding = -1;
char *src_collate = NULL; char *src_collate = NULL;
char *src_ctype = NULL; char *src_ctype = NULL;
char *src_iculocale = NULL; char *src_locale = NULL;
char *src_icurules = NULL; char *src_icurules = NULL;
char src_locprovider = '\0'; char src_locprovider = '\0';
char *src_collversion = NULL; char *src_collversion = NULL;
@ -712,7 +712,7 @@ createdb(ParseState *pstate, const CreatedbStmt *stmt)
const char *dbtemplate = NULL; const char *dbtemplate = NULL;
char *dbcollate = NULL; char *dbcollate = NULL;
char *dbctype = NULL; char *dbctype = NULL;
char *dbiculocale = NULL; char *dblocale = NULL;
char *dbicurules = NULL; char *dbicurules = NULL;
char dblocprovider = '\0'; char dblocprovider = '\0';
char *canonname; char *canonname;
@ -902,7 +902,7 @@ createdb(ParseState *pstate, const CreatedbStmt *stmt)
if (dctype && dctype->arg) if (dctype && dctype->arg)
dbctype = defGetString(dctype); dbctype = defGetString(dctype);
if (diculocale && diculocale->arg) if (diculocale && diculocale->arg)
dbiculocale = defGetString(diculocale); dblocale = defGetString(diculocale);
if (dicurules && dicurules->arg) if (dicurules && dicurules->arg)
dbicurules = defGetString(dicurules); dbicurules = defGetString(dicurules);
if (dlocprovider && dlocprovider->arg) if (dlocprovider && dlocprovider->arg)
@ -970,7 +970,7 @@ createdb(ParseState *pstate, const CreatedbStmt *stmt)
&src_dboid, &src_owner, &src_encoding, &src_dboid, &src_owner, &src_encoding,
&src_istemplate, &src_allowconn, &src_hasloginevt, &src_istemplate, &src_allowconn, &src_hasloginevt,
&src_frozenxid, &src_minmxid, &src_deftablespace, &src_frozenxid, &src_minmxid, &src_deftablespace,
&src_collate, &src_ctype, &src_iculocale, &src_icurules, &src_locprovider, &src_collate, &src_ctype, &src_locale, &src_icurules, &src_locprovider,
&src_collversion)) &src_collversion))
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_DATABASE), (errcode(ERRCODE_UNDEFINED_DATABASE),
@ -1026,12 +1026,12 @@ createdb(ParseState *pstate, const CreatedbStmt *stmt)
dbctype = src_ctype; dbctype = src_ctype;
if (dblocprovider == '\0') if (dblocprovider == '\0')
dblocprovider = src_locprovider; dblocprovider = src_locprovider;
if (dbiculocale == NULL && dblocprovider == COLLPROVIDER_ICU) if (dblocale == NULL && dblocprovider == COLLPROVIDER_ICU)
{ {
if (dlocale && dlocale->arg) if (dlocale && dlocale->arg)
dbiculocale = defGetString(dlocale); dblocale = defGetString(dlocale);
else else
dbiculocale = src_iculocale; dblocale = src_locale;
} }
if (dbicurules == NULL && dblocprovider == COLLPROVIDER_ICU) if (dbicurules == NULL && dblocprovider == COLLPROVIDER_ICU)
dbicurules = src_icurules; dbicurules = src_icurules;
@ -1070,7 +1070,7 @@ createdb(ParseState *pstate, const CreatedbStmt *stmt)
* This would happen if template0 uses the libc provider but the new * This would happen if template0 uses the libc provider but the new
* database uses icu. * database uses icu.
*/ */
if (!dbiculocale) if (!dblocale)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE), (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("LOCALE or ICU_LOCALE must be specified"))); errmsg("LOCALE or ICU_LOCALE must be specified")));
@ -1080,26 +1080,26 @@ createdb(ParseState *pstate, const CreatedbStmt *stmt)
* database, preserve locale string. Otherwise, canonicalize to a * database, preserve locale string. Otherwise, canonicalize to a
* language tag. * language tag.
*/ */
if (!IsBinaryUpgrade && dbiculocale != src_iculocale) if (!IsBinaryUpgrade && dblocale != src_locale)
{ {
char *langtag = icu_language_tag(dbiculocale, char *langtag = icu_language_tag(dblocale,
icu_validation_level); icu_validation_level);
if (langtag && strcmp(dbiculocale, langtag) != 0) if (langtag && strcmp(dblocale, langtag) != 0)
{ {
ereport(NOTICE, ereport(NOTICE,
(errmsg("using standard form \"%s\" for ICU locale \"%s\"", (errmsg("using standard form \"%s\" for ICU locale \"%s\"",
langtag, dbiculocale))); langtag, dblocale)));
dbiculocale = langtag; dblocale = langtag;
} }
} }
icu_validate_locale(dbiculocale); icu_validate_locale(dblocale);
} }
else else
{ {
if (dbiculocale) if (dblocale)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION), (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("ICU locale cannot be specified unless locale provider is ICU"))); errmsg("ICU locale cannot be specified unless locale provider is ICU")));
@ -1156,13 +1156,13 @@ createdb(ParseState *pstate, const CreatedbStmt *stmt)
char *val1; char *val1;
char *val2; char *val2;
Assert(dbiculocale); Assert(dblocale);
Assert(src_iculocale); Assert(src_locale);
if (strcmp(dbiculocale, src_iculocale) != 0) if (strcmp(dblocale, src_locale) != 0)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE), (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("new ICU locale (%s) is incompatible with the ICU locale of the template database (%s)", errmsg("new ICU locale (%s) is incompatible with the ICU locale of the template database (%s)",
dbiculocale, src_iculocale), dblocale, src_locale),
errhint("Use the same ICU locale as in the template database, or use template0 as template."))); errhint("Use the same ICU locale as in the template database, or use template0 as template.")));
val1 = dbicurules; val1 = dbicurules;
@ -1196,7 +1196,7 @@ createdb(ParseState *pstate, const CreatedbStmt *stmt)
{ {
char *actual_versionstr; char *actual_versionstr;
actual_versionstr = get_collation_actual_version(dblocprovider, dblocprovider == COLLPROVIDER_ICU ? dbiculocale : dbcollate); actual_versionstr = get_collation_actual_version(dblocprovider, dblocprovider == COLLPROVIDER_ICU ? dblocale : dbcollate);
if (!actual_versionstr) if (!actual_versionstr)
ereport(ERROR, ereport(ERROR,
(errmsg("template database \"%s\" has a collation version, but no actual collation version could be determined", (errmsg("template database \"%s\" has a collation version, but no actual collation version could be determined",
@ -1224,7 +1224,7 @@ createdb(ParseState *pstate, const CreatedbStmt *stmt)
* collation version, which is normally only the case for template0. * collation version, which is normally only the case for template0.
*/ */
if (dbcollversion == NULL) if (dbcollversion == NULL)
dbcollversion = get_collation_actual_version(dblocprovider, dblocprovider == COLLPROVIDER_ICU ? dbiculocale : dbcollate); dbcollversion = get_collation_actual_version(dblocprovider, dblocprovider == COLLPROVIDER_ICU ? dblocale : dbcollate);
/* Resolve default tablespace for new database */ /* Resolve default tablespace for new database */
if (dtablespacename && dtablespacename->arg) if (dtablespacename && dtablespacename->arg)
@ -1363,8 +1363,8 @@ createdb(ParseState *pstate, const CreatedbStmt *stmt)
* block on the unique index, and fail after we commit). * block on the unique index, and fail after we commit).
*/ */
Assert((dblocprovider == COLLPROVIDER_ICU && dbiculocale) || Assert((dblocprovider == COLLPROVIDER_ICU && dblocale) ||
(dblocprovider != COLLPROVIDER_ICU && !dbiculocale)); (dblocprovider != COLLPROVIDER_ICU && !dblocale));
/* Form tuple */ /* Form tuple */
new_record[Anum_pg_database_oid - 1] = ObjectIdGetDatum(dboid); new_record[Anum_pg_database_oid - 1] = ObjectIdGetDatum(dboid);
@ -1382,10 +1382,10 @@ createdb(ParseState *pstate, const CreatedbStmt *stmt)
new_record[Anum_pg_database_dattablespace - 1] = ObjectIdGetDatum(dst_deftablespace); new_record[Anum_pg_database_dattablespace - 1] = ObjectIdGetDatum(dst_deftablespace);
new_record[Anum_pg_database_datcollate - 1] = CStringGetTextDatum(dbcollate); new_record[Anum_pg_database_datcollate - 1] = CStringGetTextDatum(dbcollate);
new_record[Anum_pg_database_datctype - 1] = CStringGetTextDatum(dbctype); new_record[Anum_pg_database_datctype - 1] = CStringGetTextDatum(dbctype);
if (dbiculocale) if (dblocale)
new_record[Anum_pg_database_daticulocale - 1] = CStringGetTextDatum(dbiculocale); new_record[Anum_pg_database_datlocale - 1] = CStringGetTextDatum(dblocale);
else else
new_record_nulls[Anum_pg_database_daticulocale - 1] = true; new_record_nulls[Anum_pg_database_datlocale - 1] = true;
if (dbicurules) if (dbicurules)
new_record[Anum_pg_database_daticurules - 1] = CStringGetTextDatum(dbicurules); new_record[Anum_pg_database_daticurules - 1] = CStringGetTextDatum(dbicurules);
else else
@ -2471,7 +2471,7 @@ AlterDatabaseRefreshColl(AlterDatabaseRefreshCollStmt *stmt)
datum = heap_getattr(tuple, Anum_pg_database_datcollversion, RelationGetDescr(rel), &isnull); datum = heap_getattr(tuple, Anum_pg_database_datcollversion, RelationGetDescr(rel), &isnull);
oldversion = isnull ? NULL : TextDatumGetCString(datum); oldversion = isnull ? NULL : TextDatumGetCString(datum);
datum = heap_getattr(tuple, datForm->datlocprovider == COLLPROVIDER_ICU ? Anum_pg_database_daticulocale : Anum_pg_database_datcollate, RelationGetDescr(rel), &isnull); datum = heap_getattr(tuple, datForm->datlocprovider == COLLPROVIDER_ICU ? Anum_pg_database_datlocale : Anum_pg_database_datcollate, RelationGetDescr(rel), &isnull);
if (isnull) if (isnull)
elog(ERROR, "unexpected null in pg_database"); elog(ERROR, "unexpected null in pg_database");
newversion = get_collation_actual_version(datForm->datlocprovider, TextDatumGetCString(datum)); newversion = get_collation_actual_version(datForm->datlocprovider, TextDatumGetCString(datum));
@ -2669,7 +2669,7 @@ pg_database_collation_actual_version(PG_FUNCTION_ARGS)
datlocprovider = ((Form_pg_database) GETSTRUCT(tp))->datlocprovider; datlocprovider = ((Form_pg_database) GETSTRUCT(tp))->datlocprovider;
datum = SysCacheGetAttrNotNull(DATABASEOID, tp, datlocprovider == COLLPROVIDER_ICU ? Anum_pg_database_daticulocale : Anum_pg_database_datcollate); datum = SysCacheGetAttrNotNull(DATABASEOID, tp, datlocprovider == COLLPROVIDER_ICU ? Anum_pg_database_datlocale : Anum_pg_database_datcollate);
version = get_collation_actual_version(datlocprovider, TextDatumGetCString(datum)); version = get_collation_actual_version(datlocprovider, TextDatumGetCString(datum));
ReleaseSysCache(tp); ReleaseSysCache(tp);
@ -2696,7 +2696,7 @@ get_db_info(const char *name, LOCKMODE lockmode,
Oid *dbIdP, Oid *ownerIdP, Oid *dbIdP, Oid *ownerIdP,
int *encodingP, bool *dbIsTemplateP, bool *dbAllowConnP, bool *dbHasLoginEvtP, int *encodingP, bool *dbIsTemplateP, bool *dbAllowConnP, bool *dbHasLoginEvtP,
TransactionId *dbFrozenXidP, MultiXactId *dbMinMultiP, TransactionId *dbFrozenXidP, MultiXactId *dbMinMultiP,
Oid *dbTablespace, char **dbCollate, char **dbCtype, char **dbIculocale, Oid *dbTablespace, char **dbCollate, char **dbCtype, char **dbLocale,
char **dbIcurules, char **dbIcurules,
char *dbLocProvider, char *dbLocProvider,
char **dbCollversion) char **dbCollversion)
@ -2807,13 +2807,13 @@ get_db_info(const char *name, LOCKMODE lockmode,
datum = SysCacheGetAttrNotNull(DATABASEOID, tuple, Anum_pg_database_datctype); datum = SysCacheGetAttrNotNull(DATABASEOID, tuple, Anum_pg_database_datctype);
*dbCtype = TextDatumGetCString(datum); *dbCtype = TextDatumGetCString(datum);
} }
if (dbIculocale) if (dbLocale)
{ {
datum = SysCacheGetAttr(DATABASEOID, tuple, Anum_pg_database_daticulocale, &isnull); datum = SysCacheGetAttr(DATABASEOID, tuple, Anum_pg_database_datlocale, &isnull);
if (isnull) if (isnull)
*dbIculocale = NULL; *dbLocale = NULL;
else else
*dbIculocale = TextDatumGetCString(datum); *dbLocale = TextDatumGetCString(datum);
} }
if (dbIcurules) if (dbIcurules)
{ {

View File

@ -1605,7 +1605,7 @@ pg_newlocale_from_collation(Oid collid)
const char *iculocstr; const char *iculocstr;
const char *icurules; const char *icurules;
datum = SysCacheGetAttrNotNull(COLLOID, tp, Anum_pg_collation_colliculocale); datum = SysCacheGetAttrNotNull(COLLOID, tp, Anum_pg_collation_colllocale);
iculocstr = TextDatumGetCString(datum); iculocstr = TextDatumGetCString(datum);
datum = SysCacheGetAttr(COLLOID, tp, Anum_pg_collation_collicurules, &isnull); datum = SysCacheGetAttr(COLLOID, tp, Anum_pg_collation_collicurules, &isnull);
@ -1626,7 +1626,7 @@ pg_newlocale_from_collation(Oid collid)
collversionstr = TextDatumGetCString(datum); collversionstr = TextDatumGetCString(datum);
datum = SysCacheGetAttrNotNull(COLLOID, tp, collform->collprovider == COLLPROVIDER_ICU ? Anum_pg_collation_colliculocale : Anum_pg_collation_collcollate); datum = SysCacheGetAttrNotNull(COLLOID, tp, collform->collprovider == COLLPROVIDER_ICU ? Anum_pg_collation_colllocale : Anum_pg_collation_collcollate);
actual_versionstr = get_collation_actual_version(collform->collprovider, actual_versionstr = get_collation_actual_version(collform->collprovider,
TextDatumGetCString(datum)); TextDatumGetCString(datum));

View File

@ -318,7 +318,7 @@ CheckMyDatabase(const char *name, bool am_superuser, bool override_allow_connect
bool isnull; bool isnull;
char *collate; char *collate;
char *ctype; char *ctype;
char *iculocale; char *datlocale;
/* Fetch our pg_database row normally, via syscache */ /* Fetch our pg_database row normally, via syscache */
tup = SearchSysCache1(DATABASEOID, ObjectIdGetDatum(MyDatabaseId)); tup = SearchSysCache1(DATABASEOID, ObjectIdGetDatum(MyDatabaseId));
@ -427,8 +427,8 @@ CheckMyDatabase(const char *name, bool am_superuser, bool override_allow_connect
{ {
char *icurules; char *icurules;
datum = SysCacheGetAttrNotNull(DATABASEOID, tup, Anum_pg_database_daticulocale); datum = SysCacheGetAttrNotNull(DATABASEOID, tup, Anum_pg_database_datlocale);
iculocale = TextDatumGetCString(datum); datlocale = TextDatumGetCString(datum);
datum = SysCacheGetAttr(DATABASEOID, tup, Anum_pg_database_daticurules, &isnull); datum = SysCacheGetAttr(DATABASEOID, tup, Anum_pg_database_daticurules, &isnull);
if (!isnull) if (!isnull)
@ -436,10 +436,10 @@ CheckMyDatabase(const char *name, bool am_superuser, bool override_allow_connect
else else
icurules = NULL; icurules = NULL;
make_icu_collator(iculocale, icurules, &default_locale); make_icu_collator(datlocale, icurules, &default_locale);
} }
else else
iculocale = NULL; datlocale = NULL;
default_locale.provider = dbform->datlocprovider; default_locale.provider = dbform->datlocprovider;
@ -464,7 +464,7 @@ CheckMyDatabase(const char *name, bool am_superuser, bool override_allow_connect
collversionstr = TextDatumGetCString(datum); collversionstr = TextDatumGetCString(datum);
actual_versionstr = get_collation_actual_version(dbform->datlocprovider, dbform->datlocprovider == COLLPROVIDER_ICU ? iculocale : collate); actual_versionstr = get_collation_actual_version(dbform->datlocprovider, dbform->datlocprovider == COLLPROVIDER_ICU ? datlocale : collate);
if (!actual_versionstr) if (!actual_versionstr)
/* should not happen */ /* should not happen */
elog(WARNING, elog(WARNING,

View File

@ -145,7 +145,7 @@ static char *lc_numeric = NULL;
static char *lc_time = NULL; static char *lc_time = NULL;
static char *lc_messages = NULL; static char *lc_messages = NULL;
static char locale_provider = COLLPROVIDER_LIBC; static char locale_provider = COLLPROVIDER_LIBC;
static char *icu_locale = NULL; static char *datlocale = NULL;
static char *icu_rules = NULL; static char *icu_rules = NULL;
static const char *default_text_search_config = NULL; static const char *default_text_search_config = NULL;
static char *username = NULL; static char *username = NULL;
@ -1520,8 +1520,8 @@ bootstrap_template1(void)
bki_lines = replace_token(bki_lines, "LC_CTYPE", bki_lines = replace_token(bki_lines, "LC_CTYPE",
escape_quotes_bki(lc_ctype)); escape_quotes_bki(lc_ctype));
bki_lines = replace_token(bki_lines, "ICU_LOCALE", bki_lines = replace_token(bki_lines, "DATLOCALE",
icu_locale ? escape_quotes_bki(icu_locale) : "_null_"); datlocale ? escape_quotes_bki(datlocale) : "_null_");
bki_lines = replace_token(bki_lines, "ICU_RULES", bki_lines = replace_token(bki_lines, "ICU_RULES",
icu_rules ? escape_quotes_bki(icu_rules) : "_null_"); icu_rules ? escape_quotes_bki(icu_rules) : "_null_");
@ -2352,7 +2352,7 @@ setlocales(void)
{ {
char *canonname; char *canonname;
/* set empty lc_* and iculocale values to locale config if set */ /* set empty lc_* and datlocale values to locale config if set */
if (locale) if (locale)
{ {
@ -2368,8 +2368,8 @@ setlocales(void)
lc_monetary = locale; lc_monetary = locale;
if (!lc_messages) if (!lc_messages)
lc_messages = locale; lc_messages = locale;
if (!icu_locale && locale_provider == COLLPROVIDER_ICU) if (!datlocale && locale_provider == COLLPROVIDER_ICU)
icu_locale = locale; datlocale = locale;
} }
/* /*
@ -2400,17 +2400,17 @@ setlocales(void)
char *langtag; char *langtag;
/* acquire default locale from the environment, if not specified */ /* acquire default locale from the environment, if not specified */
if (icu_locale == NULL) if (datlocale == NULL)
pg_fatal("ICU locale must be specified"); pg_fatal("ICU locale must be specified");
/* canonicalize to a language tag */ /* canonicalize to a language tag */
langtag = icu_language_tag(icu_locale); langtag = icu_language_tag(datlocale);
printf(_("Using language tag \"%s\" for ICU locale \"%s\".\n"), printf(_("Using language tag \"%s\" for ICU locale \"%s\".\n"),
langtag, icu_locale); langtag, datlocale);
pg_free(icu_locale); pg_free(datlocale);
icu_locale = langtag; datlocale = langtag;
icu_validate_locale(icu_locale); icu_validate_locale(datlocale);
/* /*
* In supported builds, the ICU locale ID will be opened during * In supported builds, the ICU locale ID will be opened during
@ -2604,14 +2604,14 @@ setup_locale_encoding(void)
strcmp(lc_ctype, lc_numeric) == 0 && strcmp(lc_ctype, lc_numeric) == 0 &&
strcmp(lc_ctype, lc_monetary) == 0 && strcmp(lc_ctype, lc_monetary) == 0 &&
strcmp(lc_ctype, lc_messages) == 0 && strcmp(lc_ctype, lc_messages) == 0 &&
(!icu_locale || strcmp(lc_ctype, icu_locale) == 0)) (!datlocale || strcmp(lc_ctype, datlocale) == 0))
printf(_("The database cluster will be initialized with locale \"%s\".\n"), lc_ctype); printf(_("The database cluster will be initialized with locale \"%s\".\n"), lc_ctype);
else else
{ {
printf(_("The database cluster will be initialized with this locale configuration:\n")); printf(_("The database cluster will be initialized with this locale configuration:\n"));
printf(_(" provider: %s\n"), collprovider_name(locale_provider)); printf(_(" provider: %s\n"), collprovider_name(locale_provider));
if (icu_locale) if (datlocale)
printf(_(" ICU locale: %s\n"), icu_locale); printf(_(" ICU locale: %s\n"), datlocale);
printf(_(" LC_COLLATE: %s\n" printf(_(" LC_COLLATE: %s\n"
" LC_CTYPE: %s\n" " LC_CTYPE: %s\n"
" LC_MESSAGES: %s\n" " LC_MESSAGES: %s\n"
@ -3282,7 +3282,7 @@ main(int argc, char *argv[])
pg_fatal("unrecognized locale provider: %s", optarg); pg_fatal("unrecognized locale provider: %s", optarg);
break; break;
case 16: case 16:
icu_locale = pg_strdup(optarg); datlocale = pg_strdup(optarg);
break; break;
case 17: case 17:
icu_rules = pg_strdup(optarg); icu_rules = pg_strdup(optarg);
@ -3317,7 +3317,7 @@ main(int argc, char *argv[])
exit(1); exit(1);
} }
if (icu_locale && locale_provider != COLLPROVIDER_ICU) if (datlocale && locale_provider != COLLPROVIDER_ICU)
pg_fatal("%s cannot be specified unless locale provider \"%s\" is chosen", pg_fatal("%s cannot be specified unless locale provider \"%s\" is chosen",
"--icu-locale", "icu"); "--icu-locale", "icu");

View File

@ -2984,7 +2984,7 @@ dumpDatabase(Archive *fout)
i_datlocprovider, i_datlocprovider,
i_collate, i_collate,
i_ctype, i_ctype,
i_daticulocale, i_datlocale,
i_daticurules, i_daticurules,
i_frozenxid, i_frozenxid,
i_minmxid, i_minmxid,
@ -3003,7 +3003,7 @@ dumpDatabase(Archive *fout)
*datlocprovider, *datlocprovider,
*collate, *collate,
*ctype, *ctype,
*iculocale, *locale,
*icurules, *icurules,
*datistemplate, *datistemplate,
*datconnlimit, *datconnlimit,
@ -3027,10 +3027,12 @@ dumpDatabase(Archive *fout)
appendPQExpBufferStr(dbQry, "datminmxid, "); appendPQExpBufferStr(dbQry, "datminmxid, ");
else else
appendPQExpBufferStr(dbQry, "0 AS datminmxid, "); appendPQExpBufferStr(dbQry, "0 AS datminmxid, ");
if (fout->remoteVersion >= 150000) if (fout->remoteVersion >= 170000)
appendPQExpBufferStr(dbQry, "datlocprovider, daticulocale, datcollversion, "); appendPQExpBufferStr(dbQry, "datlocprovider, datlocale, datcollversion, ");
else if (fout->remoteVersion >= 150000)
appendPQExpBufferStr(dbQry, "datlocprovider, daticulocale AS datlocale, datcollversion, ");
else else
appendPQExpBufferStr(dbQry, "'c' AS datlocprovider, NULL AS daticulocale, NULL AS datcollversion, "); appendPQExpBufferStr(dbQry, "'c' AS datlocprovider, NULL AS datlocale, NULL AS datcollversion, ");
if (fout->remoteVersion >= 160000) if (fout->remoteVersion >= 160000)
appendPQExpBufferStr(dbQry, "daticurules, "); appendPQExpBufferStr(dbQry, "daticurules, ");
else else
@ -3051,7 +3053,7 @@ dumpDatabase(Archive *fout)
i_datlocprovider = PQfnumber(res, "datlocprovider"); i_datlocprovider = PQfnumber(res, "datlocprovider");
i_collate = PQfnumber(res, "datcollate"); i_collate = PQfnumber(res, "datcollate");
i_ctype = PQfnumber(res, "datctype"); i_ctype = PQfnumber(res, "datctype");
i_daticulocale = PQfnumber(res, "daticulocale"); i_datlocale = PQfnumber(res, "datlocale");
i_daticurules = PQfnumber(res, "daticurules"); i_daticurules = PQfnumber(res, "daticurules");
i_frozenxid = PQfnumber(res, "datfrozenxid"); i_frozenxid = PQfnumber(res, "datfrozenxid");
i_minmxid = PQfnumber(res, "datminmxid"); i_minmxid = PQfnumber(res, "datminmxid");
@ -3070,10 +3072,10 @@ dumpDatabase(Archive *fout)
datlocprovider = PQgetvalue(res, 0, i_datlocprovider); datlocprovider = PQgetvalue(res, 0, i_datlocprovider);
collate = PQgetvalue(res, 0, i_collate); collate = PQgetvalue(res, 0, i_collate);
ctype = PQgetvalue(res, 0, i_ctype); ctype = PQgetvalue(res, 0, i_ctype);
if (!PQgetisnull(res, 0, i_daticulocale)) if (!PQgetisnull(res, 0, i_datlocale))
iculocale = PQgetvalue(res, 0, i_daticulocale); locale = PQgetvalue(res, 0, i_datlocale);
else else
iculocale = NULL; locale = NULL;
if (!PQgetisnull(res, 0, i_daticurules)) if (!PQgetisnull(res, 0, i_daticurules))
icurules = PQgetvalue(res, 0, i_daticurules); icurules = PQgetvalue(res, 0, i_daticurules);
else else
@ -3138,11 +3140,12 @@ dumpDatabase(Archive *fout)
appendStringLiteralAH(creaQry, ctype, fout); appendStringLiteralAH(creaQry, ctype, fout);
} }
} }
if (iculocale) if (locale)
{ {
appendPQExpBufferStr(creaQry, " ICU_LOCALE = "); appendPQExpBufferStr(creaQry, " ICU_LOCALE = ");
appendStringLiteralAH(creaQry, iculocale, fout); appendStringLiteralAH(creaQry, locale, fout);
} }
if (icurules) if (icurules)
{ {
appendPQExpBufferStr(creaQry, " ICU_RULES = "); appendPQExpBufferStr(creaQry, " ICU_RULES = ");
@ -13756,12 +13759,12 @@ dumpCollation(Archive *fout, const CollInfo *collinfo)
int i_collisdeterministic; int i_collisdeterministic;
int i_collcollate; int i_collcollate;
int i_collctype; int i_collctype;
int i_colliculocale; int i_colllocale;
int i_collicurules; int i_collicurules;
const char *collprovider; const char *collprovider;
const char *collcollate; const char *collcollate;
const char *collctype; const char *collctype;
const char *colliculocale; const char *colllocale;
const char *collicurules; const char *collicurules;
/* Do nothing in data-only dump */ /* Do nothing in data-only dump */
@ -13793,12 +13796,15 @@ dumpCollation(Archive *fout, const CollInfo *collinfo)
appendPQExpBufferStr(query, appendPQExpBufferStr(query,
"true AS collisdeterministic, "); "true AS collisdeterministic, ");
if (fout->remoteVersion >= 150000) if (fout->remoteVersion >= 170000)
appendPQExpBufferStr(query, appendPQExpBufferStr(query,
"colliculocale, "); "colllocale, ");
else if (fout->remoteVersion >= 150000)
appendPQExpBufferStr(query,
"colliculocale AS colllocale, ");
else else
appendPQExpBufferStr(query, appendPQExpBufferStr(query,
"NULL AS colliculocale, "); "NULL AS colllocale, ");
if (fout->remoteVersion >= 160000) if (fout->remoteVersion >= 160000)
appendPQExpBufferStr(query, appendPQExpBufferStr(query,
@ -13820,7 +13826,7 @@ dumpCollation(Archive *fout, const CollInfo *collinfo)
i_collisdeterministic = PQfnumber(res, "collisdeterministic"); i_collisdeterministic = PQfnumber(res, "collisdeterministic");
i_collcollate = PQfnumber(res, "collcollate"); i_collcollate = PQfnumber(res, "collcollate");
i_collctype = PQfnumber(res, "collctype"); i_collctype = PQfnumber(res, "collctype");
i_colliculocale = PQfnumber(res, "colliculocale"); i_colllocale = PQfnumber(res, "colllocale");
i_collicurules = PQfnumber(res, "collicurules"); i_collicurules = PQfnumber(res, "collicurules");
collprovider = PQgetvalue(res, 0, i_collprovider); collprovider = PQgetvalue(res, 0, i_collprovider);
@ -13847,10 +13853,10 @@ dumpCollation(Archive *fout, const CollInfo *collinfo)
collctype = NULL; collctype = NULL;
} }
if (!PQgetisnull(res, 0, i_colliculocale)) if (!PQgetisnull(res, 0, i_colllocale))
colliculocale = PQgetvalue(res, 0, i_colliculocale); colllocale = PQgetvalue(res, 0, i_colllocale);
else else
colliculocale = NULL; colllocale = NULL;
if (!PQgetisnull(res, 0, i_collicurules)) if (!PQgetisnull(res, 0, i_collicurules))
collicurules = PQgetvalue(res, 0, i_collicurules); collicurules = PQgetvalue(res, 0, i_collicurules);
@ -13880,7 +13886,7 @@ dumpCollation(Archive *fout, const CollInfo *collinfo)
if (collprovider[0] == 'd') if (collprovider[0] == 'd')
{ {
if (collcollate || collctype || colliculocale || collicurules) if (collcollate || collctype || colllocale || collicurules)
pg_log_warning("invalid collation \"%s\"", qcollname); pg_log_warning("invalid collation \"%s\"", qcollname);
/* no locale -- the default collation cannot be reloaded anyway */ /* no locale -- the default collation cannot be reloaded anyway */
@ -13889,16 +13895,16 @@ dumpCollation(Archive *fout, const CollInfo *collinfo)
{ {
if (fout->remoteVersion >= 150000) if (fout->remoteVersion >= 150000)
{ {
if (collcollate || collctype || !colliculocale) if (collcollate || collctype || !colllocale)
pg_log_warning("invalid collation \"%s\"", qcollname); pg_log_warning("invalid collation \"%s\"", qcollname);
appendPQExpBufferStr(q, ", locale = "); appendPQExpBufferStr(q, ", locale = ");
appendStringLiteralAH(q, colliculocale ? colliculocale : "", appendStringLiteralAH(q, colllocale ? colllocale : "",
fout); fout);
} }
else else
{ {
if (!collcollate || !collctype || colliculocale || if (!collcollate || !collctype || colllocale ||
strcmp(collcollate, collctype) != 0) strcmp(collcollate, collctype) != 0)
pg_log_warning("invalid collation \"%s\"", qcollname); pg_log_warning("invalid collation \"%s\"", qcollname);
@ -13914,7 +13920,7 @@ dumpCollation(Archive *fout, const CollInfo *collinfo)
} }
else if (collprovider[0] == 'c') else if (collprovider[0] == 'c')
{ {
if (colliculocale || collicurules || !collcollate || !collctype) if (colllocale || collicurules || !collcollate || !collctype)
pg_log_warning("invalid collation \"%s\"", qcollname); pg_log_warning("invalid collation \"%s\"", qcollname);
if (collcollate && collctype && strcmp(collcollate, collctype) == 0) if (collcollate && collctype && strcmp(collcollate, collctype) == 0)

View File

@ -328,18 +328,24 @@ get_template0_info(ClusterInfo *cluster)
int i_datlocprovider; int i_datlocprovider;
int i_datcollate; int i_datcollate;
int i_datctype; int i_datctype;
int i_daticulocale; int i_datlocale;
if (GET_MAJOR_VERSION(cluster->major_version) >= 1500) if (GET_MAJOR_VERSION(cluster->major_version) >= 1700)
dbres = executeQueryOrDie(conn, dbres = executeQueryOrDie(conn,
"SELECT encoding, datlocprovider, " "SELECT encoding, datlocprovider, "
" datcollate, datctype, daticulocale " " datcollate, datctype, datlocale "
"FROM pg_catalog.pg_database "
"WHERE datname='template0'");
else if (GET_MAJOR_VERSION(cluster->major_version) >= 1500)
dbres = executeQueryOrDie(conn,
"SELECT encoding, datlocprovider, "
" datcollate, datctype, daticulocale AS datlocale "
"FROM pg_catalog.pg_database " "FROM pg_catalog.pg_database "
"WHERE datname='template0'"); "WHERE datname='template0'");
else else
dbres = executeQueryOrDie(conn, dbres = executeQueryOrDie(conn,
"SELECT encoding, 'c' AS datlocprovider, " "SELECT encoding, 'c' AS datlocprovider, "
" datcollate, datctype, NULL AS daticulocale " " datcollate, datctype, NULL AS datlocale "
"FROM pg_catalog.pg_database " "FROM pg_catalog.pg_database "
"WHERE datname='template0'"); "WHERE datname='template0'");
@ -353,16 +359,16 @@ get_template0_info(ClusterInfo *cluster)
i_datlocprovider = PQfnumber(dbres, "datlocprovider"); i_datlocprovider = PQfnumber(dbres, "datlocprovider");
i_datcollate = PQfnumber(dbres, "datcollate"); i_datcollate = PQfnumber(dbres, "datcollate");
i_datctype = PQfnumber(dbres, "datctype"); i_datctype = PQfnumber(dbres, "datctype");
i_daticulocale = PQfnumber(dbres, "daticulocale"); i_datlocale = PQfnumber(dbres, "datlocale");
locale->db_encoding = atoi(PQgetvalue(dbres, 0, i_datencoding)); locale->db_encoding = atoi(PQgetvalue(dbres, 0, i_datencoding));
locale->db_collprovider = PQgetvalue(dbres, 0, i_datlocprovider)[0]; locale->db_collprovider = PQgetvalue(dbres, 0, i_datlocprovider)[0];
locale->db_collate = pg_strdup(PQgetvalue(dbres, 0, i_datcollate)); locale->db_collate = pg_strdup(PQgetvalue(dbres, 0, i_datcollate));
locale->db_ctype = pg_strdup(PQgetvalue(dbres, 0, i_datctype)); locale->db_ctype = pg_strdup(PQgetvalue(dbres, 0, i_datctype));
if (PQgetisnull(dbres, 0, i_daticulocale)) if (PQgetisnull(dbres, 0, i_datlocale))
locale->db_iculocale = NULL; locale->db_locale = NULL;
else else
locale->db_iculocale = pg_strdup(PQgetvalue(dbres, 0, i_daticulocale)); locale->db_locale = pg_strdup(PQgetvalue(dbres, 0, i_datlocale));
cluster->template0 = locale; cluster->template0 = locale;
@ -392,12 +398,15 @@ get_db_infos(ClusterInfo *cluster)
snprintf(query, sizeof(query), snprintf(query, sizeof(query),
"SELECT d.oid, d.datname, d.encoding, d.datcollate, d.datctype, "); "SELECT d.oid, d.datname, d.encoding, d.datcollate, d.datctype, ");
if (GET_MAJOR_VERSION(cluster->major_version) < 1500) if (GET_MAJOR_VERSION(cluster->major_version) >= 1700)
snprintf(query + strlen(query), sizeof(query) - strlen(query), snprintf(query + strlen(query), sizeof(query) - strlen(query),
"'c' AS datlocprovider, NULL AS daticulocale, "); "datlocprovider, datlocale, ");
else if (GET_MAJOR_VERSION(cluster->major_version) >= 1500)
snprintf(query + strlen(query), sizeof(query) - strlen(query),
"datlocprovider, daticulocale AS datlocale, ");
else else
snprintf(query + strlen(query), sizeof(query) - strlen(query), snprintf(query + strlen(query), sizeof(query) - strlen(query),
"datlocprovider, daticulocale, "); "'c' AS datlocprovider, NULL AS datlocale, ");
snprintf(query + strlen(query), sizeof(query) - strlen(query), snprintf(query + strlen(query), sizeof(query) - strlen(query),
"pg_catalog.pg_tablespace_location(t.oid) AS spclocation " "pg_catalog.pg_tablespace_location(t.oid) AS spclocation "
"FROM pg_catalog.pg_database d " "FROM pg_catalog.pg_database d "

View File

@ -391,7 +391,7 @@ setup(char *argv0, bool *live_check)
* Copy locale and encoding information into the new cluster's template0. * Copy locale and encoding information into the new cluster's template0.
* *
* We need to copy the encoding, datlocprovider, datcollate, datctype, and * We need to copy the encoding, datlocprovider, datcollate, datctype, and
* daticulocale. We don't need datcollversion because that's never set for * datlocale. We don't need datcollversion because that's never set for
* template0. * template0.
*/ */
static void static void
@ -400,7 +400,7 @@ set_locale_and_encoding(void)
PGconn *conn_new_template1; PGconn *conn_new_template1;
char *datcollate_literal; char *datcollate_literal;
char *datctype_literal; char *datctype_literal;
char *daticulocale_literal = NULL; char *datlocale_literal = NULL;
DbLocaleInfo *locale = old_cluster.template0; DbLocaleInfo *locale = old_cluster.template0;
prep_status("Setting locale and encoding for new cluster"); prep_status("Setting locale and encoding for new cluster");
@ -414,15 +414,29 @@ set_locale_and_encoding(void)
datctype_literal = PQescapeLiteral(conn_new_template1, datctype_literal = PQescapeLiteral(conn_new_template1,
locale->db_ctype, locale->db_ctype,
strlen(locale->db_ctype)); strlen(locale->db_ctype));
if (locale->db_iculocale) if (locale->db_locale)
daticulocale_literal = PQescapeLiteral(conn_new_template1, datlocale_literal = PQescapeLiteral(conn_new_template1,
locale->db_iculocale, locale->db_locale,
strlen(locale->db_iculocale)); strlen(locale->db_locale));
else else
daticulocale_literal = pg_strdup("NULL"); datlocale_literal = pg_strdup("NULL");
/* update template0 in new cluster */ /* update template0 in new cluster */
if (GET_MAJOR_VERSION(new_cluster.major_version) >= 1500) if (GET_MAJOR_VERSION(new_cluster.major_version) >= 1700)
PQclear(executeQueryOrDie(conn_new_template1,
"UPDATE pg_catalog.pg_database "
" SET encoding = %d, "
" datlocprovider = '%c', "
" datcollate = %s, "
" datctype = %s, "
" datlocale = %s "
" WHERE datname = 'template0' ",
locale->db_encoding,
locale->db_collprovider,
datcollate_literal,
datctype_literal,
datlocale_literal));
else if (GET_MAJOR_VERSION(new_cluster.major_version) >= 1500)
PQclear(executeQueryOrDie(conn_new_template1, PQclear(executeQueryOrDie(conn_new_template1,
"UPDATE pg_catalog.pg_database " "UPDATE pg_catalog.pg_database "
" SET encoding = %d, " " SET encoding = %d, "
@ -435,7 +449,7 @@ set_locale_and_encoding(void)
locale->db_collprovider, locale->db_collprovider,
datcollate_literal, datcollate_literal,
datctype_literal, datctype_literal,
daticulocale_literal)); datlocale_literal));
else else
PQclear(executeQueryOrDie(conn_new_template1, PQclear(executeQueryOrDie(conn_new_template1,
"UPDATE pg_catalog.pg_database " "UPDATE pg_catalog.pg_database "
@ -449,7 +463,7 @@ set_locale_and_encoding(void)
PQfreemem(datcollate_literal); PQfreemem(datcollate_literal);
PQfreemem(datctype_literal); PQfreemem(datctype_literal);
PQfreemem(daticulocale_literal); PQfreemem(datlocale_literal);
PQfinish(conn_new_template1); PQfinish(conn_new_template1);

View File

@ -208,7 +208,7 @@ typedef struct
char *db_collate; char *db_collate;
char *db_ctype; char *db_ctype;
char db_collprovider; char db_collprovider;
char *db_iculocale; char *db_locale;
int db_encoding; int db_encoding;
} DbLocaleInfo; } DbLocaleInfo;

View File

@ -92,6 +92,10 @@ my $oldnode =
PostgreSQL::Test::Cluster->new('old_node', PostgreSQL::Test::Cluster->new('old_node',
install_path => $ENV{oldinstall}); install_path => $ENV{oldinstall});
# Numeric major version of old cluster, ignoring "devel" suffix.
# Needed for testing upgrades from development version to itself.
my $old_major_version = int($oldnode->pg_version =~ s/devel//rg);
my %node_params = (); my %node_params = ();
# To increase coverage of non-standard segment size and group access without # To increase coverage of non-standard segment size and group access without
@ -111,15 +115,22 @@ if ($oldnode->pg_version >= 11)
my $original_encoding = "6"; # UTF-8 my $original_encoding = "6"; # UTF-8
my $original_provider = "c"; my $original_provider = "c";
my $original_locale = "C"; my $original_locale = "C";
my $original_iculocale = ""; my $original_datlocale = "";
my $provider_field = "'c' AS datlocprovider"; my $provider_field = "'c' AS datlocprovider";
my $iculocale_field = "NULL AS daticulocale"; my $old_datlocale_field = "NULL AS datlocale";
if ($oldnode->pg_version >= 15 && $ENV{with_icu} eq 'yes') if ($old_major_version >= 15 && $ENV{with_icu} eq 'yes')
{ {
$provider_field = "datlocprovider"; $provider_field = "datlocprovider";
$iculocale_field = "daticulocale"; if ($old_major_version >= 17)
{
$old_datlocale_field = "datlocale";
}
else
{
$old_datlocale_field = "daticulocale AS datlocale";
}
$original_provider = "i"; $original_provider = "i";
$original_iculocale = "fr-CA"; $original_datlocale = "fr-CA";
} }
my @initdb_params = @custom_opts; my @initdb_params = @custom_opts;
@ -139,10 +150,10 @@ $oldnode->start;
my $result; my $result;
$result = $oldnode->safe_psql( $result = $oldnode->safe_psql(
'postgres', 'postgres',
"SELECT encoding, $provider_field, datcollate, datctype, $iculocale_field "SELECT encoding, $provider_field, datcollate, datctype, $old_datlocale_field
FROM pg_database WHERE datname='template0'"); FROM pg_database WHERE datname='template0'");
is( $result, is( $result,
"$original_encoding|$original_provider|$original_locale|$original_locale|$original_iculocale", "$original_encoding|$original_provider|$original_locale|$original_locale|$original_datlocale",
"check locales in original cluster"); "check locales in original cluster");
# The default location of the source code is the root of this directory. # The default location of the source code is the root of this directory.
@ -426,10 +437,10 @@ if (-d $log_path)
# Test that upgraded cluster has original locale settings. # Test that upgraded cluster has original locale settings.
$result = $newnode->safe_psql( $result = $newnode->safe_psql(
'postgres', 'postgres',
"SELECT encoding, $provider_field, datcollate, datctype, $iculocale_field "SELECT encoding, $provider_field, datcollate, datctype, datlocale
FROM pg_database WHERE datname='template0'"); FROM pg_database WHERE datname='template0'");
is( $result, is( $result,
"$original_encoding|$original_provider|$original_locale|$original_locale|$original_iculocale", "$original_encoding|$original_provider|$original_locale|$original_locale|$original_datlocale",
"check that locales in new cluster match original cluster"); "check that locales in new cluster match original cluster");
# Second dump from the upgraded instance. # Second dump from the upgraded instance.

View File

@ -937,14 +937,18 @@ listAllDbs(const char *pattern, bool verbose)
" d.datctype as \"%s\",\n", " d.datctype as \"%s\",\n",
gettext_noop("Collate"), gettext_noop("Collate"),
gettext_noop("Ctype")); gettext_noop("Ctype"));
if (pset.sversion >= 150000) if (pset.sversion >= 170000)
appendPQExpBuffer(&buf,
" d.datlocale as \"%s\",\n",
gettext_noop("Locale"));
else if (pset.sversion >= 150000)
appendPQExpBuffer(&buf, appendPQExpBuffer(&buf,
" d.daticulocale as \"%s\",\n", " d.daticulocale as \"%s\",\n",
gettext_noop("ICU Locale")); gettext_noop("Locale"));
else else
appendPQExpBuffer(&buf, appendPQExpBuffer(&buf,
" NULL as \"%s\",\n", " NULL as \"%s\",\n",
gettext_noop("ICU Locale")); gettext_noop("Locale"));
if (pset.sversion >= 160000) if (pset.sversion >= 160000)
appendPQExpBuffer(&buf, appendPQExpBuffer(&buf,
" d.daticurules as \"%s\",\n", " d.daticurules as \"%s\",\n",
@ -4983,14 +4987,18 @@ listCollations(const char *pattern, bool verbose, bool showSystem)
gettext_noop("Collate"), gettext_noop("Collate"),
gettext_noop("Ctype")); gettext_noop("Ctype"));
if (pset.sversion >= 150000) if (pset.sversion >= 170000)
appendPQExpBuffer(&buf,
" c.colllocale AS \"%s\",\n",
gettext_noop("Locale"));
else if (pset.sversion >= 150000)
appendPQExpBuffer(&buf, appendPQExpBuffer(&buf,
" c.colliculocale AS \"%s\",\n", " c.colliculocale AS \"%s\",\n",
gettext_noop("ICU Locale")); gettext_noop("Locale"));
else else
appendPQExpBuffer(&buf, appendPQExpBuffer(&buf,
" c.collcollate AS \"%s\",\n", " c.collcollate AS \"%s\",\n",
gettext_noop("ICU Locale")); gettext_noop("Locale"));
if (pset.sversion >= 160000) if (pset.sversion >= 160000)
appendPQExpBuffer(&buf, appendPQExpBuffer(&buf,

View File

@ -57,6 +57,6 @@
*/ */
/* yyyymmddN */ /* yyyymmddN */
#define CATALOG_VERSION_NO 202403071 #define CATALOG_VERSION_NO 202403091
#endif #endif

View File

@ -29,6 +29,6 @@
{ oid => '963', { oid => '963',
descr => 'sorts using the Unicode Collation Algorithm with default settings', descr => 'sorts using the Unicode Collation Algorithm with default settings',
collname => 'unicode', collprovider => 'i', collencoding => '-1', collname => 'unicode', collprovider => 'i', collencoding => '-1',
colliculocale => 'und' }, colllocale => 'und' },
] ]

View File

@ -42,7 +42,7 @@ CATALOG(pg_collation,3456,CollationRelationId)
#ifdef CATALOG_VARLEN /* variable-length fields start here */ #ifdef CATALOG_VARLEN /* variable-length fields start here */
text collcollate BKI_DEFAULT(_null_); /* LC_COLLATE setting */ text collcollate BKI_DEFAULT(_null_); /* LC_COLLATE setting */
text collctype BKI_DEFAULT(_null_); /* LC_CTYPE setting */ text collctype BKI_DEFAULT(_null_); /* LC_CTYPE setting */
text colliculocale BKI_DEFAULT(_null_); /* ICU locale ID */ text colllocale BKI_DEFAULT(_null_); /* locale ID */
text collicurules BKI_DEFAULT(_null_); /* ICU collation rules */ text collicurules BKI_DEFAULT(_null_); /* ICU collation rules */
text collversion BKI_DEFAULT(_null_); /* provider-dependent text collversion BKI_DEFAULT(_null_); /* provider-dependent
* version of collation * version of collation
@ -94,7 +94,7 @@ extern Oid CollationCreate(const char *collname, Oid collnamespace,
bool collisdeterministic, bool collisdeterministic,
int32 collencoding, int32 collencoding,
const char *collcollate, const char *collctype, const char *collcollate, const char *collctype,
const char *colliculocale, const char *colllocale,
const char *collicurules, const char *collicurules,
const char *collversion, const char *collversion,
bool if_not_exists, bool if_not_exists,

View File

@ -18,7 +18,7 @@
datlocprovider => 'LOCALE_PROVIDER', datistemplate => 't', datlocprovider => 'LOCALE_PROVIDER', datistemplate => 't',
datallowconn => 't', dathasloginevt => 'f', datconnlimit => '-1', datfrozenxid => '0', datallowconn => 't', dathasloginevt => 'f', datconnlimit => '-1', datfrozenxid => '0',
datminmxid => '1', dattablespace => 'pg_default', datcollate => 'LC_COLLATE', datminmxid => '1', dattablespace => 'pg_default', datcollate => 'LC_COLLATE',
datctype => 'LC_CTYPE', daticulocale => 'ICU_LOCALE', datctype => 'LC_CTYPE', datlocale => 'DATLOCALE',
daticurules => 'ICU_RULES', datacl => '_null_' }, daticurules => 'ICU_RULES', datacl => '_null_' },
] ]

View File

@ -75,7 +75,7 @@ CATALOG(pg_database,1262,DatabaseRelationId) BKI_SHARED_RELATION BKI_ROWTYPE_OID
text datctype BKI_FORCE_NOT_NULL; text datctype BKI_FORCE_NOT_NULL;
/* ICU locale ID */ /* ICU locale ID */
text daticulocale; text datlocale;
/* ICU collation rules */ /* ICU collation rules */
text daticurules; text daticurules;

View File

@ -1024,7 +1024,7 @@ SET icu_validation_level = disabled;
do $$ do $$
BEGIN BEGIN
EXECUTE 'CREATE COLLATION test0 (provider = icu, locale = ' || EXECUTE 'CREATE COLLATION test0 (provider = icu, locale = ' ||
quote_literal((SELECT CASE WHEN datlocprovider='i' THEN daticulocale ELSE datcollate END FROM pg_database WHERE datname = current_database())) || ');'; quote_literal((SELECT CASE WHEN datlocprovider='i' THEN datlocale ELSE datcollate END FROM pg_database WHERE datname = current_database())) || ');';
END END
$$; $$;
CREATE COLLATION test0 FROM "C"; -- fail, duplicate name CREATE COLLATION test0 FROM "C"; -- fail, duplicate name
@ -1032,7 +1032,7 @@ ERROR: collation "test0" already exists
do $$ do $$
BEGIN BEGIN
EXECUTE 'CREATE COLLATION test1 (provider = icu, locale = ' || EXECUTE 'CREATE COLLATION test1 (provider = icu, locale = ' ||
quote_literal((SELECT CASE WHEN datlocprovider='i' THEN daticulocale ELSE datcollate END FROM pg_database WHERE datname = current_database())) || ');'; quote_literal((SELECT CASE WHEN datlocprovider='i' THEN datlocale ELSE datcollate END FROM pg_database WHERE datname = current_database())) || ');';
END END
$$; $$;
RESET icu_validation_level; RESET icu_validation_level;

View File

@ -6222,8 +6222,8 @@ List of schemas
\dO "no.such.collation" \dO "no.such.collation"
List of collations List of collations
Schema | Name | Provider | Collate | Ctype | ICU Locale | ICU Rules | Deterministic? Schema | Name | Provider | Collate | Ctype | Locale | ICU Rules | Deterministic?
--------+------+----------+---------+-------+------------+-----------+---------------- --------+------+----------+---------+-------+--------+-----------+----------------
(0 rows) (0 rows)
\dp "no.such.access.privilege" \dp "no.such.access.privilege"
@ -6411,8 +6411,8 @@ cross-database references are not implemented: "no.such.schema"."no.such.languag
\dO "no.such.schema"."no.such.collation" \dO "no.such.schema"."no.such.collation"
List of collations List of collations
Schema | Name | Provider | Collate | Ctype | ICU Locale | ICU Rules | Deterministic? Schema | Name | Provider | Collate | Ctype | Locale | ICU Rules | Deterministic?
--------+------+----------+---------+-------+------------+-----------+---------------- --------+------+----------+---------+-------+--------+-----------+----------------
(0 rows) (0 rows)
\dp "no.such.schema"."no.such.access.privilege" \dp "no.such.schema"."no.such.access.privilege"
@ -6554,8 +6554,8 @@ List of text search templates
\dO regression."no.such.schema"."no.such.collation" \dO regression."no.such.schema"."no.such.collation"
List of collations List of collations
Schema | Name | Provider | Collate | Ctype | ICU Locale | ICU Rules | Deterministic? Schema | Name | Provider | Collate | Ctype | Locale | ICU Rules | Deterministic?
--------+------+----------+---------+-------+------------+-----------+---------------- --------+------+----------+---------+-------+--------+-----------+----------------
(0 rows) (0 rows)
\dp regression."no.such.schema"."no.such.access.privilege" \dp regression."no.such.schema"."no.such.access.privilege"

View File

@ -363,14 +363,14 @@ SET icu_validation_level = disabled;
do $$ do $$
BEGIN BEGIN
EXECUTE 'CREATE COLLATION test0 (provider = icu, locale = ' || EXECUTE 'CREATE COLLATION test0 (provider = icu, locale = ' ||
quote_literal((SELECT CASE WHEN datlocprovider='i' THEN daticulocale ELSE datcollate END FROM pg_database WHERE datname = current_database())) || ');'; quote_literal((SELECT CASE WHEN datlocprovider='i' THEN datlocale ELSE datcollate END FROM pg_database WHERE datname = current_database())) || ');';
END END
$$; $$;
CREATE COLLATION test0 FROM "C"; -- fail, duplicate name CREATE COLLATION test0 FROM "C"; -- fail, duplicate name
do $$ do $$
BEGIN BEGIN
EXECUTE 'CREATE COLLATION test1 (provider = icu, locale = ' || EXECUTE 'CREATE COLLATION test1 (provider = icu, locale = ' ||
quote_literal((SELECT CASE WHEN datlocprovider='i' THEN daticulocale ELSE datcollate END FROM pg_database WHERE datname = current_database())) || ');'; quote_literal((SELECT CASE WHEN datlocprovider='i' THEN datlocale ELSE datcollate END FROM pg_database WHERE datname = current_database())) || ');';
END END
$$; $$;