Bitrix-D7 23.9
 
Загрузка...
Поиск...
Не найдено
mysqlisqlhelper.php
1<?php
2
10namespace Bitrix\Main\DB;
11
15
20{
24 public function getLeftQuote()
25 {
26 return '`';
27 }
28
32 public function getRightQuote()
33 {
34 return '`';
35 }
36
40 public function getAliasLength()
41 {
42 return 256;
43 }
44
48 public function getQueryDelimiter()
49 {
50 return ';';
51 }
52
57 {
58 return "NOW()";
59 }
60
64 public function getCurrentDateFunction()
65 {
66 return "CURDATE()";
67 }
68
72 public function addSecondsToDateTime($seconds, $from = null)
73 {
74 if ($from === null)
75 {
76 $from = static::getCurrentDateTimeFunction();
77 }
78
79 return 'DATE_ADD('.$from.', INTERVAL '.$seconds.' SECOND)';
80 }
81
85 public function addDaysToDateTime($days, $from = null)
86 {
87 if ($from === null)
88 {
89 $from = static::getCurrentDateTimeFunction();
90 }
91
92 return 'DATE_ADD('.$from.', INTERVAL '.$days.' DAY)';
93 }
94
98 public function getDatetimeToDateFunction($value)
99 {
100 return 'DATE('.$value.')';
101 }
102
106 public function formatDate($format, $field = null)
107 {
108 static $search = array(
109 "YYYY",
110 "MMMM",
111 "MM",
112 "MI",
113 "DD",
114 "HH",
115 "GG",
116 "G",
117 "SS",
118 "TT",
119 "T",
120 "W",
121 );
122 static $replace = array(
123 "%Y",
124 "%M",
125 "%m",
126 "%i",
127 "%d",
128 "%H",
129 "%h",
130 "%l",
131 "%s",
132 "%p",
133 "%p",
134 "%w",
135 );
136
137 $format = str_replace($search, $replace, $format);
138
139 if (!str_contains($format, '%H'))
140 {
141 $format = str_replace("H", "%h", $format);
142 }
143
144 if (!str_contains($format, '%M'))
145 {
146 $format = str_replace("M", "%b", $format);
147 }
148
149 if($field === null)
150 {
151 return $format;
152 }
153 else
154 {
155 return "DATE_FORMAT(".$field.", '".$format."')";
156 }
157 }
158
162 public function getConcatFunction()
163 {
164 $str = implode(", ", func_get_args());
165 if ($str != '')
166 {
167 $str = "CONCAT(".$str.")";
168 }
169 return $str;
170 }
171
175 public function getIsNullFunction($expression, $result)
176 {
177 return "IFNULL(".$expression.", ".$result.")";
178 }
179
183 public function getLengthFunction($field)
184 {
185 return "LENGTH(".$field.")";
186 }
187
191 public function getCharToDateFunction($value)
192 {
193 return "'".$value."'";
194 }
195
199 public function getDateToCharFunction($fieldName)
200 {
201 return $fieldName;
202 }
203
207 public function getConverter(ScalarField $field)
208 {
209 if($field instanceof ORM\Fields\DatetimeField)
210 {
211 return array($this, "convertFromDbDateTime");
212 }
213 elseif($field instanceof ORM\Fields\DateField)
214 {
215 return array($this, "convertFromDbDate");
216 }
217 else
218 {
219 return parent::getConverter($field);
220 }
221 }
222
226 public function convertFromDbDateTime($value)
227 {
228 if($value !== null && $value != '0000-00-00 00:00:00')
229 {
230 return new Type\DateTime($value, "Y-m-d H:i:s");
231 }
232
233 return null;
234 }
235
239 public function convertFromDbDate($value)
240 {
241 if($value !== null && $value != '0000-00-00')
242 {
243 return new Type\Date($value, "Y-m-d");
244 }
245
246 return null;
247 }
248
252 public function castToChar($fieldName)
253 {
254 return 'CAST('.$fieldName.' AS char)';
255 }
256
260 public function softCastTextToChar($fieldName)
261 {
262 return $fieldName;
263 }
264
268 public function getColumnTypeByField(ScalarField $field)
269 {
270 if ($field instanceof ORM\Fields\IntegerField)
271 {
272 switch ($field->getSize())
273 {
274 case 2:
275 return 'smallint';
276 case 4:
277 return 'int';
278 case 8:
279 return 'bigint';
280 }
281 return 'int';
282 }
283 elseif ($field instanceof ORM\Fields\DecimalField)
284 {
285 $defaultPrecision = 18;
286 $defaultScale = 2;
287
288 $precision = $field->getPrecision() > 0 ? $field->getPrecision() : $defaultPrecision;
289 $scale = $field->getScale() > 0 ? $field->getScale() : $defaultScale;
290
291 if ($scale >= $precision)
292 {
293 $precision = $defaultPrecision;
294 $scale = $defaultScale;
295 }
296
297 return "decimal($precision, $scale)";
298 }
299 elseif ($field instanceof ORM\Fields\FloatField)
300 {
301 return 'double';
302 }
303 elseif ($field instanceof ORM\Fields\DatetimeField)
304 {
305 return 'datetime';
306 }
307 elseif ($field instanceof ORM\Fields\DateField)
308 {
309 return 'date';
310 }
311 elseif ($field instanceof ORM\Fields\TextField)
312 {
313 return $field->isLong() ? 'longtext' : 'text';
314 }
315 elseif ($field instanceof ORM\Fields\BooleanField)
316 {
317 $values = $field->getValues();
318
319 if (preg_match('/^[0-9]+$/', $values[0]) && preg_match('/^[0-9]+$/', $values[1]))
320 {
321 return 'int';
322 }
323 else
324 {
325 return 'varchar('.max(mb_strlen($values[0]), mb_strlen($values[1])).')';
326 }
327 }
328 elseif ($field instanceof ORM\Fields\EnumField)
329 {
330 return 'varchar('.max(array_map('strlen', $field->getValues())).')';
331 }
332 else
333 {
334 // string by default
335 $defaultLength = false;
336 foreach ($field->getValidators() as $validator)
337 {
338 if ($validator instanceof ORM\Fields\Validators\LengthValidator)
339 {
340 if ($defaultLength === false || $defaultLength > $validator->getMax())
341 {
342 $defaultLength = $validator->getMax();
343 }
344 }
345 }
346 return 'varchar('.($defaultLength > 0? $defaultLength: 255).')';
347 }
348 }
349
353 public function getTopSql($sql, $limit, $offset = 0)
354 {
355 $offset = intval($offset);
356 $limit = intval($limit);
357
358 if ($offset > 0 && $limit <= 0)
359 throw new \Bitrix\Main\ArgumentException("Limit must be set if offset is set");
360
361 if ($limit > 0)
362 {
363 $sql .= "\nLIMIT ".$offset.", ".$limit."\n";
364 }
365
366 return $sql;
367 }
368
372 public function prepareMerge($tableName, array $primaryFields, array $insertFields, array $updateFields)
373 {
374 $insert = $this->prepareInsert($tableName, $insertFields);
375 $update = $this->prepareUpdate($tableName, $updateFields);
376
377 if (
378 $insert && $insert[0] != "" && $insert[1] != ""
379 && $update && $update[1] != ""
380 )
381 {
382 $sql = "
383 INSERT INTO ".$this->quote($tableName)." (".$insert[0].")
384 VALUES (".$insert[1].")
385 ON DUPLICATE KEY UPDATE ".$update[0]."
386 ";
387 }
388 else
389 {
390 $sql = "";
391 }
392
393 return array(
394 $sql
395 );
396 }
397
401 public function forSql($value, $maxLength = 0)
402 {
403 if ($maxLength > 0)
404 $value = mb_substr($value, 0, $maxLength);
405
406 $con = $this->connection->getResource();
407
408 return $con->real_escape_string($value);
409 }
410
414 public function getFieldByColumnType($name, $type, array $parameters = null)
415 {
416 switch($type)
417 {
418 case MYSQLI_TYPE_TINY:
419 case MYSQLI_TYPE_SHORT:
420 return (new ORM\Fields\IntegerField($name))->configureSize(2);
421 case MYSQLI_TYPE_LONG:
422 case MYSQLI_TYPE_INT24:
423 case MYSQLI_TYPE_CHAR:
424 return (new ORM\Fields\IntegerField($name))->configureSize(4);
425 case MYSQLI_TYPE_LONGLONG:
426 return ((new ORM\Fields\IntegerField($name)))->configureSize(8);
427 case MYSQLI_TYPE_DECIMAL:
428 case MYSQLI_TYPE_NEWDECIMAL:
429 case MYSQLI_TYPE_FLOAT:
430 case MYSQLI_TYPE_DOUBLE:
431 return new ORM\Fields\FloatField($name);
432 case MYSQLI_TYPE_DATETIME:
433 case MYSQLI_TYPE_TIMESTAMP:
434 return new ORM\Fields\DatetimeField($name);
435 case MYSQLI_TYPE_DATE:
436 case MYSQLI_TYPE_NEWDATE:
437 return new ORM\Fields\DateField($name);
438 }
439 //MYSQLI_TYPE_BIT
440 //MYSQLI_TYPE_TIME
441 //MYSQLI_TYPE_YEAR
442 //MYSQLI_TYPE_INTERVAL
443 //MYSQLI_TYPE_ENUM
444 //MYSQLI_TYPE_SET
445 //MYSQLI_TYPE_TINY_BLOB
446 //MYSQLI_TYPE_MEDIUM_BLOB
447 //MYSQLI_TYPE_LONG_BLOB
448 //MYSQLI_TYPE_BLOB
449 //MYSQLI_TYPE_VAR_STRING
450 //MYSQLI_TYPE_STRING
451 //MYSQLI_TYPE_GEOMETRY
452 return new ORM\Fields\StringField($name);
453 }
454
458 public function getInsertIgnore($tableName, $fields, $sql)
459 {
460 return 'INSERT IGNORE INTO ' . $tableName . $fields . $sql;
461 }
462
466 public function getRegexpOperator($field, $regexp)
467 {
468 return $field . ' regexp ' . $regexp;
469 }
470
474 public function values($identifier)
475 {
476 return 'VALUES(' . $this->quote($identifier) . ')';
477 }
478
479 public function getMatchFunction($field, $value)
480 {
481 return "MATCH (" . $field . ") AGAINST (" . $value . " IN BOOLEAN MODE)";
482 }
483
484 public function getMatchAndExpression($values, $prefixSearch = false)
485 {
486 if ($prefixSearch)
487 {
488 foreach ($values as $i => $searchTerm)
489 {
490 $values[$i] = $searchTerm . '*';
491 }
492 }
493 return '+' . implode(' +', $values);
494 }
495
496 public function getMatchOrExpression($values, $prefixSearch = false)
497 {
498 if ($prefixSearch)
499 {
500 foreach ($values as $i => $searchTerm)
501 {
502 $values[$i] = $searchTerm . '*';
503 }
504 }
505 return implode(' ', $values);
506 }
507
511 public function prepareMergeMultiple($tableName, array $primaryFields, array $insertRows)
512 {
513 $result = [];
514 $head = '';
515 $maxBodySize = 1024*1024; //1 Mb
516 $body = [];
517 $bodySize = 0;
518 foreach ($insertRows as $insertFields)
519 {
520 $insert = $this->prepareInsert($tableName, $insertFields);
521 if (!$head && $insert && $insert[0])
522 {
523 $head = 'REPLACE INTO ' . $this->quote($tableName) . ' (' . $insert[0] . ') VALUES ';
524 }
525 if ($insert && $insert[1])
526 {
527 $values = '(' . $insert[1] . ')';
528 $bodySize += mb_strlen($values) + 4;
529 $body[] = $values;
530 if ($bodySize > $maxBodySize)
531 {
532 $result[] = $head.implode(', ', $body);
533 $body = [];
534 $bodySize = 0;
535 }
536 }
537 }
538 if ($body)
539 {
540 $result[] = $head.implode(', ', $body);
541 }
542
543 return $result;
544 }
545
549 public function prepareMergeSelect($tableName, array $primaryFields, array $selectFields, $select, $updateFields)
550 {
551 $update = [];
552
553 $tableFields = $this->connection->getTableFields($tableName);
554 // one registry
555 $tableFields = array_change_key_case($tableFields, CASE_UPPER);
556 $updateFields = array_change_key_case($updateFields, CASE_UPPER);
557 foreach ($updateFields as $columnName => $value)
558 {
559 if (isset($tableFields[$columnName]))
560 {
561 $update[] = $this->quote($columnName) . ' = '. $this->convertToDb($value, $tableFields[$columnName]);
562 }
563 else
564 {
565 trigger_error("Column `{$columnName}` is not found in the `{$tableName}` table", E_USER_WARNING);
566 }
567 }
568
569 $sql = 'INSERT INTO ' . $this->quote($tableName) . ' (' . implode(',', array_map([$this, 'quote'], $selectFields)) . ') ';
570 $sql .= $select;
571 $sql .= ' ON DUPLICATE KEY UPDATE ' . implode(',', $update);
572
573 return $sql;
574 }
575
579 public function prepareDeleteLimit($tableName, array $primaryFields, $where, array $order, $limit)
580 {
581 $orderColumns = [];
582 foreach ($order as $columnName => $sort)
583 {
584 $orderColumns[] = $this->quote($columnName) . ' ' . $sort;
585 }
586 $sqlOrder = $orderColumns ? ' ORDER BY ' . implode(', ', $orderColumns) : '';
587 return 'DELETE FROM ' . $this->quote($tableName) . ' WHERE ' . $where . $sqlOrder . ' LIMIT ' . intval($limit);
588 }
589
590 public function initRowNumber($variableName)
591 {
592 return 'set @' . $variableName . ' = 0';
593 }
594
595 public function getRowNumber($variableName)
596 {
597 return '@' . $variableName . ':=' . '@' . $variableName . ' + 1';
598 }
599
603 public function prepareCorrelatedUpdate($tableName, $tableAlias, $fields, $from, $where)
604 {
605 $dml = "UPDATE " . $tableName . ' AS ' . $tableAlias . ",\n";
606 $dml .= $from . "\n";
607
608 $set = '';
609 foreach ($fields as $fieldName => $fieldValue)
610 {
611 $set .= ($set ? ',' : '') . $tableAlias . '.' . $fieldName . ' = ' .$fieldValue . "\n";
612 }
613 $dml .= 'SET ' . $set;
614 $dml .= 'WHERE ' . $where . "\n";
615
616 return $dml;
617 }
618
619 protected function getOrderByField(string $field, array $values, callable $callback, bool $quote = true): string
620 {
621 $field = $quote ? $this->quote($field) : $field;
622 $values = implode(',', array_map($callback, $values));
623
624 return "FIELD({$field}, {$values})";
625 }
626}
getOrderByField(string $field, array $values, callable $callback, bool $quote=true)
prepareMergeMultiple($tableName, array $primaryFields, array $insertRows)
getTopSql($sql, $limit, $offset=0)
getIsNullFunction($expression, $result)
formatDate($format, $field=null)
prepareDeleteLimit($tableName, array $primaryFields, $where, array $order, $limit)
addDaysToDateTime($days, $from=null)
getFieldByColumnType($name, $type, array $parameters=null)
getColumnTypeByField(ScalarField $field)
prepareCorrelatedUpdate($tableName, $tableAlias, $fields, $from, $where)
getMatchAndExpression($values, $prefixSearch=false)
getMatchOrExpression($values, $prefixSearch=false)
addSecondsToDateTime($seconds, $from=null)
prepareMergeSelect($tableName, array $primaryFields, array $selectFields, $select, $updateFields)
getInsertIgnore($tableName, $fields, $sql)
prepareMerge($tableName, array $primaryFields, array $insertFields, array $updateFields)
prepareUpdate($tableName, array $fields)
prepareInsert($tableName, array $fields, $returnAsArray=false)
convertToDb($value, ORM\Fields\IReadable $field=null)