views:

52

answers:

1

Hello, i am using this approach. If there is an error in the sql, rollback only happens for the first id of the asset_group. Rest of the ids are ignored. Am i doing it the right way?

my $sql = "sql batch that update and insert depending on the condition";  
$dbh->{RaiseError} = 1;  
$dbh->{PrintError} = 0;  
$dbh->{AutoCommit} = 0;  

my $sth = $dbh->prepare($sql);  
my @error = ();  
my $num = 0;  
foreach my $id (@asset_group) {  
 next if ($id eq '');  
 eval {  
  $sth->bind_param(1, $id);  
  $sth->bind_param(2, $vars{'other_id'});  
  $sth->execute();  

 };  
 if ($@) {  
  $dbh->rollback();  
  push @error, $@  
 } else {  
  $dbh->commit();  
 }  
}
+6  A: 

Depending on the database, you may need to issue a begin work before you start changing things. I seem to remember Informix requiring one.

Also, it looks like you are issuing a commit or a rollback after each execute. Once you commit, you can't rollback. Normally one says something like

$dbh->begin_work;
eval {
    for my $id (@asset_group) {  
        next if ($id eq '');  
        $sth->execute($id, $vars{other_id});  
    }
    1; #if it doesn't die then this will force it to return true
} or do {
    my $error = DBI->errstr;
    $dbh->rollback();
    die "could not insert rows: $error\n"
};
$dbh->commit();

Note how I don't use $@. $@ is untrustworthy.

Chas. Owens
You shouldn't need to call `begin_work`. It exists primarily to allow you to use a transaction for a particular group of actions even though you have AutoCommit on. With AutoCommit off (as it is here), all it does is die if the database doesn't support transactions. But the rest of your answer is good advice.
cjm
Thanks all. it worked.
alp
@alp, then you should mark the answer as accepted by clicking on the checkmark near its score.
cjm