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

Please help. I am trying to finish this code to access a database and all I am getting is an ODBC error saying that there is an invalid cursor at line 50. Here's the listing.
#!usr/perl/bin use CGI; use DBI; $q = new CGI; @data; $department_type_local = "1"; my ($dbh) = DBI->connect("DBI:ODBC:messagestore") or die "Couldn't con +nect to database"; my ($query) = $dbh->prepare('SELECT message_table.message_id, message_ +table.message_date, message_table.message_time,message_table.message_ +sender_name,message_table.message_to_name, message_table.department_i +d FROM department_table INNER JOIN message_table ON department_table. +department_id = message_table.department_id WHERE message_table.department_id = ?'); $query->execute($department_type) or die "Couldn't execute statement"; if ($query->rows == 0){ my ($errormessage) = "No Records Found...Please Select Again"; print "Content-type:text/html\n\n"; ... } else { while (@data = $dbh->selectrow_array($query)){ my ($message_id) = $data[1]; my ($message_date) = $data[2]; my ($message_time) = $data[3]; my ($message_sender_name) = $data[4]; my ($message_to_name) = $data[5]; my ($department_id) = $data[6]; print "$message_id $message_date $message_time $message_sender_n +ame $message_to_name\n"; } print "Content-type:text/html\n\n" ... } $query->finish; $dbh->disconnect;
If you can help, I would be very grateful. Cheers Grax.

Replies are listed 'Best First'.
Re: More DBI Problems!!!
by repson (Chaplain) on Apr 23, 2001 at 14:47 UTC
    It would help if you told us which line 50 was in the future.

    However, I think the problem is in
    $dbh->selectrow_array($query)

    The method selectrow_array is for performing a full prepare, execute and returning the array. The parameter is an sql string, not a query object.

    What you probably meant was:
    $query->fetchrow_array

    Which returns a single row of the prepared and executed query it is call on.

      I think repson must be right that you meant to use $query->fetchrow_array instead of $dbh->selectrow_array($query).

      However, the $dbh->select... methods can take an already prepared statement handle as the first argument. This allows you to prepare the statement once ahead of time, and then execute it with select... many times. For example:

      my $sth = $dbh->prepare(<<EndOfSQL); SELECT name FROM item WHERE id = ? EndOfSQL while (<>) { chomp; if (($name) = $dbh->selectrow_array($sth, {}, $_)) { print "$_ => $name\n"; } else { print "$_ not found\n"; } }
(ar0n) Re: More DBI Problems!!!
by ar0n (Priest) on Apr 23, 2001 at 15:00 UTC
    In addition to what repson said, you may want switch on RaiseError:
    my ($dbh) = DBI->connect("DBI:ODBC:messagestore", "user", "password", +{RaiseError => 1});
    This allows for a more extensive amount of information when dying than what you have now.

    Furthermore,
    my ($message_id) = $data[1]; my ($message_date) = $data[2]; my ($message_time) = $data[3]; my ($message_sender_name) = $data[4]; my ($message_to_name) = $data[5]; my ($department_id) = $data[6];
    is better written as:
    my (undef, $message_id, $message_date, $message_time, $message_sender_ +name, $message_to_name, $department_id) = @data;
    At least, that's my opinion :-)

    ar0n ]

Re: More DBI Problems!!!
by lachoy (Parson) on Apr 23, 2001 at 15:40 UTC

    First, the first line should probably be #!/usr/bin/perl. Did you type this in or copy-and-paste? If you just typed it in, subtle errors can creep in that make it difficult for folks to help you. (Been there, felt that pain.)

    Second, this code doesn't survive a perl -c check if you put use strict; before the use CGI; line, saying that Global symbol "$department_type" requires explicit package name where you use $department_type. Did you mean to use $department_type_local?

    Third, the method call $query->rows likely isn't doing what you think it's doing. Check what the DBI docs have to say about it:

    `rows' $rv = $sth->rows; Returns the number of rows affected by the last row affecting command, or -1 if the number of rows is not known or not available. Generally, you can only rely on a row count after a *non*- `SELECT' `execute' (for some specific operations like `UPDATE' and `DELETE'), or after fetching all the rows of a `SELECT' statement. For `SELECT' statements, it is generally not possible to know how many rows will be returned except by fetching them all. Some drivers will return the number of rows the application has fetched so far, but others may return -1 until all rows have been fetched. So use of the `rows' method or `$DBI::rows' with `SELECT' statements is not recommended.

    So you probably want to try to scroll through your results before bailing.

    Fourth, as other folks have mentioned, using RaiseError (to set: $dbh->{RaiseError} = 1 before you prepare the $query statement handle) will help immensely to pinpoint where errors are occurring.

    Fifth, your while statement should read:

     while ( my @data = $query->selectrow_array() )

    since you've already prepared the $query handle, you might as well use it! :-)

    Finally, does your SQL statement work? That is, have you tested it out with your database's query tool and seen that it works ok?

    Hope this helps!

    Chris
    M-x auto-bs-mode

(jeffa) Re: More DBI Problems!!!
by jeffa (Bishop) on Apr 23, 2001 at 17:10 UTC
    Since no one else has said anything about it, you don't have 'slam' all of your SQL code together, you can format it nicely:
    $dbh->prepare(' SELECT message_table.message_id, message_table.message_date, message_table.message_time,message_table.message_sender_name, message_table.message_to_name, message_table.department_id FROM department_table INNER JOIN message_table ON department_table.department_id = message_table.department_id WHERE message_table.department_id = ? ');
    much easier to find errors that way - but as said previously, the SQL is not the problem, it was your method of getting the data. I hope you find this helpful in the future, none the less.

    Jeff

    R-R-R--R-R-R--R-R-R--R-R-R--R-R-R--
    L-L--L-L--L-L--L-L--L-L--L-L--L-L--