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

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

Win32 AS-5.8.0 Multithread build 806 DBI(1.43)DBD::ODBC(1.07) MSSQL Server I get a invalid cursor state when I run any SQL with a PRINT statement at the beginning of any SQL statement.
DBD::ODBC::st execute failed: [Microsoft][ODBC SQL Server Driver]Inval +id cursor state (SQL-24000)(DB D: dbd_describe/SQLNumResultCols err=-1) at H:\progs\dbi_test.pl line +10.


Example code:
#c:/perl/bin/perl use DBI; my $dbh = DBI->connect( 'dbi:ODBC:TEST_DSN', '','', {RaiseError=> 1} ) +; my $sth = $dbh->prepare( "PRINT '...begin' select name = 'test' " ); my $rv = $sth->execute(); print "rv: $rv \n"; while ( my $hr = $sth->fetchrow_hashref ){ print $$hr{$_}, "\n" for ( keys %$hr ); print "Err: ", $dbh->errstr, "\n" if $dbh->errstr; }
If you move the PRINT statement AFTER the select statement, you don't get the error, but you also don't see the output of the print.
Does anyone know how to capture the output of the PRINT Statements? They seem to print on command line tools like ISQL and other programs like Embarccadaro. Is my SQL in bad form here or is this a problem I am not working correctly in DBI?
Thanks in advance!
JamesNC

Replies are listed 'Best First'.
Re: DBI Invalid Cursor State when PRINT statements are embedded in SQL
by pg (Canon) on Oct 18, 2004 at 18:23 UTC

    Don't think it is a problem with DBI, first of all DBI does nothing with your SQL statement.

    And this is not a standard SQL statement, if you say this is fine with Sybase, then it is a Sybase extention. And it more like sort of debug method Sybase added (not a core function to the database manipulation or definition).

    I would think it is way too normal for other databases not to recognize it.

      I agree.. I don't use this syntax, it is in a lot of store procs another guy wrote that I am trying to run from Perl.

      A DBA sent me this regarding MSSQL PRINT:
      The PRINT statement takes either one character or a Unicode string expression as a parameter. It returns the string as a message to the application. The message is returned as an informational error in ADO, OLE DB, and ODBC applications. SQLSTATE is set to 01000, the native error is set to 0, and the error message string is set to the character string specified in the PRINT statement. The string is returned to the message handler call-back function in DB-Library applications.

      How can I trap this error and continue? Would this be better as a new question at this point?
      James NC
        Your DBA is right. Here is the output from ODBC test. ODBC test seems to know that this is a partial success and returns the rowset as well the “error message”.
        PRINT '...begin' select * from foo.bar.mytable SQLExecDirect: In: hstmt = 0x00991FB8, szSqlStr = "", cbSqlStr = -3 Return: SQL_SUCCESS_WITH_INFO=1 stmt: szSqlState = "01000", *pfNativeError = 0, *pcbErrorMsg = 55, +*ColumnNumber = -1, *RowNumber = 1 MessageText = "[Microsoft][ODBC SQL Server Driver][SQL Server]...b +egin" Get Data All: -1 rows affected by INSERT/UPDATE/DELETE or other statement. "col1", "col2", "col3" 1, "row1", "row1" 2, "row2", "row2" 2 rows fetched from 3 columns.
        MS SQL Server help also mentions that you have to call SQLError right after statement is executed.

        The timing of calling SQLError is critical when output from PRINT or RAISERROR statements are included in a result set. The call to SQLError to retrieve the PRINT or RAISERROR output must be made immediately after the statement that receives SQL_ERROR or SQL_SUCCESS_WITH_INFO. This is straightforward when only a single SQL statement is executed, as in the examples above. In these cases, the call to SQLExecDirect or SQLExecute returns SQL_ERROR or SQL_SUCCESS_WITH_INFO and SQLError can then be called. It is less straightforward when coding loops to handle the output of a batch of SQL statements or when executing SQL Server stored procedures.

Re: DBI Invalid Cursor State when PRINT statements are embedded in SQL
by Grygonos (Chaplain) on Oct 18, 2004 at 18:05 UTC

    I have never seen this syntax, and a quick look through the DBI book doesn't yield any likening to this syntax.

    You really should just fetch the rows (individually or all at once) and then loop through and print them out if you're wantin to output the contents of a select statement.

    P.S. - I have been known to be wrong many many times.

    edit: popped open my sql server docs and found that it's a T-SQL function. My understanding has been that you can use T-SQL via ODBC, but I don't quite think you need to use it here. This may be one function that doesn't work within DBI::ODBC due to what state the cursor needs to be in for the T-SQL command to work.

    P.P.S. Again ... I have been known to be very wrong.
      Thanks for the help. The syntax is valid in Sybase too. And I just verified that Sybase doesn't complain if it is at the begining, or anywhere else but nothing gets printed. It must act like a "GO" in that it never sent to the interpreter ever, but MSSQL doesn't like it.
Re: DBI Invalid Cursor State when PRINT statements are embedded in SQL
by JamesNC (Chaplain) on Oct 19, 2004 at 17:29 UTC
    Here is the Solution:
    Martin Evans on the dbi-user mailing list was able to finally find the source of this error, here is the text of his reply:

    I analysed your log and did the same thing in ODBCTest which used to come with MDAC and it fails in the same way: SQLPrepare(print 's' select count(*) from table print 'e') SQLNumResultCols() returns SQL_ERROR and invalid cursor state. so, I'm afraid, there is no bug in DBD::ODBC and the problem is in the MS SQL Server driver. Interestingly, our ODBC-ODBC Bridge makes you code almost work because it inserts a call to SQLNumParams between the SQLPrepare and the SQLNumResultCols and that puts the MS SQL Server Driver into a different state. I say "almost" because it does appear to hightlight another bug in the MS SQL Server driver later on where SQLMoreResults returns SQL_NO_DATA but a later call to SQLNumResultCols returns 1 column and this persuades DBD::ODBC there is a column and it fails on a call to SQLDescribeCol (because SQLNumResultCols lied and there is no result-set). Your only choice is to take the prints out.

    I ended up building DBI 1.45 and DBD::ODBC 1.11 on my machine.
    I was still able to achieve the desired result by using a suggestion our DBA made of substituting a SELECT everywhere there is a PRINT and that seems to work nicely. For statements that return multiple result sets I ended up using the following:

    #!C:/perl/bin/perl -w #DBI 1.45 #DBD::ODBC 1.11 use DBI; $dbh = DBI->connect("dbi:ODBC:tmpDB", 'username','password', { PrintError => 1, RaiseError =>0, LongReadLen => 65536, odbc_async_exec => 1, odbc_err_handler => \&errSub } ); $command = qq/ select 'start' select name = 'dbi-user' select 'end' /; $sth = $dbh->prepare($command); die $DBI::errstr unless $sth; my $rc = $sth->execute(); do { my @row; while (@row = $sth->fetchrow_array()) { print join(",", @row), "\n"; } } while ($sth->{odbc_more_results}); $dbh->disconnect; sub errSub { my ($state, $msg) = @_; # Strip out all of the driver ID stuff $msg =~ s/^(\[[\w\s]*\])+//; my $err_text .= $msg."\n"; print "Err($state):",$err_text; }
    Thanks to all who responded.

    JamesNC