diff options
Diffstat (limited to 'src/bin/initdb/initdb.c')
-rw-r--r-- | src/bin/initdb/initdb.c | 97 |
1 files changed, 86 insertions, 11 deletions
diff --git a/src/bin/initdb/initdb.c b/src/bin/initdb/initdb.c index 97f15971e2b..cbcd55288f2 100644 --- a/src/bin/initdb/initdb.c +++ b/src/bin/initdb/initdb.c @@ -55,6 +55,10 @@ #include <signal.h> #include <time.h> +#ifdef USE_ICU +#include <unicode/ucol.h> +#endif + #ifdef HAVE_SHM_OPEN #include "sys/mman.h" #endif @@ -132,6 +136,8 @@ static char *lc_monetary = NULL; static char *lc_numeric = NULL; static char *lc_time = NULL; static char *lc_messages = NULL; +static char locale_provider = COLLPROVIDER_LIBC; +static char *icu_locale = NULL; static const char *default_text_search_config = NULL; static char *username = NULL; static bool pwprompt = false; @@ -1405,6 +1411,12 @@ bootstrap_template1(void) bki_lines = replace_token(bki_lines, "LC_CTYPE", escape_quotes_bki(lc_ctype)); + bki_lines = replace_token(bki_lines, "ICU_LOCALE", + locale_provider == COLLPROVIDER_ICU ? escape_quotes_bki(icu_locale) : "_null_"); + + sprintf(buf, "%c", locale_provider); + bki_lines = replace_token(bki_lines, "LOCALE_PROVIDER", buf); + /* Also ensure backend isn't confused by this environment var: */ unsetenv("PGCLIENTENCODING"); @@ -2165,7 +2177,6 @@ setlocales(void) * canonicalize locale names, and obtain any missing values from our * current environment */ - check_locale_name(LC_CTYPE, lc_ctype, &canonname); lc_ctype = canonname; check_locale_name(LC_COLLATE, lc_collate, &canonname); @@ -2184,6 +2195,37 @@ setlocales(void) check_locale_name(LC_CTYPE, lc_messages, &canonname); lc_messages = canonname; #endif + + if (locale_provider == COLLPROVIDER_ICU) + { + if (!icu_locale) + { + pg_log_error("ICU locale must be specified"); + exit(1); + } + + /* + * Check ICU locale ID + */ +#ifdef USE_ICU + { + UErrorCode status; + + status = U_ZERO_ERROR; + ucol_open(icu_locale, &status); + if (U_FAILURE(status)) + { + pg_log_error("could not open collator for locale \"%s\": %s", + icu_locale, u_errorName(status)); + exit(1); + } + } +#else + pg_log_error("ICU is not supported in this build"); + fprintf(stderr, _("You need to rebuild PostgreSQL using %s.\n"), "--with-icu"); + exit(1); +#endif + } } /* @@ -2202,6 +2244,7 @@ usage(const char *progname) printf(_(" [-D, --pgdata=]DATADIR location for this database cluster\n")); printf(_(" -E, --encoding=ENCODING set default encoding for new databases\n")); printf(_(" -g, --allow-group-access allow group read/execute on data directory\n")); + printf(_(" --icu-locale=LOCALE set ICU locale ID for new databases\n")); printf(_(" -k, --data-checksums use data page checksums\n")); printf(_(" --locale=LOCALE set default locale for new databases\n")); printf(_(" --lc-collate=, --lc-ctype=, --lc-messages=LOCALE\n" @@ -2209,6 +2252,8 @@ usage(const char *progname) " set default locale in the respective category for\n" " new databases (default taken from environment)\n")); printf(_(" --no-locale equivalent to --locale=C\n")); + printf(_(" --locale-provider={libc|icu}\n" + " set default locale provider for new databases\n")); printf(_(" --pwfile=FILE read password for the new superuser from file\n")); printf(_(" -T, --text-search-config=CFG\n" " default text search configuration\n")); @@ -2372,21 +2417,26 @@ setup_locale_encoding(void) { setlocales(); - if (strcmp(lc_ctype, lc_collate) == 0 && + if (locale_provider == COLLPROVIDER_LIBC && + strcmp(lc_ctype, lc_collate) == 0 && strcmp(lc_ctype, lc_time) == 0 && strcmp(lc_ctype, lc_numeric) == 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)) printf(_("The database cluster will be initialized with locale \"%s\".\n"), lc_ctype); else { - printf(_("The database cluster will be initialized with locales\n" - " COLLATE: %s\n" - " CTYPE: %s\n" - " MESSAGES: %s\n" - " MONETARY: %s\n" - " NUMERIC: %s\n" - " TIME: %s\n"), + printf(_("The database cluster will be initialized with this locale configuration:\n")); + printf(_(" provider: %s\n"), collprovider_name(locale_provider)); + if (icu_locale) + printf(_(" ICU locale: %s\n"), icu_locale); + printf(_(" LC_COLLATE: %s\n" + " LC_CTYPE: %s\n" + " LC_MESSAGES: %s\n" + " LC_MONETARY: %s\n" + " LC_NUMERIC: %s\n" + " LC_TIME: %s\n"), lc_collate, lc_ctype, lc_messages, @@ -2395,7 +2445,9 @@ setup_locale_encoding(void) lc_time); } - if (!encoding) + if (!encoding && locale_provider == COLLPROVIDER_ICU) + encodingid = PG_UTF8; + else if (!encoding) { int ctype_enc; @@ -2899,6 +2951,8 @@ main(int argc, char *argv[]) {"data-checksums", no_argument, NULL, 'k'}, {"allow-group-access", no_argument, NULL, 'g'}, {"discard-caches", no_argument, NULL, 14}, + {"locale-provider", required_argument, NULL, 15}, + {"icu-locale", required_argument, NULL, 16}, {NULL, 0, NULL, 0} }; @@ -3045,6 +3099,20 @@ main(int argc, char *argv[]) extra_options, "-c debug_discard_caches=1"); break; + case 15: + if (strcmp(optarg, "icu") == 0) + locale_provider = COLLPROVIDER_ICU; + else if (strcmp(optarg, "libc") == 0) + locale_provider = COLLPROVIDER_LIBC; + else + { + pg_log_error("unrecognized locale provider: %s", optarg); + exit(1); + } + break; + case 16: + icu_locale = pg_strdup(optarg); + break; default: /* getopt_long already emitted a complaint */ fprintf(stderr, _("Try \"%s --help\" for more information.\n"), @@ -3073,6 +3141,13 @@ main(int argc, char *argv[]) exit(1); } + if (icu_locale && locale_provider != COLLPROVIDER_ICU) + { + pg_log_error("%s cannot be specified unless locale provider \"%s\" is chosen", + "--icu-locale", "icu"); + exit(1); + } + atexit(cleanup_directories_atexit); /* If we only need to fsync, just do it and exit */ |