1C-Bitrix 25.700.0
Загрузка...
Поиск...
Не найдено
sqlhelper.php
См. документацию.
1<?php
2
3namespace Bitrix\Main\DB;
4
5use Bitrix\Main;
6use Bitrix\Main\Type;
7use Bitrix\Main\ORM;
8
9abstract class SqlHelper
10{
12 protected $connection;
13
14 protected $idCache;
15
20 {
21 $this->connection = $connection;
22 }
23
29 public function getLeftQuote()
30 {
31 return '';
32 }
33
39 public function getRightQuote()
40 {
41 return '';
42 }
43
49 abstract public function getAliasLength();
50
65 public function quote($identifier)
66 {
67 if (empty($this->idCache[$identifier]))
68 {
69 // security unshielding
70 $quotedIdentifier = str_replace([$this->getLeftQuote(), $this->getRightQuote()], '', $identifier);
71
72 // shield [[database.]tablename.]columnname
73 if (str_contains($quotedIdentifier, '.'))
74 {
75 $quotedIdentifier = str_replace('.', $this->getRightQuote() . '.' . $this->getLeftQuote(), $quotedIdentifier);
76 }
77
78 // shield general borders
79 $this->idCache[$identifier] = $this->getLeftQuote() . $quotedIdentifier . $this->getRightQuote();
80 }
81
82 return $this->idCache[$identifier];
83 }
84
90 abstract public function getQueryDelimiter();
91
100 abstract public function forSql($value, $maxLength = 0);
101
109 public function convertToDbBinary($value)
110 {
111 return "'" . $this->forSql($value) . "'";
112 }
113
122 public function convertToFullText($value, $maxLength = 0)
123 {
124 return "'" . $this->forSql($value, $maxLength) . "'";
125 }
126
132 abstract public function getCurrentDateTimeFunction();
133
139 abstract public function getCurrentDateFunction();
140
153 abstract public function addSecondsToDateTime($seconds, $from = null);
154
168 public function addDaysToDateTime($days, $from = null)
169 {
170 throw new Main\NotImplementedException('Method should be implemented in a child class.');
171 }
172
182 abstract public function getDatetimeToDateFunction($value);
183
210 abstract public function formatDate($format, $field = null);
211
226 public function getSubstrFunction($str, $from, $length = null)
227 {
228 $sql = 'SUBSTR('.$str.', '.$from;
229
230 if (!is_null($length))
231 $sql .= ', '.$length;
232
233 return $sql.')';
234 }
235
245 abstract public function getConcatFunction();
246
258 abstract public function getIsNullFunction($expression, $result);
259
269 abstract public function getLengthFunction($field);
270
282 abstract public function getCharToDateFunction($value);
283
296 abstract public function getDateToCharFunction($fieldName);
297
305 abstract public function castToChar($fieldName);
306
316 abstract public function softCastTextToChar($fieldName);
317
330 abstract public function getTopSql($sql, $limit, $offset = 0);
331
342 public function prepareInsert($tableName, array $fields, $returnAsArray = false)
343 {
344 $columns = array();
345 $values = array();
346
347 $tableFields = $this->connection->getTableFields($tableName);
348
349 $tableFields = array_change_key_case($tableFields, CASE_UPPER);
350 $fields = array_change_key_case($fields, CASE_UPPER);
351
352 foreach ($fields as $columnName => $value)
353 {
354 if (isset($tableFields[$columnName]))
355 {
356 $columns[] = $this->quote($columnName);
357 $values[] = $this->convertToDb($value, $tableFields[$columnName]);
358 }
359 else
360 {
361 trigger_error("Column `{$columnName}` is not found in the `{$tableName}` table", E_USER_WARNING);
362 }
363 }
364
365 $binds = $this->prepareBinds($tableFields, $fields);
366
367 return array(
368 $returnAsArray ? $columns : implode(", ", $columns),
369 $returnAsArray ? $values : implode(", ", $values),
370 $binds
371 );
372 }
373
382 public function prepareUpdate($tableName, array $fields)
383 {
384 $update = array();
385
386 $tableFields = $this->connection->getTableFields($tableName);
387
388 // one registry
389 $tableFields = array_change_key_case($tableFields, CASE_UPPER);
390 $fields = array_change_key_case($fields, CASE_UPPER);
391
392 foreach ($fields as $columnName => $value)
393 {
394 if (isset($tableFields[$columnName]))
395 {
396 $update[] = $this->quote($columnName).' = '.$this->convertToDb($value, $tableFields[$columnName]);
397 }
398 else
399 {
400 trigger_error("Column `{$columnName}` is not found in the `{$tableName}` table", E_USER_WARNING);
401 }
402 }
403
404 $binds = $this->prepareBinds($tableFields, $fields);
405
406 return array(
407 implode(", ", $update),
408 $binds
409 );
410 }
411
422 abstract public function prepareMerge($tableName, array $primaryFields, array $insertFields, array $updateFields);
423
432 protected function prepareBinds(array $tableFields, array $fields)
433 {
434 return array();
435 }
436
446 public function prepareAssignment($tableName, $columnName, $value)
447 {
448 $tableField = $this->connection->getTableField($tableName, $columnName);
449
450 return $this->quote($columnName).' = '.$this->convertToDb($value, $tableField);
451 }
452
461 public function convertToDb($value, ORM\Fields\IReadable $field = null)
462 {
463 if ($value === null)
464 {
465 return "NULL";
466 }
467
468 if ($value instanceof SqlExpression)
469 {
470 return $value->compile();
471 }
472
473 if (is_a($field, '\Bitrix\Main\ORM\Fields\StringField'))
474 {
475 $size = $field->getSize();
476 if ($size)
477 {
478 $value = mb_substr($value, 0, $size);
479 }
480 }
481
482 if($field instanceof ORM\Fields\IReadable)
483 {
484 $result = $field->convertValueToDb($value);
485 }
486 else
487 {
488 $result = $this->convertToDbString($value);
489 }
490
491 return $result;
492 }
493
504 public function convertFromDb($value, ORM\Fields\IReadable $field)
505 {
506 return $field->convertValueFromDb($value);
507 }
508
517 public function convertToDbInteger($value, $size = 8)
518 {
519 $value = intval($value);
520 if ($size == 2)
521 {
522 $value = max(-32768, min(+32767, $value));
523 }
524 elseif ($size == 4)
525 {
526 $value = max(-2147483648, min(+2147483647, $value));
527 }
528 return $value;
529 }
530
536 public function convertFromDbInteger($value)
537 {
538 return intval($value);
539 }
540
549 public function convertToDbFloat($value, $scale = null)
550 {
551 $value = doubleval($value);
552 if(!is_finite($value))
553 {
554 $value = 0;
555 }
556
557 return $scale !== null ? "'".round($value, $scale)."'" : "'".$value."'";
558 }
559
566 public function convertFromDbFloat($value, $scale = null)
567 {
568 $value = doubleval($value);
569
570 return $scale !== null ? round($value, $scale) : $value;
571 }
572
581 public function convertToDbString($value, $length = null)
582 {
583 return "'".$this->forSql($value, $length)."'";
584 }
585
592 public function convertFromDbString($value, $length = null)
593 {
594 if ($length > 0)
595 {
596 $value = mb_substr($value, 0, $length);
597 }
598
599 return strval($value);
600 }
601
609 public function convertToDbText($value)
610 {
611 return $this->convertToDbString($value);
612 }
613
619 public function convertFromDbText($value)
620 {
621 return $this->convertFromDbString($value);
622 }
623
632 public function convertToDbDate($value)
633 {
634 if (empty($value))
635 {
636 return "NULL";
637 }
638 elseif($value instanceof Type\Date)
639 {
640 return $this->getCharToDateFunction($value->format("Y-m-d"));
641 }
642 else
643 {
644 throw new Main\ArgumentTypeException('value', '\Bitrix\Main\Type\Date');
645 }
646 }
647
654 public function convertFromDbDate($value)
655 {
656 return new Type\Date($value);
657 }
658
667 public function convertToDbDateTime($value)
668 {
669 if (empty($value))
670 {
671 return "NULL";
672 }
673 elseif($value instanceof Type\Date)
674 {
675 if($value instanceof Type\DateTime)
676 {
677 $value = clone($value);
678 $value->setDefaultTimeZone();
679 }
680 return $this->getCharToDateFunction($value->format("Y-m-d H:i:s"));
681 }
682 else
683 {
684 throw new Main\ArgumentTypeException('value', '\Bitrix\Main\Type\Date');
685 }
686 }
687
694 public function convertFromDbDateTime($value)
695 {
696 return new Type\DateTime($value);
697 }
698
710 public function convertDatetimeField($value)
711 {
712 return $this->convertFromDbDateTime($value);
713 }
714
726 public function convertDateField($value)
727 {
728 return $this->convertFromDbDate($value);
729 }
730
739 public function getConverter(ORM\Fields\ScalarField $field)
740 {
741 return false;
742 }
743
751 abstract public function getColumnTypeByField(ORM\Fields\ScalarField $field);
752
763 abstract public function getFieldByColumnType($name, $type, array $parameters = null);
764
770 public function getAscendingOrder()
771 {
772 return 'ASC';
773 }
774
780 public function getDescendingOrder()
781 {
782 return 'DESC';
783 }
784
790 public function getConditionalAssignment($field, string $value): string
791 {
792 $field = $field instanceof SqlExpression ? $field->compile() : $this->quote($field);
793 $hash = $this->convertToDbString(sha1($value));
794 $value = $this->convertToDbString($value);
795
796 return 'case when ' . $this->getSha1Function($field) . ' = ' . $hash . ' then ' . $field . ' else ' . $value . ' end';
797 }
798
809 public function getInsertIgnore($tableName, $fields, $sql)
810 {
811 throw new Main\NotImplementedException('Method should be implemented in a child class.');
812 }
813
819 public function getRandomFunction()
820 {
821 return 'rand()';
822 }
823
833 public function getSha1Function($field)
834 {
835 return 'sha1(' . $field . ')';
836 }
837
849 public function getRegexpOperator($field, $regexp)
850 {
851 throw new Main\NotImplementedException('Method should be implemented in a child class.');
852 }
853
865 public function getIlikeOperator($field, $value)
866 {
867 throw new Main\NotImplementedException('Method should be implemented in a child class.');
868 }
869
879 public function values($identifier)
880 {
881 throw new Main\NotImplementedException('Method should be implemented in a child class.');
882 }
883
887 public function getMatchFunction($field, $value)
888 {
889 throw new Main\NotImplementedException('Method should be implemented in a child class.');
890 }
891
895 public function getMatchAndExpression($values, $prefixSearch = false)
896 {
897 throw new Main\NotImplementedException('Method should be implemented in a child class.');
898 }
899
903 public function getMatchOrExpression($values, $prefixSearch = false)
904 {
905 throw new Main\NotImplementedException('Method should be implemented in a child class.');
906 }
907
918 public function prepareMergeMultiple($tableName, array $primaryFields, array $insertRows)
919 {
920 throw new Main\NotImplementedException('Method should be implemented in a child class.');
921 }
922
934 public function prepareMergeSelect($tableName, array $primaryFields, array $selectFields, $select, $updateFields)
935 {
936 throw new Main\NotImplementedException('Method should be implemented in a child class.');
937 }
938
951 public function prepareDeleteLimit($tableName, array $primaryFields, $where, array $order, $limit)
952 {
953 throw new Main\NotImplementedException('Method should be implemented in a child class.');
954 }
955
959 public function initRowNumber($variableName)
960 {
961 throw new Main\NotImplementedException('Method should be implemented in a child class.');
962 }
963
967 public function getRowNumber($variableName)
968 {
969 throw new Main\NotImplementedException('Method should be implemented in a child class.');
970 }
971
984 public function prepareCorrelatedUpdate($tableName, $tableAlias, $fields, $from, $where)
985 {
986 throw new Main\NotImplementedException('Method should be implemented in a child class.');
987 }
988
1000 public function prepareMergeValues(string $tableName, array $primaryFields, array $insertRows, array $updateFields = []): string
1001 {
1002 $insertColumns = array_keys($insertRows[array_key_first($insertRows)] ?? []);
1003 $insertValuesStrings = [];
1004 foreach ($insertRows as $row)
1005 {
1006 [, $rowValues] = $this->prepareInsert($tableName, $row);
1007 $insertValuesStrings[] = $rowValues;
1008 }
1009
1010 if (empty($updateFields))
1011 {
1012 $notPrimaryFields = array_diff($insertColumns, $primaryFields);
1013 if (empty($notPrimaryFields))
1014 {
1015 trigger_error("Only primary fields to update, use getInsertIgnore() or specify fields", E_USER_WARNING);
1016 }
1017 $updateFields = $notPrimaryFields;
1018 }
1019
1020 $compatibleUpdateFields = [];
1021
1022 foreach ($updateFields as $key => $value)
1023 {
1024 if (is_numeric($key) && is_string($value))
1025 {
1026 $compatibleUpdateFields[$value] = new SqlExpression('?v', $value);
1027 }
1028 else
1029 {
1030 $compatibleUpdateFields[$key] = $value;
1031 }
1032 }
1033
1034 $insertValueString = 'values (' . implode('),(', $insertValuesStrings) . ')';
1035
1036 return $this->prepareMergeSelect($tableName, $primaryFields, $insertColumns, $insertValueString, $compatibleUpdateFields);
1037 }
1038
1046 public function getOrderByStringField(string $field, array $values, bool $quote = true): string
1047 {
1048 return $this->getOrderByField($field, $values, [$this, 'convertToDbString'], $quote);
1049 }
1050
1058 public function getOrderByIntField(string $field, array $values, bool $quote = true): string
1059 {
1060 return $this->getOrderByField($field, $values, [$this, 'convertFromDbInteger'], $quote);
1061 }
1062
1071 protected function getOrderByField(string $field, array $values, callable $callback, bool $quote = true): string
1072 {
1073 return $quote ? $this->quote($field) : $field;
1074 }
1075
1081 public function getQueryTables(string $sql, int $maxLevel = -1) : array
1082 {
1083 $level = 0;
1084 $tables = [];
1085
1086 $escaped = false;
1087 $singleQuotes = false;
1088 $doubleQuotes = false;
1089
1090 $isFrom = [0 => false];
1091 $isTable = [0 => false];
1092 $isIf = [0 => false];
1093
1094 $sql = preg_replace('/\s\s+/m', ' ', $sql);
1095 $sql = preg_replace('/(HOUR|MINUTE|SECOND|YEAR|QUARTER|WEEK|MICROSECOND)(\s+)FROM/is', 'XXX_FROM', $sql);
1096
1097 foreach (preg_split('/([,()"\'\\\\]|\s+)/s', $sql, -1, PREG_SPLIT_DELIM_CAPTURE) as $token)
1098 {
1099 if ($maxLevel > -1 && $level > $maxLevel)
1100 {
1101 break;
1102 }
1103
1104 $token = trim($token, "` ;\t\n\r");
1105 if ($token === '\\')
1106 {
1107 $escaped = !$escaped;
1108 continue;
1109 }
1110
1111 if ($token === '"' && !$escaped)
1112 {
1113 $doubleQuotes = !$doubleQuotes;
1114 continue;
1115 }
1116
1117 if ($token === '\'' && !$escaped)
1118 {
1119 $singleQuotes = !$singleQuotes;
1120 continue;
1121 }
1122
1123 if ($token && !$doubleQuotes && !$singleQuotes)
1124 {
1125 if ($token === '(')
1126 {
1127 $isTable[$level] = false;
1128 $level++;
1129 $isFrom[$level] = false;
1130 $isTable[$level] = false;
1131 $isIf[$level] = false;
1132 }
1133 elseif ($token === ')')
1134 {
1135 $isTable[$level] = false;
1136 if ($level > 0)
1137 {
1138 $level--;
1139 }
1140 }
1141 else
1142 {
1143 switch (strtoupper($token))
1144 {
1145 case 'INTO':
1146 $isTable[$level] = true;
1147 break;
1148 case 'FROM':
1149 case 'UPDATE':
1150 case 'TABLE':
1151 case 'TRUNCATE':
1152 $isFrom[$level] = true;
1153 $isTable[$level] = true;
1154 break;
1155 case 'EXISTS':
1156 if ($isIf[$level])
1157 {
1158 $isFrom[$level] = true;
1159 $isTable[$level] = true;
1160 }
1161 break;
1162
1163 case 'WHERE':
1164 case 'GROUP':
1165 case 'HAVING':
1166 case 'ORDER':
1167 case 'LIMIT':
1168 case 'SET':
1169 $isFrom[$level] = false;
1170 break;
1171 case ',':
1172 case 'JOIN':
1173 case 'STRAIGHT_JOIN':
1174 if ($isFrom[$level])
1175 {
1176 $isTable[$level] = true;
1177 }
1178 break;
1179 case 'IF':
1180 $isIf[$level] = true;
1181 $isTable[$level] = false;
1182 break;
1183 case 'TEMPORARY':
1184 $isTable[$level] = false;
1185 break;
1186 default:
1187 if ($isTable[$level])
1188 {
1189 $tables[$token] = $token;
1190 $isTable[$level] = false;
1191 }
1192 }
1193 }
1194 }
1195 }
1196
1197 return $tables;
1198 }
1199
1206 public function isBigType($type): bool
1207 {
1208 return false;
1209 }
1210}
$hash
Определения ajax_redirector.php:8
$type
Определения options.php:106
softCastTextToChar($fieldName)
getOrderByField(string $field, array $values, callable $callback, bool $quote=true)
Определения sqlhelper.php:1071
prepareMergeMultiple($tableName, array $primaryFields, array $insertRows)
Определения sqlhelper.php:918
getQueryTables(string $sql, int $maxLevel=-1)
Определения sqlhelper.php:1081
convertToDbBinary($value)
Определения sqlhelper.php:109
getMatchFunction($field, $value)
Определения sqlhelper.php:887
getOrderByStringField(string $field, array $values, bool $quote=true)
Определения sqlhelper.php:1046
isBigType($type)
Определения sqlhelper.php:1206
__construct(Connection $connection)
Определения sqlhelper.php:19
getTopSql($sql, $limit, $offset=0)
convertToDbString($value, $length=null)
Определения sqlhelper.php:581
getConverter(ORM\Fields\ScalarField $field)
Определения sqlhelper.php:739
getIsNullFunction($expression, $result)
getDateToCharFunction($fieldName)
convertFromDbInteger($value)
Определения sqlhelper.php:536
getIlikeOperator($field, $value)
Определения sqlhelper.php:865
formatDate($format, $field=null)
getRegexpOperator($field, $regexp)
Определения sqlhelper.php:849
convertToDbInteger($value, $size=8)
Определения sqlhelper.php:517
prepareDeleteLimit($tableName, array $primaryFields, $where, array $order, $limit)
Определения sqlhelper.php:951
convertDatetimeField($value)
Определения sqlhelper.php:710
getLeftQuote()
Определения sqlhelper.php:29
getDescendingOrder()
Определения sqlhelper.php:780
prepareUpdate($tableName, array $fields)
Определения sqlhelper.php:382
convertToDbFloat($value, $scale=null)
Определения sqlhelper.php:549
getColumnTypeByField(ORM\Fields\ScalarField $field)
convertFromDbString($value, $length=null)
Определения sqlhelper.php:592
addDaysToDateTime($days, $from=null)
Определения sqlhelper.php:168
convertFromDbText($value)
Определения sqlhelper.php:619
getFieldByColumnType($name, $type, array $parameters=null)
convertFromDb($value, ORM\Fields\IReadable $field)
Определения sqlhelper.php:504
prepareAssignment($tableName, $columnName, $value)
Определения sqlhelper.php:446
initRowNumber($variableName)
Определения sqlhelper.php:959
convertToDbDateTime($value)
Определения sqlhelper.php:667
prepareInsert($tableName, array $fields, $returnAsArray=false)
Определения sqlhelper.php:342
convertToDbText($value)
Определения sqlhelper.php:609
convertFromDbFloat($value, $scale=null)
Определения sqlhelper.php:566
getSubstrFunction($str, $from, $length=null)
Определения sqlhelper.php:226
getRandomFunction()
Определения sqlhelper.php:819
getConditionalAssignment($field, string $value)
Определения sqlhelper.php:790
getAscendingOrder()
Определения sqlhelper.php:770
prepareCorrelatedUpdate($tableName, $tableAlias, $fields, $from, $where)
Определения sqlhelper.php:984
getSha1Function($field)
Определения sqlhelper.php:833
getMatchAndExpression($values, $prefixSearch=false)
Определения sqlhelper.php:895
convertToDb($value, ORM\Fields\IReadable $field=null)
Определения sqlhelper.php:461
getMatchOrExpression($values, $prefixSearch=false)
Определения sqlhelper.php:903
forSql($value, $maxLength=0)
convertToFullText($value, $maxLength=0)
Определения sqlhelper.php:122
convertFromDbDateTime($value)
Определения sqlhelper.php:694
addSecondsToDateTime($seconds, $from=null)
convertFromDbDate($value)
Определения sqlhelper.php:654
prepareMergeSelect($tableName, array $primaryFields, array $selectFields, $select, $updateFields)
Определения sqlhelper.php:934
convertDateField($value)
Определения sqlhelper.php:726
prepareMergeValues(string $tableName, array $primaryFields, array $insertRows, array $updateFields=[])
Определения sqlhelper.php:1000
quote($identifier)
Определения sqlhelper.php:65
getRightQuote()
Определения sqlhelper.php:39
prepareBinds(array $tableFields, array $fields)
Определения sqlhelper.php:432
values($identifier)
Определения sqlhelper.php:879
getInsertIgnore($tableName, $fields, $sql)
Определения sqlhelper.php:809
prepareMerge($tableName, array $primaryFields, array $insertFields, array $updateFields)
getOrderByIntField(string $field, array $values, bool $quote=true)
Определения sqlhelper.php:1058
convertToDbDate($value)
Определения sqlhelper.php:632
getRowNumber($variableName)
Определения sqlhelper.php:967
Определения date.php:9
$str
Определения commerceml2.php:63
</td ></tr ></table ></td ></tr >< tr >< td class="bx-popup-label bx-width30"><?=GetMessage("PAGE_NEW_TAGS")?> array( $site)
Определения file_new.php:804
$result
Определения get_property_values.php:14
$select
Определения iblock_catalog_list.php:194
$selectFields
Определения iblock_catalog_list.php:160
$name
Определения menu_edit.php:35
Определения collection.php:2
$order
Определения payment.php:8
if( $daysToExpire >=0 &&$daysToExpire< 60 elseif)( $daysToExpire< 0)
Определения prolog_main_admin.php:393
if(empty($signedUserToken)) $key
Определения quickway.php:257
$fields
Определения yandex_run.php:501