Skip to content

Commit 50d89d4

Browse files
committed
Force strings passed to and from plperl to be in UTF8 encoding.
String are converted to UTF8 on the way into perl and to the database encoding on the way back. This avoids a number of observed anomalies, and ensures Perl a consistent view of the world. Some minor code cleanups are also accomplished. Alex Hunsaker, reviewed by Andy Colson.
1 parent 5ed45ac commit 50d89d4

File tree

5 files changed

+295
-160
lines changed

5 files changed

+295
-160
lines changed

doc/src/sgml/plperl.sgml

+8
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,14 @@ $$ LANGUAGE plperl;
125125
</programlisting>
126126
</para>
127127

128+
<note>
129+
<para>
130+
Arguments will be converted from the database's encoding to UTF-8
131+
for use inside plperl, and then converted from UTF-8 back to the
132+
database encoding upon return.
133+
</para>
134+
</note>
135+
128136
<para>
129137
If an SQL null value<indexterm><primary>null value</><secondary
130138
sortas="PL/Perl">in PL/Perl</></indexterm> is passed to a function,

src/pl/plperl/SPI.xs

+36-16
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,14 @@
99

1010
/* this must be first: */
1111
#include "postgres.h"
12+
#include "mb/pg_wchar.h" /* for GetDatabaseEncoding */
13+
1214
/* Defined by Perl */
1315
#undef _
1416

1517
/* perl stuff */
1618
#include "plperl.h"
19+
#include "plperl_helpers.h"
1720

1821

1922
/*
@@ -50,18 +53,21 @@ PROTOTYPES: ENABLE
5053
VERSIONCHECK: DISABLE
5154

5255
SV*
53-
spi_spi_exec_query(query, ...)
54-
char* query;
56+
spi_spi_exec_query(sv, ...)
57+
SV* sv;
5558
PREINIT:
5659
HV *ret_hash;
5760
int limit = 0;
61+
char *query;
5862
CODE:
5963
if (items > 2)
6064
croak("Usage: spi_exec_query(query, limit) "
6165
"or spi_exec_query(query)");
6266
if (items == 2)
6367
limit = SvIV(ST(1));
68+
query = sv2cstr(sv);
6469
ret_hash = plperl_spi_exec(query, limit);
70+
pfree(query);
6571
RETVAL = newRV_noinc((SV*) ret_hash);
6672
OUTPUT:
6773
RETVAL
@@ -73,46 +79,53 @@ spi_return_next(rv)
7379
do_plperl_return_next(rv);
7480

7581
SV *
76-
spi_spi_query(query)
77-
char *query;
82+
spi_spi_query(sv)
83+
SV *sv;
7884
CODE:
85+
char* query = sv2cstr(sv);
7986
RETVAL = plperl_spi_query(query);
87+
pfree(query);
8088
OUTPUT:
8189
RETVAL
8290

8391
SV *
84-
spi_spi_fetchrow(cursor)
85-
char *cursor;
92+
spi_spi_fetchrow(sv)
93+
SV* sv;
8694
CODE:
95+
char* cursor = sv2cstr(sv);
8796
RETVAL = plperl_spi_fetchrow(cursor);
97+
pfree(cursor);
8898
OUTPUT:
8999
RETVAL
90100

91101
SV*
92-
spi_spi_prepare(query, ...)
93-
char* query;
102+
spi_spi_prepare(sv, ...)
103+
SV* sv;
94104
CODE:
95105
int i;
96106
SV** argv;
107+
char* query = sv2cstr(sv);
97108
if (items < 1)
98109
Perl_croak(aTHX_ "Usage: spi_prepare(query, ...)");
99110
argv = ( SV**) palloc(( items - 1) * sizeof(SV*));
100111
for ( i = 1; i < items; i++)
101112
argv[i - 1] = ST(i);
102113
RETVAL = plperl_spi_prepare(query, items - 1, argv);
103114
pfree( argv);
115+
pfree(query);
104116
OUTPUT:
105117
RETVAL
106118

107119
SV*
108-
spi_spi_exec_prepared(query, ...)
109-
char * query;
120+
spi_spi_exec_prepared(sv, ...)
121+
SV* sv;
110122
PREINIT:
111123
HV *ret_hash;
112124
CODE:
113125
HV *attr = NULL;
114126
int i, offset = 1, argc;
115127
SV ** argv;
128+
char *query = sv2cstr(sv);
116129
if ( items < 1)
117130
Perl_croak(aTHX_ "Usage: spi_exec_prepared(query, [\\%%attr,] "
118131
"[\\@bind_values])");
@@ -128,15 +141,17 @@ spi_spi_exec_prepared(query, ...)
128141
ret_hash = plperl_spi_exec_prepared(query, attr, argc, argv);
129142
RETVAL = newRV_noinc((SV*)ret_hash);
130143
pfree( argv);
144+
pfree(query);
131145
OUTPUT:
132146
RETVAL
133147

134148
SV*
135-
spi_spi_query_prepared(query, ...)
136-
char * query;
149+
spi_spi_query_prepared(sv, ...)
150+
SV * sv;
137151
CODE:
138152
int i;
139153
SV ** argv;
154+
char *query = sv2cstr(sv);
140155
if ( items < 1)
141156
Perl_croak(aTHX_ "Usage: spi_query_prepared(query, "
142157
"[\\@bind_values])");
@@ -145,20 +160,25 @@ spi_spi_query_prepared(query, ...)
145160
argv[i - 1] = ST(i);
146161
RETVAL = plperl_spi_query_prepared(query, items - 1, argv);
147162
pfree( argv);
163+
pfree(query);
148164
OUTPUT:
149165
RETVAL
150166

151167
void
152-
spi_spi_freeplan(query)
153-
char *query;
168+
spi_spi_freeplan(sv)
169+
SV *sv;
154170
CODE:
171+
char *query = sv2cstr(sv);
155172
plperl_spi_freeplan(query);
173+
pfree(query);
156174

157175
void
158-
spi_spi_cursor_close(cursor)
159-
char *cursor;
176+
spi_spi_cursor_close(sv)
177+
SV *sv;
160178
CODE:
179+
char *cursor = sv2cstr(sv);
161180
plperl_spi_cursor_close(cursor);
181+
pfree(cursor);
162182

163183

164184
BOOT:

src/pl/plperl/Util.xs

+32-34
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121

2222
/* perl stuff */
2323
#include "plperl.h"
24-
24+
#include "plperl_helpers.h"
2525

2626
/*
2727
* Implementation of plperl's elog() function
@@ -34,13 +34,16 @@
3434
* This is out-of-line to suppress "might be clobbered by longjmp" warnings.
3535
*/
3636
static void
37-
do_util_elog(int level, char *message)
37+
do_util_elog(int level, SV *msg)
3838
{
3939
MemoryContext oldcontext = CurrentMemoryContext;
40+
char *cmsg = NULL;
4041

4142
PG_TRY();
4243
{
43-
elog(level, "%s", message);
44+
cmsg = sv2cstr(msg);
45+
elog(level, "%s", cmsg);
46+
pfree(cmsg);
4447
}
4548
PG_CATCH();
4649
{
@@ -51,35 +54,20 @@ do_util_elog(int level, char *message)
5154
edata = CopyErrorData();
5255
FlushErrorState();
5356

57+
if (cmsg)
58+
pfree(cmsg);
59+
5460
/* Punt the error to Perl */
5561
croak("%s", edata->message);
5662
}
5763
PG_END_TRY();
5864
}
5965

60-
static SV *
61-
newSVstring_len(const char *str, STRLEN len)
62-
{
63-
SV *sv;
64-
65-
sv = newSVpvn(str, len);
66-
#if PERL_BCDVERSION >= 0x5006000L
67-
if (GetDatabaseEncoding() == PG_UTF8)
68-
SvUTF8_on(sv);
69-
#endif
70-
return sv;
71-
}
72-
7366
static text *
7467
sv2text(SV *sv)
7568
{
76-
STRLEN sv_len;
77-
char *sv_pv;
78-
79-
if (!sv)
80-
sv = &PL_sv_undef;
81-
sv_pv = SvPV(sv, sv_len);
82-
return cstring_to_text_with_len(sv_pv, sv_len);
69+
char *str = sv2cstr(sv);
70+
return cstring_to_text(str);
8371
}
8472

8573
MODULE = PostgreSQL::InServer::Util PREFIX = util_
@@ -105,15 +93,15 @@ _aliased_constants()
10593

10694

10795
void
108-
util_elog(level, message)
96+
util_elog(level, msg)
10997
int level
110-
char* message
98+
SV *msg
11199
CODE:
112100
if (level > ERROR) /* no PANIC allowed thanks */
113101
level = ERROR;
114102
if (level < DEBUG5)
115103
level = DEBUG5;
116-
do_util_elog(level, message);
104+
do_util_elog(level, msg);
117105

118106
SV *
119107
util_quote_literal(sv)
@@ -125,7 +113,9 @@ util_quote_literal(sv)
125113
else {
126114
text *arg = sv2text(sv);
127115
text *ret = DatumGetTextP(DirectFunctionCall1(quote_literal, PointerGetDatum(arg)));
128-
RETVAL = newSVstring_len(VARDATA(ret), (VARSIZE(ret) - VARHDRSZ));
116+
char *str = text_to_cstring(ret);
117+
RETVAL = cstr2sv(str);
118+
pfree(str);
129119
}
130120
OUTPUT:
131121
RETVAL
@@ -136,13 +126,15 @@ util_quote_nullable(sv)
136126
CODE:
137127
if (!sv || !SvOK(sv))
138128
{
139-
RETVAL = newSVstring_len("NULL", 4);
129+
RETVAL = cstr2sv("NULL");
140130
}
141131
else
142132
{
143133
text *arg = sv2text(sv);
144134
text *ret = DatumGetTextP(DirectFunctionCall1(quote_nullable, PointerGetDatum(arg)));
145-
RETVAL = newSVstring_len(VARDATA(ret), (VARSIZE(ret) - VARHDRSZ));
135+
char *str = text_to_cstring(ret);
136+
RETVAL = cstr2sv(str);
137+
pfree(str);
146138
}
147139
OUTPUT:
148140
RETVAL
@@ -153,10 +145,13 @@ util_quote_ident(sv)
153145
PREINIT:
154146
text *arg;
155147
text *ret;
148+
char *str;
156149
CODE:
157150
arg = sv2text(sv);
158151
ret = DatumGetTextP(DirectFunctionCall1(quote_ident, PointerGetDatum(arg)));
159-
RETVAL = newSVstring_len(VARDATA(ret), (VARSIZE(ret) - VARHDRSZ));
152+
str = text_to_cstring(ret);
153+
RETVAL = cstr2sv(str);
154+
pfree(str);
160155
OUTPUT:
161156
RETVAL
162157

@@ -167,9 +162,9 @@ util_decode_bytea(sv)
167162
char *arg;
168163
text *ret;
169164
CODE:
170-
arg = SvPV_nolen(sv);
165+
arg = SvPVbyte_nolen(sv);
171166
ret = DatumGetTextP(DirectFunctionCall1(byteain, PointerGetDatum(arg)));
172-
/* not newSVstring_len because this is raw bytes not utf8'able */
167+
/* not cstr2sv because this is raw bytes not utf8'able */
173168
RETVAL = newSVpvn(VARDATA(ret), (VARSIZE(ret) - VARHDRSZ));
174169
OUTPUT:
175170
RETVAL
@@ -180,10 +175,13 @@ util_encode_bytea(sv)
180175
PREINIT:
181176
text *arg;
182177
char *ret;
178+
STRLEN len;
183179
CODE:
184-
arg = sv2text(sv);
180+
/* not sv2text because this is raw bytes not utf8'able */
181+
ret = SvPVbyte(sv, len);
182+
arg = cstring_to_text_with_len(ret, len);
185183
ret = DatumGetCString(DirectFunctionCall1(byteaout, PointerGetDatum(arg)));
186-
RETVAL = newSVstring_len(ret, strlen(ret));
184+
RETVAL = cstr2sv(ret);
187185
OUTPUT:
188186
RETVAL
189187

0 commit comments

Comments
 (0)