|
58 | 58 | #include "catalog/pg_collation.h"
|
59 | 59 | #include "catalog/pg_control.h"
|
60 | 60 | #include "mb/pg_wchar.h"
|
| 61 | +#include "miscadmin.h" |
61 | 62 | #include "utils/builtins.h"
|
62 | 63 | #include "utils/formatting.h"
|
63 | 64 | #include "utils/guc_hooks.h"
|
@@ -95,6 +96,8 @@ char *locale_monetary;
|
95 | 96 | char *locale_numeric;
|
96 | 97 | char *locale_time;
|
97 | 98 |
|
| 99 | +int icu_validation_level = ERROR; |
| 100 | + |
98 | 101 | /*
|
99 | 102 | * lc_time localization cache.
|
100 | 103 | *
|
@@ -2821,24 +2824,77 @@ icu_set_collation_attributes(UCollator *collator, const char *loc,
|
2821 | 2824 | pfree(lower_str);
|
2822 | 2825 | }
|
2823 | 2826 |
|
2824 |
| -#endif /* USE_ICU */ |
| 2827 | +#endif |
2825 | 2828 |
|
2826 | 2829 | /*
|
2827 |
| - * Check if the given locale ID is valid, and ereport(ERROR) if it isn't. |
| 2830 | + * Perform best-effort check that the locale is a valid one. |
2828 | 2831 | */
|
2829 | 2832 | void
|
2830 |
| -check_icu_locale(const char *icu_locale) |
| 2833 | +icu_validate_locale(const char *loc_str) |
2831 | 2834 | {
|
2832 | 2835 | #ifdef USE_ICU
|
2833 |
| - UCollator *collator; |
| 2836 | + UCollator *collator; |
| 2837 | + UErrorCode status; |
| 2838 | + char lang[ULOC_LANG_CAPACITY]; |
| 2839 | + bool found = false; |
| 2840 | + int elevel = icu_validation_level; |
| 2841 | + |
| 2842 | + /* no validation */ |
| 2843 | + if (elevel < 0) |
| 2844 | + return; |
| 2845 | + |
| 2846 | + /* downgrade to WARNING during pg_upgrade */ |
| 2847 | + if (IsBinaryUpgrade && elevel > WARNING) |
| 2848 | + elevel = WARNING; |
| 2849 | + |
| 2850 | + /* validate that we can extract the language */ |
| 2851 | + status = U_ZERO_ERROR; |
| 2852 | + uloc_getLanguage(loc_str, lang, ULOC_LANG_CAPACITY, &status); |
| 2853 | + if (U_FAILURE(status)) |
| 2854 | + { |
| 2855 | + ereport(elevel, |
| 2856 | + (errmsg("could not get language from ICU locale \"%s\": %s", |
| 2857 | + loc_str, u_errorName(status)), |
| 2858 | + errhint("To disable ICU locale validation, set parameter icu_validation_level to DISABLED."))); |
| 2859 | + return; |
| 2860 | + } |
| 2861 | + |
| 2862 | + /* check for special language name */ |
| 2863 | + if (strcmp(lang, "") == 0 || |
| 2864 | + strcmp(lang, "root") == 0 || strcmp(lang, "und") == 0 || |
| 2865 | + strcmp(lang, "c") == 0 || strcmp(lang, "posix") == 0) |
| 2866 | + found = true; |
2834 | 2867 |
|
2835 |
| - collator = pg_ucol_open(icu_locale); |
| 2868 | + /* search for matching language within ICU */ |
| 2869 | + for (int32_t i = 0; !found && i < uloc_countAvailable(); i++) |
| 2870 | + { |
| 2871 | + const char *otherloc = uloc_getAvailable(i); |
| 2872 | + char otherlang[ULOC_LANG_CAPACITY]; |
| 2873 | + |
| 2874 | + status = U_ZERO_ERROR; |
| 2875 | + uloc_getLanguage(otherloc, otherlang, ULOC_LANG_CAPACITY, &status); |
| 2876 | + if (U_FAILURE(status)) |
| 2877 | + continue; |
| 2878 | + |
| 2879 | + if (strcmp(lang, otherlang) == 0) |
| 2880 | + found = true; |
| 2881 | + } |
| 2882 | + |
| 2883 | + if (!found) |
| 2884 | + ereport(elevel, |
| 2885 | + (errmsg("ICU locale \"%s\" has unknown language \"%s\"", |
| 2886 | + loc_str, lang), |
| 2887 | + errhint("To disable ICU locale validation, set parameter icu_validation_level to DISABLED."))); |
| 2888 | + |
| 2889 | + /* check that it can be opened */ |
| 2890 | + collator = pg_ucol_open(loc_str); |
2836 | 2891 | ucol_close(collator);
|
2837 |
| -#else |
| 2892 | +#else /* not USE_ICU */ |
| 2893 | + /* could get here if a collation was created by a build with ICU */ |
2838 | 2894 | ereport(ERROR,
|
2839 | 2895 | (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
2840 | 2896 | errmsg("ICU is not supported in this build")));
|
2841 |
| -#endif |
| 2897 | +#endif /* not USE_ICU */ |
2842 | 2898 | }
|
2843 | 2899 |
|
2844 | 2900 | /*
|
|
0 commit comments