|
9 | 9 |
|
10 | 10 | #include"postgres.h" |
11 | 11 |
|
| 12 | +#include"mb/pg_wchar.h" |
12 | 13 | #include"pg_upgrade.h" |
13 | 14 |
|
14 | 15 |
|
15 | 16 | staticvoidset_locale_and_encoding(ClusterInfo*cluster); |
16 | 17 | staticvoidcheck_new_cluster_is_empty(void); |
17 | 18 | staticvoidcheck_locale_and_encoding(ControlData*oldctrl, |
18 | 19 | ControlData*newctrl); |
| 20 | +staticboolequivalent_locale(intcategory,constchar*loca,constchar*locb); |
| 21 | +staticboolequivalent_encoding(constchar*chara,constchar*charb); |
19 | 22 | staticvoidcheck_is_super_user(ClusterInfo*cluster); |
20 | 23 | staticvoidcheck_for_prepared_transactions(ClusterInfo*cluster); |
21 | 24 | staticvoidcheck_for_isn_and_int8_passing_mismatch(ClusterInfo*cluster); |
@@ -360,23 +363,8 @@ set_locale_and_encoding(ClusterInfo *cluster) |
360 | 363 | i_datcollate=PQfnumber(res,"datcollate"); |
361 | 364 | i_datctype=PQfnumber(res,"datctype"); |
362 | 365 |
|
363 | | -if (GET_MAJOR_VERSION(cluster->major_version)<902) |
364 | | -{ |
365 | | -/* |
366 | | - *Pre-9.2 did not canonicalize the supplied locale names |
367 | | - *to match what the system returns, while 9.2+ does, so |
368 | | - *convert pre-9.2 to match. |
369 | | - */ |
370 | | -ctrl->lc_collate=get_canonical_locale_name(LC_COLLATE, |
371 | | -pg_strdup(PQgetvalue(res,0,i_datcollate))); |
372 | | -ctrl->lc_ctype=get_canonical_locale_name(LC_CTYPE, |
373 | | -pg_strdup(PQgetvalue(res,0,i_datctype))); |
374 | | - } |
375 | | -else |
376 | | -{ |
377 | | -ctrl->lc_collate=pg_strdup(PQgetvalue(res,0,i_datcollate)); |
378 | | -ctrl->lc_ctype=pg_strdup(PQgetvalue(res,0,i_datctype)); |
379 | | -} |
| 366 | +ctrl->lc_collate=pg_strdup(PQgetvalue(res,0,i_datcollate)); |
| 367 | +ctrl->lc_ctype=pg_strdup(PQgetvalue(res,0,i_datctype)); |
380 | 368 |
|
381 | 369 | PQclear(res); |
382 | 370 | } |
@@ -406,25 +394,89 @@ static void |
406 | 394 | check_locale_and_encoding(ControlData*oldctrl, |
407 | 395 | ControlData*newctrl) |
408 | 396 | { |
409 | | -/* |
410 | | - *These are often defined with inconsistent case, so use pg_strcasecmp(). |
411 | | - *They also often use inconsistent hyphenation, which we cannot fix, e.g. |
412 | | - *UTF-8 vs. UTF8, so at least we display the mismatching values. |
413 | | - */ |
414 | | -if (pg_strcasecmp(oldctrl->lc_collate,newctrl->lc_collate)!=0) |
| 397 | +if (!equivalent_locale(LC_COLLATE,oldctrl->lc_collate,newctrl->lc_collate)) |
415 | 398 | pg_log(PG_FATAL, |
416 | 399 | "lc_collate cluster values do not match: old \"%s\", new \"%s\"\n", |
417 | 400 | oldctrl->lc_collate,newctrl->lc_collate); |
418 | | -if (pg_strcasecmp(oldctrl->lc_ctype,newctrl->lc_ctype)!=0) |
| 401 | +if (!equivalent_locale(LC_CTYPE,oldctrl->lc_ctype,newctrl->lc_ctype)) |
419 | 402 | pg_log(PG_FATAL, |
420 | 403 | "lc_ctype cluster values do not match: old \"%s\", new \"%s\"\n", |
421 | 404 | oldctrl->lc_ctype,newctrl->lc_ctype); |
422 | | -if (pg_strcasecmp(oldctrl->encoding,newctrl->encoding)!=0) |
| 405 | +if (!equivalent_encoding(oldctrl->encoding,newctrl->encoding)) |
423 | 406 | pg_log(PG_FATAL, |
424 | 407 | "encoding cluster values do not match: old \"%s\", new \"%s\"\n", |
425 | 408 | oldctrl->encoding,newctrl->encoding); |
426 | 409 | } |
427 | 410 |
|
| 411 | +/* |
| 412 | + * equivalent_locale() |
| 413 | + * |
| 414 | + * Best effort locale-name comparison. Return false if we are not 100% sure |
| 415 | + * the locales are equivalent. |
| 416 | + * |
| 417 | + * Note: The encoding parts of the names are ignored. This function is |
| 418 | + * currently used to compare locale names stored in pg_database, and |
| 419 | + * pg_database contains a separate encoding field. That's compared directly |
| 420 | + * in check_locale_and_encoding(). |
| 421 | + */ |
| 422 | +staticbool |
| 423 | +equivalent_locale(intcategory,constchar*loca,constchar*locb) |
| 424 | +{ |
| 425 | +constchar*chara; |
| 426 | +constchar*charb; |
| 427 | +char*canona; |
| 428 | +char*canonb; |
| 429 | +intlena; |
| 430 | +intlenb; |
| 431 | + |
| 432 | +/* |
| 433 | + * If the names are equal, the locales are equivalent. Checking this |
| 434 | + * first avoids calling setlocale() in the common case that the names |
| 435 | + * are equal. That's a good thing, if setlocale() is buggy, for example. |
| 436 | + */ |
| 437 | +if (pg_strcasecmp(loca,locb)==0) |
| 438 | +return true; |
| 439 | + |
| 440 | +/* |
| 441 | + * Not identical. Canonicalize both names, remove the encoding parts, |
| 442 | + * and try again. |
| 443 | + */ |
| 444 | +canona=get_canonical_locale_name(category,loca); |
| 445 | +chara=strrchr(canona,'.'); |
| 446 | +lena=chara ? (chara-canona) :strlen(canona); |
| 447 | + |
| 448 | +canonb=get_canonical_locale_name(category,locb); |
| 449 | +charb=strrchr(canonb,'.'); |
| 450 | +lenb=charb ? (charb-canonb) :strlen(canonb); |
| 451 | + |
| 452 | +if (lena==lenb&&pg_strncasecmp(canona,canonb,lena)==0) |
| 453 | +return true; |
| 454 | + |
| 455 | +return false; |
| 456 | +} |
| 457 | + |
| 458 | +/* |
| 459 | + * equivalent_encoding() |
| 460 | + * |
| 461 | + * Best effort encoding-name comparison. Return true only if the encodings |
| 462 | + * are valid server-side encodings and known equivalent. |
| 463 | + * |
| 464 | + * Because the lookup in pg_valid_server_encoding() does case folding and |
| 465 | + * ignores non-alphanumeric characters, this will recognize many popular |
| 466 | + * variant spellings as equivalent, eg "utf8" and "UTF-8" will match. |
| 467 | + */ |
| 468 | +staticbool |
| 469 | +equivalent_encoding(constchar*chara,constchar*charb) |
| 470 | +{ |
| 471 | +intenca=pg_valid_server_encoding(chara); |
| 472 | +intencb=pg_valid_server_encoding(charb); |
| 473 | + |
| 474 | +if (enca<0||encb<0) |
| 475 | +return false; |
| 476 | + |
| 477 | +return (enca==encb); |
| 478 | +} |
| 479 | + |
428 | 480 |
|
429 | 481 | staticvoid |
430 | 482 | check_new_cluster_is_empty(void) |
|