-
Notifications
You must be signed in to change notification settings - Fork 2.5k
Limit/offset doesn't work properly when using parameters and SQL Server drivers #3198
Limit/offset doesn't work properly when using parameters and SQL Server drivers #3198
Conversation
have you tried ? :
|
That doesn't work either, not for SQL server driver or PDO driver. First reason is the absence of an order clause, which seems to be mandatory, otherwise the query does something like this:
That causes the following error to be thrown:
If I add an order(), then the PDO driver goes back to throwing the LIMIT error (since LIMIT doesn't exist in SQL server) and the SQL Server driver doesn't return the proper results. If I add an offset(), then is works fine with the SQL Server driver, but only because there are no WHERE clause parameters in your example. If I add a where clause with a parameter in it, I don't get the proper results, as explained in my first post. |
Looking further into this, this seems related to the bindParametersFromContainer() function in Zend\Db\Adapter\Driver\Sqlsrv\Statement. At the bottom, there's some code commented out that says "@todo bind errata". Looking at the ParameterContainer class, if I'm understanding the concept of errata properly, seems like this is meant to keep track of the order parameters should be in so that it can be corrected at the time you bind them to the query. Since this is not being done here, things break. This code is all rather confusing to me at this point, but I'm gonna dig in and see if I can come up with a solution based on what other drivers do. |
Looks like I may have been off on the errata based on what I see in other drivers, but I did manage to change bindParametersFromContainer() to get this to work for the SQL Server driver (though I'd love for things to work with PDO since I'd like to be able to use named parameters in queries). Here's what I did, can't say it's a robust fix since it's not extensively tested, but I guess it could help somebody else:
|
I have the same problem. I am using the PDO driver to connect to Microsoft SQL-Server. This is my select:
An the dump of the PDOStatement is like this: SELECT * FROM ( SELECT [tbl_pakete].*, ROW_NUMBER() OVER (ORDER BY [PaketID] ASC) AS [__ZEND_ROW_NUMBER] FROM [tbl_cug_pakete] WHERE [CustomerID] = :where1 ) AS [ZEND_SQL_SERVER_LIMIT_OFFSET_EMULATION] WHERE [ZEND_SQL_SERVER_LIMIT_OFFSET_EMULATION].[__ZEND_ROW_NUMBER] BETWEEN ?+1 AND ?+? After this i get the following error: SQLSTATE[HY093]: Invalid parameter number: mixed named and positional parameters @tm8747a : The problem with "ROW_NUMBER() OVER (SELECT 1)" you can solve by adding an "order" to your select. |
@frank-mueller Yeah, I'd figured out the ROW_NUMBER() issue. I'm surprised that you're getting that SQL with the PDO driver. I'm pretty sure when I used the PDO driver I was getting a query with LIMIT in it, not the query for SQL Server that you're getting. But maybe I messed up somewhere, will have to try it again. Just to make sure, what version are you running? |
I created pull request about this problem. Issue #3264 |
Yeah, I see the problem, it appears that if you don't send a value with the original where(), then the placeholder is not created inside the ParameterContainer. This is why it appears that the LIMIT and OFFSET parameters are coming in before the where(). I think the answer to this is to ensure that when using the where() with a ?, that the ? is counted and if no value is provided, a placeholder is still created. |
Just downloaded the latest code just to see if I was missing something for the PDO driver, but looks like the same error still occurs. @frank-mueller I'd be curious to know what you are running because when I try running a statement similar to yours with the PDO driver I get something like this:
In other words, it's not using the LIMIT/OFFSET style for SQL Server. Maybe I'm the one doing something wrong? I have my driver setup as follows:
Anything wrong here? |
In your code above, try this: $select = new \Zend\Db\Sql\Select();
$select->from('mytable')
->where(array('aField = ?' => array(null))
->order('myfield')
->limit(5)
->offset(0); That should work for the current codebase. To put it another way, Zend\Db\Sql\Select doesn't know from where('something = ?') that you're trying to do a placeholder b/c you did not pass in a set of parameters that it could use to know how many placeholder your expression string had it in. Since Zend\Db\Sql doesn't do any kind of parsing of your where string, it can't know how many you have in there. Either way, I agree, this is not an ideal situation, and I am trying to get to the bottom of it with regards to what we should do when you have a situation where you want to provide parameters for the first time at execution time. |
Also note, the Sqlsrv driver for PDO is currently not supported. |
This is unfortunately a step backwards. With ZF1 Sqlsrv driver for PDO was still supported. And windows-based Sqlsrv support is not an option for me. |
Good to know. May need to look at another framework, not being able to use named parameters may end up being a deal-breaker for me. Thanks for the clarification. Any specific technical reason why it's not supported? Are there features that it wouldn't be possible to get working? Or is it just a matter of manpower to get it done? If it's the latter, maybe I'll try to dig into it if I can find the time to make it work. |
Only reason it was not supported is because at the time of the writing of the SQL Server driver, the PDO version was not available yet. I will try to get this in for 2.1. |
In version 2.1 MSSQL PDO is not supported yet. Do you see the chance that this will change soon? This would be fine. |
I wanted to, but I had some problems with my integration testing suite and Sql Server, so I ran out of time. Basically PDO Mssql does't support setting INSERT IDENTITY OFF. I need to get to the bottom of that. |
@ralphschindler Do you think, that version 2.2 includes the PDO support for MS SQL server? This would be very nice :-) |
I sent a pull request to fix all this: |
Limit/offset doesn't work properly when using parameters and SQL Server drivers
When using the native SQL Server driver, it seems that using limit and offset works fine with a query that has no parameters, but doesn't work with a query that has parameters. For example, the following will return the expected results:
Whereas the following won't:
I believe the reason has something to do with the order of the parameters getting messed up. To be more specific, it seems like when ParameterContainer calls getPositionalArray(), the offset/limit parameters come before the where parameters when it should actually be the opposite.
For the PDO SQL server, the problem is totally different. When trying to run the first case above, I get the following error:
That leads me to believe the ROW_NUMBER() function has not been implemented, not sure it's a bug or if it'll be unsupported for PDO, though I've searched and don't see anything saying that the drivers provided by Microsoft don't support it.
If I run the second case above, then I get the following error:
It does not throw this error if I change my where clause to use named parameters, but seems like I should be allowed to use positional or named parameters in my where clause as long as I stick to only one. Regardless, if I change to named parameters, I get the first error for syntax error near LIMIT.