PluginProbe ʕ •ᴥ•ʔ
Independent Analytics – WordPress Analytics Plugin / 2.2.0
Independent Analytics – WordPress Analytics Plugin v2.2.0
2.15.5 2.15.4 2.15.3 2.15.2 2.15.1 2.15.0 2.14.10 trunk 1.1 1.10 1.10.1 1.11 1.12 1.13 1.14 1.15 1.16 1.17 1.17.1 1.17.2 1.17.3 1.17.4 1.18 1.18.1 1.19.0 1.19.1 1.2 1.20.0 1.21.0 1.22.0 1.22.1 1.23.0 1.23.1 1.24.0 1.24.1 1.25.0 1.25.1 1.26.0 1.27.0 1.28.0 1.28.1 1.28.2 1.28.3 1.29.0 1.3 1.30.0 1.30.1 1.4 1.5 1.6 1.7 1.8 1.9 2.0.0 2.0.1 2.1.4 2.1.5 2.1.6 2.10.0 2.10.1 2.10.2 2.10.3 2.10.4 2.11.0 2.11.1 2.11.10 2.11.2 2.11.3 2.11.4 2.11.5 2.11.6 2.11.7 2.11.8 2.11.9 2.12.0 2.12.1 2.12.2 2.13.1 2.13.2 2.13.5 2.13.6 2.14.0 2.14.1 2.14.2 2.14.4 2.14.6 2.14.7 2.14.8 2.14.9 2.2.0 2.2.1 2.3.1 2.3.2 2.4.2 2.4.3 2.5.0 2.5.1 2.6.0 2.6.1 2.6.2 2.6.3 2.6.4 2.7.0 2.7.1 2.7.2 2.7.3 2.8.2 2.8.3 2.8.4 2.8.5 2.8.6 2.8.7 2.8.8 2.8.9 2.9.2 2.9.3 2.9.4 2.9.5 2.9.6 2.9.7
independent-analytics / vendor / illuminate / database / Query / Grammars / PostgresGrammar.php
independent-analytics / vendor / illuminate / database / Query / Grammars Last commit date
Grammar.php 2 years ago MySqlGrammar.php 2 years ago PostgresGrammar.php 2 years ago SQLiteGrammar.php 2 years ago SqlServerGrammar.php 2 years ago
PostgresGrammar.php
497 lines
1 <?php
2
3 namespace IAWP_SCOPED\Illuminate\Database\Query\Grammars;
4
5 use IAWP_SCOPED\Illuminate\Database\Query\Builder;
6 use IAWP_SCOPED\Illuminate\Support\Arr;
7 use IAWP_SCOPED\Illuminate\Support\Str;
8 /** @internal */
9 class PostgresGrammar extends Grammar
10 {
11 /**
12 * All of the available clause operators.
13 *
14 * @var string[]
15 */
16 protected $operators = ['=', '<', '>', '<=', '>=', '<>', '!=', 'like', 'not like', 'between', 'ilike', 'not ilike', '~', '&', '|', '#', '<<', '>>', '<<=', '>>=', '&&', '@>', '<@', '?', '?|', '?&', '||', '-', '@?', '@@', '#-', 'is distinct from', 'is not distinct from'];
17 /**
18 * The grammar specific bitwise operators.
19 *
20 * @var array
21 */
22 protected $bitwiseOperators = ['~', '&', '|', '#', '<<', '>>', '<<=', '>>='];
23 /**
24 * {@inheritdoc}
25 *
26 * @param \Illuminate\Database\Query\Builder $query
27 * @param array $where
28 * @return string
29 */
30 protected function whereBasic(Builder $query, $where)
31 {
32 if (Str::contains(\strtolower($where['operator']), 'like')) {
33 return \sprintf('%s::text %s %s', $this->wrap($where['column']), $where['operator'], $this->parameter($where['value']));
34 }
35 return parent::whereBasic($query, $where);
36 }
37 /**
38 * {@inheritdoc}
39 *
40 * @param \Illuminate\Database\Query\Builder $query
41 * @param array $where
42 * @return string
43 */
44 protected function whereBitwise(Builder $query, $where)
45 {
46 $value = $this->parameter($where['value']);
47 $operator = \str_replace('?', '??', $where['operator']);
48 return '(' . $this->wrap($where['column']) . ' ' . $operator . ' ' . $value . ')::bool';
49 }
50 /**
51 * Compile a "where date" clause.
52 *
53 * @param \Illuminate\Database\Query\Builder $query
54 * @param array $where
55 * @return string
56 */
57 protected function whereDate(Builder $query, $where)
58 {
59 $value = $this->parameter($where['value']);
60 return $this->wrap($where['column']) . '::date ' . $where['operator'] . ' ' . $value;
61 }
62 /**
63 * Compile a "where time" clause.
64 *
65 * @param \Illuminate\Database\Query\Builder $query
66 * @param array $where
67 * @return string
68 */
69 protected function whereTime(Builder $query, $where)
70 {
71 $value = $this->parameter($where['value']);
72 return $this->wrap($where['column']) . '::time ' . $where['operator'] . ' ' . $value;
73 }
74 /**
75 * Compile a date based where clause.
76 *
77 * @param string $type
78 * @param \Illuminate\Database\Query\Builder $query
79 * @param array $where
80 * @return string
81 */
82 protected function dateBasedWhere($type, Builder $query, $where)
83 {
84 $value = $this->parameter($where['value']);
85 return 'extract(' . $type . ' from ' . $this->wrap($where['column']) . ') ' . $where['operator'] . ' ' . $value;
86 }
87 /**
88 * Compile a "where fulltext" clause.
89 *
90 * @param \Illuminate\Database\Query\Builder $query
91 * @param array $where
92 * @return string
93 */
94 public function whereFullText(Builder $query, $where)
95 {
96 $language = $where['options']['language'] ?? 'english';
97 if (!\in_array($language, $this->validFullTextLanguages())) {
98 $language = 'english';
99 }
100 $columns = \IAWP_SCOPED\collect($where['columns'])->map(function ($column) use($language) {
101 return "to_tsvector('{$language}', {$this->wrap($column)})";
102 })->implode(' || ');
103 $mode = 'plainto_tsquery';
104 if (($where['options']['mode'] ?? []) === 'phrase') {
105 $mode = 'phraseto_tsquery';
106 }
107 if (($where['options']['mode'] ?? []) === 'websearch') {
108 $mode = 'websearch_to_tsquery';
109 }
110 return "({$columns}) @@ {$mode}('{$language}', {$this->parameter($where['value'])})";
111 }
112 /**
113 * Get an array of valid full text languages.
114 *
115 * @return array
116 */
117 protected function validFullTextLanguages()
118 {
119 return ['simple', 'arabic', 'danish', 'dutch', 'english', 'finnish', 'french', 'german', 'hungarian', 'indonesian', 'irish', 'italian', 'lithuanian', 'nepali', 'norwegian', 'portuguese', 'romanian', 'russian', 'spanish', 'swedish', 'tamil', 'turkish'];
120 }
121 /**
122 * Compile the "select *" portion of the query.
123 *
124 * @param \Illuminate\Database\Query\Builder $query
125 * @param array $columns
126 * @return string|null
127 */
128 protected function compileColumns(Builder $query, $columns)
129 {
130 // If the query is actually performing an aggregating select, we will let that
131 // compiler handle the building of the select clauses, as it will need some
132 // more syntax that is best handled by that function to keep things neat.
133 if (!\is_null($query->aggregate)) {
134 return;
135 }
136 if (\is_array($query->distinct)) {
137 $select = 'select distinct on (' . $this->columnize($query->distinct) . ') ';
138 } elseif ($query->distinct) {
139 $select = 'select distinct ';
140 } else {
141 $select = 'select ';
142 }
143 return $select . $this->columnize($columns);
144 }
145 /**
146 * Compile a "JSON contains" statement into SQL.
147 *
148 * @param string $column
149 * @param string $value
150 * @return string
151 */
152 protected function compileJsonContains($column, $value)
153 {
154 $column = \str_replace('->>', '->', $this->wrap($column));
155 return '(' . $column . ')::jsonb @> ' . $value;
156 }
157 /**
158 * Compile a "JSON length" statement into SQL.
159 *
160 * @param string $column
161 * @param string $operator
162 * @param string $value
163 * @return string
164 */
165 protected function compileJsonLength($column, $operator, $value)
166 {
167 $column = \str_replace('->>', '->', $this->wrap($column));
168 return 'json_array_length((' . $column . ')::json) ' . $operator . ' ' . $value;
169 }
170 /**
171 * {@inheritdoc}
172 *
173 * @param array $having
174 * @return string
175 */
176 protected function compileHaving(array $having)
177 {
178 if ($having['type'] === 'Bitwise') {
179 return $this->compileHavingBitwise($having);
180 }
181 return parent::compileHaving($having);
182 }
183 /**
184 * Compile a having clause involving a bitwise operator.
185 *
186 * @param array $having
187 * @return string
188 */
189 protected function compileHavingBitwise($having)
190 {
191 $column = $this->wrap($having['column']);
192 $parameter = $this->parameter($having['value']);
193 return $having['boolean'] . ' (' . $column . ' ' . $having['operator'] . ' ' . $parameter . ')::bool';
194 }
195 /**
196 * Compile the lock into SQL.
197 *
198 * @param \Illuminate\Database\Query\Builder $query
199 * @param bool|string $value
200 * @return string
201 */
202 protected function compileLock(Builder $query, $value)
203 {
204 if (!\is_string($value)) {
205 return $value ? 'for update' : 'for share';
206 }
207 return $value;
208 }
209 /**
210 * Compile an insert ignore statement into SQL.
211 *
212 * @param \Illuminate\Database\Query\Builder $query
213 * @param array $values
214 * @return string
215 */
216 public function compileInsertOrIgnore(Builder $query, array $values)
217 {
218 return $this->compileInsert($query, $values) . ' on conflict do nothing';
219 }
220 /**
221 * Compile an insert and get ID statement into SQL.
222 *
223 * @param \Illuminate\Database\Query\Builder $query
224 * @param array $values
225 * @param string $sequence
226 * @return string
227 */
228 public function compileInsertGetId(Builder $query, $values, $sequence)
229 {
230 return $this->compileInsert($query, $values) . ' returning ' . $this->wrap($sequence ?: 'id');
231 }
232 /**
233 * Compile an update statement into SQL.
234 *
235 * @param \Illuminate\Database\Query\Builder $query
236 * @param array $values
237 * @return string
238 */
239 public function compileUpdate(Builder $query, array $values)
240 {
241 if (isset($query->joins) || isset($query->limit)) {
242 return $this->compileUpdateWithJoinsOrLimit($query, $values);
243 }
244 return parent::compileUpdate($query, $values);
245 }
246 /**
247 * Compile the columns for an update statement.
248 *
249 * @param \Illuminate\Database\Query\Builder $query
250 * @param array $values
251 * @return string
252 */
253 protected function compileUpdateColumns(Builder $query, array $values)
254 {
255 return \IAWP_SCOPED\collect($values)->map(function ($value, $key) {
256 $column = last(\explode('.', $key));
257 if ($this->isJsonSelector($key)) {
258 return $this->compileJsonUpdateColumn($column, $value);
259 }
260 return $this->wrap($column) . ' = ' . $this->parameter($value);
261 })->implode(', ');
262 }
263 /**
264 * Compile an "upsert" statement into SQL.
265 *
266 * @param \Illuminate\Database\Query\Builder $query
267 * @param array $values
268 * @param array $uniqueBy
269 * @param array $update
270 * @return string
271 */
272 public function compileUpsert(Builder $query, array $values, array $uniqueBy, array $update)
273 {
274 $sql = $this->compileInsert($query, $values);
275 $sql .= ' on conflict (' . $this->columnize($uniqueBy) . ') do update set ';
276 $columns = \IAWP_SCOPED\collect($update)->map(function ($value, $key) {
277 return \is_numeric($key) ? $this->wrap($value) . ' = ' . $this->wrapValue('excluded') . '.' . $this->wrap($value) : $this->wrap($key) . ' = ' . $this->parameter($value);
278 })->implode(', ');
279 return $sql . $columns;
280 }
281 /**
282 * Prepares a JSON column being updated using the JSONB_SET function.
283 *
284 * @param string $key
285 * @param mixed $value
286 * @return string
287 */
288 protected function compileJsonUpdateColumn($key, $value)
289 {
290 $segments = \explode('->', $key);
291 $field = $this->wrap(\array_shift($segments));
292 $path = '\'{"' . \implode('","', $segments) . '"}\'';
293 return "{$field} = jsonb_set({$field}::jsonb, {$path}, {$this->parameter($value)})";
294 }
295 /**
296 * Compile an update from statement into SQL.
297 *
298 * @param \Illuminate\Database\Query\Builder $query
299 * @param array $values
300 * @return string
301 */
302 public function compileUpdateFrom(Builder $query, $values)
303 {
304 $table = $this->wrapTable($query->from);
305 // Each one of the columns in the update statements needs to be wrapped in the
306 // keyword identifiers, also a place-holder needs to be created for each of
307 // the values in the list of bindings so we can make the sets statements.
308 $columns = $this->compileUpdateColumns($query, $values);
309 $from = '';
310 if (isset($query->joins)) {
311 // When using Postgres, updates with joins list the joined tables in the from
312 // clause, which is different than other systems like MySQL. Here, we will
313 // compile out the tables that are joined and add them to a from clause.
314 $froms = \IAWP_SCOPED\collect($query->joins)->map(function ($join) {
315 return $this->wrapTable($join->table);
316 })->all();
317 if (\count($froms) > 0) {
318 $from = ' from ' . \implode(', ', $froms);
319 }
320 }
321 $where = $this->compileUpdateWheres($query);
322 return \trim("update {$table} set {$columns}{$from} {$where}");
323 }
324 /**
325 * Compile the additional where clauses for updates with joins.
326 *
327 * @param \Illuminate\Database\Query\Builder $query
328 * @return string
329 */
330 protected function compileUpdateWheres(Builder $query)
331 {
332 $baseWheres = $this->compileWheres($query);
333 if (!isset($query->joins)) {
334 return $baseWheres;
335 }
336 // Once we compile the join constraints, we will either use them as the where
337 // clause or append them to the existing base where clauses. If we need to
338 // strip the leading boolean we will do so when using as the only where.
339 $joinWheres = $this->compileUpdateJoinWheres($query);
340 if (\trim($baseWheres) == '') {
341 return 'where ' . $this->removeLeadingBoolean($joinWheres);
342 }
343 return $baseWheres . ' ' . $joinWheres;
344 }
345 /**
346 * Compile the "join" clause where clauses for an update.
347 *
348 * @param \Illuminate\Database\Query\Builder $query
349 * @return string
350 */
351 protected function compileUpdateJoinWheres(Builder $query)
352 {
353 $joinWheres = [];
354 // Here we will just loop through all of the join constraints and compile them
355 // all out then implode them. This should give us "where" like syntax after
356 // everything has been built and then we will join it to the real wheres.
357 foreach ($query->joins as $join) {
358 foreach ($join->wheres as $where) {
359 $method = "where{$where['type']}";
360 $joinWheres[] = $where['boolean'] . ' ' . $this->{$method}($query, $where);
361 }
362 }
363 return \implode(' ', $joinWheres);
364 }
365 /**
366 * Prepare the bindings for an update statement.
367 *
368 * @param array $bindings
369 * @param array $values
370 * @return array
371 */
372 public function prepareBindingsForUpdateFrom(array $bindings, array $values)
373 {
374 $values = \IAWP_SCOPED\collect($values)->map(function ($value, $column) {
375 return \is_array($value) || $this->isJsonSelector($column) && !$this->isExpression($value) ? \json_encode($value) : $value;
376 })->all();
377 $bindingsWithoutWhere = Arr::except($bindings, ['select', 'where']);
378 return \array_values(\array_merge($values, $bindings['where'], Arr::flatten($bindingsWithoutWhere)));
379 }
380 /**
381 * Compile an update statement with joins or limit into SQL.
382 *
383 * @param \Illuminate\Database\Query\Builder $query
384 * @param array $values
385 * @return string
386 */
387 protected function compileUpdateWithJoinsOrLimit(Builder $query, array $values)
388 {
389 $table = $this->wrapTable($query->from);
390 $columns = $this->compileUpdateColumns($query, $values);
391 $alias = last(\preg_split('/\\s+as\\s+/i', $query->from));
392 $selectSql = $this->compileSelect($query->select($alias . '.ctid'));
393 return "update {$table} set {$columns} where {$this->wrap('ctid')} in ({$selectSql})";
394 }
395 /**
396 * Prepare the bindings for an update statement.
397 *
398 * @param array $bindings
399 * @param array $values
400 * @return array
401 */
402 public function prepareBindingsForUpdate(array $bindings, array $values)
403 {
404 $values = \IAWP_SCOPED\collect($values)->map(function ($value, $column) {
405 return \is_array($value) || $this->isJsonSelector($column) && !$this->isExpression($value) ? \json_encode($value) : $value;
406 })->all();
407 $cleanBindings = Arr::except($bindings, 'select');
408 return \array_values(\array_merge($values, Arr::flatten($cleanBindings)));
409 }
410 /**
411 * Compile a delete statement into SQL.
412 *
413 * @param \Illuminate\Database\Query\Builder $query
414 * @return string
415 */
416 public function compileDelete(Builder $query)
417 {
418 if (isset($query->joins) || isset($query->limit)) {
419 return $this->compileDeleteWithJoinsOrLimit($query);
420 }
421 return parent::compileDelete($query);
422 }
423 /**
424 * Compile a delete statement with joins or limit into SQL.
425 *
426 * @param \Illuminate\Database\Query\Builder $query
427 * @return string
428 */
429 protected function compileDeleteWithJoinsOrLimit(Builder $query)
430 {
431 $table = $this->wrapTable($query->from);
432 $alias = last(\preg_split('/\\s+as\\s+/i', $query->from));
433 $selectSql = $this->compileSelect($query->select($alias . '.ctid'));
434 return "delete from {$table} where {$this->wrap('ctid')} in ({$selectSql})";
435 }
436 /**
437 * Compile a truncate table statement into SQL.
438 *
439 * @param \Illuminate\Database\Query\Builder $query
440 * @return array
441 */
442 public function compileTruncate(Builder $query)
443 {
444 return ['truncate ' . $this->wrapTable($query->from) . ' restart identity cascade' => []];
445 }
446 /**
447 * Wrap the given JSON selector.
448 *
449 * @param string $value
450 * @return string
451 */
452 protected function wrapJsonSelector($value)
453 {
454 $path = \explode('->', $value);
455 $field = $this->wrapSegments(\explode('.', \array_shift($path)));
456 $wrappedPath = $this->wrapJsonPathAttributes($path);
457 $attribute = \array_pop($wrappedPath);
458 if (!empty($wrappedPath)) {
459 return $field . '->' . \implode('->', $wrappedPath) . '->>' . $attribute;
460 }
461 return $field . '->>' . $attribute;
462 }
463 /**
464 * Wrap the given JSON selector for boolean values.
465 *
466 * @param string $value
467 * @return string
468 */
469 protected function wrapJsonBooleanSelector($value)
470 {
471 $selector = \str_replace('->>', '->', $this->wrapJsonSelector($value));
472 return '(' . $selector . ')::jsonb';
473 }
474 /**
475 * Wrap the given JSON boolean value.
476 *
477 * @param string $value
478 * @return string
479 */
480 protected function wrapJsonBooleanValue($value)
481 {
482 return "'" . $value . "'::jsonb";
483 }
484 /**
485 * Wrap the attributes of the give JSON path.
486 *
487 * @param array $path
488 * @return array
489 */
490 protected function wrapJsonPathAttributes($path)
491 {
492 return \array_map(function ($attribute) {
493 return \filter_var($attribute, \FILTER_VALIDATE_INT) !== \false ? $attribute : "'{$attribute}'";
494 }, $path);
495 }
496 }
497