The method $dbh->prepare($stmt) of DBD::Oracle ignores the
state of the utf8 flag in the SV for $stmt. For example,
after
my $a = "select '\xe2' from dual";
my $b = decode_utf8("select '\xc3\xa2' from dual");
$a and $b compare equal with the perl 'eq' operator. However,
their internal representations differ. $a is represented in
iso-8859-1 and its utf8 flag is off. $b is represented in
utf-8 and its utf8 flag is on.
The two equal statements give different results when run
using DBD::Oracle. Which gives the 'correct' result depends
on the client-side database character set (the NLS_LANG
charset). $a gives the correct result for 8-bit charsets.
$b gives the correct result if the charset is utf-8.
This is clearly a bug. It can affect any SQL statement which
contains a non-ASCII character. It can strike whether or not
Unicode is being used in the database. I would like to fix it.
This requires that code be put somewhere which decides how to
process the SV on the basis of its utf8 flag and of the
NLS_LANG charset.
There is a problem.
At the C level, the following code, from the file Oracle.c,
is implicated:
XS(XS_DBD__Oracle__st__prepare)
{
dXSARGS;
if (items < 2 || items > 3)
Perl_croak(aTHX_ "Usage: DBD::Oracle::st::_prepare(sth, statement,
attribs=Nullsv)");
{
SV * sth = ST(0);
char * statement = (char *)SvPV_nolen(ST(1));
SV * attribs;
if (items < 3)
attribs = Nullsv;
else {
attribs = ST(2);
}
#line 411 "Oracle.xsi"
{
D_imp_sth(sth);
DBD_ATTRIBS_CHECK("_prepare", sth, attribs);
ST(0) = dbd_st_prepare(sth, imp_sth, statement, attribs) ? &sv_yes : &sv_no;
}
#line 623 "Oracle.c"
}
XSRETURN(1);
}
It is the macro SvPV_nolen which ignores the utf8 flag. This line
is the bug. By the time we get into dbd_st_prepare it is too late,
the utf8 flag is lost.
The way I would like to fix the bug is to change the prototype of
dbd_st_prepare so that it accepts the statement as an (SV *) rather
than a (char *), and change DBD::Oracle::st::_prepare so that it
passes the SV on rather than calling SvPV... itself.
It would then be a small job to put the correct handling of the
utf8 bit flag in the SV into dbd_st_prepare.
The problem is that the above code, which is the implementation
of DBD::Oracle::st::_prepare, is not part of the DBD::Oracle
distribution, nor is it derived from this distribution. It is
actually derived from the file Driver.xst, which is part of the
DBI distribution.
This has two consequences.
1. The bug must be present in all drivers which use Driver.xst :=(
2. I can't see at all how to fix it for DBD::Oracle. It seems that
a fix _requires_ an incompatible change to Driver.xst. The
bug cannot be fixed without change to the prototype for
dbd_st_prepare. However, such a change to the DBI seems
out of the question.
Can anyone suggest a way forward?
--
Charles Jardine - Computing Service, University of Cambridge
[EMAIL PROTECTED] Tel: +44 1223 334506, Fax: +44 1223 334679