Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit b631a46

Browse files
committed
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 2dfa15d). 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
1 parent 758fcfd commit b631a46

File tree

7 files changed

+87
-8
lines changed

7 files changed

+87
-8
lines changed

src/pl/plperl/SPI.xs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ do_plperl_return_next(SV *sv)
4141
FlushErrorState();
4242

4343
/* Punt the error to Perl */
44-
croak("%s", edata->message);
44+
croak_cstr(edata->message);
4545
}
4646
PG_END_TRY();
4747
}

src/pl/plperl/Util.xs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ do_util_elog(int level, SV *msg)
5858
pfree(cmsg);
5959

6060
/* Punt the error to Perl */
61-
croak("%s", edata->message);
61+
croak_cstr(edata->message);
6262
}
6363
PG_END_TRY();
6464
}

src/pl/plperl/expected/plperl_elog.out

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,3 +97,16 @@ NOTICE: caught die
9797
2
9898
(1 row)
9999

100+
-- Test non-ASCII error messages
101+
--
102+
-- Note: this test case is known to fail if the database encoding is
103+
-- EUC_CN, EUC_JP, EUC_KR, or EUC_TW, for lack of any equivalent to
104+
-- U+00A0 (no-break space) in those encodings. However, testing with
105+
-- plain ASCII data would be rather useless, so we must live with that.
106+
SET client_encoding TO UTF8;
107+
create or replace function error_with_nbsp() returns void language plperl as $$
108+
elog(ERROR, "this message contains a no-break space");
109+
$$;
110+
select error_with_nbsp();
111+
ERROR: this message contains a no-break space at line 2.
112+
CONTEXT: PL/Perl function "error_with_nbsp"

src/pl/plperl/expected/plperl_elog_1.out

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,3 +97,16 @@ NOTICE: caught die
9797
2
9898
(1 row)
9999

100+
-- Test non-ASCII error messages
101+
--
102+
-- Note: this test case is known to fail if the database encoding is
103+
-- EUC_CN, EUC_JP, EUC_KR, or EUC_TW, for lack of any equivalent to
104+
-- U+00A0 (no-break space) in those encodings. However, testing with
105+
-- plain ASCII data would be rather useless, so we must live with that.
106+
SET client_encoding TO UTF8;
107+
create or replace function error_with_nbsp() returns void language plperl as $$
108+
elog(ERROR, "this message contains a no-break space");
109+
$$;
110+
select error_with_nbsp();
111+
ERROR: this message contains a no-break space at line 2.
112+
CONTEXT: PL/Perl function "error_with_nbsp"

src/pl/plperl/plperl.c

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3066,7 +3066,7 @@ plperl_spi_exec(char *query, int limit)
30663066
SPI_restore_connection();
30673067

30683068
/* Punt the error to Perl */
3069-
croak("%s", edata->message);
3069+
croak_cstr(edata->message);
30703070

30713071
/* Can't get here, but keep compiler quiet */
30723072
return NULL;
@@ -3299,7 +3299,7 @@ plperl_spi_query(char *query)
32993299
SPI_restore_connection();
33003300

33013301
/* Punt the error to Perl */
3302-
croak("%s", edata->message);
3302+
croak_cstr(edata->message);
33033303

33043304
/* Can't get here, but keep compiler quiet */
33053305
return NULL;
@@ -3385,7 +3385,7 @@ plperl_spi_fetchrow(char *cursor)
33853385
SPI_restore_connection();
33863386

33873387
/* Punt the error to Perl */
3388-
croak("%s", edata->message);
3388+
croak_cstr(edata->message);
33893389

33903390
/* Can't get here, but keep compiler quiet */
33913391
return NULL;
@@ -3560,7 +3560,7 @@ plperl_spi_prepare(char *query, int argc, SV **argv)
35603560
SPI_restore_connection();
35613561

35623562
/* Punt the error to Perl */
3563-
croak("%s", edata->message);
3563+
croak_cstr(edata->message);
35643564

35653565
/* Can't get here, but keep compiler quiet */
35663566
return NULL;
@@ -3701,7 +3701,7 @@ plperl_spi_exec_prepared(char *query, HV *attr, int argc, SV **argv)
37013701
SPI_restore_connection();
37023702

37033703
/* Punt the error to Perl */
3704-
croak("%s", edata->message);
3704+
croak_cstr(edata->message);
37053705

37063706
/* Can't get here, but keep compiler quiet */
37073707
return NULL;
@@ -3830,7 +3830,7 @@ plperl_spi_query_prepared(char *query, int argc, SV **argv)
38303830
SPI_restore_connection();
38313831

38323832
/* Punt the error to Perl */
3833-
croak("%s", edata->message);
3833+
croak_cstr(edata->message);
38343834

38353835
/* Can't get here, but keep compiler quiet */
38363836
return NULL;

src/pl/plperl/plperl_helpers.h

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,4 +123,42 @@ cstr2sv(const char *str)
123123
return sv;
124124
}
125125

126+
/*
127+
* croak() with specified message, which is given in the database encoding.
128+
*
129+
* Ideally we'd just write croak("%s", str), but plain croak() does not play
130+
* nice with non-ASCII data. In modern Perl versions we can call cstr2sv()
131+
* and pass the result to croak_sv(); in versions that don't have croak_sv(),
132+
* we have to work harder.
133+
*/
134+
static inline void
135+
croak_cstr(const char *str)
136+
{
137+
#ifdef croak_sv
138+
/* Use sv_2mortal() to be sure the transient SV gets freed */
139+
croak_sv(sv_2mortal(cstr2sv(str)));
140+
#else
141+
142+
/*
143+
* The older way to do this is to assign a UTF8-marked value to ERRSV and
144+
* then call croak(NULL). But if we leave it to croak() to append the
145+
* error location, it does so too late (only after popping the stack) in
146+
* some Perl versions. Hence, use mess() to create an SV with the error
147+
* location info already appended.
148+
*/
149+
SV *errsv = get_sv("@", GV_ADD);
150+
char *utf8_str = utf_e2u(str);
151+
SV *ssv;
152+
153+
ssv = mess("%s", utf8_str);
154+
SvUTF8_on(ssv);
155+
156+
pfree(utf8_str);
157+
158+
sv_setsv(errsv, ssv);
159+
160+
croak(NULL);
161+
#endif /* croak_sv */
162+
}
163+
126164
#endif /* PL_PERL_HELPERS_H */

src/pl/plperl/sql/plperl_elog.sql

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,3 +76,18 @@ return $a + $b;
7676
$$;
7777

7878
select indirect_die_caller();
79+
80+
-- Test non-ASCII error messages
81+
--
82+
-- Note: this test case is known to fail if the database encoding is
83+
-- EUC_CN, EUC_JP, EUC_KR, or EUC_TW, for lack of any equivalent to
84+
-- U+00A0 (no-break space) in those encodings. However, testing with
85+
-- plain ASCII data would be rather useless, so we must live with that.
86+
87+
SET client_encoding TO UTF8;
88+
89+
create or replace function error_with_nbsp() returns void language plperl as $$
90+
elog(ERROR, "this message contains a no-break space");
91+
$$;
92+
93+
select error_with_nbsp();

0 commit comments

Comments
 (0)