From b518dbaf78d09c78525ffbb9322ea91bb141c941 Mon Sep 17 00:00:00 2001 From: naisila Date: Wed, 27 Jul 2022 12:07:04 +0300 Subject: [PATCH] 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 --- src/backend/distributed/commands/collation.c | 78 +++++++++++++-- src/test/regress/expected/pg15.out | 100 +++++++++++++++++++ src/test/regress/expected/pg15_0.out | 9 ++ src/test/regress/multi_schedule | 1 + src/test/regress/sql/pg15.sql | 62 ++++++++++++ 5 files changed, 244 insertions(+), 6 deletions(-) create mode 100644 src/test/regress/expected/pg15.out create mode 100644 src/test/regress/expected/pg15_0.out create mode 100644 src/test/regress/sql/pg15.sql diff --git a/src/backend/distributed/commands/collation.c b/src/backend/distributed/commands/collation.c index 8904ab674..879dbeeba 100644 --- a/src/backend/distributed/commands/collation.c +++ b/src/backend/distributed/commands/collation.c @@ -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) { diff --git a/src/test/regress/expected/pg15.out b/src/test/regress/expected/pg15.out new file mode 100644 index 000000000..f7aede2e1 --- /dev/null +++ b/src/test/regress/expected/pg15.out @@ -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 diff --git a/src/test/regress/expected/pg15_0.out b/src/test/regress/expected/pg15_0.out new file mode 100644 index 000000000..8e76ebbcf --- /dev/null +++ b/src/test/regress/expected/pg15_0.out @@ -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 diff --git a/src/test/regress/multi_schedule b/src/test/regress/multi_schedule index 58cfc87c8..22caeffad 100644 --- a/src/test/regress/multi_schedule +++ b/src/test/regress/multi_schedule @@ -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 diff --git a/src/test/regress/sql/pg15.sql b/src/test/regress/sql/pg15.sql new file mode 100644 index 000000000..e1b1b30a8 --- /dev/null +++ b/src/test/regress/sql/pg15.sql @@ -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;