On 04-Sep-2006 Tim Bunce wrote: > On Mon, Sep 04, 2006 at 05:21:17PM +0100, Martin J. Evans wrote: >> >> It did raise an issue where I could do with some clarification. The slides >> say: >> >> Execute a statement for multiple values >> $sth = $dbh->prepare("insert into table (foo,bar) values (?,?)"); >> $tuples = $sth->execute_array(\%attr, [EMAIL PROTECTED], [EMAIL >> PROTECTED]); >> >> returns count of executions (even ones that failed) and not rows-affected. >> >> but the latest DBI pod says: >> >> The execute_array() method returns the number of tuples executed, >> or "undef" if an error occured. Like execute(), a successful exe- >> cute_array() always returns true regardless of the number of tuples >> executed, even if it's zero. See the "ArrayTupleStatus" attribute >> below for how to determine the execution status for each tuple. >> >> I read that latter as if undef is returned 1 or more of the executes failed >> but >> now I read in the slides they suggest I may get a true value when an error >> occurs. My experience with execute_array and Oracle shows I get: >> >> return 0, when none resulted in a change but no errors >> e.g. >> drop table mytest >> create table mytest (a int primary key, b char(20)) >> insert into mytest values (1,'onetwothree') >> update mytest set b = ? where a = ? >> $sth->bind_param_array(2, [2]) >> $sth->bind_param_array(1, ['two']) >> $sth->execute_array( { ArrayTupleStatus => [EMAIL PROTECTED] } ) >> >> returns 0 >> >> No, error, just no update occurred. It does not return 1 as the slide >> suggests and does seem to be the number of rows changed - none. >> >> returns undef when there is an error >> e.g. >> as per above example but the bind_param_array for p2 is invalid e.g. 'xxx' >> >> This seems to also contradict the slide but agrees with the DBI pod. >> >> lastly I get undef if there are multiple rows but the last one errors. >> e.g. as above except the bind_param_arrays are: >> >> $sth->bind_param_array(2, [1, 'xxx']); >> $sth->bind_param_array(1, ['one', 'two']); >> >> returns undef but executes the 1,'one'. >> >> I am now unclear as to what is correct. Can you clarify? > > The pod is right and both the slides and DBD::Oracle are wrong, > though in different ways. > > The behaviour should match that of the default execute_for_fetch > method (which execute_array calls) provided by the DBI - shown below. > > Thanks! I've fixed my copy of the slide to say "returns count of > executions, not rows-affected, or undef if any failed". > > Tim. > > p.s. I'd be grateful if you could file a bug at rt.cpan.org for DBD::Oracle. > > > sub execute_for_fetch { > my ($sth, $fetch_tuple_sub, $tuple_status) = @_; > # start with empty status array > ($tuple_status) ? @$tuple_status = () : $tuple_status = []; > > my ($err_count, %errstr_cache); > while ( my $tuple = &$fetch_tuple_sub() ) { > if ( my $rc = $sth->execute(@$tuple) ) { > push @$tuple_status, $rc; > } > else { > $err_count++; > my $err = $sth->err; > push @$tuple_status, [ $err, $errstr_cache{$err} ||= > $sth->errstr, $sth->state ]; > } > } > my $tuples = @$tuple_status; > return $sth->set_err(1, "executing $tuples generated $err_count > errors") > if $err_count; > return scalar(@$tuple_status) || "0E0"; > }
Thanks for the clarification. I'll report the problems just as soon as I'm certain what they are. Here is my summary: 1. insert into table values (?,?) where all values are valid and 3 rows of values returns: 3 (correct as 3 tuples executed) ArrayTupleStatus = (-1, -1, -1) (incorrect - should be (1,1,1) as DBD::Oracle does know a row was inserted each time as evidenced by execute itself which returns rows affected) 2. insert into table values (?,?) where there are 2 rows of data but second one is invalid returns: undef (correct) ArrayTupleStatus = (-1, [1772, 'ORA-01722.......']) (incorrect as this should be (1, [1772, 'ORA-01722.......']) probably same issue as 1). 3. update table where the update does not affect any rows returns: 0 (incorrect - should be 1 for 1 tuple executed) ArrayTupleStatus = (-1) (incorrect - should be (0) for no rows affected) If my conclusions look right to you I'll report them on rt. As an aside, I am finding execute_array returning the number of tuples executed rather than the number of rows affected a bit of a pain. It seems to make it easy to ascertain how many tuples were executed but hard to find out how many rows were affected when I would have thought the former is less useful and easily calculated as [EMAIL PROTECTED]). What I normally do on a single insert/update execute is: $affected = $sth->execute(@params) ERROR if ($affected != $expected_inserts_or_updates); as this catches errors in the execute and error in the program logic (not inserting/updating what I expected). execute_array does not map easily to being n * execute as far as I can see since the equivalent test for execute_array is: $tuples_executed = $sth->execute_array if (!$tuples_executed) { # there was an error } else { # here $tuples_executed has no meaning for me since I know what it is going # to be before calling execute_array - it is going to be the number of tuples # I passed to execute_array my $affected = 0; $affected += $_ foreach (@array_tuple_status); ERROR if ($affected != $expected_inserts_or_updates) } It's possible I've misunderstood what is returned by execute_array but it is difficult to actually try it out when I don't seem to have a driver that does it properly. Martin -- Martin J. Evans Easysoft Ltd, UK http://www.easysoft.com