@@ -547,12 +547,8 @@ PGLC_localeconv(void)
547
547
static struct lconv CurrentLocaleConv ;
548
548
static bool CurrentLocaleConvAllocated = false;
549
549
struct lconv * extlconv ;
550
- struct lconv worklconv ;
551
- char * save_lc_monetary ;
552
- char * save_lc_numeric ;
553
- #ifdef WIN32
554
- char * save_lc_ctype ;
555
- #endif
550
+ struct lconv tmp ;
551
+ struct lconv worklconv = {0 };
556
552
557
553
/* Did we do it already? */
558
554
if (CurrentLocaleConvValid )
@@ -566,77 +562,21 @@ PGLC_localeconv(void)
566
562
}
567
563
568
564
/*
569
- * This is tricky because we really don't want to risk throwing error
570
- * while the locale is set to other than our usual settings. Therefore,
571
- * the process is: collect the usual settings, set locale to special
572
- * setting, copy relevant data into worklconv using strdup(), restore
573
- * normal settings, convert data to desired encoding, and finally stash
574
- * the collected data in CurrentLocaleConv. This makes it safe if we
575
- * throw an error during encoding conversion or run out of memory anywhere
576
- * in the process. All data pointed to by struct lconv members is
577
- * allocated with strdup, to avoid premature elog(ERROR) and to allow
578
- * using a single cleanup routine.
565
+ * Use thread-safe method of obtaining a copy of lconv from the operating
566
+ * system.
579
567
*/
580
- memset (& worklconv , 0 , sizeof (worklconv ));
581
-
582
- /* Save prevailing values of monetary and numeric locales */
583
- save_lc_monetary = setlocale (LC_MONETARY , NULL );
584
- if (!save_lc_monetary )
585
- elog (ERROR , "setlocale(NULL) failed" );
586
- save_lc_monetary = pstrdup (save_lc_monetary );
587
-
588
- save_lc_numeric = setlocale (LC_NUMERIC , NULL );
589
- if (!save_lc_numeric )
590
- elog (ERROR , "setlocale(NULL) failed" );
591
- save_lc_numeric = pstrdup (save_lc_numeric );
592
-
593
- #ifdef WIN32
594
-
595
- /*
596
- * The POSIX standard explicitly says that it is undefined what happens if
597
- * LC_MONETARY or LC_NUMERIC imply an encoding (codeset) different from
598
- * that implied by LC_CTYPE. In practice, all Unix-ish platforms seem to
599
- * believe that localeconv() should return strings that are encoded in the
600
- * codeset implied by the LC_MONETARY or LC_NUMERIC locale name. Hence,
601
- * once we have successfully collected the localeconv() results, we will
602
- * convert them from that codeset to the desired server encoding.
603
- *
604
- * Windows, of course, resolutely does things its own way; on that
605
- * platform LC_CTYPE has to match LC_MONETARY/LC_NUMERIC to get sane
606
- * results. Hence, we must temporarily set that category as well.
607
- */
608
-
609
- /* Save prevailing value of ctype locale */
610
- save_lc_ctype = setlocale (LC_CTYPE , NULL );
611
- if (!save_lc_ctype )
612
- elog (ERROR , "setlocale(NULL) failed" );
613
- save_lc_ctype = pstrdup (save_lc_ctype );
614
-
615
- /* Here begins the critical section where we must not throw error */
616
-
617
- /* use numeric to set the ctype */
618
- setlocale (LC_CTYPE , locale_numeric );
619
- #endif
620
-
621
- /* Get formatting information for numeric */
622
- setlocale (LC_NUMERIC , locale_numeric );
623
- extlconv = localeconv ();
624
-
625
- /* Must copy data now in case setlocale() overwrites it */
568
+ if (pg_localeconv_r (locale_monetary ,
569
+ locale_numeric ,
570
+ & tmp ) != 0 )
571
+ elog (ERROR ,
572
+ "could not get lconv for LC_MONETARY = \"%s\", LC_NUMERIC = \"%s\": %m" ,
573
+ locale_monetary , locale_numeric );
574
+
575
+ /* Must copy data now now so we can re-encode it. */
576
+ extlconv = & tmp ;
626
577
worklconv .decimal_point = strdup (extlconv -> decimal_point );
627
578
worklconv .thousands_sep = strdup (extlconv -> thousands_sep );
628
579
worklconv .grouping = strdup (extlconv -> grouping );
629
-
630
- #ifdef WIN32
631
- /* use monetary to set the ctype */
632
- setlocale (LC_CTYPE , locale_monetary );
633
- #endif
634
-
635
- /* Get formatting information for monetary */
636
- setlocale (LC_MONETARY , locale_monetary );
637
- extlconv = localeconv ();
638
-
639
- /* Must copy data now in case setlocale() overwrites it */
640
580
worklconv .int_curr_symbol = strdup (extlconv -> int_curr_symbol );
641
581
worklconv .currency_symbol = strdup (extlconv -> currency_symbol );
642
582
worklconv .mon_decimal_point = strdup (extlconv -> mon_decimal_point );
@@ -654,45 +594,19 @@ PGLC_localeconv(void)
654
594
worklconv .p_sign_posn = extlconv -> p_sign_posn ;
655
595
worklconv .n_sign_posn = extlconv -> n_sign_posn ;
656
596
657
- /*
658
- * Restore the prevailing locale settings; failure to do so is fatal.
659
- * Possibly we could limp along with nondefault LC_MONETARY or LC_NUMERIC,
660
- * but proceeding with the wrong value of LC_CTYPE would certainly be bad
661
- * news; and considering that the prevailing LC_MONETARY and LC_NUMERIC
662
- * are almost certainly "C", there's really no reason that restoring those
663
- * should fail.
664
- */
665
- #ifdef WIN32
666
- if (!setlocale (LC_CTYPE , save_lc_ctype ))
667
- elog (FATAL , "failed to restore LC_CTYPE to \"%s\"" , save_lc_ctype );
668
- #endif
669
- if (!setlocale (LC_MONETARY , save_lc_monetary ))
670
- elog (FATAL , "failed to restore LC_MONETARY to \"%s\"" , save_lc_monetary );
671
- if (!setlocale (LC_NUMERIC , save_lc_numeric ))
672
- elog (FATAL , "failed to restore LC_NUMERIC to \"%s\"" , save_lc_numeric );
597
+ /* Free the contents of the object populated by pg_localeconv_r(). */
598
+ pg_localeconv_free (& tmp );
599
+
600
+ /* If any of the preceding strdup calls failed, complain now. */
601
+ if (!struct_lconv_is_valid (& worklconv ))
602
+ ereport (ERROR ,
603
+ (errcode (ERRCODE_OUT_OF_MEMORY ),
604
+ errmsg ("out of memory" )));
673
605
674
- /*
675
- * At this point we've done our best to clean up, and can call functions
676
- * that might possibly throw errors with a clean conscience. But let's
677
- * make sure we don't leak any already-strdup'd fields in worklconv.
678
- */
679
606
PG_TRY ();
680
607
{
681
608
int encoding ;
682
609
683
- /* Release the pstrdup'd locale names */
684
- pfree (save_lc_monetary );
685
- pfree (save_lc_numeric );
686
- #ifdef WIN32
687
- pfree (save_lc_ctype );
688
- #endif
689
-
690
- /* If any of the preceding strdup calls failed, complain now. */
691
- if (!struct_lconv_is_valid (& worklconv ))
692
- ereport (ERROR ,
693
- (errcode (ERRCODE_OUT_OF_MEMORY ),
694
- errmsg ("out of memory" )));
695
-
696
610
/*
697
611
* Now we must perform encoding conversion from whatever's associated
698
612
* with the locales into the database encoding. If we can't identify
0 commit comments