1C-Bitrix 25.700.0
Загрузка...
Поиск...
Не найдено
query.php
См. документацию.
1<?php
2
4{
5 public $left_table = '';
6 public $left_column = '';
7 public $left_const = '';
8 public $right_table = '';
9 public $right_column = '';
10 public $right_const = '';
11
12 protected function _parse($sql)
13 {
14 $match = [];
15 if (preg_match('/^([`"\[\]]?[a-zA-Z0-9_]+[`"\[\]]?)\.(.+)$/', $sql, $match))
16 {
17 $table = $match[1];
18 $column = $match[2];
19 $const = '';
20 }
21 else
22 {
23 $table = '';
24 $column = '';
25 $const = $sql;
26 }
27
28 return [$table, $column, $const];
29 }
30
31 public function parse_left($sql)
32 {
34 }
35
36 public function parse_right($sql)
37 {
39 }
40}
41
43{
45 public $equation_regex = '';
46 public $sql = '';
47 public $simplified_sql = '';
48 public $joins = [];
49
51 {
52 $this->table_aliases_regex = $table_aliases_regex;
53 $this->equation_regex = '(?:' . $this->table_aliases_regex . "\\.[`\"\\[\\]]{0,1}[a-zA-Z0-9_]+[`\"\\[\\]]{0,1}|[0-9]+|'[^']*') (?:=|<|>|> =|< =|IS) (?:" . $this->table_aliases_regex . "\\.[`\"\\[\\]]{0,1}[a-zA-Z0-9_]+[`\"\\[\\]]{0,1}|[0-9]+|'[^']*'|NULL)";
54 }
55
56 public function parse($sql)
57 {
58 //Transform and simplify sql
59 //
60 //Remove balanced braces around equals
62
63 //Replace "expr1 = <const1> or expr1 = <const2> or expr1 = <const3> ..."
64 //with "expr1 in (<const1>, ...)"
65 $new_sql = preg_replace_callback('/\\( (' . $this->equation_regex . '(?: OR ' . $this->equation_regex . ')+) \\)/i', [$this, '_or2in'], CPerfQuery::removeSpaces($sql));
66 if ($new_sql !== null)
67 {
69 }
70
71 //Replace IN with no more than 5 values to equal
72 $sql = preg_replace("/ IN\s*\‍(\s*(\d+|'[^']*')(\s*,\s*(\d+|'[^']*')\s*){0,5}\s*\‍)/i", " = \\1 ", $sql);
73
74 //Remove complex inner syntax
75 while (preg_match('/\\([^()]*\\)/', $sql))
76 {
77 $sql = preg_replace('/\\([^()]*\\)/', '', $sql);
78 }
79
80 $this->simplified_sql = $sql;
81
82 foreach (preg_split('/ and /i', $sql) as $str)
83 {
84 $match = [];
85 if (preg_match('/(' . $this->table_aliases_regex . '\\.[`"\\[\\]]{0,1}[a-zA-Z0-9_]+[`"\\[\\]]{0,1}) = (' . $this->table_aliases_regex . '\\.[`"\\[\\]]{0,1}[a-zA-Z0-9_]+[`"\\[\\]]{0,1})/', $str, $match))
86 {
87 $join = new CPerfQueryJoin;
88 $join->parse_left($match[1]);
89 $join->parse_right($match[2]);
90 $this->joins[] = $join;
91 }
92 elseif (preg_match('/(' . $this->table_aliases_regex . "\\.[`\"\\[\\]]{0,1}[a-zA-Z0-9_]+[`\"\\[\\]]{0,1}) = ([0-9]+|'.+')/", $str, $match))
93 {
94 $join = new CPerfQueryJoin;
95 $join->parse_left($match[1]);
96 $join->parse_right($match[2]);
97 $this->joins[] = $join;
98 }
99 }
100
101 return !empty($this->joins);
102 }
103
104 //Remove balanced braces around equals
105 protected function _remove_braces($sql)
106 {
107 while (true)
108 {
109 $new_sql = preg_replace('/\\([ ]*(' . $this->equation_regex . '(?: AND ' . $this->equation_regex . ')*)[ ]*\\)/i', "\\1", $sql);
110 if ($new_sql === null)
111 {
112 break;
113 }
114
115 if ($new_sql === $sql)
116 {
117 $new_sql = preg_replace('/\\( \\( (' . $this->equation_regex . '(?: OR ' . $this->equation_regex . ')*) \\) \\)/i', "( \\1 )", trim($sql));
118 if ($new_sql === null)
119 {
120 break;
121 }
122
123 if ($new_sql === $sql)
124 {
125 break;
126 }
127 }
128
129 $sql = trim($new_sql);
130 }
131 return $sql;
132 }
133
134 protected function _or2in($or_match)
135 {
136 $sql = $or_match[0];
137
138 $match = [];
139 if (preg_match_all('/(' . $this->table_aliases_regex . "\\.[a-zA-Z0-9_]+|[0-9]+|'[^']*') (?:=) ([0-9]+|'[^']*')/", $or_match[1], $match))
140 {
141 if (count(array_unique($match[1])) == 1)
142 {
143 $sql = $match[1][0] . ' IN ( ' . implode(', ', $match[2]) . ' )';
144 }
145 }
146
147 return $sql;
148 }
149}
150
152{
153 public $sql = '';
154 public $name = '';
155 public $alias = '';
156 public $join = '';
157
158 public function parse($sql)
159 {
161
162 $match = [];
163 if (preg_match('/^([`"\[\]]?[a-z0-9_]+[`"\[\]]?) ([`"\[\]]?[a-z0-9_]+[`"\[\]]?) on (.+)$/i', $sql, $match))
164 {
165 $this->name = $match[1];
166 $this->alias = $match[2];
167 $this->join = $match[3];
168 }
169 if (preg_match('/^([`"\[\]]?[a-zA-Z0-9_]+[`"\[\]]?) ([`"\[\]]?[a-zA-Z0-9_]+[`"\[\]]?)($| )/', $sql, $match))
170 {
171 $this->name = $match[1];
172 $this->alias = $match[2];
173 }
174 elseif (preg_match('/^([`"\[\]]?[a-zA-Z0-9_]+[`"\[\]]?)$/', $sql, $match))
175 {
176 $this->name = $match[1];
177 $this->alias = $this->name;
178 }
179 else
180 {
181 return false;
182 }
183
184 $this->sql = $sql;
185 return true;
186 }
187}
188
190{
191 public $sql = '';
193 public $tables = [];
194 public $joins = [];
195
196 public function parse($sql)
197 {
199
200 $match = [];
201 if (preg_match('/^select(.*) from (.*?) (where|group|having|order)/is', $sql, $match))
202 {
203 $this->sql = $match[2];
204 }
205 elseif (preg_match('/^select(.*) from (.*?)$/is', $sql, $match))
206 {
207 $this->sql = $match[2];
208 }
209 else
210 {
211 $this->sql = '';
212 }
213
214 if ($this->sql)
215 {
216 $arJoinTables = preg_split('/(,|inner\\s+join|left\\s+join)(?=\\s+[`"\\[\\]]{0,1}[a-z0-9_]+[`"\\[\\]]{0,1})/is', $this->sql);
217 foreach ($arJoinTables as $str)
218 {
219 $table = new CPerfQueryTable;
220 if ($table->parse($str))
221 {
222 $this->tables[] = $table;
223 }
224 }
225
226 if (!$this->tables)
227 {
228 return false;
229 }
230
231 $tables_regex = '(?:' . implode('|', $this->getTableAliases()) . ')';
233 foreach ($this->tables as $table)
234 {
235 $where = new CPerfQueryWhere($tables_regex);
236 if ($where->parse($table->join))
237 {
238 $this->joins = array_merge($this->joins, $where->joins);
239 }
240 }
241 }
242
243 return !empty($this->tables);
244 }
245
246 public function getTableAliases()
247 {
248 $res = [];
250 foreach ($this->tables as $table)
251 {
252 $res[] = $table->alias;
253 }
254 return $res;
255 }
256}
257
259{
260 public $sql = '';
261 public $type = 'unknown';
262 public $subqueries = [];
264 public $from = null;
266 public $where = null;
267
268 public static function transform2select($sql)
269 {
270 $match = [];
271 if (preg_match("#^\\s*insert\\s+into\\s+(.+?)(\\(|)\\s*(\\s*select.*)\\s*\\2\\s*(\$|ON\\s+DUPLICATE\\s+KEY\\s+UPDATE)#is", $sql, $match))
272 {
273 $result = $match[3];
274 }
275 elseif (preg_match('#^\\s*DELETE\\s+#i', $sql))
276 {
277 $result = preg_replace('#^\\s*(DELETE.*?FROM)#is', 'select * from', $sql);
278 }
279 elseif (preg_match('#^\\s*SELECT\\s+#i', $sql))
280 {
281 $result = $sql;
282 }
283 else
284 {
285 $result = '';
286 }
287
288 return $result;
289 }
290
291 public static function removeSpaces($str)
292 {
293 return trim(preg_replace("/[ \t\n\r]+/", ' ', $str), " \t\n\r");
294 }
295
296 public function parse($sql)
297 {
298 $this->sql = preg_replace('/([()=])/', " \\1 ", $sql);
299 $this->sql = CPerfQuery::removeSpaces($this->sql);
300
301 $match = [];
302 if (preg_match('/^(select) /i', $this->sql, $match))
303 {
304 $this->type = mb_strtolower($match[1]);
305 }
306 else
307 {
308 $this->type = 'unknown';
309 }
310
311 if ($this->type === 'select')
312 {
313 //0 TODO replace literals with placeholders
314 //1 remove subqueries from sql
315 if (!$this->parse_subqueries())
316 {
317 return false;
318 }
319 //2 parse from
320 $this->from = new CPerfQueryFrom;
321 if (!$this->from->parse($this->sql))
322 {
323 return false;
324 }
325
326 $tables_regex = '(?:' . implode('|', $this->from->getTableAliases()) . ')';
327 $this->where = new CPerfQueryWhere($tables_regex);
328 if (preg_match('/ where (.+?)($| group | having | order )/i', $this->sql, $match))
329 {
330 $this->where->parse($match[1]);
331 }
332
333 return true;
334 }
335 else
336 {
337 return false;
338 }
339 }
340
341 public function parse_subqueries()
342 {
343 $this->subqueries = [];
344
345 $ar = preg_split('/(\\(\\s*select|\\(|\\))/is', $this->sql, -1, PREG_SPLIT_DELIM_CAPTURE);
346 $subq = 0;
347 $braces = 0;
348 foreach ($ar as $i => $str)
349 {
350 if ($str === ')')
351 {
352 $braces--;
353 }
354 elseif (mb_substr($str, 0, 1) === '(')
355 {
356 $braces++;
357 }
358
359 if ($subq == 0)
360 {
361 if (preg_match('/^\\(\\s*select/is', $str))
362 {
363 $this->subqueries[] = mb_substr($str, 1);
364 $subq++;
365 unset($ar[$i]);
366 }
367 }
368 elseif ($braces == 0)
369 {
370 $subq--;
371 unset($ar[$i]);
372 }
373 else
374 {
375 $this->subqueries[count($this->subqueries) - 1] .= $str;
376 unset($ar[$i]);
377 }
378 }
379
380 $this->sql = implode('', $ar);
381 return true;
382 }
383
384 public function cmp($table, $alias)
385 {
386 if ($table === $alias)
387 {
388 return true;
389 }
390 elseif ($table === '`' . $alias . '`')
391 {
392 return true;
393 }
394 else
395 {
396 return false;
397 }
398 }
399
400 public function table_joins($table_alias)
401 {
402 //Lookup table by its alias
403 $suggest_table = null;
405 foreach ($this->from->tables as $table)
406 {
407 if ($this->cmp($table->alias, $table_alias))
408 {
409 $suggest_table = $table;
410 }
411 }
412 if (!isset($suggest_table))
413 {
414 return [];
415 }
416
417 $arTableJoins = [
418 'WHERE' => []
419 ];
420 //1 iteration gather inter tables joins
421 foreach ($this->from->joins as $join)
422 {
423 if ($this->cmp($join->left_table, $table_alias) && $join->right_table !== '')
424 {
425 if (!isset($arTableJoins[$join->right_table]))
426 {
427 $arTableJoins[$join->right_table] = [];
428 }
429 $arTableJoins[$join->right_table][] = $join->left_column;
430 }
431 elseif ($this->cmp($join->right_table, $table_alias) && $join->left_table !== '')
432 {
433 if (!isset($arTableJoins[$join->left_table]))
434 {
435 $arTableJoins[$join->left_table] = [];
436 }
437 $arTableJoins[$join->left_table][] = $join->right_column;
438 }
439 }
440 //2 iteration gather inter tables joins from where
441 foreach ($this->where->joins as $join)
442 {
443 if ($this->cmp($join->left_table, $table_alias) && $join->right_table !== '')
444 {
445 if (!isset($arTableJoins[$join->right_table]))
446 {
447 $arTableJoins[$join->right_table] = [];
448 }
449 $arTableJoins[$join->right_table][] = $join->left_column;
450 }
451 elseif ($this->cmp($join->right_table, $table_alias) && $join->left_table !== '')
452 {
453 if (!isset($arTableJoins[$join->left_table]))
454 {
455 $arTableJoins[$join->left_table] = [];
456 }
457 $arTableJoins[$join->left_table][] = $join->right_column;
458 }
459 }
460 //3 iteration add constant filters from joins
461 foreach ($this->from->joins as $join)
462 {
463 if ($this->cmp($join->left_table, $table_alias) && $join->right_table === '')
464 {
465 foreach ($arTableJoins as $i => $arColumns)
466 {
467 $arTableJoins[$i][] = $join->left_column;
468 }
469 }
470 elseif ($this->cmp($join->right_table, $table_alias) && $join->left_table === '')
471 {
472 foreach ($arTableJoins as $i => $arColumns)
473 {
474 $arTableJoins[$i][] = $join->right_column;
475 }
476 }
477 }
478 //4 iteration add constant filters from where
479 foreach ($this->where->joins as $join)
480 {
481 if ($this->cmp($join->left_table, $table_alias) && $join->right_table === '')
482 {
483 foreach ($arTableJoins as $i => $arColumns)
484 {
485 $arTableJoins[$i][] = $join->left_column;
486 }
487 }
488 elseif ($this->cmp($join->right_table, $table_alias) && $join->left_table === '')
489 {
490 foreach ($arTableJoins as $i => $arColumns)
491 {
492 $arTableJoins[$i][] = $join->right_column;
493 }
494 }
495 }
496
497 if (empty($arTableJoins['WHERE']))
498 {
499 unset($arTableJoins['WHERE']);
500 }
501
502 return $arTableJoins;
503 }
504
505 public function suggest_index($table_alias)
506 {
507 global $DB;
508
509 $suggest_table = null;
511 foreach ($this->from->tables as $table)
512 {
513 if ($this->cmp($table->alias, $table_alias))
514 {
515 $suggest_table = $table;
516 }
517 }
518 if (!isset($suggest_table))
519 {
520 return false;
521 }
522
523 $arTableJoins = $this->table_joins($table_alias);
524
525 //Next read indexes already have
526 $arSuggest = [];
527 if (!empty($arTableJoins))
528 {
529 if (!$DB->TableExists($suggest_table->name))
530 {
531 return false;
532 }
533
534 $table = new CPerfomanceTable;
535 $table->Init($suggest_table->name);
536 $arIndexes = $table->GetIndexes();
537 foreach ($arIndexes as $index_name => $arColumns)
538 {
539 $arIndexes[$index_name] = implode(',', $arColumns);
540 }
541
542 //Test our suggestion against existing indexes
543 foreach ($arTableJoins as $arColumns)
544 {
545 $index_found = '';
546 $arColumns = $this->_adjust_columns($arColumns);
547 //Take all possible combinations of columns
548 $arCombosToTest = $this->array_power_set($arColumns);
549
550 foreach ($arCombosToTest as $arComboColumns)
551 {
552 if (!empty($arComboColumns))
553 {
554 $index2test = implode(',', $arComboColumns);
555 //Try to find out if index already exists
556 foreach ($arIndexes as $index_name => $index_columns)
557 {
558 if (mb_substr($index_columns, 0, mb_strlen($index2test)) === $index2test)
559 {
560 if (
561 $index_found === ''
562 || count(explode(',', $index_found)) < count(explode(',', $index2test))
563 )
564 {
565 $index_found = $index2test;
566 }
567 }
568 }
569 }
570 }
571 //
572 if (!$index_found)
573 {
574 sort($arColumns);
575 $arSuggest[] = $suggest_table->alias . ':' . $suggest_table->name . ':' . implode(',', $arColumns);
576 }
577 }
578 }
579
580 if (!empty($arSuggest))
581 {
582 return $arSuggest;
583 }
584 else
585 {
586 return false;
587 }
588 }
589
590 public function array_power_set($array)
591 {
592 $results = [[]];
593 foreach ($array as $element)
594 {
595 foreach ($results as $combination)
596 {
597 $results[] = array_merge([$element], $combination);
598 }
599 }
600 return $results;
601 }
602
603 protected function _adjust_columns($arColumns)
604 {
605 $arColumns = array_unique($arColumns);
606 while (mb_strlen(implode(',', $arColumns)) > 250)
607 {
608 //TODO: add brains here
609 //1 exclude blobs and clobs
610 //2 etc.
611 array_pop($arColumns);
612 }
613 return $arColumns;
614 }
615
616 public function has_where($table_alias = false)
617 {
618 if ($table_alias === false)
619 {
620 return !empty($this->where->joins);
621 }
622
623 foreach ($this->where->joins as $join)
624 {
625 if ($this->cmp($join->left_table, $table_alias))
626 {
627 return true;
628 }
629 elseif ($this->cmp($join->right_table, $table_alias))
630 {
631 return true;
632 }
633 }
634
635 return false;
636 }
637
638 public function find_value($table_name, $column_name)
639 {
640 //Lookup table by its name
642 foreach ($this->from->tables as $table)
643 {
644 if ($table->name === $table_name)
645 {
646 $table_alias = $table->alias;
647
648 foreach ($this->where->joins as $join)
649 {
650 if (
651 $join->left_table === $table_alias
652 && $join->left_column === $column_name
653 && $join->right_const !== ''
654 )
655 {
656 return $join->right_const;
657 }
658 elseif (
659 $join->right_table === $table_alias
660 && $join->right_column === $column_name
661 && $join->left_const !== ''
662 )
663 {
664 return $join->left_const;
665 }
666 }
667
668 foreach ($this->from->joins as $join)
669 {
670 if (
671 $join->left_table === $table_alias
672 && $join->left_column === $column_name
673 && $join->right_const !== ''
674 )
675 {
676 return $join->right_const;
677 }
678 elseif (
679 $join->right_table === $table_alias
680 && $join->right_column === $column_name
681 && $join->left_const !== ''
682 )
683 {
684 return $join->left_const;
685 }
686 }
687 }
688 }
689
690 return '';
691 }
692
693 public function find_join($table_name, $column_name)
694 {
695 //Lookup table by its name
696 $suggest_table = null;
698 foreach ($this->from->tables as $table)
699 {
700 if ($table->name === $table_name)
701 {
702 $suggest_table = $table;
703 }
704 }
705
706 if (!isset($suggest_table))
707 {
708 return '';
709 }
710 $table_alias = $suggest_table->alias;
711
712 foreach ($this->where->joins as $join)
713 {
714 if (
715 $join->left_table === $table_alias
716 && $join->left_column === $column_name
717 && $join->right_table !== ''
718 )
719 {
720 return $join->right_table . '.' . $join->right_column;
721 }
722 elseif (
723 $join->right_table === $table_alias
724 && $join->right_column === $column_name
725 && $join->left_table !== ''
726 )
727 {
728 return $join->left_table . '.' . $join->left_column;
729 }
730 }
731
732 foreach ($this->from->joins as $join)
733 {
734 if (
735 $join->left_table === $table_alias
736 && $join->left_column === $column_name
737 && $join->right_table !== ''
738 )
739 {
740 return $join->right_table . '.' . $join->right_column;
741 }
742 elseif (
743 $join->right_table === $table_alias
744 && $join->right_column === $column_name
745 && $join->left_table !== ''
746 )
747 {
748 return $join->left_table . '.' . $join->left_column;
749 }
750 }
751
752 return '';
753 }
754
755 public static function remove_literals($sql)
756 {
757 return preg_replace('/(
758 "[^"\\\\]*(?:\\\\.[^"\\\\]*)*" # match double quoted string
759 |
760 \'[^\'\\\\]*(?:\\\\.[^\'\\\\]*)*\' # match single quoted string
761 |
762 (?s:\\/\\*.*?\\*\\/) # multi line comments
763 |
764 \\/\\/.*?\\n # single line comments
765 |
766 (?<![A-Za-z_])([0-9]+\\.[0-9]+|[0-9]+)(?![A-Za-z_]) # an number
767 |
768 (?i:\\sIN\\s*\\(\\s*[0-9.]+(?:\\s*,\\s*[0-9.])*\\s*\\)) # in (1, 2, 3)
769 |
770 (?i:\\sIN\\s*\\(\\s*[\'].+?[\'](?:\\s*,\\s*[\'].+?[\'])*\\s*\\)) # in (\'a\', \'b\', \'c\')
771 )/x', '', $sql);
772 }
773}
Определения query.php:190
$sql
Определения query.php:191
$tables
Определения query.php:193
$joins
Определения query.php:194
Определения query.php:259
static transform2select($sql)
Определения query.php:268
_adjust_columns($arColumns)
Определения query.php:603
$sql
Определения query.php:260
$from
Определения query.php:264
$subqueries
Определения query.php:262
array_power_set($array)
Определения query.php:590
$type
Определения query.php:261
has_where($table_alias=false)
Определения query.php:616
static remove_literals($sql)
Определения query.php:755
parse_subqueries()
Определения query.php:341
$where
Определения query.php:266
cmp($table, $alias)
Определения query.php:384
parse($sql)
Определения query.php:296
static removeSpaces($str)
Определения query.php:291
Определения query.php:4
$right_const
Определения query.php:10
parse_right($sql)
Определения query.php:36
_parse($sql)
Определения query.php:12
parse_left($sql)
Определения query.php:31
$left_column
Определения query.php:6
$left_const
Определения query.php:7
$right_table
Определения query.php:8
$left_table
Определения query.php:5
$right_column
Определения query.php:9
Определения query.php:152
$sql
Определения query.php:153
$join
Определения query.php:156
$alias
Определения query.php:155
$name
Определения query.php:154
parse($sql)
Определения query.php:158
Определения query.php:43
$sql
Определения query.php:46
$table_aliases_regex
Определения query.php:44
$equation_regex
Определения query.php:45
$simplified_sql
Определения query.php:47
_remove_braces($sql)
Определения query.php:105
$joins
Определения query.php:48
_or2in($or_match)
Определения query.php:134
__construct($table_aliases_regex)
Определения query.php:50
parse($sql)
Определения query.php:56
$str
Определения commerceml2.php:63
$res
Определения filter_act.php:7
$result
Определения get_property_values.php:14
global $DB
Определения cron_frame.php:29
$table
Определения mysql_to_pgsql.php:36
if( $daysToExpire >=0 &&$daysToExpire< 60 elseif)( $daysToExpire< 0)
Определения prolog_main_admin.php:393
$ar
Определения options.php:199
$i
Определения factura.php:643
</p ></td >< td valign=top style='border-top:none;border-left:none;border-bottom:solid windowtext 1.0pt;border-right:solid windowtext 1.0pt;padding:0cm 2.0pt 0cm 2.0pt;height:9.0pt'>< p class=Normal align=center style='margin:0cm;margin-bottom:.0001pt;text-align:center;line-height:normal'>< a name=ТекстовоеПоле54 ></a ><?=($taxRate > count( $arTaxList) > 0) ? $taxRate."%"
Определения waybill.php:936