Bitrix-D7 23.9
 
Загрузка...
Поиск...
Не найдено
mssqlsqlhelper.php
1<?php
2
3namespace Bitrix\Main\DB;
4
9
11{
15 public function getLeftQuote()
16 {
17 return '[';
18 }
19
23 public function getRightQuote()
24 {
25 return ']';
26 }
27
31 public function getAliasLength()
32 {
33 return 28;
34 }
35
39 public function getQueryDelimiter()
40 {
41 return "\nGO";
42 }
43
47 public function forSql($value, $maxLength = 0)
48 {
49 if ($maxLength > 0)
50 {
51 $value = mb_substr($value, 0, $maxLength);
52 }
53 $value = str_replace("'", "''", $value);
54 $value = str_replace("\x00", "", $value);
55 return $value;
56 }
57
62 {
63 return "GETDATE()";
64 }
65
69 public function getCurrentDateFunction()
70 {
71 return "convert(datetime, cast(year(getdate()) as varchar(4)) + '-' + cast(month(getdate()) as varchar(2)) + '-' + cast(day(getdate()) as varchar(2)), 120)";
72 }
73
77 public function addSecondsToDateTime($seconds, $from = null)
78 {
79 if ($from === null)
80 {
81 $from = static::getCurrentDateTimeFunction();
82 }
83
84 return 'DATEADD(second, '.$seconds.', '.$from.')';
85 }
86
90 public function getDatetimeToDateFunction($value)
91 {
92 return 'DATEADD(dd, DATEDIFF(dd, 0, '.$value.'), 0)';
93 }
94
98 public function formatDate($format, $field = null)
99 {
100 if ($field === null)
101 {
102 return '';
103 }
104
105 $result = array();
106
107 foreach (preg_split("#(YYYY|MMMM|MM|MI|M|DD|HH|H|GG|G|SS|TT|T)#", $format, -1, PREG_SPLIT_DELIM_CAPTURE) as $part)
108 {
109 switch ($part)
110 {
111 case "YYYY":
112 $result[] = "\n\tCONVERT(varchar(4),DATEPART(yyyy, $field))";
113 break;
114 case "MMMM":
115 $result[] = "\n\tdatename(mm, $field)";
116 break;
117 case "MM":
118 $result[] = "\n\tREPLICATE('0',2-LEN(DATEPART(mm, $field)))+CONVERT(varchar(2),DATEPART(mm, $field))";
119 break;
120 case "MI":
121 $result[] = "\n\tREPLICATE('0',2-LEN(DATEPART(mi, $field)))+CONVERT(varchar(2),DATEPART(mi, $field))";
122 break;
123 case "M":
124 $result[] = "\n\tCONVERT(varchar(3), $field,7)";
125 break;
126 case "DD":
127 $result[] = "\n\tREPLICATE('0',2-LEN(DATEPART(dd, $field)))+CONVERT(varchar(2),DATEPART(dd, $field))";
128 break;
129 case "HH":
130 case "GG":
131 $result[] = "\n\tREPLICATE('0',2-LEN(DATEPART(hh, $field)))+CONVERT(varchar(2),DATEPART(hh, $field))";
132 break;
133 case "H":
134 case "G":
135 $result[] = "\n\tCASE WHEN DATEPART(HH, $field) < 13 THEN RIGHT(REPLICATE('0',2) + CAST(datepart(HH, $field) AS VARCHAR(2)),2) ELSE RIGHT(REPLICATE('0',2) + CAST(datepart(HH, dateadd(HH, -12, $field)) AS VARCHAR(2)), 2) END";
136 break;
137 case "SS":
138 $result[] = "\n\tREPLICATE('0',2-LEN(DATEPART(ss, $field)))+CONVERT(varchar(2),DATEPART(ss, $field))";
139 break;
140 case "TT":
141 case "T":
142 $result[] = "\n\tCASE WHEN DATEPART(HH, $field) < 12 THEN 'AM' ELSE 'PM' END";
143 break;
144 default:
145 $result[] = "'".$part."'";
146 break;
147 }
148 }
149
150 return implode("+", $result);
151 }
152
156 public function getSubstrFunction($str, $from, $length = null)
157 {
158 $sql = 'SUBSTRING('.$str.', '.$from;
159
160 if (!is_null($length))
161 $sql .= ', '.$length;
162 else
163 $sql .= ', LEN('.$str.') + 1 - '.$from;
164
165 return $sql.')';
166 }
167
171 public function getConcatFunction()
172 {
173 return implode(" + ", func_get_args());
174 }
175
179 public function getIsNullFunction($expression, $result)
180 {
181 return "ISNULL(".$expression.", ".$result.")";
182 }
183
187 public function getLengthFunction($field)
188 {
189 return "LEN(".$field.")";
190 }
191
195 public function getCharToDateFunction($value)
196 {
197 return "CONVERT(datetime, '".$value."', 120)";
198 }
199
203 public function getDateToCharFunction($fieldName)
204 {
205 return "CONVERT(varchar(19), ".$fieldName.", 120)";
206 }
207
211 public function castToChar($fieldName)
212 {
213 return 'CAST('.$fieldName.' AS varchar)';
214 }
215
219 public function softCastTextToChar($fieldName)
220 {
221 return 'CONVERT(VARCHAR(8000), '.$fieldName.')';
222 }
223
227 public function getConverter(ScalarField $field)
228 {
229 if ($field instanceof ORM\Fields\DatetimeField)
230 {
231 return array($this, "convertFromDbDateTime");
232 }
233 elseif ($field instanceof ORM\Fields\DateField)
234 {
235 return array($this, "convertFromDbDate");
236 }
237 elseif ($field instanceof ORM\Fields\StringField)
238 {
239 return array($this, "convertFromDbString");
240 }
241 else
242 {
243 return parent::getConverter($field);
244 }
245 }
246
250 public function convertFromDbDateTime($value)
251 {
252 if ($value !== null)
253 {
254 $value = new Type\DateTime(mb_substr($value, 0, 19), "Y-m-d H:i:s");
255 }
256
257 return $value;
258 }
259
263 public function convertFromDbDate($value)
264 {
265 if($value !== null)
266 {
267 $value = new Type\Date($value, "Y-m-d");
268 }
269
270 return $value;
271 }
272
276 public function convertFromDbString($value, $length = null)
277 {
278 if ($value !== null)
279 {
280 if(preg_match("#^\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}\$#", $value))
281 {
282 return new Type\DateTime($value, "Y-m-d H:i:s");
283 }
284 }
285
286 return parent::convertFromDbString($value, $length);
287 }
288
292 public function getColumnTypeByField(ScalarField $field)
293 {
294 if ($field instanceof ORM\Fields\IntegerField)
295 {
296 return 'int';
297 }
298 elseif ($field instanceof ORM\Fields\FloatField)
299 {
300 return 'float';
301 }
302 elseif ($field instanceof ORM\Fields\DatetimeField)
303 {
304 return 'datetime';
305 }
306 elseif ($field instanceof ORM\Fields\DateField)
307 {
308 return 'date';
309 }
310 elseif ($field instanceof ORM\Fields\TextField)
311 {
312 return 'text';
313 }
314 elseif ($field instanceof ORM\Fields\BooleanField)
315 {
316 $values = $field->getValues();
317
318 if (preg_match('/^[0-9]+$/', $values[0]) && preg_match('/^[0-9]+$/', $values[1]))
319 {
320 return 'int';
321 }
322 else
323 {
324 return 'varchar('.max(mb_strlen($values[0]), mb_strlen($values[1])).')';
325 }
326 }
327 elseif ($field instanceof ORM\Fields\EnumField)
328 {
329 return 'varchar('.max(array_map('strlen', $field->getValues())).')';
330 }
331 else
332 {
333 // string by default
334 $defaultLength = false;
335 foreach ($field->getValidators() as $validator)
336 {
337 if ($validator instanceof ORM\Fields\Validators\LengthValidator)
338 {
339 if ($defaultLength === false || $defaultLength > $validator->getMax())
340 {
341 $defaultLength = $validator->getMax();
342 }
343 }
344 }
345 return 'varchar('.($defaultLength > 0? $defaultLength: 255).')';
346 }
347 }
348
352 public function getFieldByColumnType($name, $type, array $parameters = null)
353 {
354 switch($type)
355 {
356 case 4:
357 case 5:
358 case -6:
359 //int SQL_INTEGER (4)
360 //smallint SQL_SMALLINT (5)
361 //tinyint SQL_TINYINT (-6)
362 return new ORM\Fields\IntegerField($name);
363
364 case 2:
365 case 3:
366 case 6:
367 case 7:
368 //numeric SQL_NUMERIC (2)
369 //decimal SQL_DECIMAL (3)
370 //smallmoney SQL_DECIMAL (3)
371 //money SQL_DECIMAL (3)
372 //float SQL_FLOAT (6)
373 //real SQL_REAL (7)
374 return new ORM\Fields\FloatField($name, array("scale" => $parameters["scale"]));
375
376 case 93:
377 //datetime - SQL_TYPE_TIMESTAMP (93)
378 //datetime2 - SQL_TYPE_TIMESTAMP (93)
379 //smalldatetime - SQL_TYPE_TIMESTAMP (93)
380 return new ORM\Fields\DatetimeField($name);
381
382 case 91:
383 //date - SQL_TYPE_DATE (91)
384 return new ORM\Fields\DateField($name);
385 }
386 //bigint SQL_BIGINT (-5)
387 //binary SQL_BINARY (-2)
388 //bit SQL_BIT (-7)
389 //char SQL_CHAR (1)
390 //datetimeoffset SQL_SS_TIMESTAMPOFFSET (-155)
391 //image SQL_LONGVARBINARY (-4)
392 //nchar SQL_WCHAR (-8)
393 //ntext SQL_WLONGVARCHAR (-10)
394 //nvarchar SQL_WVARCHAR (-9)
395 //text SQL_LONGVARCHAR (-1)
396 //time SQL_SS_TIME2 (-154)
397 //timestamp SQL_BINARY (-2)
398 //udt SQL_SS_UDT (-151)
399 //uniqueidentifier SQL_GUID (-11)
400 //varbinary SQL_VARBINARY (-3)
401 //varchar SQL_VARCHAR (12)
402 //xml SQL_SS_XML (-152)
403 return new ORM\Fields\StringField($name, array("size" => $parameters["size"]));
404 }
405
409 public function getTopSql($sql, $limit, $offset = 0)
410 {
411 $offset = intval($offset);
412 $limit = intval($limit);
413
414 if ($offset > 0 && $limit <= 0)
415 throw new Main\ArgumentException("Limit must be set if offset is set");
416
417 if ($limit > 0)
418 {
419 if ($offset <= 0)
420 {
421 $sql = preg_replace("/^\\s*SELECT/i", "SELECT TOP ".$limit, $sql);
422 }
423 else
424 {
425 $orderBy = '';
426 $sqlTmp = $sql;
427
428 preg_match_all("#\\sorder\\s+by\\s#i", $sql, $matches, PREG_OFFSET_CAPTURE);
429 if (isset($matches[0]) && is_array($matches[0]) && !empty($matches[0]))
430 {
431 $idx = $matches[0][count($matches[0]) - 1][1];
432 $s = mb_substr($sql, $idx);
433 if (substr_count($s, '(') === substr_count($s, ')'))
434 {
435 $orderBy = $s;
436 $sqlTmp = mb_substr($sql, 0, $idx);
437 }
438 }
439
440 if ($orderBy === '')
441 {
442 $orderBy = "ORDER BY (SELECT 1)";
443 $sqlTmp = $sql;
444 }
445
446 // ROW_NUMBER() Returns the sequential number of a row within a partition of a result set, starting at 1 for the first row in each partition.
447 $sqlTmp = preg_replace(
448 "/^\\s*SELECT/i",
449 "SELECT ROW_NUMBER() OVER (".$orderBy.") AS ROW_NUMBER_ALIAS,",
450 $sqlTmp
451 );
452
453 $sql =
454 "WITH ROW_NUMBER_QUERY_ALIAS AS (".$sqlTmp.") ".
455 "SELECT * ".
456 "FROM ROW_NUMBER_QUERY_ALIAS ".
457 "WHERE ROW_NUMBER_ALIAS BETWEEN ".($offset + 1)." AND ".($offset + $limit);
458 }
459 }
460 return $sql;
461 }
462
466 public function prepareMerge($tableName, array $primaryFields, array $insertFields, array $updateFields)
467 {
468 $insert = $this->prepareInsert($tableName, $insertFields);
469
470 $updateColumns = array();
471 $sourceSelectValues = array();
472 $sourceSelectColumns = array();
473 $targetConnectColumns = array();
474 $tableFields = $this->connection->getTableFields($tableName);
475 foreach($tableFields as $columnName => $tableField)
476 {
477 $quotedName = $this->quote($columnName);
478 if (in_array($columnName, $primaryFields))
479 {
480 $sourceSelectValues[] = $this->convertToDb($insertFields[$columnName], $tableField);
481 $sourceSelectColumns[] = $quotedName;
482 if($insertFields[$columnName] === null)
483 {
484 //can't just compare NULLs
485 $targetConnectColumns[] = "(source.".$quotedName." IS NULL AND target.".$quotedName." IS NULL)";
486 }
487 else
488 {
489 $targetConnectColumns[] = "(source.".$quotedName." = target.".$quotedName.")";
490 }
491 }
492
493 if (isset($updateFields[$columnName]) || array_key_exists($columnName, $updateFields))
494 {
495 $updateColumns[] = "target.".$quotedName.' = '.$this->convertToDb($updateFields[$columnName], $tableField);
496 }
497 }
498
499 if (
500 $insert && $insert[0] != "" && $insert[1] != ""
501 && $updateColumns
502 && $sourceSelectValues && $sourceSelectColumns && $targetConnectColumns
503 )
504 {
505 $sql = "
506 MERGE INTO ".$this->quote($tableName)." AS target USING (
507 SELECT ".implode(", ", $sourceSelectValues)."
508 ) AS source (
509 ".implode(", ", $sourceSelectColumns)."
510 )
511 ON
512 (
513 ".implode(" AND ", $targetConnectColumns)."
514 )
515 WHEN MATCHED THEN
516 UPDATE SET ".implode(", ", $updateColumns)."
517 WHEN NOT MATCHED THEN
518 INSERT (".$insert[0].")
519 VALUES (".$insert[1].")
520 ;
521 ";
522 }
523 else
524 {
525 $sql = "";
526 }
527
528 return array(
529 $sql
530 );
531 }
532}
getTopSql($sql, $limit, $offset=0)
getIsNullFunction($expression, $result)
formatDate($format, $field=null)
convertFromDbString($value, $length=null)
getFieldByColumnType($name, $type, array $parameters=null)
getColumnTypeByField(ScalarField $field)
getSubstrFunction($str, $from, $length=null)
getConverter(ScalarField $field)
forSql($value, $maxLength=0)
addSecondsToDateTime($seconds, $from=null)
prepareMerge($tableName, array $primaryFields, array $insertFields, array $updateFields)
prepareInsert($tableName, array $fields, $returnAsArray=false)
convertToDb($value, ORM\Fields\IReadable $field=null)