From beea2aaffb8b2bc4c2a348abeee306904c6fd32c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=ABl=20Harkes?= Date: Thu, 2 Dec 2021 21:52:55 +0100 Subject: [PATCH] [8.x] Add proper paging offset when possible to sql server (#39863) * Add proper paging offset when possible to sql server * update styling * formatting Co-authored-by: Taylor Otwell --- .../Database/Query/Grammars/SqlServerGrammar.php | 14 ++++++++++---- tests/Database/DatabaseQueryBuilderTest.php | 10 +++++----- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/src/Illuminate/Database/Query/Grammars/SqlServerGrammar.php b/src/Illuminate/Database/Query/Grammars/SqlServerGrammar.php index 0f5a27a66145..3fce201bd28c 100755 --- a/src/Illuminate/Database/Query/Grammars/SqlServerGrammar.php +++ b/src/Illuminate/Database/Query/Grammars/SqlServerGrammar.php @@ -31,15 +31,21 @@ public function compileSelect(Builder $query) return parent::compileSelect($query); } - // If an offset is present on the query, we will need to wrap the query in - // a big "ANSI" offset syntax block. This is very nasty compared to the - // other database systems but is necessary for implementing features. if (is_null($query->columns)) { $query->columns = ['*']; } + $components = $this->compileComponents($query); + + if (! empty($components['orders'])) { + return parent::compileSelect($query)." offset {$query->offset} rows fetch next {$query->limit} rows only"; + } + + // If an offset is present on the query, we will need to wrap the query in + // a big "ANSI" offset syntax block. This is very nasty compared to the + // other database systems but is necessary for implementing features. return $this->compileAnsiOffset( - $query, $this->compileComponents($query) + $query, $components ); } diff --git a/tests/Database/DatabaseQueryBuilderTest.php b/tests/Database/DatabaseQueryBuilderTest.php index 98a42ff88f09..4064664fa4b7 100755 --- a/tests/Database/DatabaseQueryBuilderTest.php +++ b/tests/Database/DatabaseQueryBuilderTest.php @@ -1221,7 +1221,7 @@ public function testOrderBysSqlServer() $builder = $this->getSqlServerBuilder(); $builder->select('*')->from('users')->skip(25)->take(10)->orderByRaw('[email] desc'); - $this->assertSame('select * from (select *, row_number() over (order by [email] desc) as row_num from [users]) as temp_table where row_num between 26 and 35 order by row_num', $builder->toSql()); + $this->assertSame('select * from [users] order by [email] desc offset 25 rows fetch next 10 rows only', $builder->toSql()); } public function testReorder() @@ -3109,8 +3109,8 @@ public function testSqlServerLimitsAndOffsets() $this->assertSame('select * from (select *, row_number() over (order by (select 0)) as row_num from [users]) as temp_table where row_num between 11 and 20 order by row_num', $builder->toSql()); $builder = $this->getSqlServerBuilder(); - $builder->select('*')->from('users')->skip(10)->take(10)->orderBy('email', 'desc'); - $this->assertSame('select * from (select *, row_number() over (order by [email] desc) as row_num from [users]) as temp_table where row_num between 11 and 20 order by row_num', $builder->toSql()); + $builder->select('*')->from('users')->skip(11)->take(10)->orderBy('email', 'desc'); + $this->assertSame('select * from [users] order by [email] desc offset 11 rows fetch next 10 rows only', $builder->toSql()); $builder = $this->getSqlServerBuilder(); $subQueryBuilder = $this->getSqlServerBuilder(); @@ -3118,8 +3118,8 @@ public function testSqlServerLimitsAndOffsets() return $query->select('created_at')->from('logins')->where('users.name', 'nameBinding')->whereColumn('user_id', 'users.id')->limit(1); }; $builder->select('*')->from('users')->where('email', 'emailBinding')->orderBy($subQuery)->skip(10)->take(10); - $this->assertSame('select * from (select *, row_number() over (order by (select top 1 [created_at] from [logins] where [users].[name] = ? and [user_id] = [users].[id]) asc) as row_num from [users] where [email] = ?) as temp_table where row_num between 11 and 20 order by row_num', $builder->toSql()); - $this->assertEquals(['nameBinding', 'emailBinding'], $builder->getBindings()); + $this->assertSame('select * from [users] where [email] = ? order by (select top 1 [created_at] from [logins] where [users].[name] = ? and [user_id] = [users].[id]) asc offset 10 rows fetch next 10 rows only', $builder->toSql()); + $this->assertEquals(['emailBinding', 'nameBinding'], $builder->getBindings()); $builder = $this->getSqlServerBuilder(); $builder->select('*')->from('users')->take('foo');