@@ -17,7 +17,7 @@ static void set_locale_and_encoding(ClusterInfo *cluster);
17
17
static void check_new_cluster_is_empty (void );
18
18
static void check_locale_and_encoding (ControlData * oldctrl ,
19
19
ControlData * newctrl );
20
- static bool equivalent_locale (const char * loca , const char * locb );
20
+ static bool equivalent_locale (int category , const char * loca , const char * locb );
21
21
static bool equivalent_encoding (const char * chara , const char * charb );
22
22
static void check_is_super_user (ClusterInfo * cluster );
23
23
static void check_for_prepared_transactions (ClusterInfo * cluster );
@@ -370,23 +370,8 @@ set_locale_and_encoding(ClusterInfo *cluster)
370
370
i_datcollate = PQfnumber (res , "datcollate" );
371
371
i_datctype = PQfnumber (res , "datctype" );
372
372
373
- if (GET_MAJOR_VERSION (cluster -> major_version ) < 902 )
374
- {
375
- /*
376
- * Pre-9.2 did not canonicalize the supplied locale names to match
377
- * what the system returns, while 9.2+ does, so convert pre-9.2 to
378
- * match.
379
- */
380
- ctrl -> lc_collate = get_canonical_locale_name (LC_COLLATE ,
381
- pg_strdup (PQgetvalue (res , 0 , i_datcollate )));
382
- ctrl -> lc_ctype = get_canonical_locale_name (LC_CTYPE ,
383
- pg_strdup (PQgetvalue (res , 0 , i_datctype )));
384
- }
385
- else
386
- {
387
- ctrl -> lc_collate = pg_strdup (PQgetvalue (res , 0 , i_datcollate ));
388
- ctrl -> lc_ctype = pg_strdup (PQgetvalue (res , 0 , i_datctype ));
389
- }
373
+ ctrl -> lc_collate = pg_strdup (PQgetvalue (res , 0 , i_datcollate ));
374
+ ctrl -> lc_ctype = pg_strdup (PQgetvalue (res , 0 , i_datctype ));
390
375
391
376
PQclear (res );
392
377
}
@@ -418,10 +403,10 @@ static void
418
403
check_locale_and_encoding (ControlData * oldctrl ,
419
404
ControlData * newctrl )
420
405
{
421
- if (!equivalent_locale (oldctrl -> lc_collate , newctrl -> lc_collate ))
406
+ if (!equivalent_locale (LC_COLLATE , oldctrl -> lc_collate , newctrl -> lc_collate ))
422
407
pg_fatal ("lc_collate cluster values do not match: old \"%s\", new \"%s\"\n" ,
423
408
oldctrl -> lc_collate , newctrl -> lc_collate );
424
- if (!equivalent_locale (oldctrl -> lc_ctype , newctrl -> lc_ctype ))
409
+ if (!equivalent_locale (LC_CTYPE , oldctrl -> lc_ctype , newctrl -> lc_ctype ))
425
410
pg_fatal ("lc_ctype cluster values do not match: old \"%s\", new \"%s\"\n" ,
426
411
oldctrl -> lc_ctype , newctrl -> lc_ctype );
427
412
if (!equivalent_encoding (oldctrl -> encoding , newctrl -> encoding ))
@@ -434,39 +419,46 @@ check_locale_and_encoding(ControlData *oldctrl,
434
419
*
435
420
* Best effort locale-name comparison. Return false if we are not 100% sure
436
421
* the locales are equivalent.
422
+ *
423
+ * Note: The encoding parts of the names are ignored. This function is
424
+ * currently used to compare locale names stored in pg_database, and
425
+ * pg_database contains a separate encoding field. That's compared directly
426
+ * in check_locale_and_encoding().
437
427
*/
438
428
static bool
439
- equivalent_locale (const char * loca , const char * locb )
429
+ equivalent_locale (int category , const char * loca , const char * locb )
440
430
{
441
- const char * chara = strrchr (loca , '.' );
442
- const char * charb = strrchr (locb , '.' );
443
- int lencmp ;
444
-
445
- /* If they don't both contain an encoding part, just do strcasecmp(). */
446
- if (!chara || !charb )
447
- return (pg_strcasecmp (loca , locb ) == 0 );
431
+ const char * chara ;
432
+ const char * charb ;
433
+ char * canona ;
434
+ char * canonb ;
435
+ int lena ;
436
+ int lenb ;
448
437
449
438
/*
450
- * Compare the encoding parts. Windows tends to use code page numbers for
451
- * the encoding part, which equivalent_encoding() won't like, so accept if
452
- * the strings are case-insensitive equal; otherwise use
453
- * equivalent_encoding() to compare.
439
+ * If the names are equal, the locales are equivalent. Checking this
440
+ * first avoids calling setlocale() in the common case that the names
441
+ * are equal. That's a good thing, if setlocale() is buggy, for example.
454
442
*/
455
- if (pg_strcasecmp (chara + 1 , charb + 1 ) != 0 &&
456
- !equivalent_encoding (chara + 1 , charb + 1 ))
457
- return false;
443
+ if (pg_strcasecmp (loca , locb ) == 0 )
444
+ return true;
458
445
459
446
/*
460
- * OK, compare the locale identifiers (e.g. en_US part of en_US.utf8).
461
- *
462
- * It's tempting to ignore non-alphanumeric chars here, but for now it's
463
- * not clear that that's necessary; just do case-insensitive comparison.
447
+ * Not identical. Canonicalize both names, remove the encoding parts,
448
+ * and try again.
464
449
*/
465
- lencmp = chara - loca ;
466
- if (lencmp != charb - locb )
467
- return false;
450
+ canona = get_canonical_locale_name (category , loca );
451
+ chara = strrchr (canona , '.' );
452
+ lena = chara ? (chara - canona ) : strlen (canona );
453
+
454
+ canonb = get_canonical_locale_name (category , locb );
455
+ charb = strrchr (canonb , '.' );
456
+ lenb = charb ? (charb - canonb ) : strlen (canonb );
457
+
458
+ if (lena == lenb && pg_strncasecmp (canona , canonb , lena ) == 0 )
459
+ return true;
468
460
469
- return ( pg_strncasecmp ( loca , locb , lencmp ) == 0 ) ;
461
+ return false ;
470
462
}
471
463
472
464
/*
0 commit comments