The problem: -----------
When Oracle matches placeholder names passed to OCIBindByName() with the actual placeholders in the SQL or PL/SQL, it uses a case-insensitive comparison. This means that Oracle regards the placeholders :a and :A as the same.
On the other hand, DBD::Oracle uses case-sensitive comparison when matching placeholder names, and regards :a and :A as different.
This has at least two undesirable effects.
1. If the statement contains two named placeholders which differ only in letter_case, they will each contribute to the count in $sth->{NUM_OF_PARAMS}, despite the fact that this is meant to be a count of _distinct_ placeholders.
2. The name passed to $sth->bind_param... must match in letter case at least one of the occurences of the placeholder in the statement. This is not what an OCI programmer would expect. Many of the examples in the OCI manual have the names passed to OCIBindByName() in upper case, and those in the PL/SQL in lower case.
Below is a tiny perl program which demonstrates this.
The proposed solution: ---------------------
I suggest that DBD::Oracle's handling of placeholder name comparisons should be changed to be case-insensitive.
Below is a patch to dbdimp.c (version 1.14) which achieves this by lower-casing the name both at preparse time and at bind time.
============================ #!/bin/perl -w use strict; use DBI;
my $dbh = DBI->connect('dbi:Oracle:', 'foo', 'bah', {RaiseError=>1, PrintError=>0, AutoCommit=>0}); my $sth = $dbh->prepare( "SELECT decode(:a, :A, 'same', 'different') from dual");
# The following prints 2, indicating that DBD::Oracle # thinks that the above has two distinct placeholders
print $sth->{NUM_OF_PARAMS}, "\n";
$sth->bind_param(':a', 'lower'); $sth->bind_param(':A', 'upper'); $sth->execute;
# The following prints 'same', indicating that Oracle # can't see the difference between the placeholders
print +($sth->fetch)->[0], "\n";
$sth->finish; $dbh->disconnect; ============================= --- dbdimp.c.orig Fri Oct 17 13:08:17 2003 +++ dbdimp.c Fri Oct 17 13:08:49 2003 @@ -812,7 +812,7 @@
} else if (isALNUM(*src)) { /* ':foo' */ while(isALNUM(*src)) /* includes '_' */ - *dest++ = *src++; + *dest++ = toLOWER(*src), src++; style = ":foo"; } else { /* perhaps ':=' PL/SQL construct */ /* if (src == ':') *dest++ = *src++; XXX? move past '::'? */ @@ -1321,7 +1321,7 @@ SV **phs_svp; STRLEN name_len; char *name = Nullch; - char namebuf[30]; + char namebuf[32]; /* ':' + 30 char name + '\0' */ phs_t *phs;
/* check if placeholder was passed as a number */ @@ -1329,7 +1329,13 @@ if (SvGMAGICAL(ph_namesv)) /* eg if from tainted expression */ mg_get(ph_namesv); if (!SvNIOKp(ph_namesv)) { + int i; name = SvPV(ph_namesv, name_len); + if (name_len>31) + croak("Placeholder name too long (%s)", neatsvpv(ph_namesv,0)); + for (i=0; i<name_len; i++) namebuf[i] = toLOWER(name[i]); + namebuf[i] = '\0'; + name = namebuf; } if (SvNIOKp(ph_namesv) || (name && isDIGIT(name[0]))) { sprintf(namebuf, ":p%d", (int)SvIV(ph_namesv));
===================================================
-- Charles Jardine - Computing Service, University of Cambridge [EMAIL PROTECTED] Tel: +44 1223 334506, Fax: +44 1223 334679