From 7ba4151235a32ebfd11bd80a5a01d9ef347d2c11 Mon Sep 17 00:00:00 2001 From: Peter Eisentraut Date: Sun, 23 Jun 2019 20:09:00 +0200 Subject: [PATCH v2] Add CREATE DATABASE LOCALE option This sets both LC_COLLATE and LC_CTYPE with one option. Similar behavior is already supported in initdb, CREATE COLLATION, and createdb. Discussion: https://www.postgresql.org/message-id/flat/d9d5043a-dc70-da8a-0166-1e218e6e34d4%402ndquadrant.com --- doc/src/sgml/ref/create_database.sgml | 25 +++++++++++++++++++++++-- src/backend/commands/dbcommands.c | 20 ++++++++++++++++++++ src/bin/pg_dump/pg_dump.c | 23 +++++++++++++++++------ src/bin/pg_dump/t/002_pg_dump.pl | 9 +++++++++ 4 files changed, 69 insertions(+), 8 deletions(-) diff --git a/doc/src/sgml/ref/create_database.sgml b/doc/src/sgml/ref/create_database.sgml index b2c9e241c2..4014f6703b 100644 --- a/doc/src/sgml/ref/create_database.sgml +++ b/doc/src/sgml/ref/create_database.sgml @@ -25,6 +25,7 @@ [ [ WITH ] [ OWNER [=] user_name ] [ TEMPLATE [=] template ] [ ENCODING [=] encoding ] + [ LOCALE [=] locale ] [ LC_COLLATE [=] lc_collate ] [ LC_CTYPE [=] lc_ctype ] [ TABLESPACE [=] tablespace_name ] @@ -111,6 +112,26 @@ Parameters + + locale + + + This is a shortcut for setting LC_COLLATE + and LC_CTYPE at once. If you specify this, + you cannot specify either of those parameters. + + + + The other locale settings , , , and + are not fixed per database and are not + set by this command. If you want to make them the default for a + specific database, you can use ALTER DATABASE + ... SET. + + + + lc_collate @@ -287,7 +308,7 @@ Examples To create a database music with a different locale: CREATE DATABASE music - LC_COLLATE 'sv_SE.utf8' LC_CTYPE 'sv_SE.utf8' + LOCALE 'sv_SE.utf8' TEMPLATE template0; In this example, the TEMPLATE template0 clause is required if @@ -300,7 +321,7 @@ Examples different character set encoding: CREATE DATABASE music2 - LC_COLLATE 'sv_SE.iso885915' LC_CTYPE 'sv_SE.iso885915' + LOCALE 'sv_SE.iso885915' ENCODING LATIN9 TEMPLATE template0; diff --git a/src/backend/commands/dbcommands.c b/src/backend/commands/dbcommands.c index 15207bf75a..ac275f7e64 100644 --- a/src/backend/commands/dbcommands.c +++ b/src/backend/commands/dbcommands.c @@ -124,6 +124,7 @@ createdb(ParseState *pstate, const CreatedbStmt *stmt) DefElem *downer = NULL; DefElem *dtemplate = NULL; DefElem *dencoding = NULL; + DefElem *dlocale = NULL; DefElem *dcollate = NULL; DefElem *dctype = NULL; DefElem *distemplate = NULL; @@ -184,6 +185,15 @@ createdb(ParseState *pstate, const CreatedbStmt *stmt) parser_errposition(pstate, defel->location))); dencoding = defel; } + else if (strcmp(defel->defname, "locale") == 0) + { + if (dlocale) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("conflicting or redundant options"), + parser_errposition(pstate, defel->location))); + dlocale = defel; + } else if (strcmp(defel->defname, "lc_collate") == 0) { if (dcollate) @@ -244,6 +254,11 @@ createdb(ParseState *pstate, const CreatedbStmt *stmt) parser_errposition(pstate, defel->location))); } + if (dlocale && (dcollate || dctype)) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("conflicting or redundant options"))); + if (downer && downer->arg) dbowner = defGetString(downer); if (dtemplate && dtemplate->arg) @@ -276,6 +291,11 @@ createdb(ParseState *pstate, const CreatedbStmt *stmt) parser_errposition(pstate, dencoding->location))); } } + if (dlocale && dlocale->arg) + { + dbcollate = defGetString(dlocale); + dbctype = defGetString(dlocale); + } if (dcollate && dcollate->arg) dbcollate = defGetString(dcollate); if (dctype && dctype->arg) diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c index 8909a45d61..5cad9ed796 100644 --- a/src/bin/pg_dump/pg_dump.c +++ b/src/bin/pg_dump/pg_dump.c @@ -2812,15 +2812,26 @@ dumpDatabase(Archive *fout) appendPQExpBufferStr(creaQry, " ENCODING = "); appendStringLiteralAH(creaQry, encoding, fout); } - if (strlen(collate) > 0) + if (strcmp(collate, ctype) == 0) { - appendPQExpBufferStr(creaQry, " LC_COLLATE = "); - appendStringLiteralAH(creaQry, collate, fout); + if (strlen(collate) > 0) + { + appendPQExpBufferStr(creaQry, " LOCALE = "); + appendStringLiteralAH(creaQry, collate, fout); + } } - if (strlen(ctype) > 0) + else { - appendPQExpBufferStr(creaQry, " LC_CTYPE = "); - appendStringLiteralAH(creaQry, ctype, fout); + if (strlen(collate) > 0) + { + appendPQExpBufferStr(creaQry, " LC_COLLATE = "); + appendStringLiteralAH(creaQry, collate, fout); + } + if (strlen(ctype) > 0) + { + appendPQExpBufferStr(creaQry, " LC_CTYPE = "); + appendStringLiteralAH(creaQry, ctype, fout); + } } /* diff --git a/src/bin/pg_dump/t/002_pg_dump.pl b/src/bin/pg_dump/t/002_pg_dump.pl index c56bf00e4b..7cbccee103 100644 --- a/src/bin/pg_dump/t/002_pg_dump.pl +++ b/src/bin/pg_dump/t/002_pg_dump.pl @@ -1407,6 +1407,15 @@ like => { pg_dumpall_dbprivs => 1, }, }, + "CREATE DATABASE dump_test2 LOCALE = 'C'" => { + create_order => 47, + create_sql => "CREATE DATABASE dump_test2 LOCALE = 'C' TEMPLATE = template0;", + regexp => qr/^ + \QCREATE DATABASE dump_test2 \E.*\QLOCALE = 'C';\E + /xm, + like => { pg_dumpall_dbprivs => 1, }, + }, + 'CREATE EXTENSION ... plpgsql' => { regexp => qr/^ \QCREATE EXTENSION IF NOT EXISTS plpgsql WITH SCHEMA pg_catalog;\E -- 2.22.0