Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitb98be8a

Browse files
committed
Provide thread-safe pg_localeconv_r().
This involves four different implementation strategies:1. For Windows, we now require _configthreadlocale() to be availableand work (commitf1da075), and the documentation says that theobject returned by localeconv() is in thread-local memory.2. For glibc, we translate to nl_langinfo_l() calls, because itoffers the same information that way as an extension, and that API isthread-safe.3. For macOS/*BSD, use localeconv_l(), which is thread-safe.4. For everything else, use uselocale() to set the locale for thethread, and use a big ugly lock to defend against the returned objectbeing concurrently clobbered. In practice this currently means onlySolaris.The new call is used in pg_locale.c, replacing calls to setlocale() andlocaleconv().Author: Thomas Munro <thomas.munro@gmail.com>Reviewed-by: Heikki Linnakangas <hlinnaka@iki.fi>Reviewed-by: Peter Eisentraut <peter@eisentraut.org>Discussion:https://postgr.es/m/CA%2BhUKGJqVe0%2BPv9dvC9dSums_PXxGo9SWcxYAMBguWJUGbWz-A%40mail.gmail.com
1 parent4a02af8 commitb98be8a

File tree

9 files changed

+403
-108
lines changed

9 files changed

+403
-108
lines changed

‎configure

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15401,7 +15401,7 @@ fi
1540115401
LIBS_including_readline="$LIBS"
1540215402
LIBS=`echo "$LIBS" | sed -e 's/-ledit//g' -e 's/-lreadline//g'`
1540315403

15404-
for ac_func in backtrace_symbols copyfile copy_file_range elf_aux_info getauxval getifaddrs getpeerucred inet_pton kqueue mbstowcs_l memset_s posix_fallocate ppoll pthread_is_threaded_np setproctitle setproctitle_fast strchrnul strsignal syncfs sync_file_range uselocale wcstombs_l
15404+
for ac_func in backtrace_symbols copyfile copy_file_range elf_aux_info getauxval getifaddrs getpeerucred inet_pton kqueuelocaleconv_lmbstowcs_l memset_s posix_fallocate ppoll pthread_is_threaded_np setproctitle setproctitle_fast strchrnul strsignal syncfs sync_file_range uselocale wcstombs_l
1540515405
do :
1540615406
as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
1540715407
ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"

‎configure.ac

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1764,6 +1764,7 @@ AC_CHECK_FUNCS(m4_normalize([
17641764
getpeerucred
17651765
inet_pton
17661766
kqueue
1767+
localeconv_l
17671768
mbstowcs_l
17681769
memset_s
17691770
posix_fallocate

‎meson.build

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2738,6 +2738,7 @@ func_checks = [
27382738
['inet_aton'],
27392739
['inet_pton'],
27402740
['kqueue'],
2741+
['localeconv_l'],
27412742
['mbstowcs_l'],
27422743
['memset_s'],
27432744
['mkdtemp'],

‎src/backend/utils/adt/pg_locale.c

Lines changed: 21 additions & 107 deletions
Original file line numberDiff line numberDiff line change
@@ -547,12 +547,8 @@ PGLC_localeconv(void)
547547
staticstructlconvCurrentLocaleConv;
548548
staticboolCurrentLocaleConvAllocated= false;
549549
structlconv*extlconv;
550-
structlconvworklconv;
551-
char*save_lc_monetary;
552-
char*save_lc_numeric;
553-
#ifdefWIN32
554-
char*save_lc_ctype;
555-
#endif
550+
structlconvtmp;
551+
structlconvworklconv= {0};
556552

557553
/* Did we do it already? */
558554
if (CurrentLocaleConvValid)
@@ -566,77 +562,21 @@ PGLC_localeconv(void)
566562
}
567563

568564
/*
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.
579567
*/
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-
#ifdefWIN32
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;
626577
worklconv.decimal_point=strdup(extlconv->decimal_point);
627578
worklconv.thousands_sep=strdup(extlconv->thousands_sep);
628579
worklconv.grouping=strdup(extlconv->grouping);
629-
630-
#ifdefWIN32
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 */
640580
worklconv.int_curr_symbol=strdup(extlconv->int_curr_symbol);
641581
worklconv.currency_symbol=strdup(extlconv->currency_symbol);
642582
worklconv.mon_decimal_point=strdup(extlconv->mon_decimal_point);
@@ -654,45 +594,19 @@ PGLC_localeconv(void)
654594
worklconv.p_sign_posn=extlconv->p_sign_posn;
655595
worklconv.n_sign_posn=extlconv->n_sign_posn;
656596

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-
#ifdefWIN32
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")));
673605

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-
*/
679606
PG_TRY();
680607
{
681608
intencoding;
682609

683-
/* Release the pstrdup'd locale names */
684-
pfree(save_lc_monetary);
685-
pfree(save_lc_numeric);
686-
#ifdefWIN32
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-
696610
/*
697611
* Now we must perform encoding conversion from whatever's associated
698612
* with the locales into the database encoding. If we can't identify

‎src/include/pg_config.h.in

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,9 @@
268268
/* Define to 1 if you have the `zstd' library (-lzstd). */
269269
#undef HAVE_LIBZSTD
270270

271+
/* Define to 1 if you have the `localeconv_l' function. */
272+
#undef HAVE_LOCALECONV_L
273+
271274
/* Define to 1 if you have the <mbarrier.h> header file. */
272275
#undef HAVE_MBARRIER_H
273276

‎src/include/port.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -487,6 +487,12 @@ extern void *bsearch_arg(const void *key, const void *base0,
487487
int (*compar) (constvoid*,constvoid*,void*),
488488
void*arg);
489489

490+
/* port/pg_localeconv_r.c */
491+
externintpg_localeconv_r(constchar*lc_monetary,
492+
constchar*lc_numeric,
493+
structlconv*output);
494+
externvoidpg_localeconv_free(structlconv*lconv);
495+
490496
/* port/chklocale.c */
491497
externintpg_get_encoding_from_locale(constchar*ctype,boolwrite_message);
492498

‎src/port/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ OBJS = \
4444
noblock.o\
4545
path.o\
4646
pg_bitutils.o\
47+
pg_localeconv_r.o\
4748
pg_popcount_avx512.o\
4849
pg_strong_random.o\
4950
pgcheckdir.o\

‎src/port/meson.build

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ pgport_sources = [
77
'noblock.c',
88
'path.c',
99
'pg_bitutils.c',
10+
'pg_localeconv_r.c',
1011
'pg_popcount_avx512.c',
1112
'pg_strong_random.c',
1213
'pgcheckdir.c',

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp