-
Notifications
You must be signed in to change notification settings - Fork 10.7k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Jared Dunham
committed
Oct 4, 2022
1 parent
ca7970e
commit 03c147e
Showing
2 changed files
with
34 additions
and
99 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -19,6 +19,25 @@ class SqlServerGrammar extends Grammar | |
'&', '&=', '|', '|=', '^', '^=', | ||
]; | ||
|
||
/** | ||
* The components that make up a select clause. | ||
* | ||
* @var string[] | ||
*/ | ||
protected $selectComponents = [ | ||
'aggregate', | ||
'columns', | ||
'from', | ||
'joins', | ||
'wheres', | ||
'groups', | ||
'havings', | ||
'orders', | ||
'offset', | ||
'limit', | ||
'lock', | ||
]; | ||
|
||
/** | ||
* Compile a select query into SQL. | ||
* | ||
|
@@ -27,26 +46,12 @@ class SqlServerGrammar extends Grammar | |
*/ | ||
public function compileSelect(Builder $query) | ||
{ | ||
if (! $query->offset) { | ||
return parent::compileSelect($query); | ||
} | ||
|
||
if (is_null($query->columns)) { | ||
$query->columns = ['*']; | ||
// An ORDER BY clause is required for offset to work | ||
if($query->offset && empty($query->orders)){ | ||
$query->orders[] = ['sql' => '(SELECT 0)']; | ||
This comment has been minimized.
Sorry, something went wrong.
This comment has been minimized.
Sorry, something went wrong.
This comment has been minimized.
Sorry, something went wrong.
dunhamjared
Contributor
|
||
} | ||
|
||
$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, $components | ||
); | ||
return parent::compileSelect($query); | ||
} | ||
|
||
/** | ||
|
@@ -235,69 +240,6 @@ protected function compileHavingBitwise($having) | |
return '('.$column.' '.$having['operator'].' '.$parameter.') != 0'; | ||
} | ||
|
||
/** | ||
* Create a full ANSI offset clause for the query. | ||
* | ||
* @param \Illuminate\Database\Query\Builder $query | ||
* @param array $components | ||
* @return string | ||
*/ | ||
protected function compileAnsiOffset(Builder $query, $components) | ||
{ | ||
// An ORDER BY clause is required to make this offset query work, so if one does | ||
// not exist we'll just create a dummy clause to trick the database and so it | ||
// does not complain about the queries for not having an "order by" clause. | ||
if (empty($components['orders'])) { | ||
$components['orders'] = 'order by (select 0)'; | ||
} | ||
|
||
// We need to add the row number to the query so we can compare it to the offset | ||
// and limit values given for the statements. So we will add an expression to | ||
// the "select" that will give back the row numbers on each of the records. | ||
$components['columns'] .= $this->compileOver($components['orders']); | ||
|
||
unset($components['orders']); | ||
|
||
if ($this->queryOrderContainsSubquery($query)) { | ||
$query->bindings = $this->sortBindingsForSubqueryOrderBy($query); | ||
} | ||
|
||
// Next we need to calculate the constraints that should be placed on the query | ||
// to get the right offset and limit from our query but if there is no limit | ||
// set we will just handle the offset only since that is all that matters. | ||
$sql = $this->concatenate($components); | ||
|
||
return $this->compileTableExpression($sql, $query); | ||
} | ||
|
||
/** | ||
* Compile the over statement for a table expression. | ||
* | ||
* @param string $orderings | ||
* @return string | ||
*/ | ||
protected function compileOver($orderings) | ||
{ | ||
return ", row_number() over ({$orderings}) as row_num"; | ||
} | ||
|
||
/** | ||
* Determine if the query's order by clauses contain a subquery. | ||
* | ||
* @param \Illuminate\Database\Query\Builder $query | ||
* @return bool | ||
*/ | ||
protected function queryOrderContainsSubquery($query) | ||
{ | ||
if (! is_array($query->orders)) { | ||
return false; | ||
} | ||
|
||
return Arr::first($query->orders, function ($value) { | ||
return $this->isExpression($value['column'] ?? null); | ||
}, false) !== false; | ||
} | ||
|
||
/** | ||
* Move the order bindings to be after the "select" statement to account for an order by subquery. | ||
* | ||
|
@@ -311,20 +253,6 @@ protected function sortBindingsForSubqueryOrderBy($query) | |
}); | ||
} | ||
|
||
/** | ||
* Compile a common table expression for a query. | ||
* | ||
* @param string $sql | ||
* @param \Illuminate\Database\Query\Builder $query | ||
* @return string | ||
*/ | ||
protected function compileTableExpression($sql, $query) | ||
{ | ||
$constraint = $this->compileRowConstraint($query); | ||
|
||
return "select * from ({$sql}) as temp_table where row_num {$constraint} order by row_num"; | ||
} | ||
|
||
/** | ||
* Compile the limit / offset row constraint for a query. | ||
* | ||
|
@@ -381,6 +309,10 @@ public function compileRandom($seed) | |
*/ | ||
protected function compileLimit(Builder $query, $limit) | ||
{ | ||
if($limit && $query->offset > 0){ | ||
return "fetch next {$limit} rows only"; | ||
} | ||
|
||
return ''; | ||
} | ||
|
||
|
@@ -393,6 +325,10 @@ protected function compileLimit(Builder $query, $limit) | |
*/ | ||
protected function compileOffset(Builder $query, $offset) | ||
{ | ||
if($offset){ | ||
return "offset {$offset} rows"; | ||
} | ||
|
||
return ''; | ||
} | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@dunhamjared I think you broke paging for us again!! this has major impact.
Page 1 is sorted differently than the other pages :(