@@ -19,6 +19,25 @@ class SqlServerGrammar extends Grammar
19
19
'& ' , '&= ' , '| ' , '|= ' , '^ ' , '^= ' ,
20
20
];
21
21
22
+ /**
23
+ * The components that make up a select clause.
24
+ *
25
+ * @var string[]
26
+ */
27
+ protected $ selectComponents = [
28
+ 'aggregate ' ,
29
+ 'columns ' ,
30
+ 'from ' ,
31
+ 'joins ' ,
32
+ 'wheres ' ,
33
+ 'groups ' ,
34
+ 'havings ' ,
35
+ 'orders ' ,
36
+ 'offset ' ,
37
+ 'limit ' ,
38
+ 'lock ' ,
39
+ ];
40
+
22
41
/**
23
42
* Compile a select query into SQL.
24
43
*
@@ -27,26 +46,12 @@ class SqlServerGrammar extends Grammar
27
46
*/
28
47
public function compileSelect (Builder $ query )
29
48
{
30
- if (! $ query ->offset ) {
31
- return parent ::compileSelect ($ query );
32
- }
33
-
34
- if (is_null ($ query ->columns )) {
35
- $ query ->columns = ['* ' ];
49
+ // An ORDER BY clause is required for offset to work
50
+ if ($ query ->offset && empty ($ query ->orders )){
51
+ $ query ->orders [] = ['sql ' => '(SELECT 0) ' ];
36
52
}
37
53
38
- $ components = $ this ->compileComponents ($ query );
39
-
40
- if (! empty ($ components ['orders ' ])) {
41
- return parent ::compileSelect ($ query )." offset {$ query ->offset } rows fetch next {$ query ->limit } rows only " ;
42
- }
43
-
44
- // If an offset is present on the query, we will need to wrap the query in
45
- // a big "ANSI" offset syntax block. This is very nasty compared to the
46
- // other database systems but is necessary for implementing features.
47
- return $ this ->compileAnsiOffset (
48
- $ query , $ components
49
- );
54
+ return parent ::compileSelect ($ query );
50
55
}
51
56
52
57
/**
@@ -235,69 +240,6 @@ protected function compileHavingBitwise($having)
235
240
return '( ' .$ column .' ' .$ having ['operator ' ].' ' .$ parameter .') != 0 ' ;
236
241
}
237
242
238
- /**
239
- * Create a full ANSI offset clause for the query.
240
- *
241
- * @param \Illuminate\Database\Query\Builder $query
242
- * @param array $components
243
- * @return string
244
- */
245
- protected function compileAnsiOffset (Builder $ query , $ components )
246
- {
247
- // An ORDER BY clause is required to make this offset query work, so if one does
248
- // not exist we'll just create a dummy clause to trick the database and so it
249
- // does not complain about the queries for not having an "order by" clause.
250
- if (empty ($ components ['orders ' ])) {
251
- $ components ['orders ' ] = 'order by (select 0) ' ;
252
- }
253
-
254
- // We need to add the row number to the query so we can compare it to the offset
255
- // and limit values given for the statements. So we will add an expression to
256
- // the "select" that will give back the row numbers on each of the records.
257
- $ components ['columns ' ] .= $ this ->compileOver ($ components ['orders ' ]);
258
-
259
- unset($ components ['orders ' ]);
260
-
261
- if ($ this ->queryOrderContainsSubquery ($ query )) {
262
- $ query ->bindings = $ this ->sortBindingsForSubqueryOrderBy ($ query );
263
- }
264
-
265
- // Next we need to calculate the constraints that should be placed on the query
266
- // to get the right offset and limit from our query but if there is no limit
267
- // set we will just handle the offset only since that is all that matters.
268
- $ sql = $ this ->concatenate ($ components );
269
-
270
- return $ this ->compileTableExpression ($ sql , $ query );
271
- }
272
-
273
- /**
274
- * Compile the over statement for a table expression.
275
- *
276
- * @param string $orderings
277
- * @return string
278
- */
279
- protected function compileOver ($ orderings )
280
- {
281
- return ", row_number() over ( {$ orderings }) as row_num " ;
282
- }
283
-
284
- /**
285
- * Determine if the query's order by clauses contain a subquery.
286
- *
287
- * @param \Illuminate\Database\Query\Builder $query
288
- * @return bool
289
- */
290
- protected function queryOrderContainsSubquery ($ query )
291
- {
292
- if (! is_array ($ query ->orders )) {
293
- return false ;
294
- }
295
-
296
- return Arr::first ($ query ->orders , function ($ value ) {
297
- return $ this ->isExpression ($ value ['column ' ] ?? null );
298
- }, false ) !== false ;
299
- }
300
-
301
243
/**
302
244
* Move the order bindings to be after the "select" statement to account for an order by subquery.
303
245
*
@@ -311,20 +253,6 @@ protected function sortBindingsForSubqueryOrderBy($query)
311
253
});
312
254
}
313
255
314
- /**
315
- * Compile a common table expression for a query.
316
- *
317
- * @param string $sql
318
- * @param \Illuminate\Database\Query\Builder $query
319
- * @return string
320
- */
321
- protected function compileTableExpression ($ sql , $ query )
322
- {
323
- $ constraint = $ this ->compileRowConstraint ($ query );
324
-
325
- return "select * from ( {$ sql }) as temp_table where row_num {$ constraint } order by row_num " ;
326
- }
327
-
328
256
/**
329
257
* Compile the limit / offset row constraint for a query.
330
258
*
@@ -381,6 +309,10 @@ public function compileRandom($seed)
381
309
*/
382
310
protected function compileLimit (Builder $ query , $ limit )
383
311
{
312
+ if ($ limit && $ query ->offset > 0 ){
313
+ return "fetch next {$ limit } rows only " ;
314
+ }
315
+
384
316
return '' ;
385
317
}
386
318
@@ -393,6 +325,10 @@ protected function compileLimit(Builder $query, $limit)
393
325
*/
394
326
protected function compileOffset (Builder $ query , $ offset )
395
327
{
328
+ if ($ offset ){
329
+ return "offset {$ offset } rows " ;
330
+ }
331
+
396
332
return '' ;
397
333
}
398
334
0 commit comments