1C-Bitrix 25.700.0
Загрузка...
Поиск...
Не найдено
oracleconnection.php
См. документацию.
1<?php
2
3namespace Bitrix\Main\DB;
4
5use Bitrix\Main\ArgumentException;
6use Bitrix\Main\ORM\Fields\ScalarField;
7
15{
16 private $transaction = OCI_COMMIT_ON_SUCCESS;
17 protected $lastInsertedId;
18
19 /**********************************************************
20 * SqlHelper
21 **********************************************************/
22
23 protected function createSqlHelper()
24 {
25 return new OracleSqlHelper($this);
26 }
27
28 /***********************************************************
29 * Connection and disconnection
30 ***********************************************************/
31
40 protected function connectInternal()
41 {
42 if ($this->isConnected)
43 {
44 return;
45 }
46
47 if ($this->isPersistent())
48 {
49 $connection = oci_pconnect($this->login, $this->password, $this->database);
50 }
51 else
52 {
53 $connection = oci_new_connect($this->login, $this->password, $this->database);
54 }
55
56 if (!$connection)
57 {
58 throw new ConnectionException('Oracle connect error', $this->getErrorMessage());
59 }
60
61 $this->isConnected = true;
62 $this->resource = $connection;
63
64 $this->afterConnected();
65 }
66
73 protected function disconnectInternal()
74 {
75 if (!$this->isConnected)
76 {
77 return;
78 }
79
80 $this->isConnected = false;
81 oci_close($this->resource);
82 }
83
84 /*********************************************************
85 * Query
86 *********************************************************/
87
91 protected function queryInternal($sql, array $binds = null, \Bitrix\Main\Diag\SqlTrackerQuery $trackerQuery = null)
92 {
93 $this->connectInternal();
94
95 $trackerQuery?->startQuery($sql, $binds);
96
97 $result = oci_parse($this->resource, $sql);
98
99 if (!$result)
100 {
101 $trackerQuery?->finishQuery();
102
103 throw new SqlQueryException("", $this->getErrorMessage($this->resource), $sql);
104 }
105
106 $executionMode = $this->transaction;
107
109 $clob = [];
110
111 if (!empty($binds))
112 {
113 $executionMode = OCI_DEFAULT;
114 foreach ($binds as $key => $val)
115 {
116 $clob[$key] = oci_new_descriptor($this->resource);
117 oci_bind_by_name($result, ":" . $key, $clob[$key], -1, OCI_B_CLOB);
118 }
119 }
120
121 if (!oci_execute($result, $executionMode))
122 {
123 $trackerQuery?->finishQuery();
124
125 throw new SqlQueryException("", $this->getErrorMessage($result), $sql);
126 }
127
128 if (!empty($binds))
129 {
130 if (oci_num_rows($result) > 0)
131 {
132 foreach ($binds as $key => $val)
133 {
134 if ($clob[$key])
135 {
136 $clob[$key]->save($val);
137 }
138 }
139 }
140
141 if ($this->transaction == OCI_COMMIT_ON_SUCCESS)
142 {
143 oci_commit($this->resource);
144 }
145
146 foreach ($binds as $key => $val)
147 {
148 if ($clob[$key])
149 {
150 $clob[$key]->free();
151 }
152 }
153 }
154
155 $trackerQuery?->finishQuery();
156
157 $this->lastQueryResult = $result;
158
159 return $result;
160 }
161
165 protected function createResult($result, \Bitrix\Main\Diag\SqlTrackerQuery $trackerQuery = null)
166 {
167 return new OracleResult($result, $this, $trackerQuery);
168 }
169
173 public function query($sql)
174 {
175 [$sql, $binds, $offset, $limit] = self::parseQueryFunctionArgs(func_get_args());
176
177 if (!empty($binds))
178 {
179 $binds1 = $binds2 = "";
180 foreach ($binds as $key => $value)
181 {
182 if ($value <> '')
183 {
184 if ($binds1 != "")
185 {
186 $binds1 .= ",";
187 $binds2 .= ",";
188 }
189
190 $binds1 .= $key;
191 $binds2 .= ":" . $key;
192 }
193 }
194
195 if ($binds1 != "")
196 {
197 $sql .= " RETURNING " . $binds1 . " INTO " . $binds2;
198 }
199 }
200
201 return parent::query($sql, $binds, $offset, $limit);
202 }
203
207 public function add($tableName, array $data, $identity = "ID")
208 {
209 if ($identity !== null && !isset($data[$identity]))
210 {
211 $data[$identity] = $this->getNextId("sq_" . $tableName);
212 }
213
214 $insert = $this->getSqlHelper()->prepareInsert($tableName, $data);
215
216 $binds = $insert[2];
217
218 $sql =
219 "INSERT INTO " . $tableName . "(" . $insert[0] . ") " .
220 "VALUES (" . $insert[1] . ")";
221
222 $this->queryExecute($sql, $binds);
223
224 $this->lastInsertedId = $data[$identity];
225
226 return $data[$identity];
227 }
228
239 public function getNextId($name = "")
240 {
241 $name = preg_replace("/[^A-Za-z0-9_]+/i", "", $name);
242 $name = trim($name);
243
244 if ($name == '')
245 {
246 throw new \Bitrix\Main\ArgumentNullException("name");
247 }
248
249 $sql = "SELECT " . $this->getSqlHelper()->quote($name) . ".NEXTVAL FROM DUAL";
250
251 $result = $this->query($sql);
252 if ($row = $result->fetch())
253 {
254 return array_shift($row);
255 }
256
257 return null;
258 }
259
263 public function getInsertedId()
264 {
266 }
267
271 public function getAffectedRowsCount()
272 {
273 return oci_num_rows($this->lastQueryResult);
274 }
275
279 public function isTableExists($tableName)
280 {
281 if (empty($tableName))
282 {
283 return false;
284 }
285
286 $result = $this->queryScalar("
287 SELECT COUNT(TABLE_NAME)
288 FROM USER_TABLES
289 WHERE TABLE_NAME LIKE UPPER('" . $this->getSqlHelper()->forSql($tableName) . "')
290 ");
291 return ($result > 0);
292 }
293
297 public function isIndexExists($tableName, array $columns)
298 {
299 return $this->getIndexName($tableName, $columns) !== null;
300 }
301
305 public function getIndexName($tableName, array $columns, $strict = false)
306 {
307 if (empty($columns))
308 {
309 return null;
310 }
311
312 $isFunc = false;
313 $indexes = [];
314
315 $result = $this->query("SELECT * FROM USER_IND_COLUMNS WHERE TABLE_NAME = upper('" . $this->getSqlHelper()->forSql($tableName) . "')");
316 while ($ar = $result->fetch())
317 {
318 $indexes[$ar["INDEX_NAME"]][$ar["COLUMN_POSITION"] - 1] = $ar["COLUMN_NAME"];
319 if (strncmp($ar["COLUMN_NAME"], "SYS_NC", 6) === 0)
320 {
321 $isFunc = true;
322 }
323 }
324
325 if ($isFunc)
326 {
327 $result = $this->query("SELECT * FROM USER_IND_EXPRESSIONS WHERE TABLE_NAME = upper('" . $this->getSqlHelper()->forSql($tableName) . "')");
328 while ($ar = $result->fetch())
329 {
330 $indexes[$ar["INDEX_NAME"]][$ar["COLUMN_POSITION"] - 1] = $ar["COLUMN_EXPRESSION"];
331 }
332 }
333
334 return static::findIndex($indexes, $columns, $strict);
335 }
336
340 public function getTableFields($tableName)
341 {
342 if (!isset($this->tableColumnsCache[$tableName]))
343 {
344 $this->connectInternal();
345
346 $query = $this->queryInternal("SELECT * FROM " . $this->getSqlHelper()->quote($tableName) . " WHERE ROWNUM = 0");
347
348 $result = $this->createResult($query);
349
350 $this->tableColumnsCache[$tableName] = $result->getFields();
351 }
352 return $this->tableColumnsCache[$tableName];
353 }
354
358 public function createTable($tableName, $fields, $primary = [], $autoincrement = [])
359 {
360 $sql = 'CREATE TABLE ' . $this->getSqlHelper()->quote($tableName) . ' (';
361 $sqlFields = [];
362
363 foreach ($fields as $columnName => $field)
364 {
365 if (!($field instanceof ScalarField))
366 {
367 throw new ArgumentException(sprintf(
368 'Field `%s` should be an Entity\ScalarField instance', $columnName
369 ));
370 }
371
372 $realColumnName = $field->getColumnName();
373
374 $sqlFields[] = $this->getSqlHelper()->quote($realColumnName)
375 . ' ' . $this->getSqlHelper()->getColumnTypeByField($field)
376 . ' ' . (in_array($columnName, $primary, true) ? 'NOT NULL' : 'NULL');
377 }
378
379 $sql .= join(', ', $sqlFields);
380
381 if (!empty($primary))
382 {
383 foreach ($primary as &$primaryColumn)
384 {
385 $realColumnName = $fields[$primaryColumn]->getColumnName();
386 $primaryColumn = $this->getSqlHelper()->quote($realColumnName);
387 }
388
389 $sql .= ', PRIMARY KEY(' . join(', ', $primary) . ')';
390 }
391
392 $sql .= ')';
393
394 $this->query($sql);
395
396 // autoincrement field
397 if (!empty($autoincrement))
398 {
399 foreach ($autoincrement as $autoincrementColumn)
400 {
401 $autoincrementColumn = $fields[$autoincrementColumn]->getColumnName();
402
403 if ($autoincrementColumn == 'ID')
404 {
405 // old-school hack
406 $aiName = $tableName;
407 }
408 else
409 {
410 $aiName = $tableName . '_' . $autoincrementColumn;
411 }
412
413 $this->query('CREATE SEQUENCE ' . $this->getSqlHelper()->quote('sq_' . $aiName));
414
415 $this->query('CREATE OR REPLACE TRIGGER ' . $this->getSqlHelper()->quote($aiName . '_insert') . '
416 BEFORE INSERT
417 ON ' . $this->getSqlHelper()->quote($tableName) . '
418 FOR EACH ROW
419 BEGIN
420 IF :NEW.' . $this->getSqlHelper()->quote($autoincrementColumn) . ' IS NULL THEN
421 SELECT ' . $this->getSqlHelper()->quote('sq_' . $aiName) . '.NEXTVAL
422 INTO :NEW.' . $this->getSqlHelper()->quote($autoincrementColumn) . ' FROM dual;
423 END IF;
424 END;'
425 );
426 }
427 }
428 }
429
433 public function renameTable($currentName, $newName)
434 {
435 $this->query('RENAME ' . $this->getSqlHelper()->quote($currentName) . ' TO ' . $this->getSqlHelper()->quote($newName));
436
437 // handle auto increment: rename primary sequence for ID
438 // properly we should check PRIMARY fields instead of ID: $aiName = $currentName.'_'.$fieldName, see createTable
439 $aiName = $currentName;
440
441 if ($this->queryScalar("SELECT 1 FROM user_sequences WHERE sequence_name=upper('" . $this->getSqlHelper()->forSql('sq_' . $aiName) . "')"))
442 {
443 // for fields excpet for ID here should be $newName.'_'.$fieldName, see createTable
444 $newAiName = $newName;
445
446 // rename sequence
447 $this->query('RENAME ' . $this->getSqlHelper()->quote('sq_' . $aiName) . ' TO ' . $this->getSqlHelper()->quote('sq_' . $newAiName));
448
449 // recreate trigger
450 $this->query('DROP TRIGGER ' . $this->getSqlHelper()->quote($aiName . '_insert'));
451
452 $this->query('CREATE OR REPLACE TRIGGER ' . $this->getSqlHelper()->quote($newAiName . '_insert') . '
453 BEFORE INSERT
454 ON ' . $this->getSqlHelper()->quote($newName) . '
455 FOR EACH ROW
456 BEGIN
457 IF :NEW.' . $this->getSqlHelper()->quote('ID') . ' IS NULL THEN
458 SELECT ' . $this->getSqlHelper()->quote('sq_' . $newAiName) . '.NEXTVAL
459 INTO :NEW.' . $this->getSqlHelper()->quote('ID') . ' FROM dual;
460 END IF;
461 END;'
462 );
463 }
464 }
465
469 public function dropTable($tableName)
470 {
471 $this->query('DROP TABLE ' . $this->getSqlHelper()->quote($tableName) . ' CASCADE CONSTRAINTS');
472
473 // handle auto increment: delete primary sequence for ID
474 // properly we should check PRIMARY fields instead of ID: $aiName = $currentName.'_'.$fieldName, see createTable
475 $aiName = $tableName;
476
477 if ($this->queryScalar("SELECT 1 FROM user_sequences WHERE sequence_name=upper('" . $this->getSqlHelper()->forSql('sq_' . $aiName) . "')"))
478 {
479 $this->query('DROP SEQUENCE ' . $this->getSqlHelper()->quote('sq_' . $aiName));
480 }
481 }
482
483 /*********************************************************
484 * Transaction
485 *********************************************************/
486
490 public function startTransaction()
491 {
492 $this->transaction = OCI_DEFAULT;
493 }
494
498 public function commitTransaction()
499 {
500 $this->connectInternal();
501 OCICommit($this->resource);
502 $this->transaction = OCI_COMMIT_ON_SUCCESS;
503 }
504
508 public function rollbackTransaction()
509 {
510 $this->connectInternal();
511 OCIRollback($this->resource);
512 $this->transaction = OCI_COMMIT_ON_SUCCESS;
513 }
514
515 /*********************************************************
516 * Type, version, cache, etc.
517 *********************************************************/
518
528 public function getType()
529 {
530 return "oracle";
531 }
532
536 public function getVersion()
537 {
538 if ($this->version == null)
539 {
540 $version = $this->queryScalar('SELECT BANNER FROM v$version');
541 if ($version != null)
542 {
543 $version = trim($version);
544 $this->versionExpress = (mb_strpos($version, "Express Edition") > 0);
545 preg_match("#[0-9]+\\.[0-9]+\\.[0-9]+#", $version, $arr);
546 $this->version = $arr[0];
547 }
548 }
549
550 return [$this->version, $this->versionExpress];
551 }
552
556 public function getErrorMessage($resource = null)
557 {
558 if ($resource)
559 {
560 $error = oci_error($resource);
561 }
562 else
563 {
564 $error = oci_error();
565 }
566
567 if (!$error)
568 {
569 return "";
570 }
571
572 $result = sprintf("[%s] %s", $error["code"], $error["message"]);
573 if (!empty($error["sqltext"]))
574 {
575 $result .= sprintf(" (%s)", $error["sqltext"]);
576 }
577
578 return $result;
579 }
580}
$connection
Определения actionsdefinitions.php:38
xml version
Определения yandex.php:67
isTableExists($tableName)
Определения oracleconnection.php:279
dropTable($tableName)
Определения oracleconnection.php:469
getIndexName($tableName, array $columns, $strict=false)
Определения oracleconnection.php:305
getTableFields($tableName)
Определения oracleconnection.php:340
renameTable($currentName, $newName)
Определения oracleconnection.php:433
isIndexExists($tableName, array $columns)
Определения oracleconnection.php:297
getErrorMessage($resource=null)
Определения oracleconnection.php:556
createResult($result, \Bitrix\Main\Diag\SqlTrackerQuery $trackerQuery=null)
Определения oracleconnection.php:165
add($tableName, array $data, $identity="ID")
Определения oracleconnection.php:207
createTable($tableName, $fields, $primary=[], $autoincrement=[])
Определения oracleconnection.php:358
$data['IS_AVAILABLE']
Определения .description.php:13
$arr
Определения file_new.php:624
</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
$query
Определения get_search.php:11
$name
Определения menu_edit.php:35
Определения cachetracker.php:2
$ar
Определения options.php:199
if(empty($signedUserToken)) $key
Определения quickway.php:257
$val
Определения options.php:1793
$error
Определения subscription_card_product.php:20
$fields
Определения yandex_run.php:501