http://www.perlmonks.org?node_id=757542

elf_firein has asked for the wisdom of the Perl Monks concerning the following question:

I have faced a major problem with DBI package when I am using perl5.8.4 in solaris 10 box.
use strict; use DBI; use Carp; sub DB_xxx { my ($dbUser, $dbPass, $db, $autoCommit) = @_; my $dbh; # logon to DB unless( $dbh = DBI->connect('dbi:Oracle:' . ($$db || ''), $$dbUser +, $$dbPass, {AutoCommit => $$autoCommit}) ) { croak "Error connecting to database $DBI::errstr \n"; } return $dbh; } my $user = "xxxx"; my $pass = "xxxx"; my $db ; my $autocommit = 0; my $dbh = DB_xxx(\$user, \$pass, \$db, \$autocommit); #problem starts here #if we so any unix command call or closing an file/pipe #handle after +that such as using system() or backtricks it #returns -1 in $! & $? c +onatins "no child process" #example `gzip -cd filename`; # or system("gzip -cd filename"); #or open ($fh, "gzip -cd filename|"); #or close ($fh); print "$?:$!\n";

after a dbi subroutine call any system call as example given above returning the message "no child process for $? & $! conatins "-1" as status. But if we pass value for variable $db in code such as:

my $user = "xxx"; my $pass = "xxx"; my $db = "abcd"; #that is valid hostname for oracle.

the program is running wirhout throwing any warning or $! as 0. I need to implement similar way by which sqlplus utility connect to database in local box only with user/password.

what I want through DBI is:

sqlplus xxx/xxx

what i don't want through DBI is

sqlplus xxx/xxx@abcd

Is it an existing bug in DBI? Is there any solution for this problem.

I have updated the text of message

Replies are listed 'Best First'.
Re: The bug in DBI package
by ikegami (Patriarch) on Apr 15, 2009 at 05:36 UTC

    after a dbi subroutine call any system call as example given above returning the message "no child process for $? & $! conatins "-1" as status.

    So? It makes no sense to check $! unconditionally. As documented, $! is meaningless except after a system call that resulted in an error. You haven't been told there was an error by a system call. You haven't even made any system calls.

    As for $?, if you want gzip's status, you should save $?'s value closer to the backticks.

    Sorry, but $! and $? changing is not a bug.

    By the way, I'm confused by your use of references to pass simple strings. It's making the code needlessly complex and error-prone. To add to the confusion, you use the same var names for the references as the actual vars!

      Hi, I have updated the posted message.in my actual code I have tested the $! & $? exactly after the backtricks call. You can check the post now.It is corrected exactly as per my original code.
Re: The bug in DBI package
by cdarke (Prior) on Apr 15, 2009 at 08:30 UTC
    In the list of "things to try", I wonder why no one has mentioned SIGCHLD? It is possible that the DBI code is changing the signal mask to ignore that signal (no idea why it might do that). After the connect, try:
    $SIG{CHLD}='DEFAULT';
    I don't have Oracle to try myself.

      The Oracle client libraries alter the disposition of SIGCHLD. You can put SIGCHLD back to default behavior as you have said but a) you must do this after DBI connect and b) it may affect the Oracle client libraries although I have not seen any issues myself.

      Thanks...........Drake....I has worked out..........I was also lookin for exact value of $SIG{CHLD} to replace the "IGNORE". You suggestion really worked out!!!!!!!!!!!!........
        Darke: Drake is some kinda duck.
        Glad it worked.
Re: The bug in DBI package
by ig (Vicar) on Apr 15, 2009 at 07:01 UTC
      Yep. Instead of checking the $? or $! I played a trick.This code sinppet inside a function.
      my $status = `gzip -cd filename 2>&1`; print "The status is:$status\n"; if (!($status eq '')) { print " ERROR : $file is corrupt. \n"; return 0; }

      It works!!! But do you think this is the right way to tackle?

      But problem is when I am trying to close a pipe handle. I did somethig like that:

      use IO::Pipe; my @command =qw(gzip -cd filename); my $fh = new IO::Pipe; $fh->reader(@command)|| warn "ERROR : Can't read : $!"; while(<$fh>) { #doing some long job here;such as $variable = readline $fh; . . . } undef $fh;#close $fh if ($? != 0) { print "problem in undef or closing:$? with status:$!"; }

      I am getting the last print message as error as:problem in undef or closing:-1 with status:no child process". My question is that is it required to check the $? or $! here? If we ignore it will system dump core?

        It works!!! But do you think this is the right way to tackle?

        I don't think this is a good solution to your problem. While many unix commands produce no output when they run successfully there are other reasons why you may recieve no output on STDOUT. For example, the command may fail with an error message written to STDERR and nothing written to STDOUT.

        The implementation of system() and backticks (``) are system dependent. For example, the implementation on Windows systems is quite different from that on *nix systems. Thus it is difficult to generalize about them.

        On many (most??, all??, I don't know) *nix systems both system() and backticks (``) use the wait functions to wait for the child process to terminate and obtain its exit status. If the child process has been automatically reaped, as will happen on many systems if SIG{CHLD} is set to 'IGNORE' then wait cannot return the exit status of the child process and, therefore, neither can system() or backticks (the latter by way of $?).

        Presuming that your problem occurs because $SIG{CHLD} is set to 'IGNORE' (the other posts in this thread suggest this is the case) then you have a dilemma - you can't easily determine the exit status of child processes without changing $SIG{CHLD} back to 'DEFAULT' but you can't change $SIG{CHLD] back to default without risk of accumulating zombie child processes.

        I would be skeptical of any code that creates child processes without checking that they complete successfully and handling any errors that occur. While it is possible to do so without using wait to obtain their exit status (e.g. some other IPC signaling mechanism may be used to reliably determine relevant status) doing so is not trivial and I wouldn't trust that it was being done without some evidence. Therefore, I would first investigate to determine what is setting $SIG{CHLD] to 'IGNORE' and rectify any deficiencies there.

        If you can't determine or "fix" the code that is setting $SIG{CHLD} to 'IGNORE' but you want to spawn other processes and obtain their exit status you have several choices:

        You could simply set $SIG{CHLD} to 'DEFAULT' and risk zombie processes accumulating until your program terminates. If only a few child processes are created, this may be fine.

        Alternatively, you could temporarily set $SIG{CHLD} back to 'DEFAULT' only when needed and reap any zombies that accumulated after restoring $SIG{CHLD} to 'IGNORE'. For example:

        use POSIX ":sys_wait_h"; # do whatever that sets $SIG{CHLD} to 'IGNORE' { local $SIG{CHLD} = 'DEFAULT'; # do something interesting here, for example... my $return = system("gzip somefile"); if($return != 0) { # handle exception here } } # reap any zombies that accumulated while # $SIG{CHLD} was set to 'DEFAULT' while ( (my $pid = waitpid(-1, WNOHANG)) > 0 ) { print "reaped $pid with status $?\n"; }

        In passing, it is easy to see how $SIG{CHLD} is set:

        use Data::Dumper; print Dumper(\%SIG); $SIG{CHLD} = 'IGNORE'; print Dumper(\%SIG);
        My question is that is it required to check the $? or $! here? If we ignore it will system dump core?

        I would check exit status after running a system command via system or backticks. For the former I would use the return value (though I believe $? provides the same value) and for backticks I would use $?. If system returns -1 I might check $! because system says:

        Return value of -1 indicates a failure to start the program or an error of the wait(2) system call (inspect $! for the reason).

        For backticks I can find no documentation that says $! indicates the reason for failure if $? is -1, so while I might check it I would be skeptical that it was meaningful.

        The system shouldn't dump core just because a system command failed to complete successfully, regardless of whether you check the exit status. But you probably should handle the error if the command you tried to execute failed for some reason, so you should check the exit status.

Re: The bug in DBI package
by Anonymous Monk on Apr 15, 2009 at 05:08 UTC
    sub DB_xxx ...

    my $dbh = DB_Connect

    ??