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

Hi. I am trying to retreive all the tables on a MS SQL Server via a DBI to ODBC call from a CGI script. The web server user doesn't have permission for some databases. That's fine... I just want those databases skipped.

The code I have below runs fine, except that DBD::ODBC spits ugly warnings like this onto the web page:
DBD::ODBC::db selectcol_arrayref failed: [Microsoft][ODBC SQL Server D +river][SQL Server]Server user 'webuser' is not a valid user in databa +se 'xmodel'.
How can I keep DBD silent about these problems? Thanks! nop
sub getalltables { my $dbh_g = &getcxn_dbi_goldmine; my @dbs = @{$dbh_g->selectcol_arrayref(q{ select name from master..sysdatabases(nolock)})}; if ($dbh_g->err) {die "bad get dbs: ", $dbh_g->errstr;} my @alltbls; foreach my $db (@dbs) { my $sql = qq{select name from $db..sysobjects(nolock) where type=' +U'}; my $ref; eval { $ref = $dbh_g->selectcol_arrayref($sql) }; if ($ref) { my @tbls = @{$ref}; foreach my $tbl (@tbls) { push(@alltbls, $db . ".." . $tbl); } } } return @alltbls; }

Replies are listed 'Best First'.
(Ovid - debugging DBI) RE: Silencing the grumbling from DBD::ODBC
by Ovid (Cardinal) on Sep 28, 2000 at 19:27 UTC
    If you are using DBI, you can insert the following statement for debugging:
    DBI->trace(3, "trace.txt");
    trace.txt is a file that is opened in append mode for DBI to write to. The number is the level of trace you desire:
    0 - Trace disabled. 1 - Trace DBI method calls returning with results or errors. 2 - Trace method entry with parameters and returning with results. 3 - As above, adding some high-level information from the driver and + some internal information from the DBI. 4 - As above, adding more detailed information from the driver. Also + includes DBI mutex information when using threaded Perl. 5 - As above but with more and more obscure information.
    I personally find that trace level 3 gives me all of the information that I need. It produces a lot of output that can take a while to wade through, but I almost always find "tough to track down" errors that way.

    Cheers,
    Ovid

    Join the Perlmonks Setiathome Group or just go the the link and check out our stats.

PrintError (boolean, inherited)
by nop (Hermit) on Sep 28, 2000 at 20:15 UTC
    Found the problem. Solved. Thanks, all.
    PrintError (boolean, inherited) This attribute can be used to force errors to generate warnings (using + warn) in addition to returning error codes in the normal way. When s +et ``on'', any method which results in an error occuring will cause t +he DBI to effectively do a warn("$class $method failed: $DBI::errstr" +) where $class is the driver class and $method is the name of the met +hod which failed. E.g., DBD::Oracle::db prepare failed: ... error text here ... By default, DBI->connect sets PrintError ``on''. If desired, the warnings can be caught and processed using a $SIG{__WA +RN__} handler or modules like CGI::Carp and CGI::ErrorWrap.
RE: Silencing the grumbling from DBD::ODBC
by little (Curate) on Sep 28, 2000 at 19:04 UTC
    Looks like you are trying to evaluate the query result:
    eval { $ref = $dbh_g->selectcol_arrayref($sql) };
    so better try
    eval("$ref = $dbh_g->selectcol_arrayref($sql)")
    and the eval will catch the error :-) if the query fails
    Have a nice day
    All decision is left to your taste
      I think either version of eval is equivalent as far as error trapping is concerned.

      Regardless, the latter version would fail, since $sql and $dbh_g would be interpolated as the string were parsed, prior to sending the resulting argument to eval. The result would be bad Perl syntax and execution would fail. You could just put it in single-quotes instead, which would work, but you're still incurring the compilation overhead at run-time instead of putting it into a block, which is compiled along with the rest of the script.

Re: Silencing the grumbling from DBD::ODBC
by TheoPetersen (Priest) on Sep 28, 2000 at 19:05 UTC
    Does your CGI script explicitly send errors to the browser? I would think those messages would go to your error log, not stdout.

    ..Theo

      How do I ensure errors don't go to stdout? I think this is my problem. Or how do I ask DBI not to complain at all?

      Update:      $dbh->{PrintError} = 0; solves the problem, see below.

        Personally, I'd be less that thrilled at the idea of surpressing error output -- it might actually help the user to know that something is wrong.

        I've had some luck (it depends a little on what you want to do) with changing the 'execute or die' syntax to an 'execute or assign the error to a subroutine'.

        Your error subroutine could then distinguish between errors as a result of access levels vs. error as a result of the database itself... and act accordingly.

        Obviously, YMMV

Re: Silencing the grumbling from DBD::ODBC
by Fastolfe (Vicar) on Sep 28, 2000 at 19:23 UTC
    I would need to experiment a bit before I would know for sure, but if your eval were merely dying, I would expect the error to be in $@. Warnings, however, I'm not sure. Perhaps you should try trapping them with $SIG{__WARN__}?
    Note: Code samples are for conceptual use only and generally are not meant to be cut/pasted into a production application. Always 'use strict', have a thorough understanding of the code you use, and check the return values of functions and handle errors according to your needs. - Fastolfe
      right, I agree,
      but the assignement of the query result to the variable happens, before that variable gets evaluated. And he is not looking for the result of the eval as he would do by saying :
      $ref = eval{$dbh_g->selectcol_arrayref($sql)};
      ??
      Have a nice day
      All decision is left to your taste
        They are equivalent. Consider:
        $a = $b = 0; eval { $a = 3; }; $b = eval { 3; }; print "$a, $b\n"; # 3, 3
        Eval operates in the same context as any other code. The return from eval is the return value of whatever that eval did. The only difference is that eval blocks can't die; errors are stored in $@ and execution of the eval block stops.