1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace Yajra\Oci8\Query\Grammars; |
4
|
|
|
|
5
|
|
|
use Illuminate\Support\Str; |
6
|
|
|
use Yajra\Oci8\OracleReservedWords; |
7
|
|
|
use Illuminate\Database\Query\Builder; |
8
|
|
|
use Illuminate\Database\Query\Grammars\Grammar; |
9
|
|
|
use Illuminate\Database\Eloquent\Builder as EloquentBuilder; |
10
|
|
|
|
11
|
|
|
class OracleGrammar extends Grammar |
12
|
|
|
{ |
13
|
|
|
use OracleReservedWords; |
14
|
|
|
|
15
|
|
|
/** |
16
|
|
|
* The keyword identifier wrapper format. |
17
|
|
|
* |
18
|
|
|
* @var string |
19
|
|
|
*/ |
20
|
|
|
protected $wrapper = '%s'; |
21
|
|
|
|
22
|
|
|
/** |
23
|
|
|
* @var string |
24
|
|
|
*/ |
25
|
|
|
protected $schema_prefix = ''; |
26
|
|
|
|
27
|
|
|
/** |
28
|
|
|
* Compile an exists statement into SQL. |
29
|
|
|
* |
30
|
|
|
* @param \Illuminate\Database\Query\Builder $query |
31
|
|
|
* @return string |
32
|
|
|
*/ |
33
|
3 |
|
public function compileExists(Builder $query) |
34
|
|
|
{ |
35
|
3 |
|
$q = clone $query; |
36
|
3 |
|
$q->columns = []; |
37
|
3 |
|
$q->selectRaw('1 as "exists"') |
38
|
3 |
|
->whereRaw('rownum = 1'); |
39
|
|
|
|
40
|
3 |
|
return $this->compileSelect($q); |
41
|
|
|
} |
42
|
|
|
|
43
|
|
|
/** |
44
|
|
|
* Compile a select query into SQL. |
45
|
|
|
* |
46
|
|
|
* @param \Illuminate\Database\Query\Builder |
47
|
|
|
* @return string |
48
|
|
|
*/ |
49
|
159 |
|
public function compileSelect(Builder $query) |
50
|
|
|
{ |
51
|
159 |
|
if ($query->unions && $query->aggregate) { |
|
|
|
|
52
|
|
|
return $this->compileUnionAggregate($query); |
53
|
|
|
} |
54
|
|
|
|
55
|
159 |
|
// If the query does not have any columns set, we'll set the columns to the |
56
|
|
|
// * character to just get all of the columns from the database. Then we |
57
|
|
|
// can build the query and concatenate all the pieces together as one. |
58
|
|
|
$original = $query->columns; |
59
|
|
|
|
60
|
159 |
|
if (is_null($query->columns)) { |
61
|
12 |
|
$query->columns = ['*']; |
62
|
|
|
} |
63
|
|
|
|
64
|
150 |
|
$components = $this->compileComponents($query); |
65
|
|
|
|
66
|
|
|
// To compile the query, we'll spin through each component of the query and |
67
|
|
|
// see if that component exists. If it does we'll just call the compiler |
68
|
|
|
// function for the component which is responsible for making the SQL. |
69
|
|
|
$sql = trim($this->concatenate($components)); |
70
|
|
|
|
71
|
|
|
// If an offset is present on the query, we will need to wrap the query in |
72
|
159 |
|
// a big "ANSI" offset syntax block. This is very nasty compared to the |
73
|
|
|
// other database systems but is necessary for implementing features. |
74
|
159 |
|
if ($this->isPaginationable($query, $components)) { |
75
|
|
|
return $this->compileAnsiOffset($query, $components); |
76
|
|
|
} |
77
|
|
|
|
78
|
|
|
if ($query->unions) { |
|
|
|
|
79
|
|
|
$sql = $this->wrapUnion($sql).' '.$this->compileUnions($query); |
80
|
|
|
} |
81
|
|
|
|
82
|
|
|
$query->columns = $original; |
83
|
|
|
|
84
|
12 |
|
return $sql; |
85
|
|
|
} |
86
|
12 |
|
|
87
|
|
|
/** |
88
|
12 |
|
* @param Builder $query |
89
|
|
|
* @param array $components |
90
|
|
|
* @return bool |
91
|
|
|
*/ |
92
|
|
|
protected function isPaginationable(Builder $query, array $components) |
93
|
12 |
|
{ |
94
|
|
|
return ($query->limit > 0 || $query->offset > 0) && ! array_key_exists('lock', $components); |
95
|
12 |
|
} |
96
|
|
|
|
97
|
|
|
/** |
98
|
|
|
* Create a full ANSI offset clause for the query. |
99
|
|
|
* |
100
|
|
|
* @param \Illuminate\Database\Query\Builder $query |
101
|
|
|
* @param array $components |
102
|
|
|
* @return string |
103
|
|
|
*/ |
104
|
12 |
|
protected function compileAnsiOffset(Builder $query, $components) |
105
|
|
|
{ |
106
|
12 |
|
// Improved response time with FIRST_ROWS(n) hint for ORDER BY queries |
107
|
|
|
if ($query->getConnection()->getConfig('server_version') == '12c') { |
108
|
12 |
|
$components['columns'] = str_replace('select', "select /*+ FIRST_ROWS({$query->limit}) */", $components['columns']); |
109
|
6 |
|
$offset = $query->offset ?: 0; |
110
|
|
|
$limit = $query->limit; |
111
|
|
|
$components['limit'] = "offset $offset rows fetch next $limit rows only"; |
112
|
6 |
|
|
113
|
6 |
|
return $this->concatenate($components); |
114
|
|
|
} |
115
|
6 |
|
|
116
|
|
|
$constraint = $this->compileRowConstraint($query); |
117
|
|
|
|
118
|
3 |
|
$sql = $this->concatenate($components); |
119
|
|
|
|
120
|
|
|
// We are now ready to build the final SQL query so we'll create a common table |
121
|
|
|
// expression from the query and get the records with row numbers within our |
122
|
|
|
// given limit and offset value that we just put on as a query constraint. |
123
|
|
|
$temp = $this->compileTableExpression($sql, $constraint, $query); |
124
|
|
|
|
125
|
|
|
return $temp; |
126
|
|
|
} |
127
|
|
|
|
128
|
|
|
/** |
129
|
12 |
|
* Compile the limit / offset row constraint for a query. |
130
|
|
|
* |
131
|
12 |
|
* @param \Illuminate\Database\Query\Builder $query |
132
|
6 |
|
* @return string |
133
|
|
|
*/ |
134
|
9 |
|
protected function compileRowConstraint($query) |
135
|
|
|
{ |
136
|
|
|
$start = $query->offset + 1; |
137
|
|
|
$finish = $query->offset + $query->limit; |
138
|
|
|
|
139
|
|
|
if ($query->limit == 1 && is_null($query->offset)) { |
140
|
|
|
return '= 1'; |
141
|
|
|
} |
142
|
|
|
|
143
|
|
|
if ($query->offset && is_null($query->limit)) { |
144
|
3 |
|
return ">= {$start}"; |
145
|
|
|
} |
146
|
3 |
|
|
147
|
|
|
return "between {$start} and {$finish}"; |
148
|
|
|
} |
149
|
|
|
|
150
|
|
|
/** |
151
|
|
|
* Compile a common table expression for a query. |
152
|
|
|
* |
153
|
|
|
* @param string $sql |
154
|
|
|
* @param string $constraint |
155
|
201 |
|
* @param Builder $query |
156
|
|
|
* @return string |
157
|
201 |
|
*/ |
158
|
|
|
protected function compileTableExpression($sql, $constraint, $query) |
159
|
|
|
{ |
160
|
|
|
if ($query->limit == 1 && is_null($query->offset)) { |
161
|
201 |
|
return "select * from ({$sql}) where rownum {$constraint}"; |
162
|
|
|
} |
163
|
|
|
|
164
|
|
|
return "select t2.* from ( select rownum AS \"rn\", t1.* from ({$sql}) t1 ) t2 where t2.\"rn\" {$constraint}"; |
165
|
201 |
|
} |
166
|
201 |
|
|
167
|
201 |
|
/** |
168
|
|
|
* Compile a truncate table statement into SQL. |
169
|
|
|
* |
170
|
|
|
* @param \Illuminate\Database\Query\Builder $query |
171
|
201 |
|
* @return array |
172
|
|
|
*/ |
173
|
|
|
public function compileTruncate(Builder $query) |
174
|
|
|
{ |
175
|
|
|
return ['truncate table ' . $this->wrapTable($query->from) => []]; |
176
|
|
|
} |
177
|
|
|
|
178
|
|
|
/** |
179
|
201 |
|
* Wrap a value in keyword identifiers. |
180
|
|
|
* |
181
|
201 |
|
* Override due to laravel's stringify integers. |
182
|
|
|
* |
183
|
|
|
* @param \Illuminate\Database\Query\Expression|string $value |
184
|
|
|
* @param bool $prefixAlias |
185
|
|
|
* @return string |
186
|
|
|
*/ |
187
|
|
|
public function wrap($value, $prefixAlias = false) |
188
|
|
|
{ |
189
|
|
|
if (is_int($value) || is_float($value)) { |
190
|
|
|
return $value; |
191
|
|
|
} |
192
|
|
|
|
193
|
|
|
return parent::wrap($value, $prefixAlias); |
194
|
|
|
} |
195
|
|
|
|
196
|
|
|
/** |
197
|
|
|
* Wrap a table in keyword identifiers. |
198
|
|
|
* |
199
|
|
|
* @param \Illuminate\Database\Query\Expression|string $table |
200
|
201 |
|
* @return string |
201
|
|
|
*/ |
202
|
201 |
|
public function wrapTable($table) |
203
|
123 |
|
{ |
204
|
|
|
if ($this->isExpression($table)) { |
205
|
|
|
return $this->getValue($table); |
|
|
|
|
206
|
201 |
|
} |
207
|
|
|
|
208
|
201 |
|
if (strpos(strtolower($table), ' as ') !== false) { |
209
|
|
|
$table = str_replace(' as ', ' ', strtolower($table)); |
210
|
|
|
} |
211
|
|
|
|
212
|
|
|
$tableName = $this->wrap($this->tablePrefix . $table, true); |
213
|
|
|
$segments = explode(' ', $table); |
214
|
|
|
if (count($segments) > 1) { |
215
|
|
|
$tableName = $this->wrap($this->tablePrefix . $segments[0]) . ' ' . $segments[1]; |
216
|
|
|
} |
217
|
|
|
|
218
|
|
|
return $this->getSchemaPrefix() . $tableName; |
219
|
6 |
|
} |
220
|
|
|
|
221
|
6 |
|
/** |
222
|
|
|
* Return the schema prefix. |
223
|
|
|
* |
224
|
|
|
* @return string |
225
|
6 |
|
*/ |
226
|
|
|
public function getSchemaPrefix() |
227
|
6 |
|
{ |
228
|
|
|
return ! empty($this->schema_prefix) ? $this->wrapValue($this->schema_prefix) . '.' : ''; |
229
|
|
|
} |
230
|
|
|
|
231
|
|
|
/** |
232
|
|
|
* Set the schema prefix. |
233
|
|
|
* |
234
|
6 |
|
* @param string $prefix |
235
|
|
|
*/ |
236
|
|
|
public function setSchemaPrefix($prefix) |
237
|
|
|
{ |
238
|
|
|
$this->schema_prefix = $prefix; |
239
|
|
|
} |
240
|
|
|
|
241
|
|
|
/** |
242
|
|
|
* Wrap a single string in keyword identifiers. |
243
|
|
|
* |
244
|
15 |
|
* @param string $value |
245
|
|
|
* @return string |
246
|
|
|
*/ |
247
|
|
|
protected function wrapValue($value) |
248
|
|
|
{ |
249
|
15 |
|
if ($value === '*') { |
250
|
|
|
return $value; |
251
|
15 |
|
} |
252
|
6 |
|
|
253
|
4 |
|
$value = Str::upper($value); |
254
|
|
|
|
255
|
15 |
|
return '"' . str_replace('"', '""', $value) . '"'; |
256
|
|
|
} |
257
|
|
|
|
258
|
|
|
/** |
259
|
|
|
* Compile an insert and get ID statement into SQL. |
260
|
15 |
|
* |
261
|
|
|
* @param \Illuminate\Database\Query\Builder $query |
262
|
15 |
|
* @param array $values |
263
|
|
|
* @param string $sequence |
264
|
15 |
|
* @return string |
265
|
3 |
|
*/ |
266
|
3 |
|
public function compileInsertGetId(Builder $query, $values, $sequence = 'id') |
267
|
3 |
|
{ |
268
|
3 |
|
if (empty($sequence)) { |
269
|
2 |
|
$sequence = 'id'; |
270
|
3 |
|
} |
271
|
|
|
|
272
|
3 |
|
$backtrace = debug_backtrace(DEBUG_BACKTRACE_PROVIDE_OBJECT, 4)[2]['object']; |
273
|
|
|
|
274
|
12 |
|
if ($backtrace instanceof EloquentBuilder) { |
275
|
|
|
$model = $backtrace->getModel(); |
276
|
12 |
|
if ($model->sequence && ! isset($values[$model->getKeyName()]) && $model->incrementing) { |
|
|
|
|
277
|
|
|
$values[$sequence] = null; |
278
|
|
|
} |
279
|
|
|
} |
280
|
|
|
|
281
|
|
|
return $this->compileInsert($query, $values) . ' returning ' . $this->wrap($sequence) . ' into ?'; |
282
|
|
|
} |
283
|
|
|
|
284
|
|
|
/** |
285
|
|
|
* Compile an insert statement into SQL. |
286
|
|
|
* |
287
|
|
|
* @param \Illuminate\Database\Query\Builder $query |
288
|
6 |
|
* @param array $values |
289
|
|
|
* @return string |
290
|
6 |
|
*/ |
291
|
|
|
public function compileInsert(Builder $query, array $values) |
292
|
|
|
{ |
293
|
|
|
// Essentially we will force every insert to be treated as a batch insert which |
294
|
6 |
|
// simply makes creating the SQL easier for us since we can utilize the same |
295
|
|
|
// basic routine regardless of an amount of records given to us to insert. |
296
|
6 |
|
$table = $this->wrapTable($query->from); |
297
|
6 |
|
|
298
|
4 |
|
if (! is_array(reset($values))) { |
299
|
|
|
$values = [$values]; |
300
|
6 |
|
} |
301
|
6 |
|
|
302
|
4 |
|
$columns = $this->columnize(array_keys(reset($values))); |
303
|
|
|
|
304
|
6 |
|
// We need to build a list of parameter place-holders of values that are bound |
305
|
6 |
|
// to the query. Each insert should have the exact same amount of parameter |
306
|
6 |
|
// bindings so we can just go off the first list of values in this array. |
307
|
|
|
$parameters = $this->parameterize(reset($values)); |
308
|
6 |
|
|
309
|
6 |
|
$value = array_fill(0, count($values), "($parameters)"); |
310
|
|
|
|
311
|
6 |
|
if (count($value) > 1) { |
312
|
6 |
|
$insertQueries = []; |
313
|
|
|
foreach ($value as $parameter) { |
314
|
6 |
|
$parameter = (str_replace(['(', ')'], '', $parameter)); |
315
|
6 |
|
$insertQueries[] = 'select ' . $parameter . ' from dual '; |
316
|
|
|
} |
317
|
6 |
|
$parameters = implode('union all ', $insertQueries); |
318
|
|
|
|
319
|
|
|
return "insert into $table ($columns) $parameters"; |
320
|
|
|
} |
321
|
|
|
$parameters = implode(', ', $value); |
322
|
|
|
|
323
|
|
|
return "insert into $table ($columns) values $parameters"; |
324
|
|
|
} |
325
|
|
|
|
326
|
|
|
/** |
327
|
|
|
* Compile an insert with blob field statement into SQL. |
328
|
|
|
* |
329
|
6 |
|
* @param \Illuminate\Database\Query\Builder $query |
330
|
|
|
* @param array $values |
331
|
6 |
|
* @param array $binaries |
332
|
|
|
* @param string $sequence |
333
|
|
|
* @return string |
334
|
|
|
*/ |
335
|
|
|
public function compileInsertLob(Builder $query, $values, $binaries, $sequence = 'id') |
336
|
6 |
|
{ |
337
|
|
|
if (empty($sequence)) { |
338
|
6 |
|
$sequence = 'id'; |
339
|
3 |
|
} |
340
|
4 |
|
|
341
|
|
|
$table = $this->wrapTable($query->from); |
342
|
6 |
|
|
343
|
|
|
if (! is_array(reset($values))) { |
344
|
|
|
$values = [$values]; |
345
|
6 |
|
} |
346
|
6 |
|
|
347
|
4 |
|
if (! is_array(reset($binaries))) { |
348
|
6 |
|
$binaries = [$binaries]; |
349
|
6 |
|
} |
350
|
|
|
|
351
|
|
|
$columns = $this->columnize(array_keys(reset($values))); |
352
|
6 |
|
$binaryColumns = $this->columnize(array_keys(reset($binaries))); |
353
|
6 |
|
$columns .= (empty($columns) ? '' : ', ') . $binaryColumns; |
354
|
6 |
|
|
355
|
4 |
|
$parameters = $this->parameterize(reset($values)); |
356
|
|
|
$binaryParameters = $this->parameterize(reset($binaries)); |
357
|
|
|
|
358
|
6 |
|
$value = array_fill(0, count($values), "$parameters"); |
359
|
6 |
|
$binaryValue = array_fill(0, count($binaries), str_replace('?', 'EMPTY_BLOB()', $binaryParameters)); |
360
|
4 |
|
|
361
|
|
|
$value = array_merge($value, $binaryValue); |
362
|
|
|
$parameters = implode(', ', array_filter($value)); |
363
|
|
|
|
364
|
|
|
return "insert into $table ($columns) values ($parameters) returning " . $binaryColumns . ', ' . $this->wrap($sequence) . ' into ' . $binaryParameters . ', ?'; |
365
|
6 |
|
} |
366
|
|
|
|
367
|
|
|
/** |
368
|
6 |
|
* Compile an update statement into SQL. |
369
|
|
|
* |
370
|
|
|
* @param \Illuminate\Database\Query\Builder $query |
371
|
|
|
* @param array $values |
372
|
|
|
* @param array $binaries |
373
|
|
|
* @param string $sequence |
374
|
6 |
|
* @return string |
375
|
|
|
*/ |
376
|
6 |
|
public function compileUpdateLob(Builder $query, array $values, array $binaries, $sequence = 'id') |
377
|
|
|
{ |
378
|
|
|
$table = $this->wrapTable($query->from); |
379
|
|
|
|
380
|
|
|
// Each one of the columns in the update statements needs to be wrapped in the |
381
|
|
|
// keyword identifiers, also a place-holder needs to be created for each of |
382
|
|
|
// the values in the list of bindings so we can make the sets statements. |
383
|
|
|
$columns = []; |
384
|
|
|
|
385
|
|
|
foreach ($values as $key => $value) { |
386
|
3 |
|
$columns[] = $this->wrap($key) . ' = ' . $this->parameter($value); |
387
|
|
|
} |
388
|
3 |
|
|
389
|
|
|
$columns = implode(', ', $columns); |
390
|
|
|
|
391
|
|
|
// set blob variables |
392
|
3 |
|
if (! is_array(reset($binaries))) { |
393
|
3 |
|
$binaries = [$binaries]; |
394
|
|
|
} |
395
|
|
|
$binaryColumns = $this->columnize(array_keys(reset($binaries))); |
396
|
|
|
$binaryParameters = $this->parameterize(reset($binaries)); |
397
|
|
|
|
398
|
|
|
// create EMPTY_BLOB sql for each binary |
399
|
|
|
$binarySql = []; |
400
|
|
|
foreach ((array) $binaryColumns as $binary) { |
401
|
|
|
$binarySql[] = "$binary = EMPTY_BLOB()"; |
402
|
|
|
} |
403
|
|
|
|
404
|
|
|
// prepare binary SQLs |
405
|
|
|
if (count($binarySql)) { |
406
|
12 |
|
$binarySql = (empty($columns) ? '' : ', ') . implode(',', $binarySql); |
407
|
|
|
} |
408
|
12 |
|
|
409
|
|
|
// If the query has any "join" clauses, we will setup the joins on the builder |
410
|
|
|
// and compile them so we can attach them to this update, as update queries |
411
|
|
|
// can get join statements to attach to other tables when they're needed. |
412
|
|
|
$joins = ''; |
413
|
|
|
if (isset($query->joins)) { |
414
|
|
|
$joins = ' ' . $this->compileJoins($query, $query->joins); |
415
|
|
|
} |
416
|
|
|
|
417
|
|
|
// Of course, update queries may also be constrained by where clauses so we'll |
418
|
3 |
|
// need to compile the where clauses and attach it to the query so only the |
419
|
|
|
// intended records are updated by the SQL statements we generate to run. |
420
|
3 |
|
$where = $this->compileWheres($query); |
421
|
|
|
|
422
|
|
|
return "update {$table}{$joins} set $columns$binarySql $where returning " . $binaryColumns . ', ' . $this->wrap($sequence) . ' into ' . $binaryParameters . ', ?'; |
423
|
|
|
} |
424
|
|
|
|
425
|
|
|
/** |
426
|
|
|
* Compile the lock into SQL. |
427
|
|
|
* |
428
|
|
|
* @param \Illuminate\Database\Query\Builder $query |
429
|
|
|
* @param bool|string $value |
430
|
3 |
|
* @return string |
431
|
|
|
*/ |
432
|
3 |
|
protected function compileLock(Builder $query, $value) |
433
|
|
|
{ |
434
|
3 |
|
if (is_string($value)) { |
435
|
|
|
return $value; |
436
|
|
|
} |
437
|
|
|
|
438
|
|
|
if ($value) { |
439
|
|
|
return 'for update'; |
440
|
|
|
} |
441
|
|
|
|
442
|
|
|
return ''; |
443
|
|
|
} |
444
|
|
|
|
445
|
9 |
|
/** |
446
|
|
|
* Compile the "limit" portions of the query. |
447
|
9 |
|
* |
448
|
|
|
* @param \Illuminate\Database\Query\Builder $query |
449
|
9 |
|
* @param int $limit |
450
|
|
|
* @return string |
451
|
|
|
*/ |
452
|
|
|
protected function compileLimit(Builder $query, $limit) |
453
|
|
|
{ |
454
|
|
|
return ''; |
455
|
|
|
} |
456
|
|
|
|
457
|
|
|
/** |
458
|
|
|
* Compile the "offset" portions of the query. |
459
|
|
|
* |
460
|
|
|
* @param \Illuminate\Database\Query\Builder $query |
461
|
|
|
* @param int $offset |
462
|
|
|
* @return string |
463
|
|
|
*/ |
464
|
|
|
protected function compileOffset(Builder $query, $offset) |
465
|
|
|
{ |
466
|
|
|
return ''; |
467
|
|
|
} |
468
|
|
|
|
469
|
|
|
/** |
470
|
|
|
* Compile a "where date" clause. |
471
|
|
|
* |
472
|
|
|
* @param \Illuminate\Database\Query\Builder $query |
473
|
|
|
* @param array $where |
474
|
|
|
* @return string |
475
|
|
|
*/ |
476
|
|
|
protected function whereDate(Builder $query, $where) |
477
|
|
|
{ |
478
|
|
|
$value = $this->parameter($where['value']); |
479
|
|
|
|
480
|
|
|
return "trunc({$this->wrap($where['column'])}) {$where['operator']} $value"; |
481
|
|
|
} |
482
|
|
|
|
483
|
|
|
/** |
484
|
|
|
* Compile a date based where clause. |
485
|
|
|
* |
486
|
|
|
* @param string $type |
487
|
|
|
* @param \Illuminate\Database\Query\Builder $query |
488
|
|
|
* @param array $where |
489
|
|
|
* @return string |
490
|
|
|
*/ |
491
|
|
|
protected function dateBasedWhere($type, Builder $query, $where) |
492
|
|
|
{ |
493
|
|
|
$value = $this->parameter($where['value']); |
494
|
|
|
|
495
|
|
|
return "extract ($type from {$this->wrap($where['column'])}) {$where['operator']} $value"; |
496
|
|
|
} |
497
|
|
|
|
498
|
|
|
/** |
499
|
|
|
* Compile a "where not in raw" clause. |
500
|
|
|
* |
501
|
|
|
* For safety, whereIntegerInRaw ensures this method is only used with integer values. |
502
|
|
|
* |
503
|
|
|
* @param \Illuminate\Database\Query\Builder $query |
504
|
|
|
* @param array $where |
505
|
|
|
* @return string |
506
|
|
|
*/ |
507
|
|
View Code Duplication |
protected function whereNotInRaw(Builder $query, $where) |
508
|
|
|
{ |
509
|
|
|
if (! empty($where['values'])) { |
510
|
|
|
if (is_array($where['values']) && count($where['values']) > 1000) { |
511
|
|
|
return $this->resolveClause($where['column'], $where['values'], 'not in'); |
512
|
|
|
} else { |
513
|
|
|
return $this->wrap($where['column']).' not in ('.implode(', ', $where['values']).')'; |
514
|
|
|
} |
515
|
|
|
} |
516
|
|
|
|
517
|
|
|
return '1 = 1'; |
518
|
|
|
} |
519
|
|
|
|
520
|
|
|
/** |
521
|
|
|
* Compile a "where in raw" clause. |
522
|
|
|
* |
523
|
|
|
* For safety, whereIntegerInRaw ensures this method is only used with integer values. |
524
|
|
|
* |
525
|
|
|
* @param \Illuminate\Database\Query\Builder $query |
526
|
|
|
* @param array $where |
527
|
|
|
* @return string |
528
|
|
|
*/ |
529
|
|
View Code Duplication |
protected function whereInRaw(Builder $query, $where) |
530
|
|
|
{ |
531
|
|
|
if (! empty($where['values'])) { |
532
|
|
|
if (is_array($where['values']) && count($where['values']) > 1000) { |
533
|
|
|
return $this->resolveClause($where['column'], $where['values'], 'in'); |
534
|
|
|
} else { |
535
|
|
|
return $this->wrap($where['column']).' in ('.implode(', ', $where['values']).')'; |
536
|
|
|
} |
537
|
|
|
} |
538
|
|
|
|
539
|
|
|
return '0 = 1'; |
540
|
|
|
} |
541
|
|
|
|
542
|
|
|
private function resolveClause($column, $values, $type) |
543
|
|
|
{ |
544
|
|
|
$chunks = array_chunk($values, 1000); |
545
|
|
|
$whereClause = ''; |
546
|
|
|
$i=0; |
547
|
|
|
$type = $this->wrap($column) . ' '.$type.' '; |
548
|
|
|
foreach ($chunks as $ch) { |
549
|
|
|
if ($i > 0) { |
550
|
|
|
$type = ' or '. $this->wrap($column) . ' ' . $type . ' '; |
551
|
|
|
} |
552
|
|
|
$whereClause .= $type . '('.implode(', ', $ch).')'; |
553
|
|
|
$i++; |
554
|
|
|
} |
555
|
|
|
|
556
|
|
|
return '(' . $whereClause . ')'; |
557
|
|
|
} |
558
|
|
|
} |
559
|
|
|
|
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.
Consider making the comparison explicit by using
empty(..)
or! empty(...)
instead.