Details
-
Type:
Bug
-
Status:
Closed
-
Priority:
Major
-
Resolution: Fixed
-
Affects Version/s: 1.2.0-RC1
-
Fix Version/s: 1.2.2
-
Component/s: Connection
-
Labels:None
-
Environment:php 5.3.1,
Symfony 1.4.0-DEV
Doctrine 1.2.0-RC1
pdo_mssql (libdb)
Description
using a doctrine generated class's find method produced erroneous SQL such as:
SELECT TOP 1 [inner_tbl].[id] AS [b__id] FROM (SELECT TOP 1 [b].[id] AS [b__id], [b].[name] AS [b__name], [b].[alias] AS [b__alias], [b].[ip] AS [b__ip], [b].[operator_id] AS [b__operator_id], [b].[cell_id] AS [b__cell_id], [b].[latitude] AS [b__latitude], [b].[longtitude] AS [b__longtitude], [b].[community_read] AS [b__community_read], [b].[community_write] AS [b__community_write], [b].[last_found_at] AS [b__last_found_at], [b].[active] AS [b__active], [b].[type] AS [b__type], [b].[poll_mac_behind_sus] AS [b__poll_mac_behind_sus], [b].[created_at] AS [b__created_at] FROM [basestation] [b] WHERE ([b].[id] = '2')) AS [inner_tbl]
commenting out the following line (193) in' function modifyLimitQuery' for lib/Doctrine/Connection/Mssql.php
$query = preg_replace('/^'.$selectRegExp.'/i', $selectReplace . 'TOP ' . ($count + $offset) . ' ', $query);
//$query = 'SELECT TOP ' . $count . ' ' . $this->quoteIdentifier('inner_tbl') . '.' . $key_field . ' FROM (' . $query . ') AS ' . $this->quoteIdentifier('inner_tbl');
if ($orderby !== false) {
It appears to have worked. This method was part of jwage's commit for change set 6795 (http://trac.doctrine-project.org/changeset/6795/branches/1.2/lib/Doctrine/Connection/Mssql.php) so there must be a reason for this change. This is very preliminary. If the change works there is a considerable amount of refactoring that way be done. I will commit a proper patch once I am able to test exhaustively, at the moment this is a show stopper and I need to continue development.
-
- Mssql-Patch-20091218.php
- 18/Dec/09 9:09 PM
- 2 kB
- Michael Card
-
- Mssql-Patch-20091221.php
- 21/Dec/09 3:20 PM
- 2 kB
- Michael Card
-
- Mssql-Patch-20091222.php
- 22/Dec/09 3:41 PM
- 2 kB
- Michael Card
Issue Links
- duplicates
-
DC-318
Doctrine_Table::find(x) fails for odbc/mssql connection due to limit() clause
-
Activity
Michael,
It seems as though I first encountered the problem after I did an svn update. I can assume that it was changeset 6795 as the problem is created in lib/Doctrine/Connection/Mssql.php and the weeks before changeset 6795 the exact same code worked.
The dql does work very well. I don't really use find methods too often as I like to bring my models back with as few loads as possible and most of my models aren't flat enough to use a find.
I found the error mostly with the pages that were generated by symonfy as doctrine:generate-model generates lines such as : $this->forward404Unless($Basestation = Doctrine::getTable('Basestation')>find(array($request>getParameter('id'))), sprintf('Object Basestation does not exist (%s).', $request->getParameter('id'));
The problem is very obvious. The changeset removed the 'SELECT *' and tried to do a 'SELECT
{key}'. The {key}is referring to the raw column name but is selecting from a subquery that has already aliased the
{key} field so it comes back with an error. I imagine there's a reason for only selecting the {key}but I haven't encountered that yet. Once I have code that breaks with my change I will be able to implement a better fix.
For now it seems to be working.
Hey Trevor,
Commenting out the line like you did won't work when using both a limit and an offset, you have to have the inner and outer queries to have the limit and offset work correctly.
Regular dql does a "select ... from table where key in (limit suquery here)" for the limit subquery has to only return 1 field.
What did you mean by "The
{key} is referring to the raw column name but is selecting from a subquery that has already aliased the {key}field so it comes back with an error." Maybe I can work out some code that works in all situations.
Mike
Hi Micheal,
"Commenting out the line like you did won't work when using both a limit and an offset, you have to have the inner and outer queries to have the limit and offset work correctly."
– exactly.
I finally had need for a limit on Friday and had started working on a proper adjustment. If it is something that you might be able to do that would be fantastic.
"What did you mean by "The
{key} is referring to the raw column name but is selecting from a subquery that has already aliased the {key}field so it comes back with an error." Maybe I can work out some code that works in all situations."
If you look at the SQL that is in the first comment I appended you'll see:
'
SELECT TOP 1 [inner_tbl].[id] AS [b__id] FROM (SELECT TOP 1 [b].[id] AS [b__id], [b].[name] AS [b__name], ..................
'
Which will cause an error as the first statement "SELECT TOP [inner_tbl].[id] AS [b__id] FROM " tries to select [inner_tbl].[id] however [inner_tbl].[id] does not exist, it has been aliased to [inner_tbl].[[b__id] as per the SQL in the inner join.
I hope that is more clear.
I'm going to fumble around the code a little this morning and see if I can come up with something.
Thank you Michael.
Hi, I will put my comments to DC-318 here since it is a duplicate of this one.
the last patch of DC-318 gives this sql statement:
SELECT TOP 1 [inner_tbl].[b__id] FROM (SELECT TOP 1 [b].[id] AS [b__id], [b].[version] AS [b__version], [b].[name] AS [b__name], [b].[number] AS [b__number], [b].[title_nl] AS [b__title_nl], [b].[title_en] AS [b__title_en], [b].[published] AS [b__published] FROM [building] [b] WHERE ([b].[id] = ?)) AS [inner_tbl]
which is a correct sql statement if executed with sqlcmd.exe. But it still gives me the same exception as shown in the backtrace attached to DC-318.
But isn't it strange that just the id is return iso the complete record?? If I remove the limit(1) clause from the find function in Table.php it give this sql statement and works perfectly:
SELECT [b].[id] AS [b__id], [b].[version] AS [b__version], [b].[name] AS [b__name], [b].[number] AS [b__number], [b].[title_nl] AS [b__title_nl], [b].[title_en] AS [b__title_en], [b].[published] AS [b__published] FROM [building] [b] WHERE ([b].[id] = ?)
Its more complicated, I'll write a patch this weekend.
It needs to be broken out to use seperate functions for modifyLimitQuery and modifyLimitSubQuery, the one function is trying to handle two different things. For a simple dql statement the modifyLimitQuery needs to return all fields. In a complex dql query, it needs to return the key field only as it is used as part of the where statement in the overall query.
I'm attaching a patch Mssql-Patch-20091218.php. This should fix all the find problems and the pager problems.
Trevor and Aiso, can you test the patch before Jon applies it. I've tested it using regular dql querying, it needs to be tested using the find function and also using the pager. Two things to look for - does it work obviously, which means it fixed the field name error, and second, does it return all the fields, before it was only returning the id field.
Jon - To avoid tons of code duplicaton between modifyLimitQuery and modifyLimitSubQuery, I added a parameter to modifyLimitQuery, if this is no good, we can change it to just duplicate the code between the two functions.
Mike
Thanks Michael for the patch. I just tested it and it doesn't work. Still the same odbc exception when executing the sql statement. The exception goes like this:
SQLSTATE[22018]: Invalid character value for cast specification: 206 [Microsoft][SQL Native Client][SQL Server]Er is een conflict met het type operand ontstaan: text is incompatibel met int (SQLExecute[206] at ext\pdo_odbc\odbc_stmt.c:254)
the query that is finally produced by modifyLimitQuery() (so the one that fails) is:
SELECT * FROM (SELECT TOP 1 [inner_tbl].[b__id] FROM (SELECT TOP 1 [b].[id] AS [b__id], [b].[name] AS [b__name], [b].[published] AS [b__published] FROM [building] [b] WHERE ([b].[id] = ?)) AS [inner_tbl]) AS [outer_tbl]
Note that if I return the $query on line 194, just after the preg_replace, everything is fine. In that case the sql statement is (so basically the inner most select):
SELECT TOP 1 [b].[id] AS [b__id], [b].[name] AS [b__name], [b].[published] AS [b__published] FROM [building] [b] WHERE ([b].[id] = ?)
so, I have 2 questions:
- why not return this last (working) query in this case? Why bother with doing the 3 nested selects?
- I don't see how the nested queries can work in the first place since the second query selects only the id, iso the complete entry. I tried this : 'SELECT TOP 1 [b].[id] AS [b__id] FROM [building] [b] WHERE ([b].[id] = ?)' and although I do not get an exception I don't get the right record! But not very suprising to me since you return only an id.
Note that if I run the failing query (so the 3 nested selects) in SQL Server Manager I get the id without problems, so the statement itself is correct (although I do not think it is correct only to return the id). So maybe this is a problem in pdo_odbc only?
Hi Michael, I completely missed the rest of your last comment, sorry about that: so my questions are a bit awkward. I read also that in some cases it is necessary to use the nested selects.
To comment on your 2 things to look for: it does work in the sense that the field name error is solved, but wrt your second thing: maybe all fields are return in the end but I could not test this properly since the pdo_odbc will not tolerate the nested selects construction so it seems.
Note that I get the same exception when using only 2 selects like this:
SELECT * FROM (SELECT TOP 1 [b].[id] AS [b__id], [b].[name] AS [b__name], [b].[published] AS [b__published] FROM [building] [b] WHERE ([b].[id] = ?)) AS [outer_tbl]
I figured out that my app suffers from a very old bug in the SQL server client app. See http://bugs.php.net/bug.php?id=36561
It says it cannot handle bound params in a subquery! So I don't know how you fellows make this work??? It basically means that all this code is useless since it will never work for mssql until microsoft comes up with a solution!
I just upgraded from sql server 2005 express to 2008 express to see if that helped but it didn't. So this is a very disturbing bug that is in the code since 2006 and till this day is never solved....
So, are there any versions of mssql server that can handle these subqueries, I wonder? What do you guys use to make this work??? I think the conclusion is that pdo_odbc and doctrine will never work.
Hi Michael and Aiso,
I had ran into that problem with sub query casting integers as strings. That cost me about 4 hours. I had to go into the Query Analyzer to find that pdo_lib was encapsulating the integers in quotation marks (making them strings) even though the query debug window was showing them without encapsulation. Although it is a terrible solution I embedded the integers directly into the SQL. It was the only option and it worked good enough (for now).
I agree that mssql (using pdo_lib for connectivity) might be too limited. As well as the bug you've indicated pdo_lib also limits column names to 30 characters. These limitations are very, very frustrating.
In regards to the patch I'm still generating errors:
SQLSTATE[HY000]: General error: 207 General SQL Server error: Check messages from the SQL Server [207] (severity 16) [(null)]
With the following code:
45 $q = Doctrine::getTable( 'Radiusdat' )->createQuery( 'r' )
46 >where( 'r.username LIKE ?', $this>getUsername( ) )
47 ->orderBy( 'r.callstart DESC' )
48 ->limit( $limit );
The SQL generated looks like this:
SELECT *
FROM (SELECT TOP 5 [inner_tbl].[r__username]
FROM (SELECT TOP 5 [r].[username] AS [r__username]
, [r].[callstart] AS [r__callstart]
, [r].[callend] AS [r__callend]
, [r].[sessid] AS [r__sessid]
FROM [radiusdat] [r]
WHERE ([r].[username] LIKE '')
ORDER BY [r].[callstart] DESC) AS [inner_tbl]
ORDER BY [inner_tbl].[r__callstart] ASC) AS [outer_tbl]
ORDER BY [outer_tbl].[r__callstart] DESC
Running the query manually I get the following:
"Invalid column name 'r__callstart'"
If you look at the SQL you'll see that it is trying to ORDER BY [inner_tbl].[r__callstart] by [inner_tbl].[r__callstart] does not exist, only [inner_tbl].[r__username] exists.
Please let me know if I can test anything else.
Trevor - added a new patch, can you give this one a try. I think this should work in both situations now: modify limit queries and modify limit subqueries.
Hi Michael - Tried applying the patch : didn't work (tried applying it to the previously patched then I deleted the file, svn updated and tried applying it still didn't work) so I did it by hand. The results might be wrong because I messed up the application.
It is having a problem now in that it isn't aliasing the outside table, ie:
The application generates this code:
SELECT * FROM ( SELECT TOP 1 * FROM ( SELECT TOP 1 [a].[login_name] AS [a__login_name], [a].[last_login_at] AS [a__last_login_at], [a].[display_name] AS [a__display_name], [a].[created_at] AS [a__created_at] FROM [ad_user] [a] WHERE ([a].[login_name] = 'tlanyon')) AS [inner_tbl]
which is missing a ") as [outer_tbl]"
results of the attempted patch:
[tlanyon@samadams Connection]$ rm Mssql.php
[tlanyon@samadams Connection]$ svn update
Restored 'Mssql.php'
At revision 6971.
[tlanyon@samadams Connection]$ patch Mssql.php Mssql-Patch-20091221.php
(Stripping trailing CRs from patch.)
patching file Mssql.php
patch unexpectedly ends in middle of line
patch: **** unexpected end of file in patch at line 47
Hope this helps.
Hi Trevor, patch corrected, I think it was missing a new line at the end. Let me know is it works now. or if it is still not including the ") as [outer_tbl]"
Hi Michael,
The patch applied. Thank you.
The solution did not work however. The below code:
Doctrine::getTable( 'CcmePoll' )
86 ->createQuery( 'p' )
87 ->innerJoin( 'p.CcmeEphoneAct a' )
88 >where( 'p.created_at < ?', $this>start )
89 ->andWhere( 'a.tag = ?', $ePhone['tag'] )
90 ->orderBy( 'p.created_at desc' )
91 ->limit( 1 )
92 ->fetchOne( );
generated this SQL:
SELECT [c].[id] AS [c__id], [c].[type] AS [c__type], [c].[created_at] AS [c__created_at], [c2].[ccme_poll_id] AS [c2__ccme_poll_id], [c2].[tag] AS [c2__tag], [c2].[device_name] AS [c2__device_name], [c2].[registration_state] AS [c2__registration_state], [c2].[active_dn] AS [c2__active_dn], [c2].[activity_status] AS [c2__activity_status], [c2].[keep_alive_count] AS [c2__keep_alive_count], [c2].[pending_reset] AS [c2__pending_reset], [c2].[registration_time] AS [c2__registration_time], [c2].[current_firmware] AS [c2__current_firmware], [c2].[previous_firmware] AS [c2__previous_firmware], [c2].[last_error] AS [c2__last_error], [c2].[observed_type] AS [c2__observed_type], [c2].[login_status] AS [c2__login_status], [c2].[dnd_status] AS [c2__dnd_status], [c2].[debug_status] AS [c2__debug_status], [c2].[media_active] AS [c2__media_active], [c2].[tapi_client] AS [c2__tapi_client], [c2].[media_capability] AS [c2__media_capability], [c2].[remote] AS [c2__remote] FROM [ccme_poll] [c] INNER JOIN [ccme_ephone_act] [c2] ON [c].[id] = [c2].[ccme_poll_id] WHERE [c].[id] IN (SELECT TOP 1 [inner_tbl].[id] FROM (SELECT DISTINCT TOP 1 [c].[id] FROM [ccme_poll] [c] INNER JOIN [ccme_ephone_act] [c2] ON [c].[id] = [c2].[ccme_poll_id] WHERE [c].[created_at] < '2009-12-22 8:0:00' AND [c2].[tag] = '13' ORDER BY [c].[created_at] desc) AS [inner_tbl] ORDER BY [inner_tbl].[ ASC) AND ([c].[created_at] < '2009-12-22 8:0:00' AND [c2].[tag] = '13') ORDER BY [c].[created_at] desc
Without having to go through the whole thing please pay special attention to this, near the bottom of the statement:
AND [c2].[tag] = '13'
ORDER BY [c].[created_at] desc) AS [inner_tbl]
ORDER BY [inner_tbl].[ ASC)
The code is not including the entire field name.
Hope this helps.
After attempting to debug this for about 30 minutes, I realized your probably not running 1.2.0RC1, apply the changes in DC-254 and this problem your having should go away.
On another note, does the query that was producing:
SELECT * FROM ( SELECT TOP 1 * FROM ( SELECT TOP 1 [a].[login_name] AS [a__login_name], [a].[last_login_at] AS [a__last_login_at], [a].[display_name] AS [a__display_name], [a].[created_at] AS [a__created_at] FROM [ad_user] [a] WHERE ([a].[login_name] = 'tlanyon')) AS [inner_tbl]
work now?
Hi Micheal,
I'm sorry if I have in anyway wasted your time. The fix http://www.doctrine-project.org/jira/browse/DC-254 has already been applied to my code base (according to the symfony debug window I'm running (Doctrine Version: 1.2.1 which seems to include the modification). I maybe be confused.
Yes. The select without the embedded order by works perfectly now.
Please let me know if I can be more of a help.
Thank you for your attention.
No problem at all, I really thought that was the issue
Are you using dblib? If so, edit \lib\Doctrine\Query.php line 1367:
< if ($driverName == 'pgsql' || $driverName == 'oracle' || $driverName == 'oci' || $driverName == 'mssql' || $driverName == 'odbc') {
—
> if ($driverName == 'pgsql' || $driverName == 'oracle' || $driverName == 'oci' || $driverName == 'mssql' || $driverName == 'odbc' || $driverName == 'dblib') {
Then give it a try again and let me know if we've got it now.
MIke
Give it a try on a bucnh of queries and see it you can come up with anything that isn't working (because of this issue
) otherwise, maybe we can finally get this committed.
Mike
Hi Mike,
I've tested it on ten different scenarios ranging from find() to complex dql including inner joins, left joins, orderBy and limit statements.
I have not tested in the example of a pager as I have no need for one. I will create a pager and have an answer for you within 24 hours.
Thanks!
I tested the pager and I had some mixed results.
The pager seemed to only work if you indicate a orderBy clause in the query you send the pager.
I imagine this has to with the strange way one must order results to facilitate the LIMIT X,Y functionality of other (IMHO superior) DBMSs.
I'm expecting this information may make sense to and should suffice for 99% of usage as most people would sort the results when using a pager.
Please let me know if I may help at all.
Thank you again!
What sql does it spit out if you don't use an order by statement? Maybe there is a small tweak I can make to get it working in those situations.
The below is an example of the same query for page 1, 2, 3 with first no order by and then order by.
Please let me know if my summary has left out inportant information
Query Used:
68 $query = Doctrine_Query::create()
69 ->from( "Customer c" )
70 ->leftJoin( 'c.Accessdatas a' )
71 ->leftJoin( 'c.SipPhoneServices s' )
72 ->where( $whereSQL );
/*No Order By Page 1
---------------*/
SELECT [c].[id] AS [c__id]
, [lots.of.fields]
FROM [customer] [c]
LEFT JOIN [accessdata] [a]
ON [c].[id] = [a].[d_custid]
LEFT JOIN [sipPhoneService] [s]
ON [c].[id] = [s].[d_custid]
WHERE [c].[id] IN (SELECT TOP 20 [inner_tbl].[id]
FROM (SELECT DISTINCT TOP 20 [c].[id]
FROM [customer] [c]
LEFT JOIN [accessdata] [a]
ON [c].[id] = [a].[d_custid]
LEFT JOIN [sipPhoneService] [s]
ON [c].[id] = [s].[d_custid]
WHERE [c].[email] LIKE '%smith%') AS [inner_tbl])
AND ([c].[email] LIKE '%smith%')
/*No Order By Page 2
---------------*/
SELECT [c].[id] AS [c__id]
, [lots.of.fields]
FROM [customer] [c]
LEFT JOIN [accessdata] [a]
ON [c].[id] = [a].[d_custid]
LEFT JOIN [sipPhoneService] [s]
ON [c].[id] = [s].[d_custid]
WHERE [c].[id] IN (SELECT TOP 20 [inner_tbl].[id]
FROM (SELECT DISTINCT TOP 40 [c].[id]
FROM [customer] [c]
LEFT JOIN [accessdata] [a]
ON [c].[id] = [a].[d_custid]
LEFT JOIN [sipPhoneService] [s]
ON [c].[id] = [s].[d_custid]
WHERE [c].[email] LIKE '%smith%') AS [inner_tbl])
AND ([c].[email] LIKE '%smith%')
/*No Order By Page 3
---------------*/
SELECT [c].[id] AS [c__id]
, [lots.of.fields]
FROM [customer] [c]
LEFT JOIN [accessdata] [a]
ON [c].[id] = [a].[d_custid]
LEFT JOIN [sipPhoneService] [s]
ON [c].[id] = [s].[d_custid]
WHERE [c].[id] IN (SELECT TOP 20 [inner_tbl].[id]
FROM (SELECT DISTINCT TOP 60 [c].[id]
FROM [customer] [c]
LEFT JOIN [accessdata] [a]
ON [c].[id] = [a].[d_custid]
LEFT JOIN [sipPhoneService] [s]
ON [c].[id] = [s].[d_custid]
WHERE [c].[email] LIKE '%smith%') AS [inner_tbl])
AND ([c].[email] LIKE '%smith%')
Query Used:
68 $query = Doctrine_Query::create()
69 ->from( "Customer c" )
70 ->leftJoin( 'c.Accessdatas a' )
71 ->leftJoin( 'c.SipPhoneServices s' )
72 ->where( $whereSQL )
73 ->orderBy( 'c.Name' );
/*Order By Page 1
---------------*/
SELECT [c].[id] AS [c__id]
, [lots.of.fields]
FROM [customer] [c]
LEFT JOIN [accessdata] [a]
ON [c].[id] = [a].[d_custid]
LEFT JOIN [sipPhoneService] [s]
ON [c].[id] = [s].[d_custid]
WHERE [c].[id] IN (SELECT TOP 20 [inner_tbl].[id]
FROM (SELECT DISTINCT TOP 20 [c].[id]
, [c].[name]
FROM [customer] [c]
LEFT JOIN [accessdata] [a]
ON [c].[id] = [a].[d_custid]
LEFT JOIN [sipPhoneService] [s]
ON [c].[id] = [s].[d_custid]
WHERE [c].[email]
LIKE '%smith%'
ORDER BY [c].[name]) AS [inner_tbl]
ORDER BY [inner_tbl].[name] DESC)
AND ([c].[email] LIKE '%smith%')
ORDER BY [c].[name]
/*Order By Page 2
---------------*/
SELECT [c].[id] AS [c__id]
, [lots.of.fields]
FROM [customer] [c]
LEFT JOIN [accessdata] [a]
ON [c].[id] = [a].[d_custid]
LEFT JOIN [sipPhoneService] [s]
ON [c].[id] = [s].[d_custid]
WHERE [c].[id] IN (SELECT TOP 20 [inner_tbl].[id]
FROM (SELECT DISTINCT TOP 40 [c].[id], [c].[name]
FROM [customer] [c]
LEFT JOIN [accessdata] [a]
ON [c].[id] = [a].[d_custid]
LEFT JOIN [sipPhoneService] [s]
ON [c].[id] = [s].[d_custid]
WHERE [c].[email]
LIKE '%smith%'
ORDER BY [c].[name]) AS [inner_tbl]
ORDER BY [inner_tbl].[name] DESC)
AND ([c].[email] LIKE '%smith%')
ORDER BY [c].[name]
/*Order By Page 3
---------------*/
SELECT [c].[id] AS [c__id]
, [lots.of.fields]
FROM [customer] [c]
LEFT JOIN [accessdata] [a]
ON [c].[id] = [a].[d_custid]
LEFT JOIN [sipPhoneService] [s]
ON [c].[id] = [s].[d_custid]
WHERE [c].[id] IN (SELECT TOP 20 [inner_tbl].[id]
FROM (SELECT DISTINCT TOP 60 [c].[id]
, [c].[name]
FROM [customer] [c]
LEFT JOIN [accessdata] [a]
ON [c].[id] = [a].[d_custid]
LEFT JOIN [sipPhoneService] [s]
ON [c].[id] = [s].[d_custid]
WHERE [c].[email] LIKE '%smith%'
ORDER BY [c].[name]) AS [inner_tbl]
ORDER BY [inner_tbl].[name] DESC)
AND ([c].[email] LIKE '%smith%') ORDER BY [c].[name]
Was it producing bad sql or just weird results. It looks like the queries for no order by are valid.
The SQL was valid.
Just weird results. Moving through the pages would not move through the results predictably. Moving from page 1 to page 2 would display the same results. Moving from page 2 to page 3 would again show the same results. Moving from page 3 to page four would then show the last page's results (or something similar).
Good, weird results is okay, just wanted to make sure the sql wasn't causing errors.
@jwage Can you commit the most recent patch, everything is finally working correctly.
@Michael Card
The issue with limit and offset methods not working properly punched me in the face today. After an hour of going through a lot of ways to simulate them in SQL Server i came up with two ways of doing it:
Default way (the one M$ suggests)
--------------
Create a query that looks like this:
SELECT * FROM (
SELECT TOP $limit * FROM (
SELECT TOP ($limit + $offset) [a].[id] AS [a__id], [a].[id_tipo_produto] AS [a__id_tipo_produto], [a].[nm_produto_base] AS [a__nm_produto_base], [a].[fg_ativo] AS [a__fg_ativo] FROM [ad_produto_base] [a] order by [a__id] ASC
) AS [inner_tbl] ORDER BY 1 DESC
) AS [outer_tbl] ORDER BY 1 ASC
Problem with this solution:
When you are near the end of the paging and queries for the remaining results you will receive all the results from the last page AND some results from the previous one.
Way that I came up with when drinking some tea
----------------------------------------------
Simply add the suffix " WHERE $index > $offset" to the end of the $query variable before wrapping it in its outer selects.
This would produce something along the lines of:
SELECT * FROM (
SELECT TOP 2 * FROM (
SELECT [a].[id] AS [a__id], [a].[id_tipo_produto] AS [a__id_tipo_produto], [a].[nm_produto_base] AS [a__nm_produto_base], [a].[fg_ativo] AS [a__fg_ativo] FROM [ad_produto_base] [a] WHERE $index > $offset
) AS [inner_tbl]
) AS [outer_tbl]
Problem with this solution: your inner select WILL need to have an integer index to compare to the value of $offset. In my case all my tables have an id field so that's not a problem but I guess this would not always be the case. Besides that, I couldn't find a way to retrieve the primary key name (my $index) from inside the method you modified and hardcoded " WHERE id > {$offset}" on it instead.
I'm sure that with my 2 cents we will be able to work out a more reliable solution to this issue.
Cheers,
@Daniel
That solution would work of sorting by anything but the id field though, the solution needs to be able to sort by any field. I will take a look at the issue you mentioned, about the last page of the paging results, and see what can be done.
Mike
Hello,
I was wondering what the status of this issue was? We're also suffering the pain of trying to get Doctrine working with ODBC and MSSQL, and the patch solved a few bugs for us. Obviously there are still some kinks to be worked out but the driver's unusable in it's current state. If it's a case of needing the pager issue resolved first I'd gladly look at fixing it.
Incidentally, regarding Aiso Haikens' comment above - we've also come up against the binding issue and like Trevor have temporarily got around it by rewriting queries so the parameters are inline rather than bound. Not pleasant. We're investigating whether it can be patched at the PDO driver level but so far no joy. Do you think it would be worth adding our rewrite patch in the meantime so at least queries aren't subject to that bug?
Craig
I committed the most recent patch and all tests passed. Thanks for everyones work and comments on the issue.
- Jon
Trevor,
I had worked on these changes the jwage committed as I couldn't find any way how the old code worked. Did this code work in versions before 1.2.0-RC1 or are you just finding this using the new version?
What code are you using for the find? The code works okay when running a normal dql query.
Mike