Subversion-Projekte lars-tiefland.laravel_shop

Revision

Zur aktuellen Revision | Details | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
148 lars 1
<?php
2
 
3
namespace Illuminate\Database\Query\Grammars;
4
 
5
use Illuminate\Database\Concerns\CompilesJsonPaths;
6
use Illuminate\Database\Grammar as BaseGrammar;
7
use Illuminate\Database\Query\Builder;
8
use Illuminate\Database\Query\JoinClause;
9
use Illuminate\Support\Arr;
10
use RuntimeException;
11
 
12
class Grammar extends BaseGrammar
13
{
14
    use CompilesJsonPaths;
15
 
16
    /**
17
     * The grammar specific operators.
18
     *
19
     * @var array
20
     */
21
    protected $operators = [];
22
 
23
    /**
24
     * The grammar specific bitwise operators.
25
     *
26
     * @var array
27
     */
28
    protected $bitwiseOperators = [];
29
 
30
    /**
31
     * The components that make up a select clause.
32
     *
33
     * @var string[]
34
     */
35
    protected $selectComponents = [
36
        'aggregate',
37
        'columns',
38
        'from',
39
        'joins',
40
        'wheres',
41
        'groups',
42
        'havings',
43
        'orders',
44
        'limit',
45
        'offset',
46
        'lock',
47
    ];
48
 
49
    /**
50
     * Compile a select query into SQL.
51
     *
52
     * @param  \Illuminate\Database\Query\Builder  $query
53
     * @return string
54
     */
55
    public function compileSelect(Builder $query)
56
    {
57
        if (($query->unions || $query->havings) && $query->aggregate) {
58
            return $this->compileUnionAggregate($query);
59
        }
60
 
61
        // If the query does not have any columns set, we'll set the columns to the
62
        // * character to just get all of the columns from the database. Then we
63
        // can build the query and concatenate all the pieces together as one.
64
        $original = $query->columns;
65
 
66
        if (is_null($query->columns)) {
67
            $query->columns = ['*'];
68
        }
69
 
70
        // To compile the query, we'll spin through each component of the query and
71
        // see if that component exists. If it does we'll just call the compiler
72
        // function for the component which is responsible for making the SQL.
73
        $sql = trim($this->concatenate(
74
            $this->compileComponents($query))
75
        );
76
 
77
        if ($query->unions) {
78
            $sql = $this->wrapUnion($sql).' '.$this->compileUnions($query);
79
        }
80
 
81
        $query->columns = $original;
82
 
83
        return $sql;
84
    }
85
 
86
    /**
87
     * Compile the components necessary for a select clause.
88
     *
89
     * @param  \Illuminate\Database\Query\Builder  $query
90
     * @return array
91
     */
92
    protected function compileComponents(Builder $query)
93
    {
94
        $sql = [];
95
 
96
        foreach ($this->selectComponents as $component) {
97
            if (isset($query->$component)) {
98
                $method = 'compile'.ucfirst($component);
99
 
100
                $sql[$component] = $this->$method($query, $query->$component);
101
            }
102
        }
103
 
104
        return $sql;
105
    }
106
 
107
    /**
108
     * Compile an aggregated select clause.
109
     *
110
     * @param  \Illuminate\Database\Query\Builder  $query
111
     * @param  array  $aggregate
112
     * @return string
113
     */
114
    protected function compileAggregate(Builder $query, $aggregate)
115
    {
116
        $column = $this->columnize($aggregate['columns']);
117
 
118
        // If the query has a "distinct" constraint and we're not asking for all columns
119
        // we need to prepend "distinct" onto the column name so that the query takes
120
        // it into account when it performs the aggregating operations on the data.
121
        if (is_array($query->distinct)) {
122
            $column = 'distinct '.$this->columnize($query->distinct);
123
        } elseif ($query->distinct && $column !== '*') {
124
            $column = 'distinct '.$column;
125
        }
126
 
127
        return 'select '.$aggregate['function'].'('.$column.') as aggregate';
128
    }
129
 
130
    /**
131
     * Compile the "select *" portion of the query.
132
     *
133
     * @param  \Illuminate\Database\Query\Builder  $query
134
     * @param  array  $columns
135
     * @return string|null
136
     */
137
    protected function compileColumns(Builder $query, $columns)
138
    {
139
        // If the query is actually performing an aggregating select, we will let that
140
        // compiler handle the building of the select clauses, as it will need some
141
        // more syntax that is best handled by that function to keep things neat.
142
        if (! is_null($query->aggregate)) {
143
            return;
144
        }
145
 
146
        if ($query->distinct) {
147
            $select = 'select distinct ';
148
        } else {
149
            $select = 'select ';
150
        }
151
 
152
        return $select.$this->columnize($columns);
153
    }
154
 
155
    /**
156
     * Compile the "from" portion of the query.
157
     *
158
     * @param  \Illuminate\Database\Query\Builder  $query
159
     * @param  string  $table
160
     * @return string
161
     */
162
    protected function compileFrom(Builder $query, $table)
163
    {
164
        return 'from '.$this->wrapTable($table);
165
    }
166
 
167
    /**
168
     * Compile the "join" portions of the query.
169
     *
170
     * @param  \Illuminate\Database\Query\Builder  $query
171
     * @param  array  $joins
172
     * @return string
173
     */
174
    protected function compileJoins(Builder $query, $joins)
175
    {
176
        return collect($joins)->map(function ($join) use ($query) {
177
            $table = $this->wrapTable($join->table);
178
 
179
            $nestedJoins = is_null($join->joins) ? '' : ' '.$this->compileJoins($query, $join->joins);
180
 
181
            $tableAndNestedJoins = is_null($join->joins) ? $table : '('.$table.$nestedJoins.')';
182
 
183
            return trim("{$join->type} join {$tableAndNestedJoins} {$this->compileWheres($join)}");
184
        })->implode(' ');
185
    }
186
 
187
    /**
188
     * Compile the "where" portions of the query.
189
     *
190
     * @param  \Illuminate\Database\Query\Builder  $query
191
     * @return string
192
     */
193
    public function compileWheres(Builder $query)
194
    {
195
        // Each type of where clause has its own compiler function, which is responsible
196
        // for actually creating the where clauses SQL. This helps keep the code nice
197
        // and maintainable since each clause has a very small method that it uses.
198
        if (is_null($query->wheres)) {
199
            return '';
200
        }
201
 
202
        // If we actually have some where clauses, we will strip off the first boolean
203
        // operator, which is added by the query builders for convenience so we can
204
        // avoid checking for the first clauses in each of the compilers methods.
205
        if (count($sql = $this->compileWheresToArray($query)) > 0) {
206
            return $this->concatenateWhereClauses($query, $sql);
207
        }
208
 
209
        return '';
210
    }
211
 
212
    /**
213
     * Get an array of all the where clauses for the query.
214
     *
215
     * @param  \Illuminate\Database\Query\Builder  $query
216
     * @return array
217
     */
218
    protected function compileWheresToArray($query)
219
    {
220
        return collect($query->wheres)->map(function ($where) use ($query) {
221
            return $where['boolean'].' '.$this->{"where{$where['type']}"}($query, $where);
222
        })->all();
223
    }
224
 
225
    /**
226
     * Format the where clause statements into one string.
227
     *
228
     * @param  \Illuminate\Database\Query\Builder  $query
229
     * @param  array  $sql
230
     * @return string
231
     */
232
    protected function concatenateWhereClauses($query, $sql)
233
    {
234
        $conjunction = $query instanceof JoinClause ? 'on' : 'where';
235
 
236
        return $conjunction.' '.$this->removeLeadingBoolean(implode(' ', $sql));
237
    }
238
 
239
    /**
240
     * Compile a raw where clause.
241
     *
242
     * @param  \Illuminate\Database\Query\Builder  $query
243
     * @param  array  $where
244
     * @return string
245
     */
246
    protected function whereRaw(Builder $query, $where)
247
    {
248
        return $where['sql'];
249
    }
250
 
251
    /**
252
     * Compile a basic where clause.
253
     *
254
     * @param  \Illuminate\Database\Query\Builder  $query
255
     * @param  array  $where
256
     * @return string
257
     */
258
    protected function whereBasic(Builder $query, $where)
259
    {
260
        $value = $this->parameter($where['value']);
261
 
262
        $operator = str_replace('?', '??', $where['operator']);
263
 
264
        return $this->wrap($where['column']).' '.$operator.' '.$value;
265
    }
266
 
267
    /**
268
     * Compile a bitwise operator where clause.
269
     *
270
     * @param  \Illuminate\Database\Query\Builder  $query
271
     * @param  array  $where
272
     * @return string
273
     */
274
    protected function whereBitwise(Builder $query, $where)
275
    {
276
        return $this->whereBasic($query, $where);
277
    }
278
 
279
    /**
280
     * Compile a "where in" clause.
281
     *
282
     * @param  \Illuminate\Database\Query\Builder  $query
283
     * @param  array  $where
284
     * @return string
285
     */
286
    protected function whereIn(Builder $query, $where)
287
    {
288
        if (! empty($where['values'])) {
289
            return $this->wrap($where['column']).' in ('.$this->parameterize($where['values']).')';
290
        }
291
 
292
        return '0 = 1';
293
    }
294
 
295
    /**
296
     * Compile a "where not in" clause.
297
     *
298
     * @param  \Illuminate\Database\Query\Builder  $query
299
     * @param  array  $where
300
     * @return string
301
     */
302
    protected function whereNotIn(Builder $query, $where)
303
    {
304
        if (! empty($where['values'])) {
305
            return $this->wrap($where['column']).' not in ('.$this->parameterize($where['values']).')';
306
        }
307
 
308
        return '1 = 1';
309
    }
310
 
311
    /**
312
     * Compile a "where not in raw" clause.
313
     *
314
     * For safety, whereIntegerInRaw ensures this method is only used with integer values.
315
     *
316
     * @param  \Illuminate\Database\Query\Builder  $query
317
     * @param  array  $where
318
     * @return string
319
     */
320
    protected function whereNotInRaw(Builder $query, $where)
321
    {
322
        if (! empty($where['values'])) {
323
            return $this->wrap($where['column']).' not in ('.implode(', ', $where['values']).')';
324
        }
325
 
326
        return '1 = 1';
327
    }
328
 
329
    /**
330
     * Compile a "where in raw" clause.
331
     *
332
     * For safety, whereIntegerInRaw ensures this method is only used with integer values.
333
     *
334
     * @param  \Illuminate\Database\Query\Builder  $query
335
     * @param  array  $where
336
     * @return string
337
     */
338
    protected function whereInRaw(Builder $query, $where)
339
    {
340
        if (! empty($where['values'])) {
341
            return $this->wrap($where['column']).' in ('.implode(', ', $where['values']).')';
342
        }
343
 
344
        return '0 = 1';
345
    }
346
 
347
    /**
348
     * Compile a "where null" clause.
349
     *
350
     * @param  \Illuminate\Database\Query\Builder  $query
351
     * @param  array  $where
352
     * @return string
353
     */
354
    protected function whereNull(Builder $query, $where)
355
    {
356
        return $this->wrap($where['column']).' is null';
357
    }
358
 
359
    /**
360
     * Compile a "where not null" clause.
361
     *
362
     * @param  \Illuminate\Database\Query\Builder  $query
363
     * @param  array  $where
364
     * @return string
365
     */
366
    protected function whereNotNull(Builder $query, $where)
367
    {
368
        return $this->wrap($where['column']).' is not null';
369
    }
370
 
371
    /**
372
     * Compile a "between" where clause.
373
     *
374
     * @param  \Illuminate\Database\Query\Builder  $query
375
     * @param  array  $where
376
     * @return string
377
     */
378
    protected function whereBetween(Builder $query, $where)
379
    {
380
        $between = $where['not'] ? 'not between' : 'between';
381
 
382
        $min = $this->parameter(is_array($where['values']) ? reset($where['values']) : $where['values'][0]);
383
 
384
        $max = $this->parameter(is_array($where['values']) ? end($where['values']) : $where['values'][1]);
385
 
386
        return $this->wrap($where['column']).' '.$between.' '.$min.' and '.$max;
387
    }
388
 
389
    /**
390
     * Compile a "between" where clause.
391
     *
392
     * @param  \Illuminate\Database\Query\Builder  $query
393
     * @param  array  $where
394
     * @return string
395
     */
396
    protected function whereBetweenColumns(Builder $query, $where)
397
    {
398
        $between = $where['not'] ? 'not between' : 'between';
399
 
400
        $min = $this->wrap(is_array($where['values']) ? reset($where['values']) : $where['values'][0]);
401
 
402
        $max = $this->wrap(is_array($where['values']) ? end($where['values']) : $where['values'][1]);
403
 
404
        return $this->wrap($where['column']).' '.$between.' '.$min.' and '.$max;
405
    }
406
 
407
    /**
408
     * Compile a "where date" clause.
409
     *
410
     * @param  \Illuminate\Database\Query\Builder  $query
411
     * @param  array  $where
412
     * @return string
413
     */
414
    protected function whereDate(Builder $query, $where)
415
    {
416
        return $this->dateBasedWhere('date', $query, $where);
417
    }
418
 
419
    /**
420
     * Compile a "where time" clause.
421
     *
422
     * @param  \Illuminate\Database\Query\Builder  $query
423
     * @param  array  $where
424
     * @return string
425
     */
426
    protected function whereTime(Builder $query, $where)
427
    {
428
        return $this->dateBasedWhere('time', $query, $where);
429
    }
430
 
431
    /**
432
     * Compile a "where day" clause.
433
     *
434
     * @param  \Illuminate\Database\Query\Builder  $query
435
     * @param  array  $where
436
     * @return string
437
     */
438
    protected function whereDay(Builder $query, $where)
439
    {
440
        return $this->dateBasedWhere('day', $query, $where);
441
    }
442
 
443
    /**
444
     * Compile a "where month" clause.
445
     *
446
     * @param  \Illuminate\Database\Query\Builder  $query
447
     * @param  array  $where
448
     * @return string
449
     */
450
    protected function whereMonth(Builder $query, $where)
451
    {
452
        return $this->dateBasedWhere('month', $query, $where);
453
    }
454
 
455
    /**
456
     * Compile a "where year" clause.
457
     *
458
     * @param  \Illuminate\Database\Query\Builder  $query
459
     * @param  array  $where
460
     * @return string
461
     */
462
    protected function whereYear(Builder $query, $where)
463
    {
464
        return $this->dateBasedWhere('year', $query, $where);
465
    }
466
 
467
    /**
468
     * Compile a date based where clause.
469
     *
470
     * @param  string  $type
471
     * @param  \Illuminate\Database\Query\Builder  $query
472
     * @param  array  $where
473
     * @return string
474
     */
475
    protected function dateBasedWhere($type, Builder $query, $where)
476
    {
477
        $value = $this->parameter($where['value']);
478
 
479
        return $type.'('.$this->wrap($where['column']).') '.$where['operator'].' '.$value;
480
    }
481
 
482
    /**
483
     * Compile a where clause comparing two columns.
484
     *
485
     * @param  \Illuminate\Database\Query\Builder  $query
486
     * @param  array  $where
487
     * @return string
488
     */
489
    protected function whereColumn(Builder $query, $where)
490
    {
491
        return $this->wrap($where['first']).' '.$where['operator'].' '.$this->wrap($where['second']);
492
    }
493
 
494
    /**
495
     * Compile a nested where clause.
496
     *
497
     * @param  \Illuminate\Database\Query\Builder  $query
498
     * @param  array  $where
499
     * @return string
500
     */
501
    protected function whereNested(Builder $query, $where)
502
    {
503
        // Here we will calculate what portion of the string we need to remove. If this
504
        // is a join clause query, we need to remove the "on" portion of the SQL and
505
        // if it is a normal query we need to take the leading "where" of queries.
506
        $offset = $query instanceof JoinClause ? 3 : 6;
507
 
508
        return '('.substr($this->compileWheres($where['query']), $offset).')';
509
    }
510
 
511
    /**
512
     * Compile a where condition with a sub-select.
513
     *
514
     * @param  \Illuminate\Database\Query\Builder  $query
515
     * @param  array  $where
516
     * @return string
517
     */
518
    protected function whereSub(Builder $query, $where)
519
    {
520
        $select = $this->compileSelect($where['query']);
521
 
522
        return $this->wrap($where['column']).' '.$where['operator']." ($select)";
523
    }
524
 
525
    /**
526
     * Compile a where exists clause.
527
     *
528
     * @param  \Illuminate\Database\Query\Builder  $query
529
     * @param  array  $where
530
     * @return string
531
     */
532
    protected function whereExists(Builder $query, $where)
533
    {
534
        return 'exists ('.$this->compileSelect($where['query']).')';
535
    }
536
 
537
    /**
538
     * Compile a where exists clause.
539
     *
540
     * @param  \Illuminate\Database\Query\Builder  $query
541
     * @param  array  $where
542
     * @return string
543
     */
544
    protected function whereNotExists(Builder $query, $where)
545
    {
546
        return 'not exists ('.$this->compileSelect($where['query']).')';
547
    }
548
 
549
    /**
550
     * Compile a where row values condition.
551
     *
552
     * @param  \Illuminate\Database\Query\Builder  $query
553
     * @param  array  $where
554
     * @return string
555
     */
556
    protected function whereRowValues(Builder $query, $where)
557
    {
558
        $columns = $this->columnize($where['columns']);
559
 
560
        $values = $this->parameterize($where['values']);
561
 
562
        return '('.$columns.') '.$where['operator'].' ('.$values.')';
563
    }
564
 
565
    /**
566
     * Compile a "where JSON boolean" clause.
567
     *
568
     * @param  \Illuminate\Database\Query\Builder  $query
569
     * @param  array  $where
570
     * @return string
571
     */
572
    protected function whereJsonBoolean(Builder $query, $where)
573
    {
574
        $column = $this->wrapJsonBooleanSelector($where['column']);
575
 
576
        $value = $this->wrapJsonBooleanValue(
577
            $this->parameter($where['value'])
578
        );
579
 
580
        return $column.' '.$where['operator'].' '.$value;
581
    }
582
 
583
    /**
584
     * Compile a "where JSON contains" clause.
585
     *
586
     * @param  \Illuminate\Database\Query\Builder  $query
587
     * @param  array  $where
588
     * @return string
589
     */
590
    protected function whereJsonContains(Builder $query, $where)
591
    {
592
        $not = $where['not'] ? 'not ' : '';
593
 
594
        return $not.$this->compileJsonContains(
595
            $where['column'],
596
            $this->parameter($where['value'])
597
        );
598
    }
599
 
600
    /**
601
     * Compile a "JSON contains" statement into SQL.
602
     *
603
     * @param  string  $column
604
     * @param  string  $value
605
     * @return string
606
     *
607
     * @throws \RuntimeException
608
     */
609
    protected function compileJsonContains($column, $value)
610
    {
611
        throw new RuntimeException('This database engine does not support JSON contains operations.');
612
    }
613
 
614
    /**
615
     * Prepare the binding for a "JSON contains" statement.
616
     *
617
     * @param  mixed  $binding
618
     * @return string
619
     */
620
    public function prepareBindingForJsonContains($binding)
621
    {
622
        return json_encode($binding);
623
    }
624
 
625
    /**
626
     * Compile a "where JSON contains key" clause.
627
     *
628
     * @param  \Illuminate\Database\Query\Builder  $query
629
     * @param  array  $where
630
     * @return string
631
     */
632
    protected function whereJsonContainsKey(Builder $query, $where)
633
    {
634
        $not = $where['not'] ? 'not ' : '';
635
 
636
        return $not.$this->compileJsonContainsKey(
637
            $where['column']
638
        );
639
    }
640
 
641
    /**
642
     * Compile a "JSON contains key" statement into SQL.
643
     *
644
     * @param  string  $column
645
     * @return string
646
     *
647
     * @throws \RuntimeException
648
     */
649
    protected function compileJsonContainsKey($column)
650
    {
651
        throw new RuntimeException('This database engine does not support JSON contains key operations.');
652
    }
653
 
654
    /**
655
     * Compile a "where JSON length" clause.
656
     *
657
     * @param  \Illuminate\Database\Query\Builder  $query
658
     * @param  array  $where
659
     * @return string
660
     */
661
    protected function whereJsonLength(Builder $query, $where)
662
    {
663
        return $this->compileJsonLength(
664
            $where['column'],
665
            $where['operator'],
666
            $this->parameter($where['value'])
667
        );
668
    }
669
 
670
    /**
671
     * Compile a "JSON length" statement into SQL.
672
     *
673
     * @param  string  $column
674
     * @param  string  $operator
675
     * @param  string  $value
676
     * @return string
677
     *
678
     * @throws \RuntimeException
679
     */
680
    protected function compileJsonLength($column, $operator, $value)
681
    {
682
        throw new RuntimeException('This database engine does not support JSON length operations.');
683
    }
684
 
685
    /**
686
     * Compile a "JSON value cast" statement into SQL.
687
     *
688
     * @param  string  $value
689
     * @return string
690
     */
691
    public function compileJsonValueCast($value)
692
    {
693
        return $value;
694
    }
695
 
696
    /**
697
     * Compile a "where fulltext" clause.
698
     *
699
     * @param  \Illuminate\Database\Query\Builder  $query
700
     * @param  array  $where
701
     * @return string
702
     */
703
    public function whereFullText(Builder $query, $where)
704
    {
705
        throw new RuntimeException('This database engine does not support fulltext search operations.');
706
    }
707
 
708
    /**
709
     * Compile the "group by" portions of the query.
710
     *
711
     * @param  \Illuminate\Database\Query\Builder  $query
712
     * @param  array  $groups
713
     * @return string
714
     */
715
    protected function compileGroups(Builder $query, $groups)
716
    {
717
        return 'group by '.$this->columnize($groups);
718
    }
719
 
720
    /**
721
     * Compile the "having" portions of the query.
722
     *
723
     * @param  \Illuminate\Database\Query\Builder  $query
724
     * @return string
725
     */
726
    protected function compileHavings(Builder $query)
727
    {
728
        return 'having '.$this->removeLeadingBoolean(collect($query->havings)->map(function ($having) {
729
            return $having['boolean'].' '.$this->compileHaving($having);
730
        })->implode(' '));
731
    }
732
 
733
    /**
734
     * Compile a single having clause.
735
     *
736
     * @param  array  $having
737
     * @return string
738
     */
739
    protected function compileHaving(array $having)
740
    {
741
        // If the having clause is "raw", we can just return the clause straight away
742
        // without doing any more processing on it. Otherwise, we will compile the
743
        // clause into SQL based on the components that make it up from builder.
744
        if ($having['type'] === 'Raw') {
745
            return $having['sql'];
746
        } elseif ($having['type'] === 'between') {
747
            return $this->compileHavingBetween($having);
748
        } elseif ($having['type'] === 'Null') {
749
            return $this->compileHavingNull($having);
750
        } elseif ($having['type'] === 'NotNull') {
751
            return $this->compileHavingNotNull($having);
752
        } elseif ($having['type'] === 'bit') {
753
            return $this->compileHavingBit($having);
754
        } elseif ($having['type'] === 'Nested') {
755
            return $this->compileNestedHavings($having);
756
        }
757
 
758
        return $this->compileBasicHaving($having);
759
    }
760
 
761
    /**
762
     * Compile a basic having clause.
763
     *
764
     * @param  array  $having
765
     * @return string
766
     */
767
    protected function compileBasicHaving($having)
768
    {
769
        $column = $this->wrap($having['column']);
770
 
771
        $parameter = $this->parameter($having['value']);
772
 
773
        return $column.' '.$having['operator'].' '.$parameter;
774
    }
775
 
776
    /**
777
     * Compile a "between" having clause.
778
     *
779
     * @param  array  $having
780
     * @return string
781
     */
782
    protected function compileHavingBetween($having)
783
    {
784
        $between = $having['not'] ? 'not between' : 'between';
785
 
786
        $column = $this->wrap($having['column']);
787
 
788
        $min = $this->parameter(head($having['values']));
789
 
790
        $max = $this->parameter(last($having['values']));
791
 
792
        return $column.' '.$between.' '.$min.' and '.$max;
793
    }
794
 
795
    /**
796
     * Compile a having null clause.
797
     *
798
     * @param  array  $having
799
     * @return string
800
     */
801
    protected function compileHavingNull($having)
802
    {
803
        $column = $this->wrap($having['column']);
804
 
805
        return $column.' is null';
806
    }
807
 
808
    /**
809
     * Compile a having not null clause.
810
     *
811
     * @param  array  $having
812
     * @return string
813
     */
814
    protected function compileHavingNotNull($having)
815
    {
816
        $column = $this->wrap($having['column']);
817
 
818
        return $column.' is not null';
819
    }
820
 
821
    /**
822
     * Compile a having clause involving a bit operator.
823
     *
824
     * @param  array  $having
825
     * @return string
826
     */
827
    protected function compileHavingBit($having)
828
    {
829
        $column = $this->wrap($having['column']);
830
 
831
        $parameter = $this->parameter($having['value']);
832
 
833
        return '('.$column.' '.$having['operator'].' '.$parameter.') != 0';
834
    }
835
 
836
    /**
837
     * Compile a nested having clause.
838
     *
839
     * @param  array  $having
840
     * @return string
841
     */
842
    protected function compileNestedHavings($having)
843
    {
844
        return '('.substr($this->compileHavings($having['query']), 7).')';
845
    }
846
 
847
    /**
848
     * Compile the "order by" portions of the query.
849
     *
850
     * @param  \Illuminate\Database\Query\Builder  $query
851
     * @param  array  $orders
852
     * @return string
853
     */
854
    protected function compileOrders(Builder $query, $orders)
855
    {
856
        if (! empty($orders)) {
857
            return 'order by '.implode(', ', $this->compileOrdersToArray($query, $orders));
858
        }
859
 
860
        return '';
861
    }
862
 
863
    /**
864
     * Compile the query orders to an array.
865
     *
866
     * @param  \Illuminate\Database\Query\Builder  $query
867
     * @param  array  $orders
868
     * @return array
869
     */
870
    protected function compileOrdersToArray(Builder $query, $orders)
871
    {
872
        return array_map(function ($order) {
873
            return $order['sql'] ?? $this->wrap($order['column']).' '.$order['direction'];
874
        }, $orders);
875
    }
876
 
877
    /**
878
     * Compile the random statement into SQL.
879
     *
880
     * @param  string|int  $seed
881
     * @return string
882
     */
883
    public function compileRandom($seed)
884
    {
885
        return 'RANDOM()';
886
    }
887
 
888
    /**
889
     * Compile the "limit" portions of the query.
890
     *
891
     * @param  \Illuminate\Database\Query\Builder  $query
892
     * @param  int  $limit
893
     * @return string
894
     */
895
    protected function compileLimit(Builder $query, $limit)
896
    {
897
        return 'limit '.(int) $limit;
898
    }
899
 
900
    /**
901
     * Compile the "offset" portions of the query.
902
     *
903
     * @param  \Illuminate\Database\Query\Builder  $query
904
     * @param  int  $offset
905
     * @return string
906
     */
907
    protected function compileOffset(Builder $query, $offset)
908
    {
909
        return 'offset '.(int) $offset;
910
    }
911
 
912
    /**
913
     * Compile the "union" queries attached to the main query.
914
     *
915
     * @param  \Illuminate\Database\Query\Builder  $query
916
     * @return string
917
     */
918
    protected function compileUnions(Builder $query)
919
    {
920
        $sql = '';
921
 
922
        foreach ($query->unions as $union) {
923
            $sql .= $this->compileUnion($union);
924
        }
925
 
926
        if (! empty($query->unionOrders)) {
927
            $sql .= ' '.$this->compileOrders($query, $query->unionOrders);
928
        }
929
 
930
        if (isset($query->unionLimit)) {
931
            $sql .= ' '.$this->compileLimit($query, $query->unionLimit);
932
        }
933
 
934
        if (isset($query->unionOffset)) {
935
            $sql .= ' '.$this->compileOffset($query, $query->unionOffset);
936
        }
937
 
938
        return ltrim($sql);
939
    }
940
 
941
    /**
942
     * Compile a single union statement.
943
     *
944
     * @param  array  $union
945
     * @return string
946
     */
947
    protected function compileUnion(array $union)
948
    {
949
        $conjunction = $union['all'] ? ' union all ' : ' union ';
950
 
951
        return $conjunction.$this->wrapUnion($union['query']->toSql());
952
    }
953
 
954
    /**
955
     * Wrap a union subquery in parentheses.
956
     *
957
     * @param  string  $sql
958
     * @return string
959
     */
960
    protected function wrapUnion($sql)
961
    {
962
        return '('.$sql.')';
963
    }
964
 
965
    /**
966
     * Compile a union aggregate query into SQL.
967
     *
968
     * @param  \Illuminate\Database\Query\Builder  $query
969
     * @return string
970
     */
971
    protected function compileUnionAggregate(Builder $query)
972
    {
973
        $sql = $this->compileAggregate($query, $query->aggregate);
974
 
975
        $query->aggregate = null;
976
 
977
        return $sql.' from ('.$this->compileSelect($query).') as '.$this->wrapTable('temp_table');
978
    }
979
 
980
    /**
981
     * Compile an exists statement into SQL.
982
     *
983
     * @param  \Illuminate\Database\Query\Builder  $query
984
     * @return string
985
     */
986
    public function compileExists(Builder $query)
987
    {
988
        $select = $this->compileSelect($query);
989
 
990
        return "select exists({$select}) as {$this->wrap('exists')}";
991
    }
992
 
993
    /**
994
     * Compile an insert statement into SQL.
995
     *
996
     * @param  \Illuminate\Database\Query\Builder  $query
997
     * @param  array  $values
998
     * @return string
999
     */
1000
    public function compileInsert(Builder $query, array $values)
1001
    {
1002
        // Essentially we will force every insert to be treated as a batch insert which
1003
        // simply makes creating the SQL easier for us since we can utilize the same
1004
        // basic routine regardless of an amount of records given to us to insert.
1005
        $table = $this->wrapTable($query->from);
1006
 
1007
        if (empty($values)) {
1008
            return "insert into {$table} default values";
1009
        }
1010
 
1011
        if (! is_array(reset($values))) {
1012
            $values = [$values];
1013
        }
1014
 
1015
        $columns = $this->columnize(array_keys(reset($values)));
1016
 
1017
        // We need to build a list of parameter place-holders of values that are bound
1018
        // to the query. Each insert should have the exact same number of parameter
1019
        // bindings so we will loop through the record and parameterize them all.
1020
        $parameters = collect($values)->map(function ($record) {
1021
            return '('.$this->parameterize($record).')';
1022
        })->implode(', ');
1023
 
1024
        return "insert into $table ($columns) values $parameters";
1025
    }
1026
 
1027
    /**
1028
     * Compile an insert ignore statement into SQL.
1029
     *
1030
     * @param  \Illuminate\Database\Query\Builder  $query
1031
     * @param  array  $values
1032
     * @return string
1033
     *
1034
     * @throws \RuntimeException
1035
     */
1036
    public function compileInsertOrIgnore(Builder $query, array $values)
1037
    {
1038
        throw new RuntimeException('This database engine does not support inserting while ignoring errors.');
1039
    }
1040
 
1041
    /**
1042
     * Compile an insert and get ID statement into SQL.
1043
     *
1044
     * @param  \Illuminate\Database\Query\Builder  $query
1045
     * @param  array  $values
1046
     * @param  string  $sequence
1047
     * @return string
1048
     */
1049
    public function compileInsertGetId(Builder $query, $values, $sequence)
1050
    {
1051
        return $this->compileInsert($query, $values);
1052
    }
1053
 
1054
    /**
1055
     * Compile an insert statement using a subquery into SQL.
1056
     *
1057
     * @param  \Illuminate\Database\Query\Builder  $query
1058
     * @param  array  $columns
1059
     * @param  string  $sql
1060
     * @return string
1061
     */
1062
    public function compileInsertUsing(Builder $query, array $columns, string $sql)
1063
    {
1064
        return "insert into {$this->wrapTable($query->from)} ({$this->columnize($columns)}) $sql";
1065
    }
1066
 
1067
    /**
1068
     * Compile an update statement into SQL.
1069
     *
1070
     * @param  \Illuminate\Database\Query\Builder  $query
1071
     * @param  array  $values
1072
     * @return string
1073
     */
1074
    public function compileUpdate(Builder $query, array $values)
1075
    {
1076
        $table = $this->wrapTable($query->from);
1077
 
1078
        $columns = $this->compileUpdateColumns($query, $values);
1079
 
1080
        $where = $this->compileWheres($query);
1081
 
1082
        return trim(
1083
            isset($query->joins)
1084
                ? $this->compileUpdateWithJoins($query, $table, $columns, $where)
1085
                : $this->compileUpdateWithoutJoins($query, $table, $columns, $where)
1086
        );
1087
    }
1088
 
1089
    /**
1090
     * Compile the columns for an update statement.
1091
     *
1092
     * @param  \Illuminate\Database\Query\Builder  $query
1093
     * @param  array  $values
1094
     * @return string
1095
     */
1096
    protected function compileUpdateColumns(Builder $query, array $values)
1097
    {
1098
        return collect($values)->map(function ($value, $key) {
1099
            return $this->wrap($key).' = '.$this->parameter($value);
1100
        })->implode(', ');
1101
    }
1102
 
1103
    /**
1104
     * Compile an update statement without joins into SQL.
1105
     *
1106
     * @param  \Illuminate\Database\Query\Builder  $query
1107
     * @param  string  $table
1108
     * @param  string  $columns
1109
     * @param  string  $where
1110
     * @return string
1111
     */
1112
    protected function compileUpdateWithoutJoins(Builder $query, $table, $columns, $where)
1113
    {
1114
        return "update {$table} set {$columns} {$where}";
1115
    }
1116
 
1117
    /**
1118
     * Compile an update statement with joins into SQL.
1119
     *
1120
     * @param  \Illuminate\Database\Query\Builder  $query
1121
     * @param  string  $table
1122
     * @param  string  $columns
1123
     * @param  string  $where
1124
     * @return string
1125
     */
1126
    protected function compileUpdateWithJoins(Builder $query, $table, $columns, $where)
1127
    {
1128
        $joins = $this->compileJoins($query, $query->joins);
1129
 
1130
        return "update {$table} {$joins} set {$columns} {$where}";
1131
    }
1132
 
1133
    /**
1134
     * Compile an "upsert" statement into SQL.
1135
     *
1136
     * @param  \Illuminate\Database\Query\Builder  $query
1137
     * @param  array  $values
1138
     * @param  array  $uniqueBy
1139
     * @param  array  $update
1140
     * @return string
1141
     *
1142
     * @throws \RuntimeException
1143
     */
1144
    public function compileUpsert(Builder $query, array $values, array $uniqueBy, array $update)
1145
    {
1146
        throw new RuntimeException('This database engine does not support upserts.');
1147
    }
1148
 
1149
    /**
1150
     * Prepare the bindings for an update statement.
1151
     *
1152
     * @param  array  $bindings
1153
     * @param  array  $values
1154
     * @return array
1155
     */
1156
    public function prepareBindingsForUpdate(array $bindings, array $values)
1157
    {
1158
        $cleanBindings = Arr::except($bindings, ['select', 'join']);
1159
 
1160
        return array_values(
1161
            array_merge($bindings['join'], $values, Arr::flatten($cleanBindings))
1162
        );
1163
    }
1164
 
1165
    /**
1166
     * Compile a delete statement into SQL.
1167
     *
1168
     * @param  \Illuminate\Database\Query\Builder  $query
1169
     * @return string
1170
     */
1171
    public function compileDelete(Builder $query)
1172
    {
1173
        $table = $this->wrapTable($query->from);
1174
 
1175
        $where = $this->compileWheres($query);
1176
 
1177
        return trim(
1178
            isset($query->joins)
1179
                ? $this->compileDeleteWithJoins($query, $table, $where)
1180
                : $this->compileDeleteWithoutJoins($query, $table, $where)
1181
        );
1182
    }
1183
 
1184
    /**
1185
     * Compile a delete statement without joins into SQL.
1186
     *
1187
     * @param  \Illuminate\Database\Query\Builder  $query
1188
     * @param  string  $table
1189
     * @param  string  $where
1190
     * @return string
1191
     */
1192
    protected function compileDeleteWithoutJoins(Builder $query, $table, $where)
1193
    {
1194
        return "delete from {$table} {$where}";
1195
    }
1196
 
1197
    /**
1198
     * Compile a delete statement with joins into SQL.
1199
     *
1200
     * @param  \Illuminate\Database\Query\Builder  $query
1201
     * @param  string  $table
1202
     * @param  string  $where
1203
     * @return string
1204
     */
1205
    protected function compileDeleteWithJoins(Builder $query, $table, $where)
1206
    {
1207
        $alias = last(explode(' as ', $table));
1208
 
1209
        $joins = $this->compileJoins($query, $query->joins);
1210
 
1211
        return "delete {$alias} from {$table} {$joins} {$where}";
1212
    }
1213
 
1214
    /**
1215
     * Prepare the bindings for a delete statement.
1216
     *
1217
     * @param  array  $bindings
1218
     * @return array
1219
     */
1220
    public function prepareBindingsForDelete(array $bindings)
1221
    {
1222
        return Arr::flatten(
1223
            Arr::except($bindings, 'select')
1224
        );
1225
    }
1226
 
1227
    /**
1228
     * Compile a truncate table statement into SQL.
1229
     *
1230
     * @param  \Illuminate\Database\Query\Builder  $query
1231
     * @return array
1232
     */
1233
    public function compileTruncate(Builder $query)
1234
    {
1235
        return ['truncate table '.$this->wrapTable($query->from) => []];
1236
    }
1237
 
1238
    /**
1239
     * Compile the lock into SQL.
1240
     *
1241
     * @param  \Illuminate\Database\Query\Builder  $query
1242
     * @param  bool|string  $value
1243
     * @return string
1244
     */
1245
    protected function compileLock(Builder $query, $value)
1246
    {
1247
        return is_string($value) ? $value : '';
1248
    }
1249
 
1250
    /**
1251
     * Determine if the grammar supports savepoints.
1252
     *
1253
     * @return bool
1254
     */
1255
    public function supportsSavepoints()
1256
    {
1257
        return true;
1258
    }
1259
 
1260
    /**
1261
     * Compile the SQL statement to define a savepoint.
1262
     *
1263
     * @param  string  $name
1264
     * @return string
1265
     */
1266
    public function compileSavepoint($name)
1267
    {
1268
        return 'SAVEPOINT '.$name;
1269
    }
1270
 
1271
    /**
1272
     * Compile the SQL statement to execute a savepoint rollback.
1273
     *
1274
     * @param  string  $name
1275
     * @return string
1276
     */
1277
    public function compileSavepointRollBack($name)
1278
    {
1279
        return 'ROLLBACK TO SAVEPOINT '.$name;
1280
    }
1281
 
1282
    /**
1283
     * Wrap the given JSON selector for boolean values.
1284
     *
1285
     * @param  string  $value
1286
     * @return string
1287
     */
1288
    protected function wrapJsonBooleanSelector($value)
1289
    {
1290
        return $this->wrapJsonSelector($value);
1291
    }
1292
 
1293
    /**
1294
     * Wrap the given JSON boolean value.
1295
     *
1296
     * @param  string  $value
1297
     * @return string
1298
     */
1299
    protected function wrapJsonBooleanValue($value)
1300
    {
1301
        return $value;
1302
    }
1303
 
1304
    /**
1305
     * Concatenate an array of segments, removing empties.
1306
     *
1307
     * @param  array  $segments
1308
     * @return string
1309
     */
1310
    protected function concatenate($segments)
1311
    {
1312
        return implode(' ', array_filter($segments, function ($value) {
1313
            return (string) $value !== '';
1314
        }));
1315
    }
1316
 
1317
    /**
1318
     * Remove the leading boolean from a statement.
1319
     *
1320
     * @param  string  $value
1321
     * @return string
1322
     */
1323
    protected function removeLeadingBoolean($value)
1324
    {
1325
        return preg_replace('/and |or /i', '', $value, 1);
1326
    }
1327
 
1328
    /**
1329
     * Get the grammar specific operators.
1330
     *
1331
     * @return array
1332
     */
1333
    public function getOperators()
1334
    {
1335
        return $this->operators;
1336
    }
1337
 
1338
    /**
1339
     * Get the grammar specific bitwise operators.
1340
     *
1341
     * @return array
1342
     */
1343
    public function getBitwiseOperators()
1344
    {
1345
        return $this->bitwiseOperators;
1346
    }
1347
}