Bitrix-D7 23.9
 
Загрузка...
Поиск...
Не найдено
oraclesqlhelper.php
1<?php
2
3namespace Bitrix\Main\DB;
4
8
10{
14 public function getLeftQuote()
15 {
16 return '"';
17 }
18
22 public function getRightQuote()
23 {
24 return '"';
25 }
26
30 public function getAliasLength()
31 {
32 return 30;
33 }
34
38 public function quote($identifier)
39 {
40 return parent::quote(mb_strtoupper($identifier));
41 }
42
46 public function getQueryDelimiter()
47 {
48 return "(?<!\\*)/(?!\\*)";
49 }
50
54 function forSql($value, $maxLength = 0)
55 {
56 if ($maxLength <= 0 || $maxLength > 2000)
57 $maxLength = 2000;
58
59 $value = mb_substr($value, 0, $maxLength);
60
62 {
63 // From http://w3.org/International/questions/qa-forms-utf-8.html
64 // This one can crash php with segmentation fault on large input data (over 20K)
65 // https://bugs.php.net/bug.php?id=60423
66 if (preg_match_all('%(
67 [\x00-\x7E] # ASCII
68 |[\xC2-\xDF][\x80-\xBF] # non-overlong 2-byte
69 |\xE0[\xA0-\xBF][\x80-\xBF] # excluding overlongs
70 |[\xE1-\xEC\xEE\xEF][\x80-\xBF]{2} # straight 3-byte
71 |\xED[\x80-\x9F][\x80-\xBF] # excluding surrogates
72 |\xF0[\x90-\xBF][\x80-\xBF]{2} # planes 1-3
73 |[\xF1-\xF3][\x80-\xBF]{3} # planes 4-15
74 |\xF4[\x80-\x8F][\x80-\xBF]{2} # plane 16
75 )+%x', $value, $match))
76 $value = implode(' ', $match[0]);
77 else
78 return ''; //There is no valid utf at all
79 }
80
81 return str_replace("'", "''", $value);
82 }
83
88 {
89 return "SYSDATE";
90 }
91
95 public function getCurrentDateFunction()
96 {
97 return "TRUNC(SYSDATE)";
98 }
99
103 public function addSecondsToDateTime($seconds, $from = null)
104 {
105 if ($from === null)
106 {
107 $from = static::getCurrentDateTimeFunction();
108 }
109
110 return '('.$from.'+'.$seconds.'/86400)';
111 }
112
116 public function getDatetimeToDateFunction($value)
117 {
118 return 'TRUNC('.$value.')';
119 }
120
124 public function formatDate($format, $field = null)
125 {
126 $format = str_replace("HH", "HH24", $format);
127 $format = str_replace("GG", "HH24", $format);
128
129 if (!str_contains($format, 'HH24'))
130 {
131 $format = str_replace("H", "HH", $format);
132 }
133
134 $format = str_replace("G", "HH", $format);
135
136 $format = str_replace("MI", "II", $format);
137
138 if (str_contains($format, 'MMMM'))
139 {
140 $format = str_replace("MMMM", "MONTH", $format);
141 }
142 elseif (!str_contains($format, 'MM'))
143 {
144 $format = str_replace("M", "MON", $format);
145 }
146
147 $format = str_replace("II", "MI", $format);
148
149 $format = str_replace("TT", "AM", $format);
150 $format = str_replace("T", "AM", $format);
151
152 if ($field === null)
153 {
154 return $format;
155 }
156 else
157 {
158 return "TO_CHAR(".$field.", '".$format."')";
159 }
160 }
161
165 public function getConcatFunction()
166 {
167 return implode(" || ", func_get_args());
168 }
169
173 public function getIsNullFunction($expression, $result)
174 {
175 return "NVL(".$expression.", ".$result.")";
176 }
177
181 public function getLengthFunction($field)
182 {
183 return "LENGTH(".$field.")";
184 }
185
189 public function getCharToDateFunction($value)
190 {
191 return "TO_DATE('".$value."', 'YYYY-MM-DD HH24:MI:SS')";
192 }
193
197 public function getDateToCharFunction($fieldName)
198 {
199 return "TO_CHAR(".$fieldName.", 'YYYY-MM-DD HH24:MI:SS')";
200 }
201
205 protected function prepareBinds(array $tableFields, array $fields)
206 {
207 $binds = array();
208
209 foreach ($tableFields as $columnName => $tableField)
210 {
211 if (isset($fields[$columnName]) && !($fields[$columnName] instanceof SqlExpression))
212 {
213 if ($tableField instanceof ORM\Fields\TextField && $fields[$columnName] <> '')
214 {
215 $binds[$columnName] = $fields[$columnName];
216 }
217 }
218 }
219
220 return $binds;
221 }
222
226 public function getConverter(ScalarField $field)
227 {
228 if ($field instanceof ORM\Fields\DatetimeField)
229 {
230 return array($this, "convertFromDbDateTime");
231 }
232 elseif ($field instanceof ORM\Fields\TextField)
233 {
234 return array($this, "convertFromDbText");
235 }
236 elseif ($field instanceof ORM\Fields\StringField)
237 {
238 return array($this, "convertFromDbString");
239 }
240 else
241 {
242 return parent::getConverter($field);
243 }
244 }
245
249 public function convertFromDbDateTime($value)
250 {
251 if ($value !== null)
252 {
253 if (mb_strlen($value) == 19)
254 {
255 //preferable format: NLS_DATE_FORMAT='YYYY-MM-DD HH24:MI:SS'
256 $value = new Type\DateTime($value, "Y-m-d H:i:s");
257 }
258 else
259 {
260 //default Oracle date format: 03-MAR-14
261 $value = new Type\DateTime($value." 00:00:00", "d-M-y H:i:s");
262 }
263 }
264
265 return $value;
266 }
267
271 public function convertFromDbText($value)
272 {
273 if (is_object($value))
274 {
276 $value = $value->load();
277 }
278
279 return $value;
280 }
281
285 public function convertToDbText($value)
286 {
287 return empty($value) ? "NULL" : "EMPTY_CLOB()";
288 }
289
293 public function convertFromDbString($value, $length = null)
294 {
295 if ($value !== null)
296 {
297 if ((mb_strlen($value) == 19) && preg_match("#^\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}$#", $value))
298 {
299 return new Type\DateTime($value, "Y-m-d H:i:s");
300 }
301 }
302
303 return parent::convertFromDbString($value, $length);
304 }
305
309 public function castToChar($fieldName)
310 {
311 return 'TO_CHAR('.$fieldName.')';
312 }
313
317 public function softCastTextToChar($fieldName)
318 {
319 return 'dbms_lob.substr('.$fieldName.', 4000, 1)';
320 }
321
325 public function getColumnTypeByField(ScalarField $field)
326 {
327 if ($field instanceof ORM\Fields\IntegerField)
328 {
329 return 'number(18)';
330 }
331 elseif ($field instanceof ORM\Fields\FloatField)
332 {
333 $scale = $field->getScale();
334 return 'number'.($scale !== null? "(*,".$scale.")": "");
335 }
336 elseif ($field instanceof ORM\Fields\DatetimeField)
337 {
338 return 'date';
339 }
340 elseif ($field instanceof ORM\Fields\DateField)
341 {
342 return 'date';
343 }
344 elseif ($field instanceof ORM\Fields\TextField)
345 {
346 return 'clob';
347 }
348 elseif ($field instanceof ORM\Fields\BooleanField)
349 {
350 $values = $field->getValues();
351
352 if (preg_match('/^[0-9]+$/', $values[0]) && preg_match('/^[0-9]+$/', $values[1]))
353 {
354 return 'number(1)';
355 }
356 else
357 {
358 return 'varchar2('.max(mb_strlen($values[0]), mb_strlen($values[1])).' char)';
359 }
360 }
361 elseif ($field instanceof ORM\Fields\EnumField)
362 {
363 return 'varchar2('.max(array_map('strlen', $field->getValues())).' char)';
364 }
365 else
366 {
367 // string by default
368 $defaultLength = false;
369 foreach ($field->getValidators() as $validator)
370 {
371 if ($validator instanceof ORM\Fields\Validators\LengthValidator)
372 {
373 if ($defaultLength === false || $defaultLength > $validator->getMax())
374 {
375 $defaultLength = $validator->getMax();
376 }
377 }
378 }
379 return 'varchar2('.($defaultLength > 0? $defaultLength: 255).' char)';
380 }
381 }
382
386 public function getFieldByColumnType($name, $type, array $parameters = null)
387 {
388 switch ($type)
389 {
390 case "DATE":
391 return new ORM\Fields\DatetimeField($name);
392
393 case "NCLOB":
394 case "CLOB":
395 case "BLOB":
396 return new ORM\Fields\TextField($name);
397
398 case "FLOAT":
399 case "BINARY_FLOAT":
400 case "BINARY_DOUBLE":
401 return new ORM\Fields\FloatField($name);
402
403 case "NUMBER":
404 if ($parameters["precision"] == 0 && $parameters["scale"] == -127)
405 {
406 //NUMBER
407 return new ORM\Fields\FloatField($name);
408 }
409 if (intval($parameters["scale"]) <= 0)
410 {
411 //NUMBER(18)
412 //NUMBER(18,-2)
413 return new ORM\Fields\IntegerField($name);
414 }
415 //NUMBER(*,2)
416 return new ORM\Fields\FloatField($name, array("scale" => $parameters["scale"]));
417 }
418 //LONG
419 //VARCHAR2(size [BYTE | CHAR])
420 //NVARCHAR2(size)
421 //TIMESTAMP [(fractional_seconds_precision)]
422 //TIMESTAMP [(fractional_seconds)] WITH TIME ZONE
423 //TIMESTAMP [(fractional_seconds)] WITH LOCAL TIME ZONE
424 //INTERVAL YEAR [(year_precision)] TO MONTH
425 //INTERVAL DAY [(day_precision)] TO SECOND [(fractional_seconds)]
426 //RAW(size)
427 //LONG RAW
428 //ROWID
429 //UROWID [(size)]
430 //CHAR [(size [BYTE | CHAR])]
431 //NCHAR[(size)]
432 //BFILE
433 return new ORM\Fields\StringField($name, array("size" => $parameters["size"]));
434 }
435
439 public function getTopSql($sql, $limit, $offset = 0)
440 {
441 $offset = intval($offset);
442 $limit = intval($limit);
443
444 if ($offset > 0 && $limit <= 0)
445 throw new \Bitrix\Main\ArgumentException("Limit must be set if offset is set");
446
447 if ($limit > 0)
448 {
449 //The first row selected has a ROWNUM of 1, the second has 2, and so on
450 if ($offset <= 0)
451 {
452 $sql =
453 "SELECT * ".
454 "FROM (".$sql.") ".
455 "WHERE ROWNUM <= ".$limit;
456 }
457 else
458 {
459 $sql =
460 "SELECT * ".
461 "FROM (".
462 " SELECT rownum_query_alias.*, ROWNUM rownum_alias ".
463 " FROM (".$sql.") rownum_query_alias ".
464 " WHERE ROWNUM <= ".($offset + $limit)." ".
465 ") ".
466 "WHERE rownum_alias >= ".($offset + 1);
467 }
468 }
469 return $sql;
470 }
471
475 public function getAscendingOrder()
476 {
477 return 'ASC NULLS FIRST';
478 }
479
483 public function getDescendingOrder()
484 {
485 return 'DESC NULLS LAST';
486 }
487
491 public function prepareMerge($tableName, array $primaryFields, array $insertFields, array $updateFields)
492 {
493 $insert = $this->prepareInsert($tableName, $insertFields);
494
495 $updateColumns = array();
496 $sourceSelectColumns = array();
497 $targetConnectColumns = array();
498 $tableFields = $this->connection->getTableFields($tableName);
499 foreach($tableFields as $columnName => $tableField)
500 {
501 $quotedName = $this->quote($columnName);
502 if (in_array($columnName, $primaryFields))
503 {
504 $sourceSelectColumns[] = $this->convertToDb($insertFields[$columnName], $tableField)." AS ".$quotedName;
505 if($insertFields[$columnName] === null)
506 {
507 //can't just compare NULLs
508 $targetConnectColumns[] = "(source.".$quotedName." IS NULL AND target.".$quotedName." IS NULL)";
509 }
510 else
511 {
512 $targetConnectColumns[] = "(source.".$quotedName." = target.".$quotedName.")";
513 }
514 }
515
516 if (isset($updateFields[$columnName]) || array_key_exists($columnName, $updateFields))
517 {
518 $updateColumns[] = "target.".$quotedName.' = '.$this->convertToDb($updateFields[$columnName], $tableField);
519 }
520 }
521
522 if (
523 $insert && $insert[0] != "" && $insert[1] != ""
524 && $updateColumns
525 && $sourceSelectColumns && $targetConnectColumns
526 )
527 {
528 $sql = "
529 MERGE INTO ".$this->quote($tableName)." target USING (
530 SELECT ".implode(", ", $sourceSelectColumns)." FROM dual
531 )
532 source ON
533 (
534 ".implode(" AND ", $targetConnectColumns)."
535 )
536 WHEN MATCHED THEN
537 UPDATE SET ".implode(", ", $updateColumns)."
538 WHEN NOT MATCHED THEN
539 INSERT (".$insert[0].")
540 VALUES (".$insert[1].")
541 ";
542 }
543 else
544 {
545 $sql = "";
546 }
547
548 return array(
549 $sql
550 );
551 }
552}
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)
addSecondsToDateTime($seconds, $from=null)
prepareBinds(array $tableFields, array $fields)
prepareMerge($tableName, array $primaryFields, array $insertFields, array $updateFields)
prepareInsert($tableName, array $fields, $returnAsArray=false)
convertToDb($value, ORM\Fields\IReadable $field=null)