php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #72503 [ODBC Cursor Library] Result set was not generated by a SELECT statement, SQL s
Submitted: 2016-06-27 11:59 UTC Modified: 2016-07-06 13:02 UTC
From: jgeert1 at its dot jnj dot com Assigned:
Status: Not a bug Package: ODBC related
PHP Version: 5.6.23 OS: Windows Server 2008 R2
Private report: No CVE-ID: None
Welcome back! If you're the original bug submitter, here's where you can edit the bug or add additional notes.
If this is not your bug, you can add a comment by following this link.
If this is your bug, but you forgot your password, you can retrieve your password here.
Password:
Status:
Package:
Bug Type:
Summary:
From: jgeert1 at its dot jnj dot com
New email:
PHP Version: OS:

 

 [2016-06-27 11:59 UTC] jgeert1 at its dot jnj dot com
Description:
------------
I'm currently running PHP 5.5.12 and use the odbc functions to retrieving data from MS SQL Server databases. I've a query which runs fine (produces the expected result)when using this PHP version.

However I would like to upgrade PHP from 5.5.12 to 5.6.23. Installation went smoothly and all existing code seems to run fine on it except one db query, which now produces the error "[ODBC Cursor Library] Result set was not generated by a SELECT statement, SQL state SL004 in SQLGetData ...".

I've no idea what's causing it. It runs fine when using the old version of PHP, but with the latest one, it always fails. I also tried PHP 7.0.8, but it also produces the same error.

Test script:
---------------
$odbcmgt_dsn = "Driver={SQL Server};Server=MYSERVER;Database=MYDATABASE;";
$dbhandle = odbc_connect($odbcmgt_dsn,$odbcmgt_user,$odbcmgt_pwd,SQL_CUR_USE_ODBC);

$result = odbc_exec($dbhandle, $sql);
while( $row = odbc_fetch_array($result)) {

// data procession code

}
odbc_free_result($result);
odbc_close($dbhandle);

Expected result:
----------------
+/- 6000 rows of data

Actual result:
--------------
Error message: Warning: odbc_fetch_array(): SQL error: [Microsoft][ODBC Cursor Library] Result set was not generated by a SELECT statement, SQL state SL004 in SQLGetData in ....




Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2016-06-27 12:11 UTC] jgeert1 at its dot jnj dot com
ODBC Traces can be found here: 
https://gist.github.com/anonymous/f91784cedbe6a6eb58e88b814deef5c6
 [2016-07-01 11:22 UTC] ab@php.net
-Status: Open +Status: Feedback
 [2016-07-01 11:22 UTC] ab@php.net
Please provide the full reproduce way with table creaton, data, and all the necessary things.

Thanks.
 [2016-07-04 13:47 UTC] jgeert1 at its dot jnj dot com
-Status: Feedback +Status: Open
 [2016-07-04 13:47 UTC] jgeert1 at its dot jnj dot com
Meanwhile after doing some additional testing, I noticed that I only have this error when a table has columns defined as "ntext" or "varchar(max)" or "nvarchar(max)" fields. If I remove these columns from my sql statement, the query runs fine again.

When I create a dummy table like this:
  CREATE TABLE [dbo].[jg_test](
	[id] [int] IDENTITY(1,1) NOT NULL,
	[test1] [int] NULL,
	[test2] [varchar](50) NULL,
	[test3] [varchar](max) NULL,
	[test4] [nvarchar](max) NULL,
	[test5] [int] NULL
  ) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]

just add some dummy data to it (in my case the varchar fields only contain "test").

use this code to access it:

$user = "username";
$pwd  = "password";
$dsn  = "Driver={SQL Server Native Client 11.0};Server=myserver;Database=mydb;MARS_Connection=Yes;";
ini_set ('odbc.default_cursortype',SQL_CURSOR_FORWARD_ONLY);	
$dbhandle = odbc_connect($dsn,$user,$pwd,SQL_CUR_USE_DRIVER);

$result = odbc_exec($dbhandle, "select * from dbo.jg_test");
while( $row = odbc_fetch_array($result)) {
  var_dump($row);
}
odbc_free_result($dbhandle);
odbc_close($dbhandle);

This will result in the error message:
Warning: odbc_fetch_array(): SQL error: [Microsoft][SQL Server Native Client 11.0]Invalid Descriptor Index, SQL state S1002 in SQLGetData 

I know it's a different error message then the one posted before, but I'm sure that these are related to each other.
 [2016-07-06 09:55 UTC] ab@php.net
-Status: Open +Status: Not a bug
 [2016-07-06 09:55 UTC] ab@php.net
Sorry, but your problem does not imply a bug in PHP itself.  For a
list of more appropriate places to ask for help using PHP, please
visit http://www.php.net/support.php as this bug system is not the
appropriate forum for asking support questions.  Due to the volume
of reports we can not explain in detail here why your report is not
a bug.  The support channels will be able to provide an explanation
for you.

Thank you for your interest in PHP.

Thanks for the additional info. In this case, it is an inappropriate configuration. Forward-only cursors shouldn't be used, if the rowset size >= 1. It is documented here https://msdn.microsoft.com/en-us/library/ms715441(v=vs.85).aspx 

Thanks.
 [2016-07-06 10:00 UTC] ab@php.net
Typo - "if the row set size > 1".

Thanks.
 [2016-07-06 10:30 UTC] jgeert1 at its dot jnj dot com
I do not agree on that one:
Please read: https://technet.microsoft.com/en-us/library/ms130807(v=sql.110).aspx

SQL_CURSOR_FORWARD_ONLY is the default setting for the SQL Server Native Client ODBC driver.
 [2016-07-06 12:34 UTC] ab@php.net
Yep, you're right, that's default. However it doesn't change anything on the API restrictions (see my previous link). Data can be fetched different ways, the most convenient for PHP is by utilizing SQLGetData(). More about data fetching https://msdn.microsoft.com/en-us/library/ms131269.aspx .

This does condition the static cursor as default in PHP. I currently don't see a way to move away from SQLGetdata() without a significant rewrite of ext/odbc. But also i'd doubt the real gain it could might bring. Clear, column or even row size binding might be faster, but there is a variety of use cases that could easily negate this advantage. And given it's currently an API restriction, classified as a non bug for PHP.

Thanks.
 [2016-07-06 13:02 UTC] jgeert1 at its dot jnj dot com
I still don't get it completely. When I use the method as described below, I can retrieve all records that I've selected as long as it doesn't contain any column that's defined as varchar(max) or nvarchar(max).  If your statement is true, I also should also have problems when retrieving the other type of data. Which is not the case at all, these are retrieved fine.

I probably could use some guidance here. I've did a lot of performance tests using all types of cursors, but I'm getting stuck with most of them.

If I'm using the default cursor (static), and use SQL_CUR_USE_DRIVER, the retrieval of the data is slow (when I use SQL_CURSOR_FORWARD_ONLY or SQL_CURSOR_KEYSET_DRIVEN, the performance is more than 100 times better).

So I also did a test with SQL_CUR_USE_ODBC and a static cursor. Performance was ok (also fast), but I noticed that I did not receive all rows, the data was cut off somewhere and no errors were shown. If I increase the value of "defaultlrl" to a value of 8192, I even get less rows, reducing the value resulted in more rows returned. The problem was that I needed all the rows, so this was not an option for me.

The best results were achieved by using SQL_CUR_USE DRIVER and using SQL_CURSOR_FORWARD_ONLY and SQL_CURSOR_KEYSET_DRIVER. Both provided me with all rows (changing defaultlrl had no impact - all rows were returned), except that I'm getting errors when I try to retrieve rows that have varchar(max) or nvarchar(max) type of columns.

So now I'm stuck ....
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Fri Apr 19 14:01:30 2024 UTC