in reply to DBD problem

Hello Umdurman,

You call $Dbh = DBI->connect() before the while loop and $Dbh->disconnect after the loop terminates. But within the loop you call UpdateDb() which itself calls $Dbh = DBI->connect (again!) and then calls $Dbh->disconnect before returning. So the next call to $Sth->fetchrow_array in the while loop condition occurs with the db disconnected, resulting in the error message you are seeing.

This is an excellent illustration of the problem with global variables: action at a distance, making it difficult to debug. If you pass the $Dbh variable into sub UpdateDb explicitly, you will easily see that the calls to connect and disconnect within sub UpdateDb are unnecessary, as the db connection is already open, and must remain so when the subroutine returns.

Hope that helps,

Athanasius <°(((><contra mundum Iustus alius egestas vitae, eros Piratica,

Replies are listed 'Best First'.
Re^2: DBD problem
by Umdurman (Acolyte) on Jan 16, 2017 at 14:56 UTC
    Hey Athanasius, thank you, I was expecting such a problem. I tried to disable the connect and the disconnect in the sub before I looked for help here but that didnt do the job. I should be able to write to the db from withinn the while loop. I know I did this before... Could you give a hint please? Kind regards, Ton
      I tried to disable the connect and the disconnect in the sub before I looked for help here but that didnt do the job.

      Looking again at sub UpdateDb, I see you have the same problem with the $Sth variable: you call prepare and finish on it, so, when the subroutine returns, the call to $Sth->fetchrow_array in the while loop is no longer valid. Here’s a suggested rewrite of the subroutine (untested):

      # Update the selected Database record sub UpdateDb { my ($dbh, $upd_query) = @_; # $dbh is already connecte +d my $sth = $dbh->prepare($upd_query); # create $sth as a local, +lexically-scoped variable unrelated to the global $Sth $sth->execute() or $ErrNum = '3007'; $ErrMess = $DBI::errstr; $sth->finish(); print "HIER $ErrMess<br>" }

      You would call it like this: UpdateDb($Dbh, $UpdQuery);

      This is still far from ideal, as $ErrNum and $ErrMess are still being used as (effectively) global variables1. But localising $sth, by declaring it within the scope of the UpdateDb subroutine, will allow the call to $Sth->fetchrow_array in the while loop condition to work correctly.

      1Strictly speaking, the only true global variables in Perl are the built-ins, such as $| and $/. Variables either declared with our or used without being declared (in the absence of use strict 'vars';) are package globals. Variables declared with my are lexicals, meaning they have lexical scope. But when I talk of “(effectively) global variables” I’m referring to the “action at a distance” problem which arises when a variable is used across so wide a scope that it becomes difficult to manage.

      Hope that helps,

      Athanasius <°(((><contra mundum Iustus alius egestas vitae, eros Piratica,

        even better would be using different (so called "self documenting") names for the different statement handles, e.g. in UpdateDb
        my $update = $dbh->prepare($upd_query); $update->execute ...
        and in the main routine
        my $select = $Dbh->prepare("SELECT " ...); $select->execute ...
        Athanasius, thank you, just making the Dbh and Sth local made the difference. it works;-) Kind regards, Ton