Subversion-Projekte lars-tiefland.laravel_shop

Revision

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