Re: Error during SQL Server restore fails to propagate back to DBI client on Windows
[email protected] ("Martin J. Evans")
| Newsgroups | perl.dbi.users |
|---|---|
| Organization | Easysoft Limited |
| Message-ID | <[email protected]> |
On 19/02/2010 23:22, pr wrote: > > --- On Fri, 2/19/10, Martin Evans<[email protected]> wrote: > > >> From: Martin Evans<[email protected]> >> Subject: Re: Error during SQL Server restore fails to propagate back to DBI client on Windows >> To: "pr"<[email protected]> >> Cc: [email protected] >> Date: Friday, February 19, 2010, 8:41 AM >> pr wrote: >> >>> --- On Thu, 2/18/10, Martin Evans<[email protected]> >>> >> wrote: >> >>> >>>> From: Martin Evans<[email protected]> >>>> Subject: Re: Error during SQL Server restore fails >>>> >> to propagate back to DBI client on Windows >> >>>> To: "pr"<[email protected]> >>>> Cc: [email protected] >>>> Date: Thursday, February 18, 2010, 8:51 AM >>>> pr wrote: >>>> >>>>> Overview: >>>>> >>>>> Using perl+DBI+DBD::ODBC on Windows, I am >>>>> >> connecting >> >>>> to a SQL Server 2005 instance and issuing a >>>> >> "restore >> >>>> database [foo] from disk='c:\foo-backup.bak'". >>>> >>>>> The restore attempt appears to succeed, and >>>>> >> nothing >> >>>> calls my installed error handler. >>>> >>>>> However, if I run a trace on the SQL Server, I >>>>> >> can see >> >>>> the restore is throwing an error: >>>> >>>>> Error 3224, Severity 16, State 1: Cannot >>>>> >> create worker >> >>>> thread. >>>> >>>>> RESTORE DATABASE is terminating abnormally. >>>>> >>>>> If I write the same SQL to a file, then >>>>> >> execute the >> >>>> file via sqlcmd, the restore works as >>>> >> expected. Hence >> >>>> I am confident in the SQL command as well as the >>>> >> backup >> >>>> file. >>>> >>>>> Other DML-type commands work as advertised, as >>>>> >> does >> >>>> the error handler. It seems to be something >>>> specifically about a restore. >>>> >>>>> Specifics: >>>>> >>>>> The version of perl is ActiveState's v5.10.0 >>>>> >> running >> >>>> on a 32 bit Windows 2003 server. >>>> >>>>> My DSN and connect code looks like: >>>>> >>>>> my $dsn = 'Driver={SQL Native >>>>> >>>> >> Client};Server=myServer;Database=master;Trusted_Connection=yes;Encrypt=yes;'; >> >>>>> my $dbh = >>>>> >> DBI->connect("dbi:ODBC:$dsn",'','', { >> >>>> RaiseError => 1, AutoCommit => 1 } ); >>>> >>>>> $dbh->{HandleError} = \&error_handler; >>>>> >>>>> My error handler looks like: >>>>> >>>>> sub error_handler { >>>>> my @err = @_; >>>>> >>>>> print "Error handler >>>>> >>>> triggered!\n"; >>>> >>>>> return 0; >>>>> } >>>>> >>>>> I have tried: >>>>> - $dbh->do ( $restore_command ) >>>>> - $sth = $dbh->prepare( $restore_command >>>>> >> ); >> >>>> $sth->execute(); ... >>>> >>>>> I've tried with and without >>>>> >>>> $dbh->{odbc_exec_direct} = 1 and also not >>>> >> specifying it. >> >>>>> The MDAC version on the machine is recent: >>>>> >> version >> >>>> 2.82.3959.0. >>>> >>>>> The version of DBI is 1.604. >>>>> >>>>> I have tried running a DBI trace at up to >>>>> >> level 15, >> >>>> and there doesn't seem to be anything of >>>> >> interest. >> >>>>> >>>>> Has this been brought up before? Has >>>>> >> someone >> >>>> encountered it? >>>> >>>>> If there are other things I should try, I >>>>> >> would very >> >>>> much appreciate the suggestions! >>>> >>>>> I'm completely at a loss where the problem is. >>>>> >> >>>> Code? DBD? DBI? SQL >>>> >> Server? mdac? >> >>>>> Thanks >>>>> -rt >>>>> >>>>> >>>>> >>>>> >>>>> >>>>> >>>> Can I see the rest of the code after the prepare >>>> >> please? >> >>>> Preferably a small self contained and complete >>>> >> example >> >>>> would be best. >>>> >>>> Are you calling odbc_more_results after execute >>>> >> until it >> >>>> returns false? >>>> >>>> Martin >>>> -- >>>> Martin J. Evans >>>> Easysoft Limited >>>> http://www.easysoft.com >>>> >>>> >>> Hi Martin, >>> >>> Thank you for your reply. >>> >>> I'm depending on DBI's do() method: >>> >>> my $dbh=DBI->connect("dbi:ODBC:$dsn",'',''); >>> $dbh->{HandleError} = sub { print "error >>> >> occurred\n"; }; >> >>> $sql = 'restore database [foo] from >>> >> disk=\'c:\\mybackup.bak\' with replace'; >> >>> $dbh->do( $sql ); >>> >>> >>> >>> I've also tried: >>> >>> my $dbh=DBI->connect("dbi:ODBC:$dsn",'',''); >>> $dbh->{HandleError} = sub { print "error >>> >> occurred\n"; }; >> >>> $sql = 'restore database [foo] from >>> >> disk=\'c:\\mybackup.bak\' with my $sth = $dbh->prepare( >> $sql ); >> >>> my $dbh->execute(); >>> while ( my @junk = $sth->fetchrow_array() ) { >>> # do nothing >>> } >>> >>> >>> In both cases, the error handler is not triggered, and >>> >> all appears well on the client in. However, a trace >> using SQLProfiler shows Msg 3224 and that the backup >> terminates abnormally. >> >>> I've been able to confirm this on two systems running >>> >> the same versions of the software. >> >>> >>> I would expect either approach to work? >>> >>> Regards, >>> -rt >>> >>> >>> >>> >>> >>> >>> >> When you call procedures in MS SQL Server you often need to >> use >> prepare/execute/odbc_more_results because SQL Server >> batches up results >> and anything printed in the procedure can count as a >> result. I would try >> this: >> >> $sth = prepare(restore....) >> $sth->execute >> do { >> my @row; >> while (@row = >> $sth->fetchrow_array()) { >> >> # do stuff here >> } >> } while >> ($sth->{odbc_more_results}); >> >> >> There is an example in t/20SqlServer.t that comes with >> DBD::ODBC - you >> can find it by browsing the source on CPAN. >> >> Martin >> -- >> Martin J. Evans >> Easysoft Limited >> http://www.easysoft.com >> >> > > > Hi Martin, > > Once again, thank you for your time and patience. > > The suggestion to use $sth->{odbc_more_results} improved the situation, but there still seems to be a major issue. > > > What works: > > my $dbh = DBI->connect("dbi:ODBC:$dsn", '', ''); > $dbh->{HandleError} = \&error_handler; > $dbh->{HandleSetErr} = \&set_error_handler; > $dbh->{odbc_exec_direct} = 1; > my $sql = qq| restore database [foo] from disk='l:\\mssql.1\\mssql\\backup\\full\\foo.bak' WITH REPLACE |; > $sth = $dbh->prepare($sql); > $sth->execute(); > do { > print "RESULT SET:\n"; > while ( my @row = $sth->fetchrow_array() ) { > print "\tfetchrow_array() should be empty\n"; > } > } while ( $sth->{odbc_more_results} ); > > > What does not work: > > Remove the call to set dbc_exec_direct to 1. > > In this case, I see in a SQLProfiler trace that the backup is prepared via a call to sp_prepexec (as would be expected). However, the trace shows the server throwing Msg 3224 Severity 16 State 1 - cannot spawn worker thread again. > > The main worry I have is this error does not propagate back to the client at all. > > Here is the code for the error handler and set err handler: > > sub error_handler { > my @err = @_; > > for ( my $i = 0; $i< scalar( @err ); $i++ ) { > if ( ! defined $err[$i] ) { > $err[$i] = '(null)'; > } > print "ERROR HANDLER: $i: $err[$i]\n"; > } > } > > sub set_error_handler { > my @err = @_; > > for ( my $i = 0; $i< scalar( @err ); $i++ ) { > if ( ! defined $err[$i] ) { > $err[$i] = '(null)'; > } > print "SET ERROR HANDLER: $i: $err[$i]\n"; > } > } > > > When I run the script in the failure case (i.e. not setting odbc_exec_direct), I see exactly this: > > SET ERROR HANDLER: 0: DBI::st=HASH(0x1a4d614) > SET ERROR HANDLER: 1: > SET ERROR HANDLER: 2: [Microsoft][SQL Native Client][SQL Server]Processed 160 pages for database 'foo', file 'foo' on file 1. (SQL-01000) > SET ERROR HANDLER: 3: 01000 > SET ERROR HANDLER: 4: (null) > RESULT SET: > > Hence there's every reason to believe from the client point of view this would be a success. > > > The exact versions of the DBI and DBD::ODBC module (updated from ActiveState) are: > > 1.609 DBI > 1.23 DBD::ODBC > > > Any other suggestions? Would it be helpful to bundle up an exact set of scripts to create, backup and run a restore to see if anyone else can reproduce this? I've been able to reproduce this on other servers with a dummy/test setup. > > Regards, > -rt > > The example I sent was just pseudo code. You still need to check for errors. The while loop over odbc_more_results will stop if a) you run out of results or b) if there is an error. You are getting an error as shown by the 01000 state but you did nothing about it in your error handler or by testing odbc_more_results. Check $sth->err after odbc_more_results returns false and I think you'll find it contains 01000 - an error. Martin -- Martin J. Evans Easysoft Limited http://www.easysoft.com