public inbox for [email protected]help / color / mirror / Atom feed
[PATCH v5 2/2] New command ALTER TABLE ALL IN TABLESPACE SET LOGGED/UNLOGGED 3+ messages / 3 participants [nested] [flat]
* [PATCH v5 2/2] New command ALTER TABLE ALL IN TABLESPACE SET LOGGED/UNLOGGED @ 2020-11-11 14:21 Kyotaro Horiguchi <[email protected]> 0 siblings, 0 replies; 3+ messages in thread From: Kyotaro Horiguchi @ 2020-11-11 14:21 UTC (permalink / raw) To ease invoking ALTER TABLE SET LOGGED/UNLOGGED, this command changes relation persistence of all tables in the specified tablespace. --- src/backend/commands/tablecmds.c | 140 +++++++++++++++++++++++++++++++ src/backend/nodes/copyfuncs.c | 16 ++++ src/backend/nodes/equalfuncs.c | 15 ++++ src/backend/parser/gram.y | 20 +++++ src/backend/tcop/utility.c | 11 +++ src/include/commands/tablecmds.h | 2 + src/include/nodes/nodes.h | 1 + src/include/nodes/parsenodes.h | 9 ++ 8 files changed, 214 insertions(+) diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index 37a15d31ee..2f65abb19b 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -13696,6 +13696,146 @@ AlterTableMoveAll(AlterTableMoveAllStmt *stmt) return new_tablespaceoid; } +/* + * Alter Table ALL ... SET LOGGED/UNLOGGED + * + * Allows a user to change persistence of all objects in a given tablespace in + * the current database. Objects can be chosen based on the owner of the + * object also, to allow users to change persistene only their objects. The + * main permissions handling is done by the lower-level change persistence + * function. + * + * All to-be-modified objects are locked first. If NOWAIT is specified and the + * lock can't be acquired then we ereport(ERROR). + */ +void +AlterTableSetLoggedAll(AlterTableSetLoggedAllStmt *stmt) +{ + List *relations = NIL; + ListCell *l; + ScanKeyData key[1]; + Relation rel; + TableScanDesc scan; + HeapTuple tuple; + Oid tablespaceoid; + List *role_oids = roleSpecsToIds(NIL); + + /* Ensure we were not asked to change something we can't */ + if (stmt->objtype != OBJECT_TABLE) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("only tables can be specified"))); + + /* Get the tablespace OID */ + tablespaceoid = get_tablespace_oid(stmt->tablespacename, false); + + /* + * Now that the checks are done, check if we should set either to + * InvalidOid because it is our database's default tablespace. + */ + if (tablespaceoid == MyDatabaseTableSpace) + tablespaceoid = InvalidOid; + + /* + * Walk the list of objects in the tablespace to pick up them. This will + * only find objects in our database, of course. + */ + ScanKeyInit(&key[0], + Anum_pg_class_reltablespace, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(tablespaceoid)); + + rel = table_open(RelationRelationId, AccessShareLock); + scan = table_beginscan_catalog(rel, 1, key); + while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL) + { + Form_pg_class relForm = (Form_pg_class) GETSTRUCT(tuple); + Oid relOid = relForm->oid; + + /* + * Do not pick-up objects in pg_catalog as part of this, if an admin + * really wishes to do so, they can issue the individual ALTER + * commands directly. + * + * Also, explicitly avoid any shared tables, temp tables, or TOAST + * (TOAST will be changed with the main table). + */ + if (IsCatalogNamespace(relForm->relnamespace) || + relForm->relisshared || + isAnyTempNamespace(relForm->relnamespace) || + IsToastNamespace(relForm->relnamespace)) + continue; + + /* Only pick up the object type requested */ + if (relForm->relkind != RELKIND_RELATION) + continue; + + /* Check if we are only picking-up objects owned by certain roles */ + if (role_oids != NIL && !list_member_oid(role_oids, relForm->relowner)) + continue; + + /* + * Handle permissions-checking here since we are locking the tables + * and also to avoid doing a bunch of work only to fail part-way. Note + * that permissions will also be checked by AlterTableInternal(). + * + * Caller must be considered an owner on the table of which we're going + * to change persistence. + */ + if (!pg_class_ownercheck(relOid, GetUserId())) + aclcheck_error(ACLCHECK_NOT_OWNER, get_relkind_objtype(get_rel_relkind(relOid)), + NameStr(relForm->relname)); + + if (stmt->nowait && + !ConditionalLockRelationOid(relOid, AccessExclusiveLock)) + ereport(ERROR, + (errcode(ERRCODE_OBJECT_IN_USE), + errmsg("aborting because lock on relation \"%s.%s\" is not available", + get_namespace_name(relForm->relnamespace), + NameStr(relForm->relname)))); + else + LockRelationOid(relOid, AccessExclusiveLock); + + /* + * Add to our list of objects of which we're going to change + * persistence. + */ + relations = lappend_oid(relations, relOid); + } + + table_endscan(scan); + table_close(rel, AccessShareLock); + + if (relations == NIL) + ereport(NOTICE, + (errcode(ERRCODE_NO_DATA_FOUND), + errmsg("no matching relations in tablespace \"%s\" found", + tablespaceoid == InvalidOid ? "(database default)" : + get_tablespace_name(tablespaceoid)))); + + /* + * Everything is locked, loop through and change persistence of all of the + * relations. + */ + foreach(l, relations) + { + List *cmds = NIL; + AlterTableCmd *cmd = makeNode(AlterTableCmd); + + if (stmt->logged) + cmd->subtype = AT_SetLogged; + else + cmd->subtype = AT_SetUnLogged; + + cmds = lappend(cmds, cmd); + + EventTriggerAlterTableStart((Node *) stmt); + /* OID is set by AlterTableInternal */ + AlterTableInternal(lfirst_oid(l), cmds, false); + EventTriggerAlterTableEnd(); + } +} + static void index_copy_data(Relation rel, RelFileNode newrnode) { diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c index ba3ccc712c..127da5151d 100644 --- a/src/backend/nodes/copyfuncs.c +++ b/src/backend/nodes/copyfuncs.c @@ -4138,6 +4138,19 @@ _copyAlterTableMoveAllStmt(const AlterTableMoveAllStmt *from) return newnode; } +static AlterTableSetLoggedAllStmt * +_copyAlterTableSetLoggedAllStmt(const AlterTableSetLoggedAllStmt *from) +{ + AlterTableSetLoggedAllStmt *newnode = makeNode(AlterTableSetLoggedAllStmt); + + COPY_STRING_FIELD(tablespacename); + COPY_SCALAR_FIELD(objtype); + COPY_SCALAR_FIELD(logged); + COPY_SCALAR_FIELD(nowait); + + return newnode; +} + static CreateExtensionStmt * _copyCreateExtensionStmt(const CreateExtensionStmt *from) { @@ -5441,6 +5454,9 @@ copyObjectImpl(const void *from) case T_AlterTableMoveAllStmt: retval = _copyAlterTableMoveAllStmt(from); break; + case T_AlterTableSetLoggedAllStmt: + retval = _copyAlterTableSetLoggedAllStmt(from); + break; case T_CreateExtensionStmt: retval = _copyCreateExtensionStmt(from); break; diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c index a2ef853dc2..4f13a1762b 100644 --- a/src/backend/nodes/equalfuncs.c +++ b/src/backend/nodes/equalfuncs.c @@ -1872,6 +1872,18 @@ _equalAlterTableMoveAllStmt(const AlterTableMoveAllStmt *a, return true; } +static bool +_equalAlterTableSetLoggedAllStmt(const AlterTableSetLoggedAllStmt *a, + const AlterTableSetLoggedAllStmt *b) +{ + COMPARE_STRING_FIELD(tablespacename); + COMPARE_SCALAR_FIELD(objtype); + COMPARE_SCALAR_FIELD(logged); + COMPARE_SCALAR_FIELD(nowait); + + return true; +} + static bool _equalCreateExtensionStmt(const CreateExtensionStmt *a, const CreateExtensionStmt *b) { @@ -3494,6 +3506,9 @@ equal(const void *a, const void *b) case T_AlterTableMoveAllStmt: retval = _equalAlterTableMoveAllStmt(a, b); break; + case T_AlterTableSetLoggedAllStmt: + retval = _equalAlterTableSetLoggedAllStmt(a, b); + break; case T_CreateExtensionStmt: retval = _equalCreateExtensionStmt(a, b); break; diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index 31c95443a5..2222fd8fe3 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -1934,6 +1934,26 @@ AlterTableStmt: n->nowait = $13; $$ = (Node *)n; } + | ALTER TABLE ALL IN_P TABLESPACE name SET LOGGED opt_nowait + { + AlterTableSetLoggedAllStmt *n = + makeNode(AlterTableSetLoggedAllStmt); + n->tablespacename = $6; + n->objtype = OBJECT_TABLE; + n->logged = true; + n->nowait = $9; + $$ = (Node *)n; + } + | ALTER TABLE ALL IN_P TABLESPACE name SET UNLOGGED opt_nowait + { + AlterTableSetLoggedAllStmt *n = + makeNode(AlterTableSetLoggedAllStmt); + n->tablespacename = $6; + n->objtype = OBJECT_TABLE; + n->logged = false; + n->nowait = $9; + $$ = (Node *)n; + } | ALTER INDEX qualified_name alter_table_cmds { AlterTableStmt *n = makeNode(AlterTableStmt); diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c index 53a511f1da..16606448bf 100644 --- a/src/backend/tcop/utility.c +++ b/src/backend/tcop/utility.c @@ -161,6 +161,7 @@ ClassifyUtilityCommandAsReadOnly(Node *parsetree) case T_AlterTSConfigurationStmt: case T_AlterTSDictionaryStmt: case T_AlterTableMoveAllStmt: + case T_AlterTableSetLoggedAllStmt: case T_AlterTableSpaceOptionsStmt: case T_AlterTableStmt: case T_AlterTypeStmt: @@ -1732,6 +1733,12 @@ ProcessUtilitySlow(ParseState *pstate, commandCollected = true; break; + case T_AlterTableSetLoggedAllStmt: + AlterTableSetLoggedAll((AlterTableSetLoggedAllStmt *) parsetree); + /* commands are stashed in AlterTableSetLoggedAll */ + commandCollected = true; + break; + case T_DropStmt: ExecDropStmt((DropStmt *) parsetree, isTopLevel); /* no commands stashed for DROP */ @@ -2619,6 +2626,10 @@ CreateCommandTag(Node *parsetree) tag = AlterObjectTypeCommandTag(((AlterTableMoveAllStmt *) parsetree)->objtype); break; + case T_AlterTableSetLoggedAllStmt: + tag = AlterObjectTypeCommandTag(((AlterTableSetLoggedAllStmt *) parsetree)->objtype); + break; + case T_AlterTableStmt: tag = AlterObjectTypeCommandTag(((AlterTableStmt *) parsetree)->objtype); break; diff --git a/src/include/commands/tablecmds.h b/src/include/commands/tablecmds.h index 08c463d3c4..646928466d 100644 --- a/src/include/commands/tablecmds.h +++ b/src/include/commands/tablecmds.h @@ -42,6 +42,8 @@ extern void AlterTableInternal(Oid relid, List *cmds, bool recurse); extern Oid AlterTableMoveAll(AlterTableMoveAllStmt *stmt); +extern void AlterTableSetLoggedAll(AlterTableSetLoggedAllStmt *stmt); + extern ObjectAddress AlterTableNamespace(AlterObjectSchemaStmt *stmt, Oid *oldschema); diff --git a/src/include/nodes/nodes.h b/src/include/nodes/nodes.h index caed683ba9..16d91d3e1d 100644 --- a/src/include/nodes/nodes.h +++ b/src/include/nodes/nodes.h @@ -424,6 +424,7 @@ typedef enum NodeTag T_AlterCollationStmt, T_CallStmt, T_AlterStatsStmt, + T_AlterTableSetLoggedAllStmt, /* * TAGS FOR PARSE TREE NODES (parsenodes.h) diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h index dc2bb40926..c3eab6f1ab 100644 --- a/src/include/nodes/parsenodes.h +++ b/src/include/nodes/parsenodes.h @@ -2253,6 +2253,15 @@ typedef struct AlterTableMoveAllStmt bool nowait; } AlterTableMoveAllStmt; +typedef struct AlterTableSetLoggedAllStmt +{ + NodeTag type; + char *tablespacename; + ObjectType objtype; /* Object type to move */ + bool logged; + bool nowait; +} AlterTableSetLoggedAllStmt; + /* ---------------------- * Create/Alter Extension Statements * ---------------------- -- 2.27.0 ----Next_Part(Thu_Jan_14_17_32_17_2021_289)---- ^ permalink raw reply [nested|flat] 3+ messages in thread
* Re: collation-related loose ends before beta2 @ 2023-06-20 16:16 Tom Lane <[email protected]> 0 siblings, 1 reply; 3+ messages in thread From: Tom Lane @ 2023-06-20 16:16 UTC (permalink / raw) To: Jeff Davis <[email protected]>; +Cc: pgsql-hackers; Daniel Verite <[email protected]>; Peter Eisentraut <[email protected]>; Andrew Gierth <[email protected]>; Joe Conway <[email protected]>; Robert Haas <[email protected]>; Jonathan S. Katz <[email protected]>; Peter Geoghegan <[email protected]>; Thomas Munro <[email protected]> Jeff Davis <[email protected]> writes: > Status on collation loose ends: This all sounds good to me. regards, tom lane ^ permalink raw reply [nested|flat] 3+ messages in thread
* Re: collation-related loose ends before beta2 @ 2023-06-20 20:46 Jeff Davis <[email protected]> parent: Tom Lane <[email protected]> 0 siblings, 0 replies; 3+ messages in thread From: Jeff Davis @ 2023-06-20 20:46 UTC (permalink / raw) To: Tom Lane <[email protected]>; +Cc: pgsql-hackers; Daniel Verite <[email protected]>; Peter Eisentraut <[email protected]>; Andrew Gierth <[email protected]>; Joe Conway <[email protected]>; Robert Haas <[email protected]>; Jonathan S. Katz <[email protected]>; Peter Geoghegan <[email protected]>; Thomas Munro <[email protected]> On Tue, 2023-06-20 at 12:16 -0400, Tom Lane wrote: > Jeff Davis <[email protected]> writes: > > Status on collation loose ends: > > This all sounds good to me. Patches attached. 0001 also removes the code to get a default locale when ICU is being used, because that was a part of the same commit that changed the default provider to be ICU and I don't see a lot of value in keeping just that part. I'm planning to commit something similar to the attached patches tomorrow (Wednesday) unless I get more input. Regards, Jeff Davis Attachments: [text/x-patch] v1-0001-initdb-change-default-locale-provider-back-to-lib.patch (9.8K, ../../[email protected]/2-v1-0001-initdb-change-default-locale-provider-back-to-lib.patch) download | inline diff: From 1aaac6e154d9a1e4f728d732fd41ee263db6903e Mon Sep 17 00:00:00 2001 From: Jeff Davis <[email protected]> Date: Tue, 20 Jun 2023 12:03:26 -0700 Subject: [PATCH v1 1/2] initdb: change default --locale-provider back to libc. Reverts 27b62377b4. Discussion: https://postgr.es/m/[email protected] Discussion: https://postgr.es/m/[email protected] --- doc/src/sgml/ref/initdb.sgml | 42 +++++++------------ src/bin/initdb/initdb.c | 23 +--------- src/bin/initdb/t/001_initdb.pl | 5 +++ src/bin/pg_dump/t/002_pg_dump.pl | 2 +- src/bin/scripts/t/020_createdb.pl | 2 +- src/test/icu/t/010_database.pl | 2 +- .../regress/expected/collate.icu.utf8.out | 4 +- src/test/regress/sql/collate.icu.utf8.sql | 4 +- 8 files changed, 29 insertions(+), 55 deletions(-) diff --git a/doc/src/sgml/ref/initdb.sgml b/doc/src/sgml/ref/initdb.sgml index f850dc404d..22f1011781 100644 --- a/doc/src/sgml/ref/initdb.sgml +++ b/doc/src/sgml/ref/initdb.sgml @@ -93,24 +93,10 @@ PostgreSQL documentation </para> <para> - By default, <command>initdb</command> uses the ICU library to provide - locale services if the server was built with ICU support; otherwise it uses - the <literal>libc</literal> locale provider (see <xref - linkend="locale-providers"/>). To choose the specific ICU locale ID to - apply, use the option <option>--icu-locale</option>. Note that for - implementation reasons and to support legacy code, - <command>initdb</command> will still select and initialize libc locale - settings when the ICU locale provider is used. - </para> - - <para> - Alternatively, <command>initdb</command> can use the locale provider - <literal>libc</literal>. To select this option, specify - <literal>--locale-provider=libc</literal>, or build the server without ICU - support. The <literal>libc</literal> locale provider takes the locale - settings from the environment, and determines the encoding from the locale - settings. This is almost always sufficient, unless there are special - requirements. + By default, <command>initdb</command> uses the locale provider + <literal>libc</literal> (see <xref linkend="locale-providers"/>). The + <literal>libc</literal> locale provider takes the locale settings from the + environment, and determines the encoding from the locale settings. </para> <para> @@ -122,6 +108,16 @@ PostgreSQL documentation this should be used with care. </para> + <para> + Alternatively, <command>initdb</command> can use the ICU library to provide + locale services by specifying <literal>--locale-provider=icu</literal>. The + server must be built with ICU support. To choose the specific ICU locale ID + to apply, use the option <option>--icu-locale</option>. Note that for + implementation reasons and to support legacy code, + <command>initdb</command> will still select and initialize libc locale + settings when the ICU locale provider is used. + </para> + <para> When <command>initdb</command> runs, it will print out the locale settings it has chosen. If you have complex requirements or specified multiple @@ -251,11 +247,6 @@ PostgreSQL documentation Specifies the ICU locale when the ICU provider is used. Locale support is described in <xref linkend="locale"/>. </para> - <para> - If this option is not specified, the locale is inherited from the - environment in which <command>initdb</command> runs. The environment's - locale is matched to a similar ICU locale name, if possible. - </para> </listitem> </varlistentry> @@ -330,9 +321,8 @@ PostgreSQL documentation This option sets the locale provider for databases created in the new cluster. It can be overridden in the <command>CREATE DATABASE</command> command when new databases are subsequently - created. The default is <literal>icu</literal> if the server was - built with ICU support; otherwise the default is - <literal>libc</literal> (see <xref linkend="locale-providers"/>). + created. The default is <literal>libc</literal> (see <xref + linkend="locale-providers"/>). </para> </listitem> </varlistentry> diff --git a/src/bin/initdb/initdb.c b/src/bin/initdb/initdb.c index 71a3d26c37..fa3af0d75c 100644 --- a/src/bin/initdb/initdb.c +++ b/src/bin/initdb/initdb.c @@ -143,11 +143,7 @@ static char *lc_monetary = NULL; static char *lc_numeric = NULL; static char *lc_time = NULL; static char *lc_messages = NULL; -#ifdef USE_ICU -static char locale_provider = COLLPROVIDER_ICU; -#else static char locale_provider = COLLPROVIDER_LIBC; -#endif static char *icu_locale = NULL; static char *icu_rules = NULL; static const char *default_text_search_config = NULL; @@ -2357,19 +2353,6 @@ icu_validate_locale(const char *loc_str) #endif } -/* - * Determine the default ICU locale - */ -static char * -default_icu_locale(void) -{ -#ifdef USE_ICU - return pg_strdup(uloc_getDefault()); -#else - pg_fatal("ICU is not supported in this build"); -#endif -} - /* * set up the locale variables * @@ -2429,10 +2412,7 @@ setlocales(void) /* acquire default locale from the environment, if not specified */ if (icu_locale == NULL) - { - icu_locale = default_icu_locale(); - printf(_("Using default ICU locale \"%s\".\n"), icu_locale); - } + pg_fatal("ICU locale must be specified"); /* canonicalize to a language tag */ langtag = icu_language_tag(icu_locale); @@ -3273,7 +3253,6 @@ main(int argc, char *argv[]) break; case 8: locale = "C"; - locale_provider = COLLPROVIDER_LIBC; break; case 9: pwfilename = pg_strdup(optarg); diff --git a/src/bin/initdb/t/001_initdb.pl b/src/bin/initdb/t/001_initdb.pl index 8b4acb7148..2d7469d2fc 100644 --- a/src/bin/initdb/t/001_initdb.pl +++ b/src/bin/initdb/t/001_initdb.pl @@ -103,6 +103,11 @@ SKIP: if ($ENV{with_icu} eq 'yes') { + command_fails_like( + [ 'initdb', '--no-sync', '--locale-provider=icu', "$tempdir/data2" ], + qr/initdb: error: ICU locale must be specified/, + 'locale provider ICU requires --icu-locale'); + command_ok( [ 'initdb', '--no-sync', diff --git a/src/bin/pg_dump/t/002_pg_dump.pl b/src/bin/pg_dump/t/002_pg_dump.pl index 15852188c4..63bb4689d4 100644 --- a/src/bin/pg_dump/t/002_pg_dump.pl +++ b/src/bin/pg_dump/t/002_pg_dump.pl @@ -1965,7 +1965,7 @@ my %tests = ( create_sql => "CREATE DATABASE dump_test2 LOCALE = 'C' TEMPLATE = template0;", regexp => qr/^ - \QCREATE DATABASE dump_test2 \E.*\QLOCALE = 'C'\E + \QCREATE DATABASE dump_test2 \E.*\QLOCALE = 'C';\E /xm, like => { pg_dumpall_dbprivs => 1, }, }, diff --git a/src/bin/scripts/t/020_createdb.pl b/src/bin/scripts/t/020_createdb.pl index 57383561a0..40291924e5 100644 --- a/src/bin/scripts/t/020_createdb.pl +++ b/src/bin/scripts/t/020_createdb.pl @@ -13,7 +13,7 @@ program_version_ok('createdb'); program_options_handling_ok('createdb'); my $node = PostgreSQL::Test::Cluster->new('main'); -$node->init(extra => ['--locale-provider=libc']); +$node->init; $node->start; $node->issues_sql_like( diff --git a/src/test/icu/t/010_database.pl b/src/test/icu/t/010_database.pl index cbe5467f3c..3beee2ff96 100644 --- a/src/test/icu/t/010_database.pl +++ b/src/test/icu/t/010_database.pl @@ -12,7 +12,7 @@ if ($ENV{with_icu} ne 'yes') } my $node1 = PostgreSQL::Test::Cluster->new('node1'); -$node1->init(extra => ['--locale-provider=libc']); +$node1->init; $node1->start; $node1->safe_psql('postgres', diff --git a/src/test/regress/expected/collate.icu.utf8.out b/src/test/regress/expected/collate.icu.utf8.out index dc96e590f7..b7fbee447f 100644 --- a/src/test/regress/expected/collate.icu.utf8.out +++ b/src/test/regress/expected/collate.icu.utf8.out @@ -1023,7 +1023,7 @@ SET client_min_messages TO WARNING; do $$ BEGIN EXECUTE 'CREATE COLLATION test0 (provider = icu, locale = ' || - quote_literal((SELECT daticulocale FROM pg_database WHERE datname = current_database())) || ');'; + quote_literal((SELECT CASE WHEN datlocprovider='i' THEN daticulocale ELSE datcollate END FROM pg_database WHERE datname = current_database())) || ');'; END $$; CREATE COLLATION test0 FROM "C"; -- fail, duplicate name @@ -1031,7 +1031,7 @@ ERROR: collation "test0" already exists do $$ BEGIN EXECUTE 'CREATE COLLATION test1 (provider = icu, locale = ' || - quote_literal((SELECT daticulocale FROM pg_database WHERE datname = current_database())) || ');'; + quote_literal((SELECT CASE WHEN datlocprovider='i' THEN daticulocale ELSE datcollate END FROM pg_database WHERE datname = current_database())) || ');'; END $$; RESET client_min_messages; diff --git a/src/test/regress/sql/collate.icu.utf8.sql b/src/test/regress/sql/collate.icu.utf8.sql index a8001b4b8e..079d7ae39d 100644 --- a/src/test/regress/sql/collate.icu.utf8.sql +++ b/src/test/regress/sql/collate.icu.utf8.sql @@ -362,14 +362,14 @@ SET client_min_messages TO WARNING; do $$ BEGIN EXECUTE 'CREATE COLLATION test0 (provider = icu, locale = ' || - quote_literal((SELECT daticulocale FROM pg_database WHERE datname = current_database())) || ');'; + quote_literal((SELECT CASE WHEN datlocprovider='i' THEN daticulocale ELSE datcollate END FROM pg_database WHERE datname = current_database())) || ');'; END $$; CREATE COLLATION test0 FROM "C"; -- fail, duplicate name do $$ BEGIN EXECUTE 'CREATE COLLATION test1 (provider = icu, locale = ' || - quote_literal((SELECT daticulocale FROM pg_database WHERE datname = current_database())) || ');'; + quote_literal((SELECT CASE WHEN datlocprovider='i' THEN daticulocale ELSE datcollate END FROM pg_database WHERE datname = current_database())) || ');'; END $$; -- 2.34.1 [text/x-patch] v1-0002-ICU-do-not-convert-locale-C-to-en-US-u-va-posix.patch (6.0K, ../../[email protected]/3-v1-0002-ICU-do-not-convert-locale-C-to-en-US-u-va-posix.patch) download | inline diff: From e339123ae9c41a1161d516173e67c543d5542a60 Mon Sep 17 00:00:00 2001 From: Jeff Davis <[email protected]> Date: Thu, 15 Jun 2023 15:18:50 -0700 Subject: [PATCH v1 2/2] ICU: do not convert locale 'C' to 'en-US-u-va-posix'. Older versions of ICU canonicalize "C" to "en-US-u-va-posix"; but starting in ICU version 64, the "C" locale is considered obsolete. Postgres commit ea1db8ae70 introduced code to always canonicalize "C" to "en-US-u-va-posix" for consistency and convenience, but it was deemed too confusing. This commit removes that code, so that "C" is treated like other ICU locale names: canonicalization is attempted, and if it fails, the behavior is controlled by icu_validation_level. A similar change was previously committed as f7faa9976c, then reverted due to an ICU-version-dependent test failure. This commit un-reverts it, omitting the test because we now expect the behavior to depend on the version of ICU being used. Discussion: https://postgr.es/m/3a200aca-4672-4b37-fc91-5d198a323503%40eisentraut.org Discussion: https://postgr.es/m/[email protected] Discussion: https://postgr.es/m/[email protected] --- src/backend/utils/adt/pg_locale.c | 27 ++++--------------- src/bin/initdb/initdb.c | 25 ++++------------- .../regress/expected/collate.icu.utf8.out | 2 ++ src/test/regress/sql/collate.icu.utf8.sql | 2 ++ 4 files changed, 14 insertions(+), 42 deletions(-) diff --git a/src/backend/utils/adt/pg_locale.c b/src/backend/utils/adt/pg_locale.c index 31e3b16ae0..69a2fb3376 100644 --- a/src/backend/utils/adt/pg_locale.c +++ b/src/backend/utils/adt/pg_locale.c @@ -2783,26 +2783,10 @@ char * icu_language_tag(const char *loc_str, int elevel) { #ifdef USE_ICU - UErrorCode status; - char lang[ULOC_LANG_CAPACITY]; - char *langtag; - size_t buflen = 32; /* arbitrary starting buffer size */ - const bool strict = true; - - status = U_ZERO_ERROR; - uloc_getLanguage(loc_str, lang, ULOC_LANG_CAPACITY, &status); - if (U_FAILURE(status) || status == U_STRING_NOT_TERMINATED_WARNING) - { - if (elevel > 0) - ereport(elevel, - (errmsg("could not get language from locale \"%s\": %s", - loc_str, u_errorName(status)))); - return NULL; - } - - /* C/POSIX locales aren't handled by uloc_getLanguageTag() */ - if (strcmp(lang, "c") == 0 || strcmp(lang, "posix") == 0) - return pstrdup("en-US-u-va-posix"); + UErrorCode status; + char *langtag; + size_t buflen = 32; /* arbitrary starting buffer size */ + const bool strict = true; /* * A BCP47 language tag doesn't have a clearly-defined upper limit (cf. @@ -2884,8 +2868,7 @@ icu_validate_locale(const char *loc_str) /* check for special language name */ if (strcmp(lang, "") == 0 || - strcmp(lang, "root") == 0 || strcmp(lang, "und") == 0 || - strcmp(lang, "c") == 0 || strcmp(lang, "posix") == 0) + strcmp(lang, "root") == 0 || strcmp(lang, "und") == 0) found = true; /* search for matching language within ICU */ diff --git a/src/bin/initdb/initdb.c b/src/bin/initdb/initdb.c index fa3af0d75c..a5ce1f66d5 100644 --- a/src/bin/initdb/initdb.c +++ b/src/bin/initdb/initdb.c @@ -2243,24 +2243,10 @@ static char * icu_language_tag(const char *loc_str) { #ifdef USE_ICU - UErrorCode status; - char lang[ULOC_LANG_CAPACITY]; - char *langtag; - size_t buflen = 32; /* arbitrary starting buffer size */ - const bool strict = true; - - status = U_ZERO_ERROR; - uloc_getLanguage(loc_str, lang, ULOC_LANG_CAPACITY, &status); - if (U_FAILURE(status) || status == U_STRING_NOT_TERMINATED_WARNING) - { - pg_fatal("could not get language from locale \"%s\": %s", - loc_str, u_errorName(status)); - return NULL; - } - - /* C/POSIX locales aren't handled by uloc_getLanguageTag() */ - if (strcmp(lang, "c") == 0 || strcmp(lang, "posix") == 0) - return pstrdup("en-US-u-va-posix"); + UErrorCode status; + char *langtag; + size_t buflen = 32; /* arbitrary starting buffer size */ + const bool strict = true; /* * A BCP47 language tag doesn't have a clearly-defined upper limit (cf. @@ -2326,8 +2312,7 @@ icu_validate_locale(const char *loc_str) /* check for special language name */ if (strcmp(lang, "") == 0 || - strcmp(lang, "root") == 0 || strcmp(lang, "und") == 0 || - strcmp(lang, "c") == 0 || strcmp(lang, "posix") == 0) + strcmp(lang, "root") == 0 || strcmp(lang, "und") == 0) found = true; /* search for matching language within ICU */ diff --git a/src/test/regress/expected/collate.icu.utf8.out b/src/test/regress/expected/collate.icu.utf8.out index b7fbee447f..78a9cb38fa 100644 --- a/src/test/regress/expected/collate.icu.utf8.out +++ b/src/test/regress/expected/collate.icu.utf8.out @@ -1020,6 +1020,7 @@ CREATE ROLE regress_test_role; CREATE SCHEMA test_schema; -- We need to do this this way to cope with varying names for encodings: SET client_min_messages TO WARNING; +SET icu_validation_level = disabled; do $$ BEGIN EXECUTE 'CREATE COLLATION test0 (provider = icu, locale = ' || @@ -1034,6 +1035,7 @@ BEGIN quote_literal((SELECT CASE WHEN datlocprovider='i' THEN daticulocale ELSE datcollate END FROM pg_database WHERE datname = current_database())) || ');'; END $$; +RESET icu_validation_level; RESET client_min_messages; CREATE COLLATION test3 (provider = icu, lc_collate = 'en_US.utf8'); -- fail, needs "locale" ERROR: parameter "locale" must be specified diff --git a/src/test/regress/sql/collate.icu.utf8.sql b/src/test/regress/sql/collate.icu.utf8.sql index 079d7ae39d..3db9e25913 100644 --- a/src/test/regress/sql/collate.icu.utf8.sql +++ b/src/test/regress/sql/collate.icu.utf8.sql @@ -358,6 +358,7 @@ CREATE SCHEMA test_schema; -- We need to do this this way to cope with varying names for encodings: SET client_min_messages TO WARNING; +SET icu_validation_level = disabled; do $$ BEGIN @@ -373,6 +374,7 @@ BEGIN END $$; +RESET icu_validation_level; RESET client_min_messages; CREATE COLLATION test3 (provider = icu, lc_collate = 'en_US.utf8'); -- fail, needs "locale" -- 2.34.1 ^ permalink raw reply [nested|flat] 3+ messages in thread
end of thread, other threads:[~2023-06-20 20:46 UTC | newest] Thread overview: 3+ messages (download: mbox mbox.gz follow: Atom feed) -- links below jump to the message on this page -- 2020-11-11 14:21 [PATCH v5 2/2] New command ALTER TABLE ALL IN TABLESPACE SET LOGGED/UNLOGGED Kyotaro Horiguchi <[email protected]> 2023-06-20 16:16 Re: collation-related loose ends before beta2 Tom Lane <[email protected]> 2023-06-20 20:46 ` Re: collation-related loose ends before beta2 Jeff Davis <[email protected]>
This inbox is served by agora; see mirroring instructions for how to clone and mirror all data and code used for this inbox