PEPPLER.ORG
Michael Peppler
Sybase Consulting
Menu
Home
Sybase on Linux
Install Guide for Sybase on Linux
General Sybase Resources
General Perl Resources
Freeware
Sybperl
Sybase::Simple
DBD::Sybase
BCP Tool
Bug Tracker
Mailing List Archive
Downloads Directory
FAQs
Sybase on Linux FAQ
Sybperl FAQ
Personal
Michael Peppler's resume

sybperl-l Archive

Up    Prev    Next    

From: "Avis, Ed" <avised at kbcfp dot com>
Subject: Infinite loop calling error handler
Date: Jun 11 2004 3:47PM

When using DBD::Sybase to call a stored procedure I found that my
program would hang and very rapidly start chewing up memory.  This
didn't happen for every call but only for one which failed (a
raiserror and negative exit status from the stored procedure).  It may
also be relevant that I had two statement handles open, one querying
a table and one running the proc.

I got some way to debugging this but then it mysteriously stopped
being reproducible.  However I did find out that the error handler was
being called again and again, and probably recursively since the
memory usage of the program rapidly rose to 1600 megabytes and CPU
use was at 100% when I killed it.  My program looks like

use warnings;
use strict;
use DBI qw(SQL_INTEGER);
my $dbh = DBI->connect("dbi:Sybase:server=$server;database=$database",
                       $login, $password,
                       {
                            RaiseError => 1,
                            ShowErrorStatement => 1,
                            AutoCommit => 0,
                            syb_err_handler => sub {
                                if ($_[0] == 0) {
                                    # Print to stdout and then ignore.
                                    print "$_[6]\n";
                                    return 0;
                                }
                                print STDERR "error handler called with: @_\n";
                                sleep 1;
                                return 1;
                            },
                        });
$dbh->{AutoCommit} = 1;

my $sth_query = $dbh->prepare('select some columns');
execute $sth_query;

$sql = <<'END'
exec my_proc @a = ?,
             @b = ?,
             @c = ?,
             @d = ?,
             @e = ?
END
    ;
my $sth_update = $dbh->prepare($sql);
$sth_update->bind_param($_, undef, SQL_INTEGER) for 1, 2, 3;

while (my @row = $sth_query->fetchrow_array()) {
    print "calling proc\n";
    $sth_update->execute(some parameters);
    print "successfully called proc\n";
}
finish $sth_query;
finish $sth_update;
disconnect $dbh;

The stored procedure does at some point

    raiserror 60020, 'message', 'some more message'

The output looks like

calling proc
error handler called with: 60020 16 1 189 DATATECH_NY my_proc message some more message exec my_proc @a = ?,
                  @b = ?,
                  @c = ?,
                  @d = ?,
                  @e = ?
 server
error handler called with: 155 1 0 0   ct_fetch(): user api layer: external error: This routine cannot be called when the command structure is idle. exec my_proc @a = ?,
                  @b = ?,
                  @c = ?,
                  @d = ?,
                  @e = ?
 client
error handler called with: 155 1 0 0   ct_fetch(): user api layer: external error: This routine cannot be called when the command structure is idle. exec my_proc @a = ?,
                  @b = ?,
                  @c = ?,
                  @d = ?,
                  @e = ?
 client
error handler called with: 155 1 0 0   ct_fetch(): user api layer: external error: This routine cannot be called when the command structure is idle. exec my_proc @a = ?,
                  @b = ?,
                  @c = ?,
                  @d = ?,
                  @e = ?
 client

and so on forever.  If it were not for the sleep(1) in the error
handler the process would start sucking up RAM very quickly.

However, I am no longer able to reproduce this, I don't know why.
But I hope that the above provides enough clues.  Strangely, when
I stepped through with 's' in the debugger it looked like the error
handler was calling itself:

KBCdbiUtil::CODE(0x84673b4)(/prod/datatech/inferno/bin/KBCdbiUtil.pm:149):
149:	                                    return 1; # handle other errors normally
  DB<3> 
KBCdbiUtil::CODE(0x84673b4)(/prod/datatech/inferno/bin/KBCdbiUtil.pm:144):
144:	                                    if ($_[0] == 0) {
  DB<3> 
KBCdbiUtil::CODE(0x84673b4)(/prod/datatech/inferno/bin/KBCdbiUtil.pm:149):
149:	                                    return 1; # handle other errors normally
  DB<3> 
KBCdbiUtil::CODE(0x84673b4)(/prod/datatech/inferno/bin/KBCdbiUtil.pm:144):
144:	                                    if ($_[0] == 0) {

in other words 's' showed just these two lines of code repeating
over and over.  Perhaps I have hit a bug in perl, who knows.

DBI-1.40, DBD::Sybase-1.02.6, perl-5.8.0 on Red Hat 8.

-- 
Ed Avis