diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2015-09-29 10:52:22 -0400 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2015-09-29 10:52:22 -0400 |
commit | b631a46ed83b7eebf5cde16b41d842596cbcc69d (patch) | |
tree | 8f542c5aca13f6830a17aebe4b7c8075dfc53dde /src/pl/plperl/plperl_helpers.h | |
parent | 758fcfdc016ac687c4f4094e0dca6ae641400820 (diff) | |
download | postgresql-b631a46ed83b7eebf5cde16b41d842596cbcc69d.tar.gz postgresql-b631a46ed83b7eebf5cde16b41d842596cbcc69d.zip |
Fix plperl to handle non-ASCII error message texts correctly.
We were passing error message texts to croak() verbatim, which turns out
not to work if the text contains non-ASCII characters; Perl mangles their
encoding, as reported in bug #13638 from Michal Leinweber. To fix, convert
the text into a UTF8-encoded SV first.
It's hard to test this without risking failures in different database
encodings; but we can follow the lead of plpython, which is already
assuming that no-break space (U+00A0) has an equivalent in all encodings
we care about running the regression tests in (cf commit 2dfa15de5).
Back-patch to 9.1. The code is quite different in 9.0, and anyway it seems
too risky to put something like this into 9.0's final minor release.
Alex Hunsaker, with suggestions from Tim Bunce and Tom Lane
Diffstat (limited to 'src/pl/plperl/plperl_helpers.h')
-rw-r--r-- | src/pl/plperl/plperl_helpers.h | 38 |
1 files changed, 38 insertions, 0 deletions
diff --git a/src/pl/plperl/plperl_helpers.h b/src/pl/plperl/plperl_helpers.h index fab0a7ba081..f8aa06835ce 100644 --- a/src/pl/plperl/plperl_helpers.h +++ b/src/pl/plperl/plperl_helpers.h @@ -123,4 +123,42 @@ cstr2sv(const char *str) return sv; } +/* + * croak() with specified message, which is given in the database encoding. + * + * Ideally we'd just write croak("%s", str), but plain croak() does not play + * nice with non-ASCII data. In modern Perl versions we can call cstr2sv() + * and pass the result to croak_sv(); in versions that don't have croak_sv(), + * we have to work harder. + */ +static inline void +croak_cstr(const char *str) +{ +#ifdef croak_sv + /* Use sv_2mortal() to be sure the transient SV gets freed */ + croak_sv(sv_2mortal(cstr2sv(str))); +#else + + /* + * The older way to do this is to assign a UTF8-marked value to ERRSV and + * then call croak(NULL). But if we leave it to croak() to append the + * error location, it does so too late (only after popping the stack) in + * some Perl versions. Hence, use mess() to create an SV with the error + * location info already appended. + */ + SV *errsv = get_sv("@", GV_ADD); + char *utf8_str = utf_e2u(str); + SV *ssv; + + ssv = mess("%s", utf8_str); + SvUTF8_on(ssv); + + pfree(utf8_str); + + sv_setsv(errsv, ssv); + + croak(NULL); +#endif /* croak_sv */ +} + #endif /* PL_PERL_HELPERS_H */ |