Handle new option colliculocale in CREATE COLLATION logic

In PG15, there is an added option to use ICU as global locale provider.
pg_collation has three locale-related fields: collcollate and collctype,
which are libc-related fields, and a new one colliculocale, which is the
ICU-related field. Only the libc-related fields or the ICU-related field
is set, never both.

Relevant PG commits:
f2553d43060edb210b36c63187d52a632448e1d2
54637508f87bd5f07fb9406bac6b08240283be3b
pg_15_iso_fix
naisila 2022-07-27 12:07:04 +03:00
parent ab802038da
commit c8888e19d1
5 changed files with 244 additions and 6 deletions

View File

@ -63,15 +63,53 @@ CreateCollationDDLInternal(Oid collationId, Oid *collowner, char **quotedCollati
const char *collname = NameStr(collationForm->collname);
bool collisdeterministic = collationForm->collisdeterministic;
char *collcollate;
char *collctype;
#if PG_VERSION_NUM >= PG_VERSION_15
/*
* In PG15, there is an added option to use ICU as global locale provider.
* pg_collation has three locale-related fields: collcollate and collctype,
* which are libc-related fields, and a new one colliculocale, which is the
* ICU-related field. Only the libc-related fields or the ICU-related field
* is set, never both.
*/
char *colliculocale;
bool isnull;
Datum datum = SysCacheGetAttr(COLLOID, heapTuple, Anum_pg_collation_collcollate,
&isnull);
Assert(!isnull);
char *collcollate = TextDatumGetCString(datum);
if (!isnull)
{
collcollate = TextDatumGetCString(datum);
}
else
{
collcollate = NULL;
}
datum = SysCacheGetAttr(COLLOID, heapTuple, Anum_pg_collation_collctype, &isnull);
Assert(!isnull);
char *collctype = TextDatumGetCString(datum);
if (!isnull)
{
collctype = TextDatumGetCString(datum);
}
else
{
collctype = NULL;
}
datum = SysCacheGetAttr(COLLOID, heapTuple, Anum_pg_collation_colliculocale, &isnull);
if (!isnull)
{
colliculocale = TextDatumGetCString(datum);
}
else
{
colliculocale = NULL;
}
AssertArg((collcollate && collctype) || colliculocale);
#else
/*
@ -79,8 +117,8 @@ CreateCollationDDLInternal(Oid collationId, Oid *collowner, char **quotedCollati
* pstrdup() to match the interface of 15 so that we consistently free the
* result later.
*/
char *collcollate = pstrdup(NameStr(collationForm->collcollate));
char *collctype = pstrdup(NameStr(collationForm->collctype));
collcollate = pstrdup(NameStr(collationForm->collcollate));
collctype = pstrdup(NameStr(collationForm->collctype));
#endif
if (collowner != NULL)
@ -106,6 +144,33 @@ CreateCollationDDLInternal(Oid collationId, Oid *collowner, char **quotedCollati
"CREATE COLLATION %s (provider = '%s'",
*quotedCollationName, providerString);
#if PG_VERSION_NUM >= PG_VERSION_15
if (colliculocale)
{
appendStringInfo(&collationNameDef,
", locale = %s",
quote_literal_cstr(colliculocale));
pfree(colliculocale);
}
else
{
if (strcmp(collcollate, collctype) == 0)
{
appendStringInfo(&collationNameDef,
", locale = %s",
quote_literal_cstr(collcollate));
}
else
{
appendStringInfo(&collationNameDef,
", lc_collate = %s, lc_ctype = %s",
quote_literal_cstr(collcollate),
quote_literal_cstr(collctype));
}
pfree(collcollate);
pfree(collctype);
}
#else
if (strcmp(collcollate, collctype) == 0)
{
appendStringInfo(&collationNameDef,
@ -122,6 +187,7 @@ CreateCollationDDLInternal(Oid collationId, Oid *collowner, char **quotedCollati
pfree(collcollate);
pfree(collctype);
#endif
if (!collisdeterministic)
{

View File

@ -0,0 +1,100 @@
--
-- PG15
--
SHOW server_version \gset
SELECT substring(:'server_version', '\d+')::int > 14 AS server_version_above_fourteen
\gset
\if :server_version_above_fourteen
\else
\q
\endif
CREATE SCHEMA pg15;
SET search_path TO pg15;
SET citus.next_shard_id TO 960000;
SET citus.shard_count TO 4;
--
-- In PG15, there is an added option to use ICU as global locale provider.
-- pg_collation has three locale-related fields: collcollate and collctype,
-- which are libc-related fields, and a new one colliculocale, which is the
-- ICU-related field. Only the libc-related fields or the ICU-related field
-- is set, never both.
-- Relevant PG commits:
-- f2553d43060edb210b36c63187d52a632448e1d2
-- 54637508f87bd5f07fb9406bac6b08240283be3b
--
-- fail, needs "locale"
CREATE COLLATION german_phonebook_test (provider = icu, lc_collate = 'de-u-co-phonebk');
ERROR: parameter "locale" must be specified
-- fail, needs "locale"
CREATE COLLATION german_phonebook_test (provider = icu, lc_collate = 'de-u-co-phonebk', lc_ctype = 'de-u-co-phonebk');
ERROR: parameter "locale" must be specified
-- works
CREATE COLLATION german_phonebook_test (provider = icu, locale = 'de-u-co-phonebk');
-- with icu provider, colliculocale will be set, collcollate and collctype will be null
SELECT result FROM run_command_on_all_nodes('
SELECT collcollate FROM pg_collation WHERE collname = ''german_phonebook_test'';
');
result
---------------------------------------------------------------------
(3 rows)
SELECT result FROM run_command_on_all_nodes('
SELECT collctype FROM pg_collation WHERE collname = ''german_phonebook_test'';
');
result
---------------------------------------------------------------------
(3 rows)
SELECT result FROM run_command_on_all_nodes('
SELECT colliculocale FROM pg_collation WHERE collname = ''german_phonebook_test'';
');
result
---------------------------------------------------------------------
de-u-co-phonebk
de-u-co-phonebk
de-u-co-phonebk
(3 rows)
-- with non-icu provider, colliculocale will be null, collcollate and collctype will be set
CREATE COLLATION default_provider (provider = libc, lc_collate = "POSIX", lc_ctype = "POSIX");
SELECT result FROM run_command_on_all_nodes('
SELECT collcollate FROM pg_collation WHERE collname = ''default_provider'';
');
result
---------------------------------------------------------------------
POSIX
POSIX
POSIX
(3 rows)
SELECT result FROM run_command_on_all_nodes('
SELECT collctype FROM pg_collation WHERE collname = ''default_provider'';
');
result
---------------------------------------------------------------------
POSIX
POSIX
POSIX
(3 rows)
SELECT result FROM run_command_on_all_nodes('
SELECT colliculocale FROM pg_collation WHERE collname = ''default_provider'';
');
result
---------------------------------------------------------------------
(3 rows)
-- Clean up
DROP SCHEMA pg15 CASCADE;
NOTICE: drop cascades to 2 other objects
DETAIL: drop cascades to collation german_phonebook_test
drop cascades to collation default_provider

View File

@ -0,0 +1,9 @@
--
-- PG15
--
SHOW server_version \gset
SELECT substring(:'server_version', '\d+')::int > 14 AS server_version_above_fourteen
\gset
\if :server_version_above_fourteen
\else
\q

View File

@ -58,6 +58,7 @@ test: cte_inline recursive_view_local_table values sequences_with_different_type
test: pg13 pg12
# run pg14 sequentially as it syncs metadata
test: pg14
test: pg15
test: drop_column_partitioned_table
test: tableam

View File

@ -0,0 +1,62 @@
--
-- PG15
--
SHOW server_version \gset
SELECT substring(:'server_version', '\d+')::int > 14 AS server_version_above_fourteen
\gset
\if :server_version_above_fourteen
\else
\q
\endif
CREATE SCHEMA pg15;
SET search_path TO pg15;
SET citus.next_shard_id TO 960000;
SET citus.shard_count TO 4;
--
-- In PG15, there is an added option to use ICU as global locale provider.
-- pg_collation has three locale-related fields: collcollate and collctype,
-- which are libc-related fields, and a new one colliculocale, which is the
-- ICU-related field. Only the libc-related fields or the ICU-related field
-- is set, never both.
-- Relevant PG commits:
-- f2553d43060edb210b36c63187d52a632448e1d2
-- 54637508f87bd5f07fb9406bac6b08240283be3b
--
-- fail, needs "locale"
CREATE COLLATION german_phonebook_test (provider = icu, lc_collate = 'de-u-co-phonebk');
-- fail, needs "locale"
CREATE COLLATION german_phonebook_test (provider = icu, lc_collate = 'de-u-co-phonebk', lc_ctype = 'de-u-co-phonebk');
-- works
CREATE COLLATION german_phonebook_test (provider = icu, locale = 'de-u-co-phonebk');
-- with icu provider, colliculocale will be set, collcollate and collctype will be null
SELECT result FROM run_command_on_all_nodes('
SELECT collcollate FROM pg_collation WHERE collname = ''german_phonebook_test'';
');
SELECT result FROM run_command_on_all_nodes('
SELECT collctype FROM pg_collation WHERE collname = ''german_phonebook_test'';
');
SELECT result FROM run_command_on_all_nodes('
SELECT colliculocale FROM pg_collation WHERE collname = ''german_phonebook_test'';
');
-- with non-icu provider, colliculocale will be null, collcollate and collctype will be set
CREATE COLLATION default_provider (provider = libc, lc_collate = "POSIX", lc_ctype = "POSIX");
SELECT result FROM run_command_on_all_nodes('
SELECT collcollate FROM pg_collation WHERE collname = ''default_provider'';
');
SELECT result FROM run_command_on_all_nodes('
SELECT collctype FROM pg_collation WHERE collname = ''default_provider'';
');
SELECT result FROM run_command_on_all_nodes('
SELECT colliculocale FROM pg_collation WHERE collname = ''default_provider'';
');
-- Clean up
DROP SCHEMA pg15 CASCADE;