On 15/08/12 17:39, Tim Bunce wrote:
On Wed, Aug 15, 2012 at 04:14:52PM +0100, Martin J. Evans wrote:
I've just been given an rt https://rt.cpan.org/Ticket/Display.html?id=78838 and 
am at a loss to explain exactly what is happening. I wonder if anyone can help?

Some background:

DBI says for bind_param:

"The bind_param method takes a copy of $bind_value and associates it (binds it) with 
a placeholder"

As far as I am aware DBD::ODBC does not copy the scalar given to it -
so perhaps DBI does this. The problem I'm seeing in the provided
example is the pointer passed to ODBC's SQLBindParameter at the time
bind_param is called no longer points to a valid string when execute
is called. However, changing the call to bind_param to pass $obj as
"$obj" appears to fix the problem.

The driver should take a copy of the value when bind_param is called.
Perhaps stored by the ParamValues attribute.
(bind_param_inout takes a reference instead and binds at execute.)

As pointed out in another reponse DBD::ODBC was taking a copy after all but 
when I dug deeper into this it has opened a bag of worms.

1. DBD::Oracle seems to work with the test code because it does:

  if (SvAMAGIC(phs->sv)) /* overloaded. XXX hack, logic ought to be pushed 
deeper */
        sv_pvn_force(phs->sv, &PL_na);

This change also fixes DBD::ODBC in this case.

I'd be interested in comments on this.

2. The logic in DBD::ODBC when a sql_type was passed meant you could change an 
in type to out type or increase the size of an output bound param after the 
first bind without it being caught. Fixed.

3. Without (1 above) things got a little silly because by only changing the 
example code to add Dumper($sth->{ParamValues}) before execute it made it work 
- I'd guess because that causes SvPV to be called on the bound parameters - oops.

Thanks for the pointers.

Martin
--
Martin J. Evans
Easysoft Limited
http://www.easysoft.com

Reply via email to