]> granicus.if.org Git - postgresql/commitdiff
In pg_upgrade, try to convert the locale names to canonical form before
authorBruce Momjian <bruce@momjian.us>
Tue, 2 Oct 2012 15:42:34 +0000 (11:42 -0400)
committerBruce Momjian <bruce@momjian.us>
Tue, 2 Oct 2012 15:42:34 +0000 (11:42 -0400)
comparison;  also report the old/new values if they don't match.

Backpatch to 9.2.

contrib/pg_upgrade/check.c

index bed10f8fb45667d6cfdad1651be3d85ecd5607e9..e4fec34195e54b782fbee72897ce6fc325d6e06a 100644 (file)
@@ -21,6 +21,7 @@ static void check_for_prepared_transactions(ClusterInfo *cluster);
 static void check_for_isn_and_int8_passing_mismatch(ClusterInfo *cluster);
 static void check_for_reg_data_type_usage(ClusterInfo *cluster);
 static void get_bin_version(ClusterInfo *cluster);
+static char *get_canonical_locale_name(int category, const char *locale);
 
 
 /*
@@ -359,8 +360,23 @@ set_locale_and_encoding(ClusterInfo *cluster)
                i_datcollate = PQfnumber(res, "datcollate");
                i_datctype = PQfnumber(res, "datctype");
 
-               ctrl->lc_collate = pg_strdup(PQgetvalue(res, 0, i_datcollate));
-               ctrl->lc_ctype = pg_strdup(PQgetvalue(res, 0, i_datctype));
+               if (GET_MAJOR_VERSION(cluster->major_version) < 902)
+               {
+                       /*
+                        *      Pre-9.2 did not canonicalize the supplied locale names
+                        *      to match what the system returns, while 9.2+ does, so
+                        *      convert pre-9.2 to match.
+                        */
+                       ctrl->lc_collate = get_canonical_locale_name(LC_COLLATE,
+                                                          pg_strdup(PQgetvalue(res, 0, i_datcollate)));
+                       ctrl->lc_ctype = get_canonical_locale_name(LC_CTYPE,
+                                                          pg_strdup(PQgetvalue(res, 0, i_datctype)));
+               }
+               else
+               {
+                       ctrl->lc_collate = pg_strdup(PQgetvalue(res, 0, i_datcollate));
+                       ctrl->lc_ctype = pg_strdup(PQgetvalue(res, 0, i_datctype));
+               }
 
                PQclear(res);
        }
@@ -390,16 +406,23 @@ static void
 check_locale_and_encoding(ControlData *oldctrl,
                                                  ControlData *newctrl)
 {
-       /* These are often defined with inconsistent case, so use pg_strcasecmp(). */
+       /*
+        *      These are often defined with inconsistent case, so use pg_strcasecmp().
+        *      They also often use inconsistent hyphenation, which we cannot fix, e.g.
+        *      UTF-8 vs. UTF8, so at least we display the mismatching values.
+        */
        if (pg_strcasecmp(oldctrl->lc_collate, newctrl->lc_collate) != 0)
                pg_log(PG_FATAL,
-                          "old and new cluster lc_collate values do not match\n");
+                          "lc_collate cluster values do not match:  old \"%s\", new \"%s\"\n",
+                          oldctrl->lc_collate, newctrl->lc_collate);
        if (pg_strcasecmp(oldctrl->lc_ctype, newctrl->lc_ctype) != 0)
                pg_log(PG_FATAL,
-                          "old and new cluster lc_ctype values do not match\n");
+                          "lc_ctype cluster values do not match:  old \"%s\", new \"%s\"\n",
+                          oldctrl->lc_ctype, newctrl->lc_ctype);
        if (pg_strcasecmp(oldctrl->encoding, newctrl->encoding) != 0)
                pg_log(PG_FATAL,
-                          "old and new cluster encoding values do not match\n");
+                          "encoding cluster values do not match:  old \"%s\", new \"%s\"\n",
+                          oldctrl->encoding, newctrl->encoding);
 }
 
 
@@ -931,3 +954,40 @@ get_bin_version(ClusterInfo *cluster)
 
        cluster->bin_version = (pre_dot * 100 + post_dot) * 100;
 }
+
+
+/*
+ * get_canonical_locale_name
+ *
+ * Send the locale name to the system, and hope we get back a canonical
+ * version.  This should match the backend's check_locale() function.
+ */
+static char *
+get_canonical_locale_name(int category, const char *locale)
+{
+       char       *save;
+       char       *res;
+
+       save = setlocale(category, NULL);
+       if (!save)
+        pg_log(PG_FATAL, "failed to get the current locale\n");
+
+       /* 'save' may be pointing at a modifiable scratch variable, so copy it. */
+       save = pg_strdup(save);
+
+       /* set the locale with setlocale, to see if it accepts it. */
+       res = setlocale(category, locale);
+
+       if (!res)
+        pg_log(PG_FATAL, "failed to get system local name for \"%s\"\n", res);
+
+       res = pg_strdup(res);
+
+       /* restore old value. */
+       if (!setlocale(category, save))
+        pg_log(PG_FATAL, "failed to restore old locale \"%s\"\n", save);
+
+       free(save);
+
+       return res;
+}